summaryrefslogtreecommitdiffstats
path: root/src/gui/text/qtextdocument.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/text/qtextdocument.cpp')
-rw-r--r--src/gui/text/qtextdocument.cpp270
1 files changed, 225 insertions, 45 deletions
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index 77e0fec80d..d3b70aaf26 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -40,6 +40,7 @@
#include "qtextlist.h"
#include <qdebug.h>
#include <qregexp.h>
+#include <qregularexpression.h>
#include <qvarlengtharray.h>
#include <qtextcodec.h>
#include <qthread.h>
@@ -1141,6 +1142,9 @@ void QTextDocument::setMetaInformation(MetaInformation info, const QString &stri
Returns the plain text contained in the document. If you want
formatting information use a QTextCursor instead.
+ \note Embedded objects, such as images, are represented by a
+ Unicode value U+FFFC (OBJECT REPLACEMENT CHARACTER).
+
\sa toHtml()
*/
QString QTextDocument::toPlainText() const
@@ -1244,6 +1248,39 @@ void QTextDocument::setHtml(const QString &html)
\sa metaInformation(), setMetaInformation()
*/
+static bool findInBlock(const QTextBlock &block, const QString &expression, int offset,
+ QTextDocument::FindFlags options, QTextCursor *cursor)
+{
+ QString text = block.text();
+ text.replace(QChar::Nbsp, QLatin1Char(' '));
+ Qt::CaseSensitivity sensitivity = options & QTextDocument::FindCaseSensitively ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ int idx = -1;
+
+ while (offset >= 0 && offset <= text.length()) {
+ idx = (options & QTextDocument::FindBackward) ?
+ text.lastIndexOf(expression, offset, sensitivity) : text.indexOf(expression, offset, sensitivity);
+ if (idx == -1)
+ return false;
+
+ if (options & QTextDocument::FindWholeWords) {
+ const int start = idx;
+ const int end = start + expression.length();
+ 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.
+ *cursor = QTextCursor(block.docHandle(), block.position() + idx);
+ cursor->setPosition(cursor->position() + expression.length(), QTextCursor::KeepAnchor);
+ return true;
+ }
+ return false;
+}
+
/*!
\fn QTextCursor QTextDocument::find(const QString &subString, int position, FindFlags options) const
@@ -1262,16 +1299,44 @@ void QTextDocument::setHtml(const QString &html)
*/
QTextCursor QTextDocument::find(const QString &subString, int from, FindFlags options) const
{
- QRegExp expr(subString);
- expr.setPatternSyntax(QRegExp::FixedString);
- expr.setCaseSensitivity((options & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive);
+ Q_D(const QTextDocument);
+
+ if (subString.isEmpty())
+ 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 < subString.size())
+ return QTextCursor();
+ }
+
+ QTextCursor cursor;
+ QTextBlock block = d->blocksFind(pos);
+ int blockOffset = pos - block.position();
+
+ if (!(options & FindBackward)) {
+ while (block.isValid()) {
+ if (findInBlock(block, subString, blockOffset, options, &cursor))
+ return cursor;
+ block = block.next();
+ blockOffset = 0;
+ }
+ } else {
+ while (block.isValid()) {
+ if (findInBlock(block, subString, blockOffset, options, &cursor))
+ return cursor;
+ block = block.previous();
+ blockOffset = block.length() - 2;
+ }
+ }
- return find(expr, from, options);
+ return QTextCursor();
}
/*!
- \fn QTextCursor QTextDocument::find(const QString &subString, const QTextCursor &cursor, FindFlags options) const
-
Finds the next occurrence of the string, \a subString, in the document.
The search starts at the position of the given \a cursor, and proceeds
forwards through the document unless specified otherwise in the search
@@ -1286,25 +1351,23 @@ QTextCursor QTextDocument::find(const QString &subString, int from, FindFlags op
By default the search is case-sensitive, and can match text anywhere in the
document.
*/
-QTextCursor QTextDocument::find(const QString &subString, const QTextCursor &from, FindFlags options) const
+QTextCursor QTextDocument::find(const QString &subString, const QTextCursor &cursor, FindFlags options) const
{
int pos = 0;
- if (!from.isNull()) {
+ if (!cursor.isNull()) {
if (options & QTextDocument::FindBackward)
- pos = from.selectionStart();
+ pos = cursor.selectionStart();
else
- pos = from.selectionEnd();
+ pos = cursor.selectionEnd();
}
- QRegExp expr(subString);
- expr.setPatternSyntax(QRegExp::FixedString);
- expr.setCaseSensitivity((options & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive);
- return find(expr, pos, options);
+ return find(subString, pos, options);
}
+#ifndef QT_NO_REGEXP
static bool findInBlock(const QTextBlock &block, const QRegExp &expression, int offset,
- QTextDocument::FindFlags options, QTextCursor &cursor)
+ QTextDocument::FindFlags options, QTextCursor *cursor)
{
QRegExp expr(expression);
QString text = block.text();
@@ -1329,22 +1392,18 @@ static bool findInBlock(const QTextBlock &block, const QRegExp &expression, int
}
}
//we have a hit, return the cursor for that.
- break;
+ *cursor = QTextCursor(block.docHandle(), block.position() + idx);
+ cursor->setPosition(cursor->position() + expr.matchedLength(), QTextCursor::KeepAnchor);
+ return true;
}
- if (idx == -1)
- return false;
- cursor = QTextCursor(block.docHandle(), block.position() + idx);
- cursor.setPosition(cursor.position() + expr.matchedLength(), QTextCursor::KeepAnchor);
- return true;
+ return false;
}
/*!
- \fn QTextCursor QTextDocument::find(const QRegExp & expr, int position, FindFlags options) const
-
\overload
Finds the next occurrence, matching the regular expression, \a expr, in the document.
- The search starts at the given \a position, and proceeds forwards
+ 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. The FindCaseSensitively
option is ignored for this overload, use QRegExp::caseSensitivity instead.
@@ -1352,7 +1411,7 @@ static bool findInBlock(const QTextBlock &block, const QRegExp &expression, int
Returns a cursor with the match selected if a match was found; otherwise
returns a null cursor.
- If the \a position is 0 (the default) the search begins from the beginning
+ 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 QRegExp & expr, int from, FindFlags options) const
@@ -1373,19 +1432,17 @@ QTextCursor QTextDocument::find(const QRegExp & expr, int from, FindFlags option
QTextCursor cursor;
QTextBlock block = d->blocksFind(pos);
-
+ int blockOffset = pos - block.position();
if (!(options & FindBackward)) {
- int blockOffset = qMax(0, pos - block.position());
while (block.isValid()) {
- if (findInBlock(block, expr, blockOffset, options, cursor))
+ if (findInBlock(block, expr, blockOffset, options, &cursor))
return cursor;
- blockOffset = 0;
block = block.next();
+ blockOffset = 0;
}
} else {
- int blockOffset = pos - block.position();
while (block.isValid()) {
- if (findInBlock(block, expr, blockOffset, options, cursor))
+ if (findInBlock(block, expr, blockOffset, options, &cursor))
return cursor;
block = block.previous();
blockOffset = block.length() - 1;
@@ -1396,10 +1453,10 @@ QTextCursor QTextDocument::find(const QRegExp & expr, int from, FindFlags option
}
/*!
- \fn QTextCursor QTextDocument::find(const QRegExp &expr, const QTextCursor &cursor, FindFlags options) const
+ \overload
Finds the next occurrence, matching the regular expression, \a expr, in the document.
- The search starts at the position of the given \a cursor, and proceeds
+ The search starts at the position of the given from \a cursor, and proceeds
forwards through the document unless specified otherwise in the search
options. The \a options control the type of search performed. The FindCaseSensitively
option is ignored for this overload, use QRegExp::caseSensitivity instead.
@@ -1407,24 +1464,147 @@ QTextCursor QTextDocument::find(const QRegExp & expr, int from, FindFlags option
Returns a cursor with the match selected if a match was found; otherwise
returns a null cursor.
- If the given \a cursor has a selection, the search begins after the
+ 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 QRegExp &expr, const QTextCursor &from, FindFlags options) const
+QTextCursor QTextDocument::find(const QRegExp &expr, const QTextCursor &cursor, FindFlags options) const
{
int pos = 0;
- if (!from.isNull()) {
+ if (!cursor.isNull()) {
if (options & QTextDocument::FindBackward)
- pos = from.selectionStart();
+ pos = cursor.selectionStart();
else
- pos = from.selectionEnd();
+ pos = cursor.selectionEnd();
}
return find(expr, pos, options);
}
+#endif // QT_REGEXP
+
+#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.
+ *cursor = QTextCursor(block.docHandle(), block.position() + idx);
+ cursor->setPosition(cursor->position() + match.capturedLength(), QTextCursor::KeepAnchor);
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \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);
+ int blockOffset = pos - block.position();
+
+ if (!(options & FindBackward)) {
+ while (block.isValid()) {
+ if (findInBlock(block, expr, blockOffset, options, &cursor))
+ return cursor;
+ block = block.next();
+ blockOffset = 0;
+ }
+ } else {
+ 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 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 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 &cursor, FindFlags options) const
+{
+ int pos = 0;
+ if (!cursor.isNull()) {
+ if (options & QTextDocument::FindBackward)
+ pos = cursor.selectionStart();
+ else
+ pos = cursor.selectionEnd();
+ }
+ return find(expr, pos, options);
+}
+#endif // QT_NO_REGULAREXPRESSION
/*!
\fn QTextObject *QTextDocument::createObject(const QTextFormat &format)