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

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 43.9 KB
Line 
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** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** 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 have questions regarding the use of this file, please contact
37** Nokia at qt-info@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
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
144const 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*/
160QLabel::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*/
175QLabel::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
194QLabel::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
213QLabel::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*/
239QLabel::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
258QLabel::~QLabel()
259{
260 Q_D(QLabel);
261 d->clearContents();
262}
263
264void 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
335void 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
374QString QLabel::text() const
375{
376 Q_D(const QLabel);
377 return d->text;
378}
379
380/*!
381 Clears any label contents.
382*/
383
384void 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*/
400void 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
414const 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
430void 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
451void 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
471void 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
487void 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*/
505void 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
513Qt::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*/
531void 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
542bool 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
569void QLabel::setIndent(int indent)
570{
571 Q_D(QLabel);
572 d->indent = indent;
573 d->updateLabel();
574}
575
576int 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*/
594int QLabel::margin() const
595{
596 Q_D(const QLabel);
597 return d->margin;
598}
599
600void 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*/
613QSize 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
705int 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*/
728bool QLabel::openExternalLinks() const
729{
730 Q_D(const QLabel);
731 return d->openExternalLinks;
732}
733
734void 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*/
754void 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
778Qt::TextInteractionFlags QLabel::textInteractionFlags() const
779{
780 Q_D(const QLabel);
781 return d->textInteractionFlags;
782}
783
784/*!\reimp
785*/
786QSize 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*/
797QSize 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*/
825void QLabel::mousePressEvent(QMouseEvent *ev)
826{
827 Q_D(QLabel);
828 d->sendControlEvent(ev);
829}
830
831/*!\reimp
832*/
833void QLabel::mouseMoveEvent(QMouseEvent *ev)
834{
835 Q_D(QLabel);
836 d->sendControlEvent(ev);
837}
838
839/*!\reimp
840*/
841void QLabel::mouseReleaseEvent(QMouseEvent *ev)
842{
843 Q_D(QLabel);
844 d->sendControlEvent(ev);
845}
846
847/*!\reimp
848*/
849void 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*/
873void 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*/
886void 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*/
906bool 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*/
916void QLabel::keyPressEvent(QKeyEvent *ev)
917{
918 Q_D(QLabel);
919 d->sendControlEvent(ev);
920}
921
922/*!\reimp
923*/
924bool 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*/
962void 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
1090void 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
1135void 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
1157QWidget * QLabel::buddy() const
1158{
1159 Q_D(const QLabel);
1160 return d->buddy;
1161}
1162
1163void 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
1182void 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
1205void 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
1223void 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
1249void 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
1303QMovie *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
1323Qt::TextFormat QLabel::textFormat() const
1324{
1325 Q_D(const QLabel);
1326 return d->textformat;
1327}
1328
1329void 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*/
1345void 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*/
1376bool QLabel::hasScaledContents() const
1377{
1378 Q_D(const QLabel);
1379 return d->scaledcontents;
1380}
1381
1382void 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
1408QRect 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
1431void 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
1470void 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
1499void 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
1523void 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
1533void 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
1558QRectF 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
1575QPoint QLabelPrivate::layoutPoint(const QPoint& p) const
1576{
1577 QRect lr = layoutRect().toRect();
1578 return p - lr.topLeft();
1579}
1580
1581#ifndef QT_NO_CONTEXTMENU
1582QMenu *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
1619QT_END_NAMESPACE
1620
1621#include "moc_qlabel.cpp"
Note: See TracBrowser for help on using the repository browser.