source: trunk/src/gui/widgets/qmainwindowlayout.cpp@ 64

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

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

File size: 54.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qmainwindowlayout_p.h"
43#include "qdockarealayout_p.h"
44
45#ifndef QT_NO_MAINWINDOW
46#include "qdockwidget.h"
47#include "qdockwidget_p.h"
48#include "qtoolbar_p.h"
49#include "qmainwindow.h"
50#include "qmainwindowlayout_p.h"
51#include "qtoolbar.h"
52#include "qtoolbarlayout_p.h"
53#include "qwidgetanimator_p.h"
54#include "qrubberband.h"
55#include "qdockwidget_p.h"
56#include "qtabbar_p.h"
57
58#include <qapplication.h>
59#include <qstatusbar.h>
60#include <qstring.h>
61#include <qstyle.h>
62#include <qvarlengtharray.h>
63#include <qstack.h>
64#include <qmap.h>
65#include <qtimer.h>
66
67#include <qdebug.h>
68
69#include <private/qapplication_p.h>
70#include <private/qlayoutengine_p.h>
71#ifdef Q_WS_MAC
72# include <private/qcore_mac_p.h>
73# include <private/qt_cocoa_helpers_mac_p.h>
74#endif
75
76#ifdef Q_DEBUG_MAINWINDOW_LAYOUT
77# include <QTextStream>
78#endif
79
80QT_BEGIN_NAMESPACE
81
82/******************************************************************************
83** debug
84*/
85
86#if defined(Q_DEBUG_MAINWINDOW_LAYOUT) && !defined(QT_NO_DOCKWIDGET)
87
88static QTextStream qout(stderr, QIODevice::WriteOnly);
89
90static void dumpLayout(QTextStream &qout, const QDockAreaLayoutInfo &layout, QString indent);
91
92static void dumpLayout(QTextStream &qout, const QDockAreaLayoutItem &item, QString indent)
93{
94 qout << indent << "QDockAreaLayoutItem: "
95 << "pos: " << item.pos << " size:" << item.size
96 << " gap:" << (item.flags & QDockAreaLayoutItem::GapItem)
97 << " keepSize:" << (item.flags & QDockAreaLayoutItem::KeepSize) << '\n';
98 indent += QLatin1String(" ");
99 if (item.widgetItem != 0) {
100 qout << indent << "widget: "
101 << item.widgetItem->widget()->metaObject()->className()
102 << ' ' << item.widgetItem->widget()->windowTitle() << '\n';
103 } else if (item.subinfo != 0) {
104 qout << indent << "subinfo:\n";
105 dumpLayout(qout, *item.subinfo, indent + QLatin1String(" "));
106 } else if (item.placeHolderItem != 0) {
107 QRect r = item.placeHolderItem->topLevelRect;
108 qout << indent << "placeHolder: "
109 << "pos: " << item.pos << " size:" << item.size
110 << " gap:" << (item.flags & QDockAreaLayoutItem::GapItem)
111 << " keepSize:" << (item.flags & QDockAreaLayoutItem::KeepSize)
112 << " objectName:" << item.placeHolderItem->objectName
113 << " hidden:" << item.placeHolderItem->hidden
114 << " window:" << item.placeHolderItem->window
115 << " rect:" << r.x() << ',' << r.y() << ' '
116 << r.width() << 'x' << r.height() << '\n';
117 }
118 qout.flush();
119}
120
121static void dumpLayout(QTextStream &qout, const QDockAreaLayoutInfo &layout, QString indent)
122{
123 qout << indent << "QDockAreaLayoutInfo: "
124 << layout.rect.left() << ','
125 << layout.rect.top() << ' '
126 << layout.rect.width() << 'x'
127 << layout.rect.height()
128 << " orient:" << layout.o
129 << " tabbed:" << layout.tabbed
130 << " tbshape:" << layout.tabBarShape << '\n';
131
132 indent += QLatin1String(" ");
133
134 for (int i = 0; i < layout.item_list.count(); ++i) {
135 qout << indent << "Item: " << i << '\n';
136 dumpLayout(qout, layout.item_list.at(i), indent + QLatin1String(" "));
137 }
138 qout.flush();
139};
140
141static void dumpLayout(QTextStream &qout, const QDockAreaLayout &layout, QString indent)
142{
143 qout << indent << "QDockAreaLayout: "
144 << layout.rect.left() << ','
145 << layout.rect.top() << ' '
146 << layout.rect.width() << 'x'
147 << layout.rect.height() << '\n';
148
149 qout << indent << "TopDockArea:\n";
150 dumpLayout(qout, layout.docks[QInternal::TopDock], indent + QLatin1String(" "));
151 qout << indent << "LeftDockArea:\n";
152 dumpLayout(qout, layout.docks[QInternal::LeftDock], indent + QLatin1String(" "));
153 qout << indent << "RightDockArea:\n";
154 dumpLayout(qout, layout.docks[QInternal::RightDock], indent + QLatin1String(" "));
155 qout << indent << "BottomDockArea:\n";
156 dumpLayout(qout, layout.docks[QInternal::BottomDock], indent + QLatin1String(" "));
157
158 qout.flush();
159};
160
161void qt_dumpLayout(QTextStream &qout, QMainWindow *window)
162{
163 QMainWindowLayout *layout = qobject_cast<QMainWindowLayout*>(window->layout());
164 dumpLayout(qout, layout->layoutState.dockAreaLayout, QString());
165}
166
167#endif // Q_DEBUG_MAINWINDOW_LAYOUT && !QT_NO_DOCKWIDGET
168
169/******************************************************************************
170** QMainWindowLayoutState
171*/
172
173// we deal with all the #ifndefferry here so QMainWindowLayout code is clean
174
175QMainWindowLayoutState::QMainWindowLayoutState(QMainWindow *win)
176 :
177#ifndef QT_NO_TOOLBAR
178 toolBarAreaLayout(win),
179#endif
180#ifndef QT_NO_DOCKWIDGET
181 dockAreaLayout(win)
182#else
183 centralWidgetItem(0)
184#endif
185
186{
187 mainWindow = win;
188}
189
190QSize QMainWindowLayoutState::sizeHint() const
191{
192
193 QSize result(0, 0);
194
195#ifndef QT_NO_DOCKWIDGET
196 result = dockAreaLayout.sizeHint();
197#else
198 if (centralWidgetItem != 0)
199 result = centralWidgetItem->sizeHint();
200#endif
201
202#ifndef QT_NO_TOOLBAR
203 result = toolBarAreaLayout.sizeHint(result);
204#endif // QT_NO_TOOLBAR
205
206 return result;
207}
208
209QSize QMainWindowLayoutState::minimumSize() const
210{
211 QSize result(0, 0);
212
213#ifndef QT_NO_DOCKWIDGET
214 result = dockAreaLayout.minimumSize();
215#else
216 if (centralWidgetItem != 0)
217 result = centralWidgetItem->minimumSize();
218#endif
219
220#ifndef QT_NO_TOOLBAR
221 result = toolBarAreaLayout.minimumSize(result);
222#endif // QT_NO_TOOLBAR
223
224 return result;
225}
226
227void QMainWindowLayoutState::apply(bool animated)
228{
229#ifndef QT_NO_TOOLBAR
230 toolBarAreaLayout.apply(animated);
231#endif
232
233#ifndef QT_NO_DOCKWIDGET
234// dumpLayout(dockAreaLayout, QString());
235 dockAreaLayout.apply(animated);
236#else
237 if (centralWidgetItem != 0) {
238 QMainWindowLayout *layout = qobject_cast<QMainWindowLayout*>(mainWindow->layout());
239 Q_ASSERT(layout != 0);
240 layout->widgetAnimator->animate(centralWidgetItem->widget(), centralWidgetRect, animated);
241 }
242#endif
243}
244
245void QMainWindowLayoutState::fitLayout()
246{
247 QRect r;
248#ifdef QT_NO_TOOLBAR
249 r = rect;
250#else
251 toolBarAreaLayout.rect = rect;
252 r = toolBarAreaLayout.fitLayout();
253#endif // QT_NO_TOOLBAR
254
255#ifndef QT_NO_DOCKWIDGET
256 dockAreaLayout.rect = r;
257 dockAreaLayout.fitLayout();
258#else
259 centralWidgetRect = r;
260#endif
261}
262
263void QMainWindowLayoutState::deleteAllLayoutItems()
264{
265#ifndef QT_NO_TOOLBAR
266 toolBarAreaLayout.deleteAllLayoutItems();
267#endif
268
269#ifndef QT_NO_DOCKWIDGET
270 dockAreaLayout.deleteAllLayoutItems();
271#endif
272}
273
274void QMainWindowLayoutState::deleteCentralWidgetItem()
275{
276#ifndef QT_NO_DOCKWIDGET
277 delete dockAreaLayout.centralWidgetItem;
278 dockAreaLayout.centralWidgetItem = 0;
279#else
280 delete centralWidgetItem;
281 centralWidgetItem = 0;
282#endif
283}
284
285QLayoutItem *QMainWindowLayoutState::itemAt(int index, int *x) const
286{
287#ifndef QT_NO_TOOLBAR
288 if (QLayoutItem *ret = toolBarAreaLayout.itemAt(x, index))
289 return ret;
290#endif
291
292#ifndef QT_NO_DOCKWIDGET
293 if (QLayoutItem *ret = dockAreaLayout.itemAt(x, index))
294 return ret;
295#else
296 if (centralWidgetItem != 0 && (*x)++ == index)
297 return centralWidgetItem;
298#endif
299
300 return 0;
301}
302
303QLayoutItem *QMainWindowLayoutState::takeAt(int index, int *x)
304{
305#ifndef QT_NO_TOOLBAR
306 if (QLayoutItem *ret = toolBarAreaLayout.takeAt(x, index))
307 return ret;
308#endif
309
310#ifndef QT_NO_DOCKWIDGET
311 if (QLayoutItem *ret = dockAreaLayout.takeAt(x, index))
312 return ret;
313#else
314 if (centralWidgetItem != 0 && (*x)++ == index) {
315 QLayoutItem *ret = centralWidgetItem;
316 centralWidgetItem = 0;
317 return ret;
318 }
319#endif
320
321 return 0;
322}
323
324QList<int> QMainWindowLayoutState::indexOf(QWidget *widget) const
325{
326 QList<int> result;
327
328#ifndef QT_NO_TOOLBAR
329 // is it a toolbar?
330 if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) {
331 result = toolBarAreaLayout.indexOf(toolBar);
332 if (!result.isEmpty())
333 result.prepend(0);
334 return result;
335 }
336#endif
337
338#ifndef QT_NO_DOCKWIDGET
339 // is it a dock widget?
340 if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(widget)) {
341 result = dockAreaLayout.indexOf(dockWidget);
342 if (!result.isEmpty())
343 result.prepend(1);
344 return result;
345 }
346#endif //QT_NO_DOCKWIDGET
347
348 return result;
349}
350
351bool QMainWindowLayoutState::contains(QWidget *widget) const
352{
353#ifndef QT_NO_DOCKWIDGET
354 if (dockAreaLayout.centralWidgetItem != 0 && dockAreaLayout.centralWidgetItem->widget() == widget)
355 return true;
356 if (!dockAreaLayout.indexOf(widget).isEmpty())
357 return true;
358#else
359 if (centralWidgetItem != 0 && centralWidgetItem->widget() == widget)
360 return true;
361#endif
362
363#ifndef QT_NO_TOOLBAR
364 if (!toolBarAreaLayout.indexOf(widget).isEmpty())
365 return true;
366#endif
367 return false;
368}
369
370void QMainWindowLayoutState::setCentralWidget(QWidget *widget)
371{
372 QLayoutItem *item = 0;
373 //make sure we remove the widget
374 deleteCentralWidgetItem();
375
376 if (widget != 0)
377 item = new QWidgetItemV2(widget);
378
379#ifndef QT_NO_DOCKWIDGET
380 dockAreaLayout.centralWidgetItem = item;
381#else
382 centralWidgetItem = item;
383#endif
384}
385
386QWidget *QMainWindowLayoutState::centralWidget() const
387{
388 QLayoutItem *item = 0;
389
390#ifndef QT_NO_DOCKWIDGET
391 item = dockAreaLayout.centralWidgetItem;
392#else
393 item = centralWidgetItem;
394#endif
395
396 if (item != 0)
397 return item->widget();
398 return 0;
399}
400
401QList<int> QMainWindowLayoutState::gapIndex(QWidget *widget,
402 const QPoint &pos) const
403{
404 QList<int> result;
405
406#ifndef QT_NO_TOOLBAR
407 // is it a toolbar?
408 if (qobject_cast<QToolBar*>(widget) != 0) {
409 result = toolBarAreaLayout.gapIndex(pos);
410 if (!result.isEmpty())
411 result.prepend(0);
412 return result;
413 }
414#endif
415
416#ifndef QT_NO_DOCKWIDGET
417 // is it a dock widget?
418 if (qobject_cast<QDockWidget *>(widget) != 0) {
419 result = dockAreaLayout.gapIndex(pos);
420 if (!result.isEmpty())
421 result.prepend(1);
422 return result;
423 }
424#endif //QT_NO_DOCKWIDGET
425
426 return result;
427}
428
429bool QMainWindowLayoutState::insertGap(QList<int> path, QLayoutItem *item)
430{
431 if (path.isEmpty())
432 return false;
433
434 int i = path.takeFirst();
435
436#ifndef QT_NO_TOOLBAR
437 if (i == 0) {
438 Q_ASSERT(qobject_cast<QToolBar*>(item->widget()) != 0);
439 return toolBarAreaLayout.insertGap(path, item);
440 }
441#endif
442
443#ifndef QT_NO_DOCKWIDGET
444 if (i == 1) {
445 Q_ASSERT(qobject_cast<QDockWidget*>(item->widget()) != 0);
446 return dockAreaLayout.insertGap(path, item);
447 }
448#endif //QT_NO_DOCKWIDGET
449
450 return false;
451}
452
453void QMainWindowLayoutState::remove(QList<int> path)
454{
455 int i = path.takeFirst();
456
457#ifndef QT_NO_TOOLBAR
458 if (i == 0)
459 toolBarAreaLayout.remove(path);
460#endif
461
462#ifndef QT_NO_DOCKWIDGET
463 if (i == 1)
464 dockAreaLayout.remove(path);
465#endif //QT_NO_DOCKWIDGET
466}
467
468void QMainWindowLayoutState::remove(QLayoutItem *item)
469{
470#ifndef QT_NO_TOOLBAR
471 toolBarAreaLayout.remove(item);
472#endif
473
474#ifndef QT_NO_DOCKWIDGET
475 // is it a dock widget?
476 if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(item->widget())) {
477 QList<int> path = dockAreaLayout.indexOf(dockWidget);
478 if (!path.isEmpty())
479 dockAreaLayout.remove(path);
480 }
481#endif //QT_NO_DOCKWIDGET
482}
483
484void QMainWindowLayoutState::clear()
485{
486#ifndef QT_NO_TOOLBAR
487 toolBarAreaLayout.clear();
488#endif
489
490#ifndef QT_NO_DOCKWIDGET
491 dockAreaLayout.clear();
492#else
493 centralWidgetRect = QRect(0, 0, -1, -1);
494#endif
495
496 rect = QRect(0, 0, -1, -1);
497}
498
499bool QMainWindowLayoutState::isValid() const
500{
501 return rect.isValid();
502}
503
504QLayoutItem *QMainWindowLayoutState::item(QList<int> path)
505{
506 int i = path.takeFirst();
507
508#ifndef QT_NO_TOOLBAR
509 if (i == 0)
510 return toolBarAreaLayout.item(path).widgetItem;
511#endif
512
513#ifndef QT_NO_DOCKWIDGET
514 if (i == 1)
515 return dockAreaLayout.item(path).widgetItem;
516#endif //QT_NO_DOCKWIDGET
517
518 return 0;
519}
520
521QRect QMainWindowLayoutState::itemRect(QList<int> path) const
522{
523 int i = path.takeFirst();
524
525#ifndef QT_NO_TOOLBAR
526 if (i == 0)
527 return toolBarAreaLayout.itemRect(path);
528#endif
529
530#ifndef QT_NO_DOCKWIDGET
531 if (i == 1)
532 return dockAreaLayout.itemRect(path);
533#endif //QT_NO_DOCKWIDGET
534
535 return QRect();
536}
537
538QRect QMainWindowLayoutState::gapRect(QList<int> path) const
539{
540 int i = path.takeFirst();
541
542#ifndef QT_NO_TOOLBAR
543 if (i == 0)
544 return toolBarAreaLayout.itemRect(path);
545#endif
546
547#ifndef QT_NO_DOCKWIDGET
548 if (i == 1)
549 return dockAreaLayout.gapRect(path);
550#endif //QT_NO_DOCKWIDGET
551
552 return QRect();
553}
554
555QLayoutItem *QMainWindowLayoutState::plug(QList<int> path)
556{
557 int i = path.takeFirst();
558
559#ifndef QT_NO_TOOLBAR
560 if (i == 0)
561 return toolBarAreaLayout.plug(path);
562#endif
563
564#ifndef QT_NO_DOCKWIDGET
565 if (i == 1)
566 return dockAreaLayout.plug(path);
567#endif //QT_NO_DOCKWIDGET
568
569 return 0;
570}
571
572QLayoutItem *QMainWindowLayoutState::unplug(QList<int> path, QMainWindowLayoutState *other)
573{
574 int i = path.takeFirst();
575
576#ifdef QT_NO_TOOLBAR
577 Q_UNUSED(other);
578#else
579 if (i == 0)
580 return toolBarAreaLayout.unplug(path, other ? &other->toolBarAreaLayout : 0);
581#endif
582
583#ifndef QT_NO_DOCKWIDGET
584 if (i == 1)
585 return dockAreaLayout.unplug(path);
586#endif //QT_NO_DOCKWIDGET
587
588 return 0;
589}
590
591void QMainWindowLayoutState::saveState(QDataStream &stream) const
592{
593#ifndef QT_NO_DOCKWIDGET
594 dockAreaLayout.saveState(stream);
595#endif
596#ifndef QT_NO_TOOLBAR
597 toolBarAreaLayout.saveState(stream);
598#endif
599}
600
601template <typename T>
602static QList<T> findChildrenHelper(const QObject *o)
603{
604 const QObjectList &list = o->children();
605 QList<T> result;
606
607 for (int i=0; i < list.size(); ++i) {
608 if (T t = qobject_cast<T>(list[i])) {
609 result.append(t);
610 }
611 }
612
613 return result;
614}
615
616//pre4.3 tests the format that was used before 4.3
617bool QMainWindowLayoutState::checkFormat(QDataStream &stream, bool pre43)
618{
619#ifdef QT_NO_TOOLBAR
620 Q_UNUSED(pre43);
621#endif
622 while (!stream.atEnd()) {
623 uchar marker;
624 stream >> marker;
625 switch(marker)
626 {
627#ifndef QT_NO_TOOLBAR
628 case QToolBarAreaLayout::ToolBarStateMarker:
629 case QToolBarAreaLayout::ToolBarStateMarkerEx:
630 {
631 QList<QToolBar *> toolBars = findChildrenHelper<QToolBar*>(mainWindow);
632 if (!toolBarAreaLayout.restoreState(stream, toolBars, marker,
633 pre43 /*testing 4.3 format*/, true /*testing*/)) {
634 return false;
635 }
636 }
637 break;
638#endif // QT_NO_TOOLBAR
639
640#ifndef QT_NO_DOCKWIDGET
641 case QDockAreaLayout::DockWidgetStateMarker:
642 {
643 QList<QDockWidget *> dockWidgets = findChildrenHelper<QDockWidget*>(mainWindow);
644 if (!dockAreaLayout.restoreState(stream, dockWidgets, true /*testing*/)) {
645 return false;
646 }
647 }
648 break;
649#endif
650 default:
651 //there was an error during the parsing
652 return false;
653 }// switch
654 } //while
655
656 //everything went fine: it must be a pre-4.3 saved state
657 return true;
658}
659
660bool QMainWindowLayoutState::restoreState(QDataStream &_stream,
661 const QMainWindowLayoutState &oldState)
662{
663 //make a copy of the data so that we can read it more than once
664 QByteArray copy;
665 while(!_stream.atEnd()) {
666 int length = 1024;
667 QByteArray ba(length, '\0');
668 length = _stream.readRawData(ba.data(), ba.size());
669 ba.resize(length);
670 copy += ba;
671 }
672
673 QDataStream ds(copy);
674 const bool oldFormat = !checkFormat(ds, false);
675 if (oldFormat) {
676 //we should try with the old format
677 QDataStream ds2(copy);
678 if (!checkFormat(ds2, true)) {
679 return false; //format unknown
680 }
681 }
682
683 QDataStream stream(copy);
684
685 while (!stream.atEnd()) {
686 uchar marker;
687 stream >> marker;
688 switch(marker)
689 {
690#ifndef QT_NO_DOCKWIDGET
691 case QDockAreaLayout::DockWidgetStateMarker:
692 {
693 QList<QDockWidget *> dockWidgets = findChildrenHelper<QDockWidget*>(mainWindow);
694 if (!dockAreaLayout.restoreState(stream, dockWidgets))
695 return false;
696
697 for (int i = 0; i < dockWidgets.size(); ++i) {
698 QDockWidget *w = dockWidgets.at(i);
699 QList<int> path = dockAreaLayout.indexOf(w);
700 if (path.isEmpty()) {
701 QList<int> oldPath = oldState.dockAreaLayout.indexOf(w);
702 if (oldPath.isEmpty()) {
703 continue;
704 }
705 QDockAreaLayoutInfo *info = dockAreaLayout.info(oldPath);
706 if (info == 0) {
707 continue;
708 }
709 info->item_list.append(QDockAreaLayoutItem(new QDockWidgetItem(w)));
710 }
711 }
712 }
713 break;
714#endif // QT_NO_DOCKWIDGET
715
716#ifndef QT_NO_TOOLBAR
717 case QToolBarAreaLayout::ToolBarStateMarker:
718 case QToolBarAreaLayout::ToolBarStateMarkerEx:
719 {
720 QList<QToolBar *> toolBars = findChildrenHelper<QToolBar*>(mainWindow);
721 if (!toolBarAreaLayout.restoreState(stream, toolBars, marker, oldFormat))
722 return false;
723
724 for (int i = 0; i < toolBars.size(); ++i) {
725 QToolBar *w = toolBars.at(i);
726 QList<int> path = toolBarAreaLayout.indexOf(w);
727 if (path.isEmpty()) {
728 QList<int> oldPath = oldState.toolBarAreaLayout.indexOf(w);
729 if (oldPath.isEmpty()) {
730 continue;
731 }
732 toolBarAreaLayout.docks[oldPath.at(0)].insertToolBar(0, w);
733 }
734 }
735 }
736 break;
737#endif //QT_NO_TOOLBAR
738 default:
739 return false;
740 }// switch
741 } //while
742
743
744 return true;
745}
746
747/******************************************************************************
748** QMainWindowLayoutState - toolbars
749*/
750
751#ifndef QT_NO_TOOLBAR
752
753static inline void validateToolBarArea(Qt::ToolBarArea &area)
754{
755 switch (area) {
756 case Qt::LeftToolBarArea:
757 case Qt::RightToolBarArea:
758 case Qt::TopToolBarArea:
759 case Qt::BottomToolBarArea:
760 break;
761 default:
762 area = Qt::TopToolBarArea;
763 }
764}
765
766static QInternal::DockPosition toDockPos(Qt::ToolBarArea area)
767{
768 switch (area) {
769 case Qt::LeftToolBarArea: return QInternal::LeftDock;
770 case Qt::RightToolBarArea: return QInternal::RightDock;
771 case Qt::TopToolBarArea: return QInternal::TopDock;
772 case Qt::BottomToolBarArea: return QInternal::BottomDock;
773 default:
774 break;
775 }
776
777 return QInternal::DockCount;
778}
779
780static Qt::ToolBarArea toToolBarArea(QInternal::DockPosition pos)
781{
782 switch (pos) {
783 case QInternal::LeftDock: return Qt::LeftToolBarArea;
784 case QInternal::RightDock: return Qt::RightToolBarArea;
785 case QInternal::TopDock: return Qt::TopToolBarArea;
786 case QInternal::BottomDock: return Qt::BottomToolBarArea;
787 default: break;
788 }
789 return Qt::NoToolBarArea;
790}
791
792static inline Qt::ToolBarArea toToolBarArea(int pos)
793{
794 return toToolBarArea(static_cast<QInternal::DockPosition>(pos));
795}
796
797void QMainWindowLayout::addToolBarBreak(Qt::ToolBarArea area)
798{
799 validateToolBarArea(area);
800
801 layoutState.toolBarAreaLayout.addToolBarBreak(toDockPos(area));
802 if (savedState.isValid())
803 savedState.toolBarAreaLayout.addToolBarBreak(toDockPos(area));
804
805 invalidate();
806}
807
808void QMainWindowLayout::insertToolBarBreak(QToolBar *before)
809{
810 layoutState.toolBarAreaLayout.insertToolBarBreak(before);
811 if (savedState.isValid())
812 savedState.toolBarAreaLayout.insertToolBarBreak(before);
813 invalidate();
814}
815
816void QMainWindowLayout::removeToolBarBreak(QToolBar *before)
817{
818 layoutState.toolBarAreaLayout.removeToolBarBreak(before);
819 if (savedState.isValid())
820 savedState.toolBarAreaLayout.removeToolBarBreak(before);
821 invalidate();
822}
823
824void QMainWindowLayout::moveToolBar(QToolBar *toolbar, int pos)
825{
826 layoutState.toolBarAreaLayout.moveToolBar(toolbar, pos);
827 if (savedState.isValid())
828 savedState.toolBarAreaLayout.moveToolBar(toolbar, pos);
829 invalidate();
830}
831
832/* Removes the toolbar from the mainwindow so that it can be added again. Does not
833 explicitly hide the toolbar. */
834void QMainWindowLayout::removeToolBar(QToolBar *toolbar)
835{
836 if (toolbar) {
837 QObject::disconnect(parentWidget(), SIGNAL(iconSizeChanged(QSize)),
838 toolbar, SLOT(_q_updateIconSize(QSize)));
839 QObject::disconnect(parentWidget(), SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
840 toolbar, SLOT(_q_updateToolButtonStyle(Qt::ToolButtonStyle)));
841
842#ifdef Q_WS_MAC
843 if (usesHIToolBar(toolbar)) {
844 removeFromMacToolbar(toolbar);
845 } else
846#endif // Q_WS_MAC
847 {
848 removeWidget(toolbar);
849 }
850 }
851}
852
853/*!
854 Adds \a toolbar to \a area, continuing the current line.
855*/
856void QMainWindowLayout::addToolBar(Qt::ToolBarArea area,
857 QToolBar *toolbar,
858 bool)
859{
860 validateToolBarArea(area);
861#ifdef Q_WS_MAC
862 if ((area == Qt::TopToolBarArea)
863 && layoutState.mainWindow->unifiedTitleAndToolBarOnMac()) {
864 insertIntoMacToolbar(0, toolbar);
865 } else
866#endif
867 {
868 //let's add the toolbar to the layout
869 addChildWidget(toolbar);
870 QLayoutItem * item = layoutState.toolBarAreaLayout.addToolBar(toDockPos(area), toolbar);
871 if (savedState.isValid() && item) {
872 // copy the toolbar also in the saved state
873 savedState.toolBarAreaLayout.insertItem(toDockPos(area), item);
874 }
875 invalidate();
876
877 //this ensures that the toolbar has the right window flags (not floating any more)
878 toolbar->d_func()->updateWindowFlags(false /*floating*/);
879 }
880}
881
882/*!
883 Adds \a toolbar before \a before
884*/
885void QMainWindowLayout::insertToolBar(QToolBar *before, QToolBar *toolbar)
886{
887#ifdef Q_WS_MAC
888 if (usesHIToolBar(before)) {
889 insertIntoMacToolbar(before, toolbar);
890 } else
891#endif // Q_WS_MAC
892 {
893 addChildWidget(toolbar);
894 QLayoutItem * item = layoutState.toolBarAreaLayout.insertToolBar(before, toolbar);
895 if (savedState.isValid() && item) {
896 // copy the toolbar also in the saved state
897 savedState.toolBarAreaLayout.insertItem(before, item);
898 }
899 if (!currentGapPos.isEmpty() && currentGapPos.first() == 0) {
900 currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex();
901 if (!currentGapPos.isEmpty()) {
902 currentGapPos.prepend(0);
903 currentGapRect = layoutState.itemRect(currentGapPos);
904 }
905 }
906 invalidate();
907 }
908}
909
910Qt::ToolBarArea QMainWindowLayout::toolBarArea(QToolBar *toolbar) const
911{
912 QInternal::DockPosition pos = layoutState.toolBarAreaLayout.findToolBar(toolbar);
913 switch (pos) {
914 case QInternal::LeftDock: return Qt::LeftToolBarArea;
915 case QInternal::RightDock: return Qt::RightToolBarArea;
916 case QInternal::TopDock: return Qt::TopToolBarArea;
917 case QInternal::BottomDock: return Qt::BottomToolBarArea;
918 default: break;
919 }
920#ifdef Q_WS_MAC
921 if (pos == QInternal::DockCount) {
922 if (qtoolbarsInUnifiedToolbarList.contains(toolbar))
923 return Qt::TopToolBarArea;
924 }
925#endif
926 return Qt::NoToolBarArea;
927}
928
929bool QMainWindowLayout::toolBarBreak(QToolBar *toolBar) const
930{
931 return layoutState.toolBarAreaLayout.toolBarBreak(toolBar);
932}
933
934void QMainWindowLayout::getStyleOptionInfo(QStyleOptionToolBar *option, QToolBar *toolBar) const
935{
936 option->toolBarArea = toolBarArea(toolBar);
937 layoutState.toolBarAreaLayout.getStyleOptionInfo(option, toolBar);
938}
939
940void QMainWindowLayout::toggleToolBarsVisible()
941{
942 layoutState.toolBarAreaLayout.visible = !layoutState.toolBarAreaLayout.visible;
943 if (!layoutState.mainWindow->isMaximized()){
944 QPoint topLeft = parentWidget()->geometry().topLeft();
945 QRect r = parentWidget()->geometry();
946 r = layoutState.toolBarAreaLayout.rectHint(r);
947 r.moveTo(topLeft);
948 parentWidget()->setGeometry(r);
949// widgetAnimator->animate(parentWidget(), r, true);
950 } else{
951 update();
952 }
953}
954
955#endif // QT_NO_TOOLBAR
956
957/******************************************************************************
958** QMainWindowLayoutState - dock areas
959*/
960
961#ifndef QT_NO_DOCKWIDGET
962
963static inline void validateDockWidgetArea(Qt::DockWidgetArea &area)
964{
965 switch (area) {
966 case Qt::LeftDockWidgetArea:
967 case Qt::RightDockWidgetArea:
968 case Qt::TopDockWidgetArea:
969 case Qt::BottomDockWidgetArea:
970 break;
971 default:
972 area = Qt::LeftDockWidgetArea;
973 }
974}
975
976static QInternal::DockPosition toDockPos(Qt::DockWidgetArea area)
977{
978 switch (area) {
979 case Qt::LeftDockWidgetArea: return QInternal::LeftDock;
980 case Qt::RightDockWidgetArea: return QInternal::RightDock;
981 case Qt::TopDockWidgetArea: return QInternal::TopDock;
982 case Qt::BottomDockWidgetArea: return QInternal::BottomDock;
983 default:
984 break;
985 }
986
987 return QInternal::DockCount;
988}
989
990static Qt::DockWidgetArea toDockWidgetArea(QInternal::DockPosition pos)
991{
992 switch (pos) {
993 case QInternal::LeftDock : return Qt::LeftDockWidgetArea;
994 case QInternal::RightDock : return Qt::RightDockWidgetArea;
995 case QInternal::TopDock : return Qt::TopDockWidgetArea;
996 case QInternal::BottomDock : return Qt::BottomDockWidgetArea;
997 default:
998 break;
999 }
1000
1001 return Qt::NoDockWidgetArea;
1002}
1003
1004inline static Qt::DockWidgetArea toDockWidgetArea(int pos)
1005{
1006 return toDockWidgetArea(static_cast<QInternal::DockPosition>(pos));
1007}
1008
1009void QMainWindowLayout::setCorner(Qt::Corner corner, Qt::DockWidgetArea area)
1010{
1011 if (layoutState.dockAreaLayout.corners[corner] == area)
1012 return;
1013 layoutState.dockAreaLayout.corners[corner] = area;
1014 if (savedState.isValid())
1015 savedState.dockAreaLayout.corners[corner] = area;
1016 invalidate();
1017}
1018
1019Qt::DockWidgetArea QMainWindowLayout::corner(Qt::Corner corner) const
1020{
1021 return layoutState.dockAreaLayout.corners[corner];
1022}
1023
1024void QMainWindowLayout::addDockWidget(Qt::DockWidgetArea area,
1025 QDockWidget *dockwidget,
1026 Qt::Orientation orientation)
1027{
1028 addChildWidget(dockwidget);
1029
1030 // If we are currently moving a separator, then we need to abort the move, since each
1031 // time we move the mouse layoutState is replaced by savedState modified by the move.
1032 if (!movingSeparator.isEmpty())
1033 endSeparatorMove(movingSeparatorPos);
1034
1035 layoutState.dockAreaLayout.addDockWidget(toDockPos(area), dockwidget, orientation);
1036 emit dockwidget->dockLocationChanged(area);
1037 invalidate();
1038}
1039
1040void QMainWindowLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
1041{
1042 addChildWidget(second);
1043 layoutState.dockAreaLayout.tabifyDockWidget(first, second);
1044 emit second->dockLocationChanged(dockWidgetArea(first));
1045 invalidate();
1046}
1047
1048bool QMainWindowLayout::restoreDockWidget(QDockWidget *dockwidget)
1049{
1050 addChildWidget(dockwidget);
1051 if (!layoutState.dockAreaLayout.restoreDockWidget(dockwidget))
1052 return false;
1053 emit dockwidget->dockLocationChanged(dockWidgetArea(dockwidget));
1054 invalidate();
1055 return true;
1056}
1057
1058#ifndef QT_NO_TABBAR
1059bool QMainWindowLayout::documentMode() const
1060{
1061 return _documentMode;
1062}
1063
1064void QMainWindowLayout::setDocumentMode(bool enabled)
1065{
1066 if (_documentMode == enabled)
1067 return;
1068
1069 _documentMode = enabled;
1070
1071 // Update the document mode for all tab bars
1072 foreach (QTabBar *bar, usedTabBars)
1073 bar->setDocumentMode(_documentMode);
1074 foreach (QTabBar *bar, unusedTabBars)
1075 bar->setDocumentMode(_documentMode);
1076}
1077#endif // QT_NO_TABBAR
1078
1079void QMainWindowLayout::setVerticalTabsEnabled(bool enabled)
1080{
1081#ifdef QT_NO_TABBAR
1082 Q_UNUSED(enabled);
1083#else
1084 if (verticalTabsEnabled == enabled)
1085 return;
1086
1087 verticalTabsEnabled = enabled;
1088
1089 updateTabBarShapes();
1090#endif // QT_NO_TABBAR
1091}
1092
1093#ifndef QT_NO_TABWIDGET
1094QTabWidget::TabShape QMainWindowLayout::tabShape() const
1095{
1096 return _tabShape;
1097}
1098
1099void QMainWindowLayout::setTabShape(QTabWidget::TabShape tabShape)
1100{
1101 if (_tabShape == tabShape)
1102 return;
1103
1104 _tabShape = tabShape;
1105
1106 updateTabBarShapes();
1107}
1108
1109QTabWidget::TabPosition QMainWindowLayout::tabPosition(Qt::DockWidgetArea area) const
1110{
1111 return tabPositions[toDockPos(area)];
1112}
1113
1114void QMainWindowLayout::setTabPosition(Qt::DockWidgetAreas areas, QTabWidget::TabPosition tabPosition)
1115{
1116 const Qt::DockWidgetArea dockWidgetAreas[] = {
1117 Qt::TopDockWidgetArea,
1118 Qt::LeftDockWidgetArea,
1119 Qt::BottomDockWidgetArea,
1120 Qt::RightDockWidgetArea
1121 };
1122 const QInternal::DockPosition dockPositions[] = {
1123 QInternal::TopDock,
1124 QInternal::LeftDock,
1125 QInternal::BottomDock,
1126 QInternal::RightDock
1127 };
1128
1129 for (int i = 0; i < QInternal::DockCount; ++i)
1130 if (areas & dockWidgetAreas[i])
1131 tabPositions[dockPositions[i]] = tabPosition;
1132
1133 updateTabBarShapes();
1134}
1135
1136static inline QTabBar::Shape tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position)
1137{
1138 const bool rounded = (shape == QTabWidget::Rounded);
1139 if (position == QTabWidget::North)
1140 return rounded ? QTabBar::RoundedNorth : QTabBar::TriangularNorth;
1141 if (position == QTabWidget::South)
1142 return rounded ? QTabBar::RoundedSouth : QTabBar::TriangularSouth;
1143 if (position == QTabWidget::East)
1144 return rounded ? QTabBar::RoundedEast : QTabBar::TriangularEast;
1145 if (position == QTabWidget::West)
1146 return rounded ? QTabBar::RoundedWest : QTabBar::TriangularWest;
1147 return QTabBar::RoundedNorth;
1148}
1149#endif // QT_NO_TABWIDGET
1150
1151#ifndef QT_NO_TABBAR
1152void QMainWindowLayout::updateTabBarShapes()
1153{
1154#ifndef QT_NO_TABWIDGET
1155 const QTabWidget::TabPosition vertical[] = {
1156 QTabWidget::West,
1157 QTabWidget::East,
1158 QTabWidget::North,
1159 QTabWidget::South
1160 };
1161#else
1162 const QTabBar::Shape vertical[] = {
1163 QTabBar::RoundedWest,
1164 QTabBar::RoundedEast,
1165 QTabBar::RoundedNorth,
1166 QTabBar::RoundedSouth
1167 };
1168#endif
1169
1170 QDockAreaLayout &layout = layoutState.dockAreaLayout;
1171
1172 for (int i = 0; i < QInternal::DockCount; ++i) {
1173#ifndef QT_NO_TABWIDGET
1174 QTabWidget::TabPosition pos = verticalTabsEnabled ? vertical[i] : tabPositions[i];
1175 QTabBar::Shape shape = tabBarShapeFrom(_tabShape, pos);
1176#else
1177 QTabBar::Shape shape = verticalTabsEnabled ? vertical[i] : QTabBar::RoundedSouth;
1178#endif
1179 layout.docks[i].setTabBarShape(shape);
1180 }
1181}
1182#endif // QT_NO_TABBAR
1183
1184void QMainWindowLayout::splitDockWidget(QDockWidget *after,
1185 QDockWidget *dockwidget,
1186 Qt::Orientation orientation)
1187{
1188 addChildWidget(dockwidget);
1189 layoutState.dockAreaLayout.splitDockWidget(after, dockwidget, orientation);
1190 emit dockwidget->dockLocationChanged(dockWidgetArea(after));
1191 invalidate();
1192}
1193
1194Qt::DockWidgetArea QMainWindowLayout::dockWidgetArea(QDockWidget *widget) const
1195{
1196 QList<int> pathToWidget = layoutState.dockAreaLayout.indexOf(widget);
1197 if (pathToWidget.isEmpty())
1198 return Qt::NoDockWidgetArea;
1199 return toDockWidgetArea(pathToWidget.first());
1200}
1201
1202void QMainWindowLayout::keepSize(QDockWidget *w)
1203{
1204 layoutState.dockAreaLayout.keepSize(w);
1205}
1206
1207#ifndef QT_NO_TABBAR
1208
1209class QMainWindowTabBar : public QTabBar
1210{
1211public:
1212 QMainWindowTabBar(QWidget *parent);
1213protected:
1214 bool event(QEvent *e);
1215};
1216
1217QMainWindowTabBar::QMainWindowTabBar(QWidget *parent)
1218 : QTabBar(parent)
1219{
1220 setExpanding(false);
1221}
1222
1223bool QMainWindowTabBar::event(QEvent *e)
1224{
1225 // show the tooltip if tab is too small to fit label
1226
1227 if (e->type() != QEvent::ToolTip)
1228 return QTabBar::event(e);
1229 QSize size = this->size();
1230 QSize hint = sizeHint();
1231 if (shape() == QTabBar::RoundedWest || shape() == QTabBar::RoundedEast) {
1232 size.transpose();
1233 hint.transpose();
1234 }
1235 if (size.width() < hint.width())
1236 return QTabBar::event(e);
1237 e->accept();
1238 return true;
1239}
1240
1241QTabBar *QMainWindowLayout::getTabBar()
1242{
1243 QTabBar *result = 0;
1244 if (!unusedTabBars.isEmpty()) {
1245 result = unusedTabBars.takeLast();
1246 } else {
1247 result = new QMainWindowTabBar(parentWidget());
1248 result->setDrawBase(true);
1249 result->setElideMode(Qt::ElideRight);
1250 result->setDocumentMode(_documentMode);
1251 connect(result, SIGNAL(currentChanged(int)), this, SLOT(tabChanged()));
1252 }
1253
1254 usedTabBars.insert(result);
1255 return result;
1256}
1257
1258// Allocates a new separator widget if needed
1259QWidget *QMainWindowLayout::getSeparatorWidget()
1260{
1261 QWidget *result = 0;
1262 if (!unusedSeparatorWidgets.isEmpty()) {
1263 result = unusedSeparatorWidgets.takeLast();
1264 } else {
1265 result = new QWidget(parentWidget());
1266 result->setAttribute(Qt::WA_MouseNoMask, true);
1267 result->setAutoFillBackground(false);
1268 result->setObjectName(QLatin1String("qt_qmainwindow_extended_splitter"));
1269 }
1270 usedSeparatorWidgets.insert(result);
1271 return result;
1272}
1273
1274void QMainWindowLayout::tabChanged()
1275{
1276 QTabBar *tb = qobject_cast<QTabBar*>(sender());
1277 if (tb == 0)
1278 return;
1279 QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(tb);
1280 if (info == 0)
1281 return;
1282 info->apply(false);
1283
1284 if (QWidget *w = centralWidget())
1285 w->raise();
1286}
1287#endif // QT_NO_TABBAR
1288
1289bool QMainWindowLayout::startSeparatorMove(const QPoint &pos)
1290{
1291 movingSeparator = layoutState.dockAreaLayout.findSeparator(pos);
1292
1293 if (movingSeparator.isEmpty())
1294 return false;
1295
1296 savedState = layoutState;
1297 movingSeparatorPos = movingSeparatorOrigin = pos;
1298
1299 return true;
1300}
1301
1302bool QMainWindowLayout::separatorMove(const QPoint &pos)
1303{
1304 if (movingSeparator.isEmpty())
1305 return false;
1306 movingSeparatorPos = pos;
1307 separatorMoveTimer->start();
1308 return true;
1309}
1310
1311void QMainWindowLayout::doSeparatorMove()
1312{
1313 if (movingSeparator.isEmpty())
1314 return;
1315 if (movingSeparatorOrigin == movingSeparatorPos)
1316 return;
1317
1318 layoutState = savedState;
1319 layoutState.dockAreaLayout.separatorMove(movingSeparator, movingSeparatorOrigin,
1320 movingSeparatorPos,
1321 &separatorMoveCache);
1322 movingSeparatorPos = movingSeparatorOrigin;
1323}
1324
1325bool QMainWindowLayout::endSeparatorMove(const QPoint&)
1326{
1327 bool result = !movingSeparator.isEmpty();
1328 movingSeparator.clear();
1329 savedState.clear();
1330 separatorMoveCache.clear();
1331 return result;
1332}
1333
1334void QMainWindowLayout::raise(QDockWidget *widget)
1335{
1336 QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(widget);
1337 if (info == 0)
1338 return;
1339#ifndef QT_NO_TABBAR
1340 if (!info->tabbed)
1341 return;
1342 info->setCurrentTab(widget);
1343#endif
1344}
1345
1346#endif // QT_NO_DOCKWIDGET
1347
1348
1349/******************************************************************************
1350** QMainWindowLayoutState - layout interface
1351*/
1352
1353int QMainWindowLayout::count() const
1354{
1355 qWarning("QMainWindowLayout::count: ?");
1356 return 0; //#################################################
1357}
1358
1359QLayoutItem *QMainWindowLayout::itemAt(int index) const
1360{
1361 int x = 0;
1362
1363 if (QLayoutItem *ret = layoutState.itemAt(index, &x))
1364 return ret;
1365
1366 if (statusbar && x++ == index)
1367 return statusbar;
1368
1369 return 0;
1370}
1371
1372QLayoutItem *QMainWindowLayout::takeAt(int index)
1373{
1374 int x = 0;
1375
1376 if (QLayoutItem *ret = layoutState.takeAt(index, &x)) {
1377 // the widget might in fact have been destroyed by now
1378 if (QWidget *w = ret->widget()) {
1379 widgetAnimator->abort(w);
1380 if (w == pluggingWidget)
1381 pluggingWidget = 0;
1382 }
1383
1384 if (savedState.isValid() ) {
1385 //we need to remove the item also from the saved state to prevent crash
1386 savedState.remove(ret);
1387 //Also, the item may be contained several times as a gap item.
1388 layoutState.remove(ret);
1389 }
1390
1391#ifndef QT_NO_TOOLBAR
1392 if (!currentGapPos.isEmpty() && currentGapPos.first() == 0) {
1393 currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex();
1394 if (!currentGapPos.isEmpty()) {
1395 currentGapPos.prepend(0);
1396 currentGapRect = layoutState.itemRect(currentGapPos);
1397 }
1398 }
1399#endif
1400
1401 return ret;
1402 }
1403
1404 if (statusbar && x++ == index) {
1405 QLayoutItem *ret = statusbar;
1406 statusbar = 0;
1407 return ret;
1408 }
1409
1410 return 0;
1411}
1412
1413void QMainWindowLayout::setGeometry(const QRect &_r)
1414{
1415 if (savedState.isValid())
1416 return;
1417
1418 QRect r = _r;
1419
1420 QLayout::setGeometry(r);
1421
1422 if (statusbar) {
1423 QRect sbr(QPoint(0, 0),
1424 QSize(r.width(), statusbar->heightForWidth(r.width()))
1425 .expandedTo(statusbar->minimumSize()));
1426 sbr.moveBottom(r.bottom());
1427 QRect vr = QStyle::visualRect(QApplication::layoutDirection(), _r, sbr);
1428 statusbar->setGeometry(vr);
1429 r.setBottom(sbr.top() - 1);
1430 }
1431
1432 layoutState.rect = r;
1433 layoutState.fitLayout();
1434 applyState(layoutState, false);
1435}
1436
1437void QMainWindowLayout::addItem(QLayoutItem *)
1438{ qWarning("QMainWindowLayout::addItem: Please use the public QMainWindow API instead"); }
1439
1440QSize QMainWindowLayout::sizeHint() const
1441{
1442 if (!szHint.isValid()) {
1443 szHint = layoutState.sizeHint();
1444 const QSize sbHint = statusbar ? statusbar->sizeHint() : QSize(0, 0);
1445 szHint = QSize(qMax(sbHint.width(), szHint.width()),
1446 sbHint.height() + szHint.height());
1447 }
1448 return szHint;
1449}
1450
1451QSize QMainWindowLayout::minimumSize() const
1452{
1453 if (!minSize.isValid()) {
1454 minSize = layoutState.minimumSize();
1455 const QSize sbMin = statusbar ? statusbar->minimumSize() : QSize(0, 0);
1456 minSize = QSize(qMax(sbMin.width(), minSize.width()),
1457 sbMin.height() + minSize.height());
1458#ifdef Q_WS_MAC
1459 const QSize storedSize = minSize;
1460 int minWidth = 0;
1461 foreach (QToolBar *toolbar, qtoolbarsInUnifiedToolbarList) {
1462 minWidth += toolbar->sizeHint().width() + 20;
1463 }
1464 minSize = QSize(qMax(minWidth, storedSize.width()), storedSize.height());
1465#endif
1466 }
1467 return minSize;
1468}
1469
1470void QMainWindowLayout::invalidate()
1471{
1472 QLayout::invalidate();
1473 minSize = szHint = QSize();
1474}
1475
1476/******************************************************************************
1477** QMainWindowLayout - remaining stuff
1478*/
1479
1480static void fixToolBarOrientation(QLayoutItem *item, int dockPos)
1481{
1482#ifndef QT_NO_TOOLBAR
1483 QToolBar *toolBar = qobject_cast<QToolBar*>(item->widget());
1484 if (toolBar == 0)
1485 return;
1486
1487 QRect oldGeo = toolBar->geometry();
1488
1489 QInternal::DockPosition pos
1490 = static_cast<QInternal::DockPosition>(dockPos);
1491 Qt::Orientation o = pos == QInternal::TopDock || pos == QInternal::BottomDock
1492 ? Qt::Horizontal : Qt::Vertical;
1493 if (o != toolBar->orientation())
1494 toolBar->setOrientation(o);
1495
1496 QSize hint = toolBar->sizeHint().boundedTo(toolBar->maximumSize())
1497 .expandedTo(toolBar->minimumSize());
1498
1499 if (toolBar->size() != hint) {
1500 QRect newGeo(oldGeo.topLeft(), hint);
1501 if (toolBar->layoutDirection() == Qt::RightToLeft)
1502 newGeo.moveRight(oldGeo.right());
1503 toolBar->setGeometry(newGeo);
1504 }
1505
1506#else
1507 Q_UNUSED(item);
1508 Q_UNUSED(dockPos);
1509#endif
1510}
1511
1512void QMainWindowLayout::revert(QLayoutItem *widgetItem)
1513{
1514 if (!savedState.isValid())
1515 return;
1516
1517 QWidget *widget = widgetItem->widget();
1518 layoutState = savedState;
1519 currentGapPos = layoutState.indexOf(widget);
1520 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
1521 layoutState.unplug(currentGapPos);
1522 layoutState.fitLayout();
1523 currentGapRect = layoutState.itemRect(currentGapPos);
1524
1525 plug(widgetItem);
1526}
1527
1528bool QMainWindowLayout::plug(QLayoutItem *widgetItem)
1529{
1530 if (!parentWidget()->isVisible() || parentWidget()->isMinimized() || currentGapPos.isEmpty())
1531 return false;
1532
1533 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
1534
1535 QWidget *widget = widgetItem->widget();
1536
1537 QList<int> previousPath = layoutState.indexOf(widget);
1538
1539 QLayoutItem *it = layoutState.plug(currentGapPos);
1540 Q_ASSERT(it == widgetItem);
1541 Q_UNUSED(it);
1542 if (!previousPath.isEmpty())
1543 layoutState.remove(previousPath);
1544
1545 pluggingWidget = widget;
1546 if (dockOptions & QMainWindow::AnimatedDocks) {
1547 QRect globalRect = currentGapRect;
1548 globalRect.moveTopLeft(parentWidget()->mapToGlobal(globalRect.topLeft()));
1549#ifndef QT_NO_DOCKWIDGET
1550 if (qobject_cast<QDockWidget*>(widget) != 0) {
1551 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(widget->layout());
1552 if (layout->nativeWindowDeco()) {
1553 globalRect.adjust(0, layout->titleHeight(), 0, 0);
1554 } else {
1555 int fw = widget->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, widget);
1556 globalRect.adjust(-fw, -fw, fw, fw);
1557 }
1558 }
1559#endif
1560 widgetAnimator->animate(widget, globalRect,
1561 dockOptions & QMainWindow::AnimatedDocks);
1562 } else {
1563#ifndef QT_NO_DOCKWIDGET
1564 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget))
1565 dw->d_func()->plug(currentGapRect);
1566#endif
1567#ifndef QT_NO_TOOLBAR
1568 if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
1569 tb->d_func()->plug(currentGapRect);
1570#endif
1571 applyState(layoutState);
1572 savedState.clear();
1573#ifndef QT_NO_DOCKWIDGET
1574 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
1575#endif
1576 currentGapPos.clear();
1577 updateGapIndicator();
1578 pluggingWidget = 0;
1579 }
1580
1581 return true;
1582}
1583
1584void QMainWindowLayout::allAnimationsFinished()
1585{
1586#ifndef QT_NO_DOCKWIDGET
1587 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
1588
1589#ifndef QT_NO_TABBAR
1590 foreach (QTabBar *tab_bar, usedTabBars)
1591 tab_bar->show();
1592#endif // QT_NO_TABBAR
1593#endif // QT_NO_DOCKWIDGET
1594
1595 updateGapIndicator();
1596}
1597
1598void QMainWindowLayout::animationFinished(QWidget *widget)
1599{
1600
1601 /* This signal is delivered from QWidgetAnimator over a qeued connection. The problem is that
1602 the widget can be deleted. This is handled as follows:
1603
1604 The animator only ever animates widgets that have been added to this layout. If a widget
1605 is deleted during animation, the widget's destructor removes the widget form this layout.
1606 This in turn aborts the animation (see takeAt()) and this signal will never be delivered.
1607
1608 If the widget is deleted after the animation is finished but before this qeued signal
1609 is delivered, the widget is no longer in the layout and we catch it here. The key is that
1610 QMainWindowLayoutState::contains() never dereferences the pointer. */
1611
1612 if (!layoutState.contains(widget))
1613 return;
1614
1615#ifndef QT_NO_TOOLBAR
1616 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
1617 QToolBarLayout *tbl = qobject_cast<QToolBarLayout*>(tb->layout());
1618 if (tbl->animating) {
1619 tbl->animating = false;
1620 if (tbl->expanded)
1621 tbl->layoutActions(tb->size());
1622 tb->update();
1623 }
1624 }
1625#endif
1626
1627 if (widget != pluggingWidget)
1628 return;
1629
1630#ifndef QT_NO_DOCKWIDGET
1631 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget))
1632 dw->d_func()->plug(currentGapRect);
1633#endif
1634#ifndef QT_NO_TOOLBAR
1635 if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
1636 tb->d_func()->plug(currentGapRect);
1637#endif
1638
1639 applyState(layoutState, false);
1640#ifndef QT_NO_DOCKWIDGET
1641#ifndef QT_NO_TABBAR
1642 if (qobject_cast<QDockWidget*>(widget) != 0) {
1643 // info() might return null if the widget is destroyed while
1644 // animating but before the animationFinished signal is received.
1645 if (QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(widget))
1646 info->setCurrentTab(widget);
1647 }
1648#endif
1649#endif
1650 savedState.clear();
1651 currentGapPos.clear();
1652 pluggingWidget = 0;
1653 updateGapIndicator();
1654}
1655
1656void QMainWindowLayout::restore(bool keepSavedState)
1657{
1658 if (!savedState.isValid())
1659 return;
1660
1661 layoutState = savedState;
1662 applyState(layoutState);
1663 if (!keepSavedState)
1664 savedState.clear();
1665 currentGapPos.clear();
1666 pluggingWidget = 0;
1667 updateGapIndicator();
1668}
1669
1670QMainWindowLayout::QMainWindowLayout(QMainWindow *mainwindow)
1671 : QLayout(mainwindow)
1672 , layoutState(mainwindow)
1673 , savedState(mainwindow)
1674 , dockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowTabbedDocks)
1675 , statusbar(0)
1676#ifndef QT_NO_DOCKWIDGET
1677#ifndef QT_NO_TABBAR
1678 , _documentMode(false)
1679 , verticalTabsEnabled(false)
1680#ifndef QT_NO_TABWIDGET
1681 , _tabShape(QTabWidget::Rounded)
1682#endif
1683#endif
1684#endif // QT_NO_DOCKWIDGET
1685{
1686#ifndef QT_NO_DOCKWIDGET
1687#ifndef QT_NO_TABBAR
1688 sep = mainwindow->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent, 0, mainwindow);
1689#endif
1690 separatorMoveTimer = new QTimer(this);
1691 separatorMoveTimer->setSingleShot(true);
1692 separatorMoveTimer->setInterval(0);
1693 connect(separatorMoveTimer, SIGNAL(timeout()), this, SLOT(doSeparatorMove()));
1694
1695#ifndef QT_NO_TABWIDGET
1696 for (int i = 0; i < QInternal::DockCount; ++i)
1697 tabPositions[i] = QTabWidget::South;
1698#endif
1699#endif // QT_NO_DOCKWIDGET
1700
1701#ifndef QT_NO_RUBBERBAND
1702 gapIndicator = new QRubberBand(QRubberBand::Rectangle, mainwindow);
1703 // For accessibility to identify this special widget.
1704 gapIndicator->setObjectName(QLatin1String("qt_rubberband"));
1705
1706 gapIndicator->hide();
1707#endif
1708 pluggingWidget = 0;
1709
1710 setObjectName(mainwindow->objectName() + QLatin1String("_layout"));
1711 widgetAnimator = new QWidgetAnimator(this);
1712 connect(widgetAnimator, SIGNAL(finished(QWidget*)),
1713 this, SLOT(animationFinished(QWidget*)), Qt::QueuedConnection);
1714 connect(widgetAnimator, SIGNAL(finishedAll()),
1715 this, SLOT(allAnimationsFinished()));
1716}
1717
1718QMainWindowLayout::~QMainWindowLayout()
1719{
1720 layoutState.deleteAllLayoutItems();
1721 layoutState.deleteCentralWidgetItem();
1722
1723#ifdef Q_WS_MAC
1724 cleanUpMacToolbarItems();
1725#endif
1726
1727 delete statusbar;
1728}
1729
1730void QMainWindowLayout::setDockOptions(QMainWindow::DockOptions opts)
1731{
1732 if (opts == dockOptions)
1733 return;
1734
1735 dockOptions = opts;
1736
1737#ifndef QT_NO_DOCKWIDGET
1738 setVerticalTabsEnabled(opts & QMainWindow::VerticalTabs);
1739#endif
1740
1741 invalidate();
1742}
1743
1744#ifndef QT_NO_STATUSBAR
1745QStatusBar *QMainWindowLayout::statusBar() const
1746{ return statusbar ? qobject_cast<QStatusBar *>(statusbar->widget()) : 0; }
1747
1748void QMainWindowLayout::setStatusBar(QStatusBar *sb)
1749{
1750 if (sb)
1751 addChildWidget(sb);
1752 delete statusbar;
1753 statusbar = sb ? new QWidgetItemV2(sb) : 0;
1754 invalidate();
1755}
1756#endif // QT_NO_STATUSBAR
1757
1758QWidget *QMainWindowLayout::centralWidget() const
1759{
1760 return layoutState.centralWidget();
1761}
1762
1763void QMainWindowLayout::setCentralWidget(QWidget *widget)
1764{
1765 if (widget != 0)
1766 addChildWidget(widget);
1767 layoutState.setCentralWidget(widget);
1768 if (savedState.isValid()) {
1769#ifndef QT_NO_DOCKWIDGET
1770 savedState.dockAreaLayout.centralWidgetItem = layoutState.dockAreaLayout.centralWidgetItem;
1771#else
1772 savedState.centralWidgetItem = layoutState.centralWidgetItem;
1773#endif
1774 }
1775 invalidate();
1776}
1777
1778QLayoutItem *QMainWindowLayout::unplug(QWidget *widget)
1779{
1780 QList<int> path = layoutState.indexOf(widget);
1781 if (path.isEmpty())
1782 return 0;
1783
1784 QLayoutItem *item = layoutState.item(path);
1785 if (widget->isWindow())
1786 return item;
1787
1788 QRect r = layoutState.itemRect(path);
1789 savedState = layoutState;
1790
1791#ifndef QT_NO_DOCKWIDGET
1792 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) {
1793 dw->d_func()->unplug(r);
1794 }
1795#endif
1796#ifndef QT_NO_TOOLBAR
1797 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
1798 tb->d_func()->unplug(r);
1799 }
1800#endif
1801
1802
1803 layoutState.unplug(path ,&savedState);
1804 savedState.fitLayout();
1805 currentGapPos = path;
1806 currentGapRect = r;
1807 updateGapIndicator();
1808
1809 fixToolBarOrientation(item, currentGapPos.at(1));
1810
1811 return item;
1812}
1813
1814void QMainWindowLayout::updateGapIndicator()
1815{
1816#ifndef QT_NO_RUBBERBAND
1817 if (widgetAnimator->animating() || currentGapPos.isEmpty()) {
1818 gapIndicator->hide();
1819 } else {
1820 if (gapIndicator->geometry() != currentGapRect)
1821 gapIndicator->setGeometry(currentGapRect);
1822 if (!gapIndicator->isVisible())
1823 gapIndicator->show();
1824 }
1825#endif
1826}
1827
1828QList<int> QMainWindowLayout::hover(QLayoutItem *widgetItem, const QPoint &mousePos)
1829{
1830 if (!parentWidget()->isVisible() || parentWidget()->isMinimized()
1831 || pluggingWidget != 0 || widgetItem == 0)
1832 return QList<int>();
1833
1834 QWidget *widget = widgetItem->widget();
1835 QPoint pos = parentWidget()->mapFromGlobal(mousePos);
1836
1837 if (!savedState.isValid())
1838 savedState = layoutState;
1839
1840 QList<int> path = savedState.gapIndex(widget, pos);
1841
1842 if (!path.isEmpty()) {
1843 bool allowed = false;
1844
1845#ifndef QT_NO_DOCKWIDGET
1846 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget))
1847 allowed = dw->isAreaAllowed(toDockWidgetArea(path.at(1)));
1848#endif
1849#ifndef QT_NO_TOOLBAR
1850 if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
1851 allowed = tb->isAreaAllowed(toToolBarArea(path.at(1)));
1852#endif
1853
1854 if (!allowed)
1855 path.clear();
1856 }
1857
1858 if (path == currentGapPos)
1859 return currentGapPos; // the gap is already there
1860
1861 currentGapPos = path;
1862 if (path.isEmpty()) {
1863 fixToolBarOrientation(widgetItem, 2); // 2 = top dock, ie. horizontal
1864 restore(true);
1865 return QList<int>();
1866 }
1867
1868 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
1869
1870 QMainWindowLayoutState newState = savedState;
1871
1872 if (!newState.insertGap(path, widgetItem)) {
1873 restore(true); // not enough space
1874 return QList<int>();
1875 }
1876
1877 QSize min = newState.minimumSize();
1878 QSize size = newState.rect.size();
1879
1880 if (min.width() > size.width() || min.height() > size.height()) {
1881 restore(true);
1882 return QList<int>();
1883 }
1884
1885 newState.fitLayout();
1886
1887 currentGapRect = newState.gapRect(currentGapPos);
1888
1889#ifndef QT_NO_DOCKWIDGET
1890 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
1891#endif
1892 layoutState = newState;
1893 applyState(layoutState);
1894
1895 updateGapIndicator();
1896
1897 return path;
1898}
1899
1900void QMainWindowLayout::applyState(QMainWindowLayoutState &newState, bool animate)
1901{
1902#ifndef QT_NO_DOCKWIDGET
1903#ifndef QT_NO_TABBAR
1904 QSet<QTabBar*> used = newState.dockAreaLayout.usedTabBars();
1905 QSet<QTabBar*> retired = usedTabBars - used;
1906 usedTabBars = used;
1907 foreach (QTabBar *tab_bar, retired) {
1908 tab_bar->hide();
1909 while (tab_bar->count() > 0)
1910 tab_bar->removeTab(0);
1911 unusedTabBars.append(tab_bar);
1912 }
1913
1914 if (sep == 1) {
1915 QSet<QWidget*> usedSeps = newState.dockAreaLayout.usedSeparatorWidgets();
1916 QSet<QWidget*> retiredSeps = usedSeparatorWidgets - usedSeps;
1917 usedSeparatorWidgets = usedSeps;
1918 foreach (QWidget *sepWidget, retiredSeps) {
1919 unusedSeparatorWidgets.append(sepWidget);
1920 }
1921 }
1922
1923
1924#endif // QT_NO_TABBAR
1925#endif // QT_NO_DOCKWIDGET
1926 newState.apply(dockOptions & QMainWindow::AnimatedDocks && animate);
1927}
1928
1929void QMainWindowLayout::saveState(QDataStream &stream) const
1930{
1931 layoutState.saveState(stream);
1932}
1933
1934bool QMainWindowLayout::restoreState(QDataStream &stream)
1935{
1936 savedState = layoutState;
1937 layoutState.clear();
1938 layoutState.rect = savedState.rect;
1939
1940 if (!layoutState.restoreState(stream, savedState)) {
1941 layoutState.deleteAllLayoutItems();
1942 layoutState = savedState;
1943 if (parentWidget()->isVisible())
1944 applyState(layoutState, false); // hides tabBars allocated by newState
1945 return false;
1946 }
1947
1948 if (parentWidget()->isVisible()) {
1949 layoutState.fitLayout();
1950 applyState(layoutState, false);
1951 }
1952
1953 savedState.deleteAllLayoutItems();
1954 savedState.clear();
1955
1956#ifndef QT_NO_DOCKWIDGET
1957 if (parentWidget()->isVisible()) {
1958#ifndef QT_NO_TABBAR
1959 foreach (QTabBar *tab_bar, usedTabBars)
1960 tab_bar->show();
1961
1962#endif
1963 }
1964#endif // QT_NO_DOCKWIDGET
1965
1966 return true;
1967}
1968
1969
1970// Returns if this toolbar *should* be using HIToolbar. Won't work for all in between cases
1971// for example, you have a toolbar in the top area and then you suddenly turn on
1972// HIToolbar.
1973bool QMainWindowLayout::usesHIToolBar(QToolBar *toolbar) const
1974{
1975#ifndef Q_WS_MAC
1976 Q_UNUSED(toolbar);
1977 return false;
1978#else
1979 return qtoolbarsInUnifiedToolbarList.contains(toolbar)
1980 || ((toolBarArea(toolbar) == Qt::TopToolBarArea)
1981 && layoutState.mainWindow->unifiedTitleAndToolBarOnMac());
1982#endif
1983}
1984
1985QT_END_NAMESPACE
1986
1987#endif // QT_NO_MAINWINDOW
Note: See TracBrowser for help on using the repository browser.