qtooltip.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/widgets/kernel/qtooltip.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
1/****************************************************************************-
2**-
3** Copyright (C) 2016 The Qt Company Ltd.-
4** Contact: https://www.qt.io/licensing/-
5**-
6** This file is part of the QtWidgets module of the Qt Toolkit.-
7**-
8** $QT_BEGIN_LICENSE:LGPL$-
9** Commercial License Usage-
10** Licensees holding valid commercial Qt licenses may use this file in-
11** accordance with the commercial license agreement provided with the-
12** Software or, alternatively, in accordance with the terms contained in-
13** a written agreement between you and The Qt Company. For licensing terms-
14** and conditions see https://www.qt.io/terms-conditions. For further-
15** information use the contact form at https://www.qt.io/contact-us.-
16**-
17** GNU Lesser General Public License Usage-
18** Alternatively, this file may be used under the terms of the GNU Lesser-
19** General Public License version 3 as published by the Free Software-
20** Foundation and appearing in the file LICENSE.LGPL3 included in the-
21** packaging of this file. Please review the following information to-
22** ensure the GNU Lesser General Public License version 3 requirements-
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.-
24**-
25** GNU General Public License Usage-
26** Alternatively, this file may be used under the terms of the GNU-
27** General Public License version 2.0 or (at your option) the GNU General-
28** Public license version 3 or any later version approved by the KDE Free-
29** Qt Foundation. The licenses are as published by the Free Software-
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3-
31** included in the packaging of this file. Please review the following-
32** information to ensure the GNU General Public License requirements will-
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and-
34** https://www.gnu.org/licenses/gpl-3.0.html.-
35**-
36** $QT_END_LICENSE$-
37**-
38****************************************************************************/-
39#ifdef Q_DEAD_CODE_FROM_QT4_MAC-
40# include <private/qcore_mac_p.h>-
41#endif-
42-
43#include <qapplication.h>-
44#include <qdesktopwidget.h>-
45#include <qevent.h>-
46#include <qlabel.h>-
47#include <qpointer.h>-
48#include <qstyle.h>-
49#include <qstyleoption.h>-
50#include <qstylepainter.h>-
51#include <qtimer.h>-
52#include <qtooltip.h>-
53#include <private/qeffects_p.h>-
54#include <qtextdocument.h>-
55#include <qdebug.h>-
56#include <private/qstylesheetstyle_p.h>-
57#ifndef QT_NO_TOOLTIP-
58-
59#ifdef Q_DEAD_CODE_FROM_QT4_MAC-
60# include <private/qcore_mac_p.h>-
61#include <private/qt_cocoa_helpers_mac_p.h>-
62#endif-
63-
64QT_BEGIN_NAMESPACE-
65-
66/*!-
67 \class QToolTip-
68-
69 \brief The QToolTip class provides tool tips (balloon help) for any-
70 widget.-
71-
72 \ingroup helpsystem-
73 \inmodule QtWidgets-
74-
75 The tip is a short piece of text reminding the user of the-
76 widget's function. It is drawn immediately below the given-
77 position in a distinctive black-on-yellow color combination. The-
78 tip can be any \l{QTextEdit}{rich text} formatted string.-
79-
80 Rich text displayed in a tool tip is implicitly word-wrapped unless-
81 specified differently with \c{<p style='white-space:pre'>}.-
82-
83 The simplest and most common way to set a widget's tool tip is by-
84 calling its QWidget::setToolTip() function.-
85-
86 It is also possible to show different tool tips for different-
87 regions of a widget, by using a QHelpEvent of type-
88 QEvent::ToolTip. Intercept the help event in your widget's \l-
89 {QWidget::}{event()} function and call QToolTip::showText() with-
90 the text you want to display. The \l{widgets/tooltips}{Tooltips}-
91 example illustrates this technique.-
92-
93 If you are calling QToolTip::hideText(), or QToolTip::showText()-
94 with an empty string, as a result of a \l{QEvent::}{ToolTip}-event you-
95 should also call \l{QEvent::}{ignore()} on the event, to signal-
96 that you don't want to start any tooltip specific modes.-
97-
98 Note that, if you want to show tooltips in an item view, the-
99 model/view architecture provides functionality to set an item's-
100 tool tip; e.g., the QTableWidgetItem::setToolTip() function.-
101 However, if you want to provide custom tool tips in an item view,-
102 you must intercept the help event in the-
103 QAbstractItemView::viewportEvent() function and handle it yourself.-
104-
105 The default tool tip color and font can be customized with-
106 setPalette() and setFont(). When a tooltip is currently on-
107 display, isVisible() returns \c true and text() the currently visible-
108 text.-
109-
110 \note Tool tips use the inactive color group of QPalette, because tool-
111 tips are not active windows.-
112-
113 \sa QWidget::toolTip, QAction::toolTip, {Tool Tips Example}-
114*/-
115-
116class QTipLabel : public QLabel-
117{-
118 Q_OBJECT-
119public:-
120 QTipLabel(const QString &text, QWidget *w, int msecDisplayTime);-
121 ~QTipLabel();-
122 static QTipLabel *instance;-
123-
124 bool eventFilter(QObject *, QEvent *) Q_DECL_OVERRIDE;-
125-
126 QBasicTimer hideTimer, expireTimer;-
127-
128 bool fadingOut;-
129-
130 void reuseTip(const QString &text, int msecDisplayTime);-
131 void hideTip();-
132 void hideTipImmediately();-
133 void setTipRect(QWidget *w, const QRect &r);-
134 void restartExpireTimer(int msecDisplayTime);-
135 bool tipChanged(const QPoint &pos, const QString &text, QObject *o);-
136 void placeTip(const QPoint &pos, QWidget *w);-
137-
138 static int getTipScreen(const QPoint &pos, QWidget *w);-
139protected:-
140 void timerEvent(QTimerEvent *e) Q_DECL_OVERRIDE;-
141 void paintEvent(QPaintEvent *e) Q_DECL_OVERRIDE;-
142 void mouseMoveEvent(QMouseEvent *e) Q_DECL_OVERRIDE;-
143 void resizeEvent(QResizeEvent *e) Q_DECL_OVERRIDE;-
144-
145#ifndef QT_NO_STYLE_STYLESHEET-
146public slots:-
147 /** \internal-
148 Cleanup the _q_stylesheet_parent propery.-
149 */-
150 void styleSheetParentDestroyed() {-
151 setProperty("_q_stylesheet_parent", QVariant());-
152 styleSheetParent = 0;-
153 }-
154-
155private:-
156 QWidget *styleSheetParent;-
157#endif-
158-
159private:-
160 QWidget *widget;-
161 QRect rect;-
162};-
163-
164QTipLabel *QTipLabel::instance = 0;-
165-
166QTipLabel::QTipLabel(const QString &text, QWidget *w, int msecDisplayTime)-
167#ifndef QT_NO_STYLE_STYLESHEET-
168 : QLabel(w, Qt::ToolTip | Qt::BypassGraphicsProxyWidget), styleSheetParent(0), widget(0)-
169#else-
170 : QLabel(w, Qt::ToolTip | Qt::BypassGraphicsProxyWidget), widget(0)-
171#endif-
172{-
173 delete instance;-
174 instance = this;-
175 setForegroundRole(QPalette::ToolTipText);-
176 setBackgroundRole(QPalette::ToolTipBase);-
177 setPalette(QToolTip::palette());-
178 ensurePolished();-
179 setMargin(1 + style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, 0, this));-
180 setFrameStyle(QFrame::NoFrame);-
181 setAlignment(Qt::AlignLeft);-
182 setIndent(1);-
183 qApp->installEventFilter(this);-
184 setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, 0, this) / 255.0);-
185 setMouseTracking(true);-
186 fadingOut = false;-
187 reuseTip(text, msecDisplayTime);-
188}-
189-
190void QTipLabel::restartExpireTimer(int msecDisplayTime)-
191{-
192 int time = 10000 + 40 * qMax(0, text().length()-100);-
193 if (msecDisplayTime > 0)-
194 time = msecDisplayTime;-
195 expireTimer.start(time, this);-
196 hideTimer.stop();-
197}-
198-
199void QTipLabel::reuseTip(const QString &text, int msecDisplayTime)-
200{-
201#ifndef QT_NO_STYLE_STYLESHEET-
202 if (styleSheetParent){-
203 disconnect(styleSheetParent, SIGNAL(destroyed()),-
204 QTipLabel::instance, SLOT(styleSheetParentDestroyed()));-
205 styleSheetParent = 0;-
206 }-
207#endif-
208-
209 setWordWrap(Qt::mightBeRichText(text));-
210 setText(text);-
211 QFontMetrics fm(font());-
212 QSize extra(1, 0);-
213 // Make it look good with the default ToolTip font on Mac, which has a small descent.-
214 if (fm.descent() == 2 && fm.ascent() >= 11)-
215 ++extra.rheight();-
216 resize(sizeHint() + extra);-
217 restartExpireTimer(msecDisplayTime);-
218}-
219-
220void QTipLabel::paintEvent(QPaintEvent *ev)-
221{-
222 QStylePainter p(this);-
223 QStyleOptionFrame opt;-
224 opt.init(this);-
225 p.drawPrimitive(QStyle::PE_PanelTipLabel, opt);-
226 p.end();-
227-
228 QLabel::paintEvent(ev);-
229}-
230-
231void QTipLabel::resizeEvent(QResizeEvent *e)-
232{-
233 QStyleHintReturnMask frameMask;-
234 QStyleOption option;-
235 option.init(this);-
236 if (style()->styleHint(QStyle::SH_ToolTip_Mask, &option, this, &frameMask))-
237 setMask(frameMask.region);-
238-
239 QLabel::resizeEvent(e);-
240}-
241-
242void QTipLabel::mouseMoveEvent(QMouseEvent *e)-
243{-
244 if (rect.isNull())-
245 return;-
246 QPoint pos = e->globalPos();-
247 if (widget)-
248 pos = widget->mapFromGlobal(pos);-
249 if (!rect.contains(pos))-
250 hideTip();-
251 QLabel::mouseMoveEvent(e);-
252}-
253-
254QTipLabel::~QTipLabel()-
255{-
256 instance = 0;-
257}-
258-
259void QTipLabel::hideTip()-
260{-
261 if (!hideTimer.isActive())-
262 hideTimer.start(300, this);-
263}-
264-
265void QTipLabel::hideTipImmediately()-
266{-
267 close(); // to trigger QEvent::Close which stops the animation-
268 deleteLater();-
269}-
270-
271void QTipLabel::setTipRect(QWidget *w, const QRect &r)-
272{-
273 if (Q_UNLIKELY(!r.isNull() && !w))) {
__builtin_expe...&& !w), false)Description
TRUEnever evaluated
FALSEnever evaluated
0
274 qWarning("QToolTip::setTipRect: Cannot pass null widget if rect is set");-
275 else{return;
never executed: return;
0
276 }-
277 widget = w;-
278 rect = r;}-
279}
never executed: end of block
0
280-
281void QTipLabel::timerEvent(QTimerEvent *e)-
282{-
283 if (e->timerId() == hideTimer.timerId()-
284 || e->timerId() == expireTimer.timerId()){-
285 hideTimer.stop();-
286 expireTimer.stop();-
287#if defined(Q_DEAD_CODE_FROM_QT4_MAC) && !defined(QT_NO_EFFECTS)-
288 if (QApplication::isEffectEnabled(Qt::UI_FadeTooltip)){-
289 // Fade out tip on mac (makes it invisible).-
290 // The tip will not be deleted until a new tip is shown.-
291-
292 // DRSWAT - Cocoa-
293 macWindowFade(qt_mac_window_for(this));-
294 QTipLabel::instance->fadingOut = true; // will never be false again.-
295 }-
296 else-
297 hideTipImmediately();-
298#else-
299 hideTipImmediately();-
300#endif-
301 }-
302}-
303-
304bool QTipLabel::eventFilter(QObject *o, QEvent *e)-
305{-
306 switch (e->type()) {-
307#ifdef Q_DEAD_CODE_FROM_QT4_MAC-
308 case QEvent::KeyPress:-
309 case QEvent::KeyRelease: {-
310 int key = static_cast<QKeyEvent *>(e)->key();-
311 Qt::KeyboardModifiers mody = static_cast<QKeyEvent *>(e)->modifiers();-
312 if (!(mody & Qt::KeyboardModifierMask)-
313 && key != Qt::Key_Shift && key != Qt::Key_Control-
314 && key != Qt::Key_Alt && key != Qt::Key_Meta)-
315 hideTip();-
316 break;-
317 }-
318#endif-
319 case QEvent::Leave:-
320 hideTip();-
321 break;-
322-
323-
324#if defined (Q_OS_QNX) // On QNX the window activate and focus events are delayed and will appear-
325 // after the window is shown.-
326 case QEvent::WindowActivate:-
327 case QEvent::FocusIn:-
328 return false;-
329 case QEvent::WindowDeactivate:-
330 if (o != this)-
331 return false;-
332 hideTipImmediately();-
333 break;-
334 case QEvent::FocusOut:-
335 if (reinterpret_cast<QWindow*>(o) != windowHandle())-
336 return false;-
337 hideTipImmediately();-
338 break;-
339#else-
340 case QEvent::WindowActivate:-
341 case QEvent::WindowDeactivate:-
342 case QEvent::FocusIn:-
343 case QEvent::FocusOut:-
344#endif-
345 case QEvent::Close: // For QTBUG-55523 (QQC) specifically: Hide tooltip when windows are closed-
346 case QEvent::MouseButtonPress:-
347 case QEvent::MouseButtonRelease:-
348 case QEvent::MouseButtonDblClick:-
349 case QEvent::Wheel:-
350 hideTipImmediately();-
351 break;-
352-
353 case QEvent::MouseMove:-
354 if (o == widget && !rect.isNull() && !rect.contains(static_cast<QMouseEvent*>(e)->pos()))-
355 hideTip();-
356 default:-
357 break;-
358 }-
359 return false;-
360}-
361-
362int QTipLabel::getTipScreen(const QPoint &pos, QWidget *w)-
363{-
364 if (QApplication::desktop()->isVirtualDesktop())-
365 return QApplication::desktop()->screenNumber(pos);-
366 else-
367 return QApplication::desktop()->screenNumber(w);-
368}-
369-
370void QTipLabel::placeTip(const QPoint &pos, QWidget *w)-
371{-
372#ifndef QT_NO_STYLE_STYLESHEET-
373 if (testAttribute(Qt::WA_StyleSheet) || (w && qobject_cast<QStyleSheetStyle *>(w->style()))) {-
374 //the stylesheet need to know the real parent-
375 QTipLabel::instance->setProperty("_q_stylesheet_parent", QVariant::fromValue(w));-
376 //we force the style to be the QStyleSheetStyle, and force to clear the cache as well.-
377 QTipLabel::instance->setStyleSheet(QLatin1String("/* */"));-
378-
379 // Set up for cleaning up this later...-
380 QTipLabel::instance->styleSheetParent = w;-
381 if (w) {-
382 connect(w, SIGNAL(destroyed()),-
383 QTipLabel::instance, SLOT(styleSheetParentDestroyed()));-
384 }-
385 }-
386#endif //QT_NO_STYLE_STYLESHEET-
387-
388-
389#ifdef Q_DEAD_CODE_FROM_QT4_MAC-
390 // When in full screen mode, there is no Dock nor Menu so we can use-
391 // the whole screen for displaying the tooltip. However when not in-
392 // full screen mode we need to save space for the dock, so we use-
393 // availableGeometry instead.-
394 extern bool qt_mac_app_fullscreen; //qapplication_mac.mm-
395 QRect screen;-
396 if(qt_mac_app_fullscreen)-
397 screen = QApplication::desktop()->screenGeometry(getTipScreen(pos, w));-
398 else-
399 screen = QApplication::desktop()->availableGeometry(getTipScreen(pos, w));-
400#else-
401 QRect screen = QApplication::desktop()->screenGeometry(getTipScreen(pos, w));-
402#endif-
403-
404 QPoint p = pos;-
405 p += QPoint(2,-
406#ifdef Q_DEAD_CODE_FROM_QT4_WIN-
407 21-
408#else-
409 16-
410#endif-
411 );-
412 if (p.x() + this->width() > screen.x() + screen.width())-
413 p.rx() -= 4 + this->width();-
414 if (p.y() + this->height() > screen.y() + screen.height())-
415 p.ry() -= 24 + this->height();-
416 if (p.y() < screen.y())-
417 p.setY(screen.y());-
418 if (p.x() + this->width() > screen.x() + screen.width())-
419 p.setX(screen.x() + screen.width() - this->width());-
420 if (p.x() < screen.x())-
421 p.setX(screen.x());-
422 if (p.y() + this->height() > screen.y() + screen.height())-
423 p.setY(screen.y() + screen.height() - this->height());-
424 this->move(p);-
425}-
426-
427bool QTipLabel::tipChanged(const QPoint &pos, const QString &text, QObject *o)-
428{-
429 if (QTipLabel::instance->text() != text)-
430 return true;-
431-
432 if (o != widget)-
433 return true;-
434-
435 if (!rect.isNull())-
436 return !rect.contains(pos);-
437 else-
438 return false;-
439}-
440-
441/*!-
442 Shows \a text as a tool tip, with the global position \a pos as-
443 the point of interest. The tool tip will be shown with a platform-
444 specific offset from this point of interest.-
445-
446 If you specify a non-empty rect the tip will be hidden as soon-
447 as you move your cursor out of this area.-
448-
449 The \a rect is in the coordinates of the widget you specify with-
450 \a w. If the \a rect is not empty you must specify a widget.-
451 Otherwise this argument can be 0 but it is used to determine the-
452 appropriate screen on multi-head systems.-
453-
454 If \a text is empty the tool tip is hidden. If the text is the-
455 same as the currently shown tooltip, the tip will \e not move.-
456 You can force moving by first hiding the tip with an empty text,-
457 and then showing the new tip at the new position.-
458*/-
459-
460void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect)-
461{-
462 showText(pos, text, w, rect, -1);-
463}-
464-
465/*!-
466 \since 5.2-
467 \overload-
468 This is similar to QToolTip::showText(\a pos, \a text, \a w, \a rect) but with an extra parameter \a msecDisplayTime-
469 that specifies how long the tool tip will be displayed, in milliseconds.-
470*/-
471-
472void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect, int msecDisplayTime)-
473{-
474 if (QTipLabel::instance && QTipLabel::instance->isVisible()){ // a tip does already exist-
475 if (text.isEmpty()){ // empty text means hide current tip-
476 QTipLabel::instance->hideTip();-
477 return;-
478 }-
479 else if (!QTipLabel::instance->fadingOut){-
480 // If the tip has changed, reuse the one-
481 // that is showing (removes flickering)-
482 QPoint localPos = pos;-
483 if (w)-
484 localPos = w->mapFromGlobal(pos);-
485 if (QTipLabel::instance->tipChanged(localPos, text, w)){-
486 QTipLabel::instance->reuseTip(text, msecDisplayTime);-
487 QTipLabel::instance->setTipRect(w, rect);-
488 QTipLabel::instance->placeTip(pos, w);-
489 }-
490 return;-
491 }-
492 }-
493-
494 if (!text.isEmpty()){ // no tip can be reused, create new tip:-
495#ifndef Q_DEAD_CODE_FROM_QT4_WIN-
496 new QTipLabel(text, w, msecDisplayTime); // sets QTipLabel::instance to itself-
497#else-
498 // On windows, we can't use the widget as parent otherwise the window will be-
499 // raised when the tooltip will be shown-
500 new QTipLabel(text, QApplication::desktop()->screen(QTipLabel::getTipScreen(pos, w)), msecDisplayTime);-
501#endif-
502 QTipLabel::instance->setTipRect(w, rect);-
503 QTipLabel::instance->placeTip(pos, w);-
504 QTipLabel::instance->setObjectName(QLatin1String("qtooltip_label"));-
505-
506-
507#if !defined(QT_NO_EFFECTS) && !defined(Q_DEAD_CODE_FROM_QT4_MAC)-
508 if (QApplication::isEffectEnabled(Qt::UI_FadeTooltip))-
509 qFadeEffect(QTipLabel::instance);-
510 else if (QApplication::isEffectEnabled(Qt::UI_AnimateTooltip))-
511 qScrollEffect(QTipLabel::instance);-
512 else-
513 QTipLabel::instance->showNormal();-
514#else-
515 QTipLabel::instance->showNormal();-
516#endif-
517 }-
518}-
519-
520/*!-
521 \overload-
522-
523 This is analogous to calling QToolTip::showText(\a pos, \a text, \a w, QRect())-
524*/-
525-
526void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w)-
527{-
528 QToolTip::showText(pos, text, w, QRect());-
529}-
530-
531-
532/*!-
533 \fn void QToolTip::hideText()-
534 \since 4.2-
535-
536 Hides the tool tip. This is the same as calling showText() with an-
537 empty string.-
538-
539 \sa showText()-
540*/-
541-
542-
543/*!-
544 \since 4.4-
545-
546 Returns \c true if this tooltip is currently shown.-
547-
548 \sa showText()-
549 */-
550bool QToolTip::isVisible()-
551{-
552 return (QTipLabel::instance != 0 && QTipLabel::instance->isVisible());-
553}-
554-
555/*!-
556 \since 4.4-
557-
558 Returns the tooltip text, if a tooltip is visible, or an-
559 empty string if a tooltip is not visible.-
560 */-
561QString QToolTip::text()-
562{-
563 if (QTipLabel::instance)-
564 return QTipLabel::instance->text();-
565 return QString();-
566}-
567-
568-
569Q_GLOBAL_STATIC(QPalette, tooltip_palette)-
570-
571/*!-
572 Returns the palette used to render tooltips.-
573-
574 \note Tool tips use the inactive color group of QPalette, because tool-
575 tips are not active windows.-
576*/-
577QPalette QToolTip::palette()-
578{-
579 return *tooltip_palette();-
580}-
581-
582/*!-
583 \since 4.2-
584-
585 Returns the font used to render tooltips.-
586*/-
587QFont QToolTip::font()-
588{-
589 return QApplication::font("QTipLabel");-
590}-
591-
592/*!-
593 \since 4.2-
594-
595 Sets the \a palette used to render tooltips.-
596-
597 \note Tool tips use the inactive color group of QPalette, because tool-
598 tips are not active windows.-
599*/-
600void QToolTip::setPalette(const QPalette &palette)-
601{-
602 *tooltip_palette() = palette;-
603 if (QTipLabel::instance)-
604 QTipLabel::instance->setPalette(palette);-
605}-
606-
607/*!-
608 \since 4.2-
609-
610 Sets the \a font used to render tooltips.-
611*/-
612void QToolTip::setFont(const QFont &font)-
613{-
614 QApplication::setFont(font, "QTipLabel");-
615}-
616-
617QT_END_NAMESPACE-
618-
619#include "qtooltip.moc"-
620#endif // QT_NO_TOOLTIP-
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9