src/qt3support/widgets/q3widgetstack.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt3Support module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    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 
       
    48 QT_BEGIN_NAMESPACE
       
    49 
       
    50 using namespace Qt;
       
    51 
       
    52 class Q3WidgetStackPrivate {
       
    53 public:
       
    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 */
       
   118 Q3WidgetStack::Q3WidgetStack(QWidget * parent, const char *name, Qt::WindowFlags f)
       
   119     : Q3Frame(parent, name, f) //## merge constructors in 4.0
       
   120 {
       
   121     init();
       
   122 }
       
   123 
       
   124 void 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 
       
   142 Q3WidgetStack::~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 
       
   168 int 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 
       
   215 void 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 
       
   236 void 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 
       
   245 static 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 
       
   269 void 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 
       
   348 void Q3WidgetStack::frameChanged()
       
   349 {
       
   350     Q3Frame::frameChanged();
       
   351     setChildGeometries();
       
   352 }
       
   353 
       
   354 
       
   355 /*!
       
   356     \internal
       
   357 */
       
   358 
       
   359 void 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 
       
   371 void Q3WidgetStack::setChildGeometries()
       
   372 {
       
   373     invisible->setGeometry(contentsRect());
       
   374     if (topWidget)
       
   375         topWidget->setGeometry(invisible->geometry());
       
   376 }
       
   377 
       
   378 
       
   379 /*!
       
   380     \reimp
       
   381 */
       
   382 void 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 
       
   415 QWidget * 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 
       
   428 int 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 
       
   447 QWidget * 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 
       
   484 void Q3WidgetStack::resizeEvent(QResizeEvent * e)
       
   485 {
       
   486     Q3Frame::resizeEvent(e);
       
   487     setChildGeometries();
       
   488 }
       
   489 
       
   490 
       
   491 /*!
       
   492     \reimp
       
   493 */
       
   494 
       
   495 QSize 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 */
       
   525 QSize 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 */
       
   554 void Q3WidgetStack::childEvent(QChildEvent *e)
       
   555 {
       
   556     if (e->child()->isWidgetType() && e->removed())
       
   557         removeWidget((QWidget *) e->child());
       
   558 }
       
   559 
       
   560 
       
   561 /*!
       
   562     \reimp
       
   563 */
       
   564 bool 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 
       
   571 QT_END_NAMESPACE