source: trunk/src/qt3support/widgets/q3widgetstack.cpp@ 1168

Last change on this file since 1168 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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