aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Schulz <david.schulz@qt.io>2021-11-05 08:56:49 +0100
committerDavid Schulz <david.schulz@qt.io>2021-11-08 08:35:38 +0000
commite0c115fb9b1806e77930bbc9d4484eaefa8aee5f (patch)
treeae35b84620eac0e3033df8ddb486b2d1276e9400
parentaf7d9d6f8e6988e0fc4441841c9d1c8931bdc627 (diff)
Editor: Allow creating block selections with alt+shift again
These block selections are a convenience for people used to the block selection allowing to also unselect parts again (at least as long as alt+shift is pressed). Fixes: QTCREATORBUG-26535 Fixes: QTCREATORBUG-26529 Change-Id: I19558dc1d823c268cc1cfda0ea8151bac483701f Reviewed-by: Orgad Shaneh <orgads@gmail.com>
-rw-r--r--src/libs/utils/multitextcursor.cpp2
-rw-r--r--src/libs/utils/multitextcursor.h3
-rw-r--r--src/plugins/texteditor/tabsettings.cpp5
-rw-r--r--src/plugins/texteditor/tabsettings.h1
-rw-r--r--src/plugins/texteditor/texteditor.cpp109
5 files changed, 117 insertions, 3 deletions
diff --git a/src/libs/utils/multitextcursor.cpp b/src/libs/utils/multitextcursor.cpp
index 7225de9344..a73c58bbb1 100644
--- a/src/libs/utils/multitextcursor.cpp
+++ b/src/libs/utils/multitextcursor.cpp
@@ -294,7 +294,7 @@ static QTextLine currentTextLine(const QTextCursor &cursor)
return layout->lineForTextPosition(relativePos);
}
-bool multiCursorAddEvent(QKeyEvent *e, QKeySequence::StandardKey matchKey)
+bool MultiTextCursor::multiCursorAddEvent(QKeyEvent *e, QKeySequence::StandardKey matchKey)
{
uint searchkey = (e->modifiers() | e->key())
& ~(Qt::KeypadModifier
diff --git a/src/libs/utils/multitextcursor.h b/src/libs/utils/multitextcursor.h
index 90938848e8..8fdf041faa 100644
--- a/src/libs/utils/multitextcursor.h
+++ b/src/libs/utils/multitextcursor.h
@@ -27,6 +27,7 @@
#include "utils_global.h"
+#include <QKeySequence>
#include <QTextCursor>
QT_BEGIN_NAMESPACE
@@ -99,6 +100,8 @@ public:
const_iterator constBegin() const { return m_cursors.constBegin(); }
const_iterator constEnd() const { return m_cursors.constEnd(); }
+ static bool multiCursorAddEvent(QKeyEvent *e, QKeySequence::StandardKey matchKey);
+
private:
QList<QTextCursor> m_cursors;
};
diff --git a/src/plugins/texteditor/tabsettings.cpp b/src/plugins/texteditor/tabsettings.cpp
index c61a0b3fb3..c363815572 100644
--- a/src/plugins/texteditor/tabsettings.cpp
+++ b/src/plugins/texteditor/tabsettings.cpp
@@ -204,6 +204,11 @@ int TabSettings::columnAt(const QString &text, int position) const
return column;
}
+int TabSettings::columnAtCursorPosition(const QTextCursor &cursor) const
+{
+ return columnAt(cursor.block().text(), cursor.positionInBlock());
+}
+
int TabSettings::positionAtColumn(const QString &text, int column, int *offset, bool allowOverstep) const
{
int col = 0;
diff --git a/src/plugins/texteditor/tabsettings.h b/src/plugins/texteditor/tabsettings.h
index e73d81b365..c6446046a8 100644
--- a/src/plugins/texteditor/tabsettings.h
+++ b/src/plugins/texteditor/tabsettings.h
@@ -66,6 +66,7 @@ public:
int lineIndentPosition(const QString &text) const;
int columnAt(const QString &text, int position) const;
+ int columnAtCursorPosition(const QTextCursor &cursor) const;
int positionAtColumn(const QString &text, int column, int *offset = nullptr, bool allowOverstep = false) const;
int columnCountForText(const QString &text, int startColumn = 0) const;
int indentedColumn(int column, bool doIndent = true) const;
diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp
index 7a76970389..499897522d 100644
--- a/src/plugins/texteditor/texteditor.cpp
+++ b/src/plugins/texteditor/texteditor.cpp
@@ -782,6 +782,18 @@ public:
bool m_scrollBarUpdateScheduled = false;
const MultiTextCursor m_cursors;
+ struct BlockSelection
+ {
+ int blockNumber = -1;
+ int column = -1;
+ int anchorBlockNumber = -1;
+ int anchorColumn = -1;
+ };
+ QList<BlockSelection> m_blockSelections;
+ QList<QTextCursor> generateCursorsForBlockSelection(const BlockSelection &blockSelection);
+ void initBlockSelection();
+ void clearBlockSelection();
+ void handleMoveBlockSelection(QTextCursor::MoveOperation op);
class UndoCursor
{
@@ -1348,6 +1360,81 @@ void TextEditorWidgetPrivate::updateAutoCompleteHighlight()
q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, extraSelections);
}
+QList<QTextCursor> TextEditorWidgetPrivate::generateCursorsForBlockSelection(
+ const BlockSelection &blockSelection)
+{
+ const TabSettings tabSettings = m_document->tabSettings();
+
+ QList<QTextCursor> result;
+ QTextBlock block = m_document->document()->findBlockByNumber(blockSelection.anchorBlockNumber);
+ QTextCursor cursor(block);
+ cursor.setPosition(block.position()
+ + tabSettings.positionAtColumn(block.text(), blockSelection.anchorColumn));
+
+ const bool forward = blockSelection.blockNumber > blockSelection.anchorBlockNumber
+ || (blockSelection.blockNumber == blockSelection.anchorBlockNumber
+ && blockSelection.column == blockSelection.anchorColumn);
+
+ while (block.isValid()) {
+ const QString &blockText = block.text();
+ cursor.setPosition(block.position()
+ + tabSettings.positionAtColumn(blockText, blockSelection.anchorColumn));
+ cursor.setPosition(block.position()
+ + tabSettings.positionAtColumn(blockText, blockSelection.column),
+ QTextCursor::KeepAnchor);
+ result.append(cursor);
+ if (block.blockNumber() == blockSelection.blockNumber)
+ break;
+ block = forward ? block.next() : block.previous();
+ }
+ return result;
+}
+
+void TextEditorWidgetPrivate::initBlockSelection()
+{
+ const TabSettings tabSettings = m_document->tabSettings();
+ for (const QTextCursor &cursor : m_cursors) {
+ const int column = tabSettings.columnAtCursorPosition(cursor);
+ QTextCursor anchor = cursor;
+ anchor.setPosition(anchor.anchor());
+ const int anchorColumn = tabSettings.columnAtCursorPosition(anchor);
+ m_blockSelections.append({cursor.blockNumber(), column, anchor.blockNumber(), anchorColumn});
+ }
+}
+
+void TextEditorWidgetPrivate::clearBlockSelection()
+{
+ m_blockSelections.clear();
+}
+
+void TextEditorWidgetPrivate::handleMoveBlockSelection(QTextCursor::MoveOperation op)
+{
+ if (m_blockSelections.isEmpty())
+ initBlockSelection();
+ QList<QTextCursor> cursors;
+ for (BlockSelection &blockSelection : m_blockSelections) {
+ switch (op) {
+ case QTextCursor::Up:
+ blockSelection.blockNumber = qMax(0, blockSelection.blockNumber - 1);
+ break;
+ case QTextCursor::Down:
+ blockSelection.blockNumber = qMin(m_document->document()->blockCount() - 1,
+ blockSelection.blockNumber + 1);
+ break;
+ case QTextCursor::NextCharacter:
+ ++blockSelection.column;
+ break;
+ case QTextCursor::PreviousCharacter:
+ blockSelection.column = qMax(0, blockSelection.column - 1);
+ break;
+ default:
+ return;
+ }
+ cursors.append(generateCursorsForBlockSelection(blockSelection));
+ }
+ q->setMultiTextCursor(MultiTextCursor(cursors));
+}
+
void TextEditorWidget::selectEncoding()
{
TextDocument *doc = d->m_document.data();
@@ -2181,6 +2268,8 @@ static inline bool isPrintableText(const QString &text)
void TextEditorWidget::keyPressEvent(QKeyEvent *e)
{
+ ExecuteOnDestruction eod([&]() { d->clearBlockSelection(); });
+
if (!isModifier(e) && mouseHidingEnabled())
viewport()->setCursor(Qt::BlankCursor);
ToolTip::hide();
@@ -2420,7 +2509,23 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
}
if (ro || !isPrintableText(eventText)) {
- if (!d->cursorMoveKeyEvent(e)) {
+ QTextCursor::MoveOperation blockSelectionOperation = QTextCursor::NoMove;
+ if (e->modifiers() & Qt::AltModifier && !Utils::HostOsInfo::isMacHost()) {
+ if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToNextLine))
+ blockSelectionOperation = QTextCursor::Down;
+ else if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToPreviousLine))
+ blockSelectionOperation = QTextCursor::Up;
+ else if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToNextChar))
+ blockSelectionOperation = QTextCursor::NextCharacter;
+ else if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToPreviousChar))
+ blockSelectionOperation = QTextCursor::PreviousCharacter;
+ }
+
+ if (blockSelectionOperation != QTextCursor::NoMove) {
+ auto doNothing = [](){};
+ eod.reset(doNothing);
+ d->handleMoveBlockSelection(blockSelectionOperation);
+ } else if (!d->cursorMoveKeyEvent(e)) {
QTextCursor cursor = textCursor();
bool cursorWithinSnippet = false;
if (d->m_snippetOverlay->isVisible()
@@ -5134,7 +5239,7 @@ void TextEditorWidget::mouseMoveEvent(QMouseEvent *e)
cursor.addCursor(c);
}
cursor.mergeCursors();
- if (!cursor.isNull() && cursor != multiTextCursor())
+ if (!cursor.isNull())
setMultiTextCursor(cursor);
} else {
if (startMouseMoveCursor.has_value())