From 04794c29cee0d97fb3b32e1c71a072e34ee37e9c Mon Sep 17 00:00:00 2001
From: Andrew den Exter <andrew.den-exter@nokia.com>
Date: Fri, 20 Apr 2012 11:40:40 +1000
Subject: [PATCH] Fix eliding when text width is reset by an implicitWidth
 change.

After emitting implicit size changed signals, reevaluate any conditions
that were dependent on the validity of the item dimensions.

Change-Id: Ie4ee0c87a22cf82752c207c69d426056c36ede67
Reviewed-by: Martin Jones <martin.jones@nokia.com>
---
 src/quick/items/qquickitem.cpp                | 14 +++--
 src/quick/items/qquicktext.cpp                | 45 +++++++---------
 .../quick/qquickitem2/data/implicitsize.qml   | 15 ++++++
 .../auto/quick/qquickitem2/tst_qquickitem.cpp | 42 +++++++++++++++
 .../auto/quick/qquicktext/tst_qquicktext.cpp  | 52 +++++++++++++++++++
 5 files changed, 138 insertions(+), 30 deletions(-)

diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 628e19dbec..cf06dc228f 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -4600,7 +4600,9 @@ void QQuickItem::setImplicitWidth(qreal w)
     if (d->width == w || widthValid()) {
         if (changed)
             d->implicitWidthChanged();
-        return;
+        if (d->width == w || widthValid())
+            return;
+        changed = false;
     }
 
     qreal oldWidth = d->width;
@@ -4695,7 +4697,9 @@ void QQuickItem::setImplicitHeight(qreal h)
     if (d->height == h || heightValid()) {
         if (changed)
             d->implicitHeightChanged();
-        return;
+        if (d->height == h || heightValid())
+            return;
+        changed = false;
     }
 
     qreal oldHeight = d->height;
@@ -4724,12 +4728,14 @@ void QQuickItem::setImplicitSize(qreal w, qreal h)
     if (d->width == w || widthValid()) {
         if (wChanged)
             d->implicitWidthChanged();
-        wDone = true;
+        wDone = d->width == w || widthValid();
+        wChanged = false;
     }
     if (d->height == h || heightValid()) {
         if (hChanged)
             d->implicitHeightChanged();
-        hDone = true;
+        hDone = d->height == h || heightValid();
+        hChanged = false;
     }
     if (wDone && hDone)
         return;
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index f52138cfa8..2a6a6da19d 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -700,8 +700,9 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
     layout.setTextOption(textOption);
     layout.setFont(font);
 
-    if ((q->widthValid() && q->width() <= 0. && elideMode != QQuickText::ElideNone)
-            || (q->heightValid() && q->height() <= 0. && wrapMode != QQuickText::NoWrap && elideMode == QQuickText::ElideRight)) {
+    if (!requireImplicitWidth
+            && ((q->widthValid() && q->width() <= 0. && elideMode != QQuickText::ElideNone)
+            || (q->heightValid() && q->height() <= 0. && wrapMode != QQuickText::NoWrap && elideMode == QQuickText::ElideRight))) {
         // we are elided and we have a zero width or height
         if (!truncated) {
             truncated = true;
@@ -712,25 +713,6 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
             emit q->lineCountChanged();
         }
 
-        if (requireImplicitWidth) {
-            // Layout to determine the implicit width.
-            layout.beginLayout();
-
-            for (int i = 0; i < maximumLineCount(); ++i) {
-                QTextLine line = layout.createLine();
-                if (!line.isValid())
-                    break;
-            }
-            layout.endLayout();
-            *naturalWidth = layout.maximumWidth();
-            layout.clearLayout();
-
-            bool wasInLayout = internalWidthUpdate;
-            internalWidthUpdate = true;
-            q->setImplicitWidth(*naturalWidth);
-            internalWidthUpdate = wasInLayout;
-        }
-
         QFontMetricsF fm(font);
         qreal height = (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : fm.height() * lineHeight();
         *baseline = fm.ascent();
@@ -743,15 +725,16 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
     const bool customLayout = isLineLaidOutConnected();
     const bool wasTruncated = truncated;
 
-    const bool singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
-    const bool multilineElide = elideMode == QQuickText::ElideRight
+    bool singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
+    bool multilineElide = elideMode == QQuickText::ElideRight
             && q->widthValid()
             && (q->heightValid() || maximumLineCountValid);
-    const bool canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
+    bool canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
 
-    const bool horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid();
-    const bool verticalFit = fontSizeMode() & QQuickText::VerticalFit
+    bool horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid();
+    bool verticalFit = fontSizeMode() & QQuickText::VerticalFit
             && (q->heightValid() || (maximumLineCountValid && canWrap));
+
     const bool pixelSize = font.pixelSize() != -1;
     QString layoutText = layout.text();
 
@@ -922,6 +905,16 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
             q->setImplicitWidth(*naturalWidth);
             internalWidthUpdate = wasInLayout;
 
+            singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
+            multilineElide = elideMode == QQuickText::ElideRight
+                    && q->widthValid()
+                    && (q->heightValid() || maximumLineCountValid);
+            canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
+
+            horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid();
+            verticalFit = fontSizeMode() & QQuickText::VerticalFit
+                    && (q->heightValid() || (maximumLineCountValid && canWrap));
+
             const qreal oldWidth = lineWidth;
             lineWidth = q->widthValid() && q->width() > 0 ? q->width() : FLT_MAX;
             if (lineWidth != oldWidth && (singlelineElide || multilineElide || canWrap || horizontalFit))
diff --git a/tests/auto/quick/qquickitem2/data/implicitsize.qml b/tests/auto/quick/qquickitem2/data/implicitsize.qml
index cc6aaf7d60..756e230a87 100644
--- a/tests/auto/quick/qquickitem2/data/implicitsize.qml
+++ b/tests/auto/quick/qquickitem2/data/implicitsize.qml
@@ -16,4 +16,19 @@ Item {
         implicitWidth = 150
         implicitHeight = 80
     }
+
+    function increaseImplicit() {
+        implicitWidth = 200
+        implicitHeight = 100
+    }
+
+    function assignImplicitBinding() {
+        width = Qt.binding(function() { return implicitWidth < 175 ? implicitWidth : 175 })
+        height = Qt.binding(function() { return implicitHeight < 90 ? implicitHeight : 90 })
+    }
+
+    function assignUndefinedBinding() {
+        width = Qt.binding(function() { return implicitWidth < 175 ? undefined : 175 })
+        height = Qt.binding(function() { return implicitHeight < 90 ? undefined : 90 })
+    }
 }
diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
index 34f51875c9..44b05586ce 100644
--- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
@@ -1350,6 +1350,48 @@ void tst_QQuickItem::implicitSize()
     QCOMPARE(item->width(), qreal(150));
     QCOMPARE(item->height(), qreal(80));
 
+    QMetaObject::invokeMethod(item, "assignImplicitBinding");
+
+    QCOMPARE(item->implicitWidth(), qreal(150));
+    QCOMPARE(item->implicitHeight(), qreal(80));
+    QCOMPARE(item->width(), qreal(150));
+    QCOMPARE(item->height(), qreal(80));
+
+    QMetaObject::invokeMethod(item, "increaseImplicit");
+
+    QCOMPARE(item->implicitWidth(), qreal(200));
+    QCOMPARE(item->implicitHeight(), qreal(100));
+    QCOMPARE(item->width(), qreal(175));
+    QCOMPARE(item->height(), qreal(90));
+
+    QMetaObject::invokeMethod(item, "changeImplicit");
+
+    QCOMPARE(item->implicitWidth(), qreal(150));
+    QCOMPARE(item->implicitHeight(), qreal(80));
+    QCOMPARE(item->width(), qreal(150));
+    QCOMPARE(item->height(), qreal(80));
+
+    QMetaObject::invokeMethod(item, "assignUndefinedBinding");
+
+    QCOMPARE(item->implicitWidth(), qreal(150));
+    QCOMPARE(item->implicitHeight(), qreal(80));
+    QCOMPARE(item->width(), qreal(150));
+    QCOMPARE(item->height(), qreal(80));
+
+    QMetaObject::invokeMethod(item, "increaseImplicit");
+
+    QCOMPARE(item->implicitWidth(), qreal(200));
+    QCOMPARE(item->implicitHeight(), qreal(100));
+    QCOMPARE(item->width(), qreal(175));
+    QCOMPARE(item->height(), qreal(90));
+
+    QMetaObject::invokeMethod(item, "changeImplicit");
+
+    QCOMPARE(item->implicitWidth(), qreal(150));
+    QCOMPARE(item->implicitHeight(), qreal(80));
+    QCOMPARE(item->width(), qreal(150));
+    QCOMPARE(item->height(), qreal(80));
+
     delete canvas;
 }
 
diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
index 125e056dad..297fa0106f 100644
--- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
@@ -72,6 +72,8 @@ private slots:
     void elide();
     void multilineElide_data();
     void multilineElide();
+    void implicitElide_data();
+    void implicitElide();
     void textFormat();
 
     void alignments_data();
@@ -531,6 +533,56 @@ void tst_qquicktext::multilineElide()
     delete canvas;
 }
 
+void tst_qquicktext::implicitElide_data()
+{
+    QTest::addColumn<QString>("width");
+    QTest::addColumn<QString>("initialText");
+    QTest::addColumn<QString>("text");
+
+    QTest::newRow("maximum width, empty")
+            << "Math.min(implicitWidth, 100)"
+            << "";
+    QTest::newRow("maximum width, short")
+            << "Math.min(implicitWidth, 100)"
+            << "the";
+    QTest::newRow("maximum width, long")
+            << "Math.min(implicitWidth, 100)"
+            << "the quick brown fox jumped over the lazy dog";
+    QTest::newRow("reset width, empty")
+            << "implicitWidth > 100 ? 100 : undefined"
+            << "";
+    QTest::newRow("reset width, short")
+            << "implicitWidth > 100 ? 100 : undefined"
+            << "the";
+    QTest::newRow("reset width, long")
+            << "implicitWidth > 100 ? 100 : undefined"
+            << "the quick brown fox jumped over the lazy dog";
+}
+
+void tst_qquicktext::implicitElide()
+{
+    QFETCH(QString, width);
+    QFETCH(QString, initialText);
+
+    QString componentStr =
+            "import QtQuick 2.0\n"
+            "Text {\n"
+                "width: " + width + "\n"
+                "text: \"" + initialText + "\"\n"
+                "elide: Text.ElideRight\n"
+            "}";
+    QQmlComponent textComponent(&engine);
+    textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+    QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+
+    QVERIFY(textObject->contentWidth() <= textObject->width());
+
+    textObject->setText("the quick brown fox jumped over");
+
+    QVERIFY(textObject->contentWidth() > 0);
+    QVERIFY(textObject->contentWidth() <= textObject->width());
+}
+
 void tst_qquicktext::textFormat()
 {
     {
-- 
GitLab