src/gui/widgets/qsplitter.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
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 QtGui 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 "qsplitter.h"
       
    43 #ifndef QT_NO_SPLITTER
       
    44 
       
    45 #include "qapplication.h"
       
    46 #include "qcursor.h"
       
    47 #include "qdrawutil.h"
       
    48 #include "qevent.h"
       
    49 #include "qlayout.h"
       
    50 #include "qlist.h"
       
    51 #include "qpainter.h"
       
    52 #include "qrubberband.h"
       
    53 #include "qstyle.h"
       
    54 #include "qstyleoption.h"
       
    55 #include "qtextstream.h"
       
    56 #include "qvarlengtharray.h"
       
    57 #include "qvector.h"
       
    58 #include "private/qlayoutengine_p.h"
       
    59 #include "private/qsplitter_p.h"
       
    60 #include "qtimer.h"
       
    61 #include "qdebug.h"
       
    62 
       
    63 #include <ctype.h>
       
    64 
       
    65 QT_BEGIN_NAMESPACE
       
    66 
       
    67 //#define QSPLITTER_DEBUG
       
    68 
       
    69 /*!
       
    70     \class QSplitterHandle
       
    71     \brief The QSplitterHandle class provides handle functionality of the splitter.
       
    72 
       
    73     \ingroup organizers
       
    74 
       
    75     QSplitterHandle is typically what people think about when they think about
       
    76     a splitter. It is the handle that is used to resize the widgets.
       
    77 
       
    78     A typical developer using QSplitter will never have to worry about
       
    79     QSplitterHandle. It is provided for developers who want splitter handles
       
    80     that provide extra features, such as popup menus.
       
    81 
       
    82     The typical way one would create splitter handles is to subclass QSplitter then
       
    83     reimplement QSplitter::createHandle() to instantiate the custom splitter
       
    84     handle. For example, a minimum QSplitter subclass might look like this:
       
    85 
       
    86     \snippet doc/src/snippets/splitterhandle/splitter.h 0
       
    87 
       
    88     The \l{QSplitter::}{createHandle()} implementation simply constructs a
       
    89     custom splitter handle, called \c Splitter in this example:
       
    90 
       
    91     \snippet doc/src/snippets/splitterhandle/splitter.cpp 1
       
    92 
       
    93     Information about a given handle can be obtained using functions like
       
    94     orientation() and opaqueResize(), and is retrieved from its parent splitter.
       
    95     Details like these can be used to give custom handles different appearances
       
    96     depending on the splitter's orientation.
       
    97 
       
    98     The complexity of a custom handle subclass depends on the tasks that it
       
    99     needs to perform. A simple subclass might only provide a paintEvent()
       
   100     implementation:
       
   101 
       
   102     \snippet doc/src/snippets/splitterhandle/splitter.cpp 0
       
   103 
       
   104     In this example, a predefined gradient is set up differently depending on
       
   105     the orientation of the handle. QSplitterHandle provides a reasonable
       
   106     size hint for the handle, so the subclass does not need to provide a
       
   107     reimplementation of sizeHint() unless the handle has special size
       
   108     requirements.
       
   109 
       
   110     \sa QSplitter
       
   111 */
       
   112 
       
   113 /*!
       
   114     Creates a QSplitter handle with the given \a orientation and
       
   115     QSplitter \a parent.
       
   116 */
       
   117 QSplitterHandle::QSplitterHandle(Qt::Orientation orientation, QSplitter *parent)
       
   118     : QWidget(*new QSplitterHandlePrivate, parent, 0)
       
   119 {
       
   120     Q_D(QSplitterHandle);
       
   121     d->s = parent;
       
   122     setOrientation(orientation);
       
   123 }
       
   124 
       
   125 /*!
       
   126     Sets the orientation of the splitter handle to \a orientation.
       
   127     This is usually propogated from the QSplitter.
       
   128 
       
   129     \sa QSplitter::setOrientation()
       
   130 */
       
   131 void QSplitterHandle::setOrientation(Qt::Orientation orientation)
       
   132 {
       
   133     Q_D(QSplitterHandle);
       
   134     d->orient = orientation;
       
   135 #ifndef QT_NO_CURSOR
       
   136     setCursor(orientation == Qt::Horizontal ? Qt::SplitHCursor : Qt::SplitVCursor);
       
   137 #endif
       
   138 }
       
   139 
       
   140 /*!
       
   141    Returns the handle's orientation. This is usually propagated from the QSplitter.
       
   142 
       
   143    \sa QSplitter::orientation()
       
   144 */
       
   145 Qt::Orientation QSplitterHandle::orientation() const
       
   146 {
       
   147     Q_D(const QSplitterHandle);
       
   148     return d->orient;
       
   149 }
       
   150 
       
   151 
       
   152 /*!
       
   153     Returns true if widgets are resized dynamically (opaquely), otherwise
       
   154     returns false. This value is controlled by the QSplitter.
       
   155 
       
   156     \sa QSplitter::opaqueResize()
       
   157 
       
   158 */
       
   159 bool QSplitterHandle::opaqueResize() const
       
   160 {
       
   161     Q_D(const QSplitterHandle);
       
   162     return d->s->opaqueResize();
       
   163 }
       
   164 
       
   165 
       
   166 /*!
       
   167     Returns the splitter associated with this splitter handle.
       
   168 
       
   169     \sa QSplitter::handle()
       
   170 */
       
   171 QSplitter *QSplitterHandle::splitter() const
       
   172 {
       
   173     return d_func()->s;
       
   174 }
       
   175 
       
   176 /*!
       
   177     Tells the splitter to move this handle to position \a pos, which is
       
   178     the distance from the left or top edge of the widget.
       
   179 
       
   180     Note that \a pos is also measured from the left (or top) for
       
   181     right-to-left languages. This function will map \a pos to the
       
   182     appropriate position before calling QSplitter::moveSplitter().
       
   183 
       
   184     \sa QSplitter::moveSplitter() closestLegalPosition()
       
   185 */
       
   186 void QSplitterHandle::moveSplitter(int pos)
       
   187 {
       
   188     Q_D(QSplitterHandle);
       
   189     if (d->s->isRightToLeft() && d->orient == Qt::Horizontal)
       
   190         pos = d->s->contentsRect().width() - pos;
       
   191     d->s->moveSplitter(pos, d->s->indexOf(this));
       
   192 }
       
   193 
       
   194 /*!
       
   195    Returns the closest legal position to \a pos of the splitter
       
   196    handle. The positions are measured from the left or top edge of
       
   197    the splitter, even for right-to-left languages.
       
   198 
       
   199    \sa QSplitter::closestLegalPosition(), moveSplitter()
       
   200 */
       
   201 
       
   202 int QSplitterHandle::closestLegalPosition(int pos)
       
   203 {
       
   204     Q_D(QSplitterHandle);
       
   205     QSplitter *s = d->s;
       
   206     if (s->isRightToLeft() && d->orient == Qt::Horizontal) {
       
   207         int w = s->contentsRect().width();
       
   208         return w - s->closestLegalPosition(w - pos, s->indexOf(this));
       
   209     }
       
   210     return s->closestLegalPosition(pos, s->indexOf(this));
       
   211 }
       
   212 
       
   213 /*!
       
   214     \reimp
       
   215 */
       
   216 QSize QSplitterHandle::sizeHint() const
       
   217 {
       
   218     Q_D(const QSplitterHandle);
       
   219     int hw = d->s->handleWidth();
       
   220     QStyleOption opt(0);
       
   221     opt.init(d->s);
       
   222     opt.state = QStyle::State_None;
       
   223     return parentWidget()->style()->sizeFromContents(QStyle::CT_Splitter, &opt, QSize(hw, hw), d->s)
       
   224         .expandedTo(QApplication::globalStrut());
       
   225 }
       
   226 
       
   227 /*!
       
   228     \reimp
       
   229 */
       
   230 bool QSplitterHandle::event(QEvent *event)
       
   231 {
       
   232     Q_D(QSplitterHandle);
       
   233     switch(event->type()) {
       
   234     case QEvent::HoverEnter:
       
   235         d->hover = true;
       
   236         update();
       
   237         break;
       
   238     case QEvent::HoverLeave:
       
   239         d->hover = false;
       
   240         update();
       
   241         break;
       
   242     default:
       
   243         break;
       
   244     }
       
   245     return QWidget::event(event);
       
   246 }
       
   247 
       
   248 /*!
       
   249     \reimp
       
   250 */
       
   251 void QSplitterHandle::mouseMoveEvent(QMouseEvent *e)
       
   252 {
       
   253     Q_D(QSplitterHandle);
       
   254     if (!(e->buttons() & Qt::LeftButton))
       
   255         return;
       
   256     int pos = d->pick(parentWidget()->mapFromGlobal(e->globalPos()))
       
   257                  - d->mouseOffset;
       
   258     if (opaqueResize()) {
       
   259         moveSplitter(pos);
       
   260     } else {
       
   261         d->s->setRubberBand(closestLegalPosition(pos));
       
   262     }
       
   263 }
       
   264 
       
   265 /*!
       
   266    \reimp
       
   267 */
       
   268 void QSplitterHandle::mousePressEvent(QMouseEvent *e)
       
   269 {
       
   270     Q_D(QSplitterHandle);
       
   271     if (e->button() == Qt::LeftButton) {
       
   272         d->mouseOffset = d->pick(e->pos());
       
   273         d->pressed = true;
       
   274         update();
       
   275     }
       
   276 }
       
   277 
       
   278 /*!
       
   279    \reimp
       
   280 */
       
   281 void QSplitterHandle::mouseReleaseEvent(QMouseEvent *e)
       
   282 {
       
   283     Q_D(QSplitterHandle);
       
   284     if (!opaqueResize() && e->button() == Qt::LeftButton) {
       
   285         int pos = d->pick(parentWidget()->mapFromGlobal(e->globalPos()))
       
   286                      - d->mouseOffset;
       
   287         d->s->setRubberBand(-1);
       
   288         moveSplitter(pos);
       
   289     }
       
   290     if (e->button() == Qt::LeftButton) {
       
   291         d->pressed = false;
       
   292         update();
       
   293     }
       
   294 }
       
   295 
       
   296 /*!
       
   297    \reimp
       
   298 */
       
   299 void QSplitterHandle::paintEvent(QPaintEvent *)
       
   300 {
       
   301     Q_D(QSplitterHandle);
       
   302     QPainter p(this);
       
   303     QStyleOption opt(0);
       
   304     opt.rect = rect();
       
   305     opt.palette = palette();
       
   306     if (orientation() == Qt::Horizontal)
       
   307         opt.state = QStyle::State_Horizontal;
       
   308     else
       
   309         opt.state = QStyle::State_None;
       
   310     if (d->hover)
       
   311         opt.state |= QStyle::State_MouseOver;
       
   312     if (d->pressed)
       
   313         opt.state |= QStyle::State_Sunken;
       
   314     if (isEnabled())
       
   315         opt.state |= QStyle::State_Enabled;
       
   316     parentWidget()->style()->drawControl(QStyle::CE_Splitter, &opt, &p, d->s);
       
   317 }
       
   318 
       
   319 
       
   320 int QSplitterLayoutStruct::getWidgetSize(Qt::Orientation orient)
       
   321 {
       
   322     if (sizer == -1) {
       
   323         QSize s = widget->sizeHint();
       
   324         const int presizer = pick(s, orient);
       
   325         const int realsize = pick(widget->size(), orient);
       
   326         if (!s.isValid() || (widget->testAttribute(Qt::WA_Resized) && (realsize > presizer))) {
       
   327             sizer = pick(widget->size(), orient);
       
   328         } else {
       
   329             sizer = presizer;
       
   330         }
       
   331         QSizePolicy p = widget->sizePolicy();
       
   332         int sf = (orient == Qt::Horizontal) ? p.horizontalStretch() : p.verticalStretch();
       
   333         if (sf > 1)
       
   334             sizer *= sf;
       
   335     }
       
   336     return sizer;
       
   337 }
       
   338 
       
   339 int QSplitterLayoutStruct::getHandleSize(Qt::Orientation orient)
       
   340 {
       
   341     return pick(handle->sizeHint(), orient);
       
   342 }
       
   343 
       
   344 void QSplitterPrivate::init()
       
   345 {
       
   346     Q_Q(QSplitter);
       
   347     QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Preferred);
       
   348     if (orient == Qt::Vertical)
       
   349         sp.transpose();
       
   350     q->setSizePolicy(sp);
       
   351     q->setAttribute(Qt::WA_WState_OwnSizePolicy, false);
       
   352 }
       
   353 
       
   354 void QSplitterPrivate::recalc(bool update)
       
   355 {
       
   356     Q_Q(QSplitter);
       
   357     int n = list.count();
       
   358     /*
       
   359       Splitter handles before the first visible widget or right
       
   360       before a hidden widget must be hidden.
       
   361     */
       
   362     bool first = true;
       
   363     for (int i = 0; i < n ; ++i) {
       
   364         QSplitterLayoutStruct *s = list.at(i);
       
   365         s->handle->setHidden(first || s->widget->isHidden());
       
   366         if (!s->widget->isHidden())
       
   367             first = false;
       
   368     }
       
   369 
       
   370     int fi = 2 * q->frameWidth();
       
   371     int maxl = fi;
       
   372     int minl = fi;
       
   373     int maxt = QWIDGETSIZE_MAX;
       
   374     int mint = fi;
       
   375     /*
       
   376       calculate min/max sizes for the whole splitter
       
   377     */
       
   378     bool empty = true;
       
   379     for (int j = 0; j < n; j++) {
       
   380         QSplitterLayoutStruct *s = list.at(j);
       
   381 
       
   382         if (!s->widget->isHidden()) {
       
   383             empty = false;
       
   384             if (!s->handle->isHidden()) {
       
   385                 minl += s->getHandleSize(orient);
       
   386                 maxl += s->getHandleSize(orient);
       
   387             }
       
   388 
       
   389             QSize minS = qSmartMinSize(s->widget);
       
   390             minl += pick(minS);
       
   391             maxl += pick(s->widget->maximumSize());
       
   392             mint = qMax(mint, trans(minS));
       
   393             int tm = trans(s->widget->maximumSize());
       
   394             if (tm > 0)
       
   395                 maxt = qMin(maxt, tm);
       
   396         }
       
   397     }
       
   398 
       
   399     if (empty) {
       
   400         if (qobject_cast<QSplitter *>(parent)) {
       
   401             // nested splitters; be nice
       
   402             maxl = maxt = 0;
       
   403         } else {
       
   404             // QSplitter with no children yet
       
   405             maxl = QWIDGETSIZE_MAX;
       
   406         }
       
   407     } else {
       
   408         maxl = qMin<int>(maxl, QWIDGETSIZE_MAX);
       
   409     }
       
   410     if (maxt < mint)
       
   411         maxt = mint;
       
   412 
       
   413     if (update) {
       
   414         if (orient == Qt::Horizontal) {
       
   415             q->setMaximumSize(maxl, maxt);
       
   416             if (q->isWindow())
       
   417                 q->setMinimumSize(minl,mint);
       
   418         } else {
       
   419             q->setMaximumSize(maxt, maxl);
       
   420             if (q->isWindow())
       
   421                 q->setMinimumSize(mint,minl);
       
   422         }
       
   423         doResize();
       
   424         q->updateGeometry();
       
   425     } else {
       
   426         firstShow = true;
       
   427     }
       
   428 }
       
   429 
       
   430 void QSplitterPrivate::doResize()
       
   431 {
       
   432     Q_Q(QSplitter);
       
   433     QRect r = q->contentsRect();
       
   434     int n = list.count();
       
   435     QVector<QLayoutStruct> a(n*2);
       
   436     int i;
       
   437 
       
   438     bool noStretchFactorsSet = true;
       
   439     for (i = 0; i < n; ++i) {
       
   440         QSizePolicy p = list.at(i)->widget->sizePolicy();
       
   441         int sf = orient == Qt::Horizontal ? p.horizontalStretch() : p.verticalStretch();
       
   442         if (sf != 0) {
       
   443             noStretchFactorsSet = false;
       
   444             break;
       
   445         }
       
   446     }
       
   447 
       
   448     int j=0;
       
   449     for (i = 0; i < n; ++i) {
       
   450         QSplitterLayoutStruct *s = list.at(i);
       
   451 #ifdef QSPLITTER_DEBUG
       
   452         qDebug("widget %d hidden: %d collapsed: %d handle hidden: %d", i, s->widget->isHidden(),
       
   453                s->collapsed, s->handle->isHidden());
       
   454 #endif
       
   455 
       
   456         a[j].init();
       
   457         if (s->handle->isHidden()) {
       
   458             a[j].maximumSize = 0;
       
   459         } else {
       
   460             a[j].sizeHint = a[j].minimumSize = a[j].maximumSize = s->getHandleSize(orient);
       
   461             a[j].empty = false;
       
   462         }
       
   463         ++j;
       
   464 
       
   465         a[j].init();
       
   466         if (s->widget->isHidden() || s->collapsed) {
       
   467             a[j].maximumSize = 0;
       
   468         } else {
       
   469             a[j].minimumSize = pick(qSmartMinSize(s->widget));
       
   470             a[j].maximumSize = pick(s->widget->maximumSize());
       
   471             a[j].empty = false;
       
   472 
       
   473             bool stretch = noStretchFactorsSet;
       
   474             if (!stretch) {
       
   475                 QSizePolicy p = s->widget->sizePolicy();
       
   476                 int sf = orient == Qt::Horizontal ? p.horizontalStretch() : p.verticalStretch();
       
   477                 stretch = (sf != 0);
       
   478             }
       
   479             if (stretch) {
       
   480                 a[j].stretch = s->getWidgetSize(orient);
       
   481                 a[j].sizeHint = a[j].minimumSize;
       
   482                 a[j].expansive = true;
       
   483             } else {
       
   484                 a[j].sizeHint = qMax(s->getWidgetSize(orient), a[j].minimumSize);
       
   485             }
       
   486         }
       
   487         ++j;
       
   488     }
       
   489 
       
   490     qGeomCalc(a, 0, n*2, pick(r.topLeft()), pick(r.size()), 0);
       
   491 
       
   492 #ifdef QSPLITTER_DEBUG
       
   493     for (i = 0; i < n*2; ++i) {
       
   494         qDebug("%*s%d: stretch %d, sh %d, minS %d, maxS %d, exp %d, emp %d -> %d, %d",
       
   495                i, "", i,
       
   496                a[i].stretch,
       
   497                a[i].sizeHint,
       
   498                a[i].minimumSize,
       
   499                a[i].maximumSize,
       
   500                a[i].expansive,
       
   501                a[i].empty,
       
   502                a[i].pos,
       
   503                a[i].size);
       
   504     }
       
   505 #endif
       
   506 
       
   507     for (i = 0; i < n; ++i) {
       
   508         QSplitterLayoutStruct *s = list.at(i);
       
   509         setGeo(s, a[i*2+1].pos, a[i*2+1].size, false);
       
   510     }
       
   511 }
       
   512 
       
   513 void QSplitterPrivate::storeSizes()
       
   514 {
       
   515     for (int i = 0; i < list.size(); ++i) {
       
   516         QSplitterLayoutStruct *sls = list.at(i);
       
   517         sls->sizer = pick(sls->rect.size());
       
   518     }
       
   519 }
       
   520 
       
   521 void QSplitterPrivate::addContribution(int index, int *min, int *max, bool mayCollapse) const
       
   522 {
       
   523     QSplitterLayoutStruct *s = list.at(index);
       
   524     if (!s->widget->isHidden()) {
       
   525         if (!s->handle->isHidden()) {
       
   526             *min += s->getHandleSize(orient);
       
   527             *max += s->getHandleSize(orient);
       
   528         }
       
   529         if (mayCollapse || !s->collapsed)
       
   530             *min += pick(qSmartMinSize(s->widget));
       
   531 
       
   532         *max += pick(s->widget->maximumSize());
       
   533     }
       
   534 }
       
   535 
       
   536 int QSplitterPrivate::findWidgetJustBeforeOrJustAfter(int index, int delta, int &collapsibleSize) const
       
   537 {
       
   538     if (delta < 0)
       
   539         index += delta;
       
   540     do {
       
   541         QWidget *w = list.at(index)->widget;
       
   542         if (!w->isHidden()) {
       
   543             if (collapsible(list.at(index)))
       
   544                 collapsibleSize = pick(qSmartMinSize(w));
       
   545             return index;
       
   546         }
       
   547         index += delta;
       
   548     } while (index >= 0 && index < list.count());
       
   549 
       
   550     return -1;
       
   551 }
       
   552 
       
   553 /*
       
   554   For the splitter handle with index \a index, \a min and \a max give the range without collapsing any widgets,
       
   555   and \a farMin and farMax give the range with collapsing included.
       
   556 */
       
   557 void QSplitterPrivate::getRange(int index, int *farMin, int *min, int *max, int *farMax) const
       
   558 {
       
   559     Q_Q(const QSplitter);
       
   560     int n = list.count();
       
   561     if (index <= 0 || index >= n)
       
   562         return;
       
   563 
       
   564     int collapsibleSizeBefore = 0;
       
   565     int idJustBefore = findWidgetJustBeforeOrJustAfter(index, -1, collapsibleSizeBefore);
       
   566 
       
   567     int collapsibleSizeAfter = 0;
       
   568     int idJustAfter = findWidgetJustBeforeOrJustAfter(index, +1, collapsibleSizeAfter);
       
   569 
       
   570     int minBefore = 0;
       
   571     int minAfter = 0;
       
   572     int maxBefore = 0;
       
   573     int maxAfter = 0;
       
   574     int i;
       
   575 
       
   576     for (i = 0; i < index; ++i)
       
   577         addContribution(i, &minBefore, &maxBefore, i == idJustBefore);
       
   578     for (i = index; i < n; ++i)
       
   579         addContribution(i, &minAfter, &maxAfter, i == idJustAfter);
       
   580 
       
   581     QRect r = q->contentsRect();
       
   582     int farMinVal;
       
   583     int minVal;
       
   584     int maxVal;
       
   585     int farMaxVal;
       
   586 
       
   587     int smartMinBefore = qMax(minBefore, pick(r.size()) - maxAfter);
       
   588     int smartMaxBefore = qMin(maxBefore, pick(r.size()) - minAfter);
       
   589 
       
   590     minVal = pick(r.topLeft()) + smartMinBefore;
       
   591     maxVal = pick(r.topLeft()) + smartMaxBefore;
       
   592 
       
   593     farMinVal = minVal;
       
   594     if (minBefore - collapsibleSizeBefore >= pick(r.size()) - maxAfter)
       
   595         farMinVal -= collapsibleSizeBefore;
       
   596     farMaxVal = maxVal;
       
   597     if (pick(r.size()) - (minAfter - collapsibleSizeAfter) <= maxBefore)
       
   598         farMaxVal += collapsibleSizeAfter;
       
   599 
       
   600     if (farMin)
       
   601         *farMin = farMinVal;
       
   602     if (min)
       
   603         *min = minVal;
       
   604     if (max)
       
   605         *max = maxVal;
       
   606     if (farMax)
       
   607         *farMax = farMaxVal;
       
   608 }
       
   609 
       
   610 int QSplitterPrivate::adjustPos(int pos, int index, int *farMin, int *min, int *max, int *farMax) const
       
   611 {
       
   612     const int Threshold = 40;
       
   613 
       
   614     getRange(index, farMin, min, max, farMax);
       
   615 
       
   616     if (pos >= *min) {
       
   617         if (pos <= *max) {
       
   618             return pos;
       
   619         } else {
       
   620             int delta = pos - *max;
       
   621             int width = *farMax - *max;
       
   622 
       
   623             if (delta > width / 2 && delta >= qMin(Threshold, width)) {
       
   624                 return *farMax;
       
   625             } else {
       
   626                 return *max;
       
   627             }
       
   628         }
       
   629     } else {
       
   630         int delta = *min - pos;
       
   631         int width = *min - *farMin;
       
   632 
       
   633         if (delta > width / 2 && delta >= qMin(Threshold, width)) {
       
   634             return *farMin;
       
   635         } else {
       
   636             return *min;
       
   637         }
       
   638     }
       
   639 }
       
   640 
       
   641 bool QSplitterPrivate::collapsible(QSplitterLayoutStruct *s) const
       
   642 {
       
   643     if (s->collapsible != Default) {
       
   644         return (bool)s->collapsible;
       
   645     } else {
       
   646         return childrenCollapsible;
       
   647     }
       
   648 }
       
   649 
       
   650 void QSplitterPrivate::updateHandles()
       
   651 {
       
   652     Q_Q(QSplitter);
       
   653     recalc(q->isVisible());
       
   654 }
       
   655 
       
   656 void QSplitterPrivate::setSizes_helper(const QList<int> &sizes, bool clampNegativeSize)
       
   657 {
       
   658     int j = 0;
       
   659 
       
   660     for (int i = 0; i < list.size(); ++i) {
       
   661         QSplitterLayoutStruct *s = list.at(i);
       
   662 
       
   663         s->collapsed = false;
       
   664         s->sizer = sizes.value(j++);
       
   665         if (clampNegativeSize && s->sizer < 0)
       
   666             s->sizer = 0;
       
   667         int smartMinSize = pick(qSmartMinSize(s->widget));
       
   668 
       
   669         // Make sure that we reset the collapsed state.
       
   670         if (s->sizer == 0) {
       
   671             if (collapsible(s) && smartMinSize > 0) {
       
   672                 s->collapsed = true;
       
   673             } else {
       
   674                 s->sizer = smartMinSize;
       
   675             }
       
   676         } else {
       
   677             if (s->sizer < smartMinSize)
       
   678                 s->sizer = smartMinSize;
       
   679         }
       
   680     }
       
   681     doResize();
       
   682 }
       
   683 
       
   684 void QSplitterPrivate::setGeo(QSplitterLayoutStruct *sls, int p, int s, bool allowCollapse)
       
   685 {
       
   686     Q_Q(QSplitter);
       
   687     QWidget *w = sls->widget;
       
   688     QRect r;
       
   689     QRect contents = q->contentsRect();
       
   690     if (orient == Qt::Horizontal) {
       
   691         r.setRect(p, contents.y(), s, contents.height());
       
   692     } else {
       
   693         r.setRect(contents.x(), p, contents.width(), s);
       
   694     }
       
   695     sls->rect = r;
       
   696 
       
   697     int minSize = pick(qSmartMinSize(w));
       
   698 
       
   699     if (orient == Qt::Horizontal && q->isRightToLeft())
       
   700         r.moveRight(contents.width() - r.left());
       
   701 
       
   702     if (allowCollapse)
       
   703         sls->collapsed = s <= 0 && minSize > 0 && !w->isHidden();
       
   704 
       
   705     //   Hide the child widget, but without calling hide() so that
       
   706     //   the splitter handle is still shown.
       
   707     if (sls->collapsed)
       
   708         r.moveTopLeft(QPoint(-r.width()-1, -r.height()-1));
       
   709 
       
   710     w->setGeometry(r);
       
   711 
       
   712     if (!sls->handle->isHidden()) {
       
   713         QSplitterHandle *h = sls->handle;
       
   714         QSize hs = h->sizeHint();
       
   715         int left, top, right, bottom;
       
   716         h->getContentsMargins(&left, &top, &right, &bottom);
       
   717         if (orient==Qt::Horizontal) {
       
   718             if (q->isRightToLeft())
       
   719                 p = contents.width() - p + hs.width();
       
   720             h->setGeometry(p-hs.width() - left, contents.y(), hs.width() + left + right, contents.height());
       
   721         } else {
       
   722             h->setGeometry(contents.x(), p-hs.height() - top, contents.width(), hs.height() + top + bottom);
       
   723         }
       
   724     }
       
   725 }
       
   726 
       
   727 void QSplitterPrivate::doMove(bool backwards, int hPos, int index, int delta, bool mayCollapse,
       
   728                               int *positions, int *widths)
       
   729 {
       
   730     if (index < 0 || index >= list.count())
       
   731         return;
       
   732 
       
   733 #ifdef QSPLITTER_DEBUG
       
   734     qDebug() << "QSplitterPrivate::doMove" << backwards << hPos << index << delta << mayCollapse;
       
   735 #endif
       
   736 
       
   737     QSplitterLayoutStruct *s = list.at(index);
       
   738     QWidget *w = s->widget;
       
   739 
       
   740     int nextId = backwards ? index - delta : index + delta;
       
   741 
       
   742     if (w->isHidden()) {
       
   743         doMove(backwards, hPos, nextId, delta, collapsible(nextId), positions, widths);
       
   744     } else {
       
   745         int hs =s->handle->isHidden() ? 0 : s->getHandleSize(orient);
       
   746 
       
   747         int  ws = backwards ? hPos - pick(s->rect.topLeft())
       
   748                  : pick(s->rect.bottomRight()) - hPos -hs + 1;
       
   749         if (ws > 0 || (!s->collapsed && !mayCollapse)) {
       
   750             ws = qMin(ws, pick(w->maximumSize()));
       
   751             ws = qMax(ws, pick(qSmartMinSize(w)));
       
   752         } else {
       
   753             ws = 0;
       
   754         }
       
   755         positions[index] = backwards ? hPos - ws : hPos + hs;
       
   756         widths[index] = ws;
       
   757         doMove(backwards, backwards ? hPos - ws - hs : hPos + hs + ws, nextId, delta,
       
   758                collapsible(nextId), positions, widths);
       
   759     }
       
   760 
       
   761 }
       
   762 
       
   763 QSplitterLayoutStruct *QSplitterPrivate::findWidget(QWidget *w) const
       
   764 {
       
   765     for (int i = 0; i < list.size(); ++i) {
       
   766         if (list.at(i)->widget == w)
       
   767             return list.at(i);
       
   768     }
       
   769     return 0;
       
   770 }
       
   771 
       
   772 #ifdef QT3_SUPPORT
       
   773 static void setStretch(QWidget *w, int sf)
       
   774 {
       
   775     QSizePolicy sp = w->sizePolicy();
       
   776     sp.setHorizontalStretch(sf);
       
   777     sp.setVerticalStretch(sf);
       
   778     w->setSizePolicy(sp);
       
   779 }
       
   780 
       
   781 static int getStretch(const QWidget *w)
       
   782 {
       
   783     QSizePolicy sp = w->sizePolicy();
       
   784     return qMax(sp.horizontalStretch(), sp.verticalStretch());
       
   785 }
       
   786 
       
   787 void QSplitter::setResizeMode(QWidget *w, ResizeMode mode)
       
   788 {
       
   789     /*
       
   790         Internal comment:
       
   791 
       
   792         This function tries to simulate the Qt 3.x ResizeMode
       
   793         behavior using QSizePolicy stretch factors. This isn't easy,
       
   794         because the default \l ResizeMode was \l Stretch, not \l
       
   795         KeepSize, whereas the default stetch factor is 0.
       
   796 
       
   797         So what we do is this: When the user calls setResizeMode()
       
   798         the first time, we iterate through all the child widgets and
       
   799         set their stretch factors to 1. Later on, if children are
       
   800         added (using addWidget()), their stretch factors are also set
       
   801         to 1.
       
   802 
       
   803         There is just one problem left: Often, setResizeMode() is
       
   804         called \e{before} addWidget(), because addWidget() is called
       
   805         from the event loop. In that case, we use a special value,
       
   806         243, instead of 0 to prevent 0 from being overwritten with 1
       
   807         in addWidget(). This is a wicked hack, but fortunately it
       
   808         only occurs as a result of calling a \c QT3_SUPPORT function.
       
   809     */
       
   810 
       
   811     Q_D(QSplitter);
       
   812     bool metWidget = false;
       
   813     if (!d->compatMode) {
       
   814         d->compatMode = true;
       
   815         for (int i = 0; i < d->list.size(); ++i) {
       
   816             QSplitterLayoutStruct *s = d->list.at(i);
       
   817             if (s->widget == w)
       
   818                 metWidget = true;
       
   819             if (getStretch(s->widget) == 0)
       
   820                 setStretch(s->widget, 1);
       
   821         }
       
   822     }
       
   823     int sf;
       
   824     if (mode == KeepSize)
       
   825         sf = metWidget ? 0 : 243;
       
   826     else
       
   827         sf = 1;
       
   828     setStretch(w, sf);
       
   829 }
       
   830 
       
   831 /*!
       
   832     Use one of the constructors that doesn't take the \a name
       
   833     argument and then use setObjectName() instead.
       
   834 */
       
   835 QSplitter::QSplitter(QWidget *parent, const char *name)
       
   836     : QFrame(*new QSplitterPrivate, parent)
       
   837 {
       
   838     Q_D(QSplitter);
       
   839     setObjectName(QString::fromAscii(name));
       
   840     d->orient = Qt::Horizontal;
       
   841     d->init();
       
   842 }
       
   843 
       
   844 
       
   845 /*!
       
   846     Use one of the constructors that don't take the \a name argument
       
   847     and then use setObjectName() instead.
       
   848 */
       
   849 QSplitter::QSplitter(Qt::Orientation orientation, QWidget *parent, const char *name)
       
   850     : QFrame(*new QSplitterPrivate, parent)
       
   851 {
       
   852     Q_D(QSplitter);
       
   853     setObjectName(QString::fromAscii(name));
       
   854     d->orient = orientation;
       
   855     d->init();
       
   856 }
       
   857 #endif
       
   858 
       
   859 /*!
       
   860     \internal
       
   861 */
       
   862 void QSplitterPrivate::insertWidget_helper(int index, QWidget *widget, bool show)
       
   863 {
       
   864     Q_Q(QSplitter);
       
   865     QBoolBlocker b(blockChildAdd);
       
   866     bool needShow = show && q->isVisible() &&
       
   867                     !(widget->isHidden() && widget->testAttribute(Qt::WA_WState_ExplicitShowHide));
       
   868     if (widget->parentWidget() != q)
       
   869         widget->setParent(q);
       
   870     if (needShow)
       
   871         widget->show();
       
   872     insertWidget(index, widget);
       
   873     recalc(q->isVisible());
       
   874 }
       
   875 
       
   876 /*
       
   877     Inserts the widget \a w at position \a index in the splitter's list of widgets.
       
   878 
       
   879     If \a w is already in the splitter, it will be moved to the new position.
       
   880 */
       
   881 
       
   882 QSplitterLayoutStruct *QSplitterPrivate::insertWidget(int index, QWidget *w)
       
   883 {
       
   884     Q_Q(QSplitter);
       
   885     QSplitterLayoutStruct *sls = 0;
       
   886     int i;
       
   887     int last = list.count();
       
   888     for (i = 0; i < list.size(); ++i) {
       
   889         QSplitterLayoutStruct *s = list.at(i);
       
   890         if (s->widget == w) {
       
   891             sls = s;
       
   892             --last;
       
   893             break;
       
   894         }
       
   895     }
       
   896     if (index < 0 || index > last)
       
   897         index = last;
       
   898 
       
   899     if (sls) {
       
   900         list.move(i,index);
       
   901     } else {
       
   902         QSplitterHandle *newHandle = 0;
       
   903         sls = new QSplitterLayoutStruct;
       
   904         QString tmp = QLatin1String("qt_splithandle_");
       
   905         tmp += w->objectName();
       
   906         newHandle = q->createHandle();
       
   907         newHandle->setObjectName(tmp);
       
   908         sls->handle = newHandle;
       
   909         sls->widget = w;
       
   910         w->lower();
       
   911         list.insert(index,sls);
       
   912 
       
   913         if (newHandle && q->isVisible())
       
   914             newHandle->show(); // will trigger sending of post events
       
   915 
       
   916 #ifdef QT3_SUPPORT
       
   917         if (compatMode) {
       
   918             int sf = getStretch(sls->widget);
       
   919             if (sf == 243)
       
   920                 setStretch(sls->widget, 0);
       
   921             else if (sf == 0)
       
   922                 setStretch(sls->widget, 1);
       
   923         }
       
   924 #endif
       
   925     }
       
   926     return sls;
       
   927 }
       
   928 
       
   929 /*!
       
   930     \class QSplitter
       
   931     \brief The QSplitter class implements a splitter widget.
       
   932 
       
   933     \ingroup organizers
       
   934 
       
   935 
       
   936     A splitter lets the user control the size of child widgets by dragging the
       
   937     boundary between the children. Any number of widgets may be controlled by a
       
   938     single splitter. The typical use of a QSplitter is to create several
       
   939     widgets and add them using insertWidget() or addWidget().
       
   940 
       
   941     The following example will show a QListView, QTreeView, and
       
   942     QTextEdit side by side, with two splitter handles:
       
   943 
       
   944     \snippet doc/src/snippets/splitter/splitter.cpp 0
       
   945 
       
   946     If a widget is already inside a QSplitter when insertWidget() or
       
   947     addWidget() is called, it will move to the new position. This can be used
       
   948     to reorder widgets in the splitter later. You can use indexOf(),
       
   949     widget(), and count() to get access to the widgets inside the splitter.
       
   950 
       
   951     A default QSplitter lays out its children horizontally (side by side); you
       
   952     can use setOrientation(Qt::Vertical) to lay its
       
   953     children out vertically.
       
   954 
       
   955     By default, all widgets can be as large or as small as the user
       
   956     wishes, between the \l minimumSizeHint() (or \l minimumSize())
       
   957     and \l maximumSize() of the widgets.
       
   958 
       
   959     QSplitter resizes its children dynamically by default. If you
       
   960     would rather have QSplitter resize the children only at the end of
       
   961     a resize operation, call setOpaqueResize(false).
       
   962 
       
   963     The initial distribution of size between the widgets is determined by
       
   964     multiplying the initial size with the stretch factor.
       
   965     You can also use setSizes() to set the sizes
       
   966     of all the widgets. The function sizes() returns the sizes set by the user.
       
   967     Alternatively, you can save and restore the sizes of the widgets from a
       
   968     QByteArray using saveState() and restoreState() respectively.
       
   969 
       
   970     When you hide() a child its space will be distributed among the
       
   971     other children. It will be reinstated when you show() it again.
       
   972 
       
   973     \sa QSplitterHandle, QHBoxLayout, QVBoxLayout, QTabWidget
       
   974 */
       
   975 
       
   976 
       
   977 /*!
       
   978     Constructs a horizontal splitter with the \a parent
       
   979     arguments is passed on to the QFrame constructor.
       
   980 
       
   981     \sa setOrientation()
       
   982 */
       
   983 QSplitter::QSplitter(QWidget *parent)
       
   984     : QFrame(*new QSplitterPrivate, parent)
       
   985 {
       
   986     Q_D(QSplitter);
       
   987     d->orient = Qt::Horizontal;
       
   988     d->init();
       
   989 }
       
   990 
       
   991 
       
   992 /*!
       
   993     Constructs a splitter with the given \a orientation and \a parent.
       
   994 
       
   995     \sa setOrientation()
       
   996 */
       
   997 QSplitter::QSplitter(Qt::Orientation orientation, QWidget *parent)
       
   998     : QFrame(*new QSplitterPrivate, parent)
       
   999 {
       
  1000     Q_D(QSplitter);
       
  1001     d->orient = orientation;
       
  1002     d->init();
       
  1003 }
       
  1004 
       
  1005 
       
  1006 /*!
       
  1007     Destroys the splitter. All children are deleted.
       
  1008 */
       
  1009 
       
  1010 QSplitter::~QSplitter()
       
  1011 {
       
  1012     Q_D(QSplitter);
       
  1013     delete d->rubberBand;
       
  1014     while (!d->list.isEmpty())
       
  1015         delete d->list.takeFirst();
       
  1016 }
       
  1017 
       
  1018 /*!
       
  1019     Updates the splitter's state. You should not need to call this
       
  1020     function.
       
  1021 */
       
  1022 void QSplitter::refresh()
       
  1023 {
       
  1024     Q_D(QSplitter);
       
  1025     d->recalc(true);
       
  1026 }
       
  1027 
       
  1028 /*!
       
  1029     \property QSplitter::orientation
       
  1030     \brief the orientation of the splitter
       
  1031 
       
  1032     By default the orientation is horizontal (i.e., the widgets are
       
  1033     laid out side by side). The possible orientations are
       
  1034     Qt::Horizontal and Qt::Vertical.
       
  1035 
       
  1036     \sa QSplitterHandle::orientation()
       
  1037 */
       
  1038 
       
  1039 void QSplitter::setOrientation(Qt::Orientation orientation)
       
  1040 {
       
  1041     Q_D(QSplitter);
       
  1042     if (d->orient == orientation)
       
  1043         return;
       
  1044 
       
  1045     if (!testAttribute(Qt::WA_WState_OwnSizePolicy)) {
       
  1046         QSizePolicy sp = sizePolicy();
       
  1047         sp.transpose();
       
  1048         setSizePolicy(sp);
       
  1049         setAttribute(Qt::WA_WState_OwnSizePolicy, false);
       
  1050     }
       
  1051 
       
  1052     d->orient = orientation;
       
  1053 
       
  1054     for (int i = 0; i < d->list.size(); ++i) {
       
  1055         QSplitterLayoutStruct *s = d->list.at(i);
       
  1056         s->handle->setOrientation(orientation);
       
  1057     }
       
  1058     d->recalc(isVisible());
       
  1059 }
       
  1060 
       
  1061 Qt::Orientation QSplitter::orientation() const
       
  1062 {
       
  1063     Q_D(const QSplitter);
       
  1064     return d->orient;
       
  1065 }
       
  1066 
       
  1067 /*!
       
  1068     \property QSplitter::childrenCollapsible
       
  1069     \brief whether child widgets can be resized down to size 0 by the user
       
  1070 
       
  1071     By default, children are collapsible. It is possible to enable
       
  1072     and disable the collapsing of individual children using
       
  1073     setCollapsible().
       
  1074 
       
  1075     \sa setCollapsible()
       
  1076 */
       
  1077 
       
  1078 void QSplitter::setChildrenCollapsible(bool collapse)
       
  1079 {
       
  1080     Q_D(QSplitter);
       
  1081     d->childrenCollapsible = collapse;
       
  1082 }
       
  1083 
       
  1084 bool QSplitter::childrenCollapsible() const
       
  1085 {
       
  1086     Q_D(const QSplitter);
       
  1087     return d->childrenCollapsible;
       
  1088 }
       
  1089 
       
  1090 /*!
       
  1091     Sets whether the child widget at index \a index is collapsible to \a collapse.
       
  1092 
       
  1093     By default, children are collapsible, meaning that the user can
       
  1094     resize them down to size 0, even if they have a non-zero
       
  1095     minimumSize() or minimumSizeHint(). This behavior can be changed
       
  1096     on a per-widget basis by calling this function, or globally for
       
  1097     all the widgets in the splitter by setting the \l
       
  1098     childrenCollapsible property.
       
  1099 
       
  1100     \sa childrenCollapsible
       
  1101 */
       
  1102 
       
  1103 void QSplitter::setCollapsible(int index, bool collapse)
       
  1104 {
       
  1105     Q_D(QSplitter);
       
  1106 
       
  1107     if (index < 0 || index >= d->list.size()) {
       
  1108         qWarning("QSplitter::setCollapsible: Index %d out of range", index);
       
  1109         return;
       
  1110     }
       
  1111     d->list.at(index)->collapsible = collapse ? 1 : 0;
       
  1112 }
       
  1113 
       
  1114 /*!
       
  1115     Returns true if the widget at \a index is collapsible, otherwise returns false
       
  1116 */
       
  1117 bool QSplitter::isCollapsible(int index) const
       
  1118 {
       
  1119     Q_D(const QSplitter);
       
  1120     if (index < 0 || index >= d->list.size()) {
       
  1121         qWarning("QSplitter::isCollapsible: Index %d out of range", index);
       
  1122         return false;
       
  1123     }
       
  1124     return d->list.at(index)->collapsible;
       
  1125 }
       
  1126 
       
  1127 /*!
       
  1128     \reimp
       
  1129 */
       
  1130 void QSplitter::resizeEvent(QResizeEvent *)
       
  1131 {
       
  1132     Q_D(QSplitter);
       
  1133     d->doResize();
       
  1134 }
       
  1135 
       
  1136 /*!
       
  1137     Adds the given \a widget to the splitter's layout after all the other
       
  1138     items.
       
  1139 
       
  1140     If \a widget is already in the splitter, it will be moved to the new position.
       
  1141 
       
  1142     \sa insertWidget() widget() indexOf()
       
  1143 */
       
  1144 void QSplitter::addWidget(QWidget *widget)
       
  1145 {
       
  1146     Q_D(QSplitter);
       
  1147     insertWidget(d->list.count(), widget);
       
  1148 }
       
  1149 
       
  1150 /*!
       
  1151     Inserts the \a widget specified into the splitter's layout at the
       
  1152     given \a index.
       
  1153 
       
  1154     If \a widget is already in the splitter, it will be moved to the new position.
       
  1155 
       
  1156     if \a index is an invalid index, then the widget will be inserted at the end.
       
  1157 
       
  1158     \sa addWidget() indexOf() widget()
       
  1159 */
       
  1160 void QSplitter::insertWidget(int index, QWidget *widget)
       
  1161 {
       
  1162     Q_D(QSplitter);
       
  1163     d->insertWidget_helper(index, widget, true);
       
  1164 }
       
  1165 
       
  1166 /*!
       
  1167     \fn int QSplitter::indexOf(QWidget *widget) const
       
  1168 
       
  1169     Returns the index in the splitter's layout of the specified \a widget. This
       
  1170     also works for handles.
       
  1171 
       
  1172     Handles are numbered from 0. There are as many handles as there
       
  1173     are child widgets, but the handle at position 0 is always hidden.
       
  1174 
       
  1175 
       
  1176     \sa count(), widget()
       
  1177 */
       
  1178 int QSplitter::indexOf(QWidget *w) const
       
  1179 {
       
  1180     Q_D(const QSplitter);
       
  1181     for (int i = 0; i < d->list.size(); ++i) {
       
  1182         QSplitterLayoutStruct *s = d->list.at(i);
       
  1183         if (s->widget == w || s->handle == w)
       
  1184             return i;
       
  1185     }
       
  1186     return -1;
       
  1187 }
       
  1188 
       
  1189 /*!
       
  1190     Returns a new splitter handle as a child widget of this splitter.
       
  1191     This function can be reimplemented in subclasses to provide support
       
  1192     for custom handles.
       
  1193 
       
  1194     \sa handle(), indexOf()
       
  1195 */
       
  1196 QSplitterHandle *QSplitter::createHandle()
       
  1197 {
       
  1198     Q_D(QSplitter);
       
  1199     return new QSplitterHandle(d->orient, this);
       
  1200 }
       
  1201 
       
  1202 /*!
       
  1203     Returns the handle to the left (or above) for the item in the
       
  1204     splitter's layout at the given \a index. The handle at index 0 is
       
  1205     always hidden.
       
  1206 
       
  1207     For right-to-left languages such as Arabic and Hebrew, the layout
       
  1208     of horizontal splitters is reversed. The handle will be to the
       
  1209     right of the widget at \a index.
       
  1210 
       
  1211     \sa count(), widget(), indexOf(), createHandle(), setHandleWidth()
       
  1212 */
       
  1213 QSplitterHandle *QSplitter::handle(int index) const
       
  1214 {
       
  1215     Q_D(const QSplitter);
       
  1216     if (index < 0 || index >= d->list.size())
       
  1217         return 0;
       
  1218     return d->list.at(index)->handle;
       
  1219 }
       
  1220 
       
  1221 /*!
       
  1222     Returns the widget at the given \a index in the splitter's layout.
       
  1223 
       
  1224     \sa count(), handle(), indexOf(), insertWidget()
       
  1225 */
       
  1226 QWidget *QSplitter::widget(int index) const
       
  1227 {
       
  1228     Q_D(const QSplitter);
       
  1229     if (index < 0 || index >= d->list.size())
       
  1230         return 0;
       
  1231     return d->list.at(index)->widget;
       
  1232 }
       
  1233 
       
  1234 /*!
       
  1235     Returns the number of widgets contained in the splitter's layout.
       
  1236 
       
  1237     \sa widget(), handle()
       
  1238 */
       
  1239 int QSplitter::count() const
       
  1240 {
       
  1241     Q_D(const QSplitter);
       
  1242     return d->list.count();
       
  1243 }
       
  1244 
       
  1245 /*!
       
  1246     \reimp
       
  1247 
       
  1248     Tells the splitter that the child widget described by \a c has been
       
  1249     inserted or removed.
       
  1250 
       
  1251     This method is also used to handle the situation where a widget is created
       
  1252     with the splitter as a parent but not explicitly added with insertWidget()
       
  1253     or addWidget(). This is for compatibility and not the recommended way of
       
  1254     putting widgets into a splitter in new code. Please use insertWidget() or
       
  1255     addWidget() in new code.
       
  1256 
       
  1257     \sa addWidget() insertWidget()
       
  1258 */
       
  1259 
       
  1260 void QSplitter::childEvent(QChildEvent *c)
       
  1261 {
       
  1262     Q_D(QSplitter);
       
  1263     if (!c->child()->isWidgetType())
       
  1264         return;
       
  1265     QWidget *w = static_cast<QWidget*>(c->child());
       
  1266 
       
  1267     if (c->added() && !d->blockChildAdd && !w->isWindow() && !d->findWidget(w)) {
       
  1268         d->insertWidget_helper(d->list.count(), w, false);
       
  1269     } else if (c->polished() && !d->blockChildAdd) {
       
  1270         if (isVisible() && !(w->isHidden() && w->testAttribute(Qt::WA_WState_ExplicitShowHide)))
       
  1271             w->show();
       
  1272     } else if (c->type() == QEvent::ChildRemoved) {
       
  1273         for (int i = 0; i < d->list.size(); ++i) {
       
  1274             QSplitterLayoutStruct *s = d->list.at(i);
       
  1275             if (s->widget == w) {
       
  1276                 d->list.removeAt(i);
       
  1277                 delete s;
       
  1278                 d->recalc(isVisible());
       
  1279                 return;
       
  1280             }
       
  1281         }
       
  1282     }
       
  1283 }
       
  1284 
       
  1285 
       
  1286 /*!
       
  1287     Displays a rubber band at position \a pos. If \a pos is negative, the
       
  1288     rubber band is removed.
       
  1289 */
       
  1290 
       
  1291 void QSplitter::setRubberBand(int pos)
       
  1292 {
       
  1293     Q_D(QSplitter);
       
  1294     if (pos < 0) {
       
  1295         if (d->rubberBand)
       
  1296             QTimer::singleShot(0, d->rubberBand, SLOT(deleteLater()));
       
  1297         return;
       
  1298     }
       
  1299     QRect r = contentsRect();
       
  1300     const int rBord = 3; // customizable?
       
  1301     int hw = handleWidth();
       
  1302     if (!d->rubberBand) {
       
  1303         d->rubberBand = new QRubberBand(QRubberBand::Line);
       
  1304         // For accessibility to identify this special widget.
       
  1305         d->rubberBand->setObjectName(QLatin1String("qt_rubberband"));
       
  1306     }
       
  1307     if (d->orient == Qt::Horizontal)
       
  1308         d->rubberBand->setGeometry(QRect(QPoint(pos + hw / 2 - rBord, r.y()),
       
  1309                                          QSize(2 * rBord, r.height())).translated(mapToGlobal(QPoint())));
       
  1310     else
       
  1311         d->rubberBand->setGeometry(QRect(QPoint(r.x(), pos + hw / 2 - rBord),
       
  1312                                    QSize(r.width(), 2 * rBord)).translated(mapToGlobal(QPoint())));
       
  1313     if (!d->rubberBand->isVisible())
       
  1314         d->rubberBand->show();
       
  1315 }
       
  1316 
       
  1317 /*!
       
  1318     \reimp
       
  1319 */
       
  1320 
       
  1321 bool QSplitter::event(QEvent *e)
       
  1322 {
       
  1323     Q_D(QSplitter);
       
  1324     switch (e->type()) {
       
  1325     case QEvent::Hide:
       
  1326         // Reset firstShow to false here since things can be done to the splitter in between
       
  1327         if (!d->firstShow)
       
  1328             d->firstShow = true;
       
  1329         break;
       
  1330     case QEvent::Show:
       
  1331         if (!d->firstShow)
       
  1332             break;
       
  1333         d->firstShow = false;
       
  1334         // fall through
       
  1335     case QEvent::HideToParent:
       
  1336     case QEvent::ShowToParent:
       
  1337     case QEvent::LayoutRequest:
       
  1338 #ifdef QT3_SUPPORT
       
  1339     case QEvent::LayoutHint:
       
  1340 #endif
       
  1341         d->recalc(isVisible());
       
  1342         break;
       
  1343     default:
       
  1344         ;
       
  1345     }
       
  1346     return QWidget::event(e);
       
  1347 }
       
  1348 
       
  1349 /*!
       
  1350     \fn QSplitter::splitterMoved(int pos, int index)
       
  1351 
       
  1352     This signal is emitted when the splitter handle at a particular \a
       
  1353     index has been moved to position \a pos.
       
  1354 
       
  1355     For right-to-left languages such as Arabic and Hebrew, the layout
       
  1356     of horizontal splitters is reversed. \a pos is then the
       
  1357     distance from the right edge of the widget.
       
  1358 
       
  1359     \sa moveSplitter()
       
  1360 */
       
  1361 
       
  1362 /*!
       
  1363     Moves the left or top edge of the splitter handle at \a index as
       
  1364     close as possible to position \a pos, which is the distance from the
       
  1365     left or top edge of the widget.
       
  1366 
       
  1367     For right-to-left languages such as Arabic and Hebrew, the layout
       
  1368     of horizontal splitters is reversed. \a pos is then the distance
       
  1369     from the right edge of the widget.
       
  1370 
       
  1371     \sa splitterMoved(), closestLegalPosition(), getRange()
       
  1372 */
       
  1373 void QSplitter::moveSplitter(int pos, int index)
       
  1374 {
       
  1375     Q_D(QSplitter);
       
  1376     QSplitterLayoutStruct *s = d->list.at(index);
       
  1377     int farMin;
       
  1378     int min;
       
  1379     int max;
       
  1380     int farMax;
       
  1381 
       
  1382 #ifdef QSPLITTER_DEBUG
       
  1383     int debugp = pos;
       
  1384 #endif
       
  1385 
       
  1386     pos = d->adjustPos(pos, index, &farMin, &min, &max, &farMax);
       
  1387     int oldP = d->pick(s->rect.topLeft());
       
  1388 #ifdef QSPLITTER_DEBUG
       
  1389     qDebug() << "QSplitter::moveSplitter" << debugp << index << "adjusted" << pos << "oldP" << oldP;
       
  1390 #endif
       
  1391 
       
  1392     QVarLengthArray<int, 32> poss(d->list.count());
       
  1393     QVarLengthArray<int, 32> ws(d->list.count());
       
  1394     bool upLeft;
       
  1395 
       
  1396     d->doMove(false, pos, index, +1, (d->collapsible(s) && (pos > max)), poss.data(), ws.data());
       
  1397     d->doMove(true, pos, index - 1, +1, (d->collapsible(index - 1) && (pos < min)), poss.data(), ws.data());
       
  1398     upLeft = (pos < oldP);
       
  1399 
       
  1400     int wid, delta, count = d->list.count();
       
  1401     if (upLeft) {
       
  1402         wid = 0;
       
  1403         delta = 1;
       
  1404     } else {
       
  1405         wid = count - 1;
       
  1406         delta = -1;
       
  1407     }
       
  1408     for (; wid >= 0 && wid < count; wid += delta) {
       
  1409         QSplitterLayoutStruct *sls = d->list.at( wid );
       
  1410         if (!sls->widget->isHidden())
       
  1411             d->setGeo(sls, poss[wid], ws[wid], true);
       
  1412     }
       
  1413     d->storeSizes();
       
  1414 
       
  1415     emit splitterMoved(pos, index);
       
  1416 }
       
  1417 
       
  1418 
       
  1419 /*!
       
  1420     Returns the valid range of the splitter with index \a index in
       
  1421     *\a{min} and *\a{max} if \a min and \a max are not 0.
       
  1422 */
       
  1423 
       
  1424 void QSplitter::getRange(int index, int *min, int *max) const
       
  1425 {
       
  1426     Q_D(const QSplitter);
       
  1427     d->getRange(index, min, 0, 0, max);
       
  1428 }
       
  1429 
       
  1430 
       
  1431 /*!
       
  1432     Returns the closest legal position to \a pos of the widget with index
       
  1433     \a index.
       
  1434 
       
  1435     For right-to-left languages such as Arabic and Hebrew, the layout
       
  1436     of horizontal splitters is reversed. Positions are then measured
       
  1437     from the right edge of the widget.
       
  1438 
       
  1439     \sa getRange()
       
  1440 */
       
  1441 
       
  1442 int QSplitter::closestLegalPosition(int pos, int index)
       
  1443 {
       
  1444     Q_D(QSplitter);
       
  1445     int x, i, n, u;
       
  1446     return d->adjustPos(pos, index, &u, &n, &i, &x);
       
  1447 }
       
  1448 
       
  1449 /*!
       
  1450     \property QSplitter::opaqueResize
       
  1451     \brief whether resizing is opaque
       
  1452 
       
  1453     Opaque resizing is on by default.
       
  1454 */
       
  1455 
       
  1456 bool QSplitter::opaqueResize() const
       
  1457 {
       
  1458     Q_D(const QSplitter);
       
  1459     return d->opaque;
       
  1460 }
       
  1461 
       
  1462 
       
  1463 void QSplitter::setOpaqueResize(bool on)
       
  1464 {
       
  1465     Q_D(QSplitter);
       
  1466     d->opaque = on;
       
  1467 }
       
  1468 
       
  1469 #ifdef QT3_SUPPORT
       
  1470 /*!
       
  1471     \fn void QSplitter::moveToFirst(QWidget *widget)
       
  1472 
       
  1473     Use insertWidget(0, \a widget) instead.
       
  1474 */
       
  1475 
       
  1476 
       
  1477 /*!
       
  1478     \fn void QSplitter::moveToLast(QWidget *widget)
       
  1479 
       
  1480     Use addWidget(\a widget) instead.
       
  1481 */
       
  1482 
       
  1483 /*!
       
  1484     \fn void QSplitter::setResizeMode(QWidget *widget, ResizeMode mode)
       
  1485 
       
  1486     Use setStretchFactor() instead.
       
  1487 
       
  1488     \oldcode
       
  1489         splitter->setResizeMode(firstChild, QSplitter::KeepSize);
       
  1490         splitter->setResizeMode(secondChild, QSplitter::Stretch);
       
  1491     \newcode
       
  1492         splitter->setStretchFactor(splitter->indexOf(firstChild), 0);
       
  1493         splitter->setStretchFactor(splitter->indexOf(secondChild), 1);
       
  1494     \endcode
       
  1495 */
       
  1496 
       
  1497 /*!
       
  1498     \enum QSplitter::ResizeMode
       
  1499     \compat
       
  1500 
       
  1501     This enum describes the different resizing behaviors child
       
  1502     widgets can have:
       
  1503 
       
  1504     \value Auto   The widget will be resized according to the stretch factors set in its sizePolicy().
       
  1505     \value Stretch  The widget will be resized when the splitter itself is resized.
       
  1506     \value KeepSize  QSplitter will try to keep the widget's size unchanged.
       
  1507     \value FollowSizeHint  QSplitter will resize the widget when the widget's size hint changes.
       
  1508 
       
  1509     Use setStretchFactor() instead.
       
  1510 */
       
  1511 
       
  1512 /*!
       
  1513     \fn void QSplitter::setCollapsible(QWidget *widget, bool collapsible)
       
  1514 
       
  1515     Use setCollapsible(indexOf(\a widget, \a collapsible)) instead.
       
  1516 */
       
  1517 
       
  1518 /*!
       
  1519     \fn void QSplitter::setMargin(int margin)
       
  1520     Sets the width of the margin around the contents of the widget to \a margin.
       
  1521 
       
  1522     Use QWidget::setContentsMargins() instead.
       
  1523     \sa margin(), QWidget::setContentsMargins()
       
  1524 */
       
  1525 
       
  1526 /*!
       
  1527     \fn int QSplitter::margin() const
       
  1528     Returns the width of the margin around the contents of the widget.
       
  1529 
       
  1530     Use QWidget::getContentsMargins() instead.
       
  1531     \sa setMargin(), QWidget::getContentsMargins()
       
  1532 */
       
  1533 
       
  1534 #endif
       
  1535 
       
  1536 /*!
       
  1537     \reimp
       
  1538 */
       
  1539 QSize QSplitter::sizeHint() const
       
  1540 {
       
  1541     Q_D(const QSplitter);
       
  1542     ensurePolished();
       
  1543     int l = 0;
       
  1544     int t = 0;
       
  1545     QObjectList childList = children();
       
  1546     for (int i = 0; i < childList.size(); ++i) {
       
  1547         if (QWidget *w = qobject_cast<QWidget *>(childList.at(i))) {
       
  1548             if (w->isHidden())
       
  1549                 continue;
       
  1550             QSize s = w->sizeHint();
       
  1551             if (s.isValid()) {
       
  1552                 l += d->pick(s);
       
  1553                 t = qMax(t, d->trans(s));
       
  1554             }
       
  1555         }
       
  1556     }
       
  1557     return orientation() == Qt::Horizontal ? QSize(l, t) : QSize(t, l);
       
  1558 }
       
  1559 
       
  1560 
       
  1561 /*!
       
  1562     \reimp
       
  1563 */
       
  1564 
       
  1565 QSize QSplitter::minimumSizeHint() const
       
  1566 {
       
  1567     Q_D(const QSplitter);
       
  1568     ensurePolished();
       
  1569     int l = 0;
       
  1570     int t = 0;
       
  1571 
       
  1572     for (int i = 0; i < d->list.size(); ++i) {
       
  1573         QSplitterLayoutStruct *s = d->list.at(i);
       
  1574         if (!s || !s->widget)
       
  1575             continue;
       
  1576         if (s->widget->isHidden())
       
  1577             continue;
       
  1578         QSize widgetSize = qSmartMinSize(s->widget);
       
  1579         if (widgetSize.isValid()) {
       
  1580             l += d->pick(widgetSize);
       
  1581             t = qMax(t, d->trans(widgetSize));
       
  1582         }
       
  1583         if (!s->handle || s->handle->isHidden())
       
  1584             continue;
       
  1585         QSize splitterSize = s->handle->sizeHint();
       
  1586         if (splitterSize.isValid()) {
       
  1587             l += d->pick(splitterSize);
       
  1588             t = qMax(t, d->trans(splitterSize));
       
  1589         }
       
  1590     }
       
  1591     return orientation() == Qt::Horizontal ? QSize(l, t) : QSize(t, l);
       
  1592 }
       
  1593 
       
  1594 
       
  1595 /*!
       
  1596     Returns a list of the size parameters of all the widgets in this splitter.
       
  1597 
       
  1598     If the splitter's orientation is horizontal, the list contains the
       
  1599     widgets width in pixels, from left to right; if the orientation is
       
  1600     vertical, the list contains the widgets height in pixels,
       
  1601     from top to bottom.
       
  1602 
       
  1603     Giving the values to another splitter's setSizes() function will
       
  1604     produce a splitter with the same layout as this one.
       
  1605 
       
  1606     Note that invisible widgets have a size of 0.
       
  1607 
       
  1608     \sa setSizes()
       
  1609 */
       
  1610 
       
  1611 QList<int> QSplitter::sizes() const
       
  1612 {
       
  1613     Q_D(const QSplitter);
       
  1614     ensurePolished();
       
  1615 
       
  1616     QList<int> list;
       
  1617     for (int i = 0; i < d->list.size(); ++i) {
       
  1618         QSplitterLayoutStruct *s = d->list.at(i);
       
  1619         list.append(d->pick(s->rect.size()));
       
  1620     }
       
  1621     return list;
       
  1622 }
       
  1623 
       
  1624 /*!
       
  1625     Sets the child widgets respective sizes to the values given in the \a list.
       
  1626 
       
  1627     If the splitter is horizontal, the values set the widths of each
       
  1628     widget in pixels, from left to right. If the splitter is vertical, the
       
  1629     heights of each widget is set, from top to bottom.
       
  1630 
       
  1631     Extra values in the \a list are ignored. If \a list contains too few
       
  1632     values, the result is undefined but the program will still be well-behaved.
       
  1633 
       
  1634     The overall size of the splitter widget is not affected.
       
  1635     Instead, any additional/missing space is distributed amongst the
       
  1636     widgets according to the relative weight of the sizes.
       
  1637 
       
  1638     If you specify a size of 0, the widget will be invisible. The size policies
       
  1639     of the widgets are preserved. That is, a value smaller then the minimal size
       
  1640     hint of the respective widget will be replaced by the value of the hint.
       
  1641 
       
  1642     \sa sizes()
       
  1643 */
       
  1644 
       
  1645 void QSplitter::setSizes(const QList<int> &list)
       
  1646 {
       
  1647     Q_D(QSplitter);
       
  1648     d->setSizes_helper(list, true);
       
  1649 }
       
  1650 
       
  1651 /*!
       
  1652     \property QSplitter::handleWidth
       
  1653     \brief the width of the splitter handles
       
  1654 
       
  1655     By default, this property contains a value that depends on the user's platform
       
  1656     and style preferences.
       
  1657 */
       
  1658 
       
  1659 int QSplitter::handleWidth() const
       
  1660 {
       
  1661     Q_D(const QSplitter);
       
  1662     if (d->handleWidth > 0) {
       
  1663         return d->handleWidth;
       
  1664     } else {
       
  1665         return style()->pixelMetric(QStyle::PM_SplitterWidth, 0, this);
       
  1666     }
       
  1667 }
       
  1668 
       
  1669 void QSplitter::setHandleWidth(int width)
       
  1670 {
       
  1671     Q_D(QSplitter);
       
  1672     d->handleWidth = width;
       
  1673     d->updateHandles();
       
  1674 }
       
  1675 
       
  1676 /*!
       
  1677     \reimp
       
  1678 */
       
  1679 void QSplitter::changeEvent(QEvent *ev)
       
  1680 {
       
  1681     Q_D(QSplitter);
       
  1682     if(ev->type() == QEvent::StyleChange)
       
  1683         d->updateHandles();
       
  1684     QFrame::changeEvent(ev);
       
  1685 }
       
  1686 
       
  1687 static const qint32 SplitterMagic = 0xff;
       
  1688 
       
  1689 /*!
       
  1690     Saves the state of the splitter's layout.
       
  1691 
       
  1692     Typically this is used in conjunction with QSettings to remember the size
       
  1693     for a future session. A version number is stored as part of the data.
       
  1694     Here is an example:
       
  1695 
       
  1696     \snippet doc/src/snippets/splitter/splitter.cpp 1
       
  1697 
       
  1698     \sa restoreState()
       
  1699 */
       
  1700 QByteArray QSplitter::saveState() const
       
  1701 {
       
  1702     Q_D(const QSplitter);
       
  1703     int version = 0;
       
  1704     QByteArray data;
       
  1705     QDataStream stream(&data, QIODevice::WriteOnly);
       
  1706 
       
  1707     stream << qint32(SplitterMagic);
       
  1708     stream << qint32(version);
       
  1709     QList<int> list;
       
  1710     for (int i = 0; i < d->list.size(); ++i) {
       
  1711         QSplitterLayoutStruct *s = d->list.at(i);
       
  1712         list.append(s->sizer);
       
  1713     }
       
  1714     stream << list;
       
  1715     stream << childrenCollapsible();
       
  1716     stream << qint32(handleWidth());
       
  1717     stream << opaqueResize();
       
  1718     stream << qint32(orientation());
       
  1719     return data;
       
  1720 }
       
  1721 
       
  1722 /*!
       
  1723     Restores the splitter's layout to the \a state specified.
       
  1724     Returns true if the state is restored; otherwise returns false.
       
  1725 
       
  1726     Typically this is used in conjunction with QSettings to restore the size
       
  1727     from a past session. Here is an example:
       
  1728 
       
  1729     Restore the splitters's state:
       
  1730 
       
  1731     \snippet doc/src/snippets/splitter/splitter.cpp 2
       
  1732 
       
  1733     A failure to restore the splitter's layout may result from either
       
  1734     invalid or out-of-date data in the supplied byte array.
       
  1735 
       
  1736     \sa saveState()
       
  1737 */
       
  1738 bool QSplitter::restoreState(const QByteArray &state)
       
  1739 {
       
  1740     Q_D(QSplitter);
       
  1741     int version = 0;
       
  1742     QByteArray sd = state;
       
  1743     QDataStream stream(&sd, QIODevice::ReadOnly);
       
  1744     QList<int> list;
       
  1745     bool b;
       
  1746     qint32 i;
       
  1747     qint32 marker;
       
  1748     qint32 v;
       
  1749 
       
  1750     stream >> marker;
       
  1751     stream >> v;
       
  1752     if (marker != SplitterMagic || v != version)
       
  1753         return false;
       
  1754 
       
  1755     stream >> list;
       
  1756     d->setSizes_helper(list, false);
       
  1757 
       
  1758     stream >> b;
       
  1759     setChildrenCollapsible(b);
       
  1760 
       
  1761     stream >> i;
       
  1762     setHandleWidth(i);
       
  1763 
       
  1764     stream >> b;
       
  1765     setOpaqueResize(b);
       
  1766 
       
  1767     stream >> i;
       
  1768     setOrientation(Qt::Orientation(i));
       
  1769     d->doResize();
       
  1770 
       
  1771     return true;
       
  1772 }
       
  1773 
       
  1774 /*!
       
  1775     Updates the size policy of the widget at position \a index to
       
  1776     have a stretch factor of \a stretch.
       
  1777 
       
  1778     \a stretch is not the effective stretch factor; the effective
       
  1779     stretch factor is calculated by taking the initial size of the 
       
  1780     widget and multiplying it with \a stretch.
       
  1781 
       
  1782     This function is provided for convenience. It is equivalent to
       
  1783 
       
  1784     \snippet doc/src/snippets/code/src_gui_widgets_qsplitter.cpp 0
       
  1785 
       
  1786     \sa setSizes(), widget()
       
  1787 */
       
  1788 void QSplitter::setStretchFactor(int index, int stretch)
       
  1789 {
       
  1790     Q_D(QSplitter);
       
  1791     if (index <= -1 || index >= d->list.count())
       
  1792         return;
       
  1793 
       
  1794     QWidget *widget = d->list.at(index)->widget;
       
  1795     QSizePolicy sp = widget->sizePolicy();
       
  1796     sp.setHorizontalStretch(stretch);
       
  1797     sp.setVerticalStretch(stretch);
       
  1798     widget->setSizePolicy(sp);
       
  1799 }
       
  1800 
       
  1801 
       
  1802 //#ifdef QT3_SUPPORT
       
  1803 #ifndef QT_NO_TEXTSTREAM
       
  1804 /*!
       
  1805     \relates QSplitter
       
  1806     \obsolete
       
  1807 
       
  1808     Use \a ts << \a{splitter}.saveState() instead.
       
  1809 */
       
  1810 
       
  1811 QTextStream& operator<<(QTextStream& ts, const QSplitter& splitter)
       
  1812 {
       
  1813     ts << splitter.saveState() << endl;
       
  1814     return ts;
       
  1815 }
       
  1816 
       
  1817 /*!
       
  1818     \relates QSplitter
       
  1819     \obsolete
       
  1820 
       
  1821     Use \a ts >> \a{splitter}.restoreState() instead.
       
  1822 */
       
  1823 
       
  1824 QTextStream& operator>>(QTextStream& ts, QSplitter& splitter)
       
  1825 {
       
  1826     QString line = ts.readLine();
       
  1827     line = line.simplified();
       
  1828     line.replace(QLatin1Char(' '), QString());
       
  1829     line = line.toUpper();
       
  1830 
       
  1831     splitter.restoreState(line.toAscii());
       
  1832     return ts;
       
  1833 }
       
  1834 #endif // QT_NO_TEXTSTREAM
       
  1835 //#endif // QT3_SUPPORT
       
  1836 
       
  1837 QT_END_NAMESPACE
       
  1838 
       
  1839 #endif // QT_NO_SPLITTER