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 
40 #include "qwhatsthis.h"
41 #include "qpointer.h"
42 #include "qapplication.h"
43 #include <private/qguiapplication_p.h>
44 #include "qdesktopwidget.h"
45 #include <private/qdesktopwidget_p.h>
46 #include "qevent.h"
47 #include "qpixmap.h"
48 #include "qscreen.h"
49 #include "qpainter.h"
50 #include "qtimer.h"
51 #if QT_CONFIG(action)
52 #include "qaction.h"
53 #endif // QT_CONFIG(action)
54 #include "qcursor.h"
55 #include "qbitmap.h"
56 #include "qtextdocument.h"
57 #include <qpa/qplatformtheme.h>
58 #include "private/qtextdocumentlayout_p.h"
59 #include "qdebug.h"
60 #ifndef QT_NO_ACCESSIBILITY
61 #include "qaccessible.h"
62 #endif
63 
64 QT_BEGIN_NAMESPACE
65 
66 /*!
67     \class QWhatsThis
68     \brief The QWhatsThis class provides a simple description of any
69     widget, i.e. answering the question "What's This?".
70 
71     \ingroup helpsystem
72     \inmodule QtWidgets
73 
74     "What's This?" help is part of an application's online help
75     system, and provides users with information about the
76     functionality and usage of a particular widget. "What's This?"
77     help texts are typically longer and more detailed than
78     \l{QToolTip}{tooltips}, but generally provide less information
79     than that supplied by separate help windows.
80 
81     QWhatsThis provides a single window with an explanatory text that
82     pops up when the user asks "What's This?". The default way for
83     users to ask the question is to move the focus to the relevant
84     widget and press Shift+F1. The help text appears immediately; it
85     goes away as soon as the user does something else.
86     (Note that if there is a shortcut for Shift+F1, this mechanism
87     will not work.) Some dialogs provide a "?" button that users can
88     click to enter "What's This?" mode; they then click the relevant
89     widget to pop up the "What's This?" window. It is also possible to
90     provide a a menu option or toolbar button to switch into "What's
91     This?" mode.
92 
93     To add "What's This?" text to a widget or an action, you simply
94     call QWidget::setWhatsThis() or QAction::setWhatsThis().
95 
96     The text can be either rich text or plain text. If you specify a
97     rich text formatted string, it will be rendered using the default
98     stylesheet, making it possible to embed images in the displayed
99     text. To be as fast as possible, the default stylesheet uses a
100     simple method to determine whether the text can be rendered as
101     plain text. See Qt::mightBeRichText() for details.
102 
103     \snippet whatsthis/whatsthis.cpp 0
104 
105     An alternative way to enter "What's This?" mode is to call
106     createAction(), and add the returned QAction to either a menu or
107     a tool bar. By invoking this context help action (in the picture
108     below, the button with the arrow and question mark icon) the user
109     switches into "What's This?" mode. If they now click on a widget
110     the appropriate help text is shown. The mode is left when help is
111     given or when the user presses Esc.
112 
113     \image whatsthis.png
114 
115     You can enter "What's This?" mode programmatically with
116     enterWhatsThisMode(), check the mode with inWhatsThisMode(), and
117     return to normal mode with leaveWhatsThisMode().
118 
119     If you want to control the "What's This?" behavior of a widget
120     manually see Qt::WA_CustomWhatsThis.
121 
122     It is also possible to show different help texts for different
123     regions of a widget, by using a QHelpEvent of type
124     QEvent::WhatsThis. Intercept the help event in your widget's
125     QWidget::event() function and call QWhatsThis::showText() with the
126     text you want to display for the position specified in
127     QHelpEvent::pos(). If the text is rich text and the user clicks
128     on a link, the widget also receives a QWhatsThisClickedEvent with
129     the link's reference as QWhatsThisClickedEvent::href(). If a
130     QWhatsThisClickedEvent is handled (i.e. QWidget::event() returns
131     true), the help window remains visible. Call
132     QWhatsThis::hideText() to hide it explicitly.
133 
134     \sa QToolTip
135 */
136 
137 Q_CORE_EXPORT void qDeleteInEventHandler(QObject *o);
138 
139 class QWhatsThat : public QWidget
140 {
141     Q_OBJECT
142 
143 public:
144     QWhatsThat(const QString& txt, QWidget* parent, QWidget *showTextFor);
145     ~QWhatsThat() ;
146 
147     static QWhatsThat *instance;
148 
149 protected:
150     void showEvent(QShowEvent *e) override;
151     void mousePressEvent(QMouseEvent*) override;
152     void mouseReleaseEvent(QMouseEvent*) override;
153     void mouseMoveEvent(QMouseEvent*) override;
154     void keyPressEvent(QKeyEvent*) override;
155     void paintEvent(QPaintEvent*) override;
156 
157 private:
158     QPointer<QWidget>widget;
159     bool pressed;
160     QString text;
161     QTextDocument* doc;
162     QString anchor;
163     QPixmap background;
164 };
165 
166 QWhatsThat *QWhatsThat::instance = nullptr;
167 
168 // shadowWidth not const, for XP drop-shadow-fu turns it to 0
169 static int shadowWidth = 6;   // also used as '5' and '6' and even '8' below
170 static const int vMargin = 8;
171 static const int hMargin = 12;
172 
dropShadow()173 static inline bool dropShadow()
174 {
175     if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
176         return theme->themeHint(QPlatformTheme::DropShadow).toBool();
177     return false;
178 }
179 
QWhatsThat(const QString & txt,QWidget * parent,QWidget * showTextFor)180 QWhatsThat::QWhatsThat(const QString& txt, QWidget* parent, QWidget *showTextFor)
181     : QWidget(parent, Qt::Popup),
182       widget(showTextFor), pressed(false), text(txt)
183 {
184     delete instance;
185     instance = this;
186     setAttribute(Qt::WA_DeleteOnClose, true);
187     setAttribute(Qt::WA_NoSystemBackground, true);
188     if (parent)
189         setPalette(parent->palette());
190     setMouseTracking(true);
191     setFocusPolicy(Qt::StrongFocus);
192 #ifndef QT_NO_CURSOR
193     setCursor(Qt::ArrowCursor);
194 #endif
195     QRect r;
196     doc = nullptr;
197     ensurePolished(); // Ensures style sheet font before size calc
198     if (Qt::mightBeRichText(text)) {
199         doc = new QTextDocument();
200         doc->setUndoRedoEnabled(false);
201         doc->setDefaultFont(QApplication::font(this));
202 #ifdef QT_NO_TEXTHTMLPARSER
203         doc->setPlainText(text);
204 #else
205         doc->setHtml(text);
206 #endif
207         doc->setUndoRedoEnabled(false);
208         doc->adjustSize();
209         r.setTop(0);
210         r.setLeft(0);
211         r.setSize(doc->size().toSize());
212     }
213     else
214     {
215         int sw = QDesktopWidgetPrivate::width() / 3;
216         if (sw < 200)
217             sw = 200;
218         else if (sw > 300)
219             sw = 300;
220 
221         r = fontMetrics().boundingRect(0, 0, sw, 1000,
222                                         Qt::AlignLeft + Qt::AlignTop
223                                         + Qt::TextWordWrap + Qt::TextExpandTabs,
224                                         text);
225     }
226     shadowWidth = dropShadow() ? 0 : 6;
227     resize(r.width() + 2*hMargin + shadowWidth, r.height() + 2*vMargin + shadowWidth);
228 }
229 
~QWhatsThat()230 QWhatsThat::~QWhatsThat()
231 {
232     instance = nullptr;
233     if (doc)
234         delete doc;
235 }
236 
showEvent(QShowEvent *)237 void QWhatsThat::showEvent(QShowEvent *)
238 {
239     background = QGuiApplication::primaryScreen()->grabWindow(QApplication::desktop()->internalWinId(),
240                                                               x(), y(), width(), height());
241 }
242 
mousePressEvent(QMouseEvent * e)243 void QWhatsThat::mousePressEvent(QMouseEvent* e)
244 {
245     pressed = true;
246     if (e->button() == Qt::LeftButton && rect().contains(e->pos())) {
247         if (doc)
248             anchor = doc->documentLayout()->anchorAt(e->pos() -  QPoint(hMargin, vMargin));
249         return;
250     }
251     close();
252 }
253 
mouseReleaseEvent(QMouseEvent * e)254 void QWhatsThat::mouseReleaseEvent(QMouseEvent* e)
255 {
256     if (!pressed)
257         return;
258     if (widget && e->button() == Qt::LeftButton && doc && rect().contains(e->pos())) {
259         QString a = doc->documentLayout()->anchorAt(e->pos() -  QPoint(hMargin, vMargin));
260         QString href;
261         if (anchor == a)
262             href = a;
263         anchor.clear();
264         if (!href.isEmpty()) {
265             QWhatsThisClickedEvent e(href);
266             if (QCoreApplication::sendEvent(widget, &e))
267                 return;
268         }
269     }
270     close();
271 }
272 
mouseMoveEvent(QMouseEvent * e)273 void QWhatsThat::mouseMoveEvent(QMouseEvent* e)
274 {
275 #ifdef QT_NO_CURSOR
276     Q_UNUSED(e);
277 #else
278     if (!doc)
279         return;
280     QString a = doc->documentLayout()->anchorAt(e->pos() -  QPoint(hMargin, vMargin));
281     if (!a.isEmpty())
282         setCursor(Qt::PointingHandCursor);
283     else
284         setCursor(Qt::ArrowCursor);
285 #endif
286 }
287 
keyPressEvent(QKeyEvent *)288 void QWhatsThat::keyPressEvent(QKeyEvent*)
289 {
290     close();
291 }
292 
paintEvent(QPaintEvent *)293 void QWhatsThat::paintEvent(QPaintEvent*)
294 {
295     const bool drawShadow = dropShadow();
296 
297     QRect r = rect();
298     r.adjust(0, 0, -1, -1);
299     if (drawShadow)
300         r.adjust(0, 0, -shadowWidth, -shadowWidth);
301     QPainter p(this);
302     p.drawPixmap(0, 0, background);
303     p.setPen(QPen(palette().toolTipText(), 0));
304     p.setBrush(palette().toolTipBase());
305     p.drawRect(r);
306     int w = r.width();
307     int h = r.height();
308     p.setPen(palette().brush(QPalette::Dark).color());
309     p.drawRect(1, 1, w-2, h-2);
310     if (drawShadow) {
311         p.setPen(palette().shadow().color());
312         p.drawPoint(w + 5, 6);
313         p.drawLine(w + 3, 6, w + 5, 8);
314         p.drawLine(w + 1, 6, w + 5, 10);
315         int i;
316         for(i=7; i < h; i += 2)
317             p.drawLine(w, i, w + 5, i + 5);
318         for(i = w - i + h; i > 6; i -= 2)
319             p.drawLine(i, h, i + 5, h + 5);
320         for(; i > 0 ; i -= 2)
321             p.drawLine(6, h + 6 - i, i + 5, h + 5);
322     }
323     r.adjust(0, 0, 1, 1);
324     p.setPen(palette().toolTipText().color());
325     r.adjust(hMargin, vMargin, -hMargin, -vMargin);
326 
327     if (doc) {
328         p.translate(r.x(), r.y());
329         QRect rect = r;
330         rect.translate(-r.x(), -r.y());
331         p.setClipRect(rect);
332         QAbstractTextDocumentLayout::PaintContext context;
333         context.palette.setBrush(QPalette::Text, context.palette.toolTipText());
334         doc->documentLayout()->draw(&p, context);
335     }
336     else
337     {
338         p.drawText(r, Qt::AlignLeft + Qt::AlignTop + Qt::TextWordWrap + Qt::TextExpandTabs, text);
339     }
340 }
341 
342 static const char * const button_image[] = {
343 "16 16 3 1",
344 "         c None",
345 "o        c #000000",
346 "a        c #000080",
347 "o        aaaaa  ",
348 "oo      aaa aaa ",
349 "ooo    aaa   aaa",
350 "oooo   aa     aa",
351 "ooooo  aa     aa",
352 "oooooo  a    aaa",
353 "ooooooo     aaa ",
354 "oooooooo   aaa  ",
355 "ooooooooo aaa   ",
356 "ooooo     aaa   ",
357 "oo ooo          ",
358 "o  ooo    aaa   ",
359 "    ooo   aaa   ",
360 "    ooo         ",
361 "     ooo        ",
362 "     ooo        "};
363 
364 class QWhatsThisPrivate : public QObject
365 {
366  public:
367     QWhatsThisPrivate();
368     ~QWhatsThisPrivate();
369     static QWhatsThisPrivate *instance;
370     bool eventFilter(QObject *, QEvent *) override;
371 #if QT_CONFIG(action)
372     QPointer<QAction> action;
373 #endif // QT_CONFIG(action)
374     static void say(QWidget *, const QString &, int x = 0, int y = 0);
375     static void notifyToplevels(QEvent *e);
376     bool leaveOnMouseRelease;
377 };
378 
notifyToplevels(QEvent * e)379 void QWhatsThisPrivate::notifyToplevels(QEvent *e)
380 {
381     const QWidgetList toplevels = QApplication::topLevelWidgets();
382     for (auto *w : toplevels)
383         QCoreApplication::sendEvent(w, e);
384 }
385 
386 QWhatsThisPrivate *QWhatsThisPrivate::instance = nullptr;
387 
QWhatsThisPrivate()388 QWhatsThisPrivate::QWhatsThisPrivate()
389     : leaveOnMouseRelease(false)
390 {
391     instance = this;
392     qApp->installEventFilter(this);
393 
394     QPoint pos = QCursor::pos();
395     if (QWidget *w = QApplication::widgetAt(pos)) {
396         QHelpEvent e(QEvent::QueryWhatsThis, w->mapFromGlobal(pos), pos);
397         const bool sentEvent = QCoreApplication::sendEvent(w, &e);
398 #ifdef QT_NO_CURSOR
399         Q_UNUSED(sentEvent);
400 #else
401         QGuiApplication::setOverrideCursor((!sentEvent || !e.isAccepted())?
402                                         Qt::ForbiddenCursor:Qt::WhatsThisCursor);
403     } else {
404         QGuiApplication::setOverrideCursor(Qt::WhatsThisCursor);
405 #endif
406     }
407 #ifndef QT_NO_ACCESSIBILITY
408     QAccessibleEvent event(this, QAccessible::ContextHelpStart);
409     QAccessible::updateAccessibility(&event);
410 #endif
411 }
412 
~QWhatsThisPrivate()413 QWhatsThisPrivate::~QWhatsThisPrivate()
414 {
415 #if QT_CONFIG(action)
416     if (action)
417         action->setChecked(false);
418 #endif // QT_CONFIG(action)
419 #ifndef QT_NO_CURSOR
420     QGuiApplication::restoreOverrideCursor();
421 #endif
422 #ifndef QT_NO_ACCESSIBILITY
423     QAccessibleEvent event(this, QAccessible::ContextHelpEnd);
424     QAccessible::updateAccessibility(&event);
425 #endif
426     instance = nullptr;
427 }
428 
eventFilter(QObject * o,QEvent * e)429 bool QWhatsThisPrivate::eventFilter(QObject *o, QEvent *e)
430 {
431     if (!o->isWidgetType())
432         return false;
433     QWidget * w = static_cast<QWidget *>(o);
434     bool customWhatsThis = w->testAttribute(Qt::WA_CustomWhatsThis);
435     switch (e->type()) {
436     case QEvent::MouseButtonPress:
437     {
438         QMouseEvent *me = static_cast<QMouseEvent*>(e);
439         if (me->button() == Qt::RightButton || customWhatsThis)
440             return false;
441         QHelpEvent e(QEvent::WhatsThis, me->pos(), me->globalPos());
442         if (!QCoreApplication::sendEvent(w, &e) || !e.isAccepted())
443             leaveOnMouseRelease = true;
444 
445     } break;
446 
447     case QEvent::MouseMove:
448     {
449         QMouseEvent *me = static_cast<QMouseEvent*>(e);
450         QHelpEvent e(QEvent::QueryWhatsThis, me->pos(), me->globalPos());
451         const bool sentEvent = QCoreApplication::sendEvent(w, &e);
452 #ifdef QT_NO_CURSOR
453         Q_UNUSED(sentEvent);
454 #else
455         QGuiApplication::changeOverrideCursor((!sentEvent || !e.isAccepted())?
456                                               Qt::ForbiddenCursor:Qt::WhatsThisCursor);
457 #endif
458         Q_FALLTHROUGH();
459     }
460     case QEvent::MouseButtonRelease:
461     case QEvent::MouseButtonDblClick:
462         if (leaveOnMouseRelease && e->type() == QEvent::MouseButtonRelease)
463             QWhatsThis::leaveWhatsThisMode();
464         if (static_cast<QMouseEvent*>(e)->button() == Qt::RightButton || customWhatsThis)
465             return false; // ignore RMB release
466         break;
467     case QEvent::KeyPress:
468     {
469         QKeyEvent* kev = (QKeyEvent*)e;
470 #if QT_CONFIG(shortcut)
471         if (kev->matches(QKeySequence::Cancel)) {
472             QWhatsThis::leaveWhatsThisMode();
473             return true;
474         } else
475 #endif
476           if (customWhatsThis) {
477             return false;
478         } else if (kev->key() == Qt::Key_Menu ||
479                     (kev->key() == Qt::Key_F10 &&
480                       kev->modifiers() == Qt::ShiftModifier)) {
481             // we don't react to these keys, they are used for context menus
482             return false;
483         } else if (kev->key() != Qt::Key_Shift && kev->key() != Qt::Key_Alt // not a modifier key
484                    && kev->key() != Qt::Key_Control && kev->key() != Qt::Key_Meta) {
485             QWhatsThis::leaveWhatsThisMode();
486         }
487     } break;
488     default:
489         return false;
490     }
491     return true;
492 }
493 
494 #if QT_CONFIG(action)
495 class QWhatsThisAction: public QAction
496 {
497     Q_OBJECT
498 
499 public:
500     explicit QWhatsThisAction(QObject* parent = nullptr);
501 
502 private slots:
503     void actionTriggered();
504 };
505 
QWhatsThisAction(QObject * parent)506 QWhatsThisAction::QWhatsThisAction(QObject *parent) : QAction(tr("What's This?"), parent)
507 {
508 #ifndef QT_NO_IMAGEFORMAT_XPM
509     QPixmap p(button_image);
510     setIcon(p);
511 #endif
512     setCheckable(true);
513     connect(this, SIGNAL(triggered()), this, SLOT(actionTriggered()));
514 #ifndef QT_NO_SHORTCUT
515     setShortcut(Qt::ShiftModifier + Qt::Key_F1);
516 #endif
517 }
518 
actionTriggered()519 void QWhatsThisAction::actionTriggered()
520 {
521     if (isChecked()) {
522         QWhatsThis::enterWhatsThisMode();
523         QWhatsThisPrivate::instance->action = this;
524     }
525 }
526 #endif // QT_CONFIG(action)
527 
528 /*!
529     This function switches the user interface into "What's This?"
530     mode. The user interface can be switched back into normal mode by
531     the user (e.g. by them clicking or pressing Esc), or
532     programmatically by calling leaveWhatsThisMode().
533 
534     When entering "What's This?" mode, a QEvent of type
535     Qt::EnterWhatsThisMode is sent to all toplevel widgets.
536 
537     \sa inWhatsThisMode(), leaveWhatsThisMode()
538 */
enterWhatsThisMode()539 void QWhatsThis::enterWhatsThisMode()
540 {
541     if (QWhatsThisPrivate::instance)
542         return;
543     (void) new QWhatsThisPrivate;
544     QEvent e(QEvent::EnterWhatsThisMode);
545     QWhatsThisPrivate::notifyToplevels(&e);
546  }
547 
548 /*!
549     Returns \c true if the user interface is in "What's This?" mode;
550     otherwise returns \c false.
551 
552     \sa enterWhatsThisMode()
553 */
inWhatsThisMode()554 bool QWhatsThis::inWhatsThisMode()
555 {
556     return (QWhatsThisPrivate::instance != nullptr);
557 }
558 
559 /*!
560     If the user interface is in "What's This?" mode, this function
561     switches back to normal mode; otherwise it does nothing.
562 
563     When leaving "What's This?" mode, a QEvent of type
564     Qt::LeaveWhatsThisMode is sent to all toplevel widgets.
565 
566     \sa enterWhatsThisMode(), inWhatsThisMode()
567 */
leaveWhatsThisMode()568 void QWhatsThis::leaveWhatsThisMode()
569 {
570     delete QWhatsThisPrivate::instance;
571     QEvent e(QEvent::LeaveWhatsThisMode);
572     QWhatsThisPrivate::notifyToplevels(&e);
573 }
574 
say(QWidget * widget,const QString & text,int x,int y)575 void QWhatsThisPrivate::say(QWidget * widget, const QString &text, int x, int y)
576 {
577     if (text.size() == 0)
578         return;
579     // make a fresh widget, and set it up
580     QWhatsThat *whatsThat = new QWhatsThat(text, nullptr, widget);
581 
582     // okay, now to find a suitable location
583     int scr = (widget ?
584                 QDesktopWidgetPrivate::screenNumber(widget) :
585                 QDesktopWidgetPrivate::screenNumber(QPoint(x,y))
586                );
587     QRect screen = QDesktopWidgetPrivate::screenGeometry(scr);
588 
589     int w = whatsThat->width();
590     int h = whatsThat->height();
591     int sx = screen.x();
592     int sy = screen.y();
593 
594     // first try locating the widget immediately above/below,
595     // with nice alignment if possible.
596     QPoint pos;
597     if (widget)
598         pos = widget->mapToGlobal(QPoint(0,0));
599 
600     if (widget && w > widget->width() + 16)
601         x = pos.x() + widget->width()/2 - w/2;
602     else
603         x = x - w/2;
604 
605         // squeeze it in if that would result in part of what's this
606         // being only partially visible
607     if (x + w  + shadowWidth > sx+screen.width())
608         x = (widget? (qMin(screen.width(),
609                            pos.x() + widget->width())
610                      ) : screen.width())
611             - w;
612 
613     if (x < sx)
614         x = sx;
615 
616     if (widget && h > widget->height() + 16) {
617         y = pos.y() + widget->height() + 2; // below, two pixels spacing
618         // what's this is above or below, wherever there's most space
619         if (y + h + 10 > sy+screen.height())
620             y = pos.y() + 2 - shadowWidth - h; // above, overlap
621     }
622     y = y + 2;
623 
624         // squeeze it in if that would result in part of what's this
625         // being only partially visible
626     if (y + h + shadowWidth > sy+screen.height())
627         y = (widget ? (qMin(screen.height(),
628                              pos.y() + widget->height())
629                        ) : screen.height())
630             - h;
631     if (y < sy)
632         y = sy;
633 
634     whatsThat->move(x, y);
635     whatsThat->show();
636     whatsThat->grabKeyboard();
637 }
638 
639 /*!
640     Shows \a text as a "What's This?" window, at global position \a
641     pos. The optional widget argument, \a w, is used to determine the
642     appropriate screen on multi-head systems.
643 
644     \sa hideText()
645 */
showText(const QPoint & pos,const QString & text,QWidget * w)646 void QWhatsThis::showText(const QPoint &pos, const QString &text, QWidget *w)
647 {
648     leaveWhatsThisMode();
649     QWhatsThisPrivate::say(w, text, pos.x(), pos.y());
650 }
651 
652 /*!
653     If a "What's This?" window is showing, this destroys it.
654 
655     \sa showText()
656 */
hideText()657 void QWhatsThis::hideText()
658 {
659     qDeleteInEventHandler(QWhatsThat::instance);
660 }
661 
662 /*!
663     Returns a ready-made QAction, used to invoke "What's This?" context
664     help, with the given \a parent.
665 
666     The returned QAction provides a convenient way to let users enter
667     "What's This?" mode.
668 */
669 #if QT_CONFIG(action)
createAction(QObject * parent)670 QAction *QWhatsThis::createAction(QObject *parent)
671 {
672     return new QWhatsThisAction(parent);
673 }
674 #endif // QT_CONFIG(action)
675 
676 QT_END_NAMESPACE
677 
678 #include "qwhatsthis.moc"
679