summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/text/qtextdocument.cpp126
-rw-r--r--src/gui/text/qtextdocument.h6
-rw-r--r--tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp65
3 files changed, 181 insertions, 16 deletions
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 <qdebug.h>
#include <qregexp.h>
+#include <qregularexpression.h>
#include <qvarlengtharray.h>
#include <qtextcodec.h>
#include <qthread.h>
@@ -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;
diff --git a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp
index 59c951332e..1c74eaa19a 100644
--- a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp
+++ b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp
@@ -86,6 +86,8 @@ private slots:
void find2();
void findWithRegExp_data();
void findWithRegExp();
+ void findWithRegularExpression_data();
+ void findWithRegularExpression();
void findMultiple();
void basicIsModifiedChecks();
void moreIsModified();
@@ -196,6 +198,7 @@ private slots:
private:
void backgroundImage_checkExpectedHtml(const QTextDocument &doc);
+ void buildRegExpData();
QTextDocument *doc;
QTextCursor cursor;
@@ -352,21 +355,7 @@ void tst_QTextDocument::find()
void tst_QTextDocument::findWithRegExp_data()
{
- QTest::addColumn<QString>("haystack");
- QTest::addColumn<QString>("needle");
- QTest::addColumn<int>("flags");
- QTest::addColumn<int>("from");
- QTest::addColumn<int>("anchor");
- QTest::addColumn<int>("position");
-
- // match integers 0 to 99
- QTest::newRow("1") << "23" << "^\\d\\d?$" << int(QTextDocument::FindCaseSensitively) << 0 << 0 << 2;
- // match ampersands but not &amp;
- QTest::newRow("2") << "His &amp; hers & theirs" << "&(?!amp;)"<< int(QTextDocument::FindCaseSensitively) << 0 << 15 << 16;
- //backward search
- QTest::newRow("3") << QString::fromLatin1("HelloBlahWorld Blah Hah")
- << "h" << int(QTextDocument::FindBackward) << 18 << 8 << 9;
-
+ buildRegExpData();
}
void tst_QTextDocument::findWithRegExp()
@@ -393,6 +382,34 @@ void tst_QTextDocument::findWithRegExp()
}
}
+void tst_QTextDocument::findWithRegularExpression_data()
+{
+ buildRegExpData();
+}
+
+void tst_QTextDocument::findWithRegularExpression()
+{
+ QFETCH(QString, haystack);
+ QFETCH(QString, needle);
+ QFETCH(int, flags);
+ QFETCH(int, from);
+ QFETCH(int, anchor);
+ QFETCH(int, position);
+
+ cursor.insertText(haystack);
+ //search using a regular expression
+ QRegularExpression expr(needle);
+ QTextDocument::FindFlags flg(flags);
+ cursor = doc->find(expr, from, flg);
+
+ if (anchor != -1) {
+ QCOMPARE(cursor.anchor(), anchor);
+ QCOMPARE(cursor.position(), position);
+ } else {
+ QVERIFY(cursor.isNull());
+ }
+}
+
void tst_QTextDocument::find2()
{
doc->setPlainText("aaa");
@@ -2602,6 +2619,24 @@ void tst_QTextDocument::backgroundImage_checkExpectedHtml(const QTextDocument &d
QCOMPARE(doc.toHtml(), expectedHtml);
}
+void tst_QTextDocument::buildRegExpData()
+{
+ QTest::addColumn<QString>("haystack");
+ QTest::addColumn<QString>("needle");
+ QTest::addColumn<int>("flags");
+ QTest::addColumn<int>("from");
+ QTest::addColumn<int>("anchor");
+ QTest::addColumn<int>("position");
+
+ // match integers 0 to 99
+ QTest::newRow("1") << "23" << "^\\d\\d?$" << int(QTextDocument::FindCaseSensitively) << 0 << 0 << 2;
+ // match ampersands but not &amp;
+ QTest::newRow("2") << "His &amp; hers & theirs" << "&(?!amp;)"<< int(QTextDocument::FindCaseSensitively) << 0 << 15 << 16;
+ //backward search
+ QTest::newRow("3") << QString::fromLatin1("HelloBlahWorld Blah Hah")
+ << "h" << int(QTextDocument::FindBackward) << 18 << 8 << 9;
+}
+
void tst_QTextDocument::backgroundImage_toHtml()
{
CREATE_DOC_AND_CURSOR();