Commit bf28a3db authored by mae's avatar mae

Restrict find & replace to vertical block selection

parent 894fd9d7
......@@ -215,7 +215,7 @@ int BaseTextFind::replaceAll(const QString &before, const QString &after,
QRegExp regexp(before);
regexp.setPatternSyntax(usesRegExp ? QRegExp::RegExp : QRegExp::FixedString);
regexp.setCaseSensitivity((findFlags & IFindSupport::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive);
QTextCursor found = document()->find(regexp, editCursor, IFindSupport::textDocumentFlagsForFindFlags(findFlags));
QTextCursor found = findOne(regexp, editCursor, IFindSupport::textDocumentFlagsForFindFlags(findFlags));
while (!found.isNull() && found.selectionStart() < found.selectionEnd()
&& inScope(found.selectionStart(), found.selectionEnd())) {
++count;
......@@ -224,7 +224,7 @@ int BaseTextFind::replaceAll(const QString &before, const QString &after,
regexp.exactMatch(found.selectedText());
QString realAfter = usesRegExp ? expandRegExpReplacement(after, regexp) : after;
editCursor.insertText(realAfter);
found = document()->find(regexp, editCursor, IFindSupport::textDocumentFlagsForFindFlags(findFlags));
found = findOne(regexp, editCursor, IFindSupport::textDocumentFlagsForFindFlags(findFlags));
}
editCursor.endEditBlock();
return count;
......@@ -241,7 +241,7 @@ bool BaseTextFind::find(const QString &txt,
QRegExp regexp(txt);
regexp.setPatternSyntax((findFlags&IFindSupport::FindRegularExpression) ? QRegExp::RegExp : QRegExp::FixedString);
regexp.setCaseSensitivity((findFlags&IFindSupport::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive);
QTextCursor found = document()->find(regexp, start, IFindSupport::textDocumentFlagsForFindFlags(findFlags));
QTextCursor found = findOne(regexp, start, IFindSupport::textDocumentFlagsForFindFlags(findFlags));
if (!m_findScope.isNull()) {
......@@ -251,7 +251,7 @@ bool BaseTextFind::find(const QString &txt,
start.setPosition(m_findScope.selectionStart());
else
start.setPosition(m_findScope.selectionEnd());
found = document()->find(regexp, start, IFindSupport::textDocumentFlagsForFindFlags(findFlags));
found = findOne(regexp, start, IFindSupport::textDocumentFlagsForFindFlags(findFlags));
if (found.isNull() || !inScope(found.selectionStart(), found.selectionEnd()))
return false;
}
......@@ -263,7 +263,7 @@ bool BaseTextFind::find(const QString &txt,
start.movePosition(QTextCursor::Start);
else
start.movePosition(QTextCursor::End);
found = document()->find(regexp, start, IFindSupport::textDocumentFlagsForFindFlags(findFlags));
found = findOne(regexp, start, IFindSupport::textDocumentFlagsForFindFlags(findFlags));
if (found.isNull()) {
return false;
}
......@@ -275,6 +275,28 @@ bool BaseTextFind::find(const QString &txt,
return true;
}
// helper function. Works just like QTextDocument::find() but supports vertical block selection
QTextCursor BaseTextFind::findOne(const QRegExp &expr, const QTextCursor &from, QTextDocument::FindFlags options) const
{
QTextCursor candidate = document()->find(expr, from, options);
if (!m_findScopeVerticalBlockSelection)
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_findScopeFromColumn
&& e.positionInBlock() <= m_findScopeToColumn)
return candidate;
candidate = document()->find(expr, candidate, options);
}
return candidate;
}
bool BaseTextFind::inScope(int startPosition, int endPosition) const
{
if (m_findScope.isNull())
......@@ -288,8 +310,25 @@ void BaseTextFind::defineFindScope()
QTextCursor cursor = textCursor();
if (cursor.hasSelection() && cursor.block() != cursor.document()->findBlock(cursor.anchor())) {
m_findScope = cursor;
emit findScopeChanged(m_findScope);
cursor.setPosition(cursor.selectionStart());
m_findScopeVerticalBlockSelection = false;
int verticalBlockSelection = 0;
if (m_plaineditor && m_plaineditor->metaObject()->indexOfProperty("verticalBlockSelection") >= 0)
verticalBlockSelection = m_plaineditor->property("verticalBlockSelection").toInt();
if (verticalBlockSelection) {
QTextDocument *doc = document();
QTextCursor b(doc->docHandle(), cursor.selectionStart());
QTextCursor e(doc->docHandle(), cursor.selectionEnd());
m_findScopeFromColumn = qMin(b.positionInBlock(), e.positionInBlock());
m_findScopeToColumn = m_findScopeFromColumn + verticalBlockSelection;
m_findScope.setPosition(b.block().position() + m_findScopeFromColumn);
m_findScope.setPosition(e.block().position() + qMin(e.block().length()-1, m_findScopeToColumn),
QTextCursor::KeepAnchor);
m_findScopeVerticalBlockSelection = verticalBlockSelection;
}
emit findScopeChanged(m_findScope, m_findScopeVerticalBlockSelection);
cursor.setPosition(m_findScope.selectionStart());
setTextCursor(cursor);
} else {
clearFindScope();
......@@ -299,5 +338,6 @@ void BaseTextFind::defineFindScope()
void BaseTextFind::clearFindScope()
{
m_findScope = QTextCursor();
emit findScopeChanged(m_findScope);
m_findScopeVerticalBlockSelection = 0;
emit findScopeChanged(m_findScope, m_findScopeVerticalBlockSelection);
}
......@@ -70,7 +70,7 @@ public:
signals:
void highlightAll(const QString &txt, Find::IFindSupport::FindFlags findFlags);
void findScopeChanged(const QTextCursor &);
void findScopeChanged(const QTextCursor &, int = 0);
private:
bool find(const QString &txt,
......@@ -84,7 +84,11 @@ private:
QPointer<QTextEdit> m_editor;
QPointer<QPlainTextEdit> m_plaineditor;
QTextCursor m_findScope;
int m_findScopeVerticalBlockSelection;
int m_findScopeFromColumn;
int m_findScopeToColumn;
bool inScope(int startPosition, int endPosition) const;
QTextCursor findOne(const QRegExp &expr, const QTextCursor &from, QTextDocument::FindFlags options) const;
int m_incrementalStartPos;
};
......
......@@ -2195,6 +2195,15 @@ void BaseTextEditorPrivate::highlightSearchResults(const QTextBlock &block,
text.replace(QChar::Nbsp, QLatin1Char(' '));
int idx = -1;
int l = 1;
int m_findScopeFirstColumn = 0;
if (!m_findScope.isNull() && m_findScopeVerticalBlockSelection) {
QTextCursor b = cursor;
cursor.setPosition(m_findScope.selectionStart());
m_findScopeFirstColumn = cursor.positionInBlock();
}
while (idx < text.length()) {
idx = m_searchExpr.indexIn(text, idx + l);
if (idx < 0)
......@@ -2205,19 +2214,26 @@ void BaseTextEditorPrivate::highlightSearchResults(const QTextBlock &block,
|| (idx + l < text.length() && text.at(idx + l).isLetterOrNumber())))
continue;
if (m_findScope.isNull()
|| (blockPosition + idx >= m_findScope.selectionStart()
&& blockPosition + idx + l <= m_findScope.selectionEnd())) {
if (!m_findScope.isNull()) {
if (blockPosition + idx < m_findScope.selectionStart()
|| blockPosition + idx + l > m_findScope.selectionEnd())
continue;
if (m_findScopeVerticalBlockSelection) {
if (idx < m_findScopeFirstColumn
|| idx + l > m_findScopeFirstColumn + m_findScopeVerticalBlockSelection)
continue;
}
}
overlay->addOverlaySelection(blockPosition + idx,
blockPosition + idx + l,
m_searchResultFormat.background().color().darker(120),
QColor(),
(idx == cursor.selectionStart() - blockPosition
&& idx + l == cursor.selectionEnd() - blockPosition)?
TextEditorOverlay::DropShadow : 0);
overlay->addOverlaySelection(blockPosition + idx,
blockPosition + idx + l,
m_searchResultFormat.background().color().darker(120),
QColor(),
(idx == cursor.selectionStart() - blockPosition
&& idx + l == cursor.selectionEnd() - blockPosition)?
TextEditorOverlay::DropShadow : 0);
}
}
}
......@@ -2475,7 +2491,9 @@ void BaseTextEditor::paintEvent(QPaintEvent *e)
TextEditorOverlay *overlay = new TextEditorOverlay(this);
overlay->addOverlaySelection(d->m_findScope, d->m_searchScopeFormat.background().color().darker(120),
d->m_searchScopeFormat.background().color());
d->m_searchScopeFormat.background().color(),
0,
d->m_findScopeVerticalBlockSelection);
overlay->setAlpha(false);
overlay->paint(&painter, e->rect());
delete overlay;
......@@ -4674,10 +4692,23 @@ void BaseTextEditor::highlightSearchResults(const QString &txt, Find::IFindSuppo
d->m_delayedUpdateTimer->start(10);
}
void BaseTextEditor::setFindScope(const QTextCursor &scope)
int BaseTextEditor::verticalBlockSelection() const
{
if (!d->m_inBlockSelectionMode)
return 0;
QTextCursor b = textCursor();
QTextCursor e = b;
b.setPosition(b.selectionStart());
e.setPosition(e.selectionEnd());
return qAbs(b.positionInBlock() - e.positionInBlock()) + d->m_blockSelectionExtraX;
}
void BaseTextEditor::setFindScope(const QTextCursor &scope, int verticalBlockSelection)
{
if (scope.isNull() != d->m_findScope.isNull()) {
d->m_findScope = scope;
d->m_findScopeVerticalBlockSelection = verticalBlockSelection;
viewport()->update();
}
}
......@@ -5628,7 +5659,7 @@ BaseTextEditorEditable::BaseTextEditorEditable(BaseTextEditor *editor)
BaseTextFind *baseTextFind = new BaseTextFind(editor);
connect(baseTextFind, SIGNAL(highlightAll(QString, Find::IFindSupport::FindFlags)),
editor, SLOT(highlightSearchResults(QString, Find::IFindSupport::FindFlags)));
connect(baseTextFind, SIGNAL(findScopeChanged(QTextCursor)), editor, SLOT(setFindScope(QTextCursor)));
connect(baseTextFind, SIGNAL(findScopeChanged(QTextCursor, int)), editor, SLOT(setFindScope(QTextCursor, int)));
aggregate->add(baseTextFind);
aggregate->add(editor);
......
......@@ -285,6 +285,7 @@ private:
class TEXTEDITOR_EXPORT BaseTextEditor : public QPlainTextEdit
{
Q_OBJECT
Q_PROPERTY(int verticalBlockSelection READ verticalBlockSelection)
public:
BaseTextEditor(QWidget *parent);
......@@ -382,6 +383,9 @@ public:
void insertCodeSnippet(const QTextCursor &cursor, const QString &snippet);
int verticalBlockSelection() const;
public slots:
void setDisplayName(const QString &title);
......@@ -457,7 +461,7 @@ private slots:
void memorizeCursorPosition();
void restoreCursorPosition();
void highlightSearchResults(const QString &txt, Find::IFindSupport::FindFlags findFlags);
void setFindScope(const QTextCursor &);
void setFindScope(const QTextCursor &, int);
void currentEditorChanged(Core::IEditor *editor);
void maybeEmitContentsChangedBecauseOfUndo();
......
......@@ -250,6 +250,7 @@ public:
bool m_moveLineUndoHack;
QTextCursor m_findScope;
int m_findScopeVerticalBlockSelection;
QTextCursor m_selectBlockAnchor;
void moveCursorVisible(bool ensureVisible = true);
......
......@@ -71,7 +71,8 @@ void TextEditorOverlay::clear()
void TextEditorOverlay::addOverlaySelection(int begin, int end,
const QColor &fg, const QColor &bg,
uint overlaySelectionFlags)
uint overlaySelectionFlags,
int verticalBlockSelection)
{
if (end < begin)
return;
......@@ -97,6 +98,8 @@ void TextEditorOverlay::addOverlaySelection(int begin, int end,
selection.m_dropShadow = (overlaySelectionFlags & DropShadow);
selection.m_verticalBlockSelection = verticalBlockSelection;
m_selections.append(selection);
update();
}
......@@ -104,9 +107,11 @@ void TextEditorOverlay::addOverlaySelection(int begin, int end,
void TextEditorOverlay::addOverlaySelection(const QTextCursor &cursor,
const QColor &fg, const QColor &bg,
uint overlaySelectionFlags)
uint overlaySelectionFlags,
int verticalBlockSelection)
{
addOverlaySelection(cursor.selectionStart(), cursor.selectionEnd(), fg, bg, overlaySelectionFlags);
addOverlaySelection(cursor.selectionStart(), cursor.selectionEnd(), fg, bg, overlaySelectionFlags,
verticalBlockSelection);
}
QRect TextEditorOverlay::rect() const
......@@ -115,7 +120,7 @@ QRect TextEditorOverlay::rect() const
}
QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, const QTextCursor &end,
const QRect &clip)
const QRect &clip, int verticalBlockSelection)
{
if (begin.isNull() || end.isNull() || begin.position() > end.position())
return QPainterPath();
......@@ -129,6 +134,7 @@ QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, co
)
return QPainterPath(); // nothing of the selection is visible
QTextBlock block = begin.block();
bool inSelection = false;
......@@ -159,10 +165,12 @@ QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, co
int beginChar = 0;
if (!inSelection) {
beginChar = begin.position() - begin.block().position();
beginChar = begin.positionInBlock();
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;
......@@ -173,10 +181,12 @@ QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, co
int lastLine = blockLayout->lineCount()-1;
int endChar = -1;
if (block == end.block()) {
endChar = end.position() - end.block().position();
endChar = end.positionInBlock();
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())
......@@ -197,7 +207,7 @@ QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, co
lineRect.setRight(line.cursorToX(endChar));
selection += lineRect.translated(blockGeometry.topLeft());
}
} else { // empty lines
} else if (!verticalBlockSelection){ // empty lines
const int emptyLineSelectionSize = 16;
if (!firstOrLastBlock && !selection.isEmpty()) { // middle
lineRect.setLeft(selection.last().left());
......@@ -314,7 +324,8 @@ void TextEditorOverlay::paintSelection(QPainter *painter,
|| begin.position() > end.position())
return;
QPainterPath path = createSelectionPath(begin, end, m_editor->viewport()->rect());
QPainterPath path = createSelectionPath(begin, end, m_editor->viewport()->rect(),
selection.m_verticalBlockSelection);
painter->save();
QColor penColor = fg;
......@@ -374,7 +385,8 @@ void TextEditorOverlay::fillSelection(QPainter *painter,
if (begin.isNull() || end.isNull() || begin.position() > end.position())
return;
QPainterPath path = createSelectionPath(begin, end, m_editor->viewport()->rect());
QPainterPath path = createSelectionPath(begin, end, m_editor->viewport()->rect(),
selection.m_verticalBlockSelection);
painter->save();
painter->translate(-.5, -.5);
......
......@@ -37,7 +37,8 @@ namespace TextEditor {
namespace Internal {
struct TEXTEDITOR_EXPORT OverlaySelection {
OverlaySelection():m_fixedLength(-1), m_dropShadow(false), m_expandBegin(false){}
OverlaySelection():m_fixedLength(-1), m_dropShadow(false),
m_expandBegin(false), m_verticalBlockSelection(0){}
QTextCursor m_cursor_begin;
QTextCursor m_cursor_end;
QColor m_fg;
......@@ -45,6 +46,7 @@ struct TEXTEDITOR_EXPORT OverlaySelection {
int m_fixedLength;
bool m_dropShadow;
bool m_expandBegin;
int m_verticalBlockSelection;
};
class TEXTEDITOR_EXPORT TextEditorOverlay : public QObject
......@@ -90,9 +92,9 @@ public:
};
void addOverlaySelection(const QTextCursor &cursor, const QColor &fg, const QColor &bg,
uint overlaySelectionFlags = 0);
uint overlaySelectionFlags = 0, int verticalBlockSelection = 0);
void addOverlaySelection(int begin, int end, const QColor &fg, const QColor &bg,
uint overlaySelectionFlags = 0);
uint overlaySelectionFlags = 0, int verticalBlockSelection = 0);
inline bool isEmpty() const { return m_selections.isEmpty(); }
......@@ -101,7 +103,8 @@ public:
bool hasCursorInSelection(const QTextCursor &cursor) const;
private:
QPainterPath createSelectionPath(const QTextCursor &begin, const QTextCursor &end, const QRect& clip);
QPainterPath createSelectionPath(const QTextCursor &begin, const QTextCursor &end, const QRect& clip,
int verticalBlockSelection);
void paintSelection(QPainter *painter, const OverlaySelection &selection);
void fillSelection(QPainter *painter, const OverlaySelection &selection, const QColor &color);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment