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