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

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

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

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