source: vendor/trolltech/current/src/widgets/qwidgetstack.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: 14.3 KB
Line 
1/****************************************************************************
2** $Id: qwidgetstack.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of QWidgetStack class
5**
6** Created : 980128
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the widgets module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qwidgetstack.h"
39#include "qlayout.h"
40#include "../kernel/qlayoutengine_p.h"
41#ifndef QT_NO_WIDGETSTACK
42
43#include "qobjectlist.h"
44#include "qfocusdata.h"
45#include "qbutton.h"
46#include "qbuttongroup.h"
47
48#include "qapplication.h"
49
50class QWidgetStackPrivate {
51public:
52 class Invisible: public QWidget
53 {
54 public:
55 Invisible( QWidgetStack * parent ): QWidget( parent, "qt_invisible_widgetstack" )
56 {
57 setBackgroundMode( NoBackground );
58 }
59 const char * className() const
60 {
61 return "QWidgetStackPrivate::Invisible";
62 }
63 };
64};
65
66
67#if (QT_VERSION-0 >= 0x040000)
68#if defined(Q_CC_GNU)
69#warning "Remove QWidgetStackEventFilter"
70#endif
71#endif
72class QWidgetStackEventFilter : public QObject
73{
74 /* For binary compatibility, since we cannot implement virtual
75 functions and rely on them being called. This is what we should
76 have
77
78 bool QWidgetStack::event( QEvent* e )
79 {
80 if ( e->type() == QEvent::LayoutHint )
81 updateGeometry(); // propgate layout hints to parent
82 return QFrame::event( e );
83 }
84 */
85public:
86
87 QWidgetStackEventFilter( QObject *parent = 0, const char * name = 0 )
88 : QObject( parent, name ) {}
89 bool eventFilter( QObject *o, QEvent * e ) {
90 if ( e->type() == QEvent::LayoutHint && o->isWidgetType() )
91 ((QWidget*)o)->updateGeometry();
92 return FALSE;
93 }
94};
95
96
97/*!
98 \class QWidgetStack
99 \brief The QWidgetStack class provides a stack of widgets of which
100 only the top widget is user-visible.
101
102 \ingroup organizers
103 \mainclass
104
105 The application programmer can move any widget to the top of the
106 stack at any time using raiseWidget(), and add or remove widgets
107 using addWidget() and removeWidget(). It is not sufficient to pass
108 the widget stack as parent to a widget which should be inserted into
109 the widgetstack.
110
111 visibleWidget() is the \e get equivalent of raiseWidget(); it
112 returns a pointer to the widget that is currently at the top of
113 the stack.
114
115 QWidgetStack also provides the ability to manipulate widgets
116 through application-specified integer IDs. You can also translate
117 from widget pointers to IDs using id() and from IDs to widget
118 pointers using widget(). These numeric IDs are unique (per
119 QWidgetStack, not globally), but QWidgetStack does not attach any
120 additional meaning to them.
121
122 The default widget stack is frameless, but you can use the usual
123 QFrame functions (such as setFrameStyle()) to add a frame.
124
125 QWidgetStack provides a signal, aboutToShow(), which is emitted
126 just before a managed widget is shown.
127
128 \sa QTabDialog QTabBar QFrame
129*/
130
131
132/*!
133 Constructs an empty widget stack.
134
135 The \a parent and \a name arguments are passed to the QFrame
136 constructor.
137*/
138
139QWidgetStack::QWidgetStack( QWidget * parent, const char *name )
140 : QFrame( parent, name )
141{
142 init();
143}
144
145/*!
146 Constructs an empty widget stack.
147
148 The \a parent, \a name and \a f arguments are passed to the QFrame
149 constructor.
150*/
151QWidgetStack::QWidgetStack( QWidget * parent, const char *name, WFlags f )
152 : QFrame( parent, name, f ) //## merge constructors in 4.0
153{
154 init();
155}
156
157void QWidgetStack::init()
158{
159 d = 0;
160 QWidgetStackEventFilter *ef = new QWidgetStackEventFilter( this );
161 installEventFilter( ef );
162 dict = new QIntDict<QWidget>;
163 focusWidgets = 0;
164 topWidget = 0;
165 invisible = new QWidgetStackPrivate::Invisible( this );
166 invisible->hide();
167}
168
169
170/*!
171 Destroys the object and frees any allocated resources.
172*/
173
174QWidgetStack::~QWidgetStack()
175{
176 delete focusWidgets;
177 delete d;
178 delete dict;
179}
180
181
182/*!
183 Adds widget \a w to this stack of widgets, with ID \a id.
184
185 If you pass an id \>= 0 this ID is used. If you pass an \a id of
186 -1 (the default), the widgets will be numbered automatically. If
187 you pass -2 a unique negative integer will be generated. No widget
188 has an ID of -1. Returns the ID or -1 on failure (e.g. \w is 0).
189
190 If you pass an id that is already used, then a unique negative
191 integer will be generated to prevent two widgets having the same
192 id.
193
194 If \a w is not a child of this QWidgetStack moves it using
195 reparent().
196*/
197
198int QWidgetStack::addWidget( QWidget * w, int id )
199{
200 static int nseq_no = -2;
201 static int pseq_no = 0;
202
203 if ( !w || w == invisible )
204 return -1;
205
206 // prevent duplicates
207 removeWidget( w );
208
209 if ( id >= 0 && dict->find( id ) )
210 id = -2;
211 if ( id < -1 )
212 id = nseq_no--;
213 else if ( id == -1 )
214 id = pseq_no++;
215 else
216 pseq_no = QMAX(pseq_no, id + 1);
217 // use id >= 0 as-is
218
219 dict->insert( id, w );
220
221 // preserve existing focus
222 QWidget * f = w->focusWidget();
223 while( f && f != w )
224 f = f->parentWidget();
225 if ( f ) {
226 if ( !focusWidgets )
227 focusWidgets = new QPtrDict<QWidget>( 17 );
228 focusWidgets->replace( w, w->focusWidget() );
229 }
230
231 w->hide();
232 if ( w->parent() != this )
233 w->reparent( this, contentsRect().topLeft(), FALSE );
234 w->setGeometry( contentsRect() );
235 updateGeometry();
236 return id;
237}
238
239
240/*!
241 Removes widget \a w from this stack of widgets. Does not delete \a
242 w. If \a w is the currently visible widget, no other widget is
243 substituted.
244
245 \sa visibleWidget() raiseWidget()
246*/
247
248void QWidgetStack::removeWidget( QWidget * w )
249{
250 if ( !w )
251 return;
252 int i = id( w );
253 if ( i != -1 )
254 dict->take( i );
255
256 if ( w == topWidget )
257 topWidget = 0;
258 if ( dict->isEmpty() )
259 invisible->hide(); // let background shine through again
260 updateGeometry();
261}
262
263
264/*!
265 Raises the widget with ID \a id to the top of the widget stack.
266
267 \sa visibleWidget()
268*/
269
270void QWidgetStack::raiseWidget( int id )
271{
272 if ( id == -1 )
273 return;
274 QWidget * w = dict->find( id );
275 if ( w )
276 raiseWidget( w );
277}
278
279static bool isChildOf( QWidget* child, QWidget *parent )
280{
281 const QObjectList *list = parent->children();
282 if ( !child || !list )
283 return FALSE;
284 QObjectListIt it(*list);
285 QObject *obj;
286 while ( (obj = it.current()) ) {
287 ++it;
288 if ( !obj->isWidgetType() || ((QWidget *)obj)->isTopLevel() )
289 continue;
290 QWidget *widget = (QWidget *)obj;
291 if ( widget == child || isChildOf( child, widget ) )
292 return TRUE;
293 }
294 return FALSE;
295}
296
297/*!
298 \overload
299
300 Raises widget \a w to the top of the widget stack.
301*/
302
303void QWidgetStack::raiseWidget( QWidget *w )
304{
305 if ( !w || w == invisible || w->parent() != this || w == topWidget )
306 return;
307
308 if ( id(w) == -1 )
309 addWidget( w );
310 if ( !isVisible() ) {
311 topWidget = w;
312 return;
313 }
314
315 if ( invisible->isHidden() ) {
316 invisible->setGeometry( contentsRect() );
317 invisible->lower();
318 invisible->show();
319 QApplication::sendPostedEvents( invisible, QEvent::ShowWindowRequest );
320 }
321
322 // try to move focus onto the incoming widget if focus
323 // was somewhere on the outgoing widget.
324 if ( topWidget ) {
325 QWidget * fw = focusWidget();
326 QWidget* p = fw;
327 while ( p && p != topWidget )
328 p = p->parentWidget();
329 if ( p == topWidget ) { // focus was on old page
330 if ( !focusWidgets )
331 focusWidgets = new QPtrDict<QWidget>( 17 );
332 focusWidgets->replace( topWidget, fw );
333 fw->clearFocus();
334 // look for the best focus widget we can find
335 // best == what we had (which may be deleted)
336 fw = focusWidgets->take( w );
337 if ( isChildOf( fw, w ) ) {
338 fw->setFocus();
339 } else {
340 // second best == first child widget in the focus chain
341 QFocusData *f = focusData();
342 QWidget* home = f->home();
343 QWidget *i = home;
344 do {
345 if ( ( ( i->focusPolicy() & TabFocus ) == TabFocus )
346 && !i->focusProxy() && i->isVisibleTo(w) && i->isEnabled() ) {
347 p = i;
348 while ( p && p != w )
349 p = p->parentWidget();
350 if ( p == w ) {
351 i->setFocus();
352 break;
353 }
354 }
355 i = f->next();
356 } while( i != home );
357 }
358 }
359 }
360
361 if ( isVisible() ) {
362 emit aboutToShow( w );
363 int i = id( w );
364 if ( i != -1 )
365 emit aboutToShow( i );
366 }
367
368 topWidget = w;
369
370 const QObjectList * c = children();
371 QObjectListIt it( *c );
372 QObject * o;
373
374 while( (o=it.current()) != 0 ) {
375 ++it;
376 if ( o->isWidgetType() && o != w && o != invisible )
377 ((QWidget *)o)->hide();
378 }
379
380 w->setGeometry( invisible->geometry() );
381 w->show();
382}
383
384/*!
385 \reimp
386*/
387
388void QWidgetStack::frameChanged()
389{
390 QFrame::frameChanged();
391 setChildGeometries();
392}
393
394
395/*!
396 \reimp
397*/
398
399void QWidgetStack::setFrameRect( const QRect & r )
400{
401 QFrame::setFrameRect( r );
402 setChildGeometries();
403}
404
405
406/*!
407 Fixes up the children's geometries.
408*/
409
410void QWidgetStack::setChildGeometries()
411{
412 invisible->setGeometry( contentsRect() );
413 if ( topWidget )
414 topWidget->setGeometry( invisible->geometry() );
415}
416
417
418/*!
419 \reimp
420*/
421void QWidgetStack::show()
422{
423 // Reimplemented in order to set the children's geometries
424 // appropriately and to pick the first widget as topWidget if no
425 // topwidget was defined
426 if ( !isVisible() && children() ) {
427 const QObjectList * c = children();
428 QObjectListIt it( *c );
429 QObject * o;
430
431 while( (o=it.current()) != 0 ) {
432 ++it;
433 if ( o->isWidgetType() ) {
434 if ( !topWidget && o != invisible )
435 topWidget = (QWidget*)o;
436 if ( o == topWidget )
437 ((QWidget *)o)->show();
438 else
439 ((QWidget *)o)->hide();
440 }
441 }
442 setChildGeometries();
443 }
444 QFrame::show();
445}
446
447
448/*!
449 Returns the widget with ID \a id. Returns 0 if this widget stack
450 does not manage a widget with ID \a id.
451
452 \sa id() addWidget()
453*/
454
455QWidget * QWidgetStack::widget( int id ) const
456{
457 return id != -1 ? dict->find( id ) : 0;
458}
459
460
461/*!
462 Returns the ID of the \a widget. Returns -1 if \a widget is 0 or
463 is not being managed by this widget stack.
464
465 \sa widget() addWidget()
466*/
467
468int QWidgetStack::id( QWidget * widget ) const
469{
470 if ( !widget )
471 return -1;
472
473 QIntDictIterator<QWidget> it( *dict );
474 while ( it.current() && it.current() != widget )
475 ++it;
476 return it.current() == widget ? it.currentKey() : -1;
477}
478
479
480/*!
481 Returns the currently visible widget (the one at the top of the
482 stack), or 0 if nothing is currently being shown.
483
484 \sa aboutToShow() id() raiseWidget()
485*/
486
487QWidget * QWidgetStack::visibleWidget() const
488{
489 return topWidget;
490}
491
492
493/*!
494 \fn void QWidgetStack::aboutToShow( int )
495
496 This signal is emitted just before a managed widget is shown if
497 that managed widget has an ID != -1. The argument is the numeric
498 ID of the widget.
499
500 If you call visibleWidget() in a slot connected to aboutToShow(),
501 the widget it returns is the one that is currently visible, not
502 the one that is about to be shown.
503*/
504
505
506/*!
507 \fn void QWidgetStack::aboutToShow( QWidget * )
508
509 \overload
510
511 This signal is emitted just before a managed widget is shown. The
512 argument is a pointer to the widget.
513
514 If you call visibleWidget() in a slot connected to aboutToShow(),
515 the widget returned is the one that is currently visible, not the
516 one that is about to be shown.
517*/
518
519
520/*!
521 \reimp
522*/
523
524void QWidgetStack::resizeEvent( QResizeEvent * e )
525{
526 QFrame::resizeEvent( e );
527 setChildGeometries();
528}
529
530
531/*!
532 \reimp
533*/
534
535QSize QWidgetStack::sizeHint() const
536{
537 constPolish();
538
539 QSize size( 0, 0 );
540
541 QIntDictIterator<QWidget> it( *dict );
542 QWidget *w;
543
544 while ( (w = it.current()) != 0 ) {
545 ++it;
546 QSize sh = w->sizeHint();
547 if ( w->sizePolicy().horData() == QSizePolicy::Ignored )
548 sh.rwidth() = 0;
549 if ( w->sizePolicy().verData() == QSizePolicy::Ignored )
550 sh.rheight() = 0;
551#ifndef QT_NO_LAYOUT
552 size = size.expandedTo( sh ).expandedTo( qSmartMinSize(w) );
553#endif
554 }
555 if ( size.isNull() )
556 size = QSize( 128, 64 );
557 size += QSize( 2*frameWidth(), 2*frameWidth() );
558 return size;
559}
560
561
562/*!
563 \reimp
564*/
565QSize QWidgetStack::minimumSizeHint() const
566{
567 constPolish();
568
569 QSize size( 0, 0 );
570
571 QIntDictIterator<QWidget> it( *dict );
572 QWidget *w;
573
574 while ( (w = it.current()) != 0 ) {
575 ++it;
576 QSize sh = w->minimumSizeHint();
577 if ( w->sizePolicy().horData() == QSizePolicy::Ignored )
578 sh.rwidth() = 0;
579 if ( w->sizePolicy().verData() == QSizePolicy::Ignored )
580 sh.rheight() = 0;
581#ifndef QT_NO_LAYOUT
582 size = size.expandedTo( sh ).expandedTo( w->minimumSize() );
583#endif
584 }
585 if ( size.isNull() )
586 size = QSize( 64, 32 );
587 size += QSize( 2*frameWidth(), 2*frameWidth() );
588 return size;
589}
590
591/*!
592 \reimp
593*/
594void QWidgetStack::childEvent( QChildEvent * e)
595{
596 if ( e->child()->isWidgetType() && e->removed() )
597 removeWidget( (QWidget*) e->child() );
598}
599#endif
Note: See TracBrowser for help on using the repository browser.