~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/gui/kernel/qwhatsthis.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

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