source: trunk/src/gui/widgets/qsplitter.cpp@ 5

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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