aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Jones <martin.jones@nokia.com>2011-11-28 15:32:31 +1000
committerQt by Nokia <qt-info@nokia.com>2011-11-28 07:45:43 +0100
commit7d4a187bc7537b1f6d441aabc1bbcffafd7017e7 (patch)
treeb83e4b2c78e5cc4bfe7795245e21ee6d56423752
parentfb237da846785b72df25c3c9e7e25d377ea308e0 (diff)
Fix multiline eliding and support eliding when height is set.
Task-number: QTBUG-22920, QTBUG-22116 Change-Id: Ibe78ce1b0b438eec32955b986a8740f173cd082f Reviewed-by: Yann Bodson <yann.bodson@nokia.com>
-rw-r--r--src/declarative/items/qquicktext.cpp188
-rw-r--r--src/declarative/items/qquicktext_p_p.h1
-rw-r--r--tests/auto/declarative/qquicktext/data/multilineelide.qml10
-rw-r--r--tests/auto/declarative/qquicktext/tst_qquicktext.cpp44
4 files changed, 154 insertions, 89 deletions
diff --git a/src/declarative/items/qquicktext.cpp b/src/declarative/items/qquicktext.cpp
index e11e4be089..e3286f0b6b 100644
--- a/src/declarative/items/qquicktext.cpp
+++ b/src/declarative/items/qquicktext.cpp
@@ -106,7 +106,7 @@ QQuickTextPrivate::QQuickTextPrivate()
richText(false), styledText(false), singleline(false), cacheAllTextAsImage(true), internalWidthUpdate(false),
requireImplicitWidth(false), truncated(false), hAlignImplicit(true), rightToLeftText(false),
layoutTextElided(false), richTextAsImage(false), textureImageCacheDirty(false), textHasChanged(true),
- naturalWidth(0), doc(0), textLine(0), nodeType(NodeIsNull)
+ naturalWidth(0), doc(0), elipsisLayout(0), textLine(0), nodeType(NodeIsNull)
#if defined(Q_OS_MAC)
, layoutThread(0), paintingThread(0)
@@ -202,6 +202,7 @@ QSet<QUrl> QQuickTextDocumentWithImageResources::errors;
QQuickTextPrivate::~QQuickTextPrivate()
{
+ delete elipsisLayout;
delete textLine; textLine = 0;
}
@@ -224,17 +225,21 @@ void QQuickTextPrivate::updateLayout()
updateOnComponentComplete = true;
return;
}
-
+ updateOnComponentComplete = false;
layoutTextElided = false;
// Setup instance of QTextLayout for all cases other than richtext
if (!richText) {
+ if (elipsisLayout) {
+ delete elipsisLayout;
+ elipsisLayout = 0;
+ }
layout.clearLayout();
layout.setFont(font);
if (!styledText) {
QString tmp = text;
tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
singleline = !tmp.contains(QChar::LineSeparator);
- if (singleline && !maximumLineCountValid && elideMode != QQuickText::ElideNone && q->widthValid()) {
+ if (singleline && !maximumLineCountValid && elideMode != QQuickText::ElideNone && q->widthValid() && wrapMode == QQuickText::NoWrap) {
QFontMetrics fm(font);
tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width());
if (tmp != text) {
@@ -516,9 +521,6 @@ QRect QQuickTextPrivate::setupTextLayout()
textOption.setUseDesignMetrics(true);
layout.setTextOption(textOption);
- bool elideText = false;
- bool truncate = false;
-
QFontMetrics fm(layout.font());
elidePos = QPointF();
@@ -548,86 +550,87 @@ QRect QQuickTextPrivate::setupTextLayout()
}
qreal height = 0;
+ QRectF br;
+
+ bool truncate = false;
bool customLayout = isLineLaidOutConnected();
+ bool elideEnabled = elideMode == QQuickText::ElideRight && q->widthValid();
+
+ layout.beginLayout();
+ if (!lineWidth)
+ lineWidth = INT_MAX;
+ int linesLeft = maximumLineCount;
+ int visibleTextLength = 0;
+ forever {
+ QTextLine line = layout.createLine();
+ if (!line.isValid())
+ break;
- if (maximumLineCountValid) {
- layout.beginLayout();
- if (!lineWidth)
- lineWidth = INT_MAX;
- int linesLeft = maximumLineCount;
- int visibleTextLength = 0;
- while (linesLeft > 0) {
- QTextLine line = layout.createLine();
- if (!line.isValid())
- break;
+ visibleCount++;
- visibleCount++;
+ qreal preLayoutHeight = height;
+ if (customLayout) {
+ setupCustomLineGeometry(line, height);
+ } else if (lineWidth) {
+ line.setLineWidth(lineWidth);
+ line.setPosition(QPointF(line.position().x(), height));
+ height += (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : line.height() * lineHeight;
+ }
- if (customLayout)
- setupCustomLineGeometry(line, height);
- else if (lineWidth)
- line.setLineWidth(lineWidth);
+ bool elide = false;
+ if (elideEnabled && q->heightValid() && height > q->height()) {
+ // This line does not fit in the remaining area.
+ elide = true;
+ if (visibleCount > 1) {
+ --visibleCount;
+ height = preLayoutHeight;
+ line.setLineWidth(0.0);
+ line.setPosition(QPointF(FLT_MAX,FLT_MAX));
+ line = layout.lineAt(visibleCount-1);
+ }
+ } else {
visibleTextLength += line.textLength();
+ }
- if (--linesLeft == 0) {
- if (visibleTextLength < text.length()) {
- truncate = true;
- if (elideMode == QQuickText::ElideRight && q->widthValid()) {
- qreal elideWidth = fm.width(elideChar);
- // Need to correct for alignment
- if (customLayout)
- setupCustomLineGeometry(line, height, elideWidth);
- else
- line.setLineWidth(lineWidth - elideWidth);
- if (layout.text().mid(line.textStart(), line.textLength()).isRightToLeft()) {
- line.setPosition(QPointF(line.position().x() + elideWidth, line.position().y()));
- elidePos.setX(line.naturalTextRect().left() - elideWidth);
- } else {
- elidePos.setX(line.naturalTextRect().right());
- }
- elideText = true;
+ if (elide || (maximumLineCountValid && --linesLeft == 0)) {
+ if (visibleTextLength < text.length()) {
+ truncate = true;
+ if (elideEnabled) {
+ qreal elideWidth = fm.width(elideChar);
+ // Need to correct for alignment
+ if (customLayout)
+ setupCustomLineGeometry(line, height, elideWidth);
+ else
+ line.setLineWidth(lineWidth - elideWidth);
+ if (layout.text().mid(line.textStart(), line.textLength()).isRightToLeft()) {
+ line.setPosition(QPointF(line.position().x() + elideWidth, line.position().y()));
+ elidePos.setX(line.naturalTextRect().left() - elideWidth);
+ } else {
+ elidePos.setX(line.naturalTextRect().right());
}
+ elidePos.setY(line.position().y());
+ if (!elipsisLayout)
+ elipsisLayout = new QTextLayout(elideChar, layout.font());
+ elipsisLayout->beginLayout();
+ QTextLine el = elipsisLayout->createLine();
+ el.setPosition(elidePos);
+ elipsisLayout->endLayout();
+ br = br.united(el.naturalTextRect());
}
- }
- }
- layout.endLayout();
-
- //Update truncated
- if (truncated != truncate) {
- truncated = truncate;
- emit q->truncatedChanged();
- }
- } else {
- layout.beginLayout();
- forever {
- QTextLine line = layout.createLine();
- if (!line.isValid())
+ br = br.united(line.naturalTextRect());
break;
- visibleCount++;
- if (customLayout)
- setupCustomLineGeometry(line, height);
- else {
- if (lineWidth)
- line.setLineWidth(lineWidth);
}
}
- layout.endLayout();
+ br = br.united(line.naturalTextRect());
}
+ layout.endLayout();
- height = 0;
- QRectF br;
- for (int i = 0; i < layout.lineCount(); ++i) {
- QTextLine line = layout.lineAt(i);
- // set line spacing
- if (!customLayout)
- line.setPosition(QPointF(line.position().x(), height));
- if (elideText && i == layout.lineCount()-1) {
- elidePos.setY(height + fm.ascent());
- br = br.united(QRectF(elidePos, QSizeF(fm.width(elideChar), fm.ascent())));
- }
- br = br.united(line.naturalTextRect());
- height += (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : line.height() * lineHeight;
+ //Update truncated
+ if (truncated != truncate) {
+ truncated = truncate;
+ emit q->truncatedChanged();
}
+
if (!customLayout)
br.setHeight(height);
@@ -1295,7 +1298,7 @@ void QQuickText::resetHAlign()
{
Q_D(QQuickText);
d->hAlignImplicit = true;
- if (d->determineHorizontalAlignment() && isComponentComplete())
+ if (isComponentComplete() && d->determineHorizontalAlignment())
d->updateLayout();
}
@@ -1335,8 +1338,7 @@ bool QQuickTextPrivate::setHAlign(QQuickText::HAlignment alignment, bool forceAl
bool QQuickTextPrivate::determineHorizontalAlignment()
{
- Q_Q(QQuickText);
- if (hAlignImplicit && q->isComponentComplete()) {
+ if (hAlignImplicit) {
bool alignToRight = text.isEmpty() ? QGuiApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
return setHAlign(alignToRight ? QQuickText::AlignRight : QQuickText::AlignLeft);
}
@@ -1553,15 +1555,17 @@ void QQuickText::setTextFormat(TextFormat format)
d->richText = format == RichText;
d->styledText = format == StyledText || (format == AutoText && Qt::mightBeRichText(d->text));
- if (!wasRich && d->richText && isComponentComplete()) {
- d->ensureDoc();
- d->doc->setText(d->text);
- d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
- d->richTextAsImage = enableImageCache();
- } else {
- d->rightToLeftText = d->text.isRightToLeft();
+ if (isComponentComplete()) {
+ if (!wasRich && d->richText) {
+ d->ensureDoc();
+ d->doc->setText(d->text);
+ d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
+ d->richTextAsImage = enableImageCache();
+ } else {
+ d->rightToLeftText = d->text.isRightToLeft();
+ }
+ d->determineHorizontalAlignment();
}
- d->determineHorizontalAlignment();
d->updateLayout();
emit textFormatChanged(d->format);
@@ -1584,7 +1588,9 @@ void QQuickText::setTextFormat(TextFormat format)
\endlist
If this property is set to Text.ElideRight, it can be used with multiline
- text. The text will only elide if maximumLineCount has been set.
+ text. The text will only elide if \c maximumLineCount, or \c height has been set.
+ If both \c maximumLineCount and \c height are set, \c maximumLineCount will
+ apply unless the lines do not fit in the height allowed.
If the text is a multi-length string, and the mode is not \c Text.ElideNone,
the first string that fits will be used, otherwise the last will be elided.
@@ -1640,11 +1646,13 @@ QRectF QQuickText::boundingRect() const
void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
Q_D(QQuickText);
- if ((!d->internalWidthUpdate && newGeometry.width() != oldGeometry.width())
+ bool elide = d->elideMode != QQuickText::ElideNone && widthValid();
+ if ((!d->internalWidthUpdate
+ && (newGeometry.width() != oldGeometry.width() || (elide && newGeometry.height() != oldGeometry.height())))
&& (d->wrapMode != QQuickText::NoWrap
|| d->elideMode != QQuickText::ElideNone
|| d->hAlign != QQuickText::AlignLeft)) {
- if ((d->singleline || d->maximumLineCountValid) && d->elideMode != QQuickText::ElideNone && widthValid()) {
+ if ((d->singleline || d->maximumLineCountValid || heightValid()) && elide) {
// We need to re-elide
d->updateLayout();
} else {
@@ -1731,6 +1739,8 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
} else {
node->addTextLayout(QPoint(0, bounds.y()), &d->layout, d->color, d->style, d->styleColor);
+ if (d->elipsisLayout)
+ node->addTextLayout(QPoint(0, bounds.y()), d->elipsisLayout, d->color, d->style, d->styleColor);
}
return node;
@@ -1842,9 +1852,7 @@ int QQuickText::resourcesLoading() const
void QQuickText::componentComplete()
{
Q_D(QQuickText);
- QQuickItem::componentComplete();
if (d->updateOnComponentComplete) {
- d->updateOnComponentComplete = false;
if (d->richText) {
d->ensureDoc();
d->doc->setText(d->text);
@@ -1854,8 +1862,10 @@ void QQuickText::componentComplete()
d->rightToLeftText = d->text.isRightToLeft();
}
d->determineHorizontalAlignment();
- d->updateLayout();
}
+ QQuickItem::componentComplete();
+ if (d->updateOnComponentComplete)
+ d->updateLayout();
}
diff --git a/src/declarative/items/qquicktext_p_p.h b/src/declarative/items/qquicktext_p_p.h
index 16cc29ac13..2035f47a9d 100644
--- a/src/declarative/items/qquicktext_p_p.h
+++ b/src/declarative/items/qquicktext_p_p.h
@@ -140,6 +140,7 @@ public:
bool isLinkActivatedConnected();
QString anchorAt(const QPointF &pos);
QTextLayout layout;
+ QTextLayout *elipsisLayout;
QList<QRectF> linesRects;
QQuickTextLine *textLine;
diff --git a/tests/auto/declarative/qquicktext/data/multilineelide.qml b/tests/auto/declarative/qquicktext/data/multilineelide.qml
new file mode 100644
index 0000000000..23398a84a1
--- /dev/null
+++ b/tests/auto/declarative/qquicktext/data/multilineelide.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+Text {
+ width: 200; height: 200
+ wrapMode: Text.WordWrap
+ elide: Text.ElideRight
+ maximumLineCount: 3
+ text: "the quick brown fox jumped over the lazy dog the quick brown fox jumped over the lazy dog"
+}
+
diff --git a/tests/auto/declarative/qquicktext/tst_qquicktext.cpp b/tests/auto/declarative/qquicktext/tst_qquicktext.cpp
index 88ac3126d3..fb37357608 100644
--- a/tests/auto/declarative/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/declarative/qquicktext/tst_qquicktext.cpp
@@ -70,6 +70,7 @@ private slots:
void width();
void wrap();
void elide();
+ void multilineElide();
void textFormat();
void alignments_data();
@@ -448,6 +449,49 @@ void tst_qquicktext::elide()
}
}
+void tst_qquicktext::multilineElide()
+{
+ QQuickView *canvas = createView(TESTDATA("multilineelide.qml"));
+
+ QQuickText *myText = qobject_cast<QQuickText*>(canvas->rootObject());
+ QVERIFY(myText != 0);
+
+ QCOMPARE(myText->lineCount(), 3);
+ QCOMPARE(myText->truncated(), true);
+
+ qreal lineHeight = myText->paintedHeight() / 3.;
+
+ // reduce size and ensure fewer lines are drawn
+ myText->setHeight(lineHeight * 2);
+ QCOMPARE(myText->lineCount(), 2);
+
+ myText->setHeight(lineHeight);
+ QCOMPARE(myText->lineCount(), 1);
+
+ myText->setHeight(5);
+ QCOMPARE(myText->lineCount(), 1);
+
+ myText->setHeight(lineHeight * 3);
+ QCOMPARE(myText->lineCount(), 3);
+
+ // remove max count and show all lines.
+ myText->setHeight(1000);
+ myText->resetMaximumLineCount();
+
+ QCOMPARE(myText->truncated(), false);
+
+ // reduce size again
+ myText->setHeight(lineHeight * 2);
+ QCOMPARE(myText->lineCount(), 2);
+ QCOMPARE(myText->truncated(), true);
+
+ // change line height
+ myText->setLineHeight(1.1);
+ QCOMPARE(myText->lineCount(), 1);
+
+ delete canvas;
+}
+
void tst_qquicktext::textFormat()
{
{