TextEditor: Fixed indentation in block selection mode

Made indentation work for block selection mode the same way it does in default mode:

1. delete text if any selected
2. indent block if no text selected
3. indent last line if cursor in first column (QTCREATORBUG-12697)

Task-number: QTCREATORBUG-12697
Change-Id: I1f6b218b389f3fdc5232ec02857aa76f5ccbaaf0
Reviewed-by: André Hartmann <aha_1980@gmx.de>
Reviewed-by: David Schulz <david.schulz@theqtcompany.com>
This commit is contained in:
Vladyslav Gapchych
2015-07-16 15:56:25 +02:00
committed by David Schulz
parent c5bca90b0e
commit aab3b0fc66
5 changed files with 110 additions and 55 deletions

View File

@@ -198,12 +198,13 @@ int TabSettings::columnAt(const QString &text, int position) const
return column; return column;
} }
int TabSettings::positionAtColumn(const QString &text, int column, int *offset) const int TabSettings::positionAtColumn(const QString &text, int column, int *offset, bool allowOverstep) const
{ {
int col = 0; int col = 0;
int i = 0; int i = 0;
while (i < text.size() && col < column) { int textSize = text.size();
if (text.at(i) == QLatin1Char('\t')) while ((i < textSize || allowOverstep) && col < column) {
if (i < textSize && text.at(i) == QLatin1Char('\t'))
col = col - (col % m_tabSize) + m_tabSize; col = col - (col % m_tabSize) + m_tabSize;
else else
++col; ++col;
@@ -228,6 +229,8 @@ int TabSettings::columnCountForText(const QString &text, int startColumn) const
int TabSettings::spacesLeftFromPosition(const QString &text, int position) int TabSettings::spacesLeftFromPosition(const QString &text, int position)
{ {
if (position >= text.size())
return 0;
int i = position; int i = position;
while (i > 0) { while (i > 0) {
if (!text.at(i-1).isSpace()) if (!text.at(i-1).isSpace())

View File

@@ -70,7 +70,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 positionAtColumn(const QString &text, int column, int *offset = 0) const; int positionAtColumn(const QString &text, int column, int *offset = 0, 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;
QString indentationString(int startColumn, int targetColumn, const QTextBlock &currentBlock = QTextBlock()) const; QString indentationString(int startColumn, int targetColumn, const QTextBlock &currentBlock = QTextBlock()) const;

View File

@@ -87,7 +87,8 @@ public:
{ {
} }
QTextCursor indentOrUnindent(const QTextCursor &textCursor, bool doIndent); QTextCursor indentOrUnindent(const QTextCursor &textCursor, bool doIndent,
bool blockSelection = false, int column = 0, int *offset = 0);
void resetRevisions(); void resetRevisions();
void updateRevisions(); void updateRevisions();
@@ -111,56 +112,84 @@ public:
TextMarks m_marksCache; // Marks not owned TextMarks m_marksCache; // Marks not owned
}; };
QTextCursor TextDocumentPrivate::indentOrUnindent(const QTextCursor &textCursor, bool doIndent) QTextCursor TextDocumentPrivate::indentOrUnindent(const QTextCursor &textCursor, bool doIndent,
bool blockSelection, int columnIn, int *offset)
{ {
QTextCursor cursor = textCursor; QTextCursor cursor = textCursor;
cursor.beginEditBlock(); cursor.beginEditBlock();
if (cursor.hasSelection()) { TabSettings &ts = m_tabSettings;
// Indent or unindent the selected lines // Indent or unindent the selected lines
int pos = cursor.position(); int pos = cursor.position();
int column = blockSelection ? columnIn
: ts.columnAt(cursor.block().text(), cursor.positionInBlock());
int anchor = cursor.anchor(); int anchor = cursor.anchor();
int start = qMin(anchor, pos); int start = qMin(anchor, pos);
int end = qMax(anchor, pos); int end = qMax(anchor, pos);
bool modified = true;
QTextBlock startBlock = m_document.findBlock(start); QTextBlock startBlock = m_document.findBlock(start);
QTextBlock endBlock = m_document.findBlock(end-1).next(); QTextBlock endBlock = m_document.findBlock(end).next();
if (startBlock.next() == endBlock const bool oneLinePartial = (startBlock.next() == endBlock)
&& (start > startBlock.position() || end < endBlock.position() - 1)) { && (start > startBlock.position() || end < endBlock.position() - 1);
// Only one line partially selected.
cursor.removeSelectedText(); // Make sure one line selection will get processed in "for" loop
} else { if (startBlock == endBlock)
endBlock = endBlock.next();
if (cursor.hasSelection() && !blockSelection && !oneLinePartial) {
for (QTextBlock block = startBlock; block != endBlock; block = block.next()) { for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
QString text = block.text(); const QString text = block.text();
int indentPosition = m_tabSettings.lineIndentPosition(text); int indentPosition = ts.lineIndentPosition(text);
if (!doIndent && !indentPosition) if (!doIndent && !indentPosition)
indentPosition = m_tabSettings.firstNonSpace(text); indentPosition = ts.firstNonSpace(text);
int targetColumn = m_tabSettings.indentedColumn(m_tabSettings.columnAt(text, indentPosition), doIndent); int targetColumn = ts.indentedColumn(ts.columnAt(text, indentPosition), doIndent);
cursor.setPosition(block.position() + indentPosition); cursor.setPosition(block.position() + indentPosition);
cursor.insertText(m_tabSettings.indentationString(0, targetColumn, block)); cursor.insertText(ts.indentationString(0, targetColumn, block));
cursor.setPosition(block.position()); cursor.setPosition(block.position());
cursor.setPosition(block.position() + indentPosition, QTextCursor::KeepAnchor); cursor.setPosition(block.position() + indentPosition, QTextCursor::KeepAnchor);
cursor.removeSelectedText(); cursor.removeSelectedText();
modified = false;
} }
cursor.endEditBlock(); } else if (cursor.hasSelection() && !blockSelection && oneLinePartial) {
return textCursor; // Only one line partially selected.
} cursor.removeSelectedText();
} else {
// Indent or unindent at cursor position
for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
QString text = block.text();
int blockColumn = ts.columnAt(text, text.size());
if (blockColumn < column) {
cursor.setPosition(block.position() + text.size());
cursor.insertText(ts.indentationString(blockColumn, column, block));
text = block.text();
} }
// Indent or unindent at cursor position int indentPosition = ts.positionAtColumn(text, column, 0, true);
QTextBlock block = cursor.block(); int spaces = ts.spacesLeftFromPosition(text, indentPosition);
QString text = block.text(); int startColumn = ts.columnAt(text, indentPosition - spaces);
int indentPosition = cursor.positionInBlock(); int targetColumn = ts.indentedColumn(ts.columnAt(text, indentPosition), doIndent);
int spaces = m_tabSettings.spacesLeftFromPosition(text, indentPosition);
int startColumn = m_tabSettings.columnAt(text, indentPosition - spaces);
int targetColumn = m_tabSettings.indentedColumn(m_tabSettings.columnAt(text, indentPosition), doIndent);
cursor.setPosition(block.position() + indentPosition); cursor.setPosition(block.position() + indentPosition);
cursor.setPosition(block.position() + indentPosition - spaces, QTextCursor::KeepAnchor); cursor.setPosition(block.position() + indentPosition - spaces, QTextCursor::KeepAnchor);
cursor.removeSelectedText(); cursor.removeSelectedText();
cursor.insertText(m_tabSettings.indentationString(startColumn, targetColumn, block)); cursor.insertText(ts.indentationString(startColumn, targetColumn, block));
}
// Preserve initial anchor of block selection
if (blockSelection) {
end = cursor.position();
if (offset)
*offset = ts.columnAt(cursor.block().text(), cursor.positionInBlock()) - column;
cursor.setPosition(start);
cursor.setPosition(end, QTextCursor::KeepAnchor);
}
}
cursor.endEditBlock(); cursor.endEditBlock();
return cursor;
return modified ? cursor : textCursor;
} }
void TextDocumentPrivate::resetRevisions() void TextDocumentPrivate::resetRevisions()
@@ -359,14 +388,16 @@ void TextDocument::autoReindent(const QTextCursor &cursor)
d->m_indenter->reindent(&d->m_document, cursor, d->m_tabSettings); d->m_indenter->reindent(&d->m_document, cursor, d->m_tabSettings);
} }
QTextCursor TextDocument::indent(const QTextCursor &cursor) QTextCursor TextDocument::indent(const QTextCursor &cursor, bool blockSelection, int column,
int *offset)
{ {
return d->indentOrUnindent(cursor, true); return d->indentOrUnindent(cursor, true, blockSelection, column, offset);
} }
QTextCursor TextDocument::unindent(const QTextCursor &cursor) QTextCursor TextDocument::unindent(const QTextCursor &cursor, bool blockSelection, int column,
int *offset)
{ {
return d->indentOrUnindent(cursor, false); return d->indentOrUnindent(cursor, false, blockSelection, column, offset);
} }
const ExtraEncodingSettings &TextDocument::extraEncodingSettings() const const ExtraEncodingSettings &TextDocument::extraEncodingSettings() const

View File

@@ -89,8 +89,10 @@ public:
Indenter *indenter() const; Indenter *indenter() const;
void autoIndent(const QTextCursor &cursor, QChar typedChar = QChar::Null); void autoIndent(const QTextCursor &cursor, QChar typedChar = QChar::Null);
void autoReindent(const QTextCursor &cursor); void autoReindent(const QTextCursor &cursor);
QTextCursor indent(const QTextCursor &cursor); QTextCursor indent(const QTextCursor &cursor, bool blockSelection = false, int column = 0,
QTextCursor unindent(const QTextCursor &cursor); int *offset = 0);
QTextCursor unindent(const QTextCursor &cursor, bool blockSelection = false, int column = 0,
int *offset = 0);
TextMarks marks() const; TextMarks marks() const;
bool addMark(TextMark *mark); bool addMark(TextMark *mark);

View File

@@ -1495,12 +1495,26 @@ void TextEditorWidget::lowercaseSelection()
void TextEditorWidget::indent() void TextEditorWidget::indent()
{ {
setTextCursor(textDocument()->indent(textCursor())); int offset = 0;
doSetTextCursor(textDocument()->indent(textCursor(), d->m_inBlockSelectionMode,
d->m_blockSelection.positionColumn, &offset),
d->m_inBlockSelectionMode);
if (d->m_inBlockSelectionMode) {
d->m_blockSelection.anchorColumn += offset;
d->m_blockSelection.positionColumn += offset;
}
} }
void TextEditorWidget::unindent() void TextEditorWidget::unindent()
{ {
setTextCursor(textDocument()->unindent(textCursor())); int offset = 0;
doSetTextCursor(textDocument()->unindent(textCursor(), d->m_inBlockSelectionMode,
d->m_blockSelection.positionColumn, &offset),
d->m_inBlockSelectionMode);
if (d->m_inBlockSelectionMode) {
d->m_blockSelection.anchorColumn += offset;
d->m_blockSelection.positionColumn += offset;
}
} }
void TextEditorWidget::undo() void TextEditorWidget::undo()
@@ -2253,12 +2267,17 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
setTextCursor(cursor); setTextCursor(cursor);
} }
d->m_document->autoIndent(cursor); d->m_document->autoIndent(cursor);
} else {
if (d->m_inBlockSelectionMode
&& d->m_blockSelection.firstVisualColumn() != d->m_blockSelection.lastVisualColumn()) {
d->removeBlockSelection();
} else { } else {
if (e->key() == Qt::Key_Tab) if (e->key() == Qt::Key_Tab)
indent(); indent();
else else
unindent(); unindent();
} }
}
e->accept(); e->accept();
return; return;
} break; } break;