forked from qt-creator/qt-creator
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>
This commit is contained in:
@@ -294,7 +294,7 @@ static QTextLine currentTextLine(const QTextCursor &cursor)
|
|||||||
return layout->lineForTextPosition(relativePos);
|
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())
|
uint searchkey = (e->modifiers() | e->key())
|
||||||
& ~(Qt::KeypadModifier
|
& ~(Qt::KeypadModifier
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "utils_global.h"
|
#include "utils_global.h"
|
||||||
|
|
||||||
|
#include <QKeySequence>
|
||||||
#include <QTextCursor>
|
#include <QTextCursor>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
@@ -99,6 +100,8 @@ public:
|
|||||||
const_iterator constBegin() const { return m_cursors.constBegin(); }
|
const_iterator constBegin() const { return m_cursors.constBegin(); }
|
||||||
const_iterator constEnd() const { return m_cursors.constEnd(); }
|
const_iterator constEnd() const { return m_cursors.constEnd(); }
|
||||||
|
|
||||||
|
static bool multiCursorAddEvent(QKeyEvent *e, QKeySequence::StandardKey matchKey);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<QTextCursor> m_cursors;
|
QList<QTextCursor> m_cursors;
|
||||||
};
|
};
|
||||||
|
@@ -204,6 +204,11 @@ int TabSettings::columnAt(const QString &text, int position) const
|
|||||||
return column;
|
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 TabSettings::positionAtColumn(const QString &text, int column, int *offset, bool allowOverstep) const
|
||||||
{
|
{
|
||||||
int col = 0;
|
int col = 0;
|
||||||
|
@@ -66,6 +66,7 @@ public:
|
|||||||
|
|
||||||
int lineIndentPosition(const QString &text) const;
|
int lineIndentPosition(const QString &text) const;
|
||||||
int columnAt(const QString &text, int position) 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 positionAtColumn(const QString &text, int column, int *offset = nullptr, bool allowOverstep = false) const;
|
||||||
int columnCountForText(const QString &text, int startColumn = 0) const;
|
int columnCountForText(const QString &text, int startColumn = 0) const;
|
||||||
int indentedColumn(int column, bool doIndent = true) const;
|
int indentedColumn(int column, bool doIndent = true) const;
|
||||||
|
@@ -782,6 +782,18 @@ public:
|
|||||||
bool m_scrollBarUpdateScheduled = false;
|
bool m_scrollBarUpdateScheduled = false;
|
||||||
|
|
||||||
const MultiTextCursor m_cursors;
|
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
|
class UndoCursor
|
||||||
{
|
{
|
||||||
@@ -1348,6 +1360,81 @@ void TextEditorWidgetPrivate::updateAutoCompleteHighlight()
|
|||||||
q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, extraSelections);
|
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()
|
void TextEditorWidget::selectEncoding()
|
||||||
{
|
{
|
||||||
TextDocument *doc = d->m_document.data();
|
TextDocument *doc = d->m_document.data();
|
||||||
@@ -2181,6 +2268,8 @@ static inline bool isPrintableText(const QString &text)
|
|||||||
|
|
||||||
void TextEditorWidget::keyPressEvent(QKeyEvent *e)
|
void TextEditorWidget::keyPressEvent(QKeyEvent *e)
|
||||||
{
|
{
|
||||||
|
ExecuteOnDestruction eod([&]() { d->clearBlockSelection(); });
|
||||||
|
|
||||||
if (!isModifier(e) && mouseHidingEnabled())
|
if (!isModifier(e) && mouseHidingEnabled())
|
||||||
viewport()->setCursor(Qt::BlankCursor);
|
viewport()->setCursor(Qt::BlankCursor);
|
||||||
ToolTip::hide();
|
ToolTip::hide();
|
||||||
@@ -2420,7 +2509,23 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ro || !isPrintableText(eventText)) {
|
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();
|
QTextCursor cursor = textCursor();
|
||||||
bool cursorWithinSnippet = false;
|
bool cursorWithinSnippet = false;
|
||||||
if (d->m_snippetOverlay->isVisible()
|
if (d->m_snippetOverlay->isVisible()
|
||||||
@@ -5134,7 +5239,7 @@ void TextEditorWidget::mouseMoveEvent(QMouseEvent *e)
|
|||||||
cursor.addCursor(c);
|
cursor.addCursor(c);
|
||||||
}
|
}
|
||||||
cursor.mergeCursors();
|
cursor.mergeCursors();
|
||||||
if (!cursor.isNull() && cursor != multiTextCursor())
|
if (!cursor.isNull())
|
||||||
setMultiTextCursor(cursor);
|
setMultiTextCursor(cursor);
|
||||||
} else {
|
} else {
|
||||||
if (startMouseMoveCursor.has_value())
|
if (startMouseMoveCursor.has_value())
|
||||||
|
Reference in New Issue
Block a user