source: trunk/src/gui/widgets/qlabel.cpp@ 5

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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