Merge branch 'master' into refactor
[profile/ivi/qtdeclarative.git] / src / qtquick1 / graphicsitems / qdeclarativetext.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "QtQuick1/private/qdeclarativetext_p.h"
43 #include "QtQuick1/private/qdeclarativetext_p_p.h"
44 #include "QtQuick1/private/qdeclarativestyledtext_p.h"
45 #include <QtDeclarative/qdeclarativeinfo.h>
46 #include "QtQuick1/private/qdeclarativepixmapcache_p.h"
47
48 #include <QSet>
49 #include <QTextLayout>
50 #include <QTextLine>
51 #include <QTextDocument>
52 #include <QGraphicsSceneMouseEvent>
53 #include <QPainter>
54 #include <QAbstractTextDocumentLayout>
55 #include <qmath.h>
56 #include <limits.h>
57
58 QT_BEGIN_NAMESPACE
59
60
61
62 extern Q_GUI_EXPORT bool qt_applefontsmoothing_enabled;
63
64 class QTextDocumentWithImageResources_1 : public QTextDocument {
65     Q_OBJECT
66
67 public:
68     QTextDocumentWithImageResources_1(QDeclarative1Text *parent);
69     virtual ~QTextDocumentWithImageResources_1();
70
71     void setText(const QString &);
72     int resourcesLoading() const { return outstanding; }
73
74 protected:
75     QVariant loadResource(int type, const QUrl &name);
76
77 private slots:
78     void requestFinished();
79
80 private:
81     QHash<QUrl, QDeclarative1Pixmap *> m_resources;
82
83     int outstanding;
84     static QSet<QUrl> errors;
85 };
86
87
88 QTextDocumentWithImageResources_1::QTextDocumentWithImageResources_1(QDeclarative1Text *parent) 
89 : QTextDocument(parent), outstanding(0)
90 {
91 }
92
93 QTextDocumentWithImageResources_1::~QTextDocumentWithImageResources_1()
94 {
95     if (!m_resources.isEmpty()) 
96         qDeleteAll(m_resources);
97 }
98
99 QVariant QTextDocumentWithImageResources_1::loadResource(int type, const QUrl &name)
100 {
101     QDeclarativeContext *context = qmlContext(parent());
102     QUrl url = context->resolvedUrl(name);
103
104     if (type == QTextDocument::ImageResource) {
105         QHash<QUrl, QDeclarative1Pixmap *>::Iterator iter = m_resources.find(url);
106
107         if (iter == m_resources.end()) {
108             QDeclarative1Pixmap *p = new QDeclarative1Pixmap(context->engine(), url);
109             iter = m_resources.insert(name, p);
110
111             if (p->isLoading()) {
112                 p->connectFinished(this, SLOT(requestFinished()));
113                 outstanding++;
114             }
115         }
116
117         QDeclarative1Pixmap *p = *iter;
118         if (p->isReady()) {
119             return p->pixmap();
120         } else if (p->isError()) {
121             if (!errors.contains(url)) {
122                 errors.insert(url);
123                 qmlInfo(parent()) << p->error();
124             }
125         }
126     }
127
128     return QTextDocument::loadResource(type,url); // The *resolved* URL
129 }
130
131 void QTextDocumentWithImageResources_1::requestFinished()
132 {
133     outstanding--;
134     if (outstanding == 0) {
135         QDeclarative1Text *textItem = static_cast<QDeclarative1Text*>(parent());
136         QString text = textItem->text();
137 #ifndef QT_NO_TEXTHTMLPARSER
138         setHtml(text);
139 #else
140         setPlainText(text);
141 #endif
142         QDeclarative1TextPrivate *d = QDeclarative1TextPrivate::get(textItem);
143         d->updateLayout();
144     }
145 }
146
147 void QTextDocumentWithImageResources_1::setText(const QString &text)
148 {
149     if (!m_resources.isEmpty()) {
150         qDeleteAll(m_resources);
151         m_resources.clear();
152         outstanding = 0;
153     }
154
155 #ifndef QT_NO_TEXTHTMLPARSER
156     setHtml(text);
157 #else
158     setPlainText(text);
159 #endif
160 }
161
162 QSet<QUrl> QTextDocumentWithImageResources_1::errors;
163
164 QDeclarative1TextPrivate::~QDeclarative1TextPrivate()
165 {
166 }
167
168 DEFINE_BOOL_CONFIG_OPTION(enableImageCache, QML_ENABLE_TEXT_IMAGE_CACHE);
169
170 QString QDeclarative1TextPrivate::elideChar = QString(0x2026);
171
172 QDeclarative1TextPrivate::QDeclarative1TextPrivate()
173 : color((QRgb)0), style(QDeclarative1Text::Normal), hAlign(QDeclarative1Text::AlignLeft),
174   vAlign(QDeclarative1Text::AlignTop), elideMode(QDeclarative1Text::ElideNone),
175   format(QDeclarative1Text::AutoText), wrapMode(QDeclarative1Text::NoWrap), lineHeight(1),
176   lineHeightMode(QDeclarative1Text::ProportionalHeight), lineCount(1), truncated(false), maximumLineCount(INT_MAX),
177   maximumLineCountValid(false), imageCacheDirty(true), updateOnComponentComplete(true), richText(false), singleline(false),
178   cacheAllTextAsImage(true), internalWidthUpdate(false), requireImplicitWidth(false),  hAlignImplicit(true),
179   rightToLeftText(false), layoutTextElided(false), naturalWidth(0), doc(0)
180 {
181     cacheAllTextAsImage = enableImageCache();
182     QGraphicsItemPrivate::acceptedMouseButtons = Qt::LeftButton;
183     QGraphicsItemPrivate::flags = QGraphicsItemPrivate::flags & ~QGraphicsItem::ItemHasNoContents;
184 }
185
186 qreal QDeclarative1TextPrivate::implicitWidth() const
187 {
188     if (!requireImplicitWidth) {
189         // We don't calculate implicitWidth unless it is required.
190         // We need to force a size update now to ensure implicitWidth is calculated
191         QDeclarative1TextPrivate *me = const_cast<QDeclarative1TextPrivate*>(this);
192         me->requireImplicitWidth = true;
193         me->updateSize();
194     }
195     return mImplicitWidth;
196 }
197
198 void QDeclarative1TextPrivate::updateLayout()
199 {
200     Q_Q(QDeclarative1Text);
201     if (!q->isComponentComplete()) {
202         updateOnComponentComplete = true;
203         return;
204     }
205
206     layoutTextElided = false;
207     // Setup instance of QTextLayout for all cases other than richtext
208     if (!richText) {
209         layout.clearLayout();
210         layout.setFont(font);
211         if (format != QDeclarative1Text::StyledText) {
212             QString tmp = text;
213             tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
214             singleline = !tmp.contains(QChar::LineSeparator);
215             if (singleline && !maximumLineCountValid && elideMode != QDeclarative1Text::ElideNone && q->widthValid()) {
216                 QFontMetrics fm(font);
217                 tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width());
218                 if (tmp != text) {
219                     layoutTextElided = true;
220                     if (!truncated) {
221                         truncated = true;
222                         emit q->truncatedChanged();
223                     }
224                 }
225             }
226             layout.setText(tmp);
227         } else {
228             singleline = false;
229             QDeclarative1StyledText::parse(text, layout);
230         }
231     }
232
233     updateSize();
234 }
235
236 void QDeclarative1TextPrivate::updateSize()
237 {
238     Q_Q(QDeclarative1Text);
239
240     if (!q->isComponentComplete()) {
241         updateOnComponentComplete = true;
242         return;
243     }
244
245     if (!requireImplicitWidth) {
246         emit q->implicitWidthChanged();
247         // if the implicitWidth is used, then updateSize() has already been called (recursively)
248         if (requireImplicitWidth)
249             return;
250     }
251
252     invalidateImageCache();
253
254     QFontMetrics fm(font);
255     if (text.isEmpty()) {
256         q->setImplicitWidth(0);
257         q->setImplicitHeight(fm.height());
258         paintedSize = QSize(0, fm.height());
259         emit q->paintedSizeChanged();
260         q->update();
261         return;
262     }
263
264     int dy = q->height();
265     QSize size(0, 0);
266
267     //setup instance of QTextLayout for all cases other than richtext
268     if (!richText) {
269         QRect textRect = setupTextLayout();
270         if (layedOutTextRect.size() != textRect.size())
271             q->prepareGeometryChange();
272         layedOutTextRect = textRect;
273         size = textRect.size();
274         dy -= size.height();
275     } else {
276         singleline = false; // richtext can't elide or be optimized for single-line case
277         ensureDoc();
278         doc->setDefaultFont(font);
279
280         QDeclarative1Text::HAlignment horizontalAlignment = q->effectiveHAlign();
281         if (rightToLeftText) {
282             if (horizontalAlignment == QDeclarative1Text::AlignLeft)
283                 horizontalAlignment = QDeclarative1Text::AlignRight;
284             else if (horizontalAlignment == QDeclarative1Text::AlignRight)
285                 horizontalAlignment = QDeclarative1Text::AlignLeft;
286         }
287         QTextOption option;
288         option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign));
289         option.setWrapMode(QTextOption::WrapMode(wrapMode));
290         doc->setDefaultTextOption(option);
291         if (requireImplicitWidth && q->widthValid()) {
292             doc->setTextWidth(-1);
293             naturalWidth = doc->idealWidth();
294         }
295         if (wrapMode != QDeclarative1Text::NoWrap && q->widthValid())
296             doc->setTextWidth(q->width());
297         else
298             doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
299         dy -= (int)doc->size().height();
300         QSize dsize = doc->size().toSize();
301         if (dsize != layedOutTextRect.size()) {
302             q->prepareGeometryChange();
303             layedOutTextRect = QRect(QPoint(0,0), dsize);
304         }
305         size = QSize(int(doc->idealWidth()),dsize.height());
306     }
307     int yoff = 0;
308
309     if (q->heightValid()) {
310         if (vAlign == QDeclarative1Text::AlignBottom)
311             yoff = dy;
312         else if (vAlign == QDeclarative1Text::AlignVCenter)
313             yoff = dy/2;
314     }
315     q->setBaselineOffset(fm.ascent() + yoff);
316
317     //### need to comfirm cost of always setting these for richText
318     internalWidthUpdate = true;
319     if (!q->widthValid())
320         q->setImplicitWidth(size.width());
321     else if (requireImplicitWidth)
322         q->setImplicitWidth(naturalWidth);
323     internalWidthUpdate = false;
324     q->setImplicitHeight(size.height());
325     if (paintedSize != size) {
326         paintedSize = size;
327         emit q->paintedSizeChanged();
328     }
329     q->update();
330 }
331
332 /*!
333     Lays out the QDeclarative1TextPrivate::layout QTextLayout in the constraints of the QDeclarative1Text.
334
335     Returns the size of the final text.  This can be used to position the text vertically (the text is
336     already absolutely positioned horizontally).
337 */
338 QRect QDeclarative1TextPrivate::setupTextLayout()
339 {
340     // ### text layout handling should be profiled and optimized as needed
341     // what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine);
342     Q_Q(QDeclarative1Text);
343     layout.setCacheEnabled(true);
344
345     qreal lineWidth = 0;
346     int visibleCount = 0;
347
348     //set manual width
349     if (q->widthValid())
350         lineWidth = q->width();
351
352     QTextOption textOption = layout.textOption();
353     textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
354     textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
355     layout.setTextOption(textOption);
356
357     bool elideText = false;
358     bool truncate = false;
359
360     QFontMetrics fm(layout.font());
361     elidePos = QPointF();
362
363     if (requireImplicitWidth && q->widthValid()) {
364         // requires an extra layout
365         QString elidedText;
366         if (layoutTextElided) {
367             // We have provided elided text to the layout, but we must calculate unelided width.
368             elidedText = layout.text();
369             layout.setText(text);
370         }
371         layout.beginLayout();
372         forever {
373             QTextLine line = layout.createLine();
374             if (!line.isValid())
375                 break;
376         }
377         layout.endLayout();
378         QRectF br;
379         for (int i = 0; i < layout.lineCount(); ++i) {
380             QTextLine line = layout.lineAt(i);
381             br = br.united(line.naturalTextRect());
382         }
383         naturalWidth = br.width();
384         if (layoutTextElided)
385             layout.setText(elidedText);
386     }
387
388     if (maximumLineCountValid) {
389         layout.beginLayout();
390         if (!lineWidth)
391             lineWidth = INT_MAX;
392         int linesLeft = maximumLineCount;
393         int visibleTextLength = 0;
394         while (linesLeft > 0) {
395             QTextLine line = layout.createLine();
396             if (!line.isValid())
397                 break;
398
399             visibleCount++;
400             if (lineWidth)
401                 line.setLineWidth(lineWidth);
402             visibleTextLength += line.textLength();
403
404             if (--linesLeft == 0) {
405                 if (visibleTextLength < text.length()) {
406                     truncate = true;
407                     if (elideMode==QDeclarative1Text::ElideRight && q->widthValid()) {
408                         qreal elideWidth = fm.width(elideChar);
409                         // Need to correct for alignment
410                         line.setLineWidth(lineWidth-elideWidth);
411                         if (layout.text().mid(line.textStart(), line.textLength()).isRightToLeft()) {
412                             line.setPosition(QPointF(line.position().x() + elideWidth, line.position().y()));
413                             elidePos.setX(line.naturalTextRect().left() - elideWidth);
414                         } else {
415                             elidePos.setX(line.naturalTextRect().right());
416                         }
417                         elideText = true;
418                     }
419                 }
420             }
421         }
422         layout.endLayout();
423
424         //Update truncated
425         if (truncated != truncate) {
426             truncated = truncate;
427             emit q->truncatedChanged();
428         }
429     } else {
430         layout.beginLayout();
431         forever {
432             QTextLine line = layout.createLine();
433             if (!line.isValid())
434                 break;
435             visibleCount++;
436             if (lineWidth)
437                 line.setLineWidth(lineWidth);
438         }
439         layout.endLayout();
440     }
441
442     qreal height = 0;
443     QRectF br;
444     for (int i = 0; i < layout.lineCount(); ++i) {
445         QTextLine line = layout.lineAt(i);
446         // set line spacing
447         line.setPosition(QPointF(line.position().x(), height));
448         if (elideText && i == layout.lineCount()-1) {
449             elidePos.setY(height + fm.ascent());
450             br = br.united(QRectF(elidePos, QSizeF(fm.width(elideChar), fm.ascent())));
451         }
452         br = br.united(line.naturalTextRect());
453         height += (lineHeightMode == QDeclarative1Text::FixedHeight) ? lineHeight : line.height() * lineHeight;
454     }
455     br.setHeight(height);
456
457     if (!q->widthValid())
458         naturalWidth = br.width();
459
460     //Update the number of visible lines
461     if (lineCount != visibleCount) {
462         lineCount = visibleCount;
463         emit q->lineCountChanged();
464     }
465
466     return QRect(qRound(br.x()), qRound(br.y()), qCeil(br.width()), qCeil(br.height()));
467 }
468
469 /*!
470     Returns a painted version of the QDeclarative1TextPrivate::layout QTextLayout.
471     If \a drawStyle is true, the style color overrides all colors in the document.
472 */
473 QPixmap QDeclarative1TextPrivate::textLayoutImage(bool drawStyle)
474 {
475     //do layout
476     QSize size = layedOutTextRect.size();
477     //paint text
478     QPixmap img(size);
479     if (!size.isEmpty()) {
480         img.fill(Qt::transparent);
481 #ifdef Q_WS_MAC
482         bool oldSmooth = qt_applefontsmoothing_enabled;
483         qt_applefontsmoothing_enabled = false;
484 #endif
485         QPainter p(&img);
486 #ifdef Q_WS_MAC
487         qt_applefontsmoothing_enabled = oldSmooth;
488 #endif
489         drawTextLayout(&p, QPointF(-layedOutTextRect.x(),0), drawStyle);
490     }
491     return img;
492 }
493
494 /*!
495     Paints the QDeclarative1TextPrivate::layout QTextLayout into \a painter at \a pos.  If 
496     \a drawStyle is true, the style color overrides all colors in the document.
497 */
498 void QDeclarative1TextPrivate::drawTextLayout(QPainter *painter, const QPointF &pos, bool drawStyle)
499 {
500     if (drawStyle)
501         painter->setPen(styleColor);
502     else
503         painter->setPen(color);
504     painter->setFont(font);
505     layout.draw(painter, pos);
506     if (!elidePos.isNull())
507         painter->drawText(pos + elidePos, elideChar);
508 }
509
510 /*!
511     Returns a painted version of the QDeclarative1TextPrivate::doc QTextDocument.
512     If \a drawStyle is true, the style color overrides all colors in the document.
513 */
514 QPixmap QDeclarative1TextPrivate::textDocumentImage(bool drawStyle)
515 {
516     QSize size = doc->size().toSize();
517
518     //paint text
519     QPixmap img(size);
520     img.fill(Qt::transparent);
521 #ifdef Q_WS_MAC
522     bool oldSmooth = qt_applefontsmoothing_enabled;
523     qt_applefontsmoothing_enabled = false;
524 #endif
525     QPainter p(&img);
526 #ifdef Q_WS_MAC
527     qt_applefontsmoothing_enabled = oldSmooth;
528 #endif
529
530     QAbstractTextDocumentLayout::PaintContext context;
531
532     QTextOption oldOption(doc->defaultTextOption());
533     if (drawStyle) {
534         context.palette.setColor(QPalette::Text, styleColor);
535         QTextOption colorOption(doc->defaultTextOption());
536         colorOption.setFlags(QTextOption::SuppressColors);
537         doc->setDefaultTextOption(colorOption);
538     } else {
539         context.palette.setColor(QPalette::Text, color);
540     }
541     doc->documentLayout()->draw(&p, context);
542     if (drawStyle)
543         doc->setDefaultTextOption(oldOption);
544     return img;
545 }
546
547 /*!
548     Mark the image cache as dirty.
549 */
550 void QDeclarative1TextPrivate::invalidateImageCache() 
551 {
552     Q_Q(QDeclarative1Text);
553
554     if(cacheAllTextAsImage || style != QDeclarative1Text::Normal){//If actually using the image cache
555         if (imageCacheDirty)
556             return;
557
558         imageCacheDirty = true;
559         imageCache = QPixmap();
560     }
561     if (q->isComponentComplete())
562         q->update();
563 }
564
565 /*!
566     Tests if the image cache is dirty, and repaints it if it is.
567 */
568 void QDeclarative1TextPrivate::checkImageCache()
569 {
570     if (!imageCacheDirty)
571         return;
572
573     if (text.isEmpty()) {
574
575         imageCache = QPixmap();
576
577     } else {
578
579         QPixmap textImage;
580         QPixmap styledImage;
581
582         if (richText) {
583             textImage = textDocumentImage(false);
584             if (style != QDeclarative1Text::Normal)
585                 styledImage = textDocumentImage(true); //### should use styleColor
586         } else {
587             textImage = textLayoutImage(false);
588             if (style != QDeclarative1Text::Normal)
589                 styledImage = textLayoutImage(true); //### should use styleColor
590         }
591
592         switch (style) {
593         case QDeclarative1Text::Outline:
594             imageCache = drawOutline(textImage, styledImage);
595             break;
596         case QDeclarative1Text::Sunken:
597             imageCache = drawOutline(textImage, styledImage, -1);
598             break;
599         case QDeclarative1Text::Raised:
600             imageCache = drawOutline(textImage, styledImage, 1);
601             break;
602         default:
603             imageCache = textImage;
604             break;
605         }
606
607     } 
608
609     imageCacheDirty = false;
610 }
611
612 /*! 
613     Ensures the QDeclarative1TextPrivate::doc variable is set to a valid text document 
614 */
615 void QDeclarative1TextPrivate::ensureDoc()
616 {
617     if (!doc) {
618         Q_Q(QDeclarative1Text);
619         doc = new QTextDocumentWithImageResources_1(q);
620         doc->setDocumentMargin(0);
621     }
622 }
623
624 /*!
625     Draw \a styleSource as an outline around \a source and return the new image.
626 */
627 QPixmap QDeclarative1TextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource)
628 {
629     QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
630     img.fill(Qt::transparent);
631
632     QPainter ppm(&img);
633
634     QPoint pos(0, 0);
635     pos += QPoint(-1, 0);
636     ppm.drawPixmap(pos, styleSource);
637     pos += QPoint(2, 0);
638     ppm.drawPixmap(pos, styleSource);
639     pos += QPoint(-1, -1);
640     ppm.drawPixmap(pos, styleSource);
641     pos += QPoint(0, 2);
642     ppm.drawPixmap(pos, styleSource);
643
644     pos += QPoint(0, -1);
645     ppm.drawPixmap(pos, source);
646     ppm.end();
647
648     return img;
649 }
650
651 /*!
652     Draw \a styleSource below \a source at \a yOffset and return the new image.
653 */
654 QPixmap QDeclarative1TextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset)
655 {
656     QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
657     img.fill(Qt::transparent);
658
659     QPainter ppm(&img);
660
661     ppm.drawPixmap(QPoint(0, yOffset), styleSource);
662     ppm.drawPixmap(0, 0, source);
663
664     ppm.end();
665
666     return img;
667 }
668
669 /*!
670     \qmlclass Text QDeclarative1Text
671     \inqmlmodule QtQuick 1
672     \ingroup qml-basic-visual-elements
673     \since QtQuick 1.0
674     \brief The Text item allows you to add formatted text to a scene.
675     \inherits Item
676
677     Text items can display both plain and rich text. For example, red text with
678     a specific font and size can be defined like this:
679
680     \qml
681     Text {
682         text: "Hello World!"
683         font.family: "Helvetica"
684         font.pointSize: 24
685         color: "red"
686     }
687     \endqml
688
689     Rich text is defined using HTML-style markup:
690
691     \qml
692     Text {
693         text: "<b>Hello</b> <i>World!</i>"
694     }
695     \endqml
696
697     \image declarative-text.png
698
699     If height and width are not explicitly set, Text will attempt to determine how
700     much room is needed and set it accordingly. Unless \l wrapMode is set, it will always
701     prefer width to height (all text will be placed on a single line).
702
703     The \l elide property can alternatively be used to fit a single line of
704     plain text to a set width.
705
706     Note that the \l{Supported HTML Subset} is limited. Also, if the text contains
707     HTML img tags that load remote images, the text is reloaded.
708
709     Text provides read-only text. For editable text, see \l TextEdit.
710
711     \sa {declarative/text/fonts}{Fonts example}
712 */
713 QDeclarative1Text::QDeclarative1Text(QDeclarativeItem *parent)
714   : QDeclarative1ImplicitSizeItem(*(new QDeclarative1TextPrivate), parent)
715 {
716 }
717
718 QDeclarative1Text::~QDeclarative1Text()
719 {
720 }
721
722 /*!
723   \qmlproperty bool QtQuick1::Text::clip
724   This property holds whether the text is clipped.
725
726   Note that if the text does not fit in the bounding rectangle it will be abruptly chopped.
727
728   If you want to display potentially long text in a limited space, you probably want to use \c elide instead.
729 */
730
731 /*!
732     \qmlproperty bool QtQuick1::Text::smooth
733
734     This property holds whether the text is smoothly scaled or transformed.
735
736     Smooth filtering gives better visual quality, but is slower.  If
737     the item is displayed at its natural size, this property has no visual or
738     performance effect.
739
740     \note Generally scaling artifacts are only visible if the item is stationary on
741     the screen.  A common pattern when animating an item is to disable smooth
742     filtering at the beginning of the animation and reenable it at the conclusion.
743 */
744
745 /*!
746     \qmlsignal QtQuick1::Text::onLinkActivated(string link)
747
748     This handler is called when the user clicks on a link embedded in the text.
749     The link must be in rich text or HTML format and the 
750     \a link string provides access to the particular link. 
751
752     \snippet doc/src/snippets/declarative/text/onLinkActivated.qml 0
753
754     The example code will display the text 
755     "The main website is at \l{http://qt.nokia.com}{Nokia Qt DF}."
756
757     Clicking on the highlighted link will output 
758     \tt{http://qt.nokia.com link activated} to the console.
759 */
760
761 /*!
762     \qmlproperty string QtQuick1::Text::font.family
763
764     Sets the family name of the font.
765
766     The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
767     If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
768     If the family isn't available a family will be set using the font matching algorithm.
769 */
770
771 /*!
772     \qmlproperty bool QtQuick1::Text::font.bold
773
774     Sets whether the font weight is bold.
775 */
776
777 /*!
778     \qmlproperty enumeration QtQuick1::Text::font.weight
779
780     Sets the font's weight.
781
782     The weight can be one of:
783     \list
784     \o Font.Light
785     \o Font.Normal - the default
786     \o Font.DemiBold
787     \o Font.Bold
788     \o Font.Black
789     \endlist
790
791     \qml
792     Text { text: "Hello"; font.weight: Font.DemiBold }
793     \endqml
794 */
795
796 /*!
797     \qmlproperty bool QtQuick1::Text::font.italic
798
799     Sets whether the font has an italic style.
800 */
801
802 /*!
803     \qmlproperty bool QtQuick1::Text::font.underline
804
805     Sets whether the text is underlined.
806 */
807
808 /*!
809     \qmlproperty bool QtQuick1::Text::font.strikeout
810
811     Sets whether the font has a strikeout style.
812 */
813
814 /*!
815     \qmlproperty real QtQuick1::Text::font.pointSize
816
817     Sets the font size in points. The point size must be greater than zero.
818 */
819
820 /*!
821     \qmlproperty int QtQuick1::Text::font.pixelSize
822
823     Sets the font size in pixels.
824
825     Using this function makes the font device dependent.
826     Use \c pointSize to set the size of the font in a device independent manner.
827 */
828
829 /*!
830     \qmlproperty real QtQuick1::Text::font.letterSpacing
831
832     Sets the letter spacing for the font.
833
834     Letter spacing changes the default spacing between individual letters in the font.
835     A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
836 */
837
838 /*!
839     \qmlproperty real QtQuick1::Text::font.wordSpacing
840
841     Sets the word spacing for the font.
842
843     Word spacing changes the default spacing between individual words.
844     A positive value increases the word spacing by a corresponding amount of pixels,
845     while a negative value decreases the inter-word spacing accordingly.
846 */
847
848 /*!
849     \qmlproperty enumeration QtQuick1::Text::font.capitalization
850
851     Sets the capitalization for the text.
852
853     \list
854     \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
855     \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
856     \o Font.AllLowercase         - This alters the text to be rendered in all lowercase type.
857     \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
858     \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
859     \endlist
860
861     \qml
862     Text { text: "Hello"; font.capitalization: Font.AllLowercase }
863     \endqml
864 */
865 QFont QDeclarative1Text::font() const
866 {
867     Q_D(const QDeclarative1Text);
868     return d->sourceFont;
869 }
870
871 void QDeclarative1Text::setFont(const QFont &font)
872 {
873     Q_D(QDeclarative1Text);
874     if (d->sourceFont == font)
875         return;
876
877     d->sourceFont = font;
878     QFont oldFont = d->font;
879     d->font = font;
880     if (d->font.pointSizeF() != -1) {
881         // 0.5pt resolution
882         qreal size = qRound(d->font.pointSizeF()*2.0);
883         d->font.setPointSizeF(size/2.0);
884     }
885
886     if (oldFont != d->font)
887         d->updateLayout();
888
889     emit fontChanged(d->sourceFont);
890 }
891
892 /*!
893     \qmlproperty string QtQuick1::Text::text
894
895     The text to display. Text supports both plain and rich text strings.
896
897     The item will try to automatically determine whether the text should
898     be treated as rich text. This determination is made using Qt::mightBeRichText().
899 */
900 QString QDeclarative1Text::text() const
901 {
902     Q_D(const QDeclarative1Text);
903     return d->text;
904 }
905
906 void QDeclarative1Text::setText(const QString &n)
907 {
908     Q_D(QDeclarative1Text);
909     if (d->text == n)
910         return;
911
912     d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(n));
913     d->text = n;
914     if (isComponentComplete()) {
915         if (d->richText) {
916             d->ensureDoc();
917             d->doc->setText(n);
918             d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
919         } else {
920             d->rightToLeftText = d->text.isRightToLeft();
921         }
922         d->determineHorizontalAlignment();
923     }
924     d->updateLayout();
925     emit textChanged(d->text);
926 }
927
928
929 /*!
930     \qmlproperty color QtQuick1::Text::color
931
932     The text color.
933
934     An example of green text defined using hexadecimal notation:
935     \qml
936     Text {
937         color: "#00FF00"
938         text: "green text"
939     }
940     \endqml
941
942     An example of steel blue text defined using an SVG color name:
943     \qml
944     Text {
945         color: "steelblue"
946         text: "blue text"
947     }
948     \endqml
949 */
950 QColor QDeclarative1Text::color() const
951 {
952     Q_D(const QDeclarative1Text);
953     return d->color;
954 }
955
956 void QDeclarative1Text::setColor(const QColor &color)
957 {
958     Q_D(QDeclarative1Text);
959     if (d->color == color)
960         return;
961
962     d->color = color;
963     d->invalidateImageCache();
964     emit colorChanged(d->color);
965 }
966
967 /*!
968     \qmlproperty enumeration QtQuick1::Text::style
969
970     Set an additional text style.
971
972     Supported text styles are:
973     \list
974     \o Text.Normal - the default
975     \o Text.Outline
976     \o Text.Raised
977     \o Text.Sunken
978     \endlist
979
980     \qml
981     Row {
982         Text { font.pointSize: 24; text: "Normal" }
983         Text { font.pointSize: 24; text: "Raised"; style: Text.Raised; styleColor: "#AAAAAA" }
984         Text { font.pointSize: 24; text: "Outline";style: Text.Outline; styleColor: "red" }
985         Text { font.pointSize: 24; text: "Sunken"; style: Text.Sunken; styleColor: "#AAAAAA" }
986     }
987     \endqml
988
989     \image declarative-textstyle.png
990 */
991 QDeclarative1Text::TextStyle QDeclarative1Text::style() const
992 {
993     Q_D(const QDeclarative1Text);
994     return d->style;
995 }
996
997 void QDeclarative1Text::setStyle(QDeclarative1Text::TextStyle style)
998 {
999     Q_D(QDeclarative1Text);
1000     if (d->style == style)
1001         return;
1002
1003     // changing to/from Normal requires the boundingRect() to change
1004     if (isComponentComplete() && (d->style == Normal || style == Normal))
1005         prepareGeometryChange();
1006     d->style = style;
1007     d->invalidateImageCache();
1008     emit styleChanged(d->style);
1009 }
1010
1011 /*!
1012     \qmlproperty color QtQuick1::Text::styleColor
1013
1014     Defines the secondary color used by text styles.
1015
1016     \c styleColor is used as the outline color for outlined text, and as the
1017     shadow color for raised or sunken text. If no style has been set, it is not
1018     used at all.
1019
1020     \qml
1021     Text { font.pointSize: 18; text: "hello"; style: Text.Raised; styleColor: "gray" }
1022     \endqml
1023
1024     \sa style
1025  */
1026 QColor QDeclarative1Text::styleColor() const
1027 {
1028     Q_D(const QDeclarative1Text);
1029     return d->styleColor;
1030 }
1031
1032 void QDeclarative1Text::setStyleColor(const QColor &color)
1033 {
1034     Q_D(QDeclarative1Text);
1035     if (d->styleColor == color)
1036         return;
1037
1038     d->styleColor = color;
1039     d->invalidateImageCache();
1040     emit styleColorChanged(d->styleColor);
1041 }
1042
1043
1044 /*!
1045     \qmlproperty enumeration QtQuick1::Text::horizontalAlignment
1046     \qmlproperty enumeration QtQuick1::Text::verticalAlignment
1047     \qmlproperty enumeration QtQuick1::Text::effectiveHorizontalAlignment
1048
1049     Sets the horizontal and vertical alignment of the text within the Text items
1050     width and height. By default, the text is vertically aligned to the top. Horizontal
1051     alignment follows the natural alignment of the text, for example text that is read
1052     from left to right will be aligned to the left.
1053
1054     The valid values for \c horizontalAlignment are \c Text.AlignLeft, \c Text.AlignRight, \c Text.AlignHCenter and
1055     \c Text.AlignJustify.  The valid values for \c verticalAlignment are \c Text.AlignTop, \c Text.AlignBottom
1056     and \c Text.AlignVCenter.
1057
1058     Note that for a single line of text, the size of the text is the area of the text. In this common case,
1059     all alignments are equivalent. If you want the text to be, say, centered in its parent, then you will
1060     need to either modify the Item::anchors, or set horizontalAlignment to Text.AlignHCenter and bind the width to 
1061     that of the parent.
1062
1063     When using the attached property LayoutMirroring::enabled to mirror application
1064     layouts, the horizontal alignment of text will also be mirrored. However, the property
1065     \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
1066     of Text, use the read-only property \c effectiveHorizontalAlignment.
1067 */
1068 QDeclarative1Text::HAlignment QDeclarative1Text::hAlign() const
1069 {
1070     Q_D(const QDeclarative1Text);
1071     return d->hAlign;
1072 }
1073
1074 void QDeclarative1Text::setHAlign(HAlignment align)
1075 {
1076     Q_D(QDeclarative1Text);
1077     bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
1078     d->hAlignImplicit = false;
1079     if (d->setHAlign(align, forceAlign) && isComponentComplete())
1080         d->updateLayout();
1081 }
1082
1083 void QDeclarative1Text::resetHAlign()
1084 {
1085     Q_D(QDeclarative1Text);
1086     d->hAlignImplicit = true;
1087     if (d->determineHorizontalAlignment() && isComponentComplete())
1088         d->updateLayout();
1089 }
1090
1091 QDeclarative1Text::HAlignment QDeclarative1Text::effectiveHAlign() const
1092 {
1093     Q_D(const QDeclarative1Text);
1094     QDeclarative1Text::HAlignment effectiveAlignment = d->hAlign;
1095     if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
1096         switch (d->hAlign) {
1097         case QDeclarative1Text::AlignLeft:
1098             effectiveAlignment = QDeclarative1Text::AlignRight;
1099             break;
1100         case QDeclarative1Text::AlignRight:
1101             effectiveAlignment = QDeclarative1Text::AlignLeft;
1102             break;
1103         default:
1104             break;
1105         }
1106     }
1107     return effectiveAlignment;
1108 }
1109
1110 bool QDeclarative1TextPrivate::setHAlign(QDeclarative1Text::HAlignment alignment, bool forceAlign)
1111 {
1112     Q_Q(QDeclarative1Text);
1113     if (hAlign != alignment || forceAlign) {
1114         QDeclarative1Text::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
1115         hAlign = alignment;
1116
1117         emit q->horizontalAlignmentChanged(hAlign);
1118         if (oldEffectiveHAlign != q->effectiveHAlign())
1119             emit q->effectiveHorizontalAlignmentChanged();
1120         return true;
1121     }
1122     return false;
1123 }
1124
1125 bool QDeclarative1TextPrivate::determineHorizontalAlignment()
1126 {
1127     Q_Q(QDeclarative1Text);
1128     if (hAlignImplicit && q->isComponentComplete()) {
1129         bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
1130         return setHAlign(alignToRight ? QDeclarative1Text::AlignRight : QDeclarative1Text::AlignLeft);
1131     }
1132     return false;
1133 }
1134
1135 void QDeclarative1TextPrivate::mirrorChange()
1136 {
1137     Q_Q(QDeclarative1Text);
1138     if (q->isComponentComplete()) {
1139         if (!hAlignImplicit && (hAlign == QDeclarative1Text::AlignRight || hAlign == QDeclarative1Text::AlignLeft)) {
1140             updateLayout();
1141             emit q->effectiveHorizontalAlignmentChanged();
1142         }
1143     }
1144 }
1145
1146 QTextDocument *QDeclarative1TextPrivate::textDocument()
1147 {
1148     return doc;
1149 }
1150
1151 QDeclarative1Text::VAlignment QDeclarative1Text::vAlign() const
1152 {
1153     Q_D(const QDeclarative1Text);
1154     return d->vAlign;
1155 }
1156
1157 void QDeclarative1Text::setVAlign(VAlignment align)
1158 {
1159     Q_D(QDeclarative1Text);
1160     if (d->vAlign == align)
1161         return;
1162
1163     if (isComponentComplete())
1164         prepareGeometryChange();
1165     d->vAlign = align;
1166     emit verticalAlignmentChanged(align);
1167 }
1168
1169 /*!
1170     \qmlproperty enumeration QtQuick1::Text::wrapMode
1171
1172     Set this property to wrap the text to the Text item's width.  The text will only
1173     wrap if an explicit width has been set.  wrapMode can be one of:
1174
1175     \list
1176     \o Text.NoWrap (default) - no wrapping will be performed. If the text contains insufficient newlines, then \l paintedWidth will exceed a set width.
1177     \o Text.WordWrap - wrapping is done on word boundaries only. If a word is too long, \l paintedWidth will exceed a set width.
1178     \o Text.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
1179     \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.
1180     \endlist
1181 */
1182 QDeclarative1Text::WrapMode QDeclarative1Text::wrapMode() const
1183 {
1184     Q_D(const QDeclarative1Text);
1185     return d->wrapMode;
1186 }
1187
1188 void QDeclarative1Text::setWrapMode(WrapMode mode)
1189 {
1190     Q_D(QDeclarative1Text);
1191     if (mode == d->wrapMode)
1192         return;
1193
1194     d->wrapMode = mode;
1195     d->updateLayout();
1196     
1197     emit wrapModeChanged();
1198 }
1199
1200 /*!
1201     \qmlproperty int QtQuick1::Text::lineCount
1202     \since Quick 1.1
1203
1204     Returns the number of lines visible in the text item.
1205
1206     This property is not supported for rich text.
1207
1208     \sa maximumLineCount
1209 */
1210 int QDeclarative1Text::lineCount() const
1211 {
1212     Q_D(const QDeclarative1Text);
1213     return d->lineCount;
1214 }
1215
1216 /*!
1217     \qmlproperty bool QtQuick1::Text::truncated
1218     \since Quick 1.1
1219
1220     Returns true if the text has been truncated due to \l maximumLineCount
1221     or \l elide.
1222
1223     This property is not supported for rich text.
1224
1225     \sa maximumLineCount, elide
1226 */
1227 bool QDeclarative1Text::truncated() const
1228 {
1229     Q_D(const QDeclarative1Text);
1230     return d->truncated;
1231 }
1232
1233 /*!
1234     \qmlproperty int QtQuick1::Text::maximumLineCount
1235     \since Quick 1.1
1236
1237     Set this property to limit the number of lines that the text item will show.
1238     If elide is set to Text.ElideRight, the text will be elided appropriately.
1239     By default, this is the value of the largest possible integer.
1240
1241     This property is not supported for rich text.
1242
1243     \sa lineCount, elide
1244 */
1245 int QDeclarative1Text::maximumLineCount() const
1246 {
1247     Q_D(const QDeclarative1Text);
1248     return d->maximumLineCount;
1249 }
1250
1251 void QDeclarative1Text::setMaximumLineCount(int lines)
1252 {
1253     Q_D(QDeclarative1Text);
1254
1255     d->maximumLineCountValid = lines==INT_MAX ? false : true;
1256     if (d->maximumLineCount != lines) {
1257         d->maximumLineCount = lines;
1258         d->updateLayout();
1259         emit maximumLineCountChanged();
1260     }
1261 }
1262
1263 void QDeclarative1Text::resetMaximumLineCount()
1264 {
1265     Q_D(QDeclarative1Text);
1266     setMaximumLineCount(INT_MAX);
1267     d->elidePos = QPointF();
1268     if (d->truncated != false) {
1269         d->truncated = false;
1270         emit truncatedChanged();
1271     }
1272 }
1273
1274 /*!
1275     \qmlproperty enumeration QtQuick1::Text::textFormat
1276
1277     The way the text property should be displayed.
1278
1279     Supported text formats are:
1280     
1281     \list
1282     \o Text.AutoText (default)
1283     \o Text.PlainText
1284     \o Text.RichText
1285     \o Text.StyledText
1286     \endlist
1287
1288     If the text format is \c Text.AutoText the text element
1289     will automatically determine whether the text should be treated as
1290     rich text.  This determination is made using Qt::mightBeRichText().
1291
1292     Text.StyledText is an optimized format supporting some basic text
1293     styling markup, in the style of html 3.2:
1294
1295     \code
1296     <font size="4" color="#ff0000">font size and color</font>
1297     <b>bold</b>
1298     <i>italic</i>
1299     <br>
1300     &gt; &lt; &amp;
1301     \endcode
1302
1303     \c Text.StyledText parser is strict, requiring tags to be correctly nested.
1304
1305     \table
1306     \row
1307     \o
1308     \qml
1309 Column {
1310     Text {
1311         font.pointSize: 24
1312         text: "<b>Hello</b> <i>World!</i>"
1313     }
1314     Text {
1315         font.pointSize: 24
1316         textFormat: Text.RichText
1317         text: "<b>Hello</b> <i>World!</i>"
1318     }
1319     Text {
1320         font.pointSize: 24
1321         textFormat: Text.PlainText
1322         text: "<b>Hello</b> <i>World!</i>"
1323     }
1324 }
1325     \endqml
1326     \o \image declarative-textformat.png
1327     \endtable
1328 */
1329 QDeclarative1Text::TextFormat QDeclarative1Text::textFormat() const
1330 {
1331     Q_D(const QDeclarative1Text);
1332     return d->format;
1333 }
1334
1335 void QDeclarative1Text::setTextFormat(TextFormat format)
1336 {
1337     Q_D(QDeclarative1Text);
1338     if (format == d->format)
1339         return;
1340     d->format = format;
1341     bool wasRich = d->richText;
1342     d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
1343
1344     if (!wasRich && d->richText && isComponentComplete()) {
1345         d->ensureDoc();
1346         d->doc->setText(d->text);
1347     }
1348
1349     d->updateLayout();
1350
1351     emit textFormatChanged(d->format);
1352 }
1353
1354 /*!
1355     \qmlproperty enumeration QtQuick1::Text::elide
1356
1357     Set this property to elide parts of the text fit to the Text item's width.
1358     The text will only elide if an explicit width has been set.
1359
1360     This property cannot be used with rich text.
1361
1362     Eliding can be:
1363     \list
1364     \o Text.ElideNone  - the default
1365     \o Text.ElideLeft
1366     \o Text.ElideMiddle
1367     \o Text.ElideRight
1368     \endlist
1369
1370     If this property is set to Text.ElideRight, it can be used with multiline
1371     text. The text will only elide if maximumLineCount has been set.
1372
1373     If the text is a multi-length string, and the mode is not \c Text.ElideNone,
1374     the first string that fits will be used, otherwise the last will be elided.
1375
1376     Multi-length strings are ordered from longest to shortest, separated by the
1377     Unicode "String Terminator" character \c U009C (write this in QML with \c{"\u009C"} or \c{"\x9C"}).
1378 */
1379 QDeclarative1Text::TextElideMode QDeclarative1Text::elideMode() const
1380 {
1381     Q_D(const QDeclarative1Text);
1382     return d->elideMode;
1383 }
1384
1385 void QDeclarative1Text::setElideMode(QDeclarative1Text::TextElideMode mode)
1386 {
1387     Q_D(QDeclarative1Text);
1388     if (mode == d->elideMode)
1389         return;
1390
1391     d->elideMode = mode;
1392     d->updateLayout();
1393     
1394     emit elideModeChanged(d->elideMode);
1395 }
1396
1397 /*! \internal */
1398 QRectF QDeclarative1Text::boundingRect() const
1399 {
1400     Q_D(const QDeclarative1Text);
1401
1402     QRect rect = d->layedOutTextRect;
1403     if (d->style != Normal)
1404         rect.adjust(-1, 0, 1, 2);
1405
1406     // Could include font max left/right bearings to either side of rectangle.
1407
1408     int h = height();
1409     switch (d->vAlign) {
1410     case AlignTop:
1411         break;
1412     case AlignBottom:
1413         rect.moveTop(h - rect.height());
1414         break;
1415     case AlignVCenter:
1416         rect.moveTop((h - rect.height()) / 2);
1417         break;
1418     }
1419
1420     return QRectF(rect);
1421 }
1422
1423 /*! \internal */
1424 void QDeclarative1Text::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
1425 {
1426     Q_D(QDeclarative1Text);
1427     if ((!d->internalWidthUpdate && newGeometry.width() != oldGeometry.width())
1428             && (d->wrapMode != QDeclarative1Text::NoWrap
1429                 || d->elideMode != QDeclarative1Text::ElideNone
1430                 || d->hAlign != QDeclarative1Text::AlignLeft)) {
1431         if ((d->singleline || d->maximumLineCountValid) && d->elideMode != QDeclarative1Text::ElideNone && widthValid()) {
1432             // We need to re-elide
1433             d->updateLayout();
1434         } else {
1435             // We just need to re-layout
1436             d->updateSize();
1437         }
1438     }
1439
1440     QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
1441 }
1442
1443 /*!
1444     \qmlproperty real QtQuick1::Text::paintedWidth
1445
1446     Returns the width of the text, including width past the width
1447     which is covered due to insufficient wrapping if WrapMode is set.
1448 */
1449 qreal QDeclarative1Text::paintedWidth() const
1450 {
1451     Q_D(const QDeclarative1Text);
1452     return d->paintedSize.width();
1453 }
1454
1455 /*!
1456     \qmlproperty real QtQuick1::Text::paintedHeight
1457
1458     Returns the height of the text, including height past the height
1459     which is covered due to there being more text than fits in the set height.
1460 */
1461 qreal QDeclarative1Text::paintedHeight() const
1462 {
1463     Q_D(const QDeclarative1Text);
1464     return d->paintedSize.height();
1465 }
1466
1467 /*!
1468     \qmlproperty real QtQuick1::Text::lineHeight
1469     \since Quick 1.1
1470
1471     Sets the line height for the text.
1472     The value can be in pixels or a multiplier depending on lineHeightMode.
1473
1474     The default value is a multiplier of 1.0.
1475     The line height must be a positive value.
1476 */
1477 qreal QDeclarative1Text::lineHeight() const
1478 {
1479     Q_D(const QDeclarative1Text);
1480     return d->lineHeight;
1481 }
1482
1483 void QDeclarative1Text::setLineHeight(qreal lineHeight)
1484 {
1485     Q_D(QDeclarative1Text);
1486
1487     if ((d->lineHeight == lineHeight) || (lineHeight < 0.0))
1488         return;
1489
1490     d->lineHeight = lineHeight;
1491     d->updateLayout();
1492     emit lineHeightChanged(lineHeight);
1493 }
1494
1495 /*!
1496     \qmlproperty enumeration QtQuick1::Text::lineHeightMode
1497
1498     This property determines how the line height is specified.
1499     The possible values are:
1500
1501     \list
1502     \o Text.ProportionalHeight (default) - this sets the spacing proportional to the
1503        line (as a multiplier). For example, set to 2 for double spacing.
1504     \o Text.FixedHeight - this sets the line height to a fixed line height (in pixels).
1505     \endlist
1506 */
1507 QDeclarative1Text::LineHeightMode QDeclarative1Text::lineHeightMode() const
1508 {
1509     Q_D(const QDeclarative1Text);
1510     return d->lineHeightMode;
1511 }
1512
1513 void QDeclarative1Text::setLineHeightMode(LineHeightMode mode)
1514 {
1515     Q_D(QDeclarative1Text);
1516     if (mode == d->lineHeightMode)
1517         return;
1518
1519     d->lineHeightMode = mode;
1520     d->updateLayout();
1521
1522     emit lineHeightModeChanged(mode);
1523 }
1524
1525 /*!
1526     Returns the number of resources (images) that are being loaded asynchronously.
1527 */
1528 int QDeclarative1Text::resourcesLoading() const
1529 {
1530     Q_D(const QDeclarative1Text);
1531     return d->doc ? d->doc->resourcesLoading() : 0;
1532 }
1533
1534 /*! \internal */
1535 void QDeclarative1Text::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
1536 {
1537     Q_D(QDeclarative1Text);
1538
1539     if (d->cacheAllTextAsImage || d->style != Normal) {
1540         d->checkImageCache();
1541         if (d->imageCache.isNull())
1542             return;
1543
1544         bool oldAA = p->testRenderHint(QPainter::Antialiasing);
1545         bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform);
1546         if (d->smooth)
1547             p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth);
1548
1549         QRect br = boundingRect().toRect();
1550
1551         bool needClip = clip() && (d->imageCache.width() > width() ||
1552                                    d->imageCache.height() > height());
1553
1554         if (needClip)
1555             p->drawPixmap(0, 0, width(), height(), d->imageCache, -br.x(), -br.y(), width(), height());
1556         else
1557             p->drawPixmap(br.x(), br.y(), d->imageCache);
1558
1559         if (d->smooth) {
1560             p->setRenderHint(QPainter::Antialiasing, oldAA);
1561             p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth);
1562         }
1563     } else {
1564         QRectF bounds = boundingRect();
1565
1566         bool needClip = clip() && (d->layedOutTextRect.width() > width() ||
1567                                    d->layedOutTextRect.height() > height());
1568
1569         if (needClip) {
1570             p->save();
1571             p->setClipRect(0, 0, width(), height(), Qt::IntersectClip);
1572         }
1573         if (d->richText) {
1574             QAbstractTextDocumentLayout::PaintContext context;
1575             context.palette.setColor(QPalette::Text, d->color);
1576             p->translate(bounds.x(), bounds.y());
1577             d->doc->documentLayout()->draw(p, context);
1578             p->translate(-bounds.x(), -bounds.y());
1579         } else {
1580             d->drawTextLayout(p, QPointF(0, bounds.y()), false);
1581         }
1582
1583         if (needClip) {
1584             p->restore();
1585         }
1586     }
1587 }
1588
1589 /*! \internal */
1590 void QDeclarative1Text::componentComplete()
1591 {
1592     Q_D(QDeclarative1Text);
1593     QDeclarativeItem::componentComplete();
1594     if (d->updateOnComponentComplete) {
1595         d->updateOnComponentComplete = false;
1596         if (d->richText) {
1597             d->ensureDoc();
1598             d->doc->setText(d->text);
1599             d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
1600         } else {
1601             d->rightToLeftText = d->text.isRightToLeft();
1602         }
1603         d->determineHorizontalAlignment();
1604         d->updateLayout();
1605     }
1606 }
1607
1608 /*!  \internal */
1609 void QDeclarative1Text::mousePressEvent(QGraphicsSceneMouseEvent *event)
1610 {
1611     Q_D(QDeclarative1Text);
1612
1613     if (!d->richText || !d->doc || d->doc->documentLayout()->anchorAt(event->pos()).isEmpty()) {
1614         event->setAccepted(false);
1615         d->activeLink.clear();
1616     } else {
1617         d->activeLink = d->doc->documentLayout()->anchorAt(event->pos());
1618     }
1619
1620     // ### may malfunction if two of the same links are clicked & dragged onto each other)
1621
1622     if (!event->isAccepted())
1623         QDeclarativeItem::mousePressEvent(event);
1624
1625 }
1626
1627 /*! \internal */
1628 void QDeclarative1Text::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1629 {
1630     Q_D(QDeclarative1Text);
1631
1632         // ### confirm the link, and send a signal out
1633     if (d->richText && d->doc && d->activeLink == d->doc->documentLayout()->anchorAt(event->pos()))
1634         emit linkActivated(d->activeLink);
1635     else
1636         event->setAccepted(false);
1637
1638     if (!event->isAccepted())
1639         QDeclarativeItem::mouseReleaseEvent(event);
1640 }
1641
1642
1643
1644 QT_END_NAMESPACE
1645
1646 #include "qdeclarativetext.moc"