From 4066a6a893dcaa1258e4801fe9e8d2d7624e37f7 Mon Sep 17 00:00:00 2001 From: Samuel Gaist Date: Wed, 27 Aug 2014 23:14:59 +0200 Subject: Add QRegularExpression support to QTextDocument Currently QTextDocuement only provides find using QRegExp. This patch aims to add support for QRegularExpression. [ChangeLog][QtGui][QTextDocument] Support for searching with a QRegularExpression in a document has been added. Change-Id: I6dba10545b83995d093407038a821fe54db3d261 Reviewed-by: Simon Hausmann --- src/gui/text/qtextdocument.cpp | 126 +++++++++++++++++++++++++++++++++++++++++ src/gui/text/qtextdocument.h | 6 +- 2 files changed, 131 insertions(+), 1 deletion(-) (limited to 'src/gui') diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index fa54776b6d..438fa75492 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -48,6 +48,7 @@ #include "qtextlist.h" #include #include +#include #include #include #include @@ -1432,6 +1433,131 @@ QTextCursor QTextDocument::find(const QRegExp &expr, const QTextCursor &from, Fi return find(expr, pos, options); } +#ifndef QT_NO_REGULAREXPRESSION +static bool findInBlock(const QTextBlock &block, const QRegularExpression &expression, int offset, + QTextDocument::FindFlags options, QTextCursor *cursor) +{ + QRegularExpression expr(expression); + if (!(options & QTextDocument::FindCaseSensitively)) + expr.setPatternOptions(expr.patternOptions() | QRegularExpression::CaseInsensitiveOption); + else + expr.setPatternOptions(expr.patternOptions() & ~QRegularExpression::CaseInsensitiveOption); + + QString text = block.text(); + text.replace(QChar::Nbsp, QLatin1Char(' ')); + QRegularExpressionMatch match; + int idx = -1; + + while (offset >= 0 && offset <= text.length()) { + idx = (options & QTextDocument::FindBackward) ? + text.lastIndexOf(expr, offset, &match) : text.indexOf(expr, offset, &match); + if (idx == -1) + return false; + + if (options & QTextDocument::FindWholeWords) { + const int start = idx; + const int end = start + match.capturedLength(); + if ((start != 0 && text.at(start - 1).isLetterOrNumber()) + || (end != text.length() && text.at(end).isLetterOrNumber())) { + //if this is not a whole word, continue the search in the string + offset = (options & QTextDocument::FindBackward) ? idx-1 : end+1; + idx = -1; + continue; + } + } + //we have a hit, return the cursor for that. + break; + } + if (idx == -1) + return false; + *cursor = qMove(QTextCursor(block.docHandle(), block.position() + idx)); + cursor->setPosition(cursor->position() + match.capturedLength(), QTextCursor::KeepAnchor); + return true; +} + +/*! + \since 5.5 + + Finds the next occurrence, matching the regular expression, \a expr, in the document. + The search starts at the given \a from position, and proceeds forwards + through the document unless specified otherwise in the search options. + The \a options control the type of search performed. + + Returns a cursor with the match selected if a match was found; otherwise + returns a null cursor. + + If the \a from position is 0 (the default) the search begins from the beginning + of the document; otherwise it begins at the specified position. +*/ +QTextCursor QTextDocument::find(const QRegularExpression &expr, int from, FindFlags options) const +{ + Q_D(const QTextDocument); + + if (!expr.isValid()) + return QTextCursor(); + + int pos = from; + //the cursor is positioned between characters, so for a backward search + //do not include the character given in the position. + if (options & FindBackward) { + --pos ; + if (pos < 0) + return QTextCursor(); + } + + QTextCursor cursor; + QTextBlock block = d->blocksFind(pos); + + if (!(options & FindBackward)) { + int blockOffset = qMax(0, pos - block.position()); + while (block.isValid()) { + if (findInBlock(block, expr, blockOffset, options, &cursor)) + return cursor; + blockOffset = 0; + block = block.next(); + } + } else { + int blockOffset = pos - block.position(); + while (block.isValid()) { + if (findInBlock(block, expr, blockOffset, options, &cursor)) + return cursor; + block = block.previous(); + blockOffset = block.length() - 1; + } + } + + return QTextCursor(); +} + +/*! + \since 5.5 + + Finds the next occurrence, matching the regular expression, \a expr, in the document. + The search starts at the position of the given \a from cursor, and proceeds + forwards through the document unless specified otherwise in the search + options. The \a options control the type of search performed. + + Returns a cursor with the match selected if a match was found; otherwise + returns a null cursor. + + If the given \a from cursor has a selection, the search begins after the + selection; otherwise it begins at the cursor's position. + + By default the search is case-sensitive, and can match text anywhere in the + document. +*/ +QTextCursor QTextDocument::find(const QRegularExpression &expr, const QTextCursor &from, FindFlags options) const +{ + int pos = 0; + if (!from.isNull()) { + if (options & QTextDocument::FindBackward) + pos = from.selectionStart(); + else + pos = from.selectionEnd(); + } + return find(expr, pos, options); +} +#endif // QT_NO_REGULAREXPRESSION /*! \fn QTextObject *QTextDocument::createObject(const QTextFormat &format) diff --git a/src/gui/text/qtextdocument.h b/src/gui/text/qtextdocument.h index 854cb29ed9..3f4b8b565b 100644 --- a/src/gui/text/qtextdocument.h +++ b/src/gui/text/qtextdocument.h @@ -169,10 +169,14 @@ public: QTextCursor find(const QString &subString, int from = 0, FindFlags options = 0) const; QTextCursor find(const QString &subString, const QTextCursor &from, FindFlags options = 0) const; - QTextCursor find(const QRegExp &expr, int from = 0, FindFlags options = 0) const; QTextCursor find(const QRegExp &expr, const QTextCursor &from, FindFlags options = 0) const; +#ifndef QT_NO_REGULAREXPRESSION + QTextCursor find(const QRegularExpression &expr, int from = 0, FindFlags options = 0) const; + QTextCursor find(const QRegularExpression &expr, const QTextCursor &from, FindFlags options = 0) const; +#endif + QTextFrame *frameAt(int pos) const; QTextFrame *rootFrame() const; -- cgit v1.2.3