Merge remote branch 'gerrit/master' into refactor
[profile/ivi/qtbase.git] / src / widgets / widgets / qlabel.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 QtGui 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 "qpainter.h"
43 #include "qevent.h"
44 #include "qdrawutil.h"
45 #include "qapplication.h"
46 #include "qabstractbutton.h"
47 #include "qstyle.h"
48 #include "qstyleoption.h"
49 #include <limits.h>
50 #include "qaction.h"
51 #include "qclipboard.h"
52 #include <qdebug.h>
53 #include <qurl.h>
54 #include "qlabel_p.h"
55 #include "private/qstylesheetstyle_p.h"
56 #include <qmath.h>
57
58 #ifndef QT_NO_ACCESSIBILITY
59 #include <qaccessible.h>
60 #endif
61
62 QT_BEGIN_NAMESPACE
63
64 /*!
65     \class QLabel
66     \brief The QLabel widget provides a text or image display.
67
68     \ingroup basicwidgets
69
70     QLabel is used for displaying text or an image. No user
71     interaction functionality is provided. The visual appearance of
72     the label can be configured in various ways, and it can be used
73     for specifying a focus mnemonic key for another widget.
74
75     A QLabel can contain any of the following content types:
76
77     \table
78     \header \o Content \o Setting
79     \row \o Plain text
80          \o Pass a QString to setText().
81     \row \o Rich text
82          \o Pass a QString that contains rich text to setText().
83     \row \o A pixmap
84          \o Pass a QPixmap to setPixmap().
85     \row \o A movie
86          \o Pass a QMovie to setMovie().
87     \row \o A number
88          \o Pass an \e int or a \e double to setNum(), which converts
89             the number to plain text.
90     \row \o Nothing
91          \o The same as an empty plain text. This is the default. Set
92             by clear().
93     \endtable
94
95     \warning When passing a QString to the constructor or calling setText(),
96     make sure to sanitize your input, as QLabel tries to guess whether it
97     displays the text as plain text or as rich text. You may want to call
98     setTextFormat() explicitly, e.g. in case you expect the text to be in
99     plain format but cannot control the text source (for instance when
100     displaying data loaded from the Web).
101
102     When the content is changed using any of these functions, any
103     previous content is cleared.
104
105     By default, labels display \l{alignment}{left-aligned, vertically-centered}
106     text and images, where any tabs in the text to be displayed are
107     \l{Qt::TextExpandTabs}{automatically expanded}. However, the look
108     of a QLabel can be adjusted and fine-tuned in several ways.
109
110     The positioning of the content within the QLabel widget area can
111     be tuned with setAlignment() and setIndent(). Text content can
112     also wrap lines along word boundaries with setWordWrap(). For
113     example, this code sets up a sunken panel with a two-line text in
114     the bottom right corner (both lines being flush with the right
115     side of the label):
116
117     \snippet doc/src/snippets/code/src_gui_widgets_qlabel.cpp 0
118
119     The properties and functions QLabel inherits from QFrame can also
120     be used to specify the widget frame to be used for any given label.
121
122     A QLabel is often used as a label for an interactive widget. For
123     this use QLabel provides a useful mechanism for adding an
124     mnemonic (see QKeySequence) that will set the keyboard focus to
125     the other widget (called the QLabel's "buddy"). For example:
126
127     \snippet doc/src/snippets/code/src_gui_widgets_qlabel.cpp 1
128
129     In this example, keyboard focus is transferred to the label's
130     buddy (the QLineEdit) when the user presses Alt+P. If the buddy
131     was a button (inheriting from QAbstractButton), triggering the
132     mnemonic would emulate a button click.
133
134     \table 100%
135     \row
136     \o \inlineimage macintosh-label.png Screenshot of a Macintosh style label
137     \o A label shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
138     \row
139     \o \inlineimage plastique-label.png Screenshot of a Plastique style label
140     \o A label shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
141     \row
142     \o \inlineimage windowsxp-label.png Screenshot of a Windows XP style label
143     \o A label shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
144     \endtable
145
146     \sa QLineEdit, QTextEdit, QPixmap, QMovie,
147         {fowler}{GUI Design Handbook: Label}
148 */
149
150 #ifndef QT_NO_PICTURE
151 /*!
152     Returns the label's picture or 0 if the label doesn't have a
153     picture.
154 */
155
156 const QPicture *QLabel::picture() const
157 {
158     Q_D(const QLabel);
159     return d->picture;
160 }
161 #endif
162
163
164 /*!
165     Constructs an empty label.
166
167     The \a parent and widget flag \a f, arguments are passed
168     to the QFrame constructor.
169
170     \sa setAlignment(), setFrameStyle(), setIndent()
171 */
172 QLabel::QLabel(QWidget *parent, Qt::WindowFlags f)
173     : QFrame(*new QLabelPrivate(), parent, f)
174 {
175     Q_D(QLabel);
176     d->init();
177 }
178
179 /*!
180     Constructs a label that displays the text, \a text.
181
182     The \a parent and widget flag \a f, arguments are passed
183     to the QFrame constructor.
184
185     \sa setText(), setAlignment(), setFrameStyle(), setIndent()
186 */
187 QLabel::QLabel(const QString &text, QWidget *parent, Qt::WindowFlags f)
188         : QFrame(*new QLabelPrivate(), parent, f)
189 {
190     Q_D(QLabel);
191     d->init();
192     setText(text);
193 }
194
195
196 #ifdef QT3_SUPPORT
197 /*! \obsolete
198     Constructs an empty label.
199
200     The \a parent, \a name and widget flag \a f, arguments are passed
201     to the QFrame constructor.
202
203     \sa setAlignment(), setFrameStyle(), setIndent()
204 */
205
206 QLabel::QLabel(QWidget *parent, const char *name, Qt::WindowFlags f)
207     : QFrame(*new QLabelPrivate(), parent, f)
208 {
209     Q_D(QLabel);
210     if (name)
211         setObjectName(QString::fromAscii(name));
212     d->init();
213 }
214
215
216 /*! \obsolete
217     Constructs a label that displays the text, \a text.
218
219     The \a parent, \a name and widget flag \a f, arguments are passed
220     to the QFrame constructor.
221
222     \sa setText(), setAlignment(), setFrameStyle(), setIndent()
223 */
224
225 QLabel::QLabel(const QString &text, QWidget *parent, const char *name,
226                 Qt::WindowFlags f)
227         : QFrame(*new QLabelPrivate(), parent, f)
228 {
229     Q_D(QLabel);
230     if (name)
231         setObjectName(QString::fromAscii(name));
232     d->init();
233     setText(text);
234 }
235
236
237 /*! \obsolete
238     Constructs a label that displays the text \a text. The label has a
239     buddy widget, \a buddy.
240
241     If the \a text contains an underlined letter (a letter preceded by
242     an ampersand, \&), when the user presses Alt+ the underlined letter,
243     focus is passed to the buddy widget.
244
245     The \a parent, \a name and widget flag, \a f, arguments are passed
246     to the QFrame constructor.
247
248     \sa setText(), setBuddy(), setAlignment(), setFrameStyle(),
249     setIndent()
250 */
251 QLabel::QLabel(QWidget *buddy, const QString &text,
252                 QWidget *parent, const char *name, Qt::WindowFlags f)
253     : QFrame(*new QLabelPrivate(), parent, f)
254 {
255     Q_D(QLabel);
256     if (name)
257         setObjectName(QString::fromAscii(name));
258     d->init();
259 #ifndef QT_NO_SHORTCUT
260     setBuddy(buddy);
261 #endif
262     setText(text);
263 }
264 #endif //QT3_SUPPORT
265
266 /*!
267     Destroys the label.
268 */
269
270 QLabel::~QLabel()
271 {
272     Q_D(QLabel);
273     d->clearContents();
274 }
275
276 void QLabelPrivate::init()
277 {
278     Q_Q(QLabel);
279
280     valid_hints = false;
281     margin = 0;
282 #ifndef QT_NO_MOVIE
283     movie = 0;
284 #endif
285 #ifndef QT_NO_SHORTCUT
286     shortcutId = 0;
287 #endif
288     pixmap = 0;
289     scaledpixmap = 0;
290     cachedimage = 0;
291 #ifndef QT_NO_PICTURE
292     picture = 0;
293 #endif
294     align = Qt::AlignLeft | Qt::AlignVCenter | Qt::TextExpandTabs;
295     indent = -1;
296     scaledcontents = false;
297     textLayoutDirty = false;
298     textDirty = false;
299     textformat = Qt::AutoText;
300     control = 0;
301     textInteractionFlags = Qt::LinksAccessibleByMouse;
302     isRichText = false;
303     isTextLabel = false;
304
305     q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred,
306                                  QSizePolicy::Label));
307
308 #ifndef QT_NO_CURSOR
309     validCursor = false;
310     onAnchor = false;
311 #endif
312
313     openExternalLinks = false;
314
315     setLayoutItemMargins(QStyle::SE_LabelLayoutItem);
316 }
317
318
319 /*!
320     \property QLabel::text
321     \brief the label's text
322
323     If no text has been set this will return an empty string. Setting
324     the text clears any previous content.
325
326     The text will be interpreted either as plain text or as rich
327     text, depending on the text format setting; see setTextFormat().
328     The default setting is Qt::AutoText; i.e. QLabel will try to
329     auto-detect the format of the text set.
330
331     If a buddy has been set, the buddy mnemonic key is updated
332     from the new text.
333
334     Note that QLabel is well-suited to display small rich text
335     documents, such as small documents that get their document
336     specific settings (font, text color, link color) from the label's
337     palette and font properties. For large documents, use QTextEdit
338     in read-only mode instead. QTextEdit can also provide a scroll bar
339     when necessary.
340
341     \note This function enables mouse tracking if \a text contains rich
342     text.
343
344     \sa setTextFormat(), setBuddy(), alignment
345 */
346
347 void QLabel::setText(const QString &text)
348 {
349     Q_D(QLabel);
350     if (d->text == text)
351         return;
352
353     QWidgetTextControl *oldControl = d->control;
354     d->control = 0;
355
356     d->clearContents();
357     d->text = text;
358     d->isTextLabel = true;
359     d->textDirty = true;
360     d->isRichText = d->textformat == Qt::RichText
361                     || (d->textformat == Qt::AutoText && Qt::mightBeRichText(d->text));
362
363     d->control = oldControl;
364
365     if (d->needTextControl()) {
366         d->ensureTextControl();
367     } else {
368         delete d->control;
369         d->control = 0;
370     }
371
372     if (d->isRichText) {
373         setMouseTracking(true);
374     } else {
375         // Note: mouse tracking not disabled intentionally
376     }
377
378 #ifndef QT_NO_SHORTCUT
379     if (d->buddy)
380         d->updateShortcut();
381 #endif
382
383     d->updateLabel();
384
385 #ifndef QT_NO_ACCESSIBILITY
386     if (accessibleName().isEmpty())
387         QAccessible::updateAccessibility(this, 0, QAccessible::NameChanged);
388 #endif
389 }
390
391 QString QLabel::text() const
392 {
393     Q_D(const QLabel);
394     return d->text;
395 }
396
397 /*!
398     Clears any label contents.
399 */
400
401 void QLabel::clear()
402 {
403     Q_D(QLabel);
404     d->clearContents();
405     d->updateLabel();
406 }
407
408 /*!
409     \property QLabel::pixmap
410     \brief the label's pixmap
411
412     If no pixmap has been set this will return 0.
413
414     Setting the pixmap clears any previous content. The buddy
415     shortcut, if any, is disabled.
416 */
417 void QLabel::setPixmap(const QPixmap &pixmap)
418 {
419     Q_D(QLabel);
420     if (!d->pixmap || d->pixmap->cacheKey() != pixmap.cacheKey()) {
421         d->clearContents();
422         d->pixmap = new QPixmap(pixmap);
423     }
424
425     if (d->pixmap->depth() == 1 && !d->pixmap->mask())
426         d->pixmap->setMask(*((QBitmap *)d->pixmap));
427
428     d->updateLabel();
429 }
430
431 const QPixmap *QLabel::pixmap() const
432 {
433     Q_D(const QLabel);
434     return d->pixmap;
435 }
436
437 #ifndef QT_NO_PICTURE
438 /*!
439     Sets the label contents to \a picture. Any previous content is
440     cleared.
441
442     The buddy shortcut, if any, is disabled.
443
444     \sa picture(), setBuddy()
445 */
446
447 void QLabel::setPicture(const QPicture &picture)
448 {
449     Q_D(QLabel);
450     d->clearContents();
451     d->picture = new QPicture(picture);
452
453     d->updateLabel();
454 }
455 #endif // QT_NO_PICTURE
456
457 /*!
458     Sets the label contents to plain text containing the textual
459     representation of integer \a num. Any previous content is cleared.
460     Does nothing if the integer's string representation is the same as
461     the current contents of the label.
462
463     The buddy shortcut, if any, is disabled.
464
465     \sa setText(), QString::setNum(), setBuddy()
466 */
467
468 void QLabel::setNum(int num)
469 {
470     QString str;
471     str.setNum(num);
472     setText(str);
473 }
474
475 /*!
476     \overload
477
478     Sets the label contents to plain text containing the textual
479     representation of double \a num. Any previous content is cleared.
480     Does nothing if the double's string representation is the same as
481     the current contents of the label.
482
483     The buddy shortcut, if any, is disabled.
484
485     \sa setText(), QString::setNum(), setBuddy()
486 */
487
488 void QLabel::setNum(double num)
489 {
490     QString str;
491     str.setNum(num);
492     setText(str);
493 }
494
495 /*!
496     \property QLabel::alignment
497     \brief the alignment of the label's contents
498
499     By default, the contents of the label are left-aligned and vertically-centered.
500
501     \sa text
502 */
503
504 void QLabel::setAlignment(Qt::Alignment alignment)
505 {
506     Q_D(QLabel);
507     if (alignment == (d->align & (Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask)))
508         return;
509     d->align = (d->align & ~(Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask))
510                | (alignment & (Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask));
511
512     d->updateLabel();
513 }
514
515 #ifdef QT3_SUPPORT
516 /*!
517     Use setAlignment(Qt::Alignment) instead.
518
519     If \a alignment specifies text flags as well, use setTextFormat()
520     to set those.
521 */
522 void QLabel::setAlignment(int alignment)
523 {
524     Q_D(QLabel);
525     d->align = alignment & ~(Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask|Qt::TextWordWrap);
526     setAlignment(Qt::Alignment(QFlag(alignment)));
527 }
528 #endif
529
530 Qt::Alignment QLabel::alignment() const
531 {
532     Q_D(const QLabel);
533     return QFlag(d->align & (Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask));
534 }
535
536
537 /*!
538     \property QLabel::wordWrap
539     \brief the label's word-wrapping policy
540
541     If this property is true then label text is wrapped where
542     necessary at word-breaks; otherwise it is not wrapped at all.
543
544     By default, word wrap is disabled.
545
546     \sa text
547 */
548 void QLabel::setWordWrap(bool on)
549 {
550     Q_D(QLabel);
551     if (on)
552         d->align |= Qt::TextWordWrap;
553     else
554         d->align &= ~Qt::TextWordWrap;
555
556     d->updateLabel();
557 }
558
559 bool QLabel::wordWrap() const
560 {
561     Q_D(const QLabel);
562     return d->align & Qt::TextWordWrap;
563 }
564
565 /*!
566     \property QLabel::indent
567     \brief the label's text indent in pixels
568
569     If a label displays text, the indent applies to the left edge if
570     alignment() is Qt::AlignLeft, to the right edge if alignment() is
571     Qt::AlignRight, to the top edge if alignment() is Qt::AlignTop, and
572     to to the bottom edge if alignment() is Qt::AlignBottom.
573
574     If indent is negative, or if no indent has been set, the label
575     computes the effective indent as follows: If frameWidth() is 0,
576     the effective indent becomes 0. If frameWidth() is greater than 0,
577     the effective indent becomes half the width of the "x" character
578     of the widget's current font().
579
580     By default, the indent is -1, meaning that an effective indent is
581     calculating in the manner described above.
582
583     \sa alignment, margin, frameWidth(), font()
584 */
585
586 void QLabel::setIndent(int indent)
587 {
588     Q_D(QLabel);
589     d->indent = indent;
590     d->updateLabel();
591 }
592
593 int QLabel::indent() const
594 {
595     Q_D(const QLabel);
596     return d->indent;
597 }
598
599
600 /*!
601     \property QLabel::margin
602     \brief the width of the margin
603
604     The margin is the distance between the innermost pixel of the
605     frame and the outermost pixel of contents.
606
607     The default margin is 0.
608
609     \sa indent
610 */
611 int QLabel::margin() const
612 {
613     Q_D(const QLabel);
614     return d->margin;
615 }
616
617 void QLabel::setMargin(int margin)
618 {
619     Q_D(QLabel);
620     if (d->margin == margin)
621         return;
622     d->margin = margin;
623     d->updateLabel();
624 }
625
626 /*!
627     Returns the size that will be used if the width of the label is \a
628     w. If \a w is -1, the sizeHint() is returned. If \a w is 0 minimumSizeHint() is returned
629 */
630 QSize QLabelPrivate::sizeForWidth(int w) const
631 {
632     Q_Q(const QLabel);
633     if(q->minimumWidth() > 0)
634         w = qMax(w, q->minimumWidth());
635     QSize contentsMargin(leftmargin + rightmargin, topmargin + bottommargin);
636
637     QRect br;
638
639     int hextra = 2 * margin;
640     int vextra = hextra;
641     QFontMetrics fm = q->fontMetrics();
642
643     if (pixmap && !pixmap->isNull())
644         br = pixmap->rect();
645 #ifndef QT_NO_PICTURE
646     else if (picture && !picture->isNull())
647         br = picture->boundingRect();
648 #endif
649 #ifndef QT_NO_MOVIE
650     else if (movie && !movie->currentPixmap().isNull())
651         br = movie->currentPixmap().rect();
652 #endif
653     else if (isTextLabel) {
654         int align = QStyle::visualAlignment(textDirection(), QFlag(this->align));
655         // Add indentation
656         int m = indent;
657
658         if (m < 0 && q->frameWidth()) // no indent, but we do have a frame
659             m = fm.width(QLatin1Char('x')) - margin*2;
660         if (m > 0) {
661             if ((align & Qt::AlignLeft) || (align & Qt::AlignRight))
662                 hextra += m;
663             if ((align & Qt::AlignTop) || (align & Qt::AlignBottom))
664                 vextra += m;
665         }
666
667         if (control) {
668             ensureTextLayouted();
669             const qreal oldTextWidth = control->textWidth();
670             // Calculate the length of document if w is the width
671             if (align & Qt::TextWordWrap) {
672                 if (w >= 0) {
673                     w = qMax(w-hextra-contentsMargin.width(), 0); // strip margin and indent
674                     control->setTextWidth(w);
675                 } else {
676                     control->adjustSize();
677                 }
678             } else {
679                 control->setTextWidth(-1);
680             }
681
682             QSizeF controlSize = control->size();
683             br = QRect(QPoint(0, 0), QSize(qCeil(controlSize.width()), qCeil(controlSize.height())));
684
685             // restore state
686             control->setTextWidth(oldTextWidth);
687         } else {
688             // Turn off center alignment in order to avoid rounding errors for centering,
689             // since centering involves a division by 2. At the end, all we want is the size.
690             int flags = align & ~(Qt::AlignVCenter | Qt::AlignHCenter);
691             if (hasShortcut) {
692                 flags |= Qt::TextShowMnemonic;
693                 QStyleOption opt;
694                 opt.initFrom(q);
695                 if (!q->style()->styleHint(QStyle::SH_UnderlineShortcut, &opt, q))
696                     flags |= Qt::TextHideMnemonic;
697             }
698
699             bool tryWidth = (w < 0) && (align & Qt::TextWordWrap);
700             if (tryWidth)
701                 w = qMin(fm.averageCharWidth() * 80, q->maximumSize().width());
702             else if (w < 0)
703                 w = 2000;
704             w -= (hextra + contentsMargin.width());
705             br = fm.boundingRect(0, 0, w ,2000, flags, text);
706             if (tryWidth && br.height() < 4*fm.lineSpacing() && br.width() > w/2)
707                 br = fm.boundingRect(0, 0, w/2, 2000, flags, text);
708             if (tryWidth && br.height() < 2*fm.lineSpacing() && br.width() > w/4)
709                 br = fm.boundingRect(0, 0, w/4, 2000, flags, text);
710         }
711     } else {
712         br = QRect(QPoint(0, 0), QSize(fm.averageCharWidth(), fm.lineSpacing()));
713     }
714
715     const QSize contentsSize(br.width() + hextra, br.height() + vextra);
716     return (contentsSize + contentsMargin).expandedTo(q->minimumSize());
717 }
718
719
720 /*!
721   \reimp
722 */
723
724 int QLabel::heightForWidth(int w) const
725 {
726     Q_D(const QLabel);
727     if (d->isTextLabel)
728         return d->sizeForWidth(w).height();
729     return QWidget::heightForWidth(w);
730 }
731
732 /*!
733     \property QLabel::openExternalLinks
734     \since 4.2
735
736     Specifies whether QLabel should automatically open links using
737     QDesktopServices::openUrl() instead of emitting the
738     linkActivated() signal.
739
740     \bold{Note:} The textInteractionFlags set on the label need to include
741     either LinksAccessibleByMouse or LinksAccessibleByKeyboard.
742
743     The default value is false.
744
745     \sa textInteractionFlags()
746 */
747 bool QLabel::openExternalLinks() const
748 {
749     Q_D(const QLabel);
750     return d->openExternalLinks;
751 }
752
753 void QLabel::setOpenExternalLinks(bool open)
754 {
755     Q_D(QLabel);
756     d->openExternalLinks = open;
757     if (d->control)
758         d->control->setOpenExternalLinks(open);
759 }
760
761 /*!
762     \property QLabel::textInteractionFlags
763     \since 4.2
764
765     Specifies how the label should interact with user input if it displays text.
766
767     If the flags contain Qt::LinksAccessibleByKeyboard the focus policy is also
768     automatically set to Qt::StrongFocus. If Qt::TextSelectableByKeyboard is set
769     then the focus policy is set to Qt::ClickFocus.
770
771     The default value is Qt::LinksAccessibleByMouse.
772 */
773 void QLabel::setTextInteractionFlags(Qt::TextInteractionFlags flags)
774 {
775     Q_D(QLabel);
776     if (d->textInteractionFlags == flags)
777         return;
778     d->textInteractionFlags = flags;
779     if (flags & Qt::LinksAccessibleByKeyboard)
780         setFocusPolicy(Qt::StrongFocus);
781     else if (flags & (Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse))
782         setFocusPolicy(Qt::ClickFocus);
783     else
784         setFocusPolicy(Qt::NoFocus);
785
786     if (d->needTextControl()) {
787         d->ensureTextControl();
788     } else {
789         delete d->control;
790         d->control = 0;
791     }
792
793     if (d->control)
794         d->control->setTextInteractionFlags(d->textInteractionFlags);
795 }
796
797 Qt::TextInteractionFlags QLabel::textInteractionFlags() const
798 {
799     Q_D(const QLabel);
800     return d->textInteractionFlags;
801 }
802
803 /*!
804     Selects text from position \a start and for \a length characters.
805
806     \sa selectedText()
807
808     \bold{Note:} The textInteractionFlags set on the label need to include
809     either TextSelectableByMouse or TextSelectableByKeyboard.
810
811     \since 4.7
812 */
813 void QLabel::setSelection(int start, int length)
814 {
815     Q_D(QLabel);
816     if (d->control) {
817         d->ensureTextPopulated();
818         QTextCursor cursor = d->control->textCursor();
819         cursor.setPosition(start);
820         cursor.setPosition(start + length, QTextCursor::KeepAnchor);
821         d->control->setTextCursor(cursor);
822     }
823 }
824
825 /*!
826     \property QLabel::hasSelectedText
827     \brief whether there is any text selected
828
829     hasSelectedText() returns true if some or all of the text has been
830     selected by the user; otherwise returns false.
831
832     By default, this property is false.
833
834     \sa selectedText()
835
836     \bold{Note:} The textInteractionFlags set on the label need to include
837     either TextSelectableByMouse or TextSelectableByKeyboard.
838
839     \since 4.7
840 */
841 bool QLabel::hasSelectedText() const
842 {
843     Q_D(const QLabel);
844     if (d->control)
845         return d->control->textCursor().hasSelection();
846     return false;
847 }
848
849 /*!
850     \property QLabel::selectedText
851     \brief the selected text
852
853     If there is no selected text this property's value is
854     an empty string.
855
856     By default, this property contains an empty string.
857
858     \sa hasSelectedText()
859
860     \bold{Note:} The textInteractionFlags set on the label need to include
861     either TextSelectableByMouse or TextSelectableByKeyboard.
862
863     \since 4.7
864 */
865 QString QLabel::selectedText() const
866 {
867     Q_D(const QLabel);
868     if (d->control)
869         return d->control->textCursor().selectedText();
870     return QString();
871 }
872
873 /*!
874     selectionStart() returns the index of the first selected character in the
875     label or -1 if no text is selected.
876
877     \sa selectedText()
878
879     \bold{Note:} The textInteractionFlags set on the label need to include
880     either TextSelectableByMouse or TextSelectableByKeyboard.
881
882     \since 4.7
883 */
884 int QLabel::selectionStart() const
885 {
886     Q_D(const QLabel);
887     if (d->control && d->control->textCursor().hasSelection())
888         return d->control->textCursor().selectionStart();
889     return -1;
890 }
891
892 /*!\reimp
893 */
894 QSize QLabel::sizeHint() const
895 {
896     Q_D(const QLabel);
897     if (!d->valid_hints)
898         (void) QLabel::minimumSizeHint();
899     return d->sh;
900 }
901
902 /*!
903   \reimp
904 */
905 QSize QLabel::minimumSizeHint() const
906 {
907     Q_D(const QLabel);
908     if (d->valid_hints) {
909         if (d->sizePolicy == sizePolicy())
910             return d->msh;
911     }
912
913     ensurePolished();
914     d->valid_hints = true;
915     d->sh = d->sizeForWidth(-1); // wrap ? golden ratio : min doc size
916     QSize msh(-1, -1);
917
918     if (!d->isTextLabel) {
919         msh = d->sh;
920     } else {
921         msh.rheight() = d->sizeForWidth(QWIDGETSIZE_MAX).height(); // height for one line
922         msh.rwidth() = d->sizeForWidth(0).width(); // wrap ? size of biggest word : min doc size
923         if (d->sh.height() < msh.height())
924             msh.rheight() = d->sh.height();
925     }
926     d->msh = msh;
927     d->sizePolicy = sizePolicy();
928     return msh;
929 }
930
931 /*!\reimp
932 */
933 void QLabel::mousePressEvent(QMouseEvent *ev)
934 {
935     Q_D(QLabel);
936     d->sendControlEvent(ev);
937 }
938
939 /*!\reimp
940 */
941 void QLabel::mouseMoveEvent(QMouseEvent *ev)
942 {
943     Q_D(QLabel);
944     d->sendControlEvent(ev);
945 }
946
947 /*!\reimp
948 */
949 void QLabel::mouseReleaseEvent(QMouseEvent *ev)
950 {
951     Q_D(QLabel);
952     d->sendControlEvent(ev);
953 }
954
955 /*!\reimp
956 */
957 void QLabel::contextMenuEvent(QContextMenuEvent *ev)
958 {
959 #ifdef QT_NO_CONTEXTMENU
960     Q_UNUSED(ev);
961 #else
962     Q_D(QLabel);
963     if (!d->isTextLabel) {
964         ev->ignore();
965         return;
966     }
967     QMenu *menu = d->createStandardContextMenu(ev->pos());
968     if (!menu) {
969         ev->ignore();
970         return;
971     }
972     ev->accept();
973     menu->setAttribute(Qt::WA_DeleteOnClose);
974     menu->popup(ev->globalPos());
975 #endif
976 }
977
978 /*!
979     \reimp
980 */
981 void QLabel::focusInEvent(QFocusEvent *ev)
982 {
983     Q_D(QLabel);
984     if (d->isTextLabel) {
985         d->ensureTextControl();
986         d->sendControlEvent(ev);
987     }
988     QFrame::focusInEvent(ev);
989 }
990
991 /*!
992     \reimp
993 */
994 void QLabel::focusOutEvent(QFocusEvent *ev)
995 {
996     Q_D(QLabel);
997     if (d->control) {
998         d->sendControlEvent(ev);
999         QTextCursor cursor = d->control->textCursor();
1000         Qt::FocusReason reason = ev->reason();
1001         if (reason != Qt::ActiveWindowFocusReason
1002             && reason != Qt::PopupFocusReason
1003             && cursor.hasSelection()) {
1004             cursor.clearSelection();
1005             d->control->setTextCursor(cursor);
1006         }
1007     }
1008
1009     QFrame::focusOutEvent(ev);
1010 }
1011
1012 /*!\reimp
1013 */
1014 bool QLabel::focusNextPrevChild(bool next)
1015 {
1016     Q_D(QLabel);
1017     if (d->control && d->control->setFocusToNextOrPreviousAnchor(next))
1018         return true;
1019     return QFrame::focusNextPrevChild(next);
1020 }
1021
1022 /*!\reimp
1023 */
1024 void QLabel::keyPressEvent(QKeyEvent *ev)
1025 {
1026     Q_D(QLabel);
1027     d->sendControlEvent(ev);
1028 }
1029
1030 /*!\reimp
1031 */
1032 bool QLabel::event(QEvent *e)
1033 {
1034     Q_D(QLabel);
1035     QEvent::Type type = e->type();
1036
1037 #ifndef QT_NO_SHORTCUT
1038     if (type == QEvent::Shortcut) {
1039         QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
1040         if (se->shortcutId() == d->shortcutId) {
1041             QWidget * w = d->buddy;
1042             QAbstractButton *button = qobject_cast<QAbstractButton *>(w);
1043             if (w->focusPolicy() != Qt::NoFocus)
1044                 w->setFocus(Qt::ShortcutFocusReason);
1045             if (button && !se->isAmbiguous())
1046                 button->animateClick();
1047             else
1048                 window()->setAttribute(Qt::WA_KeyboardFocusChange);
1049             return true;
1050         }
1051     } else
1052 #endif
1053     if (type == QEvent::Resize) {
1054         if (d->control)
1055             d->textLayoutDirty = true;
1056     } else if (e->type() == QEvent::StyleChange
1057 #ifdef Q_WS_MAC
1058                || e->type() == QEvent::MacSizeChange
1059 #endif
1060                ) {
1061         d->setLayoutItemMargins(QStyle::SE_LabelLayoutItem);
1062         d->updateLabel();
1063     }
1064
1065     return QFrame::event(e);
1066 }
1067
1068 /*!\reimp
1069 */
1070 void QLabel::paintEvent(QPaintEvent *)
1071 {
1072     Q_D(QLabel);
1073     QStyle *style = QWidget::style();
1074     QPainter painter(this);
1075     drawFrame(&painter);
1076     QRect cr = contentsRect();
1077     cr.adjust(d->margin, d->margin, -d->margin, -d->margin);
1078     int align = QStyle::visualAlignment(d->isTextLabel ? d->textDirection()
1079                                                        : layoutDirection(), QFlag(d->align));
1080
1081 #ifndef QT_NO_MOVIE
1082     if (d->movie) {
1083         if (d->scaledcontents)
1084             style->drawItemPixmap(&painter, cr, align, d->movie->currentPixmap().scaled(cr.size()));
1085         else
1086             style->drawItemPixmap(&painter, cr, align, d->movie->currentPixmap());
1087     }
1088     else
1089 #endif
1090     if (d->isTextLabel) {
1091         QRectF lr = d->layoutRect().toAlignedRect();
1092         QStyleOption opt;
1093         opt.initFrom(this);
1094 #ifndef QT_NO_STYLE_STYLESHEET
1095         if (QStyleSheetStyle* cssStyle = qobject_cast<QStyleSheetStyle*>(style)) {
1096             cssStyle->styleSheetPalette(this, &opt, &opt.palette);
1097         }
1098 #endif
1099         if (d->control) {
1100 #ifndef QT_NO_SHORTCUT
1101             const bool underline = (bool)style->styleHint(QStyle::SH_UnderlineShortcut, 0, this, 0);
1102             if (d->shortcutId != 0
1103                 && underline != d->shortcutCursor.charFormat().fontUnderline()) {
1104                 QTextCharFormat fmt;
1105                 fmt.setFontUnderline(underline);
1106                 d->shortcutCursor.mergeCharFormat(fmt);
1107             }
1108 #endif
1109             d->ensureTextLayouted();
1110
1111             QAbstractTextDocumentLayout::PaintContext context;
1112             if (!isEnabled() && !d->control &&
1113                 // We cannot support etched for rich text controls because custom
1114                 // colors and links will override the light palette
1115                 style->styleHint(QStyle::SH_EtchDisabledText, &opt, this)) {
1116                 context.palette = opt.palette;
1117                 context.palette.setColor(QPalette::Text, context.palette.light().color());
1118                 painter.save();
1119                 painter.translate(lr.x() + 1, lr.y() + 1);
1120                 painter.setClipRect(lr.translated(-lr.x() - 1, -lr.y() - 1));
1121                 QAbstractTextDocumentLayout *layout = d->control->document()->documentLayout();
1122                 layout->draw(&painter, context);
1123                 painter.restore();
1124             }
1125
1126             // Adjust the palette
1127             context.palette = opt.palette;
1128
1129             if (foregroundRole() != QPalette::Text && isEnabled())
1130                 context.palette.setColor(QPalette::Text, context.palette.color(foregroundRole()));
1131
1132             painter.save();
1133             painter.translate(lr.topLeft());
1134             painter.setClipRect(lr.translated(-lr.x(), -lr.y()));
1135             d->control->setPalette(context.palette);
1136             d->control->drawContents(&painter, QRectF(), this);
1137             painter.restore();
1138         } else {
1139             int flags = align | (d->textDirection() == Qt::LeftToRight ? Qt::TextForceLeftToRight
1140                                                                        : Qt::TextForceRightToLeft);
1141             if (d->hasShortcut) {
1142                 flags |= Qt::TextShowMnemonic;
1143                 if (!style->styleHint(QStyle::SH_UnderlineShortcut, &opt, this))
1144                     flags |= Qt::TextHideMnemonic;
1145             }
1146             style->drawItemText(&painter, lr.toRect(), flags, opt.palette, isEnabled(), d->text, foregroundRole());
1147         }
1148     } else
1149 #ifndef QT_NO_PICTURE
1150     if (d->picture) {
1151         QRect br = d->picture->boundingRect();
1152         int rw = br.width();
1153         int rh = br.height();
1154         if (d->scaledcontents) {
1155             painter.save();
1156             painter.translate(cr.x(), cr.y());
1157             painter.scale((double)cr.width()/rw, (double)cr.height()/rh);
1158             painter.drawPicture(-br.x(), -br.y(), *d->picture);
1159             painter.restore();
1160         } else {
1161             int xo = 0;
1162             int yo = 0;
1163             if (align & Qt::AlignVCenter)
1164                 yo = (cr.height()-rh)/2;
1165             else if (align & Qt::AlignBottom)
1166                 yo = cr.height()-rh;
1167             if (align & Qt::AlignRight)
1168                 xo = cr.width()-rw;
1169             else if (align & Qt::AlignHCenter)
1170                 xo = (cr.width()-rw)/2;
1171             painter.drawPicture(cr.x()+xo-br.x(), cr.y()+yo-br.y(), *d->picture);
1172         }
1173     } else
1174 #endif
1175     if (d->pixmap && !d->pixmap->isNull()) {
1176         QPixmap pix;
1177         if (d->scaledcontents) {
1178             if (!d->scaledpixmap || d->scaledpixmap->size() != cr.size()) {
1179                 if (!d->cachedimage)
1180                     d->cachedimage = new QImage(d->pixmap->toImage());
1181                 delete d->scaledpixmap;
1182                 d->scaledpixmap = new QPixmap(QPixmap::fromImage(d->cachedimage->scaled(cr.size(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation)));
1183             }
1184             pix = *d->scaledpixmap;
1185         } else
1186             pix = *d->pixmap;
1187         QStyleOption opt;
1188         opt.initFrom(this);
1189         if (!isEnabled())
1190             pix = style->generatedIconPixmap(QIcon::Disabled, pix, &opt);
1191         style->drawItemPixmap(&painter, cr, align, pix);
1192     }
1193 }
1194
1195
1196 /*!
1197     Updates the label, but not the frame.
1198 */
1199
1200 void QLabelPrivate::updateLabel()
1201 {
1202     Q_Q(QLabel);
1203     valid_hints = false;
1204
1205     if (isTextLabel) {
1206         QSizePolicy policy = q->sizePolicy();
1207         const bool wrap = align & Qt::TextWordWrap;
1208         policy.setHeightForWidth(wrap);
1209         if (policy != q->sizePolicy())  // ### should be replaced by WA_WState_OwnSizePolicy idiom
1210             q->setSizePolicy(policy);
1211         textLayoutDirty = true;
1212     }
1213     q->updateGeometry();
1214     q->update(q->contentsRect());
1215 }
1216
1217 #ifndef QT_NO_SHORTCUT
1218 /*!
1219     Sets this label's buddy to \a buddy.
1220
1221     When the user presses the shortcut key indicated by this label,
1222     the keyboard focus is transferred to the label's buddy widget.
1223
1224     The buddy mechanism is only available for QLabels that contain
1225     text in which one character is prefixed with an ampersand, '&'.
1226     This character is set as the shortcut key. See the \l
1227     QKeySequence::mnemonic() documentation for details (to display an
1228     actual ampersand, use '&&').
1229
1230     In a dialog, you might create two data entry widgets and a label
1231     for each, and set up the geometry layout so each label is just to
1232     the left of its data entry widget (its "buddy"), for example:
1233     \snippet doc/src/snippets/code/src_gui_widgets_qlabel.cpp 2
1234
1235     With the code above, the focus jumps to the Name field when the
1236     user presses Alt+N, and to the Phone field when the user presses
1237     Alt+P.
1238
1239     To unset a previously set buddy, call this function with \a buddy
1240     set to 0.
1241
1242     \sa buddy(), setText(), QShortcut, setAlignment()
1243 */
1244
1245 void QLabel::setBuddy(QWidget *buddy)
1246 {
1247     Q_D(QLabel);
1248     d->buddy = buddy;
1249     if (d->isTextLabel) {
1250         if (d->shortcutId)
1251             releaseShortcut(d->shortcutId);
1252         d->shortcutId = 0;
1253         d->textDirty = true;
1254         if (buddy)
1255             d->updateShortcut(); // grab new shortcut
1256         d->updateLabel();
1257     }
1258 }
1259
1260
1261 /*!
1262     Returns this label's buddy, or 0 if no buddy is currently set.
1263
1264     \sa setBuddy()
1265 */
1266
1267 QWidget * QLabel::buddy() const
1268 {
1269     Q_D(const QLabel);
1270     return d->buddy;
1271 }
1272
1273 void QLabelPrivate::updateShortcut()
1274 {
1275     Q_Q(QLabel);
1276     Q_ASSERT(shortcutId == 0);
1277     // Introduce an extra boolean to indicate the presence of a shortcut in the
1278     // text. We cannot use the shortcutId itself because on the mac mnemonics are
1279     // off by default, so QKeySequence::mnemonic always returns an empty sequence.
1280     // But then we do want to hide the ampersands, so we can't use shortcutId.
1281     hasShortcut = false;
1282
1283     if (!text.contains(QLatin1Char('&')))
1284         return;
1285     hasShortcut = true;
1286     shortcutId = q->grabShortcut(QKeySequence::mnemonic(text));
1287 }
1288
1289 #endif // QT_NO_SHORTCUT
1290
1291 #ifndef QT_NO_MOVIE
1292 void QLabelPrivate::_q_movieUpdated(const QRect& rect)
1293 {
1294     Q_Q(QLabel);
1295     if (movie && movie->isValid()) {
1296         QRect r;
1297         if (scaledcontents) {
1298             QRect cr = q->contentsRect();
1299             QRect pixmapRect(cr.topLeft(), movie->currentPixmap().size());
1300             if (pixmapRect.isEmpty())
1301                 return;
1302             r.setRect(cr.left(), cr.top(),
1303                       (rect.width() * cr.width()) / pixmapRect.width(),
1304                       (rect.height() * cr.height()) / pixmapRect.height());
1305         } else {
1306             r = q->style()->itemPixmapRect(q->contentsRect(), align, movie->currentPixmap());
1307             r.translate(rect.x(), rect.y());
1308             r.setWidth(qMin(r.width(), rect.width()));
1309             r.setHeight(qMin(r.height(), rect.height()));
1310         }
1311         q->update(r);
1312     }
1313 }
1314
1315 void QLabelPrivate::_q_movieResized(const QSize& size)
1316 {
1317     Q_Q(QLabel);
1318     q->update(); //we need to refresh the whole background in case the new size is smaler
1319     valid_hints = false;
1320     _q_movieUpdated(QRect(QPoint(0,0), size));
1321     q->updateGeometry();
1322 }
1323
1324 /*!
1325     Sets the label contents to \a movie. Any previous content is
1326     cleared. The label does NOT take ownership of the movie.
1327
1328     The buddy shortcut, if any, is disabled.
1329
1330     \sa movie(), setBuddy()
1331 */
1332
1333 void QLabel::setMovie(QMovie *movie)
1334 {
1335     Q_D(QLabel);
1336     d->clearContents();
1337
1338     if (!movie)
1339         return;
1340
1341     d->movie = movie;
1342     connect(movie, SIGNAL(resized(QSize)), this, SLOT(_q_movieResized(QSize)));
1343     connect(movie, SIGNAL(updated(QRect)), this, SLOT(_q_movieUpdated(QRect)));
1344
1345     // Assume that if the movie is running,
1346     // resize/update signals will come soon enough
1347     if (movie->state() != QMovie::Running)
1348         d->updateLabel();
1349 }
1350
1351 #endif // QT_NO_MOVIE
1352
1353 /*!
1354   \internal
1355
1356   Clears any contents, without updating/repainting the label.
1357 */
1358
1359 void QLabelPrivate::clearContents()
1360 {
1361     delete control;
1362     control = 0;
1363     isTextLabel = false;
1364     hasShortcut = false;
1365
1366 #ifndef QT_NO_PICTURE
1367     delete picture;
1368     picture = 0;
1369 #endif
1370     delete scaledpixmap;
1371     scaledpixmap = 0;
1372     delete cachedimage;
1373     cachedimage = 0;
1374     delete pixmap;
1375     pixmap = 0;
1376
1377     text.clear();
1378     Q_Q(QLabel);
1379 #ifndef QT_NO_SHORTCUT
1380     if (shortcutId)
1381         q->releaseShortcut(shortcutId);
1382     shortcutId = 0;
1383 #endif
1384 #ifndef QT_NO_MOVIE
1385     if (movie) {
1386         QObject::disconnect(movie, SIGNAL(resized(QSize)), q, SLOT(_q_movieResized(QSize)));
1387         QObject::disconnect(movie, SIGNAL(updated(QRect)), q, SLOT(_q_movieUpdated(QRect)));
1388     }
1389     movie = 0;
1390 #endif
1391 #ifndef QT_NO_CURSOR
1392     if (onAnchor) {
1393         if (validCursor)
1394             q->setCursor(cursor);
1395         else
1396             q->unsetCursor();
1397     }
1398     validCursor = false;
1399     onAnchor = false;
1400 #endif
1401 }
1402
1403
1404 #ifndef QT_NO_MOVIE
1405
1406 /*!
1407     Returns a pointer to the label's movie, or 0 if no movie has been
1408     set.
1409
1410     \sa setMovie()
1411 */
1412
1413 QMovie *QLabel::movie() const
1414 {
1415     Q_D(const QLabel);
1416     return d->movie;
1417 }
1418
1419 #endif  // QT_NO_MOVIE
1420
1421 /*!
1422     \property QLabel::textFormat
1423     \brief the label's text format
1424
1425     See the Qt::TextFormat enum for an explanation of the possible
1426     options.
1427
1428     The default format is Qt::AutoText.
1429
1430     \sa text()
1431 */
1432
1433 Qt::TextFormat QLabel::textFormat() const
1434 {
1435     Q_D(const QLabel);
1436     return d->textformat;
1437 }
1438
1439 void QLabel::setTextFormat(Qt::TextFormat format)
1440 {
1441     Q_D(QLabel);
1442     if (format != d->textformat) {
1443         d->textformat = format;
1444         QString t = d->text;
1445         if (!t.isNull()) {
1446             d->text.clear();
1447             setText(t);
1448         }
1449     }
1450 }
1451
1452 /*!
1453   \reimp
1454 */
1455 void QLabel::changeEvent(QEvent *ev)
1456 {
1457     Q_D(QLabel);
1458     if(ev->type() == QEvent::FontChange || ev->type() == QEvent::ApplicationFontChange) {
1459         if (d->isTextLabel) {
1460             if (d->control)
1461                 d->control->document()->setDefaultFont(font());
1462             d->updateLabel();
1463         }
1464     } else if (ev->type() == QEvent::PaletteChange && d->control) {
1465         d->control->setPalette(palette());
1466     } else if (ev->type() == QEvent::ContentsRectChange) {
1467         d->updateLabel();
1468     }
1469     QFrame::changeEvent(ev);
1470 }
1471
1472 /*!
1473     \property QLabel::scaledContents
1474     \brief whether the label will scale its contents to fill all
1475     available space.
1476
1477     When enabled and the label shows a pixmap, it will scale the
1478     pixmap to fill the available space.
1479
1480     This property's default is false.
1481 */
1482 bool QLabel::hasScaledContents() const
1483 {
1484     Q_D(const QLabel);
1485     return d->scaledcontents;
1486 }
1487
1488 void QLabel::setScaledContents(bool enable)
1489 {
1490     Q_D(QLabel);
1491     if ((bool)d->scaledcontents == enable)
1492         return;
1493     d->scaledcontents = enable;
1494     if (!enable) {
1495         delete d->scaledpixmap;
1496         d->scaledpixmap = 0;
1497         delete d->cachedimage;
1498         d->cachedimage = 0;
1499     }
1500     update(contentsRect());
1501 }
1502
1503 Qt::LayoutDirection QLabelPrivate::textDirection() const
1504 {
1505     if (control) {
1506         QTextOption opt = control->document()->defaultTextOption();
1507         return opt.textDirection();
1508     }
1509
1510     return text.isRightToLeft() ? Qt::RightToLeft : Qt::LeftToRight;
1511 }
1512
1513 /*!
1514     \fn void QLabel::setAlignment(Qt::AlignmentFlag flag)
1515     \internal
1516
1517     Without this function, a call to e.g. setAlignment(Qt::AlignTop)
1518     results in the \c QT3_SUPPORT function setAlignment(int) being called,
1519     rather than setAlignment(Qt::Alignment).
1520 */
1521
1522 // Returns the rect that is available for us to draw the document
1523 QRect QLabelPrivate::documentRect() const
1524 {
1525     Q_Q(const QLabel);
1526     Q_ASSERT_X(isTextLabel, "documentRect", "document rect called for label that is not a text label!");
1527     QRect cr = q->contentsRect();
1528     cr.adjust(margin, margin, -margin, -margin);
1529     const int align = QStyle::visualAlignment(isTextLabel ? textDirection()
1530                                                           : q->layoutDirection(), QFlag(this->align));
1531     int m = indent;
1532     if (m < 0 && q->frameWidth()) // no indent, but we do have a frame
1533         m = q->fontMetrics().width(QLatin1Char('x')) / 2 - margin;
1534     if (m > 0) {
1535         if (align & Qt::AlignLeft)
1536             cr.setLeft(cr.left() + m);
1537         if (align & Qt::AlignRight)
1538             cr.setRight(cr.right() - m);
1539         if (align & Qt::AlignTop)
1540             cr.setTop(cr.top() + m);
1541         if (align & Qt::AlignBottom)
1542             cr.setBottom(cr.bottom() - m);
1543     }
1544     return cr;
1545 }
1546
1547 void QLabelPrivate::ensureTextPopulated() const
1548 {
1549     if (!textDirty)
1550         return;
1551     if (control) {
1552         QTextDocument *doc = control->document();
1553         if (textDirty) {
1554 #ifndef QT_NO_TEXTHTMLPARSER
1555             if (isRichText)
1556                 doc->setHtml(text);
1557             else
1558                 doc->setPlainText(text);
1559 #else
1560             doc->setPlainText(text);
1561 #endif
1562             doc->setUndoRedoEnabled(false);
1563
1564 #ifndef QT_NO_SHORTCUT
1565             if (hasShortcut) {
1566                 // Underline the first character that follows an ampersand (and remove the others ampersands)
1567                 int from = 0;
1568                 bool found = false;
1569                 QTextCursor cursor;
1570                 while (!(cursor = control->document()->find((QLatin1String("&")), from)).isNull()) {
1571                     cursor.deleteChar(); // remove the ampersand
1572                     cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
1573                     from = cursor.position();
1574                     if (!found && cursor.selectedText() != QLatin1String("&")) { //not a second &
1575                         found = true;
1576                         shortcutCursor = cursor;
1577                     }
1578                 }
1579             }
1580 #endif
1581         }
1582     }
1583     textDirty = false;
1584 }
1585
1586 void QLabelPrivate::ensureTextLayouted() const
1587 {
1588     if (!textLayoutDirty)
1589         return;
1590     ensureTextPopulated();
1591     if (control) {
1592         QTextDocument *doc = control->document();
1593         QTextOption opt = doc->defaultTextOption();
1594
1595         opt.setAlignment(QFlag(this->align));
1596
1597         if (this->align & Qt::TextWordWrap)
1598             opt.setWrapMode(QTextOption::WordWrap);
1599         else
1600             opt.setWrapMode(QTextOption::ManualWrap);
1601
1602         doc->setDefaultTextOption(opt);
1603
1604         QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
1605         fmt.setMargin(0);
1606         doc->rootFrame()->setFrameFormat(fmt);
1607         doc->setTextWidth(documentRect().width());
1608     }
1609     textLayoutDirty = false;
1610 }
1611
1612 void QLabelPrivate::ensureTextControl() const
1613 {
1614     Q_Q(const QLabel);
1615     if (!isTextLabel)
1616         return;
1617     if (!control) {
1618         control = new QWidgetTextControl(const_cast<QLabel *>(q));
1619         control->document()->setUndoRedoEnabled(false);
1620         control->document()->setDefaultFont(q->font());
1621         control->setTextInteractionFlags(textInteractionFlags);
1622         control->setOpenExternalLinks(openExternalLinks);
1623         control->setPalette(q->palette());
1624         control->setFocus(q->hasFocus());
1625         QObject::connect(control, SIGNAL(updateRequest(QRectF)),
1626                          q, SLOT(update()));
1627         QObject::connect(control, SIGNAL(linkHovered(QString)),
1628                          q, SLOT(_q_linkHovered(QString)));
1629         QObject::connect(control, SIGNAL(linkActivated(QString)),
1630                          q, SIGNAL(linkActivated(QString)));
1631         textLayoutDirty = true;
1632         textDirty = true;
1633     }
1634 }
1635
1636 void QLabelPrivate::sendControlEvent(QEvent *e)
1637 {
1638     Q_Q(QLabel);
1639     if (!isTextLabel || !control || textInteractionFlags == Qt::NoTextInteraction) {
1640         e->ignore();
1641         return;
1642     }
1643     control->processEvent(e, -layoutRect().topLeft(), q);
1644 }
1645
1646 void QLabelPrivate::_q_linkHovered(const QString &anchor)
1647 {
1648     Q_Q(QLabel);
1649 #ifndef QT_NO_CURSOR
1650     if (anchor.isEmpty()) { // restore cursor
1651         if (validCursor)
1652             q->setCursor(cursor);
1653         else
1654             q->unsetCursor();
1655         onAnchor = false;
1656     } else if (!onAnchor) {
1657         validCursor = q->testAttribute(Qt::WA_SetCursor);
1658         if (validCursor) {
1659             cursor = q->cursor();
1660         }
1661         q->setCursor(Qt::PointingHandCursor);
1662         onAnchor = true;
1663     }
1664 #endif
1665     emit q->linkHovered(anchor);
1666 }
1667
1668 // Return the layout rect - this is the rect that is given to the layout painting code
1669 // This may be different from the document rect since vertical alignment is not
1670 // done by the text layout code
1671 QRectF QLabelPrivate::layoutRect() const
1672 {
1673     QRectF cr = documentRect();
1674     if (!control)
1675         return cr;
1676     ensureTextLayouted();
1677     // Caculate y position manually
1678     qreal rh = control->document()->documentLayout()->documentSize().height();
1679     qreal yo = 0;
1680     if (align & Qt::AlignVCenter)
1681         yo = qMax((cr.height()-rh)/2, qreal(0));
1682     else if (align & Qt::AlignBottom)
1683         yo = qMax(cr.height()-rh, qreal(0));
1684     return QRectF(cr.x(), yo + cr.y(), cr.width(), cr.height());
1685 }
1686
1687 // Returns the point in the document rect adjusted with p
1688 QPoint QLabelPrivate::layoutPoint(const QPoint& p) const
1689 {
1690     QRect lr = layoutRect().toRect();
1691     return p - lr.topLeft();
1692 }
1693
1694 #ifndef QT_NO_CONTEXTMENU
1695 QMenu *QLabelPrivate::createStandardContextMenu(const QPoint &pos)
1696 {
1697     QString linkToCopy;
1698     QPoint p;
1699     if (control && isRichText) {
1700         p = layoutPoint(pos);
1701         linkToCopy = control->document()->documentLayout()->anchorAt(p);
1702     }
1703
1704     if (linkToCopy.isEmpty() && !control)
1705         return 0;
1706
1707     return control->createStandardContextMenu(p, q_func());
1708 }
1709 #endif
1710
1711 /*!
1712     \fn void QLabel::linkHovered(const QString &link)
1713     \since 4.2
1714
1715     This signal is emitted when the user hovers over a link. The URL
1716     referred to by the anchor is passed in \a link.
1717
1718     \sa linkActivated()
1719 */
1720
1721
1722 /*!
1723     \fn void QLabel::linkActivated(const QString &link)
1724     \since 4.2
1725
1726     This signal is emitted when the user clicks a link. The URL
1727     referred to by the anchor is passed in \a link.
1728
1729     \sa linkHovered()
1730 */
1731
1732 QT_END_NAMESPACE
1733
1734 #include "moc_qlabel.cpp"