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

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

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

File size: 101.6 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 QDockAreaLayoutItem item(new QDockAreaLayoutInfo(sep, dockPos, o,
1994 tabBarShape, mainWindow));
1995 stream >> item.pos >> item.size >> dummy >> dummy;
1996 //we need to make sure the element is in the list so the dock widget can eventually be docked correctly
1997 if (!testing)
1998 item_list.append(item);
1999
2000 //here we need to make sure we change the item in the item_list
2001 QDockAreaLayoutItem &lastItem = testing ? item : item_list.last();
2002
2003 if (!lastItem.subinfo->restoreState(stream, widgets, testing))
2004 return false;
2005
2006 } else {
2007 return false;
2008 }
2009 }
2010
2011#ifndef QT_NO_TABBAR
2012 if (!testing && tabbed && index >= 0 && index < item_list.count()) {
2013 updateTabBar();
2014 setCurrentTabId(tabId(item_list.at(index)));
2015 }
2016 if (!testing && sep == 1)
2017 updateSeparatorWidgets();
2018#endif
2019
2020 return true;
2021}
2022
2023#ifndef QT_NO_TABBAR
2024void QDockAreaLayoutInfo::updateSeparatorWidgets() const
2025{
2026 if (tabbed) {
2027 separatorWidgets.clear();
2028 return;
2029 }
2030
2031 int j = 0;
2032 for (int i = 0; i < item_list.count(); ++i) {
2033 const QDockAreaLayoutItem &item = item_list.at(i);
2034
2035 if (item.skip())
2036 continue;
2037
2038 int next = this->next(i);
2039 if ((item.flags & QDockAreaLayoutItem::GapItem)
2040 || (next != -1 && (item_list.at(next).flags & QDockAreaLayoutItem::GapItem)))
2041 continue;
2042
2043 if (item.subinfo) {
2044 item.subinfo->updateSeparatorWidgets();
2045 }
2046
2047 if (next == -1)
2048 break;
2049
2050 QWidget *sepWidget;
2051 if (j < separatorWidgets.size() && separatorWidgets.at(j)) {
2052 sepWidget = separatorWidgets.at(j);
2053 } else {
2054 sepWidget = mainWindowLayout()->getSeparatorWidget();
2055 separatorWidgets.append(sepWidget);
2056 }
2057 j++;
2058
2059#ifndef QT_MAC_USE_COCOA
2060 sepWidget->raise();
2061#endif
2062 QRect sepRect = separatorRect(i).adjusted(-2, -2, 2, 2);
2063 sepWidget->setGeometry(sepRect);
2064 sepWidget->setMask( QRegion(separatorRect(i).translated( - sepRect.topLeft())));
2065 sepWidget->show();
2066 }
2067
2068 for (int k = j; k < separatorWidgets.size(); ++k) {
2069 separatorWidgets[k]->hide();
2070 }
2071 separatorWidgets.resize(j);
2072 Q_ASSERT(separatorWidgets.size() == j);
2073}
2074#endif //QT_NO_TABBAR
2075
2076#ifndef QT_NO_TABBAR
2077void QDockAreaLayoutInfo::updateTabBar() const
2078{
2079 if (!tabbed)
2080 return;
2081
2082 QDockAreaLayoutInfo *that = const_cast<QDockAreaLayoutInfo*>(this);
2083
2084 if (that->tabBar == 0) {
2085 that->tabBar = mainWindowLayout()->getTabBar();
2086 that->tabBar->setShape(static_cast<QTabBar::Shape>(tabBarShape));
2087 that->tabBar->setDrawBase(true);
2088 }
2089
2090 bool blocked = tabBar->blockSignals(true);
2091 bool gap = false;
2092
2093 int tab_idx = 0;
2094 bool changed = false;
2095 for (int i = 0; i < item_list.count(); ++i) {
2096 const QDockAreaLayoutItem &item = item_list.at(i);
2097 if (item.skip())
2098 continue;
2099 if (item.flags & QDockAreaLayoutItem::GapItem) {
2100 gap = true;
2101 continue;
2102 }
2103 if (item.widgetItem == 0)
2104 continue;
2105
2106 QDockWidget *dw = qobject_cast<QDockWidget*>(item.widgetItem->widget());
2107 QString title = dw->d_func()->fixedWindowTitle;
2108 quintptr id = tabId(item);
2109 if (tab_idx == tabBar->count()) {
2110 tabBar->insertTab(tab_idx, title);
2111#ifndef QT_NO_TOOLTIP
2112 tabBar->setTabToolTip(tab_idx, title);
2113#endif
2114 tabBar->setTabData(tab_idx, id);
2115 changed = true;
2116 } else if (qvariant_cast<quintptr>(tabBar->tabData(tab_idx)) != id) {
2117 if (tab_idx + 1 < tabBar->count()
2118 && qvariant_cast<quintptr>(tabBar->tabData(tab_idx + 1)) == id)
2119 tabBar->removeTab(tab_idx);
2120 else {
2121 tabBar->insertTab(tab_idx, title);
2122#ifndef QT_NO_TOOLTIP
2123 tabBar->setTabToolTip(tab_idx, title);
2124#endif
2125 tabBar->setTabData(tab_idx, id);
2126 }
2127 changed = true;
2128 }
2129
2130 if (title != tabBar->tabText(tab_idx)) {
2131 tabBar->setTabText(tab_idx, title);
2132#ifndef QT_NO_TOOLTIP
2133 tabBar->setTabToolTip(tab_idx, title);
2134#endif
2135 changed = true;
2136 }
2137
2138 ++tab_idx;
2139 }
2140
2141 while (tab_idx < tabBar->count()) {
2142 tabBar->removeTab(tab_idx);
2143 changed = true;
2144 }
2145
2146 tabBar->blockSignals(blocked);
2147
2148 that->tabBarVisible = ( (gap ? 1 : 0) + tabBar->count()) > 1;
2149
2150 if (changed || !tabBarMin.isValid() | !tabBarHint.isValid()) {
2151 that->tabBarMin = tabBar->minimumSizeHint();
2152 that->tabBarHint = tabBar->sizeHint();
2153 }
2154}
2155
2156void QDockAreaLayoutInfo::setTabBarShape(int shape)
2157{
2158 if (shape == tabBarShape)
2159 return;
2160 tabBarShape = shape;
2161 if (tabBar != 0) {
2162 tabBar->setShape(static_cast<QTabBar::Shape>(shape));
2163 tabBarMin = QSize();
2164 tabBarHint = QSize();
2165 }
2166
2167 for (int i = 0; i < item_list.count(); ++i) {
2168 QDockAreaLayoutItem &item = item_list[i];
2169 if (item.subinfo != 0)
2170 item.subinfo->setTabBarShape(shape);
2171 }
2172}
2173
2174QSize QDockAreaLayoutInfo::tabBarMinimumSize() const
2175{
2176 if (!tabbed)
2177 return QSize(0, 0);
2178
2179 updateTabBar();
2180
2181 return tabBarMin;
2182}
2183
2184QSize QDockAreaLayoutInfo::tabBarSizeHint() const
2185{
2186 if (!tabbed)
2187 return QSize(0, 0);
2188
2189 updateTabBar();
2190
2191 return tabBarHint;
2192}
2193
2194QSet<QTabBar*> QDockAreaLayoutInfo::usedTabBars() const
2195{
2196 QSet<QTabBar*> result;
2197
2198 if (tabbed) {
2199 updateTabBar();
2200 result.insert(tabBar);
2201 }
2202
2203 for (int i = 0; i < item_list.count(); ++i) {
2204 const QDockAreaLayoutItem &item = item_list.at(i);
2205 if (item.subinfo != 0)
2206 result += item.subinfo->usedTabBars();
2207 }
2208
2209 return result;
2210}
2211
2212// returns a set of all used separator widgets for this dockarelayout info
2213// and all subinfos
2214QSet<QWidget*> QDockAreaLayoutInfo::usedSeparatorWidgets() const
2215{
2216 QSet<QWidget*> result;
2217
2218 for (int i = 0; i < separatorWidgets.count(); ++i)
2219 result << separatorWidgets.at(i);
2220
2221 for (int i = 0; i < item_list.count(); ++i) {
2222 const QDockAreaLayoutItem &item = item_list.at(i);
2223 if (item.subinfo != 0)
2224 result += item.subinfo->usedSeparatorWidgets();
2225 }
2226
2227 return result;
2228}
2229
2230QRect QDockAreaLayoutInfo::tabContentRect() const
2231{
2232 if (!tabbed)
2233 return QRect();
2234
2235 QRect result = rect;
2236 QSize tbh = tabBarSizeHint();
2237
2238 if (tabBarVisible) {
2239 switch (tabBarShape) {
2240 case QTabBar::RoundedNorth:
2241 case QTabBar::TriangularNorth:
2242 result.adjust(0, tbh.height(), 0, 0);
2243 break;
2244 case QTabBar::RoundedSouth:
2245 case QTabBar::TriangularSouth:
2246 result.adjust(0, 0, 0, -tbh.height());
2247 break;
2248 case QTabBar::RoundedEast:
2249 case QTabBar::TriangularEast:
2250 result.adjust(0, 0, -tbh.width(), 0);
2251 break;
2252 case QTabBar::RoundedWest:
2253 case QTabBar::TriangularWest:
2254 result.adjust(tbh.width(), 0, 0, 0);
2255 break;
2256 default:
2257 break;
2258 }
2259 }
2260
2261 return result;
2262}
2263#endif // QT_NO_TABBAR
2264
2265/******************************************************************************
2266** QDockAreaLayout
2267*/
2268
2269QDockAreaLayout::QDockAreaLayout(QMainWindow *win) : fallbackToSizeHints(true)
2270{
2271 mainWindow = win;
2272 sep = win->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent, 0, win);
2273#ifndef QT_NO_TABBAR
2274 const int tabShape = QTabBar::RoundedSouth;
2275#else
2276 const int tabShape = 0;
2277#endif
2278 docks[QInternal::LeftDock]
2279 = QDockAreaLayoutInfo(sep, QInternal::LeftDock, Qt::Vertical, tabShape, win);
2280 docks[QInternal::RightDock]
2281 = QDockAreaLayoutInfo(sep, QInternal::RightDock, Qt::Vertical, tabShape, win);
2282 docks[QInternal::TopDock]
2283 = QDockAreaLayoutInfo(sep, QInternal::TopDock, Qt::Horizontal, tabShape, win);
2284 docks[QInternal::BottomDock]
2285 = QDockAreaLayoutInfo(sep, QInternal::BottomDock, Qt::Horizontal, tabShape, win);
2286 centralWidgetItem = 0;
2287
2288
2289 corners[Qt::TopLeftCorner] = Qt::TopDockWidgetArea;
2290 corners[Qt::TopRightCorner] = Qt::TopDockWidgetArea;
2291 corners[Qt::BottomLeftCorner] = Qt::BottomDockWidgetArea;
2292 corners[Qt::BottomRightCorner] = Qt::BottomDockWidgetArea;
2293}
2294
2295bool QDockAreaLayout::isValid() const
2296{
2297 return rect.isValid();
2298}
2299
2300void QDockAreaLayout::saveState(QDataStream &stream) const
2301{
2302 stream << (uchar) DockWidgetStateMarker;
2303 int cnt = 0;
2304 for (int i = 0; i < QInternal::DockCount; ++i) {
2305 if (!docks[i].item_list.isEmpty())
2306 ++cnt;
2307 }
2308 stream << cnt;
2309 for (int i = 0; i < QInternal::DockCount; ++i) {
2310 if (docks[i].item_list.isEmpty())
2311 continue;
2312 stream << i << docks[i].rect.size();
2313 docks[i].saveState(stream);
2314 }
2315
2316 stream << centralWidgetRect.size();
2317
2318 for (int i = 0; i < 4; ++i)
2319 stream << static_cast<int>(corners[i]);
2320}
2321
2322bool QDockAreaLayout::restoreState(QDataStream &stream, const QList<QDockWidget*> &_dockwidgets, bool testing)
2323{
2324 QList<QDockWidget*> dockwidgets = _dockwidgets;
2325
2326 int cnt;
2327 stream >> cnt;
2328 for (int i = 0; i < cnt; ++i) {
2329 int pos;
2330 stream >> pos;
2331 QSize size;
2332 stream >> size;
2333 if (!testing) {
2334 docks[pos].rect = QRect(QPoint(0, 0), size);
2335 }
2336 if (!docks[pos].restoreState(stream, dockwidgets, testing)) {
2337 stream.setStatus(QDataStream::ReadCorruptData);
2338 return false;
2339 }
2340 }
2341
2342 QSize size;
2343 stream >> size;
2344 centralWidgetRect = QRect(QPoint(0, 0), size);
2345
2346 bool ok = stream.status() == QDataStream::Ok;
2347
2348 if (ok) {
2349 int cornerData[4];
2350 for (int i = 0; i < 4; ++i)
2351 stream >> cornerData[i];
2352 if (stream.status() == QDataStream::Ok) {
2353 for (int i = 0; i < 4; ++i)
2354 corners[i] = static_cast<Qt::DockWidgetArea>(cornerData[i]);
2355 }
2356
2357 if (!testing)
2358 fallbackToSizeHints = false;
2359 }
2360
2361 return ok;
2362}
2363
2364QList<int> QDockAreaLayout::indexOfPlaceHolder(const QString &objectName) const
2365{
2366 for (int i = 0; i < QInternal::DockCount; ++i) {
2367 QList<int> result = docks[i].indexOfPlaceHolder(objectName);
2368 if (!result.isEmpty()) {
2369 result.prepend(i);
2370 return result;
2371 }
2372 }
2373 return QList<int>();
2374}
2375
2376QList<int> QDockAreaLayout::indexOf(QWidget *dockWidget) const
2377{
2378 for (int i = 0; i < QInternal::DockCount; ++i) {
2379 QList<int> result = docks[i].indexOf(dockWidget);
2380 if (!result.isEmpty()) {
2381 result.prepend(i);
2382 return result;
2383 }
2384 }
2385 return QList<int>();
2386}
2387
2388QList<int> QDockAreaLayout::gapIndex(const QPoint &pos) const
2389{
2390 QMainWindow::DockOptions opts = mainWindow->dockOptions();
2391 bool nestingEnabled = opts & QMainWindow::AllowNestedDocks;
2392 QDockAreaLayoutInfo::TabMode tabMode = QDockAreaLayoutInfo::NoTabs;
2393#ifndef QT_NO_TABBAR
2394 if (opts & QMainWindow::AllowTabbedDocks
2395 || opts & QMainWindow::VerticalTabs)
2396 tabMode = QDockAreaLayoutInfo::AllowTabs;
2397 if (opts & QMainWindow::ForceTabbedDocks)
2398 tabMode = QDockAreaLayoutInfo::ForceTabs;
2399
2400 if (tabMode == QDockAreaLayoutInfo::ForceTabs)
2401 nestingEnabled = false;
2402#endif
2403
2404
2405 for (int i = 0; i < QInternal::DockCount; ++i) {
2406 const QDockAreaLayoutInfo &info = docks[i];
2407
2408 if (!info.isEmpty() && info.rect.contains(pos)) {
2409 QList<int> result
2410 = docks[i].gapIndex(pos, nestingEnabled, tabMode);
2411 if (!result.isEmpty())
2412 result.prepend(i);
2413 return result;
2414 }
2415 }
2416
2417 for (int i = 0; i < QInternal::DockCount; ++i) {
2418 const QDockAreaLayoutInfo &info = docks[i];
2419
2420 if (info.isEmpty()) {
2421 QRect r;
2422 switch (i) {
2423 case QInternal::LeftDock:
2424 r = QRect(rect.left(), rect.top(), EmptyDropAreaSize, rect.height());
2425 break;
2426 case QInternal::RightDock:
2427 r = QRect(rect.right() - EmptyDropAreaSize, rect.top(),
2428 EmptyDropAreaSize, rect.height());
2429 break;
2430 case QInternal::TopDock:
2431 r = QRect(rect.left(), rect.top(), rect.width(), EmptyDropAreaSize);
2432 break;
2433 case QInternal::BottomDock:
2434 r = QRect(rect.left(), rect.bottom() - EmptyDropAreaSize,
2435 rect.width(), EmptyDropAreaSize);
2436 break;
2437 }
2438 if (r.contains(pos)) {
2439 if (opts & QMainWindow::ForceTabbedDocks && !info.item_list.isEmpty()) {
2440 //in case of ForceTabbedDocks, we pass -1 in order to force the gap to be tabbed
2441 //it mustn't be completely empty otherwise it won't work
2442 return QList<int>() << i << -1 << 0;
2443 } else {
2444 return QList<int>() << i << 0;
2445 }
2446 }
2447 }
2448 }
2449
2450 return QList<int>();
2451}
2452
2453QList<int> QDockAreaLayout::findSeparator(const QPoint &pos) const
2454{
2455 QList<int> result;
2456 for (int i = 0; i < QInternal::DockCount; ++i) {
2457 const QDockAreaLayoutInfo &info = docks[i];
2458 if (info.isEmpty())
2459 continue;
2460 QRect rect = separatorRect(i);
2461 if (!rect.isNull() && sep == 1)
2462 rect.adjust(-2, -2, 2, 2);
2463 if (rect.contains(pos) && !info.hasFixedSize()) {
2464 result << i;
2465 break;
2466 } else if (info.rect.contains(pos)) {
2467 result = docks[i].findSeparator(pos);
2468 if (!result.isEmpty()) {
2469 result.prepend(i);
2470 break;
2471 }
2472 }
2473 }
2474
2475 return result;
2476}
2477
2478QDockAreaLayoutInfo *QDockAreaLayout::info(QWidget *widget)
2479{
2480 for (int i = 0; i < QInternal::DockCount; ++i) {
2481 if (QDockAreaLayoutInfo *result = docks[i].info(widget))
2482 return result;
2483 }
2484
2485 return 0;
2486}
2487
2488QDockAreaLayoutInfo *QDockAreaLayout::info(const QList<int> &path)
2489{
2490 Q_ASSERT(!path.isEmpty());
2491 const int index = path.first();
2492 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2493
2494 if (path.count() == 1)
2495 return &docks[index];
2496
2497 return docks[index].info(path.mid(1));
2498}
2499
2500const QDockAreaLayoutInfo *QDockAreaLayout::info(const QList<int> &path) const
2501{
2502 return const_cast<QDockAreaLayout*>(this)->info(path);
2503}
2504
2505QDockAreaLayoutItem &QDockAreaLayout::item(const QList<int> &path)
2506{
2507 Q_ASSERT(!path.isEmpty());
2508 const int index = path.first();
2509 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2510 return docks[index].item(path.mid(1));
2511}
2512
2513QRect QDockAreaLayout::itemRect(const QList<int> &path) const
2514{
2515 Q_ASSERT(!path.isEmpty());
2516 const int index = path.first();
2517 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2518 return docks[index].itemRect(path.mid(1));
2519}
2520
2521QRect QDockAreaLayout::separatorRect(int index) const
2522{
2523 const QDockAreaLayoutInfo &dock = docks[index];
2524 if (dock.isEmpty())
2525 return QRect();
2526 QRect r = dock.rect;
2527 switch (index) {
2528 case QInternal::LeftDock:
2529 return QRect(r.right() + 1, r.top(), sep, r.height());
2530 case QInternal::RightDock:
2531 return QRect(r.left() - sep, r.top(), sep, r.height());
2532 case QInternal::TopDock:
2533 return QRect(r.left(), r.bottom() + 1, r.width(), sep);
2534 case QInternal::BottomDock:
2535 return QRect(r.left(), r.top() - sep, r.width(), sep);
2536 default:
2537 break;
2538 }
2539 return QRect();
2540}
2541
2542QRect QDockAreaLayout::separatorRect(const QList<int> &path) const
2543{
2544 Q_ASSERT(!path.isEmpty());
2545
2546 const int index = path.first();
2547 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2548
2549 if (path.count() == 1)
2550 return separatorRect(index);
2551 else
2552 return docks[index].separatorRect(path.mid(1));
2553}
2554
2555bool QDockAreaLayout::insertGap(const QList<int> &path, QLayoutItem *dockWidgetItem)
2556{
2557 Q_ASSERT(!path.isEmpty());
2558 const int index = path.first();
2559 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2560 return docks[index].insertGap(path.mid(1), dockWidgetItem);
2561}
2562
2563QLayoutItem *QDockAreaLayout::plug(const QList<int> &path)
2564{
2565 Q_ASSERT(!path.isEmpty());
2566 const int index = path.first();
2567 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2568 return docks[index].plug(path.mid(1));
2569}
2570
2571QLayoutItem *QDockAreaLayout::unplug(const QList<int> &path)
2572{
2573 Q_ASSERT(!path.isEmpty());
2574 const int index = path.first();
2575 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2576 return docks[index].unplug(path.mid(1));
2577}
2578
2579void QDockAreaLayout::remove(const QList<int> &path)
2580{
2581 Q_ASSERT(!path.isEmpty());
2582 const int index = path.first();
2583 Q_ASSERT(index >= 0 && index < QInternal::DockCount);
2584 docks[index].remove(path.mid(1));
2585}
2586
2587static inline int qMin(int i1, int i2, int i3) { return qMin(i1, qMin(i2, i3)); }
2588static inline int qMax(int i1, int i2, int i3) { return qMax(i1, qMax(i2, i3)); }
2589
2590void QDockAreaLayout::getGrid(QVector<QLayoutStruct> *_ver_struct_list,
2591 QVector<QLayoutStruct> *_hor_struct_list)
2592{
2593 QSize center_hint(0, 0);
2594 QSize center_min(0, 0);
2595 const bool have_central = centralWidgetItem != 0 && !centralWidgetItem->isEmpty();
2596 if (have_central) {
2597 center_hint = centralWidgetRect.size();
2598 if (!center_hint.isValid())
2599 center_hint = centralWidgetItem->sizeHint();
2600 center_min = centralWidgetItem->minimumSize();
2601 }
2602
2603 QRect center_rect = rect;
2604 if (!docks[QInternal::LeftDock].isEmpty())
2605 center_rect.setLeft(rect.left() + docks[QInternal::LeftDock].rect.width() + sep);
2606 if (!docks[QInternal::TopDock].isEmpty())
2607 center_rect.setTop(rect.top() + docks[QInternal::TopDock].rect.height() + sep);
2608 if (!docks[QInternal::RightDock].isEmpty())
2609 center_rect.setRight(rect.right() - docks[QInternal::RightDock].rect.width() - sep);
2610 if (!docks[QInternal::BottomDock].isEmpty())
2611 center_rect.setBottom(rect.bottom() - docks[QInternal::BottomDock].rect.height() - sep);
2612
2613 QSize left_hint = docks[QInternal::LeftDock].size();
2614 if (left_hint.isNull() || fallbackToSizeHints)
2615 left_hint = docks[QInternal::LeftDock].sizeHint();
2616 QSize left_min = docks[QInternal::LeftDock].minimumSize();
2617 QSize left_max = docks[QInternal::LeftDock].maximumSize();
2618 left_hint = left_hint.boundedTo(left_max).expandedTo(left_min);
2619
2620 QSize right_hint = docks[QInternal::RightDock].size();
2621 if (right_hint.isNull() || fallbackToSizeHints)
2622 right_hint = docks[QInternal::RightDock].sizeHint();
2623 QSize right_min = docks[QInternal::RightDock].minimumSize();
2624 QSize right_max = docks[QInternal::RightDock].maximumSize();
2625 right_hint = right_hint.boundedTo(right_max).expandedTo(right_min);
2626
2627 QSize top_hint = docks[QInternal::TopDock].size();
2628 if (top_hint.isNull() || fallbackToSizeHints)
2629 top_hint = docks[QInternal::TopDock].sizeHint();
2630 QSize top_min = docks[QInternal::TopDock].minimumSize();
2631 QSize top_max = docks[QInternal::TopDock].maximumSize();
2632 top_hint = top_hint.boundedTo(top_max).expandedTo(top_min);
2633
2634 QSize bottom_hint = docks[QInternal::BottomDock].size();
2635 if (bottom_hint.isNull() || fallbackToSizeHints)
2636 bottom_hint = docks[QInternal::BottomDock].sizeHint();
2637 QSize bottom_min = docks[QInternal::BottomDock].minimumSize();
2638 QSize bottom_max = docks[QInternal::BottomDock].maximumSize();
2639 bottom_hint = bottom_hint.boundedTo(bottom_max).expandedTo(bottom_min);
2640
2641 fallbackToSizeHints = false;
2642
2643 if (_ver_struct_list != 0) {
2644 QVector<QLayoutStruct> &ver_struct_list = *_ver_struct_list;
2645 ver_struct_list.resize(3);
2646
2647 // top --------------------------------------------------
2648 ver_struct_list[0].init();
2649 ver_struct_list[0].stretch = 0;
2650 ver_struct_list[0].sizeHint = top_hint.height();
2651 ver_struct_list[0].minimumSize = top_min.height();
2652 ver_struct_list[0].maximumSize = top_max.height();
2653 ver_struct_list[0].expansive = false;
2654 ver_struct_list[0].empty = docks[QInternal::TopDock].isEmpty();
2655 ver_struct_list[0].pos = docks[QInternal::TopDock].rect.top();
2656 ver_struct_list[0].size = docks[QInternal::TopDock].rect.height();
2657
2658 // center --------------------------------------------------
2659 ver_struct_list[1].init();
2660 ver_struct_list[1].stretch = center_hint.height();
2661
2662 bool tl_significant = corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea
2663 || docks[QInternal::TopDock].isEmpty();
2664 bool bl_significant = corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea
2665 || docks[QInternal::BottomDock].isEmpty();
2666 bool tr_significant = corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea
2667 || docks[QInternal::TopDock].isEmpty();
2668 bool br_significant = corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea
2669 || docks[QInternal::BottomDock].isEmpty();
2670
2671 int left = (tl_significant && bl_significant) ? left_hint.height() : 0;
2672 int right = (tr_significant && br_significant) ? right_hint.height() : 0;
2673 ver_struct_list[1].sizeHint = qMax(left, center_hint.height(), right);
2674
2675 left = (tl_significant && bl_significant) ? left_min.height() : 0;
2676 right = (tr_significant && br_significant) ? right_min.height() : 0;
2677 ver_struct_list[1].minimumSize = qMax(left, center_min.height(), right);
2678 ver_struct_list[1].maximumSize = have_central ? QWIDGETSIZE_MAX : 0;
2679 ver_struct_list[1].expansive = have_central;
2680 ver_struct_list[1].empty = docks[QInternal::LeftDock].isEmpty()
2681 && !have_central
2682 && docks[QInternal::RightDock].isEmpty();
2683 ver_struct_list[1].pos = center_rect.top();
2684 ver_struct_list[1].size = center_rect.height();
2685
2686 // bottom --------------------------------------------------
2687 ver_struct_list[2].init();
2688 ver_struct_list[2].stretch = 0;
2689 ver_struct_list[2].sizeHint = bottom_hint.height();
2690 ver_struct_list[2].minimumSize = bottom_min.height();
2691 ver_struct_list[2].maximumSize = bottom_max.height();
2692 ver_struct_list[2].expansive = false;
2693 ver_struct_list[2].empty = docks[QInternal::BottomDock].isEmpty();
2694 ver_struct_list[2].pos = docks[QInternal::BottomDock].rect.top();
2695 ver_struct_list[2].size = docks[QInternal::BottomDock].rect.height();
2696
2697 for (int i = 0; i < 3; ++i) {
2698 ver_struct_list[i].sizeHint
2699 = qMax(ver_struct_list[i].sizeHint, ver_struct_list[i].minimumSize);
2700 }
2701 }
2702
2703 if (_hor_struct_list != 0) {
2704 QVector<QLayoutStruct> &hor_struct_list = *_hor_struct_list;
2705 hor_struct_list.resize(3);
2706
2707 // left --------------------------------------------------
2708 hor_struct_list[0].init();
2709 hor_struct_list[0].stretch = 0;
2710 hor_struct_list[0].sizeHint = left_hint.width();
2711 hor_struct_list[0].minimumSize = left_min.width();
2712 hor_struct_list[0].maximumSize = left_max.width();
2713 hor_struct_list[0].expansive = false;
2714 hor_struct_list[0].empty = docks[QInternal::LeftDock].isEmpty();
2715 hor_struct_list[0].pos = docks[QInternal::LeftDock].rect.left();
2716 hor_struct_list[0].size = docks[QInternal::LeftDock].rect.width();
2717
2718 // center --------------------------------------------------
2719 hor_struct_list[1].init();
2720 hor_struct_list[1].stretch = center_hint.width();
2721
2722 bool tl_significant = corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea
2723 || docks[QInternal::LeftDock].isEmpty();
2724 bool tr_significant = corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea
2725 || docks[QInternal::RightDock].isEmpty();
2726 bool bl_significant = corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea
2727 || docks[QInternal::LeftDock].isEmpty();
2728 bool br_significant = corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea
2729 || docks[QInternal::RightDock].isEmpty();
2730
2731 int top = (tl_significant && tr_significant) ? top_hint.width() : 0;
2732 int bottom = (bl_significant && br_significant) ? bottom_hint.width() : 0;
2733 hor_struct_list[1].sizeHint = qMax(top, center_hint.width(), bottom);
2734
2735 top = (tl_significant && tr_significant) ? top_min.width() : 0;
2736 bottom = (bl_significant && br_significant) ? bottom_min.width() : 0;
2737 hor_struct_list[1].minimumSize = qMax(top, center_min.width(), bottom);
2738
2739 hor_struct_list[1].maximumSize = have_central ? QWIDGETSIZE_MAX : 0;
2740 hor_struct_list[1].expansive = have_central;
2741 hor_struct_list[1].empty = !have_central;
2742 hor_struct_list[1].pos = center_rect.left();
2743 hor_struct_list[1].size = center_rect.width();
2744
2745 // right --------------------------------------------------
2746 hor_struct_list[2].init();
2747 hor_struct_list[2].stretch = 0;
2748 hor_struct_list[2].sizeHint = right_hint.width();
2749 hor_struct_list[2].minimumSize = right_min.width();
2750 hor_struct_list[2].maximumSize = right_max.width();
2751 hor_struct_list[2].expansive = false;
2752 hor_struct_list[2].empty = docks[QInternal::RightDock].isEmpty();
2753 hor_struct_list[2].pos = docks[QInternal::RightDock].rect.left();
2754 hor_struct_list[2].size = docks[QInternal::RightDock].rect.width();
2755
2756 for (int i = 0; i < 3; ++i) {
2757 hor_struct_list[i].sizeHint
2758 = qMax(hor_struct_list[i].sizeHint, hor_struct_list[i].minimumSize);
2759 }
2760 }
2761}
2762
2763void QDockAreaLayout::setGrid(QVector<QLayoutStruct> *ver_struct_list,
2764 QVector<QLayoutStruct> *hor_struct_list)
2765{
2766
2767 // top ---------------------------------------------------
2768
2769 if (!docks[QInternal::TopDock].isEmpty()) {
2770 QRect r = docks[QInternal::TopDock].rect;
2771 if (hor_struct_list != 0) {
2772 r.setLeft(corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea
2773 || docks[QInternal::LeftDock].isEmpty()
2774 ? rect.left() : hor_struct_list->at(1).pos);
2775 r.setRight(corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea
2776 || docks[QInternal::RightDock].isEmpty()
2777 ? rect.right() : hor_struct_list->at(2).pos - sep - 1);
2778 }
2779 if (ver_struct_list != 0) {
2780 r.setTop(rect.top());
2781 r.setBottom(ver_struct_list->at(1).pos - sep - 1);
2782 }
2783 docks[QInternal::TopDock].rect = r;
2784 docks[QInternal::TopDock].fitItems();
2785 }
2786
2787 // bottom ---------------------------------------------------
2788
2789 if (!docks[QInternal::BottomDock].isEmpty()) {
2790 QRect r = docks[QInternal::BottomDock].rect;
2791 if (hor_struct_list != 0) {
2792 r.setLeft(corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea
2793 || docks[QInternal::LeftDock].isEmpty()
2794 ? rect.left() : hor_struct_list->at(1).pos);
2795 r.setRight(corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea
2796 || docks[QInternal::RightDock].isEmpty()
2797 ? rect.right() : hor_struct_list->at(2).pos - sep - 1);
2798 }
2799 if (ver_struct_list != 0) {
2800 r.setTop(ver_struct_list->at(2).pos);
2801 r.setBottom(rect.bottom());
2802 }
2803 docks[QInternal::BottomDock].rect = r;
2804 docks[QInternal::BottomDock].fitItems();
2805 }
2806
2807 // left ---------------------------------------------------
2808
2809 if (!docks[QInternal::LeftDock].isEmpty()) {
2810 QRect r = docks[QInternal::LeftDock].rect;
2811 if (hor_struct_list != 0) {
2812 r.setLeft(rect.left());
2813 r.setRight(hor_struct_list->at(1).pos - sep - 1);
2814 }
2815 if (ver_struct_list != 0) {
2816 r.setTop(corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea
2817 || docks[QInternal::TopDock].isEmpty()
2818 ? rect.top() : ver_struct_list->at(1).pos);
2819 r.setBottom(corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea
2820 || docks[QInternal::BottomDock].isEmpty()
2821 ? rect.bottom() : ver_struct_list->at(2).pos - sep - 1);
2822 }
2823 docks[QInternal::LeftDock].rect = r;
2824 docks[QInternal::LeftDock].fitItems();
2825 }
2826
2827 // right ---------------------------------------------------
2828
2829 if (!docks[QInternal::RightDock].isEmpty()) {
2830 QRect r = docks[QInternal::RightDock].rect;
2831 if (hor_struct_list != 0) {
2832 r.setLeft(hor_struct_list->at(2).pos);
2833 r.setRight(rect.right());
2834 }
2835 if (ver_struct_list != 0) {
2836 r.setTop(corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea
2837 || docks[QInternal::TopDock].isEmpty()
2838 ? rect.top() : ver_struct_list->at(1).pos);
2839 r.setBottom(corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea
2840 || docks[QInternal::BottomDock].isEmpty()
2841 ? rect.bottom() : ver_struct_list->at(2).pos - sep - 1);
2842 }
2843 docks[QInternal::RightDock].rect = r;
2844 docks[QInternal::RightDock].fitItems();
2845 }
2846
2847 // center ---------------------------------------------------
2848
2849 if (hor_struct_list != 0) {
2850 centralWidgetRect.setLeft(hor_struct_list->at(1).pos);
2851 centralWidgetRect.setWidth(hor_struct_list->at(1).size);
2852 }
2853 if (ver_struct_list != 0) {
2854 centralWidgetRect.setTop(ver_struct_list->at(1).pos);
2855 centralWidgetRect.setHeight(ver_struct_list->at(1).size);
2856 }
2857}
2858
2859void QDockAreaLayout::fitLayout()
2860{
2861 QVector<QLayoutStruct> ver_struct_list(3);
2862 QVector<QLayoutStruct> hor_struct_list(3);
2863 getGrid(&ver_struct_list, &hor_struct_list);
2864
2865 qGeomCalc(ver_struct_list, 0, 3, rect.top(), rect.height(), sep);
2866 qGeomCalc(hor_struct_list, 0, 3, rect.left(), rect.width(), sep);
2867
2868 setGrid(&ver_struct_list, &hor_struct_list);
2869}
2870
2871void QDockAreaLayout::clear()
2872{
2873 for (int i = 0; i < QInternal::DockCount; ++i)
2874 docks[i].clear();
2875
2876 rect = QRect();
2877 centralWidgetRect = QRect();
2878}
2879
2880QSize QDockAreaLayout::sizeHint() const
2881{
2882 int left_sep = 0;
2883 int right_sep = 0;
2884 int top_sep = 0;
2885 int bottom_sep = 0;
2886
2887 if (centralWidgetItem != 0) {
2888 left_sep = docks[QInternal::LeftDock].isEmpty() ? 0 : sep;
2889 right_sep = docks[QInternal::RightDock].isEmpty() ? 0 : sep;
2890 top_sep = docks[QInternal::TopDock].isEmpty() ? 0 : sep;
2891 bottom_sep = docks[QInternal::BottomDock].isEmpty() ? 0 : sep;
2892 }
2893
2894 QSize left = docks[QInternal::LeftDock].sizeHint() + QSize(left_sep, 0);
2895 QSize right = docks[QInternal::RightDock].sizeHint() + QSize(right_sep, 0);
2896 QSize top = docks[QInternal::TopDock].sizeHint() + QSize(0, top_sep);
2897 QSize bottom = docks[QInternal::BottomDock].sizeHint() + QSize(0, bottom_sep);
2898 QSize center = centralWidgetItem == 0 ? QSize(0, 0) : centralWidgetItem->sizeHint();
2899
2900 int row1 = top.width();
2901 int row2 = left.width() + center.width() + right.width();
2902 int row3 = bottom.width();
2903 int col1 = left.height();
2904 int col2 = top.height() + center.height() + bottom.height();
2905 int col3 = right.height();
2906
2907 if (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea)
2908 row1 += left.width();
2909 else
2910 col1 += top.height();
2911
2912 if (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea)
2913 row1 += right.width();
2914 else
2915 col3 += top.height();
2916
2917 if (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea)
2918 row3 += left.width();
2919 else
2920 col1 += bottom.height();
2921
2922 if (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea)
2923 row3 += right.width();
2924 else
2925 col3 += bottom.height();
2926
2927 return QSize(qMax(row1, row2, row3), qMax(col1, col2, col3));
2928}
2929
2930QSize QDockAreaLayout::minimumSize() const
2931{
2932 int left_sep = 0;
2933 int right_sep = 0;
2934 int top_sep = 0;
2935 int bottom_sep = 0;
2936
2937 if (centralWidgetItem != 0) {
2938 left_sep = docks[QInternal::LeftDock].isEmpty() ? 0 : sep;
2939 right_sep = docks[QInternal::RightDock].isEmpty() ? 0 : sep;
2940 top_sep = docks[QInternal::TopDock].isEmpty() ? 0 : sep;
2941 bottom_sep = docks[QInternal::BottomDock].isEmpty() ? 0 : sep;
2942 }
2943
2944 QSize left = docks[QInternal::LeftDock].minimumSize() + QSize(left_sep, 0);
2945 QSize right = docks[QInternal::RightDock].minimumSize() + QSize(right_sep, 0);
2946 QSize top = docks[QInternal::TopDock].minimumSize() + QSize(0, top_sep);
2947 QSize bottom = docks[QInternal::BottomDock].minimumSize() + QSize(0, bottom_sep);
2948 QSize center = centralWidgetItem == 0 ? QSize(0, 0) : centralWidgetItem->minimumSize();
2949
2950 int row1 = top.width();
2951 int row2 = left.width() + center.width() + right.width();
2952 int row3 = bottom.width();
2953 int col1 = left.height();
2954 int col2 = top.height() + center.height() + bottom.height();
2955 int col3 = right.height();
2956
2957 if (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea)
2958 row1 += left.width();
2959 else
2960 col1 += top.height();
2961
2962 if (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea)
2963 row1 += right.width();
2964 else
2965 col3 += top.height();
2966
2967 if (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea)
2968 row3 += left.width();
2969 else
2970 col1 += bottom.height();
2971
2972 if (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea)
2973 row3 += right.width();
2974 else
2975 col3 += bottom.height();
2976
2977 return QSize(qMax(row1, row2, row3), qMax(col1, col2, col3));
2978}
2979
2980bool QDockAreaLayout::restoreDockWidget(QDockWidget *dockWidget)
2981{
2982 QList<int> index = indexOfPlaceHolder(dockWidget->objectName());
2983 if (index.isEmpty())
2984 return false;
2985
2986 QDockAreaLayoutItem &item = this->item(index);
2987 QPlaceHolderItem *placeHolder = item.placeHolderItem;
2988 Q_ASSERT(placeHolder != 0);
2989
2990 item.widgetItem = new QDockWidgetItem(dockWidget);
2991
2992 if (placeHolder->window) {
2993 QDesktopWidget desktop;
2994 QRect r = constrainedRect(placeHolder->topLevelRect, desktop.screenGeometry(dockWidget));
2995 dockWidget->d_func()->setWindowState(true, true, r);
2996 }
2997 dockWidget->show();
2998// dockWidget->setVisible(!placeHolder->hidden);
2999#ifdef Q_WS_X11
3000 if (placeHolder->window) // gets rid of the X11BypassWindowManager window flag
3001 dockWidget->d_func()->setWindowState(true);
3002#endif
3003
3004 item.placeHolderItem = 0;
3005 delete placeHolder;
3006
3007 return true;
3008}
3009
3010void QDockAreaLayout::addDockWidget(QInternal::DockPosition pos, QDockWidget *dockWidget,
3011 Qt::Orientation orientation)
3012{
3013 QLayoutItem *dockWidgetItem = new QDockWidgetItem(dockWidget);
3014 QDockAreaLayoutInfo &info = docks[pos];
3015 if (orientation == info.o || info.item_list.count() <= 1) {
3016 // empty dock areas, or dock areas containing exactly one widget can have their orientation
3017 // switched.
3018 info.o = orientation;
3019
3020 QDockAreaLayoutItem new_item(dockWidgetItem);
3021 info.item_list.append(new_item);
3022#ifndef QT_NO_TABBAR
3023 if (info.tabbed && !new_item.skip()) {
3024 info.updateTabBar();
3025 info.setCurrentTabId(tabId(new_item));
3026 }
3027#endif
3028 } else {
3029#ifndef QT_NO_TABBAR
3030 int tbshape = info.tabBarShape;
3031#else
3032 int tbshape = 0;
3033#endif
3034 QDockAreaLayoutInfo new_info(sep, pos, orientation, tbshape, mainWindow);
3035 new_info.item_list.append(new QDockAreaLayoutInfo(info));
3036 new_info.item_list.append(dockWidgetItem);
3037 info = new_info;
3038 }
3039
3040 QList<int> index = indexOfPlaceHolder(dockWidget->objectName());
3041 if (!index.isEmpty())
3042 remove(index);
3043}
3044
3045void QDockAreaLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
3046{
3047 QList<int> path = indexOf(first);
3048 if (path.isEmpty())
3049 return;
3050
3051 QDockAreaLayoutInfo *info = this->info(path);
3052 Q_ASSERT(info != 0);
3053 info->tab(path.last(), new QDockWidgetItem(second));
3054
3055 QList<int> index = indexOfPlaceHolder(second->objectName());
3056 if (!index.isEmpty())
3057 remove(index);
3058}
3059
3060void QDockAreaLayout::splitDockWidget(QDockWidget *after,
3061 QDockWidget *dockWidget,
3062 Qt::Orientation orientation)
3063{
3064 QList<int> path = indexOf(after);
3065 if (path.isEmpty())
3066 return;
3067
3068 QDockAreaLayoutInfo *info = this->info(path);
3069 Q_ASSERT(info != 0);
3070 info->split(path.last(), orientation, new QDockWidgetItem(dockWidget));
3071
3072 QList<int> index = indexOfPlaceHolder(dockWidget->objectName());
3073 if (!index.isEmpty())
3074 remove(index);
3075}
3076
3077void QDockAreaLayout::apply(bool animate)
3078{
3079 QWidgetAnimator &widgetAnimator
3080 = qobject_cast<QMainWindowLayout*>(mainWindow->layout())->widgetAnimator;
3081
3082 for (int i = 0; i < QInternal::DockCount; ++i)
3083 docks[i].apply(animate);
3084 if (centralWidgetItem != 0 && !centralWidgetItem->isEmpty()) {
3085 widgetAnimator.animate(centralWidgetItem->widget(), centralWidgetRect,
3086 animate);
3087 }
3088#ifndef QT_NO_TABBAR
3089 if (sep == 1)
3090 updateSeparatorWidgets();
3091#endif //QT_NO_TABBAR
3092}
3093
3094void QDockAreaLayout::paintSeparators(QPainter *p, QWidget *widget,
3095 const QRegion &clip,
3096 const QPoint &mouse) const
3097{
3098 for (int i = 0; i < QInternal::DockCount; ++i) {
3099 const QDockAreaLayoutInfo &dock = docks[i];
3100 if (dock.isEmpty())
3101 continue;
3102 QRect r = separatorRect(i);
3103 if (clip.contains(r) && !dock.hasFixedSize()) {
3104 Qt::Orientation opposite = dock.o == Qt::Horizontal
3105 ? Qt::Vertical : Qt::Horizontal;
3106 paintSep(p, widget, r, opposite, r.contains(mouse));
3107 }
3108 if (clip.contains(dock.rect))
3109 dock.paintSeparators(p, widget, clip, mouse);
3110 }
3111}
3112
3113QRegion QDockAreaLayout::separatorRegion() const
3114{
3115 QRegion result;
3116
3117 for (int i = 0; i < QInternal::DockCount; ++i) {
3118 const QDockAreaLayoutInfo &dock = docks[i];
3119 if (dock.isEmpty())
3120 continue;
3121 result |= separatorRect(i);
3122 result |= dock.separatorRegion();
3123 }
3124
3125 return result;
3126}
3127
3128int QDockAreaLayout::separatorMove(const QList<int> &separator, const QPoint &origin,
3129 const QPoint &dest)
3130{
3131 int delta = 0;
3132 int index = separator.last();
3133
3134 if (separator.count() > 1) {
3135 QDockAreaLayoutInfo *info = this->info(separator);
3136 delta = pick(info->o, dest - origin);
3137 if (delta != 0)
3138 delta = info->separatorMove(index, delta);
3139 info->apply(false);
3140 return delta;
3141 }
3142
3143 QVector<QLayoutStruct> list;
3144
3145 if (index == QInternal::LeftDock || index == QInternal::RightDock)
3146 getGrid(0, &list);
3147 else
3148 getGrid(&list, 0);
3149
3150 int sep_index = index == QInternal::LeftDock || index == QInternal::TopDock
3151 ? 0 : 1;
3152 Qt::Orientation o = index == QInternal::LeftDock || index == QInternal::RightDock
3153 ? Qt::Horizontal
3154 : Qt::Vertical;
3155
3156 delta = pick(o, dest - origin);
3157 delta = separatorMoveHelper(list, sep_index, delta, sep);
3158
3159 if (index == QInternal::LeftDock || index == QInternal::RightDock)
3160 setGrid(0, &list);
3161 else
3162 setGrid(&list, 0);
3163
3164 apply(false);
3165
3166 return delta;
3167}
3168
3169#ifndef QT_NO_TABBAR
3170// Sets the correct positions for the seperator widgets
3171// Allocates new sepearator widgets with getSeparatorWidget
3172void QDockAreaLayout::updateSeparatorWidgets() const
3173{
3174 int j = 0;
3175
3176 for (int i = 0; i < QInternal::DockCount; ++i) {
3177 const QDockAreaLayoutInfo &dock = docks[i];
3178 if (dock.isEmpty())
3179 continue;
3180
3181 QWidget *sepWidget;
3182 if (j < separatorWidgets.size()) {
3183 sepWidget = separatorWidgets.at(j);
3184 } else {
3185 sepWidget = qobject_cast<QMainWindowLayout*>(mainWindow->layout())->getSeparatorWidget();
3186 separatorWidgets.append(sepWidget);
3187 }
3188 j++;
3189
3190#ifndef QT_MAC_USE_COCOA
3191 sepWidget->raise();
3192#endif
3193 QRect sepRect = separatorRect(i).adjusted(-2, -2, 2, 2);
3194 sepWidget->setGeometry(sepRect);
3195 sepWidget->setMask( QRegion(separatorRect(i).translated( - sepRect.topLeft())));
3196 sepWidget->show();
3197 }
3198 for (int i = j; i < separatorWidgets.size(); ++i)
3199 separatorWidgets.at(i)->hide();
3200
3201 separatorWidgets.resize(j);
3202}
3203#endif //QT_NO_TABBAR
3204
3205QLayoutItem *QDockAreaLayout::itemAt(int *x, int index) const
3206{
3207 Q_ASSERT(x != 0);
3208
3209 for (int i = 0; i < QInternal::DockCount; ++i) {
3210 const QDockAreaLayoutInfo &dock = docks[i];
3211 if (QLayoutItem *ret = dock.itemAt(x, index))
3212 return ret;
3213 }
3214
3215 if (centralWidgetItem && (*x)++ == index)
3216 return centralWidgetItem;
3217
3218 return 0;
3219}
3220
3221QLayoutItem *QDockAreaLayout::takeAt(int *x, int index)
3222{
3223 Q_ASSERT(x != 0);
3224
3225 for (int i = 0; i < QInternal::DockCount; ++i) {
3226 QDockAreaLayoutInfo &dock = docks[i];
3227 if (QLayoutItem *ret = dock.takeAt(x, index))
3228 return ret;
3229 }
3230
3231 if (centralWidgetItem && (*x)++ == index) {
3232 QLayoutItem *ret = centralWidgetItem;
3233 centralWidgetItem = 0;
3234 return ret;
3235 }
3236
3237 return 0;
3238}
3239
3240void QDockAreaLayout::deleteAllLayoutItems()
3241{
3242 for (int i = 0; i < QInternal::DockCount; ++i)
3243 docks[i].deleteAllLayoutItems();
3244}
3245
3246#ifndef QT_NO_TABBAR
3247QSet<QTabBar*> QDockAreaLayout::usedTabBars() const
3248{
3249 QSet<QTabBar*> result;
3250 for (int i = 0; i < QInternal::DockCount; ++i) {
3251 const QDockAreaLayoutInfo &dock = docks[i];
3252 result += dock.usedTabBars();
3253 }
3254 return result;
3255}
3256
3257// Returns the set of all used separator widgets
3258QSet<QWidget*> QDockAreaLayout::usedSeparatorWidgets() const
3259{
3260 QSet<QWidget*> result;
3261
3262 for (int i = 0; i < separatorWidgets.count(); ++i)
3263 result << separatorWidgets.at(i);
3264 for (int i = 0; i < QInternal::DockCount; ++i) {
3265 const QDockAreaLayoutInfo &dock = docks[i];
3266 result += dock.usedSeparatorWidgets();
3267 }
3268 return result;
3269}
3270#endif
3271
3272QRect QDockAreaLayout::gapRect(const QList<int> &path) const
3273{
3274 const QDockAreaLayoutInfo *info = this->info(path);
3275 if (info == 0)
3276 return QRect();
3277 const QList<QDockAreaLayoutItem> &item_list = info->item_list;
3278 Qt::Orientation o = info->o;
3279 int index = path.last();
3280 if (index < 0 || index >= item_list.count())
3281 return QRect();
3282 const QDockAreaLayoutItem &item = item_list.at(index);
3283 if (!(item.flags & QDockAreaLayoutItem::GapItem))
3284 return QRect();
3285
3286 QRect result;
3287
3288#ifndef QT_NO_TABBAR
3289 if (info->tabbed) {
3290 result = info->tabContentRect();
3291 } else
3292#endif
3293 {
3294 int pos = item.pos;
3295 int size = item.size;
3296
3297 int prev = info->prev(index);
3298 int next = info->next(index);
3299
3300 if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem)) {
3301 pos += sep;
3302 size -= sep;
3303 }
3304 if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem))
3305 size -= sep;
3306
3307 QPoint p;
3308 rpick(o, p) = pos;
3309 rperp(o, p) = perp(o, info->rect.topLeft());
3310 QSize s;
3311 rpick(o, s) = size;
3312 rperp(o, s) = perp(o, info->rect.size());
3313
3314 result = QRect(p, s);
3315 }
3316
3317 return result;
3318}
3319
3320void QDockAreaLayout::keepSize(QDockWidget *w)
3321{
3322 QList<int> path = indexOf(w);
3323 if (path.isEmpty())
3324 return;
3325 QDockAreaLayoutItem &item = this->item(path);
3326 if (item.size != -1)
3327 item.flags |= QDockAreaLayoutItem::KeepSize;
3328}
3329
3330QT_END_NAMESPACE
3331
3332#endif // QT_NO_DOCKWIDGET
Note: See TracBrowser for help on using the repository browser.