summaryrefslogtreecommitdiffstats
path: root/src/widgets/qwhatsthis.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/qwhatsthis.cpp')
-rw-r--r--src/widgets/qwhatsthis.cpp1001
1 files changed, 1001 insertions, 0 deletions
diff --git a/src/widgets/qwhatsthis.cpp b/src/widgets/qwhatsthis.cpp
new file mode 100644
index 0000000..c6e8f04
--- /dev/null
+++ b/src/widgets/qwhatsthis.cpp
@@ -0,0 +1,1001 @@
+/****************************************************************************
+**
+** Implementation of QWhatsThis class
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qwhatsthis.h"
+#ifndef QT_NO_WHATSTHIS
+#include "qapplication.h"
+#include "qpaintdevicemetrics.h"
+#include "qpixmap.h"
+#include "qpainter.h"
+#include "qtimer.h"
+#include "qptrdict.h"
+#include "qtoolbutton.h"
+#include "qshared.h"
+#include "qcursor.h"
+#include "qbitmap.h"
+#include "qtooltip.h"
+#include "qsimplerichtext.h"
+#include "qstylesheet.h"
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+#if defined(Q_WS_WIN)
+#include "qt_windows.h"
+#ifndef SPI_GETDROPSHADOW
+#define SPI_GETDROPSHADOW 0x1024
+#endif
+#endif
+
+/*!
+ \class QWhatsThis qwhatsthis.h
+ \brief The QWhatsThis class provides a simple description of any
+ widget, i.e. answering the question "What's this?".
+
+ \ingroup helpsystem
+ \mainclass
+
+ "What's this?" help is part of an application's online help system
+ that provides users with information about functionality, usage,
+ background etc., in various levels of detail from short tool tips
+ to full text browsing help windows.
+
+ QWhatsThis provides a single window with an explanatory text that
+ pops up when the user asks "What's this?". The default way to do
+ this is to focus the relevant widget and press Shift+F1. The help
+ text appears immediately; it goes away as soon as the user does
+ something else.
+
+ (Note that if there is an accelerator for Shift+F1, this mechanism
+ will not work.)
+
+ To add "What's this?" text to a widget you simply call
+ QWhatsThis::add() for the widget. For example, to assign text to a
+ menu item, call QMenuData::setWhatsThis(); for a global
+ accelerator key, call QAccel::setWhatsThis() and If you're using
+ actions, use QAction::setWhatsThis().
+
+ The text can be either rich text or plain text. If you specify a
+ rich text formatted string, it will be rendered using the default
+ stylesheet. This makes it possible to embed images. See
+ QStyleSheet::defaultSheet() for details.
+
+ \quotefile action/application.cpp
+ \skipto fileOpenText
+ \printuntil setWhatsThis
+
+ An alternative way to enter "What's this?" mode is to use the
+ ready-made tool bar tool button from
+ QWhatsThis::whatsThisButton(). By invoking this context help
+ button (in the picture below the first one from the right) the
+ user switches into "What's this?" mode. If they now click on a
+ widget the appropriate help text is shown. The mode is left when
+ help is given or when the user presses Esc.
+
+ \img whatsthis.png
+
+ If you are using QMainWindow you can also use the
+ QMainWindow::whatsThis() slot to invoke the mode from a menu item.
+
+ For more control you can create a dedicated QWhatsThis object for
+ a special widget. By subclassing and reimplementing
+ QWhatsThis::text() it is possible to have different help texts,
+ depending on the position of the mouse click. By reimplementing
+ QWhatsThis::clicked() it is possible to have hyperlinks inside the
+ help texts.
+
+ If you wish to control the "What's this?" behavior of a widget
+ manually see QWidget::customWhatsThis().
+
+ The What's This object can be removed using QWhatsThis::remove(),
+ although this is rarely necessary because it is automatically
+ removed when the widget is destroyed.
+
+ \sa QToolTip
+*/
+
+// a special button
+class QWhatsThisButton: public QToolButton
+{
+ Q_OBJECT
+
+public:
+ QWhatsThisButton( QWidget * parent, const char * name );
+ ~QWhatsThisButton();
+
+public slots:
+ void mouseReleased();
+
+};
+
+
+class QWhatsThat : public QWidget
+{
+ Q_OBJECT
+public:
+ QWhatsThat( QWidget* w, const QString& txt, QWidget* parent, const char* name );
+ ~QWhatsThat() ;
+
+public slots:
+ void hide();
+ inline void widgetDestroyed() { widget = 0; }
+
+protected:
+ void mousePressEvent( QMouseEvent* );
+ void mouseReleaseEvent( QMouseEvent* );
+ void mouseMoveEvent( QMouseEvent* );
+ void keyPressEvent( QKeyEvent* );
+ void paintEvent( QPaintEvent* );
+
+private:
+ QString text;
+#ifndef QT_NO_RICHTEXT
+ QSimpleRichText* doc;
+#endif
+ QString anchor;
+ bool pressed;
+ QWidget* widget;
+};
+
+
+class QWhatsThisPrivate: public QObject
+{
+ Q_OBJECT
+public:
+
+ // an item for storing texts
+ struct WhatsThisItem: public QShared
+ {
+ WhatsThisItem(): QShared() { whatsthis = 0; }
+ ~WhatsThisItem();
+ QString s;
+ QWhatsThis* whatsthis;
+ };
+
+ // the (these days pretty small) state machine
+ enum State { Inactive, Waiting };
+
+ QWhatsThisPrivate();
+ ~QWhatsThisPrivate();
+
+ bool eventFilter( QObject *, QEvent * );
+
+ WhatsThisItem* newItem( QWidget * widget );
+ void add( QWidget * widget, QWhatsThis* special );
+ void add( QWidget * widget, const QString& text );
+
+ // say it.
+ void say( QWidget *, const QString&, const QPoint& );
+
+ // setup and teardown
+ static void setUpWhatsThis();
+
+ void enterWhatsThisMode();
+ void leaveWhatsThisMode();
+
+ // variables
+ QWhatsThat * whatsThat;
+ QPtrDict<WhatsThisItem> * dict;
+ QPtrDict<QWidget> * tlw;
+ QPtrDict<QWhatsThisButton> * buttons;
+ State state;
+
+private slots:
+ void cleanupWidget()
+ {
+ const QObject* o = sender();
+ if ( o->isWidgetType() ) // sanity
+ QWhatsThis::remove((QWidget*)o);
+ }
+
+};
+
+// static, but static the less-typing way
+static QWhatsThisPrivate * wt = 0;
+
+// shadowWidth not const, for XP drop-shadow-fu turns it to 0
+static int shadowWidth = 6; // also used as '5' and '6' and even '8' below
+const int vMargin = 8;
+const int hMargin = 12;
+
+// Lets QPopupMenu destroy the QWhatsThat.
+void qWhatsThisBDH()
+{
+ if ( wt && wt->whatsThat )
+ wt->whatsThat->hide();
+}
+
+
+QWhatsThat::QWhatsThat( QWidget* w, const QString& txt, QWidget* parent, const char* name )
+ : QWidget( parent, name, WType_Popup ), text( txt ), pressed( FALSE ), widget( w )
+{
+
+ setBackgroundMode( NoBackground );
+ setPalette( QToolTip::palette() );
+ setMouseTracking( TRUE );
+#ifndef QT_NO_CURSOR
+ setCursor( arrowCursor );
+#endif
+
+ if ( widget )
+ connect( widget, SIGNAL( destroyed() ), this, SLOT( widgetDestroyed() ) );
+
+
+ QRect r;
+#ifndef QT_NO_RICHTEXT
+ doc = 0;
+ if ( QStyleSheet::mightBeRichText( text ) ) {
+ QFont f = QApplication::font( this );
+ doc = new QSimpleRichText( text, f );
+ doc->adjustSize();
+ r.setRect( 0, 0, doc->width(), doc->height() );
+ }
+ else
+#endif
+ {
+ int sw = QApplication::desktop()->width() / 3;
+ if ( sw < 200 )
+ sw = 200;
+ else if ( sw > 300 )
+ sw = 300;
+
+ r = fontMetrics().boundingRect( 0, 0, sw, 1000,
+ AlignAuto + AlignTop + WordBreak + ExpandTabs,
+ text );
+ }
+#if defined(Q_WS_WIN)
+ if ( (qWinVersion()&WV_NT_based) > WV_2000 ) {
+ BOOL shadow;
+ SystemParametersInfo( SPI_GETDROPSHADOW, 0, &shadow, 0 );
+ shadowWidth = shadow ? 0 : 6;
+ }
+#endif
+ resize( r.width() + 2*hMargin + shadowWidth, r.height() + 2*vMargin + shadowWidth );
+}
+
+QWhatsThat::~QWhatsThat()
+{
+ if ( wt && wt->whatsThat == this )
+ wt->whatsThat = 0;
+#ifndef QT_NO_RICHTEXT
+ if ( doc )
+ delete doc;
+#endif
+}
+
+void QWhatsThat::hide()
+{
+ QWidget::hide();
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ContextHelpEnd );
+#endif
+}
+
+void QWhatsThat::mousePressEvent( QMouseEvent* e )
+{
+ pressed = TRUE;
+ if ( e->button() == LeftButton && rect().contains( e->pos() ) ) {
+#ifndef QT_NO_RICHTEXT
+ if ( doc )
+ anchor = doc->anchorAt( e->pos() - QPoint( hMargin, vMargin) );
+#endif
+ return;
+ }
+ hide();
+}
+
+void QWhatsThat::mouseReleaseEvent( QMouseEvent* e )
+{
+ if ( !pressed )
+ return;
+#ifndef QT_NO_RICHTEXT
+ if ( e->button() == LeftButton && doc && rect().contains( e->pos() ) ) {
+ QString a = doc->anchorAt( e->pos() - QPoint( hMargin, vMargin ) );
+ QString href;
+ if ( anchor == a )
+ href = a;
+ anchor = QString::null;
+ if ( widget && wt && wt->dict ) {
+ QWhatsThisPrivate::WhatsThisItem * i = wt->dict->find( widget );
+ if ( i && i->whatsthis && !i->whatsthis->clicked( href ) )
+ return;
+ }
+ }
+#endif
+ hide();
+}
+
+void QWhatsThat::mouseMoveEvent( QMouseEvent* e)
+{
+#ifndef QT_NO_RICHTEXT
+#ifndef QT_NO_CURSOR
+ if ( !doc )
+ return;
+ QString a = doc->anchorAt( e->pos() - QPoint( hMargin, vMargin ) );
+ if ( !a.isEmpty() )
+ setCursor( pointingHandCursor );
+ else
+ setCursor( arrowCursor );
+#endif
+#endif
+}
+
+
+void QWhatsThat::keyPressEvent( QKeyEvent* )
+{
+ hide();
+}
+
+
+
+void QWhatsThat::paintEvent( QPaintEvent* )
+{
+ bool drawShadow = TRUE;
+#if defined(Q_WS_WIN)
+ if ( (qWinVersion()&WV_NT_based) > WV_2000 ) {
+ BOOL shadow;
+ SystemParametersInfo( SPI_GETDROPSHADOW, 0, &shadow, 0 );
+ drawShadow = !shadow;
+ }
+#elif defined(Q_WS_MACX)
+ drawShadow = FALSE; //never draw it on OS X we get it for free
+#endif
+
+ QRect r = rect();
+ if ( drawShadow )
+ r.addCoords( 0, 0, -shadowWidth, -shadowWidth );
+ QPainter p( this);
+ p.setPen( colorGroup().foreground() );
+ p.drawRect( r );
+ p.setPen( colorGroup().mid() );
+ p.setBrush( colorGroup().brush( QColorGroup::Background ) );
+ int w = r.width();
+ int h = r.height();
+ p.drawRect( 1, 1, w-2, h-2 );
+ if ( drawShadow ) {
+ p.setPen( colorGroup().shadow() );
+ p.drawPoint( w + 5, 6 );
+ p.drawLine( w + 3, 6, w + 5, 8 );
+ p.drawLine( w + 1, 6, w + 5, 10 );
+ int i;
+ for( i=7; i < h; i += 2 )
+ p.drawLine( w, i, w + 5, i + 5 );
+ for( i = w - i + h; i > 6; i -= 2 )
+ p.drawLine( i, h, i + 5, h + 5 );
+ for( ; i > 0 ; i -= 2 )
+ p.drawLine( 6, h + 6 - i, i + 5, h + 5 );
+ }
+ p.setPen( colorGroup().foreground() );
+ r.addCoords( hMargin, vMargin, -hMargin, -vMargin );
+
+#ifndef QT_NO_RICHTEXT
+ if ( doc ) {
+ doc->draw( &p, r.x(), r.y(), r, colorGroup(), 0 );
+ }
+ else
+#endif
+ {
+ p.drawText( r, AlignAuto + AlignTop + WordBreak + ExpandTabs, text );
+ }
+}
+
+// the item
+QWhatsThisPrivate::WhatsThisItem::~WhatsThisItem()
+{
+ if ( count )
+ qFatal( "QWhatsThis: Internal error (%d)", count );
+ delete whatsthis;
+}
+
+
+static const char * const button_image[] = {
+"16 16 3 1",
+" c None",
+"o c #000000",
+"a c #000080",
+"o aaaaa ",
+"oo aaa aaa ",
+"ooo aaa aaa",
+"oooo aa aa",
+"ooooo aa aa",
+"oooooo a aaa",
+"ooooooo aaa ",
+"oooooooo aaa ",
+"ooooooooo aaa ",
+"ooooo aaa ",
+"oo ooo ",
+"o ooo aaa ",
+" ooo aaa ",
+" ooo ",
+" ooo ",
+" ooo "};
+
+// the button class
+QWhatsThisButton::QWhatsThisButton( QWidget * parent, const char * name )
+ : QToolButton( parent, name )
+{
+ QPixmap p( (const char**)button_image );
+ setPixmap( p );
+ setToggleButton( TRUE );
+ setAutoRaise( TRUE );
+ setFocusPolicy( NoFocus );
+ setTextLabel( tr( "What's this?" ) );
+ wt->buttons->insert( (void *)this, this );
+ connect( this, SIGNAL( released() ),
+ this, SLOT( mouseReleased() ) );
+}
+
+
+QWhatsThisButton::~QWhatsThisButton()
+{
+ if ( wt && wt->buttons )
+ wt->buttons->take( (void *)this );
+}
+
+
+void QWhatsThisButton::mouseReleased()
+{
+ if ( wt->state == QWhatsThisPrivate::Inactive && isOn() ) {
+ QWhatsThisPrivate::setUpWhatsThis();
+#ifndef QT_NO_CURSOR
+ QApplication::setOverrideCursor( whatsThisCursor, FALSE );
+#endif
+ wt->state = QWhatsThisPrivate::Waiting;
+ qApp->installEventFilter( wt );
+ }
+}
+
+static void qWhatsThisPrivateCleanup()
+{
+ if( wt ) {
+ delete wt;
+ wt = 0;
+ }
+}
+
+// the what's this manager class
+QWhatsThisPrivate::QWhatsThisPrivate()
+ : QObject( 0, "global what's this object" )
+{
+ whatsThat = 0;
+ dict = new QPtrDict<QWhatsThisPrivate::WhatsThisItem>;
+ tlw = new QPtrDict<QWidget>;
+ wt = this;
+ buttons = new QPtrDict<QWhatsThisButton>;
+ state = Inactive;
+}
+
+QWhatsThisPrivate::~QWhatsThisPrivate()
+{
+#ifndef QT_NO_CURSOR
+ if ( state == Waiting && qApp )
+ QApplication::restoreOverrideCursor();
+#endif
+ // the two straight-and-simple dicts
+ delete tlw;
+ delete buttons;
+
+ // then delete the complex one.
+ QPtrDictIterator<WhatsThisItem> it( *dict );
+ WhatsThisItem * i;
+ QWidget * w;
+ while( (i=it.current()) != 0 ) {
+ w = (QWidget *)it.currentKey();
+ ++it;
+ dict->take( w );
+ if ( i->deref() )
+ delete i;
+ }
+ delete dict;
+ if ( whatsThat && !whatsThat->parentWidget() ) {
+ delete whatsThat;
+ }
+ // and finally lose wt
+ wt = 0;
+}
+
+bool QWhatsThisPrivate::eventFilter( QObject * o, QEvent * e )
+{
+ switch( state ) {
+ case Waiting:
+ if ( e->type() == QEvent::MouseButtonPress && o->isWidgetType() ) {
+ QWidget * w = (QWidget *) o;
+ if ( ( (QMouseEvent*)e)->button() == RightButton )
+ return FALSE; // ignore RMB
+ if ( w->customWhatsThis() )
+ return FALSE;
+ QWhatsThisPrivate::WhatsThisItem * i = 0;
+ QMouseEvent* me = (QMouseEvent*) e;
+ QPoint p = me->pos();
+ while( w && !i ) {
+ i = dict->find( w );
+ if ( !i ) {
+ p += w->pos();
+ w = w->parentWidget( TRUE );
+ }
+ }
+ leaveWhatsThisMode();
+ if (!i ) {
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ContextHelpEnd );
+#endif
+ return TRUE;
+ }
+ if ( i->whatsthis )
+ say( w, i->whatsthis->text( p ), me->globalPos() );
+ else
+ say( w, i->s, me->globalPos() );
+ return TRUE;
+ } else if ( e->type() == QEvent::MouseButtonRelease ) {
+ if ( ( (QMouseEvent*)e)->button() == RightButton )
+ return FALSE; // ignore RMB
+ return !o->isWidgetType() || !((QWidget*)o)->customWhatsThis();
+ } else if ( e->type() == QEvent::MouseMove ) {
+ return !o->isWidgetType() || !((QWidget*)o)->customWhatsThis();
+ } else if ( e->type() == QEvent::KeyPress ) {
+ QKeyEvent* kev = (QKeyEvent*)e;
+
+ if ( kev->key() == Qt::Key_Escape ) {
+ leaveWhatsThisMode();
+ return TRUE;
+ } else if ( o->isWidgetType() && ((QWidget*)o)->customWhatsThis() ) {
+ return FALSE;
+ } else if ( kev->key() == Key_Menu ||
+ ( kev->key() == Key_F10 &&
+ kev->state() == ShiftButton ) ) {
+ // we don't react to these keys, they are used for context menus
+ return FALSE;
+ } else if ( kev->state() == kev->stateAfter() &&
+ kev->key() != Key_Meta ) { // not a modifier key
+ leaveWhatsThisMode();
+ }
+ } else if ( e->type() == QEvent::MouseButtonDblClick ) {
+ return TRUE;
+ }
+ break;
+ case Inactive:
+ if ( e->type() == QEvent::Accel &&
+ ((QKeyEvent *)e)->key() == Key_F1 &&
+ o->isWidgetType() &&
+ ((QKeyEvent *)e)->state() == ShiftButton ) {
+ QWidget * w = ((QWidget *)o)->focusWidget();
+ if ( !w )
+ break;
+ QString s = QWhatsThis::textFor( w, QPoint(0,0), TRUE );
+ if ( !s.isNull() ) {
+ say ( w, s, w->mapToGlobal( w->rect().center() ) );
+ ((QKeyEvent *)e)->accept();
+ return TRUE;
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+
+
+void QWhatsThisPrivate::setUpWhatsThis()
+{
+ if ( !wt ) {
+ wt = new QWhatsThisPrivate();
+
+ // It is necessary to use a post routine, because
+ // the destructor deletes pixmaps and other stuff that
+ // needs a working X connection under X11.
+ qAddPostRoutine( qWhatsThisPrivateCleanup );
+ }
+}
+
+
+void QWhatsThisPrivate::enterWhatsThisMode()
+{
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ContextHelpStart );
+#endif
+}
+
+
+void QWhatsThisPrivate::leaveWhatsThisMode()
+{
+ if ( state == Waiting ) {
+ QPtrDictIterator<QWhatsThisButton> it( *(wt->buttons) );
+ QWhatsThisButton * b;
+ while( (b=it.current()) != 0 ) {
+ ++it;
+ b->setOn( FALSE );
+ }
+#ifndef QT_NO_CURSOR
+ QApplication::restoreOverrideCursor();
+#endif
+ state = Inactive;
+ qApp->removeEventFilter( this );
+ }
+}
+
+
+
+void QWhatsThisPrivate::say( QWidget * widget, const QString &text, const QPoint& ppos)
+{
+ if ( text.isEmpty() )
+ return;
+ // make a fresh widget, and set it up
+ delete whatsThat;
+ whatsThat = new QWhatsThat(
+ widget, text,
+#if defined(Q_WS_X11)
+ QApplication::desktop()->screen( widget ?
+ widget->x11Screen() :
+ QCursor::x11Screen() ),
+#else
+ 0,
+#endif
+ "automatic what's this? widget" );
+
+
+ // okay, now to find a suitable location
+
+ int scr = ( widget ?
+ QApplication::desktop()->screenNumber( widget ) :
+#if defined(Q_WS_X11)
+ QCursor::x11Screen()
+#else
+ QApplication::desktop()->screenNumber( ppos )
+#endif // Q_WS_X11
+ );
+ QRect screen = QApplication::desktop()->screenGeometry( scr );
+
+ int x;
+ int w = whatsThat->width();
+ int h = whatsThat->height();
+ int sx = screen.x();
+ int sy = screen.y();
+
+ // first try locating the widget immediately above/below,
+ // with nice alignment if possible.
+ QPoint pos;
+ if ( widget )
+ pos = widget->mapToGlobal( QPoint( 0,0 ) );
+
+ if ( widget && w > widget->width() + 16 )
+ x = pos.x() + widget->width()/2 - w/2;
+ else
+ x = ppos.x() - w/2;
+
+ // squeeze it in if that would result in part of what's this
+ // being only partially visible
+ if ( x + w + shadowWidth > sx+screen.width() )
+ x = (widget? (QMIN(screen.width(),
+ pos.x() + widget->width())
+ ) : screen.width() )
+ - w;
+
+ if ( x < sx )
+ x = sx;
+
+ int y;
+ if ( widget && h > widget->height() + 16 ) {
+ y = pos.y() + widget->height() + 2; // below, two pixels spacing
+ // what's this is above or below, wherever there's most space
+ if ( y + h + 10 > sy+screen.height() )
+ y = pos.y() + 2 - shadowWidth - h; // above, overlap
+ }
+ y = ppos.y() + 2;
+
+ // squeeze it in if that would result in part of what's this
+ // being only partially visible
+ if ( y + h + shadowWidth > sy+screen.height() )
+ y = ( widget ? (QMIN(screen.height(),
+ pos.y() + widget->height())
+ ) : screen.height() )
+ - h;
+ if ( y < sy )
+ y = sy;
+
+ whatsThat->move( x, y );
+ whatsThat->show();
+}
+
+QWhatsThisPrivate::WhatsThisItem* QWhatsThisPrivate::newItem( QWidget * widget )
+{
+ WhatsThisItem * i = dict->find( (void *)widget );
+ if ( i )
+ QWhatsThis::remove( widget );
+ i = new WhatsThisItem;
+ dict->insert( (void *)widget, i );
+ QWidget * t = widget->topLevelWidget();
+ if ( !tlw->find( (void *)t ) ) {
+ tlw->insert( (void *)t, t );
+ t->installEventFilter( this );
+ }
+ connect( widget, SIGNAL(destroyed()), this, SLOT(cleanupWidget()) );
+ return i;
+}
+
+void QWhatsThisPrivate::add( QWidget * widget, QWhatsThis* special )
+{
+ newItem( widget )->whatsthis = special;
+}
+
+void QWhatsThisPrivate::add( QWidget * widget, const QString &text )
+{
+ newItem( widget )->s = text;
+}
+
+
+// and finally the What's This class itself
+
+/*!
+ Adds \a text as "What's this" help for \a widget. If the text is
+ rich text formatted (i.e. it contains markup) it will be rendered
+ with the default stylesheet QStyleSheet::defaultSheet().
+
+ The text is destroyed if the widget is later destroyed, so it need
+ not be explicitly removed.
+
+ \sa remove()
+*/
+void QWhatsThis::add( QWidget * widget, const QString &text )
+{
+ if ( text.isEmpty() )
+ return; // pointless
+ QWhatsThisPrivate::setUpWhatsThis();
+ wt->add(widget,text);
+}
+
+
+/*!
+ Removes the "What's this?" help associated with the \a widget.
+ This happens automatically if the widget is destroyed.
+
+ \sa add()
+*/
+void QWhatsThis::remove( QWidget * widget )
+{
+ QWhatsThisPrivate::setUpWhatsThis();
+ QWhatsThisPrivate::WhatsThisItem * i = wt->dict->find( (void *)widget );
+ if ( !i )
+ return;
+
+ wt->dict->take( (void *)widget );
+
+ i->deref();
+ if ( !i->count )
+ delete i;
+}
+
+
+/*!
+ Returns the what's this text for widget \a w or QString::null if
+ there is no "What's this?" help for the widget. \a pos contains
+ the mouse position; this is useful, for example, if you've
+ subclassed to make the text that is displayed position dependent.
+
+ If \a includeParents is TRUE, parent widgets are taken into
+ consideration as well when looking for what's this help text.
+
+ \sa add()
+*/
+QString QWhatsThis::textFor( QWidget * w, const QPoint& pos, bool includeParents )
+{
+ QWhatsThisPrivate::setUpWhatsThis();
+ QWhatsThisPrivate::WhatsThisItem * i = 0;
+ QPoint p = pos;
+ while( w && !i ) {
+ i = wt->dict->find( w );
+ if ( !includeParents )
+ break;
+ if ( !i ) {
+ p += w->pos();
+ w = w->parentWidget( TRUE );
+ }
+ }
+ if (!i)
+ return QString::null;
+ if ( i->whatsthis )
+ return i->whatsthis->text( p );
+ return i->s;
+}
+
+
+/*!
+ Creates a QToolButton preconfigured to enter "What's this?" mode
+ when clicked. You will often use this with a tool bar as \a
+ parent:
+ \code
+ (void) QWhatsThis::whatsThisButton( my_help_tool_bar );
+ \endcode
+*/
+QToolButton * QWhatsThis::whatsThisButton( QWidget * parent )
+{
+ QWhatsThisPrivate::setUpWhatsThis();
+ return new QWhatsThisButton( parent,
+ "automatic what's this? button" );
+}
+
+/*!
+ Constructs a dynamic "What's this?" object for \a widget. The
+ object is deleted when the \a widget is destroyed.
+
+ When the widget is queried by the user the text() function of this
+ QWhatsThis will be called to provide the appropriate text, rather
+ than using the text assigned by add().
+*/
+QWhatsThis::QWhatsThis( QWidget * widget)
+{
+ QWhatsThisPrivate::setUpWhatsThis();
+ wt->add(widget,this);
+}
+
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+QWhatsThis::~QWhatsThis()
+{
+}
+
+
+/*!
+ This virtual function returns the text for position \e p in the
+ widget that this "What's this?" object documents. If there is no
+ "What's this?" text for the position, QString::null is returned.
+
+ The default implementation returns QString::null.
+*/
+QString QWhatsThis::text( const QPoint & )
+{
+ return QString::null;
+}
+
+/*!
+ \fn bool QWhatsThis::clicked( const QString& href )
+
+ This virtual function is called when the user clicks inside the
+ "What's this?" window. \a href is the link the user clicked on, or
+ QString::null if there was no link.
+
+ If the function returns TRUE (the default), the "What's this?"
+ window is closed, otherwise it remains visible.
+
+ The default implementation ignores \a href and returns TRUE.
+*/
+bool QWhatsThis::clicked( const QString& )
+{
+ return TRUE;
+}
+
+
+/*!
+ Enters "What's this?" mode and returns immediately.
+
+ Qt will install a special cursor and take over mouse input until
+ the user clicks somewhere. It then shows any help available and
+ ends "What's this?" mode. Finally, Qt removes the special cursor
+ and help window and then restores ordinary event processing, at
+ which point the left mouse button is no longer pressed.
+
+ The user can also use the Esc key to leave "What's this?" mode.
+
+ \sa inWhatsThisMode(), leaveWhatsThisMode()
+*/
+
+void QWhatsThis::enterWhatsThisMode()
+{
+ QWhatsThisPrivate::setUpWhatsThis();
+ if ( wt->state == QWhatsThisPrivate::Inactive ) {
+ wt->enterWhatsThisMode();
+#ifndef QT_NO_CURSOR
+ QApplication::setOverrideCursor( whatsThisCursor, FALSE );
+#endif
+ wt->state = QWhatsThisPrivate::Waiting;
+ qApp->installEventFilter( wt );
+ }
+}
+
+
+/*!
+ Returns TRUE if the application is in "What's this?" mode;
+ otherwise returns FALSE.
+
+ \sa enterWhatsThisMode(), leaveWhatsThisMode()
+*/
+bool QWhatsThis::inWhatsThisMode()
+{
+ if (!wt)
+ return FALSE;
+ return wt->state == QWhatsThisPrivate::Waiting;
+}
+
+
+/*!
+ Leaves "What's this?" question mode.
+
+ This function is used internally by widgets that support
+ QWidget::customWhatsThis(); applications do not usually call it.
+ An example of such a widget is QPopupMenu: menus still work
+ normally in "What's this?" mode but also provide help texts for
+ individual menu items.
+
+ If \a text is not QString::null, a "What's this?" help window is
+ displayed at the global screen position \a pos. If widget \a w is
+ not 0 and has its own dedicated QWhatsThis object, this object
+ will receive clicked() messages when the user clicks on hyperlinks
+ inside the help text.
+
+ \sa inWhatsThisMode(), enterWhatsThisMode(), QWhatsThis::clicked()
+*/
+void QWhatsThis::leaveWhatsThisMode( const QString& text, const QPoint& pos, QWidget* w )
+{
+ if ( !inWhatsThisMode() )
+ return;
+
+ wt->leaveWhatsThisMode();
+ if ( !text.isNull() )
+ wt->say( w, text, pos );
+}
+
+/*!
+ Display \a text in a help window at the global screen position \a
+ pos.
+
+ If widget \a w is not 0 and has its own dedicated QWhatsThis
+ object, this object will receive clicked() messages when the user
+ clicks on hyperlinks inside the help text.
+
+ \sa QWhatsThis::clicked()
+*/
+void QWhatsThis::display( const QString& text, const QPoint& pos, QWidget* w )
+{
+ if ( inWhatsThisMode() ) {
+ leaveWhatsThisMode( text, pos, w );
+ return;
+ }
+ QWhatsThisPrivate::setUpWhatsThis();
+ wt->say( w, text, pos );
+}
+
+/*!
+ Sets the font for all "What's this?" helps to \a font.
+*/
+void QWhatsThis::setFont( const QFont &font )
+{
+ QApplication::setFont( font, TRUE, "QWhatsThat" );
+}
+
+#include "qwhatsthis.moc"
+#endif