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

Last change on this file since 858 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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