source: vendor/trolltech/current/src/widgets/qwhatsthis.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 26.7 KB
Line 
1/****************************************************************************
2** $Id: qwhatsthis.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of QWhatsThis class
5**
6** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
7**
8** This file is part of the widgets module of the Qt GUI Toolkit.
9**
10** This file may be distributed under the terms of the Q Public License
11** as defined by Trolltech AS of Norway and appearing in the file
12** LICENSE.QPL included in the packaging of this file.
13**
14** This file may be distributed and/or modified under the terms of the
15** GNU General Public License version 2 as published by the Free Software
16** Foundation and appearing in the file LICENSE.GPL included in the
17** packaging of this file.
18**
19** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
20** licenses may use this file in accordance with the Qt Commercial License
21** Agreement provided with the Software.
22**
23** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
24** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25**
26** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
27** information about Qt Commercial License Agreements.
28** See http://www.trolltech.com/qpl/ for QPL licensing information.
29** See http://www.trolltech.com/gpl/ for GPL licensing information.
30**
31** Contact info@trolltech.com if any conditions of this licensing are
32** not clear to you.
33**
34**********************************************************************/
35
36#include "qwhatsthis.h"
37#ifndef QT_NO_WHATSTHIS
38#include "qapplication.h"
39#include "qpaintdevicemetrics.h"
40#include "qpixmap.h"
41#include "qpainter.h"
42#include "qtimer.h"
43#include "qptrdict.h"
44#include "qtoolbutton.h"
45#include "qshared.h"
46#include "qcursor.h"
47#include "qbitmap.h"
48#include "qtooltip.h"
49#include "qsimplerichtext.h"
50#include "qstylesheet.h"
51#if defined(QT_ACCESSIBILITY_SUPPORT)
52#include "qaccessible.h"
53#endif
54#if defined(Q_WS_WIN)
55#include "qt_windows.h"
56#ifndef SPI_GETDROPSHADOW
57#define SPI_GETDROPSHADOW 0x1024
58#endif
59#endif
60
61/*!
62 \class QWhatsThis qwhatsthis.h
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 system
70 that provides users with information about functionality, usage,
71 background etc., in various levels of detail from short tool tips
72 to full text browsing help windows.
73
74 QWhatsThis provides a single window with an explanatory text that
75 pops up when the user asks "What's this?". The default way to do
76 this is to focus the relevant widget and press Shift+F1. The help
77 text appears immediately; it goes away as soon as the user does
78 something else.
79
80 (Note that if there is an accelerator for Shift+F1, this mechanism
81 will not work.)
82
83 To add "What's this?" text to a widget you simply call
84 QWhatsThis::add() for the widget. For example, to assign text to a
85 menu item, call QMenuData::setWhatsThis(); for a global
86 accelerator key, call QAccel::setWhatsThis() and If you're using
87 actions, use QAction::setWhatsThis().
88
89 The text can be either rich text or plain text. If you specify a
90 rich text formatted string, it will be rendered using the default
91 stylesheet. This makes it possible to embed images. See
92 QStyleSheet::defaultSheet() for details.
93
94 \quotefile action/application.cpp
95 \skipto fileOpenText
96 \printuntil setWhatsThis
97
98 An alternative way to enter "What's this?" mode is to use the
99 ready-made tool bar tool button from
100 QWhatsThis::whatsThisButton(). By invoking this context help
101 button (in the picture below the first one from the right) the
102 user switches into "What's this?" mode. If they now click on a
103 widget the appropriate help text is shown. The mode is left when
104 help is given or when the user presses Esc.
105
106 \img whatsthis.png
107
108 If you are using QMainWindow you can also use the
109 QMainWindow::whatsThis() slot to invoke the mode from a menu item.
110
111 For more control you can create a dedicated QWhatsThis object for
112 a special widget. By subclassing and reimplementing
113 QWhatsThis::text() it is possible to have different help texts,
114 depending on the position of the mouse click. By reimplementing
115 QWhatsThis::clicked() it is possible to have hyperlinks inside the
116 help texts.
117
118 If you wish to control the "What's this?" behavior of a widget
119 manually see QWidget::customWhatsThis().
120
121 The What's This object can be removed using QWhatsThis::remove(),
122 although this is rarely necessary because it is automatically
123 removed when the widget is destroyed.
124
125 \sa QToolTip
126*/
127
128// a special button
129class QWhatsThisButton: public QToolButton
130{
131 Q_OBJECT
132
133public:
134 QWhatsThisButton( QWidget * parent, const char * name );
135 ~QWhatsThisButton();
136
137public slots:
138 void mouseReleased();
139
140};
141
142
143class QWhatsThat : public QWidget
144{
145 Q_OBJECT
146public:
147 QWhatsThat( QWidget* w, const QString& txt, QWidget* parent, const char* name );
148 ~QWhatsThat() ;
149
150public slots:
151 void hide();
152 inline void widgetDestroyed() { widget = 0; }
153
154protected:
155 void mousePressEvent( QMouseEvent* );
156 void mouseReleaseEvent( QMouseEvent* );
157 void mouseMoveEvent( QMouseEvent* );
158 void keyPressEvent( QKeyEvent* );
159 void paintEvent( QPaintEvent* );
160
161private:
162 QString text;
163#ifndef QT_NO_RICHTEXT
164 QSimpleRichText* doc;
165#endif
166 QString anchor;
167 bool pressed;
168 QWidget* widget;
169};
170
171
172class QWhatsThisPrivate: public QObject
173{
174 Q_OBJECT
175public:
176
177 // an item for storing texts
178 struct WhatsThisItem: public QShared
179 {
180 WhatsThisItem(): QShared() { whatsthis = 0; }
181 ~WhatsThisItem();
182 QString s;
183 QWhatsThis* whatsthis;
184 };
185
186 // the (these days pretty small) state machine
187 enum State { Inactive, Waiting };
188
189 QWhatsThisPrivate();
190 ~QWhatsThisPrivate();
191
192 bool eventFilter( QObject *, QEvent * );
193
194 WhatsThisItem* newItem( QWidget * widget );
195 void add( QWidget * widget, QWhatsThis* special );
196 void add( QWidget * widget, const QString& text );
197
198 // say it.
199 void say( QWidget *, const QString&, const QPoint& );
200
201 // setup and teardown
202 static void setUpWhatsThis();
203
204 void enterWhatsThisMode();
205 void leaveWhatsThisMode();
206
207 // variables
208 QWhatsThat * whatsThat;
209 QPtrDict<WhatsThisItem> * dict;
210 QPtrDict<QWidget> * tlw;
211 QPtrDict<QWhatsThisButton> * buttons;
212 State state;
213
214private slots:
215 void cleanupWidget()
216 {
217 const QObject* o = sender();
218 if ( o->isWidgetType() ) // sanity
219 QWhatsThis::remove((QWidget*)o);
220 }
221
222};
223
224// static, but static the less-typing way
225static QWhatsThisPrivate * wt = 0;
226
227// shadowWidth not const, for XP drop-shadow-fu turns it to 0
228int shadowWidth = 6; // also used as '5' and '6' and even '8' below
229const int vMargin = 8;
230const int hMargin = 12;
231
232// Lets QPopupMenu destroy the QWhatsThat.
233void qWhatsThisBDH()
234{
235 if ( wt && wt->whatsThat )
236 wt->whatsThat->hide();
237}
238
239
240QWhatsThat::QWhatsThat( QWidget* w, const QString& txt, QWidget* parent, const char* name )
241 : QWidget( parent, name, WType_Popup ), text( txt ), pressed( FALSE ), widget( w )
242{
243
244 setBackgroundMode( NoBackground );
245 setPalette( QToolTip::palette() );
246 setMouseTracking( TRUE );
247#ifndef QT_NO_CURSOR
248 setCursor( arrowCursor );
249#endif
250
251 if ( widget )
252 connect( widget, SIGNAL( destroyed() ), this, SLOT( widgetDestroyed() ) );
253
254
255 QRect r;
256#ifndef QT_NO_RICHTEXT
257 doc = 0;
258 if ( QStyleSheet::mightBeRichText( text ) ) {
259 QFont f = QApplication::font( this );
260 doc = new QSimpleRichText( text, f );
261 doc->adjustSize();
262 r.setRect( 0, 0, doc->width(), doc->height() );
263 }
264 else
265#endif
266 {
267 int sw = QApplication::desktop()->width() / 3;
268 if ( sw < 200 )
269 sw = 200;
270 else if ( sw > 300 )
271 sw = 300;
272
273 r = fontMetrics().boundingRect( 0, 0, sw, 1000,
274 AlignAuto + AlignTop + WordBreak + ExpandTabs,
275 text );
276 }
277#if defined(Q_WS_WIN)
278 if ( (qWinVersion()&WV_NT_based) > WV_2000 ) {
279 BOOL shadow;
280 SystemParametersInfo( SPI_GETDROPSHADOW, 0, &shadow, 0 );
281 shadowWidth = shadow ? 0 : 6;
282 }
283#endif
284 resize( r.width() + 2*hMargin + shadowWidth, r.height() + 2*vMargin + shadowWidth );
285}
286
287QWhatsThat::~QWhatsThat()
288{
289 if ( wt && wt->whatsThat == this )
290 wt->whatsThat = 0;
291#ifndef QT_NO_RICHTEXT
292 if ( doc )
293 delete doc;
294#endif
295}
296
297void QWhatsThat::hide()
298{
299 QWidget::hide();
300#if defined(QT_ACCESSIBILITY_SUPPORT)
301 QAccessible::updateAccessibility( this, 0, QAccessible::ContextHelpEnd );
302#endif
303}
304
305void QWhatsThat::mousePressEvent( QMouseEvent* e )
306{
307 pressed = TRUE;
308 if ( e->button() == LeftButton && rect().contains( e->pos() ) ) {
309#ifndef QT_NO_RICHTEXT
310 if ( doc )
311 anchor = doc->anchorAt( e->pos() - QPoint( hMargin, vMargin) );
312#endif
313 return;
314 }
315 hide();
316}
317
318void QWhatsThat::mouseReleaseEvent( QMouseEvent* e )
319{
320 if ( !pressed )
321 return;
322#ifndef QT_NO_RICHTEXT
323 if ( e->button() == LeftButton && doc && rect().contains( e->pos() ) ) {
324 QString a = doc->anchorAt( e->pos() - QPoint( hMargin, vMargin ) );
325 QString href;
326 if ( anchor == a )
327 href = a;
328 anchor = QString::null;
329 if ( widget && wt && wt->dict ) {
330 QWhatsThisPrivate::WhatsThisItem * i = wt->dict->find( widget );
331 if ( i && i->whatsthis && !i->whatsthis->clicked( href ) )
332 return;
333 }
334 }
335#endif
336 hide();
337}
338
339void QWhatsThat::mouseMoveEvent( QMouseEvent* e)
340{
341#ifndef QT_NO_RICHTEXT
342#ifndef QT_NO_CURSOR
343 if ( !doc )
344 return;
345 QString a = doc->anchorAt( e->pos() - QPoint( hMargin, vMargin ) );
346 if ( !a.isEmpty() )
347 setCursor( pointingHandCursor );
348 else
349 setCursor( arrowCursor );
350#endif
351#endif
352}
353
354
355void QWhatsThat::keyPressEvent( QKeyEvent* )
356{
357 hide();
358}
359
360
361
362void QWhatsThat::paintEvent( QPaintEvent* )
363{
364 bool drawShadow = TRUE;
365#if defined(Q_WS_WIN)
366 if ( (qWinVersion()&WV_NT_based) > WV_2000 ) {
367 BOOL shadow;
368 SystemParametersInfo( SPI_GETDROPSHADOW, 0, &shadow, 0 );
369 drawShadow = !shadow;
370 }
371#elif defined(Q_WS_MACX)
372 drawShadow = FALSE; //never draw it on OS X we get it for free
373#endif
374
375 QRect r = rect();
376 if ( drawShadow )
377 r.addCoords( 0, 0, -shadowWidth, -shadowWidth );
378 QPainter p( this);
379 p.setPen( colorGroup().foreground() );
380 p.drawRect( r );
381 p.setPen( colorGroup().mid() );
382 p.setBrush( colorGroup().brush( QColorGroup::Background ) );
383 int w = r.width();
384 int h = r.height();
385 p.drawRect( 1, 1, w-2, h-2 );
386 if ( drawShadow ) {
387 p.setPen( colorGroup().shadow() );
388 p.drawPoint( w + 5, 6 );
389 p.drawLine( w + 3, 6, w + 5, 8 );
390 p.drawLine( w + 1, 6, w + 5, 10 );
391 int i;
392 for( i=7; i < h; i += 2 )
393 p.drawLine( w, i, w + 5, i + 5 );
394 for( i = w - i + h; i > 6; i -= 2 )
395 p.drawLine( i, h, i + 5, h + 5 );
396 for( ; i > 0 ; i -= 2 )
397 p.drawLine( 6, h + 6 - i, i + 5, h + 5 );
398 }
399 p.setPen( colorGroup().foreground() );
400 r.addCoords( hMargin, vMargin, -hMargin, -vMargin );
401
402#ifndef QT_NO_RICHTEXT
403 if ( doc ) {
404 doc->draw( &p, r.x(), r.y(), r, colorGroup(), 0 );
405 }
406 else
407#endif
408 {
409 p.drawText( r, AlignAuto + AlignTop + WordBreak + ExpandTabs, text );
410 }
411}
412
413// the item
414QWhatsThisPrivate::WhatsThisItem::~WhatsThisItem()
415{
416 if ( count )
417 qFatal( "QWhatsThis: Internal error (%d)", count );
418 delete whatsthis;
419}
420
421
422static const char * const button_image[] = {
423"16 16 3 1",
424" c None",
425"o c #000000",
426"a c #000080",
427"o aaaaa ",
428"oo aaa aaa ",
429"ooo aaa aaa",
430"oooo aa aa",
431"ooooo aa aa",
432"oooooo a aaa",
433"ooooooo aaa ",
434"oooooooo aaa ",
435"ooooooooo aaa ",
436"ooooo aaa ",
437"oo ooo ",
438"o ooo aaa ",
439" ooo aaa ",
440" ooo ",
441" ooo ",
442" ooo "};
443
444// the button class
445QWhatsThisButton::QWhatsThisButton( QWidget * parent, const char * name )
446 : QToolButton( parent, name )
447{
448 QPixmap p( (const char**)button_image );
449 setPixmap( p );
450 setToggleButton( TRUE );
451 setAutoRaise( TRUE );
452 setFocusPolicy( NoFocus );
453 setTextLabel( tr( "What's this?" ) );
454 wt->buttons->insert( (void *)this, this );
455 connect( this, SIGNAL( released() ),
456 this, SLOT( mouseReleased() ) );
457}
458
459
460QWhatsThisButton::~QWhatsThisButton()
461{
462 if ( wt && wt->buttons )
463 wt->buttons->take( (void *)this );
464}
465
466
467void QWhatsThisButton::mouseReleased()
468{
469 if ( wt->state == QWhatsThisPrivate::Inactive && isOn() ) {
470 QWhatsThisPrivate::setUpWhatsThis();
471#ifndef QT_NO_CURSOR
472 QApplication::setOverrideCursor( whatsThisCursor, FALSE );
473#endif
474 wt->state = QWhatsThisPrivate::Waiting;
475 qApp->installEventFilter( wt );
476 }
477}
478
479static void qWhatsThisPrivateCleanup()
480{
481 if( wt ) {
482 delete wt;
483 wt = 0;
484 }
485}
486
487// the what's this manager class
488QWhatsThisPrivate::QWhatsThisPrivate()
489 : QObject( 0, "global what's this object" )
490{
491 whatsThat = 0;
492 dict = new QPtrDict<QWhatsThisPrivate::WhatsThisItem>;
493 tlw = new QPtrDict<QWidget>;
494 wt = this;
495 buttons = new QPtrDict<QWhatsThisButton>;
496 state = Inactive;
497}
498
499QWhatsThisPrivate::~QWhatsThisPrivate()
500{
501#ifndef QT_NO_CURSOR
502 if ( state == Waiting && qApp )
503 QApplication::restoreOverrideCursor();
504#endif
505 // the two straight-and-simple dicts
506 delete tlw;
507 delete buttons;
508
509 // then delete the complex one.
510 QPtrDictIterator<WhatsThisItem> it( *dict );
511 WhatsThisItem * i;
512 QWidget * w;
513 while( (i=it.current()) != 0 ) {
514 w = (QWidget *)it.currentKey();
515 ++it;
516 dict->take( w );
517 if ( i->deref() )
518 delete i;
519 }
520 delete dict;
521 if ( whatsThat && !whatsThat->parentWidget() ) {
522 delete whatsThat;
523 }
524 // and finally lose wt
525 wt = 0;
526}
527
528bool QWhatsThisPrivate::eventFilter( QObject * o, QEvent * e )
529{
530 switch( state ) {
531 case Waiting:
532 if ( e->type() == QEvent::MouseButtonPress && o->isWidgetType() ) {
533 QWidget * w = (QWidget *) o;
534 if ( ( (QMouseEvent*)e)->button() == RightButton )
535 return FALSE; // ignore RMB
536 if ( w->customWhatsThis() )
537 return FALSE;
538 QWhatsThisPrivate::WhatsThisItem * i = 0;
539 QMouseEvent* me = (QMouseEvent*) e;
540 QPoint p = me->pos();
541 while( w && !i ) {
542 i = dict->find( w );
543 if ( !i ) {
544 p += w->pos();
545 w = w->parentWidget( TRUE );
546 }
547 }
548 leaveWhatsThisMode();
549 if (!i ) {
550#if defined(QT_ACCESSIBILITY_SUPPORT)
551 QAccessible::updateAccessibility( this, 0, QAccessible::ContextHelpEnd );
552#endif
553 return TRUE;
554 }
555 if ( i->whatsthis )
556 say( w, i->whatsthis->text( p ), me->globalPos() );
557 else
558 say( w, i->s, me->globalPos() );
559 return TRUE;
560 } else if ( e->type() == QEvent::MouseButtonRelease ) {
561 if ( ( (QMouseEvent*)e)->button() == RightButton )
562 return FALSE; // ignore RMB
563 return !o->isWidgetType() || !((QWidget*)o)->customWhatsThis();
564 } else if ( e->type() == QEvent::MouseMove ) {
565 return !o->isWidgetType() || !((QWidget*)o)->customWhatsThis();
566 } else if ( e->type() == QEvent::KeyPress ) {
567 QKeyEvent* kev = (QKeyEvent*)e;
568
569 if ( kev->key() == Qt::Key_Escape ) {
570 leaveWhatsThisMode();
571 return TRUE;
572 } else if ( o->isWidgetType() && ((QWidget*)o)->customWhatsThis() ) {
573 return FALSE;
574 } else if ( kev->key() == Key_Menu ||
575 ( kev->key() == Key_F10 &&
576 kev->state() == ShiftButton ) ) {
577 // we don't react to these keys, they are used for context menus
578 return FALSE;
579 } else if ( kev->state() == kev->stateAfter() &&
580 kev->key() != Key_Meta ) { // not a modifier key
581 leaveWhatsThisMode();
582 }
583 } else if ( e->type() == QEvent::MouseButtonDblClick ) {
584 return TRUE;
585 }
586 break;
587 case Inactive:
588 if ( e->type() == QEvent::Accel &&
589 ((QKeyEvent *)e)->key() == Key_F1 &&
590 o->isWidgetType() &&
591 ((QKeyEvent *)e)->state() == ShiftButton ) {
592 QWidget * w = ((QWidget *)o)->focusWidget();
593 if ( !w )
594 break;
595 QString s = QWhatsThis::textFor( w, QPoint(0,0), TRUE );
596 if ( !s.isNull() ) {
597 say ( w, s, w->mapToGlobal( w->rect().center() ) );
598 ((QKeyEvent *)e)->accept();
599 return TRUE;
600 }
601 }
602 break;
603 }
604 return FALSE;
605}
606
607
608
609void QWhatsThisPrivate::setUpWhatsThis()
610{
611 if ( !wt ) {
612 wt = new QWhatsThisPrivate();
613
614 // It is necessary to use a post routine, because
615 // the destructor deletes pixmaps and other stuff that
616 // needs a working X connection under X11.
617 qAddPostRoutine( qWhatsThisPrivateCleanup );
618 }
619}
620
621
622void QWhatsThisPrivate::enterWhatsThisMode()
623{
624#if defined(QT_ACCESSIBILITY_SUPPORT)
625 QAccessible::updateAccessibility( this, 0, QAccessible::ContextHelpStart );
626#endif
627}
628
629
630void QWhatsThisPrivate::leaveWhatsThisMode()
631{
632 if ( state == Waiting ) {
633 QPtrDictIterator<QWhatsThisButton> it( *(wt->buttons) );
634 QWhatsThisButton * b;
635 while( (b=it.current()) != 0 ) {
636 ++it;
637 b->setOn( FALSE );
638 }
639#ifndef QT_NO_CURSOR
640 QApplication::restoreOverrideCursor();
641#endif
642 state = Inactive;
643 qApp->removeEventFilter( this );
644 }
645}
646
647
648
649void QWhatsThisPrivate::say( QWidget * widget, const QString &text, const QPoint& ppos)
650{
651 if ( text.isEmpty() )
652 return;
653 // make a fresh widget, and set it up
654 delete whatsThat;
655 whatsThat = new QWhatsThat(
656 widget, text,
657#if defined(Q_WS_X11)
658 QApplication::desktop()->screen( widget ?
659 widget->x11Screen() :
660 QCursor::x11Screen() ),
661#else
662 0,
663#endif
664 "automatic what's this? widget" );
665
666
667 // okay, now to find a suitable location
668
669 int scr = ( widget ?
670 QApplication::desktop()->screenNumber( widget ) :
671#if defined(Q_WS_X11)
672 QCursor::x11Screen()
673#else
674 QApplication::desktop()->screenNumber( ppos )
675#endif // Q_WS_X11
676 );
677 QRect screen = QApplication::desktop()->screenGeometry( scr );
678
679 int x;
680 int w = whatsThat->width();
681 int h = whatsThat->height();
682 int sx = screen.x();
683 int sy = screen.y();
684
685 // first try locating the widget immediately above/below,
686 // with nice alignment if possible.
687 QPoint pos;
688 if ( widget )
689 pos = widget->mapToGlobal( QPoint( 0,0 ) );
690
691 if ( widget && w > widget->width() + 16 )
692 x = pos.x() + widget->width()/2 - w/2;
693 else
694 x = ppos.x() - w/2;
695
696 // squeeze it in if that would result in part of what's this
697 // being only partially visible
698 if ( x + w + shadowWidth > sx+screen.width() )
699 x = (widget? (QMIN(screen.width(),
700 pos.x() + widget->width())
701 ) : screen.width() )
702 - w;
703
704 if ( x < sx )
705 x = sx;
706
707 int y;
708 if ( widget && h > widget->height() + 16 ) {
709 y = pos.y() + widget->height() + 2; // below, two pixels spacing
710 // what's this is above or below, wherever there's most space
711 if ( y + h + 10 > sy+screen.height() )
712 y = pos.y() + 2 - shadowWidth - h; // above, overlap
713 }
714 y = ppos.y() + 2;
715
716 // squeeze it in if that would result in part of what's this
717 // being only partially visible
718 if ( y + h + shadowWidth > sy+screen.height() )
719 y = ( widget ? (QMIN(screen.height(),
720 pos.y() + widget->height())
721 ) : screen.height() )
722 - h;
723 if ( y < sy )
724 y = sy;
725
726 whatsThat->move( x, y );
727 whatsThat->show();
728}
729
730QWhatsThisPrivate::WhatsThisItem* QWhatsThisPrivate::newItem( QWidget * widget )
731{
732 WhatsThisItem * i = dict->find( (void *)widget );
733 if ( i )
734 QWhatsThis::remove( widget );
735 i = new WhatsThisItem;
736 dict->insert( (void *)widget, i );
737 QWidget * t = widget->topLevelWidget();
738 if ( !tlw->find( (void *)t ) ) {
739 tlw->insert( (void *)t, t );
740 t->installEventFilter( this );
741 }
742 connect( widget, SIGNAL(destroyed()), this, SLOT(cleanupWidget()) );
743 return i;
744}
745
746void QWhatsThisPrivate::add( QWidget * widget, QWhatsThis* special )
747{
748 newItem( widget )->whatsthis = special;
749}
750
751void QWhatsThisPrivate::add( QWidget * widget, const QString &text )
752{
753 newItem( widget )->s = text;
754}
755
756
757// and finally the What's This class itself
758
759/*!
760 Adds \a text as "What's this" help for \a widget. If the text is
761 rich text formatted (i.e. it contains markup) it will be rendered
762 with the default stylesheet QStyleSheet::defaultSheet().
763
764 The text is destroyed if the widget is later destroyed, so it need
765 not be explicitly removed.
766
767 \sa remove()
768*/
769void QWhatsThis::add( QWidget * widget, const QString &text )
770{
771 if ( text.isEmpty() )
772 return; // pointless
773 QWhatsThisPrivate::setUpWhatsThis();
774 wt->add(widget,text);
775}
776
777
778/*!
779 Removes the "What's this?" help associated with the \a widget.
780 This happens automatically if the widget is destroyed.
781
782 \sa add()
783*/
784void QWhatsThis::remove( QWidget * widget )
785{
786 QWhatsThisPrivate::setUpWhatsThis();
787 QWhatsThisPrivate::WhatsThisItem * i = wt->dict->find( (void *)widget );
788 if ( !i )
789 return;
790
791 wt->dict->take( (void *)widget );
792
793 i->deref();
794 if ( !i->count )
795 delete i;
796}
797
798
799/*!
800 Returns the what's this text for widget \a w or QString::null if
801 there is no "What's this?" help for the widget. \a pos contains
802 the mouse position; this is useful, for example, if you've
803 subclassed to make the text that is displayed position dependent.
804
805 If \a includeParents is TRUE, parent widgets are taken into
806 consideration as well when looking for what's this help text.
807
808 \sa add()
809*/
810QString QWhatsThis::textFor( QWidget * w, const QPoint& pos, bool includeParents )
811{
812 QWhatsThisPrivate::setUpWhatsThis();
813 QWhatsThisPrivate::WhatsThisItem * i = 0;
814 QPoint p = pos;
815 while( w && !i ) {
816 i = wt->dict->find( w );
817 if ( !includeParents )
818 break;
819 if ( !i ) {
820 p += w->pos();
821 w = w->parentWidget( TRUE );
822 }
823 }
824 if (!i)
825 return QString::null;
826 if ( i->whatsthis )
827 return i->whatsthis->text( p );
828 return i->s;
829}
830
831
832/*!
833 Creates a QToolButton preconfigured to enter "What's this?" mode
834 when clicked. You will often use this with a tool bar as \a
835 parent:
836 \code
837 (void) QWhatsThis::whatsThisButton( my_help_tool_bar );
838 \endcode
839*/
840QToolButton * QWhatsThis::whatsThisButton( QWidget * parent )
841{
842 QWhatsThisPrivate::setUpWhatsThis();
843 return new QWhatsThisButton( parent,
844 "automatic what's this? button" );
845}
846
847/*!
848 Constructs a dynamic "What's this?" object for \a widget. The
849 object is deleted when the \a widget is destroyed.
850
851 When the widget is queried by the user the text() function of this
852 QWhatsThis will be called to provide the appropriate text, rather
853 than using the text assigned by add().
854*/
855QWhatsThis::QWhatsThis( QWidget * widget)
856{
857 QWhatsThisPrivate::setUpWhatsThis();
858 wt->add(widget,this);
859}
860
861
862/*!
863 Destroys the object and frees any allocated resources.
864*/
865QWhatsThis::~QWhatsThis()
866{
867}
868
869
870/*!
871 This virtual function returns the text for position \e p in the
872 widget that this "What's this?" object documents. If there is no
873 "What's this?" text for the position, QString::null is returned.
874
875 The default implementation returns QString::null.
876*/
877QString QWhatsThis::text( const QPoint & )
878{
879 return QString::null;
880}
881
882/*!
883 \fn bool QWhatsThis::clicked( const QString& href )
884
885 This virtual function is called when the user clicks inside the
886 "What's this?" window. \a href is the link the user clicked on, or
887 QString::null if there was no link.
888
889 If the function returns TRUE (the default), the "What's this?"
890 window is closed, otherwise it remains visible.
891
892 The default implementation ignores \a href and returns TRUE.
893*/
894bool QWhatsThis::clicked( const QString& )
895{
896 return TRUE;
897}
898
899
900/*!
901 Enters "What's this?" mode and returns immediately.
902
903 Qt will install a special cursor and take over mouse input until
904 the user clicks somewhere. It then shows any help available and
905 ends "What's this?" mode. Finally, Qt removes the special cursor
906 and help window and then restores ordinary event processing, at
907 which point the left mouse button is no longer pressed.
908
909 The user can also use the Esc key to leave "What's this?" mode.
910
911 \sa inWhatsThisMode(), leaveWhatsThisMode()
912*/
913
914void QWhatsThis::enterWhatsThisMode()
915{
916 QWhatsThisPrivate::setUpWhatsThis();
917 if ( wt->state == QWhatsThisPrivate::Inactive ) {
918 wt->enterWhatsThisMode();
919#ifndef QT_NO_CURSOR
920 QApplication::setOverrideCursor( whatsThisCursor, FALSE );
921#endif
922 wt->state = QWhatsThisPrivate::Waiting;
923 qApp->installEventFilter( wt );
924 }
925}
926
927
928/*!
929 Returns TRUE if the application is in "What's this?" mode;
930 otherwise returns FALSE.
931
932 \sa enterWhatsThisMode(), leaveWhatsThisMode()
933*/
934bool QWhatsThis::inWhatsThisMode()
935{
936 if (!wt)
937 return FALSE;
938 return wt->state == QWhatsThisPrivate::Waiting;
939}
940
941
942/*!
943 Leaves "What's this?" question mode.
944
945 This function is used internally by widgets that support
946 QWidget::customWhatsThis(); applications do not usually call it.
947 An example of such a widget is QPopupMenu: menus still work
948 normally in "What's this?" mode but also provide help texts for
949 individual menu items.
950
951 If \a text is not QString::null, a "What's this?" help window is
952 displayed at the global screen position \a pos. If widget \a w is
953 not 0 and has its own dedicated QWhatsThis object, this object
954 will receive clicked() messages when the user clicks on hyperlinks
955 inside the help text.
956
957 \sa inWhatsThisMode(), enterWhatsThisMode(), QWhatsThis::clicked()
958*/
959void QWhatsThis::leaveWhatsThisMode( const QString& text, const QPoint& pos, QWidget* w )
960{
961 if ( !inWhatsThisMode() )
962 return;
963
964 wt->leaveWhatsThisMode();
965 if ( !text.isNull() )
966 wt->say( w, text, pos );
967}
968
969/*!
970 Display \a text in a help window at the global screen position \a
971 pos.
972
973 If widget \a w is not 0 and has its own dedicated QWhatsThis
974 object, this object will receive clicked() messages when the user
975 clicks on hyperlinks inside the help text.
976
977 \sa QWhatsThis::clicked()
978*/
979void QWhatsThis::display( const QString& text, const QPoint& pos, QWidget* w )
980{
981 if ( inWhatsThisMode() ) {
982 leaveWhatsThisMode( text, pos, w );
983 return;
984 }
985 QWhatsThisPrivate::setUpWhatsThis();
986 wt->say( w, text, pos );
987}
988
989/*!
990 Sets the font for all "What's this?" helps to \a font.
991*/
992void QWhatsThis::setFont( const QFont &font )
993{
994 QApplication::setFont( font, TRUE, "QWhatsThat" );
995}
996
997#include "qwhatsthis.moc"
998#endif
Note: See TracBrowser for help on using the repository browser.