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