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