Avoid creating unnecessary copies of TextEdit's text data.
authorAndrew den Exter <andrew.den-exter@nokia.com>
Wed, 11 Jan 2012 01:00:36 +0000 (11:00 +1000)
committerQt by Nokia <qt-info@nokia.com>
Mon, 16 Jan 2012 10:26:16 +0000 (11:26 +0100)
Delay rebuilding the text data from QTextDocument until it is actually
requested rather than everytime the contents of the document change.

Change-Id: Ibfdc9e9e0372010f0731fb02a223c8b59a67f2c3
Reviewed-by: Martin Jones <martin.jones@nokia.com>
src/quick/items/qquicktextcontrol.cpp
src/quick/items/qquicktextedit.cpp
src/quick/items/qquicktextedit_p.h
src/quick/items/qquicktextedit_p_p.h
tests/auto/qtquick2/qquicktextedit/tst_qquicktextedit.cpp

index 4f9475f..69a2a27 100644 (file)
@@ -624,7 +624,7 @@ QQuickTextControl::QQuickTextControl(QTextDocument *doc, QObject *parent)
     : QObject(*new QQuickTextControlPrivate, parent)
 {
     Q_D(QQuickTextControl);
-    d->init(Qt::RichText, QString(), doc);
+    d->init(Qt::PlainText, QString(), doc);
 }
 
 QQuickTextControl::~QQuickTextControl()
index e971ef7..f56a21b 100644 (file)
@@ -127,13 +127,17 @@ QQuickTextEdit::QQuickTextEdit(QQuickItem *parent)
 QString QQuickTextEdit::text() const
 {
     Q_D(const QQuickTextEdit);
-
+    if (!d->textCached) {
+        QQuickTextEditPrivate *d = const_cast<QQuickTextEditPrivate *>(d_func());
 #ifndef QT_NO_TEXTHTMLPARSER
-    if (d->richText)
-        return d->control->toHtml();
-    else
+        if (d->richText)
+            d->text = d->control->toHtml();
+        else
 #endif
-        return d->control->toPlainText();
+            d->text = d->control->toPlainText();
+        d->textCached = true;
+    }
+    return d->text;
 }
 
 /*!
@@ -320,21 +324,21 @@ void QQuickTextEdit::setTextFormat(TextFormat format)
     Q_D(QQuickTextEdit);
     if (format == d->format)
         return;
+
     bool wasRich = d->richText;
-    d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
+    d->richText = format == RichText || (format == AutoText && (wasRich || Qt::mightBeRichText(text())));
 
+#ifndef QT_NO_TEXTHTMLPARSER
     if (wasRich && !d->richText) {
-        d->control->setPlainText(d->text);
+        d->control->setPlainText(!d->textCached ? d->control->toHtml() : d->text);
         updateSize();
     } else if (!wasRich && d->richText) {
-#ifndef QT_NO_TEXTHTMLPARSER
-        d->control->setHtml(d->text);
-#else
-        d->control->setPlainText(d->text);
-#endif
+        d->control->setHtml(!d->textCached ? d->control->toPlainText() : d->text);
         updateSize();
         d->useImageFallback = qmlEnableImageCache();
     }
+#endif
+
     d->format = format;
     d->control->setAcceptRichText(d->format != PlainText);
     emit textFormatChanged(d->format);
@@ -553,7 +557,7 @@ bool QQuickTextEditPrivate::determineHorizontalAlignment()
     Q_Q(QQuickTextEdit);
     if (hAlignImplicit && q->isComponentComplete()) {
         bool alignToRight;
-        if (text.isEmpty()) {
+        if (document->isEmpty()) {
             const QString preeditText = control->textCursor().block().layout()->preeditAreaText();
             alignToRight = preeditText.isEmpty()
                     ? qApp->inputPanel()->inputDirection() == Qt::RightToLeft
@@ -864,7 +868,7 @@ int QQuickTextEdit::cursorPosition() const
 void QQuickTextEdit::setCursorPosition(int pos)
 {
     Q_D(QQuickTextEdit);
-    if (pos < 0 || pos > d->text.length())
+    if (pos < 0 || pos >= d->document->characterCount()) // characterCount includes the terminating null.
         return;
     QTextCursor cursor = d->control->textCursor();
     if (cursor.position() == pos && cursor.anchor() == pos)
@@ -1338,7 +1342,7 @@ void QQuickTextEdit::selectWord()
 void QQuickTextEdit::select(int start, int end)
 {
     Q_D(QQuickTextEdit);
-    if (start < 0 || end < 0 || start > d->text.length() || end > d->text.length())
+    if (start < 0 || end < 0 || start >= d->document->characterCount() || end >= d->document->characterCount())
         return;
     QTextCursor cursor = d->control->textCursor();
     cursor.beginEditBlock();
@@ -1359,12 +1363,11 @@ void QQuickTextEdit::select(int start, int end)
 */
 bool QQuickTextEdit::isRightToLeft(int start, int end)
 {
-    Q_D(QQuickTextEdit);
     if (start > end) {
         qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
         return false;
     } else {
-        return d->text.mid(start, end - start).isRightToLeft();
+        return getText(start, end).isRightToLeft();
     }
 }
 
@@ -1772,13 +1775,13 @@ void QQuickTextEditPrivate::init()
 void QQuickTextEdit::q_textChanged()
 {
     Q_D(QQuickTextEdit);
-    d->text = text();
+    d->textCached = false;
     d->rightToLeftText = d->document->begin().layout()->engine()->isRightToLeft();
     d->determineHorizontalAlignment();
     d->updateDefaultTextOption();
     updateSize();
     updateTotalLines();
-    emit textChanged(d->text);
+    emit textChanged();
 }
 
 void QQuickTextEdit::moveCursorDelegate()
index f37b7cd..e127416 100644 (file)
@@ -227,7 +227,7 @@ public:
     Q_INVOKABLE QString getFormattedText(int start, int end) const;
 
 Q_SIGNALS:
-    void textChanged(const QString &);
+    void textChanged();
     void paintedSizeChanged();
     void cursorPositionChanged();
     void cursorRectangleChanged();
index fe2172d..bf7edf5 100644 (file)
@@ -74,6 +74,7 @@ public:
       documentDirty(true), dirty(false), richText(false), cursorVisible(false), focusOnPress(true),
       persistentSelection(true), requireImplicitWidth(false), selectByMouse(false), canPaste(false),
       canPasteValid(false), hAlignImplicit(true), rightToLeftText(false), useImageFallback(false),
+      textCached(false),
       textMargin(0.0), lastSelectionStart(0), lastSelectionEnd(0), cursorComponent(0), cursor(0),
       format(QQuickTextEdit::PlainText), document(0), wrapMode(QQuickTextEdit::NoWrap),
       mouseSelectionMode(QQuickTextEdit::SelectCharacters),
@@ -114,6 +115,7 @@ public:
     bool hAlignImplicit:1;
     bool rightToLeftText:1;
     bool useImageFallback:1;
+    bool textCached:1;
 
     qreal textMargin;
     int lastSelectionStart;
index 40dc438..ba63e04 100644 (file)
@@ -2077,7 +2077,7 @@ void tst_qquicktextedit::textInput()
     QVERIFY(edit->hasActiveFocus() == true);
 
     // test that input method event is committed and change signal is emitted
-    QSignalSpy spy(edit, SIGNAL(textChanged(QString)));
+    QSignalSpy spy(edit, SIGNAL(textChanged()));
     QInputMethodEvent event;
     event.setCommitString( "Hello world!", 0, 0);
     QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &event);
@@ -2804,7 +2804,7 @@ void tst_qquicktextedit::insert()
     QSignalSpy selectionSpy(textEdit, SIGNAL(selectionChanged()));
     QSignalSpy selectionStartSpy(textEdit, SIGNAL(selectionStartChanged()));
     QSignalSpy selectionEndSpy(textEdit, SIGNAL(selectionEndChanged()));
-    QSignalSpy textSpy(textEdit, SIGNAL(textChanged(QString)));
+    QSignalSpy textSpy(textEdit, SIGNAL(textChanged()));
     QSignalSpy cursorPositionSpy(textEdit, SIGNAL(cursorPositionChanged()));
 
     textEdit->insert(insertPosition, insertText);
@@ -3049,7 +3049,7 @@ void tst_qquicktextedit::remove()
     QSignalSpy selectionSpy(textEdit, SIGNAL(selectionChanged()));
     QSignalSpy selectionStartSpy(textEdit, SIGNAL(selectionStartChanged()));
     QSignalSpy selectionEndSpy(textEdit, SIGNAL(selectionEndChanged()));
-    QSignalSpy textSpy(textEdit, SIGNAL(textChanged(QString)));
+    QSignalSpy textSpy(textEdit, SIGNAL(textChanged()));
     QSignalSpy cursorPositionSpy(textEdit, SIGNAL(cursorPositionChanged()));
 
     textEdit->remove(removeStart, removeEnd);