From 29b073e92e61972846b743e52787b56a0a4d58d0 Mon Sep 17 00:00:00 2001 From: mae <qt-info@nokia.com> Date: Thu, 5 Aug 2010 15:01:20 +0200 Subject: [PATCH] Refactor block selection Block selection was "broken" when using tabs, or rather incomplete: It treated tabs as normal characters, which has shown to be unexpected by people using tabs in code. The new implementation has a vastly improved find scope as well. In addition, creating a blog selection with mouse or keyboard feels a lot more solid now, as the actual selection is detached from possible valid cursor positions. Task-number: QTCREATORBUG-1541 --- src/plugins/find/basetextfind.cpp | 54 +- src/plugins/find/basetextfind.h | 7 +- src/plugins/projectexplorer/outputwindow.cpp | 6 +- src/plugins/texteditor/basetexteditor.cpp | 559 ++++++++++++++----- src/plugins/texteditor/basetexteditor.h | 38 +- src/plugins/texteditor/basetexteditor_p.h | 8 +- src/plugins/texteditor/tabsettings.cpp | 16 + src/plugins/texteditor/tabsettings.h | 1 + src/plugins/texteditor/texteditoroverlay.cpp | 34 +- src/plugins/texteditor/texteditoroverlay.h | 14 +- 10 files changed, 511 insertions(+), 226 deletions(-) diff --git a/src/plugins/find/basetextfind.cpp b/src/plugins/find/basetextfind.cpp index 211066938b2..063afe8d221 100644 --- a/src/plugins/find/basetextfind.cpp +++ b/src/plugins/find/basetextfind.cpp @@ -39,14 +39,16 @@ using namespace Find; BaseTextFind::BaseTextFind(QTextEdit *editor) : m_editor(editor) - , m_findScopeVerticalBlockSelection(0) + , m_findScopeVerticalBlockSelectionFirstColumn(-1) + , m_findScopeVerticalBlockSelectionLastColumn(-1) , m_incrementalStartPos(-1) { } BaseTextFind::BaseTextFind(QPlainTextEdit *editor) : m_plaineditor(editor) - , m_findScopeVerticalBlockSelection(0) + , m_findScopeVerticalBlockSelectionFirstColumn(-1) + , m_findScopeVerticalBlockSelectionLastColumn(-1) , m_incrementalStartPos(-1) { } @@ -268,17 +270,16 @@ QTextCursor BaseTextFind::findOne(const QRegExp &expr, const QTextCursor &from, if (candidate.isNull()) return candidate; - if (!m_findScopeVerticalBlockSelection) + if (m_findScopeVerticalBlockSelectionFirstColumn < 0) return candidate; forever { if (!inScope(candidate.selectionStart(), candidate.selectionEnd())) return candidate; - QTextCursor b = candidate; - b.setPosition(candidate.selectionStart()); - QTextCursor e = candidate; - e.setPosition(candidate.selectionEnd()); - if (b.positionInBlock() >= m_findScopeStart.positionInBlock() + 1 - && e.positionInBlock() <= m_findScopeStart.positionInBlock() + 1 + m_findScopeVerticalBlockSelection) + bool inVerticalFindScope = false; + QMetaObject::invokeMethod(m_plaineditor, "inFindScope", Qt::DirectConnection, + Q_RETURN_ARG(bool, inVerticalFindScope), + Q_ARG(QTextCursor, candidate)); + if (inVerticalFindScope) return candidate; candidate = document()->find(expr, candidate, options); } @@ -299,23 +300,19 @@ void BaseTextFind::defineFindScope() if (cursor.hasSelection() && cursor.block() != cursor.document()->findBlock(cursor.anchor())) { m_findScopeStart = QTextCursor(document()->docHandle(), qMax(0, cursor.selectionStart()-1)); m_findScopeEnd = QTextCursor(document()->docHandle(), cursor.selectionEnd()); - m_findScopeVerticalBlockSelection = 0; - - int verticalBlockSelection = 0; - if (m_plaineditor && m_plaineditor->metaObject()->indexOfProperty("verticalBlockSelection") >= 0) - verticalBlockSelection = m_plaineditor->property("verticalBlockSelection").toInt(); - - if (verticalBlockSelection) { - QTextCursor findScopeVisualStart(document()->docHandle(), cursor.selectionStart()); - int findScopeFromColumn = qMin(findScopeVisualStart.positionInBlock(), - m_findScopeEnd.positionInBlock()); - int findScopeToColumn = findScopeFromColumn + verticalBlockSelection; - m_findScopeStart.setPosition(findScopeVisualStart.block().position() + findScopeFromColumn - 1); - m_findScopeEnd.setPosition(m_findScopeEnd.block().position() - + qMin(m_findScopeEnd.block().length()-1, findScopeToColumn)); - m_findScopeVerticalBlockSelection = verticalBlockSelection; + m_findScopeVerticalBlockSelectionFirstColumn = -1; + m_findScopeVerticalBlockSelectionLastColumn = -1; + + if (m_plaineditor && m_plaineditor->metaObject()->indexOfProperty("verticalBlockSelectionFirstColumn") >= 0) { + m_findScopeVerticalBlockSelectionFirstColumn + = m_plaineditor->property("verticalBlockSelectionFirstColumn").toInt(); + m_findScopeVerticalBlockSelectionLastColumn + = m_plaineditor->property("verticalBlockSelectionLastColumn").toInt(); } - emit findScopeChanged(m_findScopeStart, m_findScopeEnd, m_findScopeVerticalBlockSelection); + + emit findScopeChanged(m_findScopeStart, m_findScopeEnd, + m_findScopeVerticalBlockSelectionFirstColumn, + m_findScopeVerticalBlockSelectionLastColumn); cursor.setPosition(m_findScopeStart.position()+1); setTextCursor(cursor); } else { @@ -327,6 +324,9 @@ void BaseTextFind::clearFindScope() { m_findScopeStart = QTextCursor(); m_findScopeEnd = QTextCursor(); - m_findScopeVerticalBlockSelection = 0; - emit findScopeChanged(m_findScopeStart, m_findScopeEnd, m_findScopeVerticalBlockSelection); + m_findScopeVerticalBlockSelectionFirstColumn = -1; + m_findScopeVerticalBlockSelectionLastColumn = -1; + emit findScopeChanged(m_findScopeStart, m_findScopeEnd, + m_findScopeVerticalBlockSelectionFirstColumn, + m_findScopeVerticalBlockSelectionLastColumn); } diff --git a/src/plugins/find/basetextfind.h b/src/plugins/find/basetextfind.h index 2bce44a4db6..d632e730e80 100644 --- a/src/plugins/find/basetextfind.h +++ b/src/plugins/find/basetextfind.h @@ -72,7 +72,9 @@ public: signals: void highlightAll(const QString &txt, Find::FindFlags findFlags); - void findScopeChanged(const QTextCursor &start, const QTextCursor &end, int verticalBlockSelection); + void findScopeChanged(const QTextCursor &start, const QTextCursor &end, + int verticalBlockSelectionFirstColumn, + int verticalBlockSelectionLastColumn); private: bool find(const QString &txt, @@ -89,7 +91,8 @@ private: QPointer<QPlainTextEdit> m_plaineditor; QTextCursor m_findScopeStart; QTextCursor m_findScopeEnd; - int m_findScopeVerticalBlockSelection; + int m_findScopeVerticalBlockSelectionFirstColumn; + int m_findScopeVerticalBlockSelectionLastColumn; bool inScope(int startPosition, int endPosition) const; QTextCursor findOne(const QRegExp &expr, const QTextCursor &from, QTextDocument::FindFlags options) const; int m_incrementalStartPos; diff --git a/src/plugins/projectexplorer/outputwindow.cpp b/src/plugins/projectexplorer/outputwindow.cpp index bcee5d1c771..ad111bfc2a9 100644 --- a/src/plugins/projectexplorer/outputwindow.cpp +++ b/src/plugins/projectexplorer/outputwindow.cpp @@ -591,7 +591,11 @@ void OutputWindow::appendText(const QString &textIn, const QTextCharFormat &form bool OutputWindow::isScrollbarAtBottom() const { - return verticalScrollBar()->value() == verticalScrollBar()->maximum(); + return isVisible() + && (blockBoundingRect(document()->lastBlock()).bottom() + + contentOffset().y() <= viewport()->rect().bottom()); + + // return verticalScrollBar()->value() == verticalScrollBar()->maximum(); } void OutputWindow::scrollToBottom() diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index a842ce94638..d32c566d65a 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -710,12 +710,12 @@ void BaseTextEditor::editorContentsChange(int position, int charsRemoved, int ch void BaseTextEditor::slotSelectionChanged() { - bool changed = (d->m_inBlockSelectionMode != d->m_lastEventWasBlockSelectionEvent); - d->m_inBlockSelectionMode = d->m_lastEventWasBlockSelectionEvent; - if (changed || d->m_inBlockSelectionMode) + if (d->m_inBlockSelectionMode && !textCursor().hasSelection()) { + d->m_inBlockSelectionMode = false; + d->m_blockSelection.clear(); viewport()->update(); - if (!d->m_inBlockSelectionMode) - d->m_blockSelectionExtraX = 0; + } + if (!d->m_selectBlockAnchor.isNull() && !textCursor().hasSelection()) d->m_selectBlockAnchor = QTextCursor(); @@ -1092,9 +1092,6 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) d->m_moveLineUndoHack = false; d->clearVisibleFoldedBlock(); - QKeyEvent *original_e = e; - d->m_lastEventWasBlockSelectionEvent = false; - if (e->key() == Qt::Key_Escape) { if (d->m_snippetOverlay->isVisible()) { e->accept(); @@ -1182,16 +1179,20 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) } else if (!ro && (e == QKeySequence::MoveToStartOfBlock || e == QKeySequence::SelectStartOfBlock)){ - if ((e->modifiers() & (Qt::AltModifier | Qt::ShiftModifier)) == (Qt::AltModifier | Qt::ShiftModifier)) - d->m_lastEventWasBlockSelectionEvent = true; + if ((e->modifiers() & (Qt::AltModifier | Qt::ShiftModifier)) == (Qt::AltModifier | Qt::ShiftModifier)) { + e->accept(); + return; + } handleHomeKey(e == QKeySequence::SelectStartOfBlock); e->accept(); return; } else if (!ro && (e == QKeySequence::MoveToStartOfLine || e == QKeySequence::SelectStartOfLine)){ - if ((e->modifiers() & (Qt::AltModifier | Qt::ShiftModifier)) == (Qt::AltModifier | Qt::ShiftModifier)) - d->m_lastEventWasBlockSelectionEvent = true; + if ((e->modifiers() & (Qt::AltModifier | Qt::ShiftModifier)) == (Qt::AltModifier | Qt::ShiftModifier)) { + e->accept(); + return; + } QTextCursor cursor = textCursor(); if (QTextLayout *layout = cursor.block().layout()) { if (layout->lineForTextPosition(cursor.position() - cursor.block().position()).lineNumber() == 0) { @@ -1273,36 +1274,23 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) return; } // fall through - case Qt::Key_End: case Qt::Key_Right: case Qt::Key_Left: #ifndef Q_WS_MAC if ((e->modifiers() & (Qt::AltModifier | Qt::ShiftModifier)) == (Qt::AltModifier | Qt::ShiftModifier)) { - - d->m_lastEventWasBlockSelectionEvent = true; - - if (d->m_inBlockSelectionMode) { - if (e->key() == Qt::Key_Right && textCursor().atBlockEnd()) { - d->m_blockSelectionExtraX++; - viewport()->update(); - e->accept(); - return; - } else if (e->key() == Qt::Key_Left && d->m_blockSelectionExtraX > 0) { - d->m_blockSelectionExtraX--; - e->accept(); - viewport()->update(); - return; - } - } - - e = new QKeyEvent( - e->type(), - e->key(), - e->modifiers() & ~Qt::AltModifier, - e->text(), - e->isAutoRepeat(), - e->count() - ); + int diff_row = 0; + int diff_col = 0; + if (e->key() == Qt::Key_Up) + diff_row = -1; + else if (e->key() == Qt::Key_Down) + diff_row = 1; + else if (e->key() == Qt::Key_Left) + diff_col = -1; + else if (e->key() == Qt::Key_Right) + diff_col = 1; + handleBlockSelection(diff_row, diff_col); + e->accept(); + return; } #endif break; @@ -1395,8 +1383,6 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) maybeRequestAutoCompletion(e->text().at(0)); } - if (e != original_e) - delete e; } void BaseTextEditor::maybeRequestAutoCompletion(const QChar &ch) @@ -1934,10 +1920,9 @@ BaseTextEditorPrivate::BaseTextEditorPrivate() m_editable(0), m_actionHack(0), m_inBlockSelectionMode(false), - m_lastEventWasBlockSelectionEvent(false), - m_blockSelectionExtraX(-1), m_moveLineUndoHack(false), - m_findScopeVerticalBlockSelection(0), + m_findScopeVerticalBlockSelectionFirstColumn(-1), + m_findScopeVerticalBlockSelectionLastColumn(-1), m_highlightBlocksTimer(0), m_requestAutoCompletionRevision(0), m_requestAutoCompletionPosition(0), @@ -2158,12 +2143,6 @@ void BaseTextEditorPrivate::highlightSearchResults(const QTextBlock &block, int idx = -1; int l = 1; - int m_findScopeFirstColumn = 0; - if (!m_findScopeStart.isNull() && m_findScopeVerticalBlockSelection) { - m_findScopeFirstColumn = m_findScopeStart.positionInBlock() + 1; - } - - while (idx < text.length()) { idx = m_searchExpr.indexIn(text, idx + l); if (idx < 0) @@ -2176,17 +2155,8 @@ void BaseTextEditorPrivate::highlightSearchResults(const QTextBlock &block, || (idx + l < text.length() && text.at(idx + l).isLetterOrNumber()))) continue; - if (!m_findScopeStart.isNull()) { - if (blockPosition + idx < m_findScopeStart.position() - || blockPosition + idx + l > m_findScopeEnd.position()) - continue; - if (m_findScopeVerticalBlockSelection) { - if (idx < m_findScopeFirstColumn - || idx + l > m_findScopeFirstColumn + m_findScopeVerticalBlockSelection) - continue; - } - } - + if (!q->inFindScope(blockPosition + idx, blockPosition + idx + l)) + continue; overlay->addOverlaySelection(blockPosition + idx, blockPosition + idx + l, @@ -2216,6 +2186,7 @@ void BaseTextEditorPrivate::clearBlockSelection() { if (m_inBlockSelectionMode) { m_inBlockSelectionMode = false; + m_blockSelection.clear(); QTextCursor cursor = q->textCursor(); cursor.clearSelection(); q->setTextCursor(cursor); @@ -2224,68 +2195,77 @@ void BaseTextEditorPrivate::clearBlockSelection() QString BaseTextEditorPrivate::copyBlockSelection() { - QString text; - + QString selection; QTextCursor cursor = q->textCursor(); - if (!cursor.hasSelection()) - return text; - - QTextDocument *doc = q->document(); - int start = cursor.selectionStart(); - int end = cursor.selectionEnd(); - QTextBlock startBlock = doc->findBlock(start); - int columnA = start - startBlock.position(); - QTextBlock endBlock = doc->findBlock(end); - int columnB = end - endBlock.position(); - int firstColumn = qMin(columnA, columnB); - int lastColumn = qMax(columnA, columnB) + m_blockSelectionExtraX; - - QTextBlock block = startBlock; + if (!m_inBlockSelectionMode) + return selection; + const TabSettings &ts = q->tabSettings(); + QTextBlock block = m_blockSelection.firstBlock.block(); + QTextBlock lastBlock = m_blockSelection.lastBlock.block(); for (;;) { + QString text = block.text(); + int startOffset = 0; + int startPos = ts.positionAtColumn(text, m_blockSelection.firstVisualColumn, &startOffset); + int endOffset = 0; + int endPos = ts.positionAtColumn(text, m_blockSelection.lastVisualColumn, &endOffset); - cursor.setPosition(block.position() + qMin(block.length()-1, firstColumn)); - cursor.setPosition(block.position() + qMin(block.length()-1, lastColumn), QTextCursor::KeepAnchor); - text += cursor.selectedText(); - if (block == endBlock) + if (startPos == endPos) { + selection += QString(endOffset - startOffset, QLatin1Char(' ')); + } else { + if (startOffset < 0) + selection += QString(-startOffset, QLatin1Char(' ')); + if (endOffset < 0) + --endPos; + selection += text.mid(startPos, endPos - startPos); + if (endOffset < 0) { + selection += QString(ts.m_tabSize + endOffset, QLatin1Char(' ')); + } else if (endOffset > 0) { + selection += QString(endOffset, QLatin1Char(' ')); + } + } + if (block == lastBlock) break; - text += QLatin1Char('\n'); + selection += QLatin1Char('\n'); block = block.next(); } - - return text; + return selection; } void BaseTextEditorPrivate::removeBlockSelection(const QString &text) { QTextCursor cursor = q->textCursor(); - if (!cursor.hasSelection()) + if (!cursor.hasSelection() || !m_inBlockSelectionMode) return; - QTextDocument *doc = q->document(); - int start = cursor.selectionStart(); - int end = cursor.selectionEnd(); - QTextBlock startBlock = doc->findBlock(start); - int columnA = start - startBlock.position(); - QTextBlock endBlock = doc->findBlock(end); - int columnB = end - endBlock.position(); - int firstColumn = qMin(columnA, columnB); - int lastColumn = qMax(columnA, columnB) + m_blockSelectionExtraX; - + int cursorPosition = cursor.selectionStart(); cursor.clearSelection(); cursor.beginEditBlock(); - QTextBlock block = startBlock; + const TabSettings &ts = q->tabSettings(); + QTextBlock block = m_blockSelection.firstBlock.block(); + QTextBlock lastBlock = m_blockSelection.lastBlock.block(); for (;;) { + QString text = block.text(); + int startOffset = 0; + int startPos = ts.positionAtColumn(text, m_blockSelection.firstVisualColumn, &startOffset); + int endOffset = 0; + int endPos = ts.positionAtColumn(text, m_blockSelection.lastVisualColumn, &endOffset); - cursor.setPosition(block.position() + qMin(block.length()-1, firstColumn)); - cursor.setPosition(block.position() + qMin(block.length()-1, lastColumn), QTextCursor::KeepAnchor); + cursor.setPosition(block.position() + startPos); + cursor.setPosition(block.position() + endPos, QTextCursor::KeepAnchor); cursor.removeSelectedText(); - if (block == endBlock) + + if (startOffset < 0) + cursor.insertText(QString(ts.m_tabSize + startOffset, QLatin1Char(' '))); + if (endOffset < 0) + cursor.insertText(QString(-endOffset, QLatin1Char(' '))); + + if (block == lastBlock) break; block = block.next(); } - cursor.setPosition(start); + cursor.setPosition(cursorPosition); if (!text.isEmpty()) cursor.insertText(text); cursor.endEditBlock(); @@ -2448,37 +2428,25 @@ void BaseTextEditor::paintEvent(QPaintEvent *e) } } - - - if (!d->m_findScopeStart.isNull()) { + if (!d->m_findScopeStart.isNull() && d->m_findScopeVerticalBlockSelectionFirstColumn < 0) { TextEditorOverlay *overlay = new TextEditorOverlay(this); overlay->addOverlaySelection(d->m_findScopeStart.position(), d->m_findScopeEnd.position(), d->m_searchScopeFormat.background().color().darker(120), d->m_searchScopeFormat.background().color(), - TextEditorOverlay::ExpandBegin, - d->m_findScopeVerticalBlockSelection); + TextEditorOverlay::ExpandBegin); overlay->setAlpha(false); overlay->paint(&painter, e->rect()); delete overlay; } - BlockSelectionData *blockSelection = 0; + int blockSelectionIndex = -1; if (d->m_inBlockSelectionMode && context.selections.count() && context.selections.last().cursor == textCursor()) { - blockSelection = new BlockSelectionData; - blockSelection->selectionIndex = context.selections.size()-1; - const QAbstractTextDocumentLayout::Selection &selection = context.selections[blockSelection->selectionIndex]; - int start = blockSelection->selectionStart = selection.cursor.selectionStart(); - int end = blockSelection->selectionEnd = selection.cursor.selectionEnd(); - QTextBlock block = doc->findBlock(start); - int columnA = start - block.position(); - block = doc->findBlock(end); - int columnB = end - block.position(); - blockSelection->firstColumn = qMin(columnA, columnB); - blockSelection->lastColumn = qMax(columnA, columnB) + d->m_blockSelectionExtraX; + blockSelectionIndex = context.selections.size()-1; + context.selections[blockSelectionIndex].format.clearBackground(); } QTextBlock visibleCollapsedBlock; @@ -2517,6 +2485,74 @@ void BaseTextEditor::paintEvent(QPaintEvent *e) } // end first pass + // possible extra pass for the block selection find scope + if (!d->m_findScopeStart.isNull() && d->m_findScopeVerticalBlockSelectionFirstColumn >= 0) { + QTextBlock blockFS = block; + QPointF offsetFS = offset; + + while (blockFS.isValid()) { + + QRectF r = blockBoundingRect(blockFS).translated(offsetFS); + + if (r.bottom() >= er.top() && r.top() <= er.bottom()) { + + if (blockFS.position() >= d->m_findScopeStart.block().position() + && blockFS.position() <= d->m_findScopeEnd.block().position()) { + QTextLayout *layout = blockFS.layout(); + QString text = blockFS.text(); + const TabSettings &ts = tabSettings(); + int spacew = fontMetrics().width(QChar(QLatin1Char(' '))); + + int offset = 0; + int relativePos = ts.positionAtColumn(text, + d->m_findScopeVerticalBlockSelectionFirstColumn, + &offset); + QTextLine line = layout->lineForTextPosition(relativePos); + qreal x = line.cursorToX(relativePos) + offset * spacew; + + int eoffset = 0; + int erelativePos = ts.positionAtColumn(text, + d->m_findScopeVerticalBlockSelectionLastColumn, + &eoffset); + QTextLine eline = layout->lineForTextPosition(erelativePos); + qreal ex = eline.cursorToX(erelativePos) + eoffset * spacew; + + QRectF rr = line.naturalTextRect(); + rr.moveTop(rr.top() + r.top()); + rr.setLeft(r.left() + x); + if (line.lineNumber() == eline.lineNumber()) { + rr.setRight(r.left() + ex); + } + painter.fillRect(rr, d->m_searchScopeFormat.background()); + + QColor lineCol = d->m_searchScopeFormat.background().color().darker(120); + QPen pen = painter.pen(); + painter.setPen(lineCol); + if (blockFS == d->m_findScopeStart.block()) + painter.drawLine(rr.topLeft(), rr.topRight()); + if (blockFS == d->m_findScopeEnd.block()) + painter.drawLine(rr.bottomLeft(), rr.bottomRight()); + painter.drawLine(rr.topLeft(), rr.bottomLeft()); + painter.drawLine(rr.topRight(), rr.bottomRight()); + painter.setPen(pen); + } + } + offsetFS.ry() += r.height(); + + if (offsetFS.y() > viewportRect.height()) + break; + + blockFS = blockFS.next(); + if (!blockFS.isVisible()) { + // invisible blocks do have zero line count + blockFS = doc->findBlockByLineNumber(blockFS.firstLineNumber()); + } + + } + } + + + d->m_searchResultOverlay->fill(&painter, d->m_searchResultFormat.background().color(), e->rect()); @@ -2565,9 +2601,11 @@ void BaseTextEditor::paintEvent(QPaintEvent *e) o.start = selStart; o.length = selEnd - selStart; o.format = range.format; - if (blockSelection && blockSelection->selectionIndex == i) { - o.start = qMin(blockSelection->firstColumn, bllen-1); - o.length = qMin(blockSelection->lastColumn, bllen-1) - o.start; + if (i == blockSelectionIndex) { + QString text = block.text(); + const TabSettings &ts = tabSettings(); + o.start = ts.positionAtColumn(text, d->m_blockSelection.firstVisualColumn); + o.length = ts.positionAtColumn(text, d->m_blockSelection.lastVisualColumn) - o.start; } if ((hasMainSelection && i == context.selections.size()-1) || (o.format.foreground().style() == Qt::NoBrush @@ -2609,6 +2647,62 @@ void BaseTextEditor::paintEvent(QPaintEvent *e) painter.fillRect(rr, color); } + + QRectF blockSelectionCursorRect; + if (d->m_inBlockSelectionMode + && block.position() >= d->m_blockSelection.firstBlock.block().position() + && block.position() <= d->m_blockSelection.lastBlock.block().position()) { + QString text = block.text(); + const TabSettings &ts = tabSettings(); + int spacew = fontMetrics().width(QChar(QLatin1Char(' '))); + + int offset = 0; + int relativePos = ts.positionAtColumn(text, d->m_blockSelection.firstVisualColumn, &offset); + QTextLine line = layout->lineForTextPosition(relativePos); + qreal x = line.cursorToX(relativePos) + offset * spacew; + + int eoffset = 0; + int erelativePos = ts.positionAtColumn(text, d->m_blockSelection.lastVisualColumn, &eoffset); + QTextLine eline = layout->lineForTextPosition(erelativePos); + qreal ex = eline.cursorToX(erelativePos) + eoffset * spacew; + + QRectF rr = line.naturalTextRect(); + rr.moveTop(rr.top() + r.top()); + rr.setLeft(r.left() + x); + if (line.lineNumber() == eline.lineNumber()) { + rr.setRight(r.left() + ex); + } + painter.fillRect(rr, palette().highlight()); + if ((d->m_blockSelection.anchor == BaseTextBlockSelection::TopLeft + && block == d->m_blockSelection.firstBlock.block()) + || (d->m_blockSelection.anchor == BaseTextBlockSelection::BottomLeft + && block == d->m_blockSelection.lastBlock.block()) + ) { + rr.setRight(rr.left()+2); + blockSelectionCursorRect = rr; + } + for (int i = line.lineNumber() + 1; i < eline.lineNumber(); ++i) { + rr = layout->lineAt(i).naturalTextRect(); + rr.moveTop(rr.top() + r.top()); + rr.setLeft(r.left() + x); + painter.fillRect(rr, palette().highlight()); + } + + rr = eline.naturalTextRect(); + rr.moveTop(rr.top() + r.top()); + rr.setRight(r.left() + ex); + if (line.lineNumber() != eline.lineNumber()) + painter.fillRect(rr, palette().highlight()); + if ((d->m_blockSelection.anchor == BaseTextBlockSelection::TopRight + && block == d->m_blockSelection.firstBlock.block()) + || (d->m_blockSelection.anchor == BaseTextBlockSelection::BottomRight + && block == d->m_blockSelection.lastBlock.block())) { + rr.setLeft(rr.right()-2); + blockSelectionCursorRect = rr; + } + } + + bool drawCursor = ((editable || true) // we want the cursor in read-only mode && context.cursorPosition >= blpos && context.cursorPosition < blpos + bllen); @@ -2665,6 +2759,12 @@ void BaseTextEditor::paintEvent(QPaintEvent *e) cursor_cpos = cpos; cursor_pen = painter.pen(); } + +#ifndef Q_WS_MAC // no visible cursor on mac + if (blockSelectionCursorRect.isValid()) + painter.fillRect(blockSelectionCursorRect, palette().text()); +#endif + } offset.ry() += r.height(); @@ -2693,8 +2793,6 @@ void BaseTextEditor::paintEvent(QPaintEvent *e) //end QPlainTextEdit::paintEvent() - delete blockSelection; - offset = contentOffset(); block = firstVisibleBlock(); @@ -2822,22 +2920,27 @@ void BaseTextEditor::paintEvent(QPaintEvent *e) d->m_animator->draw(&painter, cursorRect(cursor).topLeft()); } - if (d->m_overlay->isVisible()) - d->m_overlay->paint(&painter, e->rect()); + // draw the overlays, but only if we do not have a find scope, otherwise the + // view becomes too noisy. + if (d->m_findScopeStart.isNull()) { + if (d->m_overlay->isVisible()) + d->m_overlay->paint(&painter, e->rect()); - if (d->m_snippetOverlay->isVisible()) - d->m_snippetOverlay->paint(&painter, e->rect()); + if (d->m_snippetOverlay->isVisible()) + d->m_snippetOverlay->paint(&painter, e->rect()); + + if (!d->m_refactorOverlay->isEmpty()) + d->m_refactorOverlay->paint(&painter, e->rect()); + } if (!d->m_searchResultOverlay->isEmpty()) { d->m_searchResultOverlay->paint(&painter, e->rect()); d->m_searchResultOverlay->clear(); } - if (!d->m_refactorOverlay->isEmpty()) - d->m_refactorOverlay->paint(&painter, e->rect()); // draw the cursor last, on top of everything - if (cursor_layout) { + if (cursor_layout && !d->m_inBlockSelectionMode) { painter.setPen(cursor_pen); cursor_layout->drawCursor(&painter, cursor_offset, cursor_cpos, cursorWidth()); } @@ -2897,6 +3000,7 @@ void BaseTextEditor::drawCollapsedBlockPopup(QPainter &painter, layout->draw(&painter, offset, selections, clip); b.setVisible(false); // restore previous state + b.setLineCount(0); // restore 0 line count for invisible block offset.ry() += r.height(); b = b.next(); } @@ -3421,8 +3525,6 @@ void BaseTextEditorPrivate::clearVisibleFoldedBlock() void BaseTextEditor::mouseMoveEvent(QMouseEvent *e) { - d->m_lastEventWasBlockSelectionEvent = (e->modifiers() & Qt::AltModifier); - updateLink(e); if (e->buttons() == Qt::NoButton) { @@ -3447,12 +3549,23 @@ void BaseTextEditor::mouseMoveEvent(QMouseEvent *e) } } else { QPlainTextEdit::mouseMoveEvent(e); - } - if (d->m_lastEventWasBlockSelectionEvent && d->m_inBlockSelectionMode) { - if (textCursor().atBlockEnd()) { - d->m_blockSelectionExtraX = qMax(0, e->pos().x() - cursorRect().center().x()) / fontMetrics().averageCharWidth(); - } else { - d->m_blockSelectionExtraX = 0; + + if (e->modifiers() & Qt::AltModifier) { + if (!d->m_inBlockSelectionMode) { + d->m_blockSelection.fromSelection(tabSettings(), textCursor()); + d->m_inBlockSelectionMode = true; + } else { + QTextCursor cursor = textCursor(); + + // get visual column + int column = tabSettings().columnAt(cursor.block().text(), cursor.positionInBlock()); + if (cursor.positionInBlock() == cursor.block().length()-1) { + column += (e->pos().x() - cursorRect().center().x())/fontMetrics().width(QChar(QLatin1Char(' '))); + } + d->m_blockSelection.moveAnchor(cursor.blockNumber(), column); + setTextCursor(d->m_blockSelection.selection(tabSettings())); + viewport()->update(); + } } } if (viewport()->cursor().shape() == Qt::BlankCursor) @@ -4306,16 +4419,18 @@ void BaseTextEditor::highlightSearchResults(const QString &txt, Find::FindFlags d->m_delayedUpdateTimer->start(10); } -int BaseTextEditor::verticalBlockSelection() const +int BaseTextEditor::verticalBlockSelectionFirstColumn() const { - if (!d->m_inBlockSelectionMode) - return 0; - QTextCursor b = textCursor(); - QTextCursor e = b; - b.setPosition(b.selectionStart()); - e.setPosition(e.selectionEnd()); + if (d->m_inBlockSelectionMode) + return d->m_blockSelection.firstVisualColumn; + return -1; +} - return qAbs(b.positionInBlock() - e.positionInBlock()) + d->m_blockSelectionExtraX; +int BaseTextEditor::verticalBlockSelectionLastColumn() const +{ + if (d->m_inBlockSelectionMode) + return d->m_blockSelection.lastVisualColumn; + return -1; } QRegion BaseTextEditor::translatedLineRegion(int lineStart, int lineEnd) const @@ -4337,12 +4452,18 @@ QRegion BaseTextEditor::translatedLineRegion(int lineStart, int lineEnd) const return region; } -void BaseTextEditor::setFindScope(const QTextCursor &start, const QTextCursor &end, int verticalBlockSelection) +void BaseTextEditor::setFindScope(const QTextCursor &start, const QTextCursor &end, + int verticalBlockSelectionFirstColumn, + int verticalBlockSelectionLastColumn) { - if (start != d->m_findScopeStart || end != d->m_findScopeEnd) { + if (start != d->m_findScopeStart + || end != d->m_findScopeEnd + || verticalBlockSelectionFirstColumn != d->m_findScopeVerticalBlockSelectionFirstColumn + || verticalBlockSelectionLastColumn != d->m_findScopeVerticalBlockSelectionLastColumn) { d->m_findScopeStart = start; d->m_findScopeEnd = end; - d->m_findScopeVerticalBlockSelection = verticalBlockSelection; + d->m_findScopeVerticalBlockSelectionFirstColumn = verticalBlockSelectionFirstColumn; + d->m_findScopeVerticalBlockSelectionLastColumn = verticalBlockSelectionLastColumn; viewport()->update(); } } @@ -5247,21 +5368,27 @@ void BaseTextEditor::insertFromMimeData(const QMimeData *source) QStringList lines = text.split(QLatin1Char('\n')); QTextCursor cursor = textCursor(); cursor.beginEditBlock(); + const TabSettings &ts = d->m_document->tabSettings(); int initialCursorPosition = cursor.position(); - int column = cursor.position() - cursor.block().position(); + int column = ts.columnAt(cursor.block().text(), cursor.positionInBlock()); cursor.insertText(lines.first()); for (int i = 1; i < lines.count(); ++i) { QTextBlock next = cursor.block().next(); if (next.isValid()) { - cursor.setPosition(next.position() + qMin(column, next.length()-1)); + cursor.setPosition(next.position()); } else { cursor.movePosition(QTextCursor::EndOfBlock); cursor.insertBlock(); } - - int actualColumn = cursor.position() - cursor.block().position(); - if (actualColumn < column) - cursor.insertText(QString(column - actualColumn, QLatin1Char(' '))); + int offset = 0; + int position = ts.positionAtColumn(cursor.block().text(), column, &offset); + cursor.setPosition(cursor.block().position() + position); + if (offset < 0) { + cursor.deleteChar(); + cursor.insertText(QString(-offset, QLatin1Char(' '))); + } else { + cursor.insertText(QString(offset, QLatin1Char(' '))); + } cursor.insertText(lines.at(i)); } cursor.setPosition(initialCursorPosition); @@ -5359,8 +5486,8 @@ BaseTextEditorEditable::BaseTextEditorEditable(BaseTextEditor *editor) BaseTextFind *baseTextFind = new BaseTextFind(editor); connect(baseTextFind, SIGNAL(highlightAll(QString, Find::FindFlags)), editor, SLOT(highlightSearchResults(QString, Find::FindFlags))); - connect(baseTextFind, SIGNAL(findScopeChanged(QTextCursor, QTextCursor, int)), - editor, SLOT(setFindScope(QTextCursor, QTextCursor, int))); + connect(baseTextFind, SIGNAL(findScopeChanged(QTextCursor, QTextCursor, int, int)), + editor, SLOT(setFindScope(QTextCursor, QTextCursor, int, int))); aggregate->add(baseTextFind); aggregate->add(editor); @@ -5524,3 +5651,125 @@ void BaseTextEditor::doFoo() { setRefactorMarkers(markers); #endif } + +void Internal::BaseTextBlockSelection::moveAnchor(int blockNumber, int visualColumn) +{ + if (visualColumn >= 0) { + if (anchor % 2) { + lastVisualColumn = visualColumn; + if (lastVisualColumn < firstVisualColumn) { + qSwap(firstVisualColumn, lastVisualColumn); + anchor = (Anchor) (anchor - 1); + } + } else { + firstVisualColumn = visualColumn; + if (firstVisualColumn > lastVisualColumn) { + qSwap(firstVisualColumn, lastVisualColumn); + anchor = (Anchor) (anchor + 1); + } + } + } + + if (blockNumber >= 0 && blockNumber < firstBlock.document()->blockCount()) { + if (anchor <= TopRight) { + firstBlock.setPosition(firstBlock.document()->findBlockByNumber(blockNumber).position()); + if (firstBlock.blockNumber() > lastBlock.blockNumber()) { + qSwap(firstBlock, lastBlock); + anchor = (Anchor) (anchor + 2); + } + } else { + lastBlock.setPosition(firstBlock.document()->findBlockByNumber(blockNumber).position()); + if (lastBlock.blockNumber() < firstBlock.blockNumber()) { + qSwap(firstBlock, lastBlock); + anchor = (Anchor) (anchor - 2); + } + } + } + firstBlock.movePosition(QTextCursor::StartOfBlock); + lastBlock.movePosition(QTextCursor::EndOfBlock); +} + +QTextCursor Internal::BaseTextBlockSelection::selection(const TabSettings &ts) const +{ + QTextCursor cursor = firstBlock; + if (anchor <= TopRight) { + cursor.setPosition(lastBlock.block().position() + ts.positionAtColumn(lastBlock.block().text(), lastVisualColumn)); + cursor.setPosition(firstBlock.block().position() + ts.positionAtColumn(firstBlock.block().text(), firstVisualColumn), + QTextCursor::KeepAnchor); + } else { + cursor.setPosition(firstBlock.block().position() + ts.positionAtColumn(firstBlock.block().text(), firstVisualColumn)); + cursor.setPosition(lastBlock.block().position() + ts.positionAtColumn(lastBlock.block().text(), lastVisualColumn), + QTextCursor::KeepAnchor); + } + return cursor; +} + +void Internal::BaseTextBlockSelection::fromSelection(const TabSettings &ts, const QTextCursor &selection) +{ + firstBlock = selection; + firstBlock.setPosition(selection.selectionStart()); + firstVisualColumn = ts.columnAt(firstBlock.block().text(), firstBlock.positionInBlock()); + lastBlock = selection; + lastBlock.setPosition(selection.selectionEnd()); + lastVisualColumn = ts.columnAt(lastBlock.block().text(), lastBlock.positionInBlock()); + if (selection.anchor() > selection.position()) + anchor = TopLeft; + else + anchor = BottomRight; + + firstBlock.movePosition(QTextCursor::StartOfBlock); + lastBlock.movePosition(QTextCursor::EndOfBlock); +} +bool BaseTextEditor::inFindScope(const QTextCursor &cursor) +{ + if (cursor.isNull()) + return false; + return inFindScope(cursor.selectionStart(), cursor.selectionEnd()); +} + +bool BaseTextEditor::inFindScope(int selectionStart, int selectionEnd) +{ + if (d->m_findScopeStart.isNull()) + return true; // no scope, everything is included + if (selectionStart < d->m_findScopeStart.position()) + return false; + if (selectionEnd > d->m_findScopeEnd.position()) + return false; + if (d->m_findScopeVerticalBlockSelectionFirstColumn < 0) + return true; + QTextBlock block = document()->findBlock(selectionStart); + if (block != document()->findBlock(selectionEnd)) + return false; + QString text = block.text(); + const TabSettings &ts = tabSettings(); + int startPosition = ts.positionAtColumn(text, d->m_findScopeVerticalBlockSelectionFirstColumn); + int endPosition = ts.positionAtColumn(text, d->m_findScopeVerticalBlockSelectionLastColumn); + if (selectionStart - block.position() < startPosition) + return false; + if (selectionEnd - block.position() > endPosition) + return false; + return true; +} + +void BaseTextEditor::handleBlockSelection(int diff_row, int diff_col) +{ + + if (!d->m_inBlockSelectionMode) { + d->m_blockSelection.fromSelection(tabSettings(), textCursor()); + d->m_inBlockSelectionMode = true; + } + + d->m_blockSelection.moveAnchor(d->m_blockSelection.anchorBlockNumber() + diff_row, + d->m_blockSelection.anchorColumnNumber() + diff_col); + setTextCursor(d->m_blockSelection.selection(tabSettings())); + + viewport()->update(); + + // ### TODO ensure horizontal visibility +// const bool rtl = q->isRightToLeft(); +// if (cr.left() < visible.left() || cr.right() > visible.right()) { +// int x = cr.center().x() + horizontalOffset() - visible.width()/2; +// hbar->setValue(rtl ? hbar->maximum() - x : x); +// } + +} diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h index ecd0494fce0..2aa8f39f31e 100644 --- a/src/plugins/texteditor/basetexteditor.h +++ b/src/plugins/texteditor/basetexteditor.h @@ -47,6 +47,7 @@ namespace Utils { } namespace TextEditor { +struct TabSettings; namespace Internal { class BaseTextEditorPrivate; @@ -55,6 +56,28 @@ namespace Internal { struct RefactorMarker; typedef QList<RefactorMarker> RefactorMarkers; + class TEXTEDITOR_EXPORT BaseTextBlockSelection + { + public: + + bool isValid() const{ return !firstBlock.isNull() && !lastBlock.isNull(); } + void clear() { firstBlock = lastBlock = QTextCursor(); } + + QTextCursor firstBlock; // defines the first block + QTextCursor lastBlock; // defines the last block + int firstVisualColumn; // defines the first visual column of the selection + int lastVisualColumn; // defines the last visual column of the selection + enum Anchor {TopLeft = 0, TopRight, BottomLeft, BottomRight} anchor; + BaseTextBlockSelection():firstVisualColumn(0), lastVisualColumn(0), anchor(BottomRight){} + void moveAnchor(int blockNumber, int visualColumn); + inline int anchorColumnNumber() const { return (anchor % 2) ? lastVisualColumn : firstVisualColumn; } + inline int anchorBlockNumber() const { + return (anchor <= TopRight ? firstBlock.blockNumber() : lastBlock.blockNumber()); } + QTextCursor selection(const TabSettings &ts) const; + void fromSelection(const TabSettings &ts, const QTextCursor &selection); + }; + + } class ITextMarkable; @@ -66,8 +89,6 @@ struct BehaviorSettings; struct CompletionSettings; struct DisplaySettings; struct StorageSettings; -struct TabSettings; - class TEXTEDITOR_EXPORT BaseTextEditorAnimator : public QObject { @@ -113,8 +134,8 @@ private: class TEXTEDITOR_EXPORT BaseTextEditor : public QPlainTextEdit { Q_OBJECT - Q_PROPERTY(int verticalBlockSelection READ verticalBlockSelection) - + Q_PROPERTY(int verticalBlockSelectionFirstColumn READ verticalBlockSelectionFirstColumn) + Q_PROPERTY(int verticalBlockSelectionLastColumn READ verticalBlockSelectionLastColumn) public: BaseTextEditor(QWidget *parent); ~BaseTextEditor(); @@ -214,7 +235,8 @@ public: void insertCodeSnippet(const QTextCursor &cursor, const QString &snippet); - int verticalBlockSelection() const; + int verticalBlockSelectionFirstColumn() const; + int verticalBlockSelectionLastColumn() const; QRegion translatedLineRegion(int lineStart, int lineEnd) const; @@ -315,7 +337,9 @@ private slots: void documentAboutToBeReloaded(); void documentReloaded(); void highlightSearchResults(const QString &txt, Find::FindFlags findFlags); - void setFindScope(const QTextCursor &start, const QTextCursor &end, int); + void setFindScope(const QTextCursor &start, const QTextCursor &end, int, int); + bool inFindScope(const QTextCursor &cursor); + bool inFindScope(int selectionStart, int selectionEnd); void currentEditorChanged(Core::IEditor *editor); void maybeEmitContentsChangedBecauseOfUndo(); @@ -532,6 +556,8 @@ private slots: // auto completion void _q_requestAutoCompletion(); + void handleBlockSelection(int diff_row, int diff_col); + // parentheses matcher void _q_matchParentheses(); void _q_highlightBlocks(); diff --git a/src/plugins/texteditor/basetexteditor_p.h b/src/plugins/texteditor/basetexteditor_p.h index a344349be54..c16803a1bf8 100644 --- a/src/plugins/texteditor/basetexteditor_p.h +++ b/src/plugins/texteditor/basetexteditor_p.h @@ -245,8 +245,6 @@ public: // block selection mode bool m_inBlockSelectionMode; - bool m_lastEventWasBlockSelectionEvent; - int m_blockSelectionExtraX; void clearBlockSelection(); QString copyBlockSelection(); void removeBlockSelection(const QString &text = QString()); @@ -254,9 +252,13 @@ public: QTextCursor m_findScopeStart; QTextCursor m_findScopeEnd; - int m_findScopeVerticalBlockSelection; + int m_findScopeVerticalBlockSelectionFirstColumn; + int m_findScopeVerticalBlockSelectionLastColumn; + QTextCursor m_selectBlockAnchor; + Internal::BaseTextBlockSelection m_blockSelection; + void moveCursorVisible(bool ensureVisible = true); int visualIndent(const QTextBlock &block) const; diff --git a/src/plugins/texteditor/tabsettings.cpp b/src/plugins/texteditor/tabsettings.cpp index e02d13d74fa..b9772bb37a2 100644 --- a/src/plugins/texteditor/tabsettings.cpp +++ b/src/plugins/texteditor/tabsettings.cpp @@ -226,6 +226,22 @@ int TabSettings::columnAt(const QString &text, int position) const return column; } +int TabSettings::positionAtColumn(const QString &text, int column, int *offset) const +{ + int col = 0; + int i = 0; + while (i < text.size() && col < column) { + if (text.at(i) == QLatin1Char('\t')) + col = col - (col % m_tabSize) + m_tabSize; + else + ++col; + ++i; + } + if (offset) + *offset = column - col; + return i; +} + int TabSettings::spacesLeftFromPosition(const QString &text, int position) const { int i = position; diff --git a/src/plugins/texteditor/tabsettings.h b/src/plugins/texteditor/tabsettings.h index ae63e116a81..edccbbe1986 100644 --- a/src/plugins/texteditor/tabsettings.h +++ b/src/plugins/texteditor/tabsettings.h @@ -61,6 +61,7 @@ struct TEXTEDITOR_EXPORT TabSettings int firstNonSpace(const QString &text) const; inline bool onlySpace(const QString &text) const { return firstNonSpace(text) == text.length(); } int columnAt(const QString &text, int position) const; + int positionAtColumn(const QString &text, int column, int *offset = 0) const; int spacesLeftFromPosition(const QString &text, int position) const; int indentedColumn(int column, bool doIndent = true) const; QString indentationString(int startColumn, int targetColumn, const QTextBlock ¤tBlock = QTextBlock()) const; diff --git a/src/plugins/texteditor/texteditoroverlay.cpp b/src/plugins/texteditor/texteditoroverlay.cpp index 20d38fae38a..a9bc6d76347 100644 --- a/src/plugins/texteditor/texteditoroverlay.cpp +++ b/src/plugins/texteditor/texteditoroverlay.cpp @@ -72,8 +72,7 @@ void TextEditorOverlay::clear() void TextEditorOverlay::addOverlaySelection(int begin, int end, const QColor &fg, const QColor &bg, - uint overlaySelectionFlags, - int verticalBlockSelection) + uint overlaySelectionFlags) { if (end < begin) return; @@ -84,14 +83,15 @@ void TextEditorOverlay::addOverlaySelection(int begin, int end, selection.m_fg = fg; selection.m_bg = bg; + selection.m_cursor_begin = QTextCursor(document->docHandle(), begin); + selection.m_cursor_end = QTextCursor(document->docHandle(), end); + if (overlaySelectionFlags & ExpandBegin) { if (begin > 0 && begin < end) { // not empty - selection.m_expandBegin = true; + selection.m_cursor_begin.setKeepPositionOnInsert(true); } } - selection.m_cursor_begin = QTextCursor(document->docHandle(), begin); - selection.m_cursor_end = QTextCursor(document->docHandle(), end); if (overlaySelectionFlags & LockSize) selection.m_fixedLength = (end - begin); @@ -99,8 +99,6 @@ void TextEditorOverlay::addOverlaySelection(int begin, int end, selection.m_dropShadow = (overlaySelectionFlags & DropShadow); - selection.m_verticalBlockSelection = verticalBlockSelection; - m_selections.append(selection); update(); } @@ -108,11 +106,9 @@ void TextEditorOverlay::addOverlaySelection(int begin, int end, void TextEditorOverlay::addOverlaySelection(const QTextCursor &cursor, const QColor &fg, const QColor &bg, - uint overlaySelectionFlags, - int verticalBlockSelection) + uint overlaySelectionFlags) { - addOverlaySelection(cursor.selectionStart(), cursor.selectionEnd(), fg, bg, overlaySelectionFlags, - verticalBlockSelection); + addOverlaySelection(cursor.selectionStart(), cursor.selectionEnd(), fg, bg, overlaySelectionFlags); } QRect TextEditorOverlay::rect() const @@ -121,7 +117,7 @@ QRect TextEditorOverlay::rect() const } QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, const QTextCursor &end, - const QRect &clip, int verticalBlockSelection) + const QRect &clip) { if (begin.isNull() || end.isNull() || begin.position() > end.position()) return QPainterPath(); @@ -173,8 +169,6 @@ QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, co line = blockLayout->lineForTextPosition(beginChar); inSelection = true; firstOrLastBlock = true; - } else if (verticalBlockSelection) { - beginChar = qMin(block.length()-1, begin.positionInBlock()); } else { while (beginChar < block.length() && document->characterAt(block.position() + beginChar).isSpace()) ++beginChar; @@ -189,8 +183,6 @@ QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, co lastLine = blockLayout->lineForTextPosition(endChar).lineNumber(); inSelection = false; firstOrLastBlock = true; - } else if (verticalBlockSelection) { - endChar = qMin(block.length()-1, begin.positionInBlock() + verticalBlockSelection); } else { endChar = block.length(); while (endChar > beginChar && document->characterAt(block.position() + endChar - 1).isSpace()) @@ -211,7 +203,7 @@ QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, co lineRect.setRight(line.cursorToX(endChar)); selection += lineRect.translated(blockGeometry.topLeft()); } - } else if (!verticalBlockSelection){ // empty lines + } else { // empty lines const int emptyLineSelectionSize = 16; if (!firstOrLastBlock && !selection.isEmpty()) { // middle lineRect.setLeft(selection.last().left()); @@ -315,8 +307,6 @@ void TextEditorOverlay::paintSelection(QPainter *painter, { QTextCursor begin = selection.m_cursor_begin; - if (selection.m_expandBegin) - begin.setPosition(begin.position() + 1); const QTextCursor &end= selection.m_cursor_end; const QColor &fg = selection.m_fg; @@ -328,8 +318,7 @@ void TextEditorOverlay::paintSelection(QPainter *painter, || begin.position() > end.position()) return; - QPainterPath path = createSelectionPath(begin, end, m_editor->viewport()->rect(), - selection.m_verticalBlockSelection); + QPainterPath path = createSelectionPath(begin, end, m_editor->viewport()->rect()); painter->save(); QColor penColor = fg; @@ -389,8 +378,7 @@ void TextEditorOverlay::fillSelection(QPainter *painter, if (begin.isNull() || end.isNull() || begin.position() > end.position()) return; - QPainterPath path = createSelectionPath(begin, end, m_editor->viewport()->rect(), - selection.m_verticalBlockSelection); + QPainterPath path = createSelectionPath(begin, end, m_editor->viewport()->rect()); painter->save(); painter->translate(-.5, -.5); diff --git a/src/plugins/texteditor/texteditoroverlay.h b/src/plugins/texteditor/texteditoroverlay.h index 7cc9593c6d1..59fa6ed7cf2 100644 --- a/src/plugins/texteditor/texteditoroverlay.h +++ b/src/plugins/texteditor/texteditoroverlay.h @@ -37,17 +37,14 @@ namespace TextEditor { namespace Internal { struct TEXTEDITOR_EXPORT OverlaySelection { - OverlaySelection():m_fixedLength(-1), m_dropShadow(false), - m_expandBegin(false), m_verticalBlockSelection(0){} + OverlaySelection():m_fixedLength(-1), m_dropShadow(false){} QTextCursor m_cursor_begin; QTextCursor m_cursor_end; QColor m_fg; QColor m_bg; int m_fixedLength; bool m_dropShadow; - bool m_expandBegin; - int m_verticalBlockSelection; -}; + }; class TEXTEDITOR_EXPORT TextEditorOverlay : public QObject { @@ -92,9 +89,9 @@ public: }; void addOverlaySelection(const QTextCursor &cursor, const QColor &fg, const QColor &bg, - uint overlaySelectionFlags = 0, int verticalBlockSelection = 0); + uint overlaySelectionFlags = 0); void addOverlaySelection(int begin, int end, const QColor &fg, const QColor &bg, - uint overlaySelectionFlags = 0, int verticalBlockSelection = 0); + uint overlaySelectionFlags = 0); inline bool isEmpty() const { return m_selections.isEmpty(); } @@ -103,8 +100,7 @@ public: bool hasCursorInSelection(const QTextCursor &cursor) const; private: - QPainterPath createSelectionPath(const QTextCursor &begin, const QTextCursor &end, const QRect& clip, - int verticalBlockSelection); + QPainterPath createSelectionPath(const QTextCursor &begin, const QTextCursor &end, const QRect& clip); void paintSelection(QPainter *painter, const OverlaySelection &selection); void fillSelection(QPainter *painter, const OverlaySelection &selection, const QColor &color); -- GitLab