1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
44 #include "qdrawutil.h"
45 #include "qapplication.h"
46 #include "qabstractbutton.h"
48 #include "qstyleoption.h"
51 #include "qclipboard.h"
55 #include "private/qstylesheetstyle_p.h"
58 #ifndef QT_NO_ACCESSIBILITY
59 #include <qaccessible.h>
66 \brief The QLabel widget provides a text or image display.
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.
75 A QLabel can contain any of the following content types:
78 \header \o Content \o Setting
80 \o Pass a QString to setText().
82 \o Pass a QString that contains rich text to setText().
84 \o Pass a QPixmap to setPixmap().
86 \o Pass a QMovie to setMovie().
88 \o Pass an \e int or a \e double to setNum(), which converts
89 the number to plain text.
91 \o The same as an empty plain text. This is the default. Set
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).
102 When the content is changed using any of these functions, any
103 previous content is cleared.
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.
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
117 \snippet doc/src/snippets/code/src_gui_widgets_qlabel.cpp 0
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.
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:
127 \snippet doc/src/snippets/code/src_gui_widgets_qlabel.cpp 1
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.
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}.
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}.
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}.
146 \sa QLineEdit, QTextEdit, QPixmap, QMovie,
147 {fowler}{GUI Design Handbook: Label}
150 #ifndef QT_NO_PICTURE
152 Returns the label's picture or 0 if the label doesn't have a
156 const QPicture *QLabel::picture() const
165 Constructs an empty label.
167 The \a parent and widget flag \a f, arguments are passed
168 to the QFrame constructor.
170 \sa setAlignment(), setFrameStyle(), setIndent()
172 QLabel::QLabel(QWidget *parent, Qt::WindowFlags f)
173 : QFrame(*new QLabelPrivate(), parent, f)
180 Constructs a label that displays the text, \a text.
182 The \a parent and widget flag \a f, arguments are passed
183 to the QFrame constructor.
185 \sa setText(), setAlignment(), setFrameStyle(), setIndent()
187 QLabel::QLabel(const QString &text, QWidget *parent, Qt::WindowFlags f)
188 : QFrame(*new QLabelPrivate(), parent, f)
198 Constructs an empty label.
200 The \a parent, \a name and widget flag \a f, arguments are passed
201 to the QFrame constructor.
203 \sa setAlignment(), setFrameStyle(), setIndent()
206 QLabel::QLabel(QWidget *parent, const char *name, Qt::WindowFlags f)
207 : QFrame(*new QLabelPrivate(), parent, f)
211 setObjectName(QString::fromAscii(name));
217 Constructs a label that displays the text, \a text.
219 The \a parent, \a name and widget flag \a f, arguments are passed
220 to the QFrame constructor.
222 \sa setText(), setAlignment(), setFrameStyle(), setIndent()
225 QLabel::QLabel(const QString &text, QWidget *parent, const char *name,
227 : QFrame(*new QLabelPrivate(), parent, f)
231 setObjectName(QString::fromAscii(name));
238 Constructs a label that displays the text \a text. The label has a
239 buddy widget, \a buddy.
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.
245 The \a parent, \a name and widget flag, \a f, arguments are passed
246 to the QFrame constructor.
248 \sa setText(), setBuddy(), setAlignment(), setFrameStyle(),
251 QLabel::QLabel(QWidget *buddy, const QString &text,
252 QWidget *parent, const char *name, Qt::WindowFlags f)
253 : QFrame(*new QLabelPrivate(), parent, f)
257 setObjectName(QString::fromAscii(name));
259 #ifndef QT_NO_SHORTCUT
276 void QLabelPrivate::init()
285 #ifndef QT_NO_SHORTCUT
291 #ifndef QT_NO_PICTURE
294 align = Qt::AlignLeft | Qt::AlignVCenter | Qt::TextExpandTabs;
296 scaledcontents = false;
297 textLayoutDirty = false;
299 textformat = Qt::AutoText;
301 textInteractionFlags = Qt::LinksAccessibleByMouse;
305 q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred,
306 QSizePolicy::Label));
313 openExternalLinks = false;
315 setLayoutItemMargins(QStyle::SE_LabelLayoutItem);
320 \property QLabel::text
321 \brief the label's text
323 If no text has been set this will return an empty string. Setting
324 the text clears any previous content.
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.
331 If a buddy has been set, the buddy mnemonic key is updated
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
341 \note This function enables mouse tracking if \a text contains rich
344 \sa setTextFormat(), setBuddy(), alignment
347 void QLabel::setText(const QString &text)
353 QWidgetTextControl *oldControl = d->control;
358 d->isTextLabel = true;
360 d->isRichText = d->textformat == Qt::RichText
361 || (d->textformat == Qt::AutoText && Qt::mightBeRichText(d->text));
363 d->control = oldControl;
365 if (d->needTextControl()) {
366 d->ensureTextControl();
373 setMouseTracking(true);
375 // Note: mouse tracking not disabled intentionally
378 #ifndef QT_NO_SHORTCUT
385 #ifndef QT_NO_ACCESSIBILITY
386 if (accessibleName().isEmpty())
387 QAccessible::updateAccessibility(this, 0, QAccessible::NameChanged);
391 QString QLabel::text() const
398 Clears any label contents.
409 \property QLabel::pixmap
410 \brief the label's pixmap
412 If no pixmap has been set this will return 0.
414 Setting the pixmap clears any previous content. The buddy
415 shortcut, if any, is disabled.
417 void QLabel::setPixmap(const QPixmap &pixmap)
420 if (!d->pixmap || d->pixmap->cacheKey() != pixmap.cacheKey()) {
422 d->pixmap = new QPixmap(pixmap);
425 if (d->pixmap->depth() == 1 && !d->pixmap->mask())
426 d->pixmap->setMask(*((QBitmap *)d->pixmap));
431 const QPixmap *QLabel::pixmap() const
437 #ifndef QT_NO_PICTURE
439 Sets the label contents to \a picture. Any previous content is
442 The buddy shortcut, if any, is disabled.
444 \sa picture(), setBuddy()
447 void QLabel::setPicture(const QPicture &picture)
451 d->picture = new QPicture(picture);
455 #endif // QT_NO_PICTURE
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.
463 The buddy shortcut, if any, is disabled.
465 \sa setText(), QString::setNum(), setBuddy()
468 void QLabel::setNum(int num)
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.
483 The buddy shortcut, if any, is disabled.
485 \sa setText(), QString::setNum(), setBuddy()
488 void QLabel::setNum(double num)
496 \property QLabel::alignment
497 \brief the alignment of the label's contents
499 By default, the contents of the label are left-aligned and vertically-centered.
504 void QLabel::setAlignment(Qt::Alignment alignment)
507 if (alignment == (d->align & (Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask)))
509 d->align = (d->align & ~(Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask))
510 | (alignment & (Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask));
517 Use setAlignment(Qt::Alignment) instead.
519 If \a alignment specifies text flags as well, use setTextFormat()
522 void QLabel::setAlignment(int alignment)
525 d->align = alignment & ~(Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask|Qt::TextWordWrap);
526 setAlignment(Qt::Alignment(QFlag(alignment)));
530 Qt::Alignment QLabel::alignment() const
533 return QFlag(d->align & (Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask));
538 \property QLabel::wordWrap
539 \brief the label's word-wrapping policy
541 If this property is true then label text is wrapped where
542 necessary at word-breaks; otherwise it is not wrapped at all.
544 By default, word wrap is disabled.
548 void QLabel::setWordWrap(bool on)
552 d->align |= Qt::TextWordWrap;
554 d->align &= ~Qt::TextWordWrap;
559 bool QLabel::wordWrap() const
562 return d->align & Qt::TextWordWrap;
566 \property QLabel::indent
567 \brief the label's text indent in pixels
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.
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().
580 By default, the indent is -1, meaning that an effective indent is
581 calculating in the manner described above.
583 \sa alignment, margin, frameWidth(), font()
586 void QLabel::setIndent(int indent)
593 int QLabel::indent() const
601 \property QLabel::margin
602 \brief the width of the margin
604 The margin is the distance between the innermost pixel of the
605 frame and the outermost pixel of contents.
607 The default margin is 0.
611 int QLabel::margin() const
617 void QLabel::setMargin(int margin)
620 if (d->margin == margin)
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
630 QSize QLabelPrivate::sizeForWidth(int w) const
633 if(q->minimumWidth() > 0)
634 w = qMax(w, q->minimumWidth());
635 QSize contentsMargin(leftmargin + rightmargin, topmargin + bottommargin);
639 int hextra = 2 * margin;
641 QFontMetrics fm = q->fontMetrics();
643 if (pixmap && !pixmap->isNull())
645 #ifndef QT_NO_PICTURE
646 else if (picture && !picture->isNull())
647 br = picture->boundingRect();
650 else if (movie && !movie->currentPixmap().isNull())
651 br = movie->currentPixmap().rect();
653 else if (isTextLabel) {
654 int align = QStyle::visualAlignment(textDirection(), QFlag(this->align));
658 if (m < 0 && q->frameWidth()) // no indent, but we do have a frame
659 m = fm.width(QLatin1Char('x')) - margin*2;
661 if ((align & Qt::AlignLeft) || (align & Qt::AlignRight))
663 if ((align & Qt::AlignTop) || (align & Qt::AlignBottom))
668 ensureTextLayouted();
669 const qreal oldTextWidth = control->textWidth();
670 // Calculate the length of document if w is the width
671 if (align & Qt::TextWordWrap) {
673 w = qMax(w-hextra-contentsMargin.width(), 0); // strip margin and indent
674 control->setTextWidth(w);
676 control->adjustSize();
679 control->setTextWidth(-1);
682 QSizeF controlSize = control->size();
683 br = QRect(QPoint(0, 0), QSize(qCeil(controlSize.width()), qCeil(controlSize.height())));
686 control->setTextWidth(oldTextWidth);
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);
692 flags |= Qt::TextShowMnemonic;
695 if (!q->style()->styleHint(QStyle::SH_UnderlineShortcut, &opt, q))
696 flags |= Qt::TextHideMnemonic;
699 bool tryWidth = (w < 0) && (align & Qt::TextWordWrap);
701 w = qMin(fm.averageCharWidth() * 80, q->maximumSize().width());
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);
712 br = QRect(QPoint(0, 0), QSize(fm.averageCharWidth(), fm.lineSpacing()));
715 const QSize contentsSize(br.width() + hextra, br.height() + vextra);
716 return (contentsSize + contentsMargin).expandedTo(q->minimumSize());
724 int QLabel::heightForWidth(int w) const
728 return d->sizeForWidth(w).height();
729 return QWidget::heightForWidth(w);
733 \property QLabel::openExternalLinks
736 Specifies whether QLabel should automatically open links using
737 QDesktopServices::openUrl() instead of emitting the
738 linkActivated() signal.
740 \bold{Note:} The textInteractionFlags set on the label need to include
741 either LinksAccessibleByMouse or LinksAccessibleByKeyboard.
743 The default value is false.
745 \sa textInteractionFlags()
747 bool QLabel::openExternalLinks() const
750 return d->openExternalLinks;
753 void QLabel::setOpenExternalLinks(bool open)
756 d->openExternalLinks = open;
758 d->control->setOpenExternalLinks(open);
762 \property QLabel::textInteractionFlags
765 Specifies how the label should interact with user input if it displays text.
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.
771 The default value is Qt::LinksAccessibleByMouse.
773 void QLabel::setTextInteractionFlags(Qt::TextInteractionFlags flags)
776 if (d->textInteractionFlags == flags)
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);
784 setFocusPolicy(Qt::NoFocus);
786 if (d->needTextControl()) {
787 d->ensureTextControl();
794 d->control->setTextInteractionFlags(d->textInteractionFlags);
797 Qt::TextInteractionFlags QLabel::textInteractionFlags() const
800 return d->textInteractionFlags;
804 Selects text from position \a start and for \a length characters.
808 \bold{Note:} The textInteractionFlags set on the label need to include
809 either TextSelectableByMouse or TextSelectableByKeyboard.
813 void QLabel::setSelection(int start, int length)
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);
826 \property QLabel::hasSelectedText
827 \brief whether there is any text selected
829 hasSelectedText() returns true if some or all of the text has been
830 selected by the user; otherwise returns false.
832 By default, this property is false.
836 \bold{Note:} The textInteractionFlags set on the label need to include
837 either TextSelectableByMouse or TextSelectableByKeyboard.
841 bool QLabel::hasSelectedText() const
845 return d->control->textCursor().hasSelection();
850 \property QLabel::selectedText
851 \brief the selected text
853 If there is no selected text this property's value is
856 By default, this property contains an empty string.
858 \sa hasSelectedText()
860 \bold{Note:} The textInteractionFlags set on the label need to include
861 either TextSelectableByMouse or TextSelectableByKeyboard.
865 QString QLabel::selectedText() const
869 return d->control->textCursor().selectedText();
874 selectionStart() returns the index of the first selected character in the
875 label or -1 if no text is selected.
879 \bold{Note:} The textInteractionFlags set on the label need to include
880 either TextSelectableByMouse or TextSelectableByKeyboard.
884 int QLabel::selectionStart() const
887 if (d->control && d->control->textCursor().hasSelection())
888 return d->control->textCursor().selectionStart();
894 QSize QLabel::sizeHint() const
898 (void) QLabel::minimumSizeHint();
905 QSize QLabel::minimumSizeHint() const
908 if (d->valid_hints) {
909 if (d->sizePolicy == sizePolicy())
914 d->valid_hints = true;
915 d->sh = d->sizeForWidth(-1); // wrap ? golden ratio : min doc size
918 if (!d->isTextLabel) {
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();
927 d->sizePolicy = sizePolicy();
933 void QLabel::mousePressEvent(QMouseEvent *ev)
936 d->sendControlEvent(ev);
941 void QLabel::mouseMoveEvent(QMouseEvent *ev)
944 d->sendControlEvent(ev);
949 void QLabel::mouseReleaseEvent(QMouseEvent *ev)
952 d->sendControlEvent(ev);
957 void QLabel::contextMenuEvent(QContextMenuEvent *ev)
959 #ifdef QT_NO_CONTEXTMENU
963 if (!d->isTextLabel) {
967 QMenu *menu = d->createStandardContextMenu(ev->pos());
973 menu->setAttribute(Qt::WA_DeleteOnClose);
974 menu->popup(ev->globalPos());
981 void QLabel::focusInEvent(QFocusEvent *ev)
984 if (d->isTextLabel) {
985 d->ensureTextControl();
986 d->sendControlEvent(ev);
988 QFrame::focusInEvent(ev);
994 void QLabel::focusOutEvent(QFocusEvent *ev)
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);
1009 QFrame::focusOutEvent(ev);
1014 bool QLabel::focusNextPrevChild(bool next)
1017 if (d->control && d->control->setFocusToNextOrPreviousAnchor(next))
1019 return QFrame::focusNextPrevChild(next);
1024 void QLabel::keyPressEvent(QKeyEvent *ev)
1027 d->sendControlEvent(ev);
1032 bool QLabel::event(QEvent *e)
1035 QEvent::Type type = e->type();
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();
1048 window()->setAttribute(Qt::WA_KeyboardFocusChange);
1053 if (type == QEvent::Resize) {
1055 d->textLayoutDirty = true;
1056 } else if (e->type() == QEvent::StyleChange
1058 || e->type() == QEvent::MacSizeChange
1061 d->setLayoutItemMargins(QStyle::SE_LabelLayoutItem);
1065 return QFrame::event(e);
1070 void QLabel::paintEvent(QPaintEvent *)
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));
1083 if (d->scaledcontents)
1084 style->drawItemPixmap(&painter, cr, align, d->movie->currentPixmap().scaled(cr.size()));
1086 style->drawItemPixmap(&painter, cr, align, d->movie->currentPixmap());
1090 if (d->isTextLabel) {
1091 QRectF lr = d->layoutRect().toAlignedRect();
1094 #ifndef QT_NO_STYLE_STYLESHEET
1095 if (QStyleSheetStyle* cssStyle = qobject_cast<QStyleSheetStyle*>(style)) {
1096 cssStyle->styleSheetPalette(this, &opt, &opt.palette);
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);
1109 d->ensureTextLayouted();
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());
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);
1126 // Adjust the palette
1127 context.palette = opt.palette;
1129 if (foregroundRole() != QPalette::Text && isEnabled())
1130 context.palette.setColor(QPalette::Text, context.palette.color(foregroundRole()));
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);
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;
1146 style->drawItemText(&painter, lr.toRect(), flags, opt.palette, isEnabled(), d->text, foregroundRole());
1149 #ifndef QT_NO_PICTURE
1151 QRect br = d->picture->boundingRect();
1152 int rw = br.width();
1153 int rh = br.height();
1154 if (d->scaledcontents) {
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);
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)
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);
1175 if (d->pixmap && !d->pixmap->isNull()) {
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)));
1184 pix = *d->scaledpixmap;
1190 pix = style->generatedIconPixmap(QIcon::Disabled, pix, &opt);
1191 style->drawItemPixmap(&painter, cr, align, pix);
1197 Updates the label, but not the frame.
1200 void QLabelPrivate::updateLabel()
1203 valid_hints = false;
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;
1213 q->updateGeometry();
1214 q->update(q->contentsRect());
1217 #ifndef QT_NO_SHORTCUT
1219 Sets this label's buddy to \a buddy.
1221 When the user presses the shortcut key indicated by this label,
1222 the keyboard focus is transferred to the label's buddy widget.
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 '&&').
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
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
1239 To unset a previously set buddy, call this function with \a buddy
1242 \sa buddy(), setText(), QShortcut, setAlignment()
1245 void QLabel::setBuddy(QWidget *buddy)
1249 if (d->isTextLabel) {
1251 releaseShortcut(d->shortcutId);
1253 d->textDirty = true;
1255 d->updateShortcut(); // grab new shortcut
1262 Returns this label's buddy, or 0 if no buddy is currently set.
1267 QWidget * QLabel::buddy() const
1273 void QLabelPrivate::updateShortcut()
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;
1283 if (!text.contains(QLatin1Char('&')))
1286 shortcutId = q->grabShortcut(QKeySequence::mnemonic(text));
1289 #endif // QT_NO_SHORTCUT
1292 void QLabelPrivate::_q_movieUpdated(const QRect& rect)
1295 if (movie && movie->isValid()) {
1297 if (scaledcontents) {
1298 QRect cr = q->contentsRect();
1299 QRect pixmapRect(cr.topLeft(), movie->currentPixmap().size());
1300 if (pixmapRect.isEmpty())
1302 r.setRect(cr.left(), cr.top(),
1303 (rect.width() * cr.width()) / pixmapRect.width(),
1304 (rect.height() * cr.height()) / pixmapRect.height());
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()));
1315 void QLabelPrivate::_q_movieResized(const QSize& size)
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();
1325 Sets the label contents to \a movie. Any previous content is
1326 cleared. The label does NOT take ownership of the movie.
1328 The buddy shortcut, if any, is disabled.
1330 \sa movie(), setBuddy()
1333 void QLabel::setMovie(QMovie *movie)
1342 connect(movie, SIGNAL(resized(QSize)), this, SLOT(_q_movieResized(QSize)));
1343 connect(movie, SIGNAL(updated(QRect)), this, SLOT(_q_movieUpdated(QRect)));
1345 // Assume that if the movie is running,
1346 // resize/update signals will come soon enough
1347 if (movie->state() != QMovie::Running)
1351 #endif // QT_NO_MOVIE
1356 Clears any contents, without updating/repainting the label.
1359 void QLabelPrivate::clearContents()
1363 isTextLabel = false;
1364 hasShortcut = false;
1366 #ifndef QT_NO_PICTURE
1370 delete scaledpixmap;
1379 #ifndef QT_NO_SHORTCUT
1381 q->releaseShortcut(shortcutId);
1386 QObject::disconnect(movie, SIGNAL(resized(QSize)), q, SLOT(_q_movieResized(QSize)));
1387 QObject::disconnect(movie, SIGNAL(updated(QRect)), q, SLOT(_q_movieUpdated(QRect)));
1391 #ifndef QT_NO_CURSOR
1394 q->setCursor(cursor);
1398 validCursor = false;
1407 Returns a pointer to the label's movie, or 0 if no movie has been
1413 QMovie *QLabel::movie() const
1419 #endif // QT_NO_MOVIE
1422 \property QLabel::textFormat
1423 \brief the label's text format
1425 See the Qt::TextFormat enum for an explanation of the possible
1428 The default format is Qt::AutoText.
1433 Qt::TextFormat QLabel::textFormat() const
1436 return d->textformat;
1439 void QLabel::setTextFormat(Qt::TextFormat format)
1442 if (format != d->textformat) {
1443 d->textformat = format;
1444 QString t = d->text;
1455 void QLabel::changeEvent(QEvent *ev)
1458 if(ev->type() == QEvent::FontChange || ev->type() == QEvent::ApplicationFontChange) {
1459 if (d->isTextLabel) {
1461 d->control->document()->setDefaultFont(font());
1464 } else if (ev->type() == QEvent::PaletteChange && d->control) {
1465 d->control->setPalette(palette());
1466 } else if (ev->type() == QEvent::ContentsRectChange) {
1469 QFrame::changeEvent(ev);
1473 \property QLabel::scaledContents
1474 \brief whether the label will scale its contents to fill all
1477 When enabled and the label shows a pixmap, it will scale the
1478 pixmap to fill the available space.
1480 This property's default is false.
1482 bool QLabel::hasScaledContents() const
1485 return d->scaledcontents;
1488 void QLabel::setScaledContents(bool enable)
1491 if ((bool)d->scaledcontents == enable)
1493 d->scaledcontents = enable;
1495 delete d->scaledpixmap;
1496 d->scaledpixmap = 0;
1497 delete d->cachedimage;
1500 update(contentsRect());
1503 Qt::LayoutDirection QLabelPrivate::textDirection() const
1506 QTextOption opt = control->document()->defaultTextOption();
1507 return opt.textDirection();
1510 return text.isRightToLeft() ? Qt::RightToLeft : Qt::LeftToRight;
1514 \fn void QLabel::setAlignment(Qt::AlignmentFlag flag)
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).
1522 // Returns the rect that is available for us to draw the document
1523 QRect QLabelPrivate::documentRect() const
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));
1532 if (m < 0 && q->frameWidth()) // no indent, but we do have a frame
1533 m = q->fontMetrics().width(QLatin1Char('x')) / 2 - margin;
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);
1547 void QLabelPrivate::ensureTextPopulated() const
1552 QTextDocument *doc = control->document();
1554 #ifndef QT_NO_TEXTHTMLPARSER
1558 doc->setPlainText(text);
1560 doc->setPlainText(text);
1562 doc->setUndoRedoEnabled(false);
1564 #ifndef QT_NO_SHORTCUT
1566 // Underline the first character that follows an ampersand (and remove the others ampersands)
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 &
1576 shortcutCursor = cursor;
1586 void QLabelPrivate::ensureTextLayouted() const
1588 if (!textLayoutDirty)
1590 ensureTextPopulated();
1592 QTextDocument *doc = control->document();
1593 QTextOption opt = doc->defaultTextOption();
1595 opt.setAlignment(QFlag(this->align));
1597 if (this->align & Qt::TextWordWrap)
1598 opt.setWrapMode(QTextOption::WordWrap);
1600 opt.setWrapMode(QTextOption::ManualWrap);
1602 doc->setDefaultTextOption(opt);
1604 QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
1606 doc->rootFrame()->setFrameFormat(fmt);
1607 doc->setTextWidth(documentRect().width());
1609 textLayoutDirty = false;
1612 void QLabelPrivate::ensureTextControl() const
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)),
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;
1636 void QLabelPrivate::sendControlEvent(QEvent *e)
1639 if (!isTextLabel || !control || textInteractionFlags == Qt::NoTextInteraction) {
1643 control->processEvent(e, -layoutRect().topLeft(), q);
1646 void QLabelPrivate::_q_linkHovered(const QString &anchor)
1649 #ifndef QT_NO_CURSOR
1650 if (anchor.isEmpty()) { // restore cursor
1652 q->setCursor(cursor);
1656 } else if (!onAnchor) {
1657 validCursor = q->testAttribute(Qt::WA_SetCursor);
1659 cursor = q->cursor();
1661 q->setCursor(Qt::PointingHandCursor);
1665 emit q->linkHovered(anchor);
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
1673 QRectF cr = documentRect();
1676 ensureTextLayouted();
1677 // Caculate y position manually
1678 qreal rh = control->document()->documentLayout()->documentSize().height();
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());
1687 // Returns the point in the document rect adjusted with p
1688 QPoint QLabelPrivate::layoutPoint(const QPoint& p) const
1690 QRect lr = layoutRect().toRect();
1691 return p - lr.topLeft();
1694 #ifndef QT_NO_CONTEXTMENU
1695 QMenu *QLabelPrivate::createStandardContextMenu(const QPoint &pos)
1699 if (control && isRichText) {
1700 p = layoutPoint(pos);
1701 linkToCopy = control->document()->documentLayout()->anchorAt(p);
1704 if (linkToCopy.isEmpty() && !control)
1707 return control->createStandardContextMenu(p, q_func());
1712 \fn void QLabel::linkHovered(const QString &link)
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.
1723 \fn void QLabel::linkActivated(const QString &link)
1726 This signal is emitted when the user clicks a link. The URL
1727 referred to by the anchor is passed in \a link.
1734 #include "moc_qlabel.cpp"