** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
+** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
#include "qquicktext_p_p.h"
#include <QtQuick/private/qsgcontext_p.h>
+#include <private/qqmlglobal_p.h>
#include <private/qsgadaptationlayer_p.h>
#include "qquicktextnode_p.h"
#include "qquickimage_p_p.h"
#include <QtQuick/private/qsgtexture_p.h>
-#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtQml/qqmlinfo.h>
#include <QtGui/qevent.h>
#include <QtGui/qabstracttextdocumentlayout.h>
#include <QtGui/qpainter.h>
#include <QtGui/qinputmethod.h>
#include <private/qtextengine_p.h>
-#include <private/qdeclarativestyledtext_p.h>
-#include <QtQuick/private/qdeclarativepixmapcache_p.h>
+#include <private/qquickstyledtext_p.h>
+#include <QtQuick/private/qquickpixmapcache_p.h>
#include <qmath.h>
#include <limits.h>
const QChar QQuickTextPrivate::elideChar = QChar(0x2026);
QQuickTextPrivate::QQuickTextPrivate()
- : lineHeight(1)
- , elideLayout(0), textLine(0), doc(0)
+ : elideLayout(0), textLine(0)
#if defined(Q_OS_MAC)
, layoutThread(0), paintingThread(0)
#endif
, color(0xFF000000), linkColor(0xFF0000FF), styleColor(0xFF000000)
- , lineCount(1), maximumLineCount(INT_MAX), multilengthEos(-1), minimumPixelSize(12), minimumPointSize(12), nbActiveDownloads(0)
- , hAlign(QQuickText::AlignLeft), vAlign(QQuickText::AlignTop), elideMode(QQuickText::ElideNone)
+ , lineCount(1), multilengthEos(-1)
+ , elideMode(QQuickText::ElideNone), hAlign(QQuickText::AlignLeft), vAlign(QQuickText::AlignTop)
, format(QQuickText::AutoText), wrapMode(QQuickText::NoWrap)
- , lineHeightMode(QQuickText::ProportionalHeight), style(QQuickText::Normal)
- , fontSizeMode(QQuickText::FixedSize), updateType(UpdatePaintNode)
+ , style(QQuickText::Normal)
+ , updateType(UpdatePaintNode)
, maximumLineCountValid(false), updateOnComponentComplete(true), richText(false)
, styledText(false), singleline(false), internalWidthUpdate(false), requireImplicitWidth(false)
, truncated(false), hAlignImplicit(true), rightToLeftText(false)
- , layoutTextElided(false), textHasChanged(true), needToUpdateLayout(false)
+ , layoutTextElided(false), textHasChanged(true), needToUpdateLayout(false), formatModifiesFontSize(false)
+{
+}
+
+QQuickTextPrivate::ExtraData::ExtraData()
+ : lineHeight(1.0)
+ , doc(0)
+ , minimumPixelSize(12)
+ , minimumPointSize(12)
+ , nbActiveDownloads(0)
+ , maximumLineCount(INT_MAX)
+ , lineHeightMode(QQuickText::ProportionalHeight)
+ , fontSizeMode(QQuickText::FixedSize)
{
}
QVariant QQuickTextDocumentWithImageResources::loadResource(int type, const QUrl &name)
{
- QDeclarativeContext *context = qmlContext(parent());
+ QQmlContext *context = qmlContext(parent());
QUrl url = m_baseUrl.resolved(name);
if (type == QTextDocument::ImageResource) {
- QDeclarativePixmap *p = loadPixmap(context, url);
+ QQuickPixmap *p = loadPixmap(context, url);
return p->image();
}
QSizeF size(width, height);
if (!hasWidth || !hasHeight) {
- QDeclarativeContext *context = qmlContext(parent());
+ QQmlContext *context = qmlContext(parent());
QUrl url = m_baseUrl.resolved(QUrl(imageFormat.name()));
- QDeclarativePixmap *p = loadPixmap(context, url);
+ QQuickPixmap *p = loadPixmap(context, url);
if (!p->isReady()) {
if (!hasWidth)
size.setWidth(16);
QImage QQuickTextDocumentWithImageResources::image(const QTextImageFormat &format)
{
- QDeclarativeContext *context = qmlContext(parent());
+ QQmlContext *context = qmlContext(parent());
QUrl url = m_baseUrl.resolved(QUrl(format.name()));
- QDeclarativePixmap *p = loadPixmap(context, url);
+ QQuickPixmap *p = loadPixmap(context, url);
return p->image();
}
}
}
-QDeclarativePixmap *QQuickTextDocumentWithImageResources::loadPixmap(
- QDeclarativeContext *context, const QUrl &url)
+QQuickPixmap *QQuickTextDocumentWithImageResources::loadPixmap(
+ QQmlContext *context, const QUrl &url)
{
- QHash<QUrl, QDeclarativePixmap *>::Iterator iter = m_resources.find(url);
+ QHash<QUrl, QQuickPixmap *>::Iterator iter = m_resources.find(url);
if (iter == m_resources.end()) {
- QDeclarativePixmap *p = new QDeclarativePixmap(context->engine(), url);
+ QQuickPixmap *p = new QQuickPixmap(context->engine(), url);
iter = m_resources.insert(url, p);
if (p->isLoading()) {
}
}
- QDeclarativePixmap *p = *iter;
+ QQuickPixmap *p = *iter;
if (p->isError()) {
if (!errors.contains(url)) {
errors.insert(url);
void QQuickTextDocumentWithImageResources::clearResources()
{
- foreach (QDeclarativePixmap *pixmap, m_resources)
+ foreach (QQuickPixmap *pixmap, m_resources)
pixmap->clear(this);
qDeleteAll(m_resources);
m_resources.clear();
if (!richText) {
if (textHasChanged) {
if (styledText && !text.isEmpty()) {
- QDeclarativeStyledText::parse(text, layout, imgTags, q->baseUrl(), qmlContext(q), !maximumLineCountValid);
+ layout.setFont(font);
+ // needs temporary bool because formatModifiesFontSize is in a bit-field
+ bool fontSizeModified = false;
+ QQuickStyledText::parse(text, layout, imgTags, q->baseUrl(), qmlContext(q), !maximumLineCountValid, &fontSizeModified);
+ formatModifiesFontSize = fontSizeModified;
} else {
layout.clearAdditionalFormats();
- multilengthEos = text.indexOf(QLatin1Char('\x9c'));
- QString tmp = multilengthEos != -1 ? text.mid(0, multilengthEos) : text;
- tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
+ QString tmp = text;
+ multilengthEos = tmp.indexOf(QLatin1Char('\x9c'));
+ if (multilengthEos != -1) {
+ tmp = tmp.mid(0, multilengthEos);
+ tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
+ } else if (tmp.contains(QLatin1Char('\n'))) {
+ // Replace always does a detach. Checking for the new line character first
+ // means iterating over those items again if found but prevents a realloc
+ // otherwise.
+ tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
+ }
layout.setText(tmp);
}
textHasChanged = false;
} else {
ensureDoc();
QTextBlockFormat::LineHeightTypes type;
- type = lineHeightMode == QQuickText::FixedHeight ? QTextBlockFormat::FixedHeight : QTextBlockFormat::ProportionalHeight;
+ type = lineHeightMode() == QQuickText::FixedHeight ? QTextBlockFormat::FixedHeight : QTextBlockFormat::ProportionalHeight;
QTextBlockFormat blockFormat;
- blockFormat.setLineHeight((lineHeightMode == QQuickText::FixedHeight ? lineHeight : lineHeight * 100), type);
- for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next()) {
+ blockFormat.setLineHeight((lineHeightMode() == QQuickText::FixedHeight ? lineHeight() : lineHeight() * 100), type);
+ for (QTextBlock it = extra->doc->begin(); it != extra->doc->end(); it = it.next()) {
QTextCursor cursor(it);
cursor.mergeBlockFormat(blockFormat);
}
{
Q_D(QQuickText);
- (d->nbActiveDownloads)--;
+ (d->extra->nbActiveDownloads)--;
// when all the remote images have been downloaded,
// if one of the sizes was not specified at parsing time
// we use the implicit size from pixmapcache and re-layout.
- if (d->nbActiveDownloads == 0) {
+ if (d->extra.isAllocated() && d->extra->nbActiveDownloads == 0) {
bool needToUpdateLayout = false;
- foreach (QDeclarativeStyledTextImgTag *img, d->visibleImgTags) {
+ foreach (QQuickStyledTextImgTag *img, d->visibleImgTags) {
if (!img->size.isValid()) {
img->size = img->pix->implicitSize();
needToUpdateLayout = true;
}
}
+void QQuickTextPrivate::updateBaseline(qreal baseline, qreal dy)
+{
+ Q_Q(QQuickText);
+
+ qreal yoff = 0;
+
+ if (q->heightValid()) {
+ if (vAlign == QQuickText::AlignBottom)
+ yoff = dy;
+ else if (vAlign == QQuickText::AlignVCenter)
+ yoff = dy/2;
+ }
+
+ q->setBaselineOffset(baseline + yoff);
+}
+
void QQuickTextPrivate::updateSize()
{
Q_Q(QQuickText);
return;
}
- QFontMetrics fm(font);
- if (text.isEmpty()) {
- qreal fontHeight = fm.height();
+ if (text.isEmpty() && !isLineLaidOutConnected() && fontSizeMode() == QQuickText::FixedSize) {
+ // How much more expensive is it to just do a full layout on an empty string here?
+ // There may be subtle differences in the height and baseline calculations between
+ // QTextLayout and QFontMetrics and the number of variables that can affect the size
+ // and position of a line is increasing.
+ QFontMetricsF fm(font);
+ qreal fontHeight = qCeil(fm.height()); // QScriptLine and therefore QTextLine rounds up
+ if (!richText) { // line height, so we will as well.
+ fontHeight = lineHeightMode() == QQuickText::FixedHeight
+ ? lineHeight()
+ : fontHeight * lineHeight();
+ }
+ updateBaseline(fm.ascent(), q->height() - fontHeight);
q->setImplicitSize(0, fontHeight);
- layedOutTextRect = QRect(0, 0, 0, fontHeight);
+ layedOutTextRect = QRectF(0, 0, 0, fontHeight);
emit q->contentSizeChanged();
updateType = UpdatePaintNode;
q->update();
qreal naturalWidth = 0;
- int dy = q->height();
- QSize size(0, 0);
- QSize previousSize = layedOutTextRect.size();
+ QSizeF size(0, 0);
+ QSizeF previousSize = layedOutTextRect.size();
#if defined(Q_OS_MAC)
layoutThread = QThread::currentThread();
#endif
//setup instance of QTextLayout for all cases other than richtext
if (!richText) {
- QRect textRect = setupTextLayout(&naturalWidth);
+ qreal baseline = 0;
+ QRectF textRect = setupTextLayout(&naturalWidth, &baseline);
+
+ if (internalWidthUpdate) // probably the result of a binding loop, but by letting it
+ return; // get this far we'll get a warning to that effect if it is.
+
layedOutTextRect = textRect;
size = textRect.size();
- dy -= size.height();
+ updateBaseline(baseline, q->height() - size.height());
} else {
singleline = false; // richtext can't elide or be optimized for single-line case
ensureDoc();
- doc->setDefaultFont(font);
+ extra->doc->setDefaultFont(font);
QQuickText::HAlignment horizontalAlignment = q->effectiveHAlign();
if (rightToLeftText) {
if (horizontalAlignment == QQuickText::AlignLeft)
option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign));
option.setWrapMode(QTextOption::WrapMode(wrapMode));
option.setUseDesignMetrics(true);
- doc->setDefaultTextOption(option);
+ extra->doc->setDefaultTextOption(option);
if (requireImplicitWidth && q->widthValid()) {
- doc->setTextWidth(-1);
- naturalWidth = doc->idealWidth();
+ extra->doc->setTextWidth(-1);
+ naturalWidth = extra->doc->idealWidth();
+ const bool wasInLayout = internalWidthUpdate;
+ internalWidthUpdate = true;
+ q->setImplicitWidth(naturalWidth);
+ internalWidthUpdate = wasInLayout;
}
+ if (internalWidthUpdate)
+ return;
if (wrapMode != QQuickText::NoWrap && q->widthValid())
- doc->setTextWidth(q->width());
+ extra->doc->setTextWidth(q->width());
else
- doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
- dy -= (int)doc->size().height();
- QSize dsize = doc->size().toSize();
- layedOutTextRect = QRect(QPoint(0,0), dsize);
- size = QSize(int(doc->idealWidth()),dsize.height());
- }
- int yoff = 0;
+ extra->doc->setTextWidth(extra->doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
+ QSizeF dsize = extra->doc->size();
+ layedOutTextRect = QRectF(QPointF(0,0), dsize);
+ size = QSizeF(extra->doc->idealWidth(),dsize.height());
- if (q->heightValid()) {
- if (vAlign == QQuickText::AlignBottom)
- yoff = dy;
- else if (vAlign == QQuickText::AlignVCenter)
- yoff = dy/2;
+ QFontMetricsF fm(font);
+ updateBaseline(fm.ascent(), q->height() - size.height());
}
- q->setBaselineOffset(fm.ascent() + yoff);
//### need to comfirm cost of always setting these for richText
internalWidthUpdate = true;
qreal iWidth = -1;
if (!q->widthValid())
iWidth = size.width();
- else if (requireImplicitWidth)
- iWidth = naturalWidth;
if (iWidth > -1)
q->setImplicitSize(iWidth, size.height());
internalWidthUpdate = false;
bool QQuickTextPrivate::isLineLaidOutConnected()
{
- static int idx = this->signalIndex("lineLaidOut(QQuickTextLine*)");
- return this->isSignalConnected(idx);
+ Q_Q(QQuickText);
+ IS_SIGNAL_CONNECTED(q, "lineLaidOut(QQuickTextLine*)");
}
void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, int lineOffset)
textLine->setWidth(q->width());
else
textLine->setWidth(INT_MAX);
- if (lineHeight != 1.0)
- textLine->setHeight((lineHeightMode == QQuickText::FixedHeight) ? lineHeight : line.height() * lineHeight);
+ if (lineHeight() != 1.0)
+ textLine->setHeight((lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : line.height() * lineHeight());
emit q->lineLaidOut(textLine);
#endif
}
-QString QQuickTextPrivate::elidedText(int lineWidth, const QTextLine &line, QTextLine *nextLine) const
+void QQuickTextPrivate::elideFormats(
+ const int start, const int length, int offset, QList<QTextLayout::FormatRange> *elidedFormats)
+{
+ const int end = start + length;
+ QList<QTextLayout::FormatRange> formats = layout.additionalFormats();
+ for (int i = 0; i < formats.count(); ++i) {
+ QTextLayout::FormatRange format = formats.at(i);
+ const int formatLength = qMin(format.start + format.length, end) - qMax(format.start, start);
+ if (formatLength > 0) {
+ format.start = qMax(offset, format.start - start + offset);
+ format.length = formatLength;
+ elidedFormats->append(format);
+ }
+ }
+}
+
+QString QQuickTextPrivate::elidedText(qreal lineWidth, const QTextLine &line, QTextLine *nextLine) const
{
if (nextLine) {
nextLine->setLineWidth(INT_MAX);
return layout.engine()->elidedText(
Qt::TextElideMode(elideMode),
- lineWidth,
+ QFixed::fromReal(lineWidth),
0,
line.textStart(),
line.textLength() + nextLine->textLength());
} else {
QString elideText = layout.text().mid(line.textStart(), line.textLength());
- elideText[elideText.length() - 1] = elideChar;
- // Appending the elide character may push the line over the maximum width
- // in which case the elided text will need to be elided.
- QFontMetricsF metrics(layout.font());
- if (metrics.width(elideChar) + line.naturalTextWidth() >= lineWidth)
- elideText = metrics.elidedText(elideText, Qt::TextElideMode(elideMode), lineWidth);
+ if (!styledText) {
+ // QFontMetrics won't help eliding styled text.
+ elideText[elideText.length() - 1] = elideChar;
+ // Appending the elide character may push the line over the maximum width
+ // in which case the elided text will need to be elided.
+ QFontMetricsF metrics(layout.font());
+ if (metrics.width(elideChar) + line.naturalTextWidth() >= lineWidth)
+ elideText = metrics.elidedText(elideText, Qt::TextElideMode(elideMode), lineWidth);
+ }
return elideText;
}
}
already absolutely positioned horizontally).
*/
-QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
+QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *const baseline)
{
Q_Q(QQuickText);
layout.setCacheEnabled(true);
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;
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();
- }
-
- QFontMetrics fm(font);
- qreal height = (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : fm.height() * lineHeight;
- return QRect(0, 0, 0, height);
+ QFontMetricsF fm(font);
+ qreal height = (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : fm.height() * lineHeight();
+ *baseline = fm.ascent();
+ return QRectF(0, 0, 0, height);
}
- const int lineWidth = q->widthValid() ? q->width() : INT_MAX;
+ qreal lineWidth = q->widthValid() && q->width() > 0 ? q->width() : FLT_MAX;
+ const qreal maxHeight = q->heightValid() ? q->height() : FLT_MAX;
+
const bool customLayout = isLineLaidOutConnected();
const bool wasTruncated = truncated;
- const bool singlelineElide = !styledText && elideMode != QQuickText::ElideNone && q->widthValid();
- const bool multilineElide = !styledText
- && 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();
int largeFont = pixelSize ? font.pixelSize() : font.pointSize();
- int smallFont = fontSizeMode != QQuickText::FixedSize
- ? qMin(pixelSize ? minimumPixelSize : minimumPointSize, largeFont)
+ int smallFont = fontSizeMode() != QQuickText::FixedSize
+ ? qMin(pixelSize ? minimumPixelSize() : minimumPointSize(), largeFont)
: largeFont;
int scaledFontSize = largeFont;
qreal height = 0;
QString elideText;
bool once = true;
+ int elideStart = 0;
+ int elideEnd = 0;
*naturalWidth = 0;
scaledFont.setPointSize(scaledFontSize);
layout.setFont(scaledFont);
}
+
layout.beginLayout();
bool wrapped = false;
elide = false;
int characterCount = 0;
int unwrappedLineCount = 1;
+ int maxLineCount = maximumLineCount();
height = 0;
br = QRectF();
line = layout.createLine();
// Elide the previous line if the accumulated height of the text exceeds the height
// of the element.
- if (multilineElide && height > q->height() && visibleCount > 1) {
+ if (multilineElide && height > maxHeight && visibleCount > 1) {
elide = true;
if (eos != -1) // There's an abbreviated string available, skip the rest as it's
break; // all going to be discarded.
height = preLayoutHeight;
characterCount = line.textStart() + line.textLength();
+ visibleCount -= 1;
- QTextLine previousLine = layout.lineAt(visibleCount - 2);
+ QTextLine previousLine = layout.lineAt(visibleCount - 1);
elideText = layoutText.at(line.textStart() - 1) != QChar::LineSeparator
? elidedText(lineWidth, previousLine, &line)
: elidedText(lineWidth, previousLine);
- // The previous line is the last one visible so move the current one off somewhere
- // out of the way and back everything up one line.
- line.setLineWidth(0);
- line.setPosition(QPointF(FLT_MAX, FLT_MAX));
+ elideStart = previousLine.textStart();
+ // elideEnd isn't required for right eliding.
+
line = previousLine;
- --visibleCount;
- height -= (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : previousLine.height() * lineHeight;
+ height -= (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : previousLine.height() * lineHeight();
break;
}
height = preLayoutHeight;
elideText = layout.engine()->elidedText(
Qt::TextElideMode(elideMode),
- lineWidth,
+ QFixed::fromReal(lineWidth),
0,
line.textStart(),
line.textLength());
+ elideStart = line.textStart();
+ elideEnd = elideStart + line.textLength();
} else {
br = br.united(line.naturalTextRect());
}
// Stop if the maximum number of lines has been reached and elide the last line
// if enabled.
- if (visibleCount == maximumLineCount) {
+ if (visibleCount == maxLineCount) {
truncated = true;
characterCount = nextLine.textStart() + nextLine.textLength();
elideText = wrappedLine
? elidedText(lineWidth, line, &nextLine)
: elidedText(lineWidth, line);
+ elideStart = line.textStart();
+ // elideEnd isn't required for right eliding.
} else {
br = br.united(line.naturalTextRect());
}
- nextLine.setLineWidth(0);
- nextLine.setPosition(QPointF(FLT_MAX, FLT_MAX));
break;
}
}
br = br.united(line.naturalTextRect());
line = nextLine;
}
-
layout.endLayout();
br.moveTop(0);
if (requireImplicitWidth
&& characterCount < layoutText.length()
- && unwrappedLineCount < maximumLineCount) {
+ && unwrappedLineCount < maxLineCount) {
// Use a new layout to get the maximum width for the remaining text. Using a
// different layout excludes the truncated text from rendering.
QTextLayout widthLayout(layoutText.mid(characterCount), scaledFont);
widthLayout.setTextOption(layout.textOption());
- for (; unwrappedLineCount <= maximumLineCount; ++unwrappedLineCount) {
+ widthLayout.beginLayout();
+ for (; unwrappedLineCount <= maxLineCount; ++unwrappedLineCount) {
QTextLine line = widthLayout.createLine();
if (!line.isValid())
break;
}
+ widthLayout.endLayout();
*naturalWidth = qMax(*naturalWidth, widthLayout.maximumWidth());
}
+
+ bool wasInLayout = internalWidthUpdate;
+ internalWidthUpdate = true;
+ 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))
+ continue;
}
// If the next needs to be elided and there's an abbreviated string available
if (horizontalFit) {
if (unelidedRect.width() > lineWidth || (!verticalFit && wrapped)) {
largeFont = scaledFontSize - 1;
- scaledFontSize = (smallFont + largeFont) / 2;
if (smallFont > largeFont)
break;
+ scaledFontSize = (smallFont + largeFont) / 2;
+ if (pixelSize)
+ scaledFont.setPixelSize(scaledFontSize);
+ else
+ scaledFont.setPointSize(scaledFontSize);
continue;
} else if (!verticalFit) {
smallFont = scaledFontSize;
- scaledFontSize = (smallFont + largeFont + 1) / 2;
if (smallFont == largeFont)
break;
+ scaledFontSize = (smallFont + largeFont + 1) / 2;
}
}
if (verticalFit) {
- if (truncateHeight || (q->heightValid() && unelidedRect.height() > q->height())) {
+ if (truncateHeight || unelidedRect.height() > maxHeight) {
largeFont = scaledFontSize - 1;
- scaledFontSize = (smallFont + largeFont + 1) / 2;
if (smallFont > largeFont)
break;
+ scaledFontSize = (smallFont + largeFont) / 2;
+
} else {
smallFont = scaledFontSize;
- scaledFontSize = (smallFont + largeFont + 1) / 2;
if (smallFont == largeFont)
break;
+ scaledFontSize = (smallFont + largeFont + 1) / 2;
}
}
-
}
if (eos != multilengthEos)
truncated = true;
if (elide) {
- if (!elideLayout)
+ if (!elideLayout) {
elideLayout = new QTextLayout;
+ elideLayout->setCacheEnabled(true);
+ }
+ if (styledText) {
+ QList<QTextLayout::FormatRange> formats;
+ switch (elideMode) {
+ case QQuickText::ElideRight:
+ elideFormats(elideStart, elideText.length() - 1, 0, &formats);
+ break;
+ case QQuickText::ElideLeft:
+ elideFormats(elideEnd - elideText.length() + 1, elideText.length() - 1, 1, &formats);
+ break;
+ case QQuickText::ElideMiddle: {
+ const int index = elideText.indexOf(elideChar);
+ if (index != -1) {
+ elideFormats(elideStart, index, 0, &formats);
+ elideFormats(
+ elideEnd - elideText.length() + index + 1,
+ elideText.length() - index - 1,
+ index + 1,
+ &formats);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ elideLayout->setAdditionalFormats(formats);
+ }
+
elideLayout->setFont(layout.font());
elideLayout->setTextOption(layout.textOption());
elideLayout->setText(elideText);
br = br.united(elidedLine.naturalTextRect());
- if (visibleCount > 1)
- line.setPosition(QPointF(FLT_MAX, FLT_MAX));
- else
+ if (visibleCount == 1)
layout.clearLayout();
} else {
delete elideLayout;
elideLayout = 0;
}
+ QTextLine firstLine = visibleCount == 1 && elideLayout
+ ? elideLayout->lineAt(0)
+ : layout.lineAt(0);
+ Q_ASSERT(firstLine.isValid());
+ *baseline = firstLine.y() + firstLine.ascent();
+
if (!customLayout)
br.setHeight(height);
if (truncated != wasTruncated)
emit q->truncatedChanged();
- return QRect(qRound(br.x()), qRound(br.y()), qCeil(br.width()), qCeil(br.height()));
+ return br;
}
void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal &height)
if (imgTags.isEmpty()) {
line.setPosition(QPointF(line.position().x(), height));
- height += (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : line.height() * lineHeight;
+ height += (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : line.height() * lineHeight();
return;
}
qreal textHeight = line.height();
qreal totalLineHeight = textHeight;
- QList<QDeclarativeStyledTextImgTag *> imagesInLine;
+ QList<QQuickStyledTextImgTag *> imagesInLine;
- foreach (QDeclarativeStyledTextImgTag *image, imgTags) {
+ foreach (QQuickStyledTextImgTag *image, imgTags) {
if (image->position >= line.textStart() &&
image->position < line.textStart() + line.textLength()) {
if (!image->pix) {
QUrl url = q->baseUrl().resolved(image->url);
- image->pix = new QDeclarativePixmap(qmlEngine(q), url, image->size);
+ image->pix = new QQuickPixmap(qmlEngine(q), url, image->size);
if (image->pix->isLoading()) {
image->pix->connectFinished(q, SLOT(imageDownloadFinished()));
- nbActiveDownloads++;
+ if (!extra.isAllocated() || !extra->nbActiveDownloads)
+ extra.value().nbActiveDownloads = 0;
+ extra->nbActiveDownloads++;
} else if (image->pix->isReady()) {
if (!image->size.isValid()) {
image->size = image->pix->implicitSize();
}
qreal ih = qreal(image->size.height());
- if (image->align == QDeclarativeStyledTextImgTag::Top)
+ if (image->align == QQuickStyledTextImgTag::Top)
image->pos.setY(0);
- else if (image->align == QDeclarativeStyledTextImgTag::Middle)
+ else if (image->align == QQuickStyledTextImgTag::Middle)
image->pos.setY((textHeight / 2.0) - (ih / 2.0));
else
image->pos.setY(textHeight - ih);
}
}
- foreach (QDeclarativeStyledTextImgTag *image, imagesInLine) {
+ foreach (QQuickStyledTextImgTag *image, imagesInLine) {
totalLineHeight = qMax(totalLineHeight, textTop + image->pos.y() + image->size.height());
image->pos.setX(line.cursorToX(image->position));
image->pos.setY(image->pos.y() + height + textTop);
}
line.setPosition(QPointF(line.position().x(), height + textTop));
- height += (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : totalLineHeight * lineHeight;
+ height += (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : totalLineHeight * lineHeight();
}
/*!
*/
void QQuickTextPrivate::ensureDoc()
{
- if (!doc) {
+ if (!extra.isAllocated() || !extra->doc) {
Q_Q(QQuickText);
- doc = new QQuickTextDocumentWithImageResources(q);
- doc->setDocumentMargin(0);
- doc->setBaseUrl(q->baseUrl());
- FAST_CONNECT(doc, SIGNAL(imagesLoaded()), q, SLOT(q_imagesLoaded()));
+ extra.value().doc = new QQuickTextDocumentWithImageResources(q);
+ extra->doc->setDocumentMargin(0);
+ extra->doc->setBaseUrl(q->baseUrl());
+ FAST_CONNECT(extra->doc, SIGNAL(imagesLoaded()), q, SLOT(q_imagesLoaded()));
}
}
The properties of a line are:
\list
- \o number (read-only)
- \o x
- \o y
- \o width
- \o height
+ \li number (read-only)
+ \li x
+ \li y
+ \li width
+ \li height
\endlist
For example, this will move the first 5 lines of a text element by 100 pixels to the right:
The link must be in rich text or HTML format and the
\a link string provides access to the particular link.
- \snippet doc/src/snippets/declarative/text/onLinkActivated.qml 0
+ \snippet doc/src/snippets/qml/text/onLinkActivated.qml 0
The example code will display the text
"The main website is at \l{http://qt.nokia.com}{Nokia Qt DF}."
The weight can be one of:
\list
- \o Font.Light
- \o Font.Normal - the default
- \o Font.DemiBold
- \o Font.Bold
- \o Font.Black
+ \li Font.Light
+ \li Font.Normal - the default
+ \li Font.DemiBold
+ \li Font.Bold
+ \li Font.Black
\endlist
\qml
Sets the capitalization for the text.
\list
- \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
- \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
- \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
- \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
- \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
+ \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
+ \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
+ \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
+ \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
+ \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
\endlist
\qml
d->font.setPointSizeF(size/2.0);
}
- if (oldFont != d->font)
+ if (oldFont != d->font) {
+ // if the format changes the size of the text
+ // with headings or <font> tag, we need to re-parse
+ if (d->formatModifiesFontSize)
+ d->textHasChanged = true;
d->updateLayout();
+ }
emit fontChanged(d->sourceFont);
}
if (isComponentComplete()) {
if (d->richText) {
d->ensureDoc();
- d->doc->setText(n);
- d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
+ d->extra->doc->setText(n);
+ d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft();
} else {
d->rightToLeftText = d->text.isRightToLeft();
}
Supported text styles are:
\list
- \o Text.Normal - the default
- \o Text.Outline
- \o Text.Raised
- \o Text.Sunken
+ \li Text.Normal - the default
+ \li Text.Outline
+ \li Text.Raised
+ \li Text.Sunken
\endlist
\qml
}
}
-QTextDocument *QQuickTextPrivate::textDocument()
-{
- return doc;
-}
-
QQuickText::VAlignment QQuickText::vAlign() const
{
Q_D(const QQuickText);
wrap if an explicit width has been set. wrapMode can be one of:
\list
- \o Text.NoWrap (default) - no wrapping will be performed. If the text contains insufficient newlines, then \l contentWidth will exceed a set width.
- \o Text.WordWrap - wrapping is done on word boundaries only. If a word is too long, \l contentWidth will exceed a set width.
- \o Text.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
- \o Text.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
+ \li Text.NoWrap (default) - no wrapping will be performed. If the text contains insufficient newlines, then \l contentWidth will exceed a set width.
+ \li Text.WordWrap - wrapping is done on word boundaries only. If a word is too long, \l contentWidth will exceed a set width.
+ \li Text.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
+ \li Text.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
\endlist
*/
QQuickText::WrapMode QQuickText::wrapMode() const
int QQuickText::maximumLineCount() const
{
Q_D(const QQuickText);
- return d->maximumLineCount;
+ return d->maximumLineCount();
}
void QQuickText::setMaximumLineCount(int lines)
Q_D(QQuickText);
d->maximumLineCountValid = lines==INT_MAX ? false : true;
- if (d->maximumLineCount != lines) {
- d->maximumLineCount = lines;
+ if (d->maximumLineCount() != lines) {
+ d->extra.value().maximumLineCount = lines;
d->updateLayout();
emit maximumLineCountChanged();
}
Supported text formats are:
\list
- \o Text.AutoText (default)
- \o Text.PlainText
- \o Text.StyledText
- \o Text.RichText
+ \li Text.AutoText (default)
+ \li Text.PlainText
+ \li Text.StyledText
+ \li Text.RichText
\endlist
If the text format is \c Text.AutoText the text element
\table
\row
- \o
+ \li
\qml
Column {
Text {
}
}
\endqml
- \o \image declarative-textformat.png
+ \li \image declarative-textformat.png
\endtable
*/
QQuickText::TextFormat QQuickText::textFormat() const
if (isComponentComplete()) {
if (!wasRich && d->richText) {
d->ensureDoc();
- d->doc->setText(d->text);
- d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
+ d->extra->doc->setText(d->text);
+ d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft();
} else {
d->rightToLeftText = d->text.isRightToLeft();
}
Eliding can be:
\list
- \o Text.ElideNone - the default
- \o Text.ElideLeft
- \o Text.ElideMiddle
- \o Text.ElideRight
+ \li Text.ElideNone - the default
+ \li Text.ElideLeft
+ \li Text.ElideMiddle
+ \li Text.ElideRight
\endlist
If this property is set to Text.ElideRight, it can be used with \l {wrapMode}{wrapped}
d->elideMode = mode;
d->updateLayout();
- emit elideModeChanged(d->elideMode);
+ emit elideModeChanged(mode);
}
/*!
URL meaning any portion of the path after the last '/' will be ignored.
\table
- \header \o Base URL \o Relative URL \o Resolved URL
- \row \o http://qt-project.org/ \o images/logo.png \o http://qt-project.org/images/logo.png
- \row \o http://qt-project.org/index.html \o images/logo.png \o http://qt-project.org/images/logo.png
- \row \o http://qt-project.org/content \o images/logo.png \o http://qt-project.org/content/images/logo.png
- \row \o http://qt-project.org/content/ \o images/logo.png \o http://qt-project.org/content/images/logo.png
- \row \o http://qt-project.org/content/index.html \o images/logo.png \o http://qt-project.org/content/images/logo.png
- \row \o http://qt-project.org/content/index.html \o ../images/logo.png \o http://qt-project.org/images/logo.png
- \row \o http://qt-project.org/content/index.html \o /images/logo.png \o http://qt-project.org/images/logo.png
+ \header \li Base URL \li Relative URL \li Resolved URL
+ \row \li http://qt-project.org/ \li images/logo.png \li http://qt-project.org/images/logo.png
+ \row \li http://qt-project.org/index.html \li images/logo.png \li http://qt-project.org/images/logo.png
+ \row \li http://qt-project.org/content \li images/logo.png \li http://qt-project.org/content/images/logo.png
+ \row \li http://qt-project.org/content/ \li images/logo.png \li http://qt-project.org/content/images/logo.png
+ \row \li http://qt-project.org/content/index.html \li images/logo.png \li http://qt-project.org/content/images/logo.png
+ \row \li http://qt-project.org/content/index.html \li ../images/logo.png \li http://qt-project.org/images/logo.png
+ \row \li http://qt-project.org/content/index.html \li /images/logo.png \li http://qt-project.org/images/logo.png
\endtable
By default is the url of the Text element.
{
Q_D(const QQuickText);
if (d->baseUrl.isEmpty()) {
- if (QDeclarativeContext *context = qmlContext(this))
+ if (QQmlContext *context = qmlContext(this))
const_cast<QQuickTextPrivate *>(d)->baseUrl = context->baseUrl();
}
return d->baseUrl;
if (baseUrl() != url) {
d->baseUrl = url;
- if (d->doc)
- d->doc->setBaseUrl(url);
+ if (d->richText) {
+ d->ensureDoc();
+ d->extra->doc->setBaseUrl(url);
+ }
if (d->styledText) {
d->textHasChanged = true;
qDeleteAll(d->imgTags);
void QQuickText::resetBaseUrl()
{
- if (QDeclarativeContext *context = qmlContext(this))
+ if (QQmlContext *context = qmlContext(this))
setBaseUrl(context->baseUrl());
else
setBaseUrl(QUrl());
{
Q_D(const QQuickText);
- QRect rect = d->layedOutTextRect;
+ QRectF rect = d->layedOutTextRect;
if (d->style != Normal)
rect.adjust(-1, 0, 1, 2);
// Could include font max left/right bearings to either side of rectangle.
- int h = height();
+ qreal w = width();
+ switch (d->hAlign) {
+ case AlignLeft:
+ case AlignJustify:
+ break;
+ case AlignRight:
+ rect.moveLeft(w - rect.width());
+ break;
+ case AlignHCenter:
+ rect.moveLeft((w - rect.width()) / 2);
+ break;
+ }
+
+ qreal h = height();
switch (d->vAlign) {
case AlignTop:
break;
break;
}
- return QRectF(rect);
+ return rect;
}
/*! \internal */
bool leftAligned = effectiveHAlign() == QQuickText::AlignLeft;
bool wrapped = d->wrapMode != QQuickText::NoWrap;
bool elide = d->elideMode != QQuickText::ElideNone;
- bool scaleFont = d->fontSizeMode != QQuickText::FixedSize && (widthValid() || heightValid());
+ bool scaleFont = d->fontSizeMode() != QQuickText::FixedSize && (widthValid() || heightValid());
if ((!widthChanged && !heightChanged) || d->internalWidthUpdate)
goto geomChangeDone;
if (d->elideMode == QQuickText::ElideRight && wrapped && newGeometry.height() > oldGeometry.height() && !scaleFont) {
if (!d->truncated)
goto geomChangeDone; // Multiline eliding not affected if we're not currently truncated and we get higher.
- if (d->maximumLineCountValid && d->lineCount == d->maximumLineCount)
+ if (d->maximumLineCountValid && d->lineCount == d->maximumLineCount())
goto geomChangeDone; // Multiline eliding not affected if we're already at max line count and we get higher.
}
if (d->richText) {
d->ensureDoc();
- node->addTextDocument(bounds.topLeft(), d->doc, color, d->style, styleColor, linkColor);
+ node->addTextDocument(bounds.topLeft(), d->extra->doc, color, d->style, styleColor, linkColor);
} else if (d->elideMode == QQuickText::ElideNone || bounds.width() > 0.) {
- node->addTextLayout(QPoint(0, bounds.y()), &d->layout, color, d->style, styleColor, linkColor);
+ int unelidedLineCount = d->lineCount;
+ if (d->elideLayout)
+ unelidedLineCount -= 1;
+ if (unelidedLineCount > 0) {
+ node->addTextLayout(
+ QPoint(0, bounds.y()),
+ &d->layout,
+ d->color, d->style, d->styleColor, d->linkColor,
+ QColor(), QColor(), -1, -1,
+ 0, unelidedLineCount);
+ }
if (d->elideLayout)
node->addTextLayout(QPoint(0, bounds.y()), d->elideLayout, color, d->style, styleColor, linkColor);
}
- foreach (QDeclarativeStyledTextImgTag *img, d->visibleImgTags) {
- QDeclarativePixmap *pix = img->pix;
+ foreach (QQuickStyledTextImgTag *img, d->visibleImgTags) {
+ QQuickPixmap *pix = img->pix;
if (pix && pix->isReady())
node->addImage(QRectF(img->pos.x(), img->pos.y() + bounds.y(), pix->width(), pix->height()), pix->image());
}
void QQuickText::updatePolish()
{
Q_D(QQuickText);
- if (d->updateLayoutOnPolish)
- d->updateLayout();
- else
- d->updateSize();
+ d->updateSize();
}
/*!
qreal QQuickText::lineHeight() const
{
Q_D(const QQuickText);
- return d->lineHeight;
+ return d->lineHeight();
}
void QQuickText::setLineHeight(qreal lineHeight)
{
Q_D(QQuickText);
- if ((d->lineHeight == lineHeight) || (lineHeight < 0.0))
+ if ((d->lineHeight() == lineHeight) || (lineHeight < 0.0))
return;
- d->lineHeight = lineHeight;
+ d->extra.value().lineHeight = lineHeight;
d->updateLayout();
emit lineHeightChanged(lineHeight);
}
The possible values are:
\list
- \o Text.ProportionalHeight (default) - this sets the spacing proportional to the
+ \li Text.ProportionalHeight (default) - this sets the spacing proportional to the
line (as a multiplier). For example, set to 2 for double spacing.
- \o Text.FixedHeight - this sets the line height to a fixed line height (in pixels).
+ \li Text.FixedHeight - this sets the line height to a fixed line height (in pixels).
\endlist
*/
QQuickText::LineHeightMode QQuickText::lineHeightMode() const
{
Q_D(const QQuickText);
- return d->lineHeightMode;
+ return d->lineHeightMode();
}
void QQuickText::setLineHeightMode(LineHeightMode mode)
{
Q_D(QQuickText);
- if (mode == d->lineHeightMode)
+ if (mode == d->lineHeightMode())
return;
- d->lineHeightMode = mode;
+ d->extra.value().lineHeightMode = mode;
d->updateLayout();
emit lineHeightModeChanged(mode);
The possible values are:
\list
- \o Text.FixedSize (default) - The size specified by \l font.pixelSize
+ \li Text.FixedSize (default) - The size specified by \l font.pixelSize
or \l font.pointSize is used.
- \o Text.HorizontalFit - The largest size up to the size specified that fits
+ \li Text.HorizontalFit - The largest size up to the size specified that fits
within the width of the item without wrapping is used.
- \o Text.VerticalFit - The largest size up to the size specified that fits
+ \li Text.VerticalFit - The largest size up to the size specified that fits
the height of the item is used.
- \o Text.Fit - The largest size up to the size specified the fits within the
+ \li Text.Fit - The largest size up to the size specified the fits within the
width and height of the item is used.
\endlist
QQuickText::FontSizeMode QQuickText::fontSizeMode() const
{
Q_D(const QQuickText);
- return d->fontSizeMode;
+ return d->fontSizeMode();
}
void QQuickText::setFontSizeMode(FontSizeMode mode)
{
Q_D(QQuickText);
- if (d->fontSizeMode == mode)
+ if (d->fontSizeMode() == mode)
return;
polish();
- d->fontSizeMode = mode;
+ d->extra.value().fontSizeMode = mode;
emit fontSizeModeChanged();
}
int QQuickText::minimumPixelSize() const
{
Q_D(const QQuickText);
- return d->minimumPixelSize;
+ return d->minimumPixelSize();
}
void QQuickText::setMinimumPixelSize(int size)
{
Q_D(QQuickText);
- if (d->minimumPixelSize == size)
+ if (d->minimumPixelSize() == size)
return;
- if (d->fontSizeMode != FixedSize && (widthValid() || heightValid()))
+ if (d->fontSizeMode() != FixedSize && (widthValid() || heightValid()))
polish();
- d->minimumPixelSize = size;
+ d->extra.value().minimumPixelSize = size;
emit minimumPixelSizeChanged();
}
int QQuickText::minimumPointSize() const
{
Q_D(const QQuickText);
- return d->minimumPointSize;
+ return d->minimumPointSize();
}
void QQuickText::setMinimumPointSize(int size)
{
Q_D(QQuickText);
- if (d->minimumPointSize == size)
+ if (d->minimumPointSize() == size)
return;
- if (d->fontSizeMode != FixedSize && (widthValid() || heightValid()))
+ if (d->fontSizeMode() != FixedSize && (widthValid() || heightValid()))
polish();
- d->minimumPointSize = size;
+ d->extra.value().minimumPointSize = size;
emit minimumPointSizeChanged();
}
int QQuickText::resourcesLoading() const
{
Q_D(const QQuickText);
- return d->doc ? d->doc->resourcesLoading() : 0;
+ if (d->richText && d->extra.isAllocated() && d->extra->doc)
+ return d->extra->doc->resourcesLoading();
+ return 0;
}
/*! \internal */
if (d->updateOnComponentComplete) {
if (d->richText) {
d->ensureDoc();
- d->doc->setText(d->text);
- d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
+ d->extra->doc->setText(d->text);
+ d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft();
} else {
d->rightToLeftText = d->text.isRightToLeft();
}
QQuickItem::componentComplete();
if (d->updateOnComponentComplete)
d->updateLayout();
-
- // Enable accessibility for text items.
- d->setAccessibleFlagAndListener();
}
bool QQuickTextPrivate::isLinkActivatedConnected()
{
- static int idx = this->signalIndex("linkActivated(QString)");
- return this->isSignalConnected(idx);
+ Q_Q(QQuickText);
+ IS_SIGNAL_CONNECTED(q, "linkActivated(QString)");
}
/*! \internal */
{
Q_D(QQuickText);
+ QString link;
if (d->isLinkActivatedConnected()) {
if (d->styledText)
- d->activeLink = d->anchorAt(event->localPos());
- else if (d->richText && d->doc)
- d->activeLink = d->doc->documentLayout()->anchorAt(event->localPos());
+ link = d->anchorAt(event->localPos());
+ else if (d->richText) {
+ d->ensureDoc();
+ link = d->extra->doc->documentLayout()->anchorAt(event->localPos());
+ }
}
- if (d->activeLink.isEmpty())
+ if (link.isEmpty()) {
event->setAccepted(false);
+ } else {
+ d->extra.value().activeLink = link;
+ }
// ### may malfunction if two of the same links are clicked & dragged onto each other)
if (d->isLinkActivatedConnected()) {
if (d->styledText)
link = d->anchorAt(event->localPos());
- else if (d->richText && d->doc)
- link = d->doc->documentLayout()->anchorAt(event->localPos());
+ else if (d->richText) {
+ d->ensureDoc();
+ link = d->extra->doc->documentLayout()->anchorAt(event->localPos());
+ }
}
- if (!link.isEmpty() && d->activeLink == link)
- emit linkActivated(d->activeLink);
+ if (!link.isEmpty() && d->extra.isAllocated() && d->extra->activeLink == link)
+ emit linkActivated(d->extra->activeLink);
else
event->setAccepted(false);