diff options
Diffstat (limited to 'src/declarative/graphicsitems/qdeclarativetext.cpp')
-rw-r--r-- | src/declarative/graphicsitems/qdeclarativetext.cpp | 190 |
1 files changed, 171 insertions, 19 deletions
diff --git a/src/declarative/graphicsitems/qdeclarativetext.cpp b/src/declarative/graphicsitems/qdeclarativetext.cpp index 640965c..64925d0 100644 --- a/src/declarative/graphicsitems/qdeclarativetext.cpp +++ b/src/declarative/graphicsitems/qdeclarativetext.cpp @@ -54,6 +54,7 @@ #include <QPainter> #include <QAbstractTextDocumentLayout> #include <qmath.h> +#include <limits.h> QT_BEGIN_NAMESPACE @@ -84,12 +85,14 @@ private: DEFINE_BOOL_CONFIG_OPTION(enableImageCache, QML_ENABLE_TEXT_IMAGE_CACHE); +QString QDeclarativeTextPrivate::elideChar = QString(0x2026); + QDeclarativeTextPrivate::QDeclarativeTextPrivate() : color((QRgb)0), style(QDeclarativeText::Normal), hAlign(QDeclarativeText::AlignLeft), vAlign(QDeclarativeText::AlignTop), elideMode(QDeclarativeText::ElideNone), - format(QDeclarativeText::AutoText), wrapMode(QDeclarativeText::NoWrap), imageCacheDirty(true), - updateOnComponentComplete(true), richText(false), singleline(false), cacheAllTextAsImage(true), - internalWidthUpdate(false), doc(0) + format(QDeclarativeText::AutoText), wrapMode(QDeclarativeText::NoWrap), lineCount(1), truncated(false), maximumLineCount(INT_MAX), + maximumLineCountValid(false), imageCacheDirty(true), updateOnComponentComplete(true), richText(false), singleline(false), + cacheAllTextAsImage(true), internalWidthUpdate(false), doc(0) { cacheAllTextAsImage = enableImageCache(); QGraphicsItemPrivate::acceptedMouseButtons = Qt::LeftButton; @@ -192,9 +195,13 @@ void QDeclarativeTextPrivate::updateLayout() QString tmp = text; tmp.replace(QLatin1Char('\n'), QChar::LineSeparator); singleline = !tmp.contains(QChar::LineSeparator); - if (singleline && elideMode != QDeclarativeText::ElideNone && q->widthValid()) { + if (singleline && !maximumLineCountValid && elideMode != QDeclarativeText::ElideNone && q->widthValid()) { QFontMetrics fm(font); tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width()); // XXX still worth layout...? + if (tmp != text && !truncated) { + truncated = true; + emit q->truncatedChanged(); + } } layout.setText(tmp); } else { @@ -291,25 +298,84 @@ QSize QDeclarativeTextPrivate::setupTextLayout() qreal height = 0; qreal widthUsed = 0; qreal lineWidth = 0; + int visibleTextLength = 0; + int visibleCount = 0; //set manual width if ((wrapMode != QDeclarativeText::NoWrap || elideMode != QDeclarativeText::ElideNone) && q->widthValid()) lineWidth = q->width(); QTextOption textOption = layout.textOption(); + if (hAlign == QDeclarativeText::AlignJustify) + textOption.setAlignment(Qt::Alignment(hAlign)); textOption.setWrapMode(QTextOption::WrapMode(wrapMode)); layout.setTextOption(textOption); - layout.beginLayout(); - forever { - QTextLine line = layout.createLine(); - if (!line.isValid()) - break; + bool elideText = false; + bool truncate = false; + + QFontMetrics fm(layout.font()); + qreal elideWidth = fm.width(elideChar); + elidePos = QPointF(); + + if (maximumLineCountValid) { + layout.beginLayout(); + int y = 0; + int linesLeft = maximumLineCount; + while (linesLeft > 0) { + QTextLine line = layout.createLine(); + if (!line.isValid()) + break; + + visibleCount++; + + if (lineWidth) { + if (--linesLeft == 0) { + line.setLineWidth(q->width()*2); // Set out more than is required, but not too much. + if (line.naturalTextWidth() > lineWidth) + line.setLineWidth(lineWidth - elideWidth); + visibleTextLength += line.textLength(); // Used to catch new lines that are shorter than the layout width. + + if (visibleTextLength < text.length()) { + truncate = true; + if (elideMode==QDeclarativeText::ElideRight) { + // Need to correct for alignment + int x = line.naturalTextWidth(); + if (hAlign == QDeclarativeText::AlignRight) { + x = q->width()-elideWidth; + } else if (hAlign == QDeclarativeText::AlignHCenter) { + x = (q->width()+line.naturalTextWidth()-elideWidth)/2; + } + elidePos = QPointF(x, y + fm.ascent()); + } + } + } else { + line.setLineWidth(lineWidth); + visibleTextLength += line.textLength(); + } + + y += line.height(); + } + } + layout.endLayout(); - if (lineWidth) - line.setLineWidth(lineWidth); + //Update truncated + if (truncated != truncate) { + truncated = truncate; + emit q->truncatedChanged(); + } + } else { + layout.beginLayout(); + forever { + QTextLine line = layout.createLine(); + if (!line.isValid()) + break; + visibleCount++; + if (lineWidth) + line.setLineWidth(lineWidth); + } + layout.endLayout(); } - layout.endLayout(); for (int i = 0; i < layout.lineCount(); ++i) { QTextLine line = layout.lineAt(i); @@ -325,17 +391,27 @@ QSize QDeclarativeTextPrivate::setupTextLayout() height += line.height(); if (!cacheAllTextAsImage) { - if (hAlign == QDeclarativeText::AlignLeft) { + if ((hAlign == QDeclarativeText::AlignLeft) || (hAlign == QDeclarativeText::AlignJustify)) { x = 0; } else if (hAlign == QDeclarativeText::AlignRight) { x = layoutWidth - line.naturalTextWidth(); + if (elideText && i == layout.lineCount()-1) + x -= elideWidth; // Correct for when eliding multilines } else if (hAlign == QDeclarativeText::AlignHCenter) { x = (layoutWidth - line.naturalTextWidth()) / 2; + if (elideText && i == layout.lineCount()-1) + x -= elideWidth/2; // Correct for when eliding multilines } line.setPosition(QPointF(x, line.y())); } } + //Update the number of visible lines + if (lineCount != visibleCount) { + lineCount = visibleCount; + emit q->lineCountChanged(); + } + return layout.boundingRect().toAlignedRect().size(); } @@ -351,7 +427,7 @@ QPixmap QDeclarativeTextPrivate::textLayoutImage(bool drawStyle) qreal x = 0; for (int i = 0; i < layout.lineCount(); ++i) { QTextLine line = layout.lineAt(i); - if (hAlign == QDeclarativeText::AlignLeft) { + if ((hAlign == QDeclarativeText::AlignLeft) || (hAlign == QDeclarativeText::AlignJustify)) { x = 0; } else if (hAlign == QDeclarativeText::AlignRight) { x = size.width() - line.naturalTextWidth(); @@ -389,7 +465,9 @@ void QDeclarativeTextPrivate::drawTextLayout(QPainter *painter, const QPointF &p else painter->setPen(color); painter->setFont(font); - layout.draw(painter, pos); + layout.draw(painter, pos); + if (!elidePos.isNull()) + painter->drawText(elidePos, elideChar); } /*! @@ -907,8 +985,8 @@ void QDeclarativeText::setStyleColor(const QColor &color) Sets the horizontal and vertical alignment of the text within the Text items width and height. By default, the text is top-left aligned. - The valid values for \c horizontalAlignment are \c Text.AlignLeft, \c Text.AlignRight and - \c Text.AlignHCenter. The valid values for \c verticalAlignment are \c Text.AlignTop, \c Text.AlignBottom + The valid values for \c horizontalAlignment are \c Text.AlignLeft, \c Text.AlignRight, \c Text.AlignHCenter and + \c Text.AlignJustify. The valid values for \c verticalAlignment are \c Text.AlignTop, \c Text.AlignBottom and \c Text.AlignVCenter. Note that for a single line of text, the size of the text is the area of the text. In this common case, @@ -986,6 +1064,76 @@ void QDeclarativeText::setWrapMode(WrapMode mode) emit wrapModeChanged(); } +/*! + \qmlproperty int Text::lineCount + + Returns the number of lines visible in the text item. + + This property is not supported for rich text. + + \sa maximumLineCount +*/ +int QDeclarativeText::lineCount() const +{ + Q_D(const QDeclarativeText); + return d->lineCount; +} + +/*! + \qmlproperty bool Text::truncated + + Returns true if the text has been truncated due to \l maximumLineCount + or \l elide. + + This property is not supported for rich text. + + \sa maximumLineCount, elide +*/ +bool QDeclarativeText::truncated() const +{ + Q_D(const QDeclarativeText); + return d->truncated; +} + +/*! + \qmlproperty int Text::maximumLineCount + + Set this property to limit the number of lines that the text item will show. + If elide is set to Text.ElideRight, the text will be elided appropriately. + By default, this is the value of the largest possible integer. + + This property is not supported for rich text. + + \sa lineCount, elide +*/ +int QDeclarativeText::maximumLineCount() const +{ + Q_D(const QDeclarativeText); + return d->maximumLineCount; +} + +void QDeclarativeText::setMaximumLineCount(int lines) +{ + Q_D(QDeclarativeText); + + d->maximumLineCountValid = lines==INT_MAX ? false : true; + if (d->maximumLineCount != lines) { + d->maximumLineCount = lines; + d->updateLayout(); + emit maximumLineCountChanged(); + } +} + +void QDeclarativeText::resetMaximumLineCount() +{ + Q_D(QDeclarativeText); + setMaximumLineCount(INT_MAX); + d->elidePos = QPointF(); + if (d->truncated != false) { + d->truncated = false; + emit truncatedChanged(); + } +} /*! \qmlproperty enumeration Text::textFormat @@ -1073,7 +1221,7 @@ void QDeclarativeText::setTextFormat(TextFormat format) Set this property to elide parts of the text fit to the Text item's width. The text will only elide if an explicit width has been set. - This property cannot be used with multi-line text or with rich text. + This property cannot be used with rich text. Eliding can be: \list @@ -1083,6 +1231,9 @@ void QDeclarativeText::setTextFormat(TextFormat format) \o Text.ElideRight \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. + 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. @@ -1126,6 +1277,7 @@ QRectF QDeclarativeText::boundingRect() const switch (d->hAlign) { case AlignLeft: + case AlignJustify: x = 0; break; case AlignRight: @@ -1159,7 +1311,7 @@ void QDeclarativeText::geometryChanged(const QRectF &newGeometry, const QRectF & && (d->wrapMode != QDeclarativeText::NoWrap || d->elideMode != QDeclarativeText::ElideNone || d->hAlign != QDeclarativeText::AlignLeft)) { - if (d->singleline && d->elideMode != QDeclarativeText::ElideNone && widthValid()) { + if ((d->singleline || d->maximumLineCountValid) && d->elideMode != QDeclarativeText::ElideNone && widthValid()) { // We need to re-elide d->updateLayout(); } else { |