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