source: trunk/src/gui/widgets/qdockarealayout.cpp@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 101.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "QtGui/qapplication.h"
43#include "QtGui/qwidget.h"
44#include "QtGui/qtabbar.h"
45#include "QtGui/qstyle.h"
46#include "QtGui/qdesktopwidget.h"
47#include "QtCore/qvariant.h"
48#include "qdockarealayout_p.h"
49#include "qdockwidget.h"
50#include "qmainwindow.h"
51#include "qwidgetanimator_p.h"
52#include "qmainwindowlayout_p.h"
53#include "qdockwidget_p.h"
54#include <private/qlayoutengine_p.h>
55
56#include <qpainter.h>
57#include <qstyleoption.h>
58
59#ifndef QT_NO_DOCKWIDGET
60
61QT_BEGIN_NAMESPACE
62
63enum { StateFlagVisible = 1, StateFlagFloating = 2 };
64
65/******************************************************************************
66** QPlaceHolderItem
67*/
68
69QPlaceHolderItem::QPlaceHolderItem(QWidget *w)
70{
71 objectName = w->objectName();
72 hidden = w->isHidden();
73 window = w->isWindow();
74 if (window)
75 topLevelRect = w->geometry();
76}
77
78/******************************************************************************
79** QDockAreaLayoutItem
80*/
81
82QDockAreaLayoutItem::QDockAreaLayoutItem(QLayoutItem *_widgetItem)
83 : widgetItem(_widgetItem), subinfo(0), placeHolderItem(0), pos(0), size(-1), flags(NoFlags)
84{
85}
86
87QDockAreaLayoutItem::QDockAreaLayoutItem(QDockAreaLayoutInfo *_subinfo)
88 : widgetItem(0), subinfo(_subinfo), placeHolderItem(0), pos(0), size(-1), flags(NoFlags)
89{
90}
91
92QDockAreaLayoutItem::QDockAreaLayoutItem(QPlaceHolderItem *_placeHolderItem)
93 : widgetItem(0), subinfo(0), placeHolderItem(_placeHolderItem), pos(0), size(-1), flags(NoFlags)
94{
95}
96
97QDockAreaLayoutItem::QDockAreaLayoutItem(const QDockAreaLayoutItem &other)
98 : widgetItem(other.widgetItem), subinfo(0), placeHolderItem(0), pos(other.pos),
99 size(other.size), flags(other.flags)
100{
101 if (other.subinfo != 0)
102 subinfo = new QDockAreaLayoutInfo(*other.subinfo);
103 else if (other.placeHolderItem != 0)
104 placeHolderItem = new QPlaceHolderItem(*other.placeHolderItem);
105}
106
107QDockAreaLayoutItem::~QDockAreaLayoutItem()
108{
109 delete subinfo;
110 delete placeHolderItem;
111}
112
113bool QDockAreaLayoutItem::skip() const
114{
115 if (placeHolderItem != 0)
116 return true;
117
118 if (flags & GapItem)
119 return false;
120
121 if (widgetItem != 0)
122 return widgetItem->isEmpty();
123
124 if (subinfo != 0) {
125 for (int i = 0; i < subinfo->item_list.count(); ++i) {
126 if (!subinfo->item_list.at(i).skip())
127 return false;
128 }
129 }
130
131 return true;
132}
133
134QSize QDockAreaLayoutItem::minimumSize() const
135{
136 if (widgetItem != 0) {
137 int left, top, right, bottom;
138 widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom);
139 return widgetItem->minimumSize() + QSize(left+right, top+bottom);
140 }
141 if (subinfo != 0)
142 return subinfo->minimumSize();
143 return QSize(0, 0);
144}
145
146QSize QDockAreaLayoutItem::maximumSize() const
147{
148 if (widgetItem != 0) {
149 int left, top, right, bottom;
150 widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom);
151 return widgetItem->maximumSize()+ QSize(left+right, top+bottom);
152 }
153 if (subinfo != 0)
154 return subinfo->maximumSize();
155 return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
156}
157
158bool QDockAreaLayoutItem::hasFixedSize(Qt::Orientation o) const
159{
160 return perp(o, minimumSize()) == perp(o, maximumSize());
161}
162
163bool QDockAreaLayoutItem::expansive(Qt::Orientation o) const
164{
165 if ((flags & GapItem) || placeHolderItem != 0)
166 return false;
167 if (widgetItem != 0)
168 return ((widgetItem->expandingDirections() & o) == o);
169 if (subinfo != 0)
170 return subinfo->expansive(o);
171 return false;
172}
173
174QSize QDockAreaLayoutItem::sizeHint() const
175{
176 if (placeHolderItem != 0)
177 return QSize(0, 0);
178 if (widgetItem != 0) {
179 int left, top, right, bottom;
180 widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom);
181 return widgetItem->sizeHint() + QSize(left+right, top+bottom);
182 }
183 if (subinfo != 0)
184 return subinfo->sizeHint();
185 return QSize(-1, -1);
186}
187
188QDockAreaLayoutItem
189 &QDockAreaLayoutItem::operator = (const QDockAreaLayoutItem &other)
190{
191 widgetItem = other.widgetItem;
192 if (other.subinfo == 0)
193 subinfo = 0;
194 else
195 subinfo = new QDockAreaLayoutInfo(*other.subinfo);
196
197 delete placeHolderItem;
198 if (other.placeHolderItem == 0)
199 placeHolderItem = 0;
200 else
201 placeHolderItem = new QPlaceHolderItem(*other.placeHolderItem);
202
203 pos = other.pos;
204 size = other.size;
205 flags = other.flags;
206
207 return *this;
208}
209
210/******************************************************************************
211** QDockAreaLayoutInfo
212*/
213
214#ifndef QT_NO_TABBAR
215static quintptr tabId(const QDockAreaLayoutItem &item)
216{
217 if (item.widgetItem == 0)
218 return 0;
219 return reinterpret_cast<quintptr>(item.widgetItem->widget());
220}
221#endif
222
223QDockAreaLayoutInfo::QDockAreaLayoutInfo()
224 : sep(0), dockPos(QInternal::LeftDock), o(Qt::Horizontal), mainWindow(0)
225#ifndef QT_NO_TABBAR
226 , tabbed(false), tabBar(0), tabBarShape(QTabBar::RoundedSouth), tabBarVisible(false)
227#endif
228{
229}
230
231QDockAreaLayoutInfo::QDockAreaLayoutInfo(int _sep, QInternal::DockPosition _dockPos,
232 Qt::Orientation _o, int tbshape,
233 QMainWindow *window)
234 : sep(_sep), dockPos(_dockPos), o(_o), mainWindow(window)
235#ifndef QT_NO_TABBAR
236 , tabbed(false), tabBar(0), tabBarShape(static_cast<QTabBar::Shape>(tbshape)), tabBarVisible(false)
237#endif
238{
239#ifdef QT_NO_TABBAR
240 Q_UNUSED(tbshape);
241#endif
242}
243
244QSize QDockAreaLayoutInfo::size() const
245{
246 return isEmpty() ? QSize(0, 0) : rect.size();
247}
248
249void QDockAreaLayoutInfo::clear()
250{
251 item_list.clear();
252 rect = QRect();
253#ifndef QT_NO_TABBAR
254 tabbed = false;
255 tabBar = 0;
256#endif
257}
258
259bool QDockAreaLayoutInfo::isEmpty() const
260{
261 return next(-1) == -1;
262}
263
264QSize QDockAreaLayoutInfo::minimumSize() const
265{
266 if (isEmpty())
267 return QSize(0, 0);
268
269 int a = 0, b = 0;
270 bool first = true;
271 for (int i = 0; i < item_list.size(); ++i) {
272 const QDockAreaLayoutItem &item = item_list.at(i);
273 if (item.skip())
274 continue;
275
276 QSize min_size = item.minimumSize();
277#ifndef QT_NO_TABBAR
278 if (tabbed) {
279 a = qMax(a, pick(o, min_size));
280 } else
281#endif
282 {
283 if (!first)
284 a += sep;
285 a += pick(o, min_size);
286 }
287 b = qMax(b, perp(o, min_size));
288
289 first = false;
290 }
291
292 QSize result;
293 rpick(o, result) = a;
294 rperp(o, result) = b;
295
296#ifndef QT_NO_TABBAR
297 if (tabbed) {
298 QSize tbm = tabBarMinimumSize();
299 switch (tabBarShape) {
300 case QTabBar::RoundedNorth:
301 case QTabBar::RoundedSouth:
302 case QTabBar::TriangularNorth:
303 case QTabBar::TriangularSouth:
304 result.rheight() += tbm.height();
305 result.rwidth() = qMax(tbm.width(), result.width());
306 break;
307 case QTabBar::RoundedEast:
308 case QTabBar::RoundedWest:
309 case QTabBar::TriangularEast:
310 case QTabBar::TriangularWest:
311 result.rheight() = qMax(tbm.height(), result.height());
312 result.rwidth() += tbm.width();
313 break;
314 default:
315 break;
316 }
317 }
318#endif // QT_NO_TABBAR
319
320 return result;
321}
322
323QSize QDockAreaLayoutInfo::maximumSize() const
324{
325 if (isEmpty())
326 return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
327
328 int a = 0, b = QWIDGETSIZE_MAX;
329#ifndef QT_NO_TABBAR
330 if (tabbed)
331 a = QWIDGETSIZE_MAX;
332#endif
333
334 int min_perp = 0;
335
336 bool first = true;
337 for (int i = 0; i < item_list.size(); ++i) {
338 const QDockAreaLayoutItem &item = item_list.at(i);
339 if (item.skip())
340 continue;
341
342 QSize max_size = item.maximumSize();
343 min_perp = qMax(min_perp, perp(o, item.minimumSize()));
344
345#ifndef QT_NO_TABBAR
346 if (tabbed) {
347 a = qMin(a, pick(o, max_size));
348 } else
349#endif
350 {
351 if (!first)
352 a += sep;
353 a += pick(o, max_size);
354 }
355 b = qMin(b, perp(o, max_size));
356
357 a = qMin(a, int(QWIDGETSIZE_MAX));
358 b = qMin(b, int(QWIDGETSIZE_MAX));
359
360 first = false;
361 }
362
363 b = qMax(b, min_perp);
364
365 QSize result;
366 rpick(o, result) = a;
367 rperp(o, result) = b;
368
369#ifndef QT_NO_TABBAR
370 if (tabbed) {
371 QSize tbh = tabBarSizeHint();
372 switch (tabBarShape) {
373 case QTabBar::RoundedNorth:
374 case QTabBar::RoundedSouth:
375 result.rheight() += tbh.height();
376 break;
377 case QTabBar::RoundedEast:
378 case QTabBar::RoundedWest:
379 result.rwidth() += tbh.width();
380 break;
381 default:
382 break;
383 }
384 }
385#endif // QT_NO_TABBAR
386
387 return result;
388}
389
390QSize QDockAreaLayoutInfo::sizeHint() const
391{
392 if (isEmpty())
393 return QSize(0, 0);
394
395 int a = 0, b = 0;
396 int min_perp = 0;
397 int max_perp = QWIDGETSIZE_MAX;
398 const QDockAreaLayoutItem *previous = 0;
399 for (int i = 0; i < item_list.size(); ++i) {
400 const QDockAreaLayoutItem &item = item_list.at(i);
401 if (item.skip())
402 continue;
403
404 bool gap = item.flags & QDockAreaLayoutItem::GapItem;
405
406 QSize size_hint = item.sizeHint();
407 min_perp = qMax(min_perp, perp(o, item.minimumSize()));
408 max_perp = qMin(max_perp, perp(o, item.maximumSize()));
409
410#ifndef QT_NO_TABBAR
411 if (tabbed) {
412 a = qMax(a, gap ? item.size : pick(o, size_hint));
413 } else
414#endif
415 {
416 if (previous && !gap && !(previous->flags & QDockAreaLayoutItem::GapItem)
417 && !previous->hasFixedSize(o)) {
418 a += sep;
419 }
420 a += gap ? item.size : pick(o, size_hint);
421 }
422 b = qMax(b, perp(o, size_hint));
423
424 previous = &item;
425 }
426
427 max_perp = qMax(max_perp, min_perp);
428 b = qMax(b, min_perp);
429 b = qMin(b, max_perp);
430
431 QSize result;
432 rpick(o, result) = a;
433 rperp(o, result) = b;
434
435#ifndef QT_NO_TABBAR
436 if (tabbed) {
437 QSize tbh = tabBarSizeHint();
438 switch (tabBarShape) {
439 case QTabBar::RoundedNorth:
440 case QTabBar::RoundedSouth:
441 case QTabBar::TriangularNorth:
442 case QTabBar::TriangularSouth:
443 result.rheight() += tbh.height();
444 result.rwidth() = qMax(tbh.width(), result.width());
445 break;
446 case QTabBar::RoundedEast:
447 case QTabBar::RoundedWest:
448 case QTabBar::TriangularEast:
449 case QTabBar::TriangularWest:
450 result.rheight() = qMax(tbh.height(), result.height());
451 result.rwidth() += tbh.width();
452 break;
453 default:
454 break;
455 }
456 }
457#endif // QT_NO_TABBAR
458
459 return result;
460}
461
462bool QDockAreaLayoutInfo::expansive(Qt::Orientation o) const
463{
464 for (int i = 0; i < item_list.size(); ++i) {
465 if (item_list.at(i).expansive(o))
466 return true;
467 }
468 return false;
469}
470
471/* QDockAreaLayoutInfo::maximumSize() doesn't return the real max size. For example,
472 if the layout is empty, it returns QWIDGETSIZE_MAX. This is so that empty dock areas
473 don't constrain the size of the QMainWindow, but sometimes we really need to know the
474 maximum size. Also, these functions take into account widgets that want to keep their
475 size (f.ex. when they are hidden and then shown, they should not change size).
476*/
477
478static int realMinSize(const QDockAreaLayoutInfo &info)
479{
480 int result = 0;
481 bool first = true;
482 for (int i = 0; i < info.item_list.size(); ++i) {
483 const QDockAreaLayoutItem &item = info.item_list.at(i);
484 if (item.skip())
485 continue;
486
487 int min = 0;
488 if ((item.flags & QDockAreaLayoutItem::KeepSize) && item.size != -1)
489 min = item.size;
490 else
491 min = pick(info.o, item.minimumSize());
492
493 if (!first)
494 result += info.sep;
495 result += min;
496
497 first = false;
498 }
499
500 return result;
501}
502
503static int realMaxSize(const QDockAreaLayoutInfo &info)
504{
505 int result = 0;
506 bool first = true;
507 for (int i = 0; i < info.item_list.size(); ++i) {
508 const QDockAreaLayoutItem &item = info.item_list.at(i);
509 if (item.skip())
510 continue;
511
512 int max = 0;
513 if ((item.flags & QDockAreaLayoutItem::KeepSize) && item.size != -1)
514 max = item.size;
515 else
516 max = pick(info.o, item.maximumSize());
517
518 if (!first)
519 result += info.sep;
520 result += max;
521
522 if (result >= QWIDGETSIZE_MAX)
523 return QWIDGETSIZE_MAX;
524
525 first = false;
526 }
527
528 return result;
529}
530
531void QDockAreaLayoutInfo::fitItems()
532{
533#ifndef QT_NO_TABBAR
534 if (tabbed) {
535 return;
536 }
537#endif
538
539 QVector<QLayoutStruct> layout_struct_list(item_list.size()*2);
540 int j = 0;
541
542 int size = pick(o, rect.size());
543 int min_size = realMinSize(*this);
544 int max_size = realMaxSize(*this);
545 int last_index = -1;
546
547 const QDockAreaLayoutItem *previous = 0;
548 for (int i = 0; i < item_list.size(); ++i) {
549 QDockAreaLayoutItem &item = item_list[i];
550 if (item.skip())
551 continue;
552
553 bool gap = item.flags & QDockAreaLayoutItem::GapItem;
554 if (previous && !gap) {
555 if (!(previous->flags & QDockAreaLayoutItem::GapItem)) {
556 QLayoutStruct &ls = layout_struct_list[j++];
557 ls.init();
558 ls.minimumSize = ls.maximumSize = ls.sizeHint = previous->hasFixedSize(o) ? 0 : sep;
559 ls.empty = false;
560 }
561 }
562
563 if (item.flags & QDockAreaLayoutItem::KeepSize) {
564 // Check if the item can keep its size, without violating size constraints
565 // of other items.
566
567 if (size < min_size) {
568 // There is too little space to keep this widget's size
569 item.flags &= ~QDockAreaLayoutItem::KeepSize;
570 min_size -= item.size;
571 min_size += pick(o, item.minimumSize());
572 min_size = qMax(0, min_size);
573 } else if (size > max_size) {
574 // There is too much space to keep this widget's size
575 item.flags &= ~QDockAreaLayoutItem::KeepSize;
576 max_size -= item.size;
577 max_size += pick(o, item.maximumSize());
578 max_size = qMin<int>(QWIDGETSIZE_MAX, max_size);
579 }
580 }
581
582 last_index = j;
583 QLayoutStruct &ls = layout_struct_list[j++];
584 ls.init();
585 ls.empty = false;
586 if (item.flags & QDockAreaLayoutItem::KeepSize) {
587 ls.minimumSize = ls.maximumSize = ls.sizeHint = item.size;
588 ls.expansive = false;
589 ls.stretch = 0;
590 } else {
591 ls.maximumSize = pick(o, item.maximumSize());
592 ls.expansive = item.expansive(o);
593 ls.minimumSize = pick(o, item.minimumSize());
594 ls.sizeHint = item.size == -1 ? pick(o, item.sizeHint()) : item.size;
595 ls.stretch = ls.expansive ? ls.sizeHint : 0;
596 }
597
598 item.flags &= ~QDockAreaLayoutItem::KeepSize;
599 previous = &item;
600 }
601 layout_struct_list.resize(j);
602
603 // If there is more space than the widgets can take (due to maximum size constraints),
604 // we detect it here and stretch the last widget to take up the rest of the space.
605 if (size > max_size && last_index != -1) {
606 layout_struct_list[last_index].maximumSize = QWIDGETSIZE_MAX;
607 layout_struct_list[last_index].expansive = true;
608 }
609
610 qGeomCalc(layout_struct_list, 0, j, pick(o, rect.topLeft()), size, 0);
611
612 j = 0;
613 bool prev_gap = false;
614 bool first = true;
615 for (int i = 0; i < item_list.size(); ++i) {
616 QDockAreaLayoutItem &item = item_list[i];
617 if (item.skip())
618 continue;
619
620 bool gap = item.flags & QDockAreaLayoutItem::GapItem;
621 if (!first && !gap && !prev_gap)
622 ++j;
623
624 const QLayoutStruct &ls = layout_struct_list.at(j++);
625 item.size = ls.size;
626 item.pos = ls.pos;
627
628 if (item.subinfo != 0) {
629 item.subinfo->rect = itemRect(i);
630 item.subinfo->fitItems();
631 }
632
633 prev_gap = gap;
634 first = false;
635 }
636}
637
638static QInternal::DockPosition dockPosHelper(const QRect &rect, const QPoint &_pos,
639 Qt::Orientation o,
640 bool nestingEnabled,
641 QDockAreaLayoutInfo::TabMode tabMode)
642{
643 if (tabMode == QDockAreaLayoutInfo::ForceTabs)
644 return QInternal::DockCount;
645
646 QPoint pos = _pos - rect.topLeft();
647
648 int x = pos.x();
649 int y = pos.y();
650 int w = rect.width();
651 int h = rect.height();
652
653 if (tabMode != QDockAreaLayoutInfo::NoTabs) {
654 // is it in the center?
655 if (nestingEnabled) {
656 /* 2/3
657 +--------------+
658 | |
659 | CCCCCCCC |
660 2/3 | CCCCCCCC |
661 | CCCCCCCC |
662 | |
663 +--------------+ */
664
665 QRect center(w/6, h/6, 2*w/3, 2*h/3);
666 if (center.contains(pos))
667 return QInternal::DockCount;
668 } else if (o == Qt::Horizontal) {
669 /* 2/3
670 +--------------+
671 | CCCCCCCC |
672 | CCCCCCCC |
673 | CCCCCCCC |
674 | CCCCCCCC |
675 | CCCCCCCC |
676 +--------------+ */
677
678 if (x > w/6 && x < w*5/6)
679 return QInternal::DockCount;
680 } else {
681 /*
682 +--------------+
683 | |
684 2/3 |CCCCCCCCCCCCCC|
685 |CCCCCCCCCCCCCC|
686 | |
687 +--------------+ */
688 if (y > h/6 && y < 5*h/6)
689 return QInternal::DockCount;
690 }
691 }
692
693 // not in the center. which edge?
694 if (nestingEnabled) {
695 if (o == Qt::Horizontal) {
696 /* 1/3 1/3 1/3
697 +------------+ (we've already ruled out the center)
698 |LLLLTTTTRRRR|
699 |LLLLTTTTRRRR|
700 |LLLLBBBBRRRR|
701 |LLLLBBBBRRRR|
702 +------------+ */
703
704 if (x < w/3)
705 return QInternal::LeftDock;
706 if (x > 2*w/3)
707 return QInternal::RightDock;
708 if (y < h/2)
709 return QInternal::TopDock;
710 return QInternal::BottomDock;
711 } else {
712 /* +------------+ (we've already ruled out the center)
713 1/3 |TTTTTTTTTTTT|
714 |LLLLLLRRRRRR|
715 1/3 |LLLLLLRRRRRR|
716 1/3 |BBBBBBBBBBBB|
717 +------------+ */
718
719 if (y < h/3)
720 return QInternal::TopDock;
721 if (y > 2*h/3)
722 return QInternal::BottomDock;
723 if (x < w/2)
724 return QInternal::LeftDock;
725 return QInternal::RightDock;
726 }
727 } else {
728 if (o == Qt::Horizontal) {
729 return x < w/2
730 ? QInternal::LeftDock
731 : QInternal::RightDock;
732 } else {
733 return y < h/2
734 ? QInternal::TopDock
735 : QInternal::BottomDock;
736 }
737 }
738}
739
740QList<int> QDockAreaLayoutInfo::gapIndex(const QPoint& _pos,
741 bool nestingEnabled, TabMode tabMode) const
742{
743 QList<int> result;
744 QRect item_rect;
745 int item_index = 0;
746
747#ifndef QT_NO_TABBAR
748 if (tabbed) {
749 item_rect = tabContentRect();
750 } else
751#endif
752 {
753 int pos = pick(o, _pos);
754
755 int last = -1;
756 for (int i = 0; i < item_list.size(); ++i) {
757 const QDockAreaLayoutItem &item = item_list.at(i);
758 if (item.skip())
759 continue;
760
761 last = i;
762
763 if (item.pos + item.size < pos)
764 continue;
765
766 if (item.subinfo != 0
767#ifndef QT_NO_TABBAR
768 && !item.subinfo->tabbed
769#endif
770 ) {
771 result = item.subinfo->gapIndex(_pos, nestingEnabled,
772 tabMode);
773 result.prepend(i);
774 return result;
775 }
776
777 item_rect = itemRect(i);
778 item_index = i;
779 break;
780 }
781
782 if (item_rect.isNull()) {
783 result.append(last + 1);
784 return result;
785 }
786 }
787
788 Q_ASSERT(!item_rect.isNull());
789
790 QInternal::DockPosition dock_pos
791 = dockPosHelper(item_rect, _pos, o, nestingEnabled, tabMode);
792
793 switch (dock_pos) {
794 case QInternal::LeftDock:
795 if (o == Qt::Horizontal)
796 result << item_index;
797 else
798 result << item_index << 0; // this subinfo doesn't exist yet, but insertGap()
799 // handles this by inserting it
800 break;
801 case QInternal::RightDock:
802 if (o == Qt::Horizontal)
803 result << item_index + 1;
804 else
805 result << item_index << 1;
806 break;
807 case QInternal::TopDock:
808 if (o == Qt::Horizontal)
809 result << item_index << 0;
810 else
811 result << item_index;
812 break;
813 case QInternal::BottomDock:
814 if (o == Qt::Horizontal)
815 result << item_index << 1;
816 else
817 result << item_index + 1;
818 break;
819 case QInternal::DockCount:
820 result << (-item_index - 1) << 0; // negative item_index means "on top of"
821 // -item_index - 1, insertGap()
822 // will insert a tabbed subinfo
823 break;
824 default:
825 break;
826 }
827
828 return result;
829}
830
831static inline int shrink(QLayoutStruct &ls, int delta)
832{
833 if (ls.empty)
834 return 0;
835 int old_size = ls.size;
836 ls.size = qMax(ls.size - delta, ls.minimumSize);
837 return old_size - ls.size;
838}
839
840static inline int grow(QLayoutStruct &ls, int delta)
841{
842 if (ls.empty)
843 return 0;
844 int old_size = ls.size;
845 ls.size = qMin(ls.size + delta, ls.maximumSize);
846 return ls.size - old_size;
847}
848
849static int separatorMoveHelper(QVector<QLayoutStruct> &list, int index, int delta, int sep)
850{
851 // adjust sizes
852 int pos = -1;
853 for (int i = 0; i < list.size(); ++i) {
854 const QLayoutStruct &ls = list.at(i);
855 if (!ls.empty) {
856 pos = ls.pos;
857 break;
858 }
859 }
860 if (pos == -1)
861 return 0;
862
863 if (delta > 0) {
864 int growlimit = 0;
865 for (int i = 0; i<=index; ++i) {
866 const QLayoutStruct &ls = list.at(i);
867 if (ls.empty)
868 continue;
869 if (ls.maximumSize == QLAYOUTSIZE_MAX) {
870 growlimit = QLAYOUTSIZE_MAX;
871 break;
872 }
873 growlimit += ls.maximumSize - ls.size;
874 }
875 if (delta > growlimit)
876 delta = growlimit;
877
878 int d = 0;
879 for (int i = index + 1; d < delta && i < list.count(); ++i)
880 d += shrink(list[i], delta - d);
881 delta = d;
882 d = 0;
883 for (int i = index; d < delta && i >= 0; --i)
884 d += grow(list[i], delta - d);
885 } else if (delta < 0) {
886 int growlimit = 0;
887 for (int i = index + 1; i < list.count(); ++i) {
888 const QLayoutStruct &ls = list.at(i);
889 if (ls.empty)
890 continue;
891 if (ls.maximumSize == QLAYOUTSIZE_MAX) {
892 growlimit = QLAYOUTSIZE_MAX;
893 break;
894 }
895 growlimit += ls.maximumSize - ls.size;
896 }
897 if (-delta > growlimit)
898 delta = -growlimit;
899
900 int d = 0;
901 for (int i = index; d < -delta && i >= 0; --i)
902 d += shrink(list[i], -delta - d);
903 delta = -d;
904 d = 0;
905 for (int i = index + 1; d < -delta && i < list.count(); ++i)
906 d += grow(list[i], -delta - d);
907 }
908
909 // adjust positions
910 bool first = true;
911 for (int i = 0; i < list.size(); ++i) {
912 QLayoutStruct &ls = list[i];
913 if (ls.empty) {
914 ls.pos = pos + (first ? 0 : sep);
915 continue;
916 }
917 if (!first)
918 pos += sep;
919 ls.pos = pos;
920 pos += ls.size;
921 first = false;
922 }
923
924 return delta;
925}
926
927int QDockAreaLayoutInfo::separatorMove(int index, int delta)
928{
929#ifndef QT_NO_TABBAR
930 Q_ASSERT(!tabbed);
931#endif
932
933 QVector<QLayoutStruct> list(item_list.size());
934 for (int i = 0; i < list.size(); ++i) {
935 const QDockAreaLayoutItem &item = item_list.at(i);
936 QLayoutStruct &ls = list[i];
937 Q_ASSERT(!(item.flags & QDockAreaLayoutItem::GapItem));
938 if (item.skip()) {
939 ls.empty = true;
940 } else {
941 const int separatorSpace = item.hasFixedSize(o) ? 0 : sep;
942 ls.empty = false;
943 ls.pos = item.pos;
944 ls.size = item.size + separatorSpace;
945 ls.minimumSize = pick(o, item.minimumSize()) + separatorSpace;
946 ls.maximumSize = pick(o, item.maximumSize()) + separatorSpace;
947
948 }
949 }
950
951 //the separator space has been added to the size, so we pass 0 as a parameter
952 delta = separatorMoveHelper(list, index, delta, 0 /*separator*/);
953
954 for (int i = 0; i < list.size(); ++i) {
955 QDockAreaLayoutItem &item = item_list[i];
956 if (item.skip())
957 continue;
958 QLayoutStruct &ls = list[i];
959 const int separatorSpace = item.hasFixedSize(o) ? 0 : sep;
960 item.size = ls.size - separatorSpace;
961 item.pos = ls.pos;
962 if (item.subinfo != 0) {
963 item.subinfo->rect = itemRect(i);
964 item.subinfo->fitItems();
965 }
966 }
967
968 return delta;
969}
970
971void QDockAreaLayoutInfo::unnest(int index)
972{
973 QDockAreaLayoutItem &item = item_list[index];
974 if (item.subinfo == 0)
975 return;
976 if (item.subinfo->item_list.count() > 1)
977 return;
978
979 if (item.subinfo->item_list.count() == 0) {
980 item_list.removeAt(index);
981 } else if (item.subinfo->item_list.count() == 1) {
982 QDockAreaLayoutItem &child = item.subinfo->item_list.first();
983 if (child.widgetItem != 0) {
984 item.widgetItem = child.widgetItem;
985 delete item.subinfo;
986 item.subinfo = 0;
987 } else if (child.subinfo != 0) {
988 QDockAreaLayoutInfo *tmp = item.subinfo;
989 item.subinfo = child.subinfo;
990 child.subinfo = 0;
991 tmp->item_list.clear();
992 delete tmp;
993 }
994 }
995}
996
997void QDockAreaLayoutInfo::remove(const QList<int> &path)
998{
999 Q_ASSERT(!path.isEmpty());
1000
1001 if (path.count() > 1) {
1002 const int index = path.first();
1003 QDockAreaLayoutItem &item = item_list[index];
1004 Q_ASSERT(item.subinfo != 0);
1005 item.subinfo->remove(path.mid(1));
1006 unnest(index);
1007 } else {
1008 int index = path.first();
1009 item_list.removeAt(index);
1010 }
1011}
1012
1013QLayoutItem *QDockAreaLayoutInfo::plug(const QList<int> &path)
1014{
1015 Q_ASSERT(!path.isEmpty());
1016
1017 int index = path.first();
1018 if (index < 0)
1019 index = -index - 1;
1020
1021 if (path.count() > 1) {
1022 const QDockAreaLayoutItem &item = item_list.at(index);
1023 Q_ASSERT(item.subinfo != 0);
1024 return item.subinfo->plug(path.mid(1));
1025 }
1026
1027 QDockAreaLayoutItem &item = item_list[index];
1028
1029 Q_ASSERT(item.widgetItem != 0);
1030 Q_ASSERT(item.flags & QDockAreaLayoutItem::GapItem);
1031 item.flags &= ~QDockAreaLayoutItem::GapItem;
1032
1033 QRect result;
1034
1035#ifndef QT_NO_TABBAR
1036 if (tabbed) {
1037 } else
1038#endif
1039 {
1040 int prev = this->prev(index);
1041 int next = this->next(index);
1042
1043 if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem)) {
1044 item.pos += sep;
1045 item.size -= sep;
1046 }
1047 if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem))
1048 item.size -= sep;
1049
1050 QPoint pos;
1051 rpick(o, pos) = item.pos;
1052 rperp(o, pos) = perp(o, rect.topLeft());
1053 QSize s;
1054 rpick(o, s) = item.size;
1055 rperp(o, s) = perp(o, rect.size());
1056 result = QRect(pos, s);
1057 }
1058
1059 return item.widgetItem;
1060}
1061
1062QLayoutItem *QDockAreaLayoutInfo::unplug(const QList<int> &path)
1063{
1064 Q_ASSERT(!path.isEmpty());
1065
1066 const int index = path.first();
1067 if (path.count() > 1) {
1068 const QDockAreaLayoutItem &item = item_list.at(index);
1069 Q_ASSERT(item.subinfo != 0);
1070 return item.subinfo->unplug(path.mid(1));
1071 }
1072
1073 QDockAreaLayoutItem &item = item_list[index];
1074 int prev = this->prev(index);
1075 int next = this->next(index);
1076
1077 Q_ASSERT(!(item.flags & QDockAreaLayoutItem::GapItem));
1078 item.flags |= QDockAreaLayoutItem::GapItem;
1079
1080#ifndef QT_NO_TABBAR
1081 if (tabbed) {
1082 } else
1083#endif
1084 {
1085 if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem)) {
1086 item.pos -= sep;
1087 item.size += sep;
1088 }
1089 if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem))
1090 item.size += sep;
1091 }
1092
1093 return item.widgetItem;
1094}
1095
1096#ifndef QT_NO_TABBAR
1097
1098quintptr QDockAreaLayoutInfo::currentTabId() const
1099{
1100 if (!tabbed || tabBar == 0)
1101 return 0;
1102
1103 int index = tabBar->currentIndex();
1104 if (index == -1)
1105 return 0;
1106
1107 return qvariant_cast<quintptr>(tabBar->tabData(index));
1108}
1109
1110void QDockAreaLayoutInfo::setCurrentTab(QWidget *widget)
1111{
1112 setCurrentTabId(reinterpret_cast<quintptr>(widget));
1113}
1114
1115void QDockAreaLayoutInfo::setCurrentTabId(quintptr id)
1116{
1117 if (!tabbed || tabBar == 0)
1118 return;
1119
1120 for (int i = 0; i < tabBar->count(); ++i) {
1121 if (qvariant_cast<quintptr>(tabBar->tabData(i)) == id) {
1122 tabBar->setCurrentIndex(i);
1123 return;
1124 }
1125 }
1126}
1127
1128#endif // QT_NO_TABBAR
1129
1130static QRect dockedGeometry(QWidget *widget)
1131{
1132 int titleHeight = 0;
1133
1134 QDockWidgetLayout *layout
1135 = qobject_cast<QDockWidgetLayout*>(widget->layout());
1136 if(layout != 0 && layout->nativeWindowDeco())
1137 titleHeight = layout->titleHeight();
1138
1139 QRect result = widget->geometry();
1140 result.adjust(0, -titleHeight, 0, 0);
1141 return result;
1142}
1143
1144bool QDockAreaLayoutInfo::insertGap(const QList<int> &path, QLayoutItem *dockWidgetItem)
1145{
1146 Q_ASSERT(!path.isEmpty());
1147
1148 bool insert_tabbed = false;
1149 int index = path.first();
1150 if (index < 0) {
1151 insert_tabbed = true;
1152 index = -index - 1;
1153 }
1154
1155// dump(qDebug() << "insertGap() before:" << index << tabIndex, *this, QString());
1156
1157 if (path.count() > 1) {
1158 QDockAreaLayoutItem &item = item_list[index];
1159
1160 if (item.subinfo == 0
1161#ifndef QT_NO_TABBAR
1162 || (item.subinfo->tabbed && !insert_tabbed)
1163#endif
1164 ) {
1165
1166 // this is not yet a nested layout - make it
1167
1168 QDockAreaLayoutInfo *subinfo = item.subinfo;
1169 QLayoutItem *widgetItem = item.widgetItem;
1170 QPlaceHolderItem *placeHolderItem = item.placeHolderItem;
1171 QRect r = subinfo == 0 ? widgetItem ? dockedGeometry(widgetItem->widget()) : placeHolderItem->topLevelRect : subinfo->rect;
1172
1173 Qt::Orientation opposite = o == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal;
1174#ifdef QT_NO_TABBAR
1175 const int tabBarShape = 0;
1176#endif
1177 QDockAreaLayoutInfo *new_info
1178 = new QDockAreaLayoutInfo(sep, dockPos, opposite, tabBarShape, mainWindow);
1179
1180 //item become a new top-level
1181 item.subinfo = new_info;
1182 item.widgetItem = 0;
1183 item.placeHolderItem = 0;
1184
1185 QDockAreaLayoutItem new_item
1186 = widgetItem == 0
1187 ? QDockAreaLayoutItem(subinfo)
1188 : widgetItem ? QDockAreaLayoutItem(widgetItem) : QDockAreaLayoutItem(placeHolderItem);
1189 new_item.size = pick(opposite, r.size());
1190 new_item.pos = pick(opposite, r.topLeft());
1191 new_info->item_list.append(new_item);
1192#ifndef QT_NO_TABBAR
1193 if (insert_tabbed) {
1194 new_info->tabbed = true;
1195 }
1196#endif
1197 }
1198
1199 return item.subinfo->insertGap(path.mid(1), dockWidgetItem);
1200 }
1201
1202 // create the gap item
1203 QDockAreaLayoutItem gap_item;
1204 gap_item.flags |= QDockAreaLayoutItem::GapItem;
1205 gap_item.widgetItem = dockWidgetItem; // so minimumSize(), maximumSize() and
1206 // sizeHint() will work
1207#ifndef QT_NO_TABBAR
1208 if (!tabbed)
1209#endif
1210 {
1211 int prev = this->prev(index);
1212 int next = this->next(index - 1);
1213 // find out how much space we have in the layout
1214 int space = 0;
1215 if (isEmpty()) {
1216 // I am an empty dock area, therefore I am a top-level dock area.
1217 switch (dockPos) {
1218 case QInternal::LeftDock:
1219 case QInternal::RightDock:
1220 if (o == Qt::Vertical) {
1221 // the "size" is the height of the dock area (remember we are empty)
1222 space = pick(Qt::Vertical, rect.size());
1223 } else {
1224 space = pick(Qt::Horizontal, dockWidgetItem->widget()->size());
1225 }
1226 break;
1227 case QInternal::TopDock:
1228 case QInternal::BottomDock:
1229 default:
1230 if (o == Qt::Horizontal) {
1231 // the "size" is width of the dock area
1232 space = pick(Qt::Horizontal, rect.size());
1233 } else {
1234 space = pick(Qt::Vertical, dockWidgetItem->widget()->size());
1235 }
1236 break;
1237 }
1238 } else {
1239 for (int i = 0; i < item_list.count(); ++i) {
1240 const QDockAreaLayoutItem &item = item_list.at(i);
1241 if (item.skip())
1242 continue;
1243 Q_ASSERT(!(item.flags & QDockAreaLayoutItem::GapItem));
1244 space += item.size - pick(o, item.minimumSize());
1245 }
1246 }
1247
1248 // find the actual size of the gap
1249 int gap_size = 0;
1250 int sep_size = 0;
1251 if (isEmpty()) {
1252 gap_size = space;
1253 sep_size = 0;
1254 } else {
1255 QRect r = dockedGeometry(dockWidgetItem->widget());
1256 gap_size = pick(o, r.size());
1257 if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem))
1258 sep_size += sep;
1259 if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem))
1260 sep_size += sep;
1261 }
1262 if (gap_size + sep_size > space)
1263 gap_size = pick(o, gap_item.minimumSize());
1264 gap_item.size = gap_size + sep_size;
1265 }
1266
1267 // finally, insert the gap
1268 item_list.insert(index, gap_item);
1269
1270// dump(qDebug() << "insertGap() after:" << index << tabIndex, *this, QString());
1271
1272 return true;
1273}
1274
1275QDockAreaLayoutInfo *QDockAreaLayoutInfo::info(QWidget *widget)
1276{
1277 for (int i = 0; i < item_list.count(); ++i) {
1278 const QDockAreaLayoutItem &item = item_list.at(i);
1279 if (item.skip())
1280 continue;
1281
1282#ifndef QT_NO_TABBAR
1283 if (tabbed && widget == tabBar)
1284 return this;
1285#endif
1286
1287 if (item.widgetItem != 0 && item.widgetItem->widget() == widget)
1288 return this;
1289
1290 if (item.subinfo != 0) {
1291 if (QDockAreaLayoutInfo *result = item.subinfo->info(widget))
1292 return result;
1293 }
1294 }
1295
1296 return 0;
1297}
1298
1299QDockAreaLayoutInfo *QDockAreaLayoutInfo::info(const QList<int> &path)
1300{
1301 int index = path.first();
1302 if (index < 0)
1303 index = -index - 1;
1304 if (index >= item_list.count())
1305 return this;
1306 if (path.count() == 1 || item_list[index].subinfo == 0)
1307 return this;
1308 return item_list[index].subinfo->info(path.mid(1));
1309}
1310
1311QRect QDockAreaLayoutInfo::itemRect(int index) const
1312{
1313 const QDockAreaLayoutItem &item = item_list.at(index);
1314
1315 if (item.skip())
1316 return QRect();
1317
1318 QRect result;
1319
1320#ifndef QT_NO_TABBAR
1321 if (tabbed) {
1322 if (tabId(item) == currentTabId())
1323 result = tabContentRect();
1324 } else
1325#endif
1326 {
1327 QPoint pos;
1328 rpick(o, pos) = item.pos;
1329 rperp(o, pos) = perp(o, rect.topLeft());
1330 QSize s;
1331 rpick(o, s) = item.size;
1332 rperp(o, s) = perp(o, rect.size());
1333 result = QRect(pos, s);
1334 }
1335
1336 return result;
1337}
1338
1339QRect QDockAreaLayoutInfo::itemRect(const QList<int> &path) const
1340{
1341 Q_ASSERT(!path.isEmpty());
1342
1343 const int index = path.first();
1344 if (path.count() > 1) {
1345 const QDockAreaLayoutItem &item = item_list.at(index);
1346 Q_ASSERT(item.subinfo != 0);
1347 return item.subinfo->itemRect(path.mid(1));
1348 }
1349
1350 return itemRect(index);
1351}
1352
1353QRect QDockAreaLayoutInfo::separatorRect(int index) const
1354{
1355#ifndef QT_NO_TABBAR
1356 if (tabbed)
1357 return QRect();
1358#endif
1359
1360 const QDockAreaLayoutItem &item = item_list.at(index);
1361 if (item.skip())
1362 return QRect();
1363
1364 QPoint pos = rect.topLeft();
1365 rpick(o, pos) = item.pos + item.size;
1366 QSize s = rect.size();
1367 rpick(o, s) = sep;
1368
1369 return QRect(pos, s);
1370}
1371
1372QRect QDockAreaLayoutInfo::separatorRect(const QList<int> &path) const
1373{
1374 Q_ASSERT(!path.isEmpty());
1375
1376 const int index = path.first();
1377 if (path.count() > 1) {
1378 const QDockAreaLayoutItem &item = item_list.at(index);
1379 Q_ASSERT(item.subinfo != 0);
1380 return item.subinfo->separatorRect(path.mid(1));
1381 }
1382 return separatorRect(index);
1383}
1384
1385QList<int> QDockAreaLayoutInfo::findSeparator(const QPoint &_pos) const
1386{
1387#ifndef QT_NO_TABBAR
1388 if (tabbed)
1389 return QList<int>();
1390#endif
1391
1392 int pos = pick(o, _pos);
1393
1394 for (int i = 0; i < item_list.size(); ++i) {
1395 const QDockAreaLayoutItem &item = item_list.at(i);
1396 if (item.skip() || (item.flags & QDockAreaLayoutItem::GapItem))
1397 continue;
1398
1399 if (item.pos + item.size > pos) {
1400 if (item.subinfo != 0) {
1401 QList<int> result = item.subinfo->findSeparator(_pos);
1402 if (!result.isEmpty()) {
1403 result.prepend(i);
1404 return result;
1405 } else {
1406 return QList<int>();
1407 }
1408 }
1409 }
1410
1411 int next = this->next(i);
1412 if (next == -1 || (item_list.at(next).flags & QDockAreaLayoutItem::GapItem))
1413 continue;
1414
1415 QRect sepRect = separatorRect(i);
1416 if (!sepRect.isNull() && sep == 1)
1417 sepRect.adjust(-2, -2, 2, 2);
1418 //we also make sure we don't find a separator that's not there
1419 if (sepRect.contains(_pos) && !item.hasFixedSize(o)) {
1420 return QList<int>() << i;
1421 }
1422
1423 }
1424
1425 return QList<int>();
1426}
1427
1428QList<int> QDockAreaLayoutInfo::indexOfPlaceHolder(const QString &objectName) const
1429{
1430 for (int i = 0; i < item_list.size(); ++i) {
1431 const QDockAreaLayoutItem &item = item_list.at(i);
1432
1433 if (item.subinfo != 0) {
1434 QList<int> result = item.subinfo->indexOfPlaceHolder(objectName);
1435 if (!result.isEmpty()) {
1436 result.prepend(i);
1437 return result;
1438 }
1439 continue;
1440 }
1441
1442 if (item.placeHolderItem != 0 && item.placeHolderItem->objectName == objectName) {
1443 QList<int> result;
1444 result << i;
1445 return result;
1446 }
1447 }
1448
1449 return QList<int>();
1450}
1451
1452QList<int> QDockAreaLayoutInfo::indexOf(QWidget *widget) const
1453{
1454 for (int i = 0; i < item_list.size(); ++i) {
1455 const QDockAreaLayoutItem &item = item_list.at(i);
1456
1457 if (item.placeHolderItem != 0)
1458 continue;
1459
1460 if (item.subinfo != 0) {
1461 QList<int> result = item.subinfo->indexOf(widget);
1462 if (!result.isEmpty()) {
1463 result.prepend(i);
1464 return result;
1465 }
1466 continue;
1467 }
1468
1469 if (!(item.flags & QDockAreaLayoutItem::GapItem) && item.widgetItem->widget() == widget) {
1470 QList<int> result;
1471 result << i;
1472 return result;
1473 }
1474 }
1475
1476 return QList<int>();
1477}
1478
1479QMainWindowLayout *QDockAreaLayoutInfo::mainWindowLayout() const
1480{
1481 QMainWindowLayout *result = qobject_cast<QMainWindowLayout*>(mainWindow->layout());
1482 Q_ASSERT(result != 0);
1483 return result;
1484}
1485
1486bool QDockAreaLayoutInfo::hasFixedSize() const
1487{
1488 return perp(o, minimumSize()) == perp(o, maximumSize());
1489}
1490
1491
1492void QDockAreaLayoutInfo::apply(bool animate)
1493{
1494 QWidgetAnimator &widgetAnimator = mainWindowLayout()->widgetAnimator;
1495
1496#ifndef QT_NO_TABBAR
1497 if (tabbed) {
1498 QRect tab_rect;
1499 QSize tbh = tabBarSizeHint();
1500
1501 if (tabBarVisible) {
1502 switch (tabBarShape) {
1503 case QTabBar::RoundedNorth:
1504 case QTabBar::TriangularNorth:
1505 tab_rect = QRect(rect.left(), rect.top(), rect.width(), tbh.height());
1506 break;
1507 case QTabBar::RoundedSouth:
1508 case QTabBar::TriangularSouth:
1509 tab_rect = QRect(rect.left(), rect.bottom() - tbh.height() + 1,
1510 rect.width(), tbh.height());
1511 break;
1512 case QTabBar::RoundedEast:
1513 case QTabBar::TriangularEast:
1514 tab_rect = QRect(rect.right() - tbh.width() + 1, rect.top(),
1515 tbh.width(), rect.height());
1516 break;
1517 case QTabBar::RoundedWest:
1518 case QTabBar::TriangularWest:
1519 tab_rect = QRect(rect.left(), rect.top(),
1520 tbh.width(), rect.height());
1521 break;
1522 default:
1523 break;
1524 }
1525 }
1526
1527 widgetAnimator.animate(tabBar, tab_rect, animate);
1528 }
1529#endif // QT_NO_TABBAR
1530
1531 for (int i = 0; i < item_list.size(); ++i) {
1532 QDockAreaLayoutItem &item = item_list[i];
1533
1534 if (item.flags & QDockAreaLayoutItem::GapItem)
1535 continue;
1536
1537 if (item.subinfo != 0) {
1538 item.subinfo->apply(animate);
1539 continue;
1540 }
1541
1542 if (item.skip())
1543 continue;
1544
1545 Q_ASSERT(item.widgetItem);
1546 QRect r = itemRect(i);
1547 QWidget *w = item.widgetItem->widget();
1548
1549 QRect geo = w->geometry();
1550 widgetAnimator.animate(w, r, animate);
1551 if (!w->isHidden() && w->window()->isVisible()) {
1552 QDockWidget *dw = qobject_cast<QDockWidget*>(w);
1553 if (!r.isValid() && geo.right() >= 0 && geo.bottom() >= 0) {
1554 dw->lower();
1555 emit dw->visibilityChanged(false);
1556 } else if (r.isValid()
1557 && (geo.right() < 0 || geo.bottom() < 0)) {
1558 emit dw->visibilityChanged(true);
1559 }
1560 }
1561 }
1562#ifndef QT_NO_TABBAR
1563 if (sep == 1)
1564 updateSeparatorWidgets();
1565#endif //QT_NO_TABBAR
1566}
1567
1568static void paintSep(QPainter *p, QWidget *w, const QRect &r, Qt::Orientation o, bool mouse_over)
1569{
1570 QStyleOption opt(0);
1571 opt.state = QStyle::State_None;
1572 if (w->isEnabled())
1573 opt.state |= QStyle::State_Enabled;
1574 if (o != Qt::Horizontal)
1575 opt.state |= QStyle::State_Horizontal;
1576 if (mouse_over)
1577 opt.state |= QStyle::State_MouseOver;
1578 opt.rect = r;
1579 opt.palette = w->palette();
1580
1581 w->style()->drawPrimitive(QStyle::PE_IndicatorDockWidgetResizeHandle, &opt, p, w);
1582}
1583
1584QRegion QDockAreaLayoutInfo::separatorRegion() const
1585{
1586 QRegion result;
1587
1588 if (isEmpty())
1589 return result;
1590#ifndef QT_NO_TABBAR
1591 if (tabbed)
1592 return result;
1593#endif
1594
1595 for (int i = 0; i < item_list.count(); ++i) {
1596 const QDockAreaLayoutItem &item = item_list.at(i);
1597
1598 if (item.skip())
1599 continue;
1600
1601 int next = this->next(i);
1602
1603 if (item.subinfo)
1604 result |= item.subinfo->separatorRegion();
1605
1606 if (next == -1)
1607 break;
1608 result |= separatorRect(i);
1609 }
1610
1611 return result;
1612}
1613
1614void QDockAreaLayoutInfo::paintSeparators(QPainter *p, QWidget *widget,
1615 const QRegion &clip,
1616 const QPoint &mouse) const
1617{
1618 if (isEmpty())
1619 return;
1620#ifndef QT_NO_TABBAR
1621 if (tabbed)
1622 return;
1623#endif
1624
1625 for (int i = 0; i < item_list.count(); ++i) {
1626 const QDockAreaLayoutItem &item = item_list.at(i);
1627
1628 if (item.skip())
1629 continue;
1630
1631 int next = this->next(i);
1632 if ((item.flags & QDockAreaLayoutItem::GapItem)
1633 || (next != -1 && (item_list.at(next).flags & QDockAreaLayoutItem::GapItem)))
1634 continue;
1635
1636 if (item.subinfo) {
1637 if (clip.contains(item.subinfo->rect))
1638 item.subinfo->paintSeparators(p, widget, clip, mouse);
1639 }
1640
1641 if (next == -1)
1642 break;
1643 QRect r = separatorRect(i);
1644 if (clip.contains(r) && !item.hasFixedSize(o))
1645 paintSep(p, widget, r, o, r.contains(mouse));
1646 }
1647}
1648
1649int QDockAreaLayoutInfo::next(int index) const
1650{
1651 for (int i = index + 1; i < item_list.size(); ++i) {
1652 if (!item_list.at(i).skip())
1653 return i;
1654 }
1655 return -1;
1656}
1657
1658int QDockAreaLayoutInfo::prev(int index) const
1659{
1660 for (int i = index - 1; i >= 0; --i) {
1661 if (!item_list.at(i).skip())
1662 return i;
1663 }
1664 return -1;
1665}
1666
1667void QDockAreaLayoutInfo::tab(int index, QLayoutItem *dockWidgetItem)
1668{
1669#ifdef QT_NO_TABBAR
1670 Q_UNUSED(index);
1671 Q_UNUSED(dockWidgetItem);
1672#else
1673 if (tabbed) {
1674 item_list.append(QDockAreaLayoutItem(dockWidgetItem));
1675 updateTabBar();
1676 setCurrentTab(dockWidgetItem->widget());
1677 } else {
1678 QDockAreaLayoutInfo *new_info
1679 = new QDockAreaLayoutInfo(sep, dockPos, o, tabBarShape, mainWindow);
1680 item_list[index].subinfo = new_info;
1681 new_info->item_list.append(item_list.at(index).widgetItem);
1682 item_list[index].widgetItem = 0;
1683 new_info->item_list.append(dockWidgetItem);
1684 new_info->tabbed = true;
1685 new_info->updateTabBar();
1686 new_info->setCurrentTab(dockWidgetItem->widget());
1687 }
1688#endif // QT_NO_TABBAR
1689}
1690
1691void QDockAreaLayoutInfo::split(int index, Qt::Orientation orientation,
1692 QLayoutItem *dockWidgetItem)
1693{
1694 if (orientation == o) {
1695 item_list.insert(index + 1, QDockAreaLayoutItem(dockWidgetItem));
1696 } else {
1697#ifdef QT_NO_TABBAR
1698 const int tabBarShape = 0;
1699#endif
1700 QDockAreaLayoutInfo *new_info
1701 = new QDockAreaLayoutInfo(sep, dockPos, orientation, tabBarShape, mainWindow);
1702 item_list[index].subinfo = new_info;
1703 new_info->item_list.append(item_list.at(index).widgetItem);
1704 item_list[index].widgetItem = 0;
1705 new_info->item_list.append(dockWidgetItem);
1706 }
1707}
1708
1709QDockAreaLayoutItem &QDockAreaLayoutInfo::item(const QList<int> &path)
1710{
1711 Q_ASSERT(!path.isEmpty());
1712 const int index = path.first();
1713 if (path.count() > 1) {
1714 const QDockAreaLayoutItem &item = item_list[index];
1715 Q_ASSERT(item.subinfo != 0);
1716 return item.subinfo->item(path.mid(1));
1717 }
1718 return item_list[index];
1719}
1720
1721QLayoutItem *QDockAreaLayoutInfo::itemAt(int *x, int index) const
1722{
1723 for (int i = 0; i < item_list.count(); ++i) {
1724 const QDockAreaLayoutItem &item = item_list.at(i);
1725 if (item.placeHolderItem != 0)
1726 continue;
1727 if (item.subinfo) {
1728 if (QLayoutItem *ret = item.subinfo->itemAt(x, index))
1729 return ret;
1730 } else if (item.widgetItem) {
1731 if ((*x)++ == index)
1732 return item.widgetItem;
1733 }
1734 }
1735 return 0;
1736}
1737
1738QLayoutItem *QDockAreaLayoutInfo::takeAt(int *x, int index)
1739{
1740 for (int i = 0; i < item_list.count(); ++i) {
1741 QDockAreaLayoutItem &item = item_list[i];
1742 if (item.placeHolderItem != 0)
1743 continue;
1744 else if (item.subinfo) {
1745 if (QLayoutItem *ret = item.subinfo->takeAt(x, index)) {
1746 unnest(i);
1747 return ret;
1748 }
1749 } else if (item.widgetItem) {
1750 if ((*x)++ == index) {
1751 item.placeHolderItem = new QPlaceHolderItem(item.widgetItem->widget());
1752 QLayoutItem *ret = item.widgetItem;
1753 item.widgetItem = 0;
1754 if (item.size != -1)
1755 item.flags |= QDockAreaLayoutItem::KeepSize;
1756 return ret;
1757 }
1758 }
1759 }
1760 return 0;
1761}
1762
1763void QDockAreaLayoutInfo::deleteAllLayoutItems()
1764{
1765 for (int i = 0; i < item_list.count(); ++i) {
1766 QDockAreaLayoutItem &item= item_list[i];
1767 if (item.subinfo) {
1768 item.subinfo->deleteAllLayoutItems();
1769 } else {
1770 delete item.widgetItem;
1771 item.widgetItem = 0;
1772 }
1773 }
1774}
1775
1776void QDockAreaLayoutInfo::saveState(QDataStream &stream) const
1777{
1778#ifndef QT_NO_TABBAR
1779 if (tabbed) {
1780 stream << (uchar) TabMarker;
1781
1782 // write the index in item_list of the widget that's currently on top.
1783 quintptr id = currentTabId();
1784 int index = -1;
1785 for (int i = 0; i < item_list.count(); ++i) {
1786 if (tabId(item_list.at(i)) == id) {
1787 index = i;
1788 break;
1789 }
1790 }
1791 stream << index;
1792 } else
1793#endif // QT_NO_TABBAR
1794 {
1795 stream << (uchar) SequenceMarker;
1796 }
1797
1798 stream << (uchar) o << item_list.count();
1799
1800 for (int i = 0; i < item_list.count(); ++i) {
1801 const QDockAreaLayoutItem &item = item_list.at(i);
1802 if (item.widgetItem != 0) {
1803 stream << (uchar) WidgetMarker;
1804 QWidget *w = item.widgetItem->widget();
1805 QString name = w->objectName();
1806 if (name.isEmpty()) {
1807 qWarning("QMainWindow::saveState(): 'objectName' not set for QDockWidget %p '%s;",
1808 w, qPrintable(w->windowTitle()));
1809 }
1810 stream << name;
1811
1812 uchar flags = 0;
1813 if (!w->isHidden())
1814 flags |= StateFlagVisible;
1815 if (w->isWindow())
1816 flags |= StateFlagFloating;
1817 stream << flags;
1818
1819 if (w->isWindow()) {
1820 stream << w->x() << w->y() << w->width() << w->height();
1821 } else {
1822 stream << item.pos << item.size << pick(o, item.minimumSize())
1823 << pick(o, item.maximumSize());
1824 }
1825 } else if (item.placeHolderItem != 0) {
1826 stream << (uchar) WidgetMarker;
1827 stream << item.placeHolderItem->objectName;
1828 uchar flags = 0;
1829 if (!item.placeHolderItem->hidden)
1830 flags |= StateFlagVisible;
1831 if (item.placeHolderItem->window)
1832 flags |= StateFlagFloating;
1833 stream << flags;
1834 if (item.placeHolderItem->window) {
1835 QRect r = item.placeHolderItem->topLevelRect;
1836 stream << r.x() << r.y() << r.width() << r.height();
1837 } else {
1838 stream << item.pos << item.size << (int)0 << (int)0;
1839 }
1840 } else if (item.subinfo != 0) {
1841 stream << (uchar) SequenceMarker << item.pos << item.size << pick(o, item.minimumSize()) << pick(o, item.maximumSize());
1842 item.subinfo->saveState(stream);
1843 }
1844 }
1845}
1846
1847static Qt::DockWidgetArea toDockWidgetArea(QInternal::DockPosition pos)
1848{
1849 switch (pos) {
1850 case QInternal::LeftDock: return Qt::LeftDockWidgetArea;
1851 case QInternal::RightDock: return Qt::RightDockWidgetArea;
1852 case QInternal::TopDock: return Qt::TopDockWidgetArea;
1853 case QInternal::BottomDock: return Qt::BottomDockWidgetArea;
1854 default: break;
1855 }
1856 return Qt::NoDockWidgetArea;
1857}
1858
1859static QRect constrainedRect(QRect rect, const QRect &desktop)
1860{
1861 if (desktop.isValid()) {
1862 rect.setWidth(qMin(rect.width(), desktop.width()));
1863 rect.setHeight(qMin(rect.height(), desktop.height()));
1864 rect.moveLeft(qMax(rect.left(), desktop.left()));
1865 rect.moveTop(qMax(rect.top(), desktop.top()));
1866 rect.moveRight(qMin(rect.right(), desktop.right()));
1867 rect.moveBottom(qMin(rect.bottom(), desktop.bottom()));
1868 }
1869
1870 return rect;
1871}
1872
1873bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList<QDockWidget*> &widgets, bool testing)
1874{
1875 uchar marker;
1876 stream >> marker;
1877 if (marker != TabMarker && marker != SequenceMarker)
1878 return false;
1879
1880#ifndef QT_NO_TABBAR
1881 tabbed = marker == TabMarker;
1882
1883 int index = -1;
1884 if (tabbed)
1885 stream >> index;
1886#endif
1887
1888 uchar orientation;
1889 stream >> orientation;
1890 o = static_cast<Qt::Orientation>(orientation);
1891
1892 int cnt;
1893 stream >> cnt;
1894
1895 for (int i = 0; i < cnt; ++i) {
1896 uchar nextMarker;
1897 stream >> nextMarker;
1898 if (nextMarker == WidgetMarker) {
1899 QString name;
1900 uchar flags;
1901 stream >> name >> flags;
1902 if (name.isEmpty()) {
1903 int dummy;
1904 stream >> dummy >> dummy >> dummy >> dummy;
1905 continue;
1906 }
1907
1908 QDockWidget *widget = 0;
1909 for (int j = 0; j < widgets.count(); ++j) {
1910 if (widgets.at(j)->objectName() == name) {
1911 widget = widgets.takeAt(j);
1912 break;
1913 }
1914 }
1915
1916 if (widget == 0) {
1917 QPlaceHolderItem *placeHolder = new QPlaceHolderItem;
1918 QDockAreaLayoutItem item(placeHolder);
1919
1920 placeHolder->objectName = name;
1921 placeHolder->window = flags & StateFlagFloating;
1922 placeHolder->hidden = !(flags & StateFlagVisible);
1923 if (placeHolder->window) {
1924 int x, y, w, h;
1925 stream >> x >> y >> w >> h;
1926 placeHolder->topLevelRect = QRect(x, y, w, h);
1927 } else {
1928 int dummy;
1929 stream >> item.pos >> item.size >> dummy >> dummy;
1930 }
1931 if (item.size != -1)
1932 item.flags |= QDockAreaLayoutItem::KeepSize;
1933 if (!testing)
1934 item_list.append(item);
1935 } else {
1936 QDockAreaLayoutItem item(new QDockWidgetItem(widget));
1937 if (flags & StateFlagFloating) {
1938 bool drawer = false;
1939#ifdef Q_WS_MAC // drawer support
1940 extern bool qt_mac_is_macdrawer(const QWidget *); //qwidget_mac.cpp
1941 extern bool qt_mac_set_drawer_preferred_edge(QWidget *, Qt::DockWidgetArea); //qwidget_mac.cpp
1942 drawer = qt_mac_is_macdrawer(widget);
1943#endif
1944
1945 if (!testing) {
1946 widget->hide();
1947 if (!drawer)
1948 widget->setFloating(true);
1949 }
1950
1951 int x, y, w, h;
1952 stream >> x >> y >> w >> h;
1953
1954#ifdef Q_WS_MAC // drawer support
1955 if (drawer) {
1956 mainWindow->window()->createWinId();
1957 widget->window()->createWinId();
1958 qt_mac_set_drawer_preferred_edge(widget, toDockWidgetArea(dockPos));
1959 } else
1960#endif
1961 if (!testing) {
1962 QRect r(x, y, w, h);
1963 QDesktopWidget *desktop = QApplication::desktop();
1964 if (desktop->isVirtualDesktop())
1965 r = constrainedRect(r, desktop->screenGeometry(desktop->screenNumber(r.topLeft())));
1966 else
1967 r = constrainedRect(r, desktop->screenGeometry(widget));
1968 widget->move(r.topLeft());
1969 widget->resize(r.size());
1970 }
1971
1972 if (!testing) {
1973 widget->setVisible(flags & StateFlagVisible);
1974 item_list.append(item);
1975 }
1976 } else {
1977 int dummy;
1978 stream >> item.pos >> item.size >> dummy >> dummy;
1979 if (!testing) {
1980 item_list.append(item);
1981 widget->setFloating(false);
1982 widget->setVisible(flags & StateFlagVisible);
1983 emit widget->dockLocationChanged(toDockWidgetArea(dockPos));
1984 }
1985 }
1986
1987 }
1988 } else if (nextMarker == SequenceMarker) {
1989 int dummy;
1990#ifdef QT_NO_TABBAR
1991 const int tabBarShape = 0;
1992#endif
1993 QDockAreaLayoutInfo *info = new QDockAreaLayoutInfo(sep, dockPos, o,
1994 tabBarShape, mainWindow);
1995 QDockAreaLayoutItem item(info);
1996 stream >> item.pos >> item.size >> dummy >> dummy;
1997 if (!info->restoreState(stream, widgets, testing))
1998 return false;
1999
2000 if (!testing) {
2001 item_list.append(item);
2002 }
2003 } else {
2004 return false;
2005 }
2006 }
2007
2008#ifndef QT_NO_TABBAR
2009 if (!testing && tabbed && index >= 0 && index < item_list.count()) {
2010 updateTabBar();
2011 setCurrentTabId(tabId(item_list.at(index)));
2012 }
2013 if (!testing && sep == 1)
2014 updateSeparatorWidgets();
2015#endif
2016
2017 return true;
2018}
2019
2020#ifndef QT_NO_TABBAR
2021void QDockAreaLayoutInfo::updateSeparatorWidgets() const
2022{
2023 if (tabbed) {
2024 separatorWidgets.clear();
2025 return;
2026 }
2027
2028 int j = 0;
2029 for (int i = 0; i < item_list.count(); ++i) {
2030 const QDockAreaLayoutItem &item = item_list.at(i);
2031
2032 if (item.skip())
2033 continue;
2034
2035 int next = this->next(i);
2036 if ((item.flags & QDockAreaLayoutItem::GapItem)
2037 || (next != -1 && (item_list.at(next).flags & QDockAreaLayoutItem::GapItem)))
2038 continue;
2039
2040 if (item.subinfo) {
2041 item.subinfo->updateSeparatorWidgets();
2042 }
2043
2044 if (next == -1)
2045 break;
2046
2047 QWidget *sepWidget;
2048 if (j < separatorWidgets.size() && separatorWidgets.at(j)) {
2049 sepWidget = separatorWidgets.at(j);
2050 } else {
2051 sepWidget = mainWindowLayout()->getSeparatorWidget();
2052 separatorWidgets.append(sepWidget);
2053 }
2054 j++;
2055
2056#ifndef QT_MAC_USE_COCOA
2057 sepWidget->raise();
2058#endif
2059 QRect sepRect = separatorRect(i).adjusted(-2, -2, 2, 2);
2060 sepWidget->setGeometry(sepRect);
2061 sepWidget->setMask( QRegion(separatorRect(i).translated( - sepRect.topLeft())));
2062 sepWidget->show();
2063 }
2064
2065 for (int k = j; k < separatorWidgets.size(); ++k) {
2066 separatorWidgets[k]->hide();
2067 }
2068 separatorWidgets.resize(j);
2069 Q_ASSERT(separatorWidgets.size() == j);
2070}
2071#endif //QT_NO_TABBAR
2072
2073#ifndef QT_NO_TABBAR
2074void QDockAreaLayoutInfo::updateTabBar() const
2075{
2076 if (!tabbed)
2077 return;
2078
2079 QDockAreaLayoutInfo *that = const_cast<QDockAreaLayoutInfo*>(this);
2080
2081 if (that->tabBar == 0) {
2082 that->tabBar = mainWindowLayout()->getTabBar();
2083 that->tabBar->setShape(static_cast<QTabBar::Shape>(tabBarShape));
2084 that->tabBar->setDrawBase(true);
2085 }
2086
2087 bool blocked = tabBar->blockSignals(true);
2088 bool gap = false;
2089
2090 int tab_idx = 0;
2091 bool changed = false;
2092 for (int i = 0; i < item_list.count(); ++i) {
2093 const QDockAreaLayoutItem &item = item_list.at(i);
2094 if (item.skip())
2095 continue;
2096 if (item.flags & QDockAreaLayoutItem::GapItem) {
2097 gap = true;
2098 continue;
2099 }
2100 if (item.widgetItem == 0)
2101 continue;
2102
2103 QDockWidget *dw = qobject_cast<QDockWidget*>(item.widgetItem->widget());
2104 QString title = dw->d_func()->fixedWindowTitle;
2105 quintptr id = tabId(item);
2106 if (tab_idx == tabBar->count()) {
2107 tabBar->insertTab(tab_idx, title);
2108#ifndef QT_NO_TOOLTIP
2109 tabBar->setTabToolTip(tab_idx, title);
2110#endif
2111 tabBar->setTabData(tab_idx, id);
2112 changed = true;
2113 } else if (qvariant_cast<quintptr>(tabBar->tabData(tab_idx)) != id) {
2114 if (tab_idx + 1 < tabBar->count()
2115 && qvariant_cast<quintptr>(tabBar->tabData(tab_idx + 1)) == id)
2116 tabBar->removeTab(tab_idx);
2117 else {
2118 tabBar->insertTab(tab_idx, title);
2119#ifndef QT_NO_TOOLTIP
2120 tabBar->setTabToolTip(tab_idx, title);
2121#endif
2122 tabBar->setTabData(tab_idx, id);
2123 }
2124 changed = true;
2125 }
2126
2127 if (title != tabBar->tabText(tab_idx)) {
2128 tabBar->setTabText(tab_idx, title);
2129#ifndef QT_NO_TOOLTIP
2130 tabBar->setTabToolTip(tab_idx, title);
2131#endif
2132 changed = true;
2133 }
2134
2135 ++tab_idx;
2136 }
2137
2138 while (tab_idx < tabBar->count()) {
2139 tabBar->removeTab(tab_idx);
2140 changed = true;
2141 }
2142
2143 tabBar->blockSignals(blocked);
2144
2145 that->tabBarVisible = ( (gap ? 1 : 0) + tabBar->count()) > 1;
2146
2147 if (changed || !tabBarMin.isValid() | !tabBarHint.isValid()) {
2148 that->tabBarMin = tabBar->minimumSizeHint();
2149 that->tabBarHint = tabBar->sizeHint();
2150 }
2151}
2152
2153void QDockAreaLayoutInfo::setTabBarShape(int shape)
2154{
2155 if (shape == tabBarShape)
2156 return;
2157 tabBarShape = shape;
2158 if (tabBar != 0) {
2159 tabBar->setShape(static_cast<QTabBar::Shape>(shape));
2160 tabBarMin = QSize();
2161 tabBarHint = QSize();
2162 }
2163
2164 for (int i = 0; i < item_list.count(); ++i) {
2165 QDockAreaLayoutItem &item = item_list[i];
2166 if (item.subinfo != 0)
2167 item.subinfo->setTabBarShape(shape);
2168 }
2169}
2170
2171QSize QDockAreaLayoutInfo::tabBarMinimumSize() const
2172{
2173 if (!tabbed)
2174 return QSize(0, 0);
2175
2176 updateTabBar();
2177
2178 return tabBarMin;
2179}
2180
2181QSize QDockAreaLayoutInfo::tabBarSizeHint() const
2182{
2183 if (!tabbed)
2184 return QSize(0, 0);
2185
2186 updateTabBar();
2187
2188 return tabBarHint;
2189}
2190
2191QSet<QTabBar*> QDockAreaLayoutInfo::usedTabBars() const
2192{
2193 QSet<QTabBar*> result;
2194
2195 if (tabbed) {
2196 updateTabBar();
2197 result.insert(tabBar);
2198 }
2199
2200 for (int i = 0; i < item_list.count(); ++i) {
2201 const QDockAreaLayoutItem &item = item_list.at(i);
2202 if (item.subinfo != 0)
2203 result += item.subinfo->usedTabBars();
2204 }
2205
2206 return result;
2207}
2208
2209// returns a set of all used separator widgets for this dockarelayout info
2210// and all subinfos
2211QSet<QWidget*> QDockAreaLayoutInfo::usedSeparatorWidgets() const
2212{
2213 QSet<QWidget*> result;
2214
2215 for (int i = 0; i < separatorWidgets.count(); ++i)
2216 result << separatorWidgets.at(i);
2217
2218 for (int i = 0; i < item_list.count(); ++i) {
2219 const QDockAreaLayoutItem &item = item_list.at(i);
2220 if (item.subinfo != 0)
2221 result += item.subinfo->usedSeparatorWidgets();
2222 }
2223
2224 return result;
2225}
2226
2227QRect QDockAreaLayoutInfo::tabContentRect() const
2228{
2229 if (!tabbed)
2230 return QRect();
2231
2232 QRect result = rect;
2233 QSize tbh = tabBarSizeHint();
2234
2235 if (tabBarVisible) {
2236 switch (tabBarShape) {
2237 case QTabBar::RoundedNorth:
2238 case QTabBar::TriangularNorth:
2239 result.adjust(0, tbh.height(), 0, 0);
2240 break;
2241 case QTabBar::RoundedSouth:
2242 case QTabBar::TriangularSouth:
2243 result.adjust(0, 0, 0, -tbh.height());
2244 break;
2245 case QTabBar::RoundedEast:
2246 case QTabBar::TriangularEast:
2247 result.adjust(0, 0, -tbh.width(), 0);
2248 break;
2249 case QTabBar::RoundedWest:
2250 case QTabBar::TriangularWest:
2251 result.adjust(tbh.width(), 0, 0, 0);
2252 break;
2253 default:
2254 break;
2255 }
2256 }
2257
2258 return result;
2259}
2260#endif // QT_NO_TABBAR
2261
2262/******************************************************************************
2263** QDockAreaLayout
2264*/
2265
2266QDockAreaLayout::QDockAreaLayout(QMainWindow *win) : fallbackToSizeHints(true)
2267{
2268 mainWindow = win;
2269 sep = win->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent, 0, win);
2270#ifndef QT_NO_TABBAR
2271 const int tabShape = QTabBar::RoundedSouth;
2272#else
2273 const int tabShape = 0;
2274#endif
2275 docks[QInternal::LeftDock]
2276 = QDockAreaLayoutInfo(sep, QInternal::LeftDock, Qt::Vertical, tabShape, win);
2277 docks[QInternal::RightDock]
2278 = QDockAreaLayoutInfo(sep, QInternal::RightDock, Qt::Vertical, tabShape, win);
2279 docks[QInternal::TopDock]
2280 = QDockAreaLayoutInfo(sep, QInternal::TopDock, Qt::Horizontal, tabShape, win);
2281 docks[QInternal::BottomDock]
2282 = QDockAreaLayoutInfo(sep, QInternal::BottomDock, Qt::Horizontal, tabShape, win);
2283 centralWidgetItem = 0;
2284
2285
2286 corners[Qt::TopLeftCorner] = Qt::TopDockWidgetArea;
2287 corners[Qt::TopRightCorner] = Qt::TopDockWidgetArea;
2288 corners[Qt::BottomLeftCorner] = Qt::BottomDockWidgetArea;
2289 corners[Qt::BottomRightCorner] = Qt::BottomDockWidgetArea;
2290}
2291
2292bool QDockAreaLayout::isValid() const
2293{
2294 return rect.isValid();
2295}
2296
2297void QDockAreaLayout::saveState(QDataStream &stream) const
2298{
2299 stream << (uchar) DockWidgetStateMarker;
2300 int cnt = 0;
2301 for (int i = 0; i < QInternal::DockCount; ++i) {
2302 if (!docks[i].item_list.isEmpty())
2303 ++cnt;
2304 }
2305 stream << cnt;
2306 for (int i = 0; i < QInternal::DockCount; ++i) {
2307 if (docks[i].item_list.isEmpty())
2308 continue;
2309 stream << i << docks[i].rect.size();
2310 docks[i].saveState(stream);
2311 }
2312
2313 stream << centralWidgetRect.size();
2314
2315 for (int i = 0; i < 4; ++i)
2316 stream << static_cast<int>(corners[i]);
2317}
2318
2319bool QDockAreaLayout::restoreState(QDataStream &stream, const QList<QDockWidget*> &_dockwidgets, bool testing)
2320{
2321 QList<QDockWidget*> dockwidgets = _dockwidgets;
2322
2323 int cnt;
2324 stream >> cnt;
2325 for (int i = 0; i < cnt; ++i) {
2326 int pos;
2327 stream >> pos;
2328 QSize size;
2329 stream >> size;
2330 if (!testing) {
2331 docks[pos].rect = QRect(QPoint(0, 0), size);
2332 }
2333 if (!docks[pos].restoreState(stream, dockwidgets, testing)) {
2334 stream.setStatus(QDataStream::ReadCorruptData);
2335 return false;
2336 }
2337 }
2338
2339 QSize size;
2340 stream >> size;
2341 centralWidgetRect = QRect(QPoint(0, 0), size);
2342
2343 bool ok = stream.status() == QDataStream::Ok;
2344
2345 if (ok) {
2346 int cornerData[4];
2347 for (int i = 0; i < 4; ++i)
2348 stream >> cornerData[i];
2349 if (stream.status() == QDataStream::Ok) {
2350 for (int i = 0; i < 4; ++i)
2351 corners[i] = static_cast<Qt::DockWidgetArea>(cornerData[i]);
2352 }
2353
2354 if (!testing)
2355 fallbackToSizeHints = false;
2356 }
2357
2358 return ok;
2359}
2360
2361QList<int> QDockAreaLayout::indexOfPlaceHolder(const QString &objectName) const
2362{
2363 for (int i = 0; i < QInternal::DockCount; ++i) {
2364 QList<int> result = docks[i].indexOfPlaceHolder(objectName);
2365 if (!result.isEmpty()) {
2366 result.prepend(i);
2367 return result;
2368 }
2369 }
2370 return QList<int>();
2371}
2372
2373QList<int> QDockAreaLayout::indexOf(QWidget *dockWidget) const
2374{
2375 for (int i = 0; i < QInternal::DockCount; ++i) {
2376 QList<int> result = docks[i].indexOf(dockWidget);
2377 if (!result.isEmpty()) {
2378 result.prepend(i);
2379 return result;
2380 }
2381 }
2382 return QList<int>();
2383}
2384
2385QList<int> QDockAreaLayout::gapIndex(const QPoint &pos) const
2386{
2387 QMainWindow::DockOptions opts = mainWindow->dockOptions();
2388 bool nestingEnabled = opts & QMainWindow::AllowNestedDocks;
2389 QDockAreaLayoutInfo::TabMode tabMode = QDockAreaLayoutInfo::NoTabs;
2390#ifndef QT_NO_TABBAR
2391 if (opts & QMainWindow::AllowTabbedDocks
2392 || opts & QMainWindow::VerticalTabs)
2393 tabMode = QDockAreaLayoutInfo::AllowTabs;
2394 if (opts & QMainWindow::ForceTabbedDocks)
2395 tabMode = QDockAreaLayoutInfo::ForceTabs;
2396
2397 if (tabMode == QDockAreaLayoutInfo::ForceTabs)
2398 nestingEnabled = false;
2399#endif
2400
2401
2402 for (int i = 0; i < QInternal::DockCount; ++i) {
2403 const QDockAreaLayoutInfo &info = docks[i];
2404
2405 if (!info.isEmpty() && info.rect.contains(pos)) {
2406 QList<int> result
2407 = docks[i].gapIndex(pos, nestingEnabled, tabMode);
2408 if (!result.isEmpty())
2409 result.prepend(i);
2410 return result;
2411 }
2412 }
2413
2414 for (int i = 0; i < QInternal::DockCount; ++i) {
2415 const QDockAreaLayoutInfo &info = docks[i];
2416
2417 if (info.isEmpty()) {
2418 QRect r;
2419 switch (i) {
2420 case QInternal::LeftDock:
2421 r = QRect(rect.left(), rect.top(), EmptyDropAreaSize, rect.height());
2422 break;
2423 case QInternal::RightDock:
2424 r = QRect(rect.right() - EmptyDropAreaSize, rect.top(),
2425 EmptyDropAreaSize, rect.height());
2426 break;
2427 case QInternal::TopDock:
2428 r = QRect(rect.left(), rect.top(), rect.width(), EmptyDropAreaSize);
2429 break;
2430 case QInternal::BottomDock:
2431 r = QRect(rect.left(), rect.bottom() - EmptyDropAreaSize,
2432 rect.width(), EmptyDropAreaSize);
2433 break;
2434 }
2435 if (r.contains(pos)) {
2436 if (opts & QMainWindow::ForceTabbedDocks && !info.item_list.isEmpty()) {
2437 //in case of ForceTabbedDocks, we pass -1 in order to force the gap to be tabbed
2438 //it mustn't be completely empty otherwise it won't work
2439 return QList<int>() << i << -1 << 0;
2440 } else {
2441 return QList<int>() << i << 0;
2442 }
2443 }
2444 }
2445 }
2446
2447 return QList<int>();
2448}
2449
2450QList<int> QDockAreaLayout::findSeparator(const QPoint &pos) const
2451{
2452 QList<int> result;
2453 for (int i = 0; i < QInternal::DockCount; ++i) {
2454 const QDockAreaLayoutInfo &info = docks[i];
2455 if (info.isEmpty())
2456 continue;
2457 QRect rect = separatorRect(i);
2458 if (!rect.isNull() && sep == 1)
2459 rect.adjust(-2, -2, 2, 2);
2460 if (rect.contains(pos) && !info.hasFixedSize()) {
2461 result << i;
2462 break;
2463 } else if (info.rect.contains(pos)) {
2464 result = docks[i].findSeparator(pos);
2465 if (!result.isEmpty()) {
2466 result.prepend(i);
2467 break;
2468 }
2469 }
2470 }
2471
2472 return result;
2473}
2474
2475QDockAreaLayoutInfo *QDockAreaLayout::info(QWidget *widget)
2476{
2477 for (int i = 0; i < QInternal::DockCount; ++i) {
2478 if (QDockAreaLayoutInfo *result = docks[i].info(widget))
2479 return result;
2480 }
2481
2482 return 0;
2483}
2484
2485QDockAreaLayoutInfo *QDockAreaLayout::info(const QList<int> &path)
2486{
2487 Q_ASSERT(!path.isEmpty());
2488 const int index = path.first();
2489 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2490
2491 if (path.count() == 1)
2492 return &docks[index];
2493
2494 return docks[index].info(path.mid(1));
2495}
2496
2497const QDockAreaLayoutInfo *QDockAreaLayout::info(const QList<int> &path) const
2498{
2499 return const_cast<QDockAreaLayout*>(this)->info(path);
2500}
2501
2502QDockAreaLayoutItem &QDockAreaLayout::item(const QList<int> &path)
2503{
2504 Q_ASSERT(!path.isEmpty());
2505 const int index = path.first();
2506 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2507 return docks[index].item(path.mid(1));
2508}
2509
2510QRect QDockAreaLayout::itemRect(const QList<int> &path) const
2511{
2512 Q_ASSERT(!path.isEmpty());
2513 const int index = path.first();
2514 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2515 return docks[index].itemRect(path.mid(1));
2516}
2517
2518QRect QDockAreaLayout::separatorRect(int index) const
2519{
2520 const QDockAreaLayoutInfo &dock = docks[index];
2521 if (dock.isEmpty())
2522 return QRect();
2523 QRect r = dock.rect;
2524 switch (index) {
2525 case QInternal::LeftDock:
2526 return QRect(r.right() + 1, r.top(), sep, r.height());
2527 case QInternal::RightDock:
2528 return QRect(r.left() - sep, r.top(), sep, r.height());
2529 case QInternal::TopDock:
2530 return QRect(r.left(), r.bottom() + 1, r.width(), sep);
2531 case QInternal::BottomDock:
2532 return QRect(r.left(), r.top() - sep, r.width(), sep);
2533 default:
2534 break;
2535 }
2536 return QRect();
2537}
2538
2539QRect QDockAreaLayout::separatorRect(const QList<int> &path) const
2540{
2541 Q_ASSERT(!path.isEmpty());
2542
2543 const int index = path.first();
2544 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2545
2546 if (path.count() == 1)
2547 return separatorRect(index);
2548 else
2549 return docks[index].separatorRect(path.mid(1));
2550}
2551
2552bool QDockAreaLayout::insertGap(const QList<int> &path, QLayoutItem *dockWidgetItem)
2553{
2554 Q_ASSERT(!path.isEmpty());
2555 const int index = path.first();
2556 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2557 return docks[index].insertGap(path.mid(1), dockWidgetItem);
2558}
2559
2560QLayoutItem *QDockAreaLayout::plug(const QList<int> &path)
2561{
2562 Q_ASSERT(!path.isEmpty());
2563 const int index = path.first();
2564 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2565 return docks[index].plug(path.mid(1));
2566}
2567
2568QLayoutItem *QDockAreaLayout::unplug(const QList<int> &path)
2569{
2570 Q_ASSERT(!path.isEmpty());
2571 const int index = path.first();
2572 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2573 return docks[index].unplug(path.mid(1));
2574}
2575
2576void QDockAreaLayout::remove(const QList<int> &path)
2577{
2578 Q_ASSERT(!path.isEmpty());
2579 const int index = path.first();
2580 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2581 docks[index].remove(path.mid(1));
2582}
2583
2584static inline int qMin(int i1, int i2, int i3) { return qMin(i1, qMin(i2, i3)); }
2585static inline int qMax(int i1, int i2, int i3) { return qMax(i1, qMax(i2, i3)); }
2586
2587void QDockAreaLayout::getGrid(QVector<QLayoutStruct> *_ver_struct_list,
2588 QVector<QLayoutStruct> *_hor_struct_list)
2589{
2590 QSize center_hint(0, 0);
2591 QSize center_min(0, 0);
2592 const bool have_central = centralWidgetItem != 0 && !centralWidgetItem->isEmpty();
2593 if (have_central) {
2594 center_hint = centralWidgetRect.size();
2595 if (!center_hint.isValid())
2596 center_hint = centralWidgetItem->sizeHint();
2597 center_min = centralWidgetItem->minimumSize();
2598 }
2599
2600 QRect center_rect = rect;
2601 if (!docks[QInternal::LeftDock].isEmpty())
2602 center_rect.setLeft(rect.left() + docks[QInternal::LeftDock].rect.width() + sep);
2603 if (!docks[QInternal::TopDock].isEmpty())
2604 center_rect.setTop(rect.top() + docks[QInternal::TopDock].rect.height() + sep);
2605 if (!docks[QInternal::RightDock].isEmpty())
2606 center_rect.setRight(rect.right() - docks[QInternal::RightDock].rect.width() - sep);
2607 if (!docks[QInternal::BottomDock].isEmpty())
2608 center_rect.setBottom(rect.bottom() - docks[QInternal::BottomDock].rect.height() - sep);
2609
2610 QSize left_hint = docks[QInternal::LeftDock].size();
2611 if (left_hint.isNull() || fallbackToSizeHints)
2612 left_hint = docks[QInternal::LeftDock].sizeHint();
2613 QSize left_min = docks[QInternal::LeftDock].minimumSize();
2614 QSize left_max = docks[QInternal::LeftDock].maximumSize();
2615 left_hint = left_hint.boundedTo(left_max).expandedTo(left_min);
2616
2617 QSize right_hint = docks[QInternal::RightDock].size();
2618 if (right_hint.isNull() || fallbackToSizeHints)
2619 right_hint = docks[QInternal::RightDock].sizeHint();
2620 QSize right_min = docks[QInternal::RightDock].minimumSize();
2621 QSize right_max = docks[QInternal::RightDock].maximumSize();
2622 right_hint = right_hint.boundedTo(right_max).expandedTo(right_min);
2623
2624 QSize top_hint = docks[QInternal::TopDock].size();
2625 if (top_hint.isNull() || fallbackToSizeHints)
2626 top_hint = docks[QInternal::TopDock].sizeHint();
2627 QSize top_min = docks[QInternal::TopDock].minimumSize();
2628 QSize top_max = docks[QInternal::TopDock].maximumSize();
2629 top_hint = top_hint.boundedTo(top_max).expandedTo(top_min);
2630
2631 QSize bottom_hint = docks[QInternal::BottomDock].size();
2632 if (bottom_hint.isNull() || fallbackToSizeHints)
2633 bottom_hint = docks[QInternal::BottomDock].sizeHint();
2634 QSize bottom_min = docks[QInternal::BottomDock].minimumSize();
2635 QSize bottom_max = docks[QInternal::BottomDock].maximumSize();
2636 bottom_hint = bottom_hint.boundedTo(bottom_max).expandedTo(bottom_min);
2637
2638 fallbackToSizeHints = !have_central;
2639
2640 if (_ver_struct_list != 0) {
2641 QVector<QLayoutStruct> &ver_struct_list = *_ver_struct_list;
2642 ver_struct_list.resize(3);
2643
2644 // top --------------------------------------------------
2645 ver_struct_list[0].init();
2646 ver_struct_list[0].stretch = 0;
2647 ver_struct_list[0].sizeHint = top_hint.height();
2648 ver_struct_list[0].minimumSize = top_min.height();
2649 ver_struct_list[0].maximumSize = top_max.height();
2650 ver_struct_list[0].expansive = false;
2651 ver_struct_list[0].empty = docks[QInternal::TopDock].isEmpty();
2652 ver_struct_list[0].pos = docks[QInternal::TopDock].rect.top();
2653 ver_struct_list[0].size = docks[QInternal::TopDock].rect.height();
2654
2655 // center --------------------------------------------------
2656 ver_struct_list[1].init();
2657 ver_struct_list[1].stretch = center_hint.height();
2658
2659 bool tl_significant = corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea
2660 || docks[QInternal::TopDock].isEmpty();
2661 bool bl_significant = corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea
2662 || docks[QInternal::BottomDock].isEmpty();
2663 bool tr_significant = corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea
2664 || docks[QInternal::TopDock].isEmpty();
2665 bool br_significant = corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea
2666 || docks[QInternal::BottomDock].isEmpty();
2667
2668 int left = (tl_significant && bl_significant) ? left_hint.height() : 0;
2669 int right = (tr_significant && br_significant) ? right_hint.height() : 0;
2670 ver_struct_list[1].sizeHint = qMax(left, center_hint.height(), right);
2671
2672 left = (tl_significant && bl_significant) ? left_min.height() : 0;
2673 right = (tr_significant && br_significant) ? right_min.height() : 0;
2674 ver_struct_list[1].minimumSize = qMax(left, center_min.height(), right);
2675 ver_struct_list[1].maximumSize = have_central ? QWIDGETSIZE_MAX : 0;
2676 ver_struct_list[1].expansive = have_central;
2677 ver_struct_list[1].empty = docks[QInternal::LeftDock].isEmpty()
2678 && !have_central
2679 && docks[QInternal::RightDock].isEmpty();
2680 ver_struct_list[1].pos = center_rect.top();
2681 ver_struct_list[1].size = center_rect.height();
2682
2683 // bottom --------------------------------------------------
2684 ver_struct_list[2].init();
2685 ver_struct_list[2].stretch = 0;
2686 ver_struct_list[2].sizeHint = bottom_hint.height();
2687 ver_struct_list[2].minimumSize = bottom_min.height();
2688 ver_struct_list[2].maximumSize = bottom_max.height();
2689 ver_struct_list[2].expansive = false;
2690 ver_struct_list[2].empty = docks[QInternal::BottomDock].isEmpty();
2691 ver_struct_list[2].pos = docks[QInternal::BottomDock].rect.top();
2692 ver_struct_list[2].size = docks[QInternal::BottomDock].rect.height();
2693
2694 for (int i = 0; i < 3; ++i) {
2695 ver_struct_list[i].sizeHint
2696 = qMax(ver_struct_list[i].sizeHint, ver_struct_list[i].minimumSize);
2697 }
2698 }
2699
2700 if (_hor_struct_list != 0) {
2701 QVector<QLayoutStruct> &hor_struct_list = *_hor_struct_list;
2702 hor_struct_list.resize(3);
2703
2704 // left --------------------------------------------------
2705 hor_struct_list[0].init();
2706 hor_struct_list[0].stretch = 0;
2707 hor_struct_list[0].sizeHint = left_hint.width();
2708 hor_struct_list[0].minimumSize = left_min.width();
2709 hor_struct_list[0].maximumSize = left_max.width();
2710 hor_struct_list[0].expansive = false;
2711 hor_struct_list[0].empty = docks[QInternal::LeftDock].isEmpty();
2712 hor_struct_list[0].pos = docks[QInternal::LeftDock].rect.left();
2713 hor_struct_list[0].size = docks[QInternal::LeftDock].rect.width();
2714
2715 // center --------------------------------------------------
2716 hor_struct_list[1].init();
2717 hor_struct_list[1].stretch = center_hint.width();
2718
2719 bool tl_significant = corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea
2720 || docks[QInternal::LeftDock].isEmpty();
2721 bool tr_significant = corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea
2722 || docks[QInternal::RightDock].isEmpty();
2723 bool bl_significant = corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea
2724 || docks[QInternal::LeftDock].isEmpty();
2725 bool br_significant = corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea
2726 || docks[QInternal::RightDock].isEmpty();
2727
2728 int top = (tl_significant && tr_significant) ? top_hint.width() : 0;
2729 int bottom = (bl_significant && br_significant) ? bottom_hint.width() : 0;
2730 hor_struct_list[1].sizeHint = qMax(top, center_hint.width(), bottom);
2731
2732 top = (tl_significant && tr_significant) ? top_min.width() : 0;
2733 bottom = (bl_significant && br_significant) ? bottom_min.width() : 0;
2734 hor_struct_list[1].minimumSize = qMax(top, center_min.width(), bottom);
2735
2736 hor_struct_list[1].maximumSize = have_central ? QWIDGETSIZE_MAX : 0;
2737 hor_struct_list[1].expansive = have_central;
2738 hor_struct_list[1].empty = !have_central;
2739 hor_struct_list[1].pos = center_rect.left();
2740 hor_struct_list[1].size = center_rect.width();
2741
2742 // right --------------------------------------------------
2743 hor_struct_list[2].init();
2744 hor_struct_list[2].stretch = 0;
2745 hor_struct_list[2].sizeHint = right_hint.width();
2746 hor_struct_list[2].minimumSize = right_min.width();
2747 hor_struct_list[2].maximumSize = right_max.width();
2748 hor_struct_list[2].expansive = false;
2749 hor_struct_list[2].empty = docks[QInternal::RightDock].isEmpty();
2750 hor_struct_list[2].pos = docks[QInternal::RightDock].rect.left();
2751 hor_struct_list[2].size = docks[QInternal::RightDock].rect.width();
2752
2753 for (int i = 0; i < 3; ++i) {
2754 hor_struct_list[i].sizeHint
2755 = qMax(hor_struct_list[i].sizeHint, hor_struct_list[i].minimumSize);
2756 }
2757 }
2758}
2759
2760void QDockAreaLayout::setGrid(QVector<QLayoutStruct> *ver_struct_list,
2761 QVector<QLayoutStruct> *hor_struct_list)
2762{
2763
2764 // top ---------------------------------------------------
2765
2766 if (!docks[QInternal::TopDock].isEmpty()) {
2767 QRect r = docks[QInternal::TopDock].rect;
2768 if (hor_struct_list != 0) {
2769 r.setLeft(corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea
2770 || docks[QInternal::LeftDock].isEmpty()
2771 ? rect.left() : hor_struct_list->at(1).pos);
2772 r.setRight(corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea
2773 || docks[QInternal::RightDock].isEmpty()
2774 ? rect.right() : hor_struct_list->at(2).pos - sep - 1);
2775 }
2776 if (ver_struct_list != 0) {
2777 r.setTop(rect.top());
2778 r.setBottom(ver_struct_list->at(1).pos - sep - 1);
2779 }
2780 docks[QInternal::TopDock].rect = r;
2781 docks[QInternal::TopDock].fitItems();
2782 }
2783
2784 // bottom ---------------------------------------------------
2785
2786 if (!docks[QInternal::BottomDock].isEmpty()) {
2787 QRect r = docks[QInternal::BottomDock].rect;
2788 if (hor_struct_list != 0) {
2789 r.setLeft(corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea
2790 || docks[QInternal::LeftDock].isEmpty()
2791 ? rect.left() : hor_struct_list->at(1).pos);
2792 r.setRight(corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea
2793 || docks[QInternal::RightDock].isEmpty()
2794 ? rect.right() : hor_struct_list->at(2).pos - sep - 1);
2795 }
2796 if (ver_struct_list != 0) {
2797 r.setTop(ver_struct_list->at(2).pos);
2798 r.setBottom(rect.bottom());
2799 }
2800 docks[QInternal::BottomDock].rect = r;
2801 docks[QInternal::BottomDock].fitItems();
2802 }
2803
2804 // left ---------------------------------------------------
2805
2806 if (!docks[QInternal::LeftDock].isEmpty()) {
2807 QRect r = docks[QInternal::LeftDock].rect;
2808 if (hor_struct_list != 0) {
2809 r.setLeft(rect.left());
2810 r.setRight(hor_struct_list->at(1).pos - sep - 1);
2811 }
2812 if (ver_struct_list != 0) {
2813 r.setTop(corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea
2814 || docks[QInternal::TopDock].isEmpty()
2815 ? rect.top() : ver_struct_list->at(1).pos);
2816 r.setBottom(corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea
2817 || docks[QInternal::BottomDock].isEmpty()
2818 ? rect.bottom() : ver_struct_list->at(2).pos - sep - 1);
2819 }
2820 docks[QInternal::LeftDock].rect = r;
2821 docks[QInternal::LeftDock].fitItems();
2822 }
2823
2824 // right ---------------------------------------------------
2825
2826 if (!docks[QInternal::RightDock].isEmpty()) {
2827 QRect r = docks[QInternal::RightDock].rect;
2828 if (hor_struct_list != 0) {
2829 r.setLeft(hor_struct_list->at(2).pos);
2830 r.setRight(rect.right());
2831 }
2832 if (ver_struct_list != 0) {
2833 r.setTop(corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea
2834 || docks[QInternal::TopDock].isEmpty()
2835 ? rect.top() : ver_struct_list->at(1).pos);
2836 r.setBottom(corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea
2837 || docks[QInternal::BottomDock].isEmpty()
2838 ? rect.bottom() : ver_struct_list->at(2).pos - sep - 1);
2839 }
2840 docks[QInternal::RightDock].rect = r;
2841 docks[QInternal::RightDock].fitItems();
2842 }
2843
2844 // center ---------------------------------------------------
2845
2846 if (hor_struct_list != 0) {
2847 centralWidgetRect.setLeft(hor_struct_list->at(1).pos);
2848 centralWidgetRect.setWidth(hor_struct_list->at(1).size);
2849 }
2850 if (ver_struct_list != 0) {
2851 centralWidgetRect.setTop(ver_struct_list->at(1).pos);
2852 centralWidgetRect.setHeight(ver_struct_list->at(1).size);
2853 }
2854}
2855
2856void QDockAreaLayout::fitLayout()
2857{
2858 QVector<QLayoutStruct> ver_struct_list(3);
2859 QVector<QLayoutStruct> hor_struct_list(3);
2860 getGrid(&ver_struct_list, &hor_struct_list);
2861
2862 qGeomCalc(ver_struct_list, 0, 3, rect.top(), rect.height(), sep);
2863 qGeomCalc(hor_struct_list, 0, 3, rect.left(), rect.width(), sep);
2864
2865 setGrid(&ver_struct_list, &hor_struct_list);
2866}
2867
2868void QDockAreaLayout::clear()
2869{
2870 for (int i = 0; i < QInternal::DockCount; ++i)
2871 docks[i].clear();
2872
2873 rect = QRect();
2874 centralWidgetRect = QRect();
2875}
2876
2877QSize QDockAreaLayout::sizeHint() const
2878{
2879 int left_sep = 0;
2880 int right_sep = 0;
2881 int top_sep = 0;
2882 int bottom_sep = 0;
2883
2884 if (centralWidgetItem != 0) {
2885 left_sep = docks[QInternal::LeftDock].isEmpty() ? 0 : sep;
2886 right_sep = docks[QInternal::RightDock].isEmpty() ? 0 : sep;
2887 top_sep = docks[QInternal::TopDock].isEmpty() ? 0 : sep;
2888 bottom_sep = docks[QInternal::BottomDock].isEmpty() ? 0 : sep;
2889 }
2890
2891 QSize left = docks[QInternal::LeftDock].sizeHint() + QSize(left_sep, 0);
2892 QSize right = docks[QInternal::RightDock].sizeHint() + QSize(right_sep, 0);
2893 QSize top = docks[QInternal::TopDock].sizeHint() + QSize(0, top_sep);
2894 QSize bottom = docks[QInternal::BottomDock].sizeHint() + QSize(0, bottom_sep);
2895 QSize center = centralWidgetItem == 0 ? QSize(0, 0) : centralWidgetItem->sizeHint();
2896
2897 int row1 = top.width();
2898 int row2 = left.width() + center.width() + right.width();
2899 int row3 = bottom.width();
2900 int col1 = left.height();
2901 int col2 = top.height() + center.height() + bottom.height();
2902 int col3 = right.height();
2903
2904 if (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea)
2905 row1 += left.width();
2906 else
2907 col1 += top.height();
2908
2909 if (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea)
2910 row1 += right.width();
2911 else
2912 col3 += top.height();
2913
2914 if (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea)
2915 row3 += left.width();
2916 else
2917 col1 += bottom.height();
2918
2919 if (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea)
2920 row3 += right.width();
2921 else
2922 col3 += bottom.height();
2923
2924 return QSize(qMax(row1, row2, row3), qMax(col1, col2, col3));
2925}
2926
2927QSize QDockAreaLayout::minimumSize() const
2928{
2929 int left_sep = 0;
2930 int right_sep = 0;
2931 int top_sep = 0;
2932 int bottom_sep = 0;
2933
2934 if (centralWidgetItem != 0) {
2935 left_sep = docks[QInternal::LeftDock].isEmpty() ? 0 : sep;
2936 right_sep = docks[QInternal::RightDock].isEmpty() ? 0 : sep;
2937 top_sep = docks[QInternal::TopDock].isEmpty() ? 0 : sep;
2938 bottom_sep = docks[QInternal::BottomDock].isEmpty() ? 0 : sep;
2939 }
2940
2941 QSize left = docks[QInternal::LeftDock].minimumSize() + QSize(left_sep, 0);
2942 QSize right = docks[QInternal::RightDock].minimumSize() + QSize(right_sep, 0);
2943 QSize top = docks[QInternal::TopDock].minimumSize() + QSize(0, top_sep);
2944 QSize bottom = docks[QInternal::BottomDock].minimumSize() + QSize(0, bottom_sep);
2945 QSize center = centralWidgetItem == 0 ? QSize(0, 0) : centralWidgetItem->minimumSize();
2946
2947 int row1 = top.width();
2948 int row2 = left.width() + center.width() + right.width();
2949 int row3 = bottom.width();
2950 int col1 = left.height();
2951 int col2 = top.height() + center.height() + bottom.height();
2952 int col3 = right.height();
2953
2954 if (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea)
2955 row1 += left.width();
2956 else
2957 col1 += top.height();
2958
2959 if (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea)
2960 row1 += right.width();
2961 else
2962 col3 += top.height();
2963
2964 if (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea)
2965 row3 += left.width();
2966 else
2967 col1 += bottom.height();
2968
2969 if (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea)
2970 row3 += right.width();
2971 else
2972 col3 += bottom.height();
2973
2974 return QSize(qMax(row1, row2, row3), qMax(col1, col2, col3));
2975}
2976
2977bool QDockAreaLayout::restoreDockWidget(QDockWidget *dockWidget)
2978{
2979 QList<int> index = indexOfPlaceHolder(dockWidget->objectName());
2980 if (index.isEmpty())
2981 return false;
2982
2983 QDockAreaLayoutItem &item = this->item(index);
2984 QPlaceHolderItem *placeHolder = item.placeHolderItem;
2985 Q_ASSERT(placeHolder != 0);
2986
2987 item.widgetItem = new QDockWidgetItem(dockWidget);
2988
2989 if (placeHolder->window) {
2990 QDesktopWidget desktop;
2991 QRect r = constrainedRect(placeHolder->topLevelRect, desktop.screenGeometry(dockWidget));
2992 dockWidget->d_func()->setWindowState(true, true, r);
2993 }
2994 dockWidget->show();
2995// dockWidget->setVisible(!placeHolder->hidden);
2996#ifdef Q_WS_X11
2997 if (placeHolder->window) // gets rid of the X11BypassWindowManager window flag
2998 dockWidget->d_func()->setWindowState(true);
2999#endif
3000
3001 item.placeHolderItem = 0;
3002 delete placeHolder;
3003
3004 return true;
3005}
3006
3007void QDockAreaLayout::addDockWidget(QInternal::DockPosition pos, QDockWidget *dockWidget,
3008 Qt::Orientation orientation)
3009{
3010 QLayoutItem *dockWidgetItem = new QDockWidgetItem(dockWidget);
3011 QDockAreaLayoutInfo &info = docks[pos];
3012 if (orientation == info.o || info.item_list.count() <= 1) {
3013 // empty dock areas, or dock areas containing exactly one widget can have their orientation
3014 // switched.
3015 info.o = orientation;
3016
3017 QDockAreaLayoutItem new_item(dockWidgetItem);
3018 info.item_list.append(new_item);
3019#ifndef QT_NO_TABBAR
3020 if (info.tabbed && !new_item.skip()) {
3021 info.updateTabBar();
3022 info.setCurrentTabId(tabId(new_item));
3023 }
3024#endif
3025 } else {
3026#ifndef QT_NO_TABBAR
3027 int tbshape = info.tabBarShape;
3028#else
3029 int tbshape = 0;
3030#endif
3031 QDockAreaLayoutInfo new_info(sep, pos, orientation, tbshape, mainWindow);
3032 new_info.item_list.append(new QDockAreaLayoutInfo(info));
3033 new_info.item_list.append(dockWidgetItem);
3034 info = new_info;
3035 }
3036
3037 QList<int> index = indexOfPlaceHolder(dockWidget->objectName());
3038 if (!index.isEmpty())
3039 remove(index);
3040}
3041
3042void QDockAreaLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
3043{
3044 QList<int> path = indexOf(first);
3045 if (path.isEmpty())
3046 return;
3047
3048 QDockAreaLayoutInfo *info = this->info(path);
3049 Q_ASSERT(info != 0);
3050 info->tab(path.last(), new QDockWidgetItem(second));
3051
3052 QList<int> index = indexOfPlaceHolder(second->objectName());
3053 if (!index.isEmpty())
3054 remove(index);
3055}
3056
3057void QDockAreaLayout::splitDockWidget(QDockWidget *after,
3058 QDockWidget *dockWidget,
3059 Qt::Orientation orientation)
3060{
3061 QList<int> path = indexOf(after);
3062 if (path.isEmpty())
3063 return;
3064
3065 QDockAreaLayoutInfo *info = this->info(path);
3066 Q_ASSERT(info != 0);
3067 info->split(path.last(), orientation, new QDockWidgetItem(dockWidget));
3068
3069 QList<int> index = indexOfPlaceHolder(dockWidget->objectName());
3070 if (!index.isEmpty())
3071 remove(index);
3072}
3073
3074void QDockAreaLayout::apply(bool animate)
3075{
3076 QWidgetAnimator &widgetAnimator
3077 = qobject_cast<QMainWindowLayout*>(mainWindow->layout())->widgetAnimator;
3078
3079 for (int i = 0; i < QInternal::DockCount; ++i)
3080 docks[i].apply(animate);
3081 if (centralWidgetItem != 0 && !centralWidgetItem->isEmpty()) {
3082 widgetAnimator.animate(centralWidgetItem->widget(), centralWidgetRect,
3083 animate);
3084 }
3085#ifndef QT_NO_TABBAR
3086 if (sep == 1)
3087 updateSeparatorWidgets();
3088#endif //QT_NO_TABBAR
3089}
3090
3091void QDockAreaLayout::paintSeparators(QPainter *p, QWidget *widget,
3092 const QRegion &clip,
3093 const QPoint &mouse) const
3094{
3095 for (int i = 0; i < QInternal::DockCount; ++i) {
3096 const QDockAreaLayoutInfo &dock = docks[i];
3097 if (dock.isEmpty())
3098 continue;
3099 QRect r = separatorRect(i);
3100 if (clip.contains(r) && !dock.hasFixedSize()) {
3101 Qt::Orientation opposite = dock.o == Qt::Horizontal
3102 ? Qt::Vertical : Qt::Horizontal;
3103 paintSep(p, widget, r, opposite, r.contains(mouse));
3104 }
3105 if (clip.contains(dock.rect))
3106 dock.paintSeparators(p, widget, clip, mouse);
3107 }
3108}
3109
3110QRegion QDockAreaLayout::separatorRegion() const
3111{
3112 QRegion result;
3113
3114 for (int i = 0; i < QInternal::DockCount; ++i) {
3115 const QDockAreaLayoutInfo &dock = docks[i];
3116 if (dock.isEmpty())
3117 continue;
3118 result |= separatorRect(i);
3119 result |= dock.separatorRegion();
3120 }
3121
3122 return result;
3123}
3124
3125int QDockAreaLayout::separatorMove(const QList<int> &separator, const QPoint &origin,
3126 const QPoint &dest)
3127{
3128 int delta = 0;
3129 int index = separator.last();
3130
3131 if (separator.count() > 1) {
3132 QDockAreaLayoutInfo *info = this->info(separator);
3133 delta = pick(info->o, dest - origin);
3134 if (delta != 0)
3135 delta = info->separatorMove(index, delta);
3136 info->apply(false);
3137 return delta;
3138 }
3139
3140 QVector<QLayoutStruct> list;
3141
3142 if (index == QInternal::LeftDock || index == QInternal::RightDock)
3143 getGrid(0, &list);
3144 else
3145 getGrid(&list, 0);
3146
3147 int sep_index = index == QInternal::LeftDock || index == QInternal::TopDock
3148 ? 0 : 1;
3149 Qt::Orientation o = index == QInternal::LeftDock || index == QInternal::RightDock
3150 ? Qt::Horizontal
3151 : Qt::Vertical;
3152
3153 delta = pick(o, dest - origin);
3154 delta = separatorMoveHelper(list, sep_index, delta, sep);
3155
3156 if (index == QInternal::LeftDock || index == QInternal::RightDock)
3157 setGrid(0, &list);
3158 else
3159 setGrid(&list, 0);
3160
3161 apply(false);
3162
3163 return delta;
3164}
3165
3166#ifndef QT_NO_TABBAR
3167// Sets the correct positions for the seperator widgets
3168// Allocates new sepearator widgets with getSeparatorWidget
3169void QDockAreaLayout::updateSeparatorWidgets() const
3170{
3171 int j = 0;
3172
3173 for (int i = 0; i < QInternal::DockCount; ++i) {
3174 const QDockAreaLayoutInfo &dock = docks[i];
3175 if (dock.isEmpty())
3176 continue;
3177
3178 QWidget *sepWidget;
3179 if (j < separatorWidgets.size()) {
3180 sepWidget = separatorWidgets.at(j);
3181 } else {
3182 sepWidget = qobject_cast<QMainWindowLayout*>(mainWindow->layout())->getSeparatorWidget();
3183 separatorWidgets.append(sepWidget);
3184 }
3185 j++;
3186
3187#ifndef QT_MAC_USE_COCOA
3188 sepWidget->raise();
3189#endif
3190 QRect sepRect = separatorRect(i).adjusted(-2, -2, 2, 2);
3191 sepWidget->setGeometry(sepRect);
3192 sepWidget->setMask( QRegion(separatorRect(i).translated( - sepRect.topLeft())));
3193 sepWidget->show();
3194 }
3195 for (int i = j; i < separatorWidgets.size(); ++i)
3196 separatorWidgets.at(i)->hide();
3197
3198 separatorWidgets.resize(j);
3199}
3200#endif //QT_NO_TABBAR
3201
3202QLayoutItem *QDockAreaLayout::itemAt(int *x, int index) const
3203{
3204 Q_ASSERT(x != 0);
3205
3206 for (int i = 0; i < QInternal::DockCount; ++i) {
3207 const QDockAreaLayoutInfo &dock = docks[i];
3208 if (QLayoutItem *ret = dock.itemAt(x, index))
3209 return ret;
3210 }
3211
3212 if (centralWidgetItem && (*x)++ == index)
3213 return centralWidgetItem;
3214
3215 return 0;
3216}
3217
3218QLayoutItem *QDockAreaLayout::takeAt(int *x, int index)
3219{
3220 Q_ASSERT(x != 0);
3221
3222 for (int i = 0; i < QInternal::DockCount; ++i) {
3223 QDockAreaLayoutInfo &dock = docks[i];
3224 if (QLayoutItem *ret = dock.takeAt(x, index))
3225 return ret;
3226 }
3227
3228 if (centralWidgetItem && (*x)++ == index) {
3229 QLayoutItem *ret = centralWidgetItem;
3230 centralWidgetItem = 0;
3231 return ret;
3232 }
3233
3234 return 0;
3235}
3236
3237void QDockAreaLayout::deleteAllLayoutItems()
3238{
3239 for (int i = 0; i < QInternal::DockCount; ++i)
3240 docks[i].deleteAllLayoutItems();
3241}
3242
3243#ifndef QT_NO_TABBAR
3244QSet<QTabBar*> QDockAreaLayout::usedTabBars() const
3245{
3246 QSet<QTabBar*> result;
3247 for (int i = 0; i < QInternal::DockCount; ++i) {
3248 const QDockAreaLayoutInfo &dock = docks[i];
3249 result += dock.usedTabBars();
3250 }
3251 return result;
3252}
3253
3254// Returns the set of all used separator widgets
3255QSet<QWidget*> QDockAreaLayout::usedSeparatorWidgets() const
3256{
3257 QSet<QWidget*> result;
3258
3259 for (int i = 0; i < separatorWidgets.count(); ++i)
3260 result << separatorWidgets.at(i);
3261 for (int i = 0; i < QInternal::DockCount; ++i) {
3262 const QDockAreaLayoutInfo &dock = docks[i];
3263 result += dock.usedSeparatorWidgets();
3264 }
3265 return result;
3266}
3267#endif
3268
3269QRect QDockAreaLayout::gapRect(const QList<int> &path) const
3270{
3271 const QDockAreaLayoutInfo *info = this->info(path);
3272 if (info == 0)
3273 return QRect();
3274 const QList<QDockAreaLayoutItem> &item_list = info->item_list;
3275 Qt::Orientation o = info->o;
3276 int index = path.last();
3277 if (index < 0 || index >= item_list.count())
3278 return QRect();
3279 const QDockAreaLayoutItem &item = item_list.at(index);
3280 if (!(item.flags & QDockAreaLayoutItem::GapItem))
3281 return QRect();
3282
3283 QRect result;
3284
3285#ifndef QT_NO_TABBAR
3286 if (info->tabbed) {
3287 result = info->tabContentRect();
3288 } else
3289#endif
3290 {
3291 int pos = item.pos;
3292 int size = item.size;
3293
3294 int prev = info->prev(index);
3295 int next = info->next(index);
3296
3297 if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem)) {
3298 pos += sep;
3299 size -= sep;
3300 }
3301 if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem))
3302 size -= sep;
3303
3304 QPoint p;
3305 rpick(o, p) = pos;
3306 rperp(o, p) = perp(o, info->rect.topLeft());
3307 QSize s;
3308 rpick(o, s) = size;
3309 rperp(o, s) = perp(o, info->rect.size());
3310
3311 result = QRect(p, s);
3312 }
3313
3314 return result;
3315}
3316
3317void QDockAreaLayout::keepSize(QDockWidget *w)
3318{
3319 QList<int> path = indexOf(w);
3320 if (path.isEmpty())
3321 return;
3322 QDockAreaLayoutItem &item = this->item(path);
3323 if (item.size != -1)
3324 item.flags |= QDockAreaLayoutItem::KeepSize;
3325}
3326
3327QT_END_NAMESPACE
3328
3329#endif // QT_NO_DOCKWIDGET
Note: See TracBrowser for help on using the repository browser.