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

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

trunk: Merged in qt 4.6.1 sources.

File size: 56.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [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(const QList<int> &path, QLayoutItem *item)
430{
431 if (path.isEmpty())
432 return false;
433
434 int i = path.first();
435
436#ifndef QT_NO_TOOLBAR
437 if (i == 0) {
438 Q_ASSERT(qobject_cast<QToolBar*>(item->widget()) != 0);
439 return toolBarAreaLayout.insertGap(path.mid(1), 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.mid(1), item);
447 }
448#endif //QT_NO_DOCKWIDGET
449
450 return false;
451}
452
453void QMainWindowLayoutState::remove(const QList<int> &path)
454{
455 int i = path.first();
456
457#ifndef QT_NO_TOOLBAR
458 if (i == 0)
459 toolBarAreaLayout.remove(path.mid(1));
460#endif
461
462#ifndef QT_NO_DOCKWIDGET
463 if (i == 1)
464 dockAreaLayout.remove(path.mid(1));
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();
494#endif
495
496 rect = QRect();
497}
498
499bool QMainWindowLayoutState::isValid() const
500{
501 return rect.isValid();
502}
503
504QLayoutItem *QMainWindowLayoutState::item(const QList<int> &path)
505{
506 int i = path.first();
507
508#ifndef QT_NO_TOOLBAR
509 if (i == 0)
510 return toolBarAreaLayout.item(path.mid(1)).widgetItem;
511#endif
512
513#ifndef QT_NO_DOCKWIDGET
514 if (i == 1)
515 return dockAreaLayout.item(path.mid(1)).widgetItem;
516#endif //QT_NO_DOCKWIDGET
517
518 return 0;
519}
520
521QRect QMainWindowLayoutState::itemRect(const QList<int> &path) const
522{
523 int i = path.first();
524
525#ifndef QT_NO_TOOLBAR
526 if (i == 0)
527 return toolBarAreaLayout.itemRect(path.mid(1));
528#endif
529
530#ifndef QT_NO_DOCKWIDGET
531 if (i == 1)
532 return dockAreaLayout.itemRect(path.mid(1));
533#endif //QT_NO_DOCKWIDGET
534
535 return QRect();
536}
537
538QRect QMainWindowLayoutState::gapRect(const QList<int> &path) const
539{
540 int i = path.first();
541
542#ifndef QT_NO_TOOLBAR
543 if (i == 0)
544 return toolBarAreaLayout.itemRect(path.mid(1));
545#endif
546
547#ifndef QT_NO_DOCKWIDGET
548 if (i == 1)
549 return dockAreaLayout.gapRect(path.mid(1));
550#endif //QT_NO_DOCKWIDGET
551
552 return QRect();
553}
554
555QLayoutItem *QMainWindowLayoutState::plug(const QList<int> &path)
556{
557 int i = path.first();
558
559#ifndef QT_NO_TOOLBAR
560 if (i == 0)
561 return toolBarAreaLayout.plug(path.mid(1));
562#endif
563
564#ifndef QT_NO_DOCKWIDGET
565 if (i == 1)
566 return dockAreaLayout.plug(path.mid(1));
567#endif //QT_NO_DOCKWIDGET
568
569 return 0;
570}
571
572QLayoutItem *QMainWindowLayoutState::unplug(const QList<int> &path, QMainWindowLayoutState *other)
573{
574 int i = path.first();
575
576#ifdef QT_NO_TOOLBAR
577 Q_UNUSED(other);
578#else
579 if (i == 0)
580 return toolBarAreaLayout.unplug(path.mid(1), other ? &other->toolBarAreaLayout : 0);
581#endif
582
583#ifndef QT_NO_DOCKWIDGET
584 if (i == 1)
585 return dockAreaLayout.unplug(path.mid(1));
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 bool updateNonUnifiedParts = true;
943#ifdef Q_WS_MAC
944 if (layoutState.mainWindow->unifiedTitleAndToolBarOnMac()) {
945 // If we hit this case, someone has pressed the "toolbar button" which will
946 // toggle the unified toolbar visiblity, because that's what the user wants.
947 // We might be in a situation where someone has hidden all the toolbars
948 // beforehand (maybe in construction), but now they've hit this button and
949 // and are expecting the items to show. What do we do?
950 // 1) Check the visibility of all the toolbars, if one is visible, do nothing, this
951 // preserves what people would expect (these toolbars were visible when I clicked last time).
952 // 2) If NONE are visible, then show them all. Again, this preserves the user expectation
953 // of, "I want to see the toolbars." The user may get more toolbars than expected, but this
954 // is better seeing nothing.
955 // Don't worry about any of this if we are going invisible. This does mean we may get
956 // into issues when switching into and out of fullscreen mode, but this is probably minor.
957 // If we ever need to do hiding, that would have to be taken care of after the unified toolbar
958 // has finished hiding.
959 // People can of course handle the QEvent::ToolBarChange event themselves and do
960 // WHATEVER they want if they don't like what we are doing (though the unified toolbar
961 // will fire regardless).
962
963 // Check if we REALLY need to update the geometry below. If we only have items in the
964 // unified toolbar, all the docks will be empty, so there's very little point
965 // in doing the geometry as Apple will do it (we also avoid flicker in Cocoa as well).
966 // FWIW, layoutState.toolBarAreaLayout.visible and the state of the unified toolbar
967 // visibility can get out of sync. I really don't think it's a big issue. It is kept
968 // to a minimum because we only change the visibility if we absolutely must.
969 // update the "non unified parts."
970 updateNonUnifiedParts = !layoutState.toolBarAreaLayout.isEmpty();
971
972 // We get this function before the unified toolbar does its thing.
973 // So, the value will be opposite of what we expect.
974 bool goingVisible = !macWindowToolbarIsVisible(qt_mac_window_for(layoutState.mainWindow));
975 if (goingVisible) {
976 const int ToolBarCount = qtoolbarsInUnifiedToolbarList.size();
977 bool needAllVisible = true;
978 for (int i = 0; i < ToolBarCount; ++i) {
979 if (!qtoolbarsInUnifiedToolbarList.at(i)->isHidden()) {
980 needAllVisible = false;
981 break;
982 }
983 }
984 if (needAllVisible) {
985 QBoolBlocker blocker(blockVisiblityCheck); // Disable the visibilty check because
986 // the toggle has already happened.
987 for (int i = 0; i < ToolBarCount; ++i)
988 qtoolbarsInUnifiedToolbarList.at(i)->setVisible(true);
989 }
990 }
991 if (!updateNonUnifiedParts)
992 layoutState.toolBarAreaLayout.visible = goingVisible;
993 }
994#endif
995 if (updateNonUnifiedParts) {
996 layoutState.toolBarAreaLayout.visible = !layoutState.toolBarAreaLayout.visible;
997 if (!layoutState.mainWindow->isMaximized()) {
998 QPoint topLeft = parentWidget()->geometry().topLeft();
999 QRect r = parentWidget()->geometry();
1000 r = layoutState.toolBarAreaLayout.rectHint(r);
1001 r.moveTo(topLeft);
1002 parentWidget()->setGeometry(r);
1003 } else {
1004 update();
1005 }
1006 }
1007}
1008
1009#endif // QT_NO_TOOLBAR
1010
1011/******************************************************************************
1012** QMainWindowLayoutState - dock areas
1013*/
1014
1015#ifndef QT_NO_DOCKWIDGET
1016
1017static inline void validateDockWidgetArea(Qt::DockWidgetArea &area)
1018{
1019 switch (area) {
1020 case Qt::LeftDockWidgetArea:
1021 case Qt::RightDockWidgetArea:
1022 case Qt::TopDockWidgetArea:
1023 case Qt::BottomDockWidgetArea:
1024 break;
1025 default:
1026 area = Qt::LeftDockWidgetArea;
1027 }
1028}
1029
1030static QInternal::DockPosition toDockPos(Qt::DockWidgetArea area)
1031{
1032 switch (area) {
1033 case Qt::LeftDockWidgetArea: return QInternal::LeftDock;
1034 case Qt::RightDockWidgetArea: return QInternal::RightDock;
1035 case Qt::TopDockWidgetArea: return QInternal::TopDock;
1036 case Qt::BottomDockWidgetArea: return QInternal::BottomDock;
1037 default:
1038 break;
1039 }
1040
1041 return QInternal::DockCount;
1042}
1043
1044static Qt::DockWidgetArea toDockWidgetArea(QInternal::DockPosition pos)
1045{
1046 switch (pos) {
1047 case QInternal::LeftDock : return Qt::LeftDockWidgetArea;
1048 case QInternal::RightDock : return Qt::RightDockWidgetArea;
1049 case QInternal::TopDock : return Qt::TopDockWidgetArea;
1050 case QInternal::BottomDock : return Qt::BottomDockWidgetArea;
1051 default:
1052 break;
1053 }
1054
1055 return Qt::NoDockWidgetArea;
1056}
1057
1058inline static Qt::DockWidgetArea toDockWidgetArea(int pos)
1059{
1060 return toDockWidgetArea(static_cast<QInternal::DockPosition>(pos));
1061}
1062
1063void QMainWindowLayout::setCorner(Qt::Corner corner, Qt::DockWidgetArea area)
1064{
1065 if (layoutState.dockAreaLayout.corners[corner] == area)
1066 return;
1067 layoutState.dockAreaLayout.corners[corner] = area;
1068 if (savedState.isValid())
1069 savedState.dockAreaLayout.corners[corner] = area;
1070 invalidate();
1071}
1072
1073Qt::DockWidgetArea QMainWindowLayout::corner(Qt::Corner corner) const
1074{
1075 return layoutState.dockAreaLayout.corners[corner];
1076}
1077
1078void QMainWindowLayout::addDockWidget(Qt::DockWidgetArea area,
1079 QDockWidget *dockwidget,
1080 Qt::Orientation orientation)
1081{
1082 addChildWidget(dockwidget);
1083
1084 // If we are currently moving a separator, then we need to abort the move, since each
1085 // time we move the mouse layoutState is replaced by savedState modified by the move.
1086 if (!movingSeparator.isEmpty())
1087 endSeparatorMove(movingSeparatorPos);
1088
1089 layoutState.dockAreaLayout.addDockWidget(toDockPos(area), dockwidget, orientation);
1090 emit dockwidget->dockLocationChanged(area);
1091 invalidate();
1092}
1093
1094void QMainWindowLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
1095{
1096 addChildWidget(second);
1097 layoutState.dockAreaLayout.tabifyDockWidget(first, second);
1098 emit second->dockLocationChanged(dockWidgetArea(first));
1099 invalidate();
1100}
1101
1102bool QMainWindowLayout::restoreDockWidget(QDockWidget *dockwidget)
1103{
1104 addChildWidget(dockwidget);
1105 if (!layoutState.dockAreaLayout.restoreDockWidget(dockwidget))
1106 return false;
1107 emit dockwidget->dockLocationChanged(dockWidgetArea(dockwidget));
1108 invalidate();
1109 return true;
1110}
1111
1112#ifndef QT_NO_TABBAR
1113bool QMainWindowLayout::documentMode() const
1114{
1115 return _documentMode;
1116}
1117
1118void QMainWindowLayout::setDocumentMode(bool enabled)
1119{
1120 if (_documentMode == enabled)
1121 return;
1122
1123 _documentMode = enabled;
1124
1125 // Update the document mode for all tab bars
1126 foreach (QTabBar *bar, usedTabBars)
1127 bar->setDocumentMode(_documentMode);
1128 foreach (QTabBar *bar, unusedTabBars)
1129 bar->setDocumentMode(_documentMode);
1130}
1131#endif // QT_NO_TABBAR
1132
1133void QMainWindowLayout::setVerticalTabsEnabled(bool enabled)
1134{
1135#ifdef QT_NO_TABBAR
1136 Q_UNUSED(enabled);
1137#else
1138 if (verticalTabsEnabled == enabled)
1139 return;
1140
1141 verticalTabsEnabled = enabled;
1142
1143 updateTabBarShapes();
1144#endif // QT_NO_TABBAR
1145}
1146
1147#ifndef QT_NO_TABWIDGET
1148QTabWidget::TabShape QMainWindowLayout::tabShape() const
1149{
1150 return _tabShape;
1151}
1152
1153void QMainWindowLayout::setTabShape(QTabWidget::TabShape tabShape)
1154{
1155 if (_tabShape == tabShape)
1156 return;
1157
1158 _tabShape = tabShape;
1159
1160 updateTabBarShapes();
1161}
1162
1163QTabWidget::TabPosition QMainWindowLayout::tabPosition(Qt::DockWidgetArea area) const
1164{
1165 return tabPositions[toDockPos(area)];
1166}
1167
1168void QMainWindowLayout::setTabPosition(Qt::DockWidgetAreas areas, QTabWidget::TabPosition tabPosition)
1169{
1170 const Qt::DockWidgetArea dockWidgetAreas[] = {
1171 Qt::TopDockWidgetArea,
1172 Qt::LeftDockWidgetArea,
1173 Qt::BottomDockWidgetArea,
1174 Qt::RightDockWidgetArea
1175 };
1176 const QInternal::DockPosition dockPositions[] = {
1177 QInternal::TopDock,
1178 QInternal::LeftDock,
1179 QInternal::BottomDock,
1180 QInternal::RightDock
1181 };
1182
1183 for (int i = 0; i < QInternal::DockCount; ++i)
1184 if (areas & dockWidgetAreas[i])
1185 tabPositions[dockPositions[i]] = tabPosition;
1186
1187 updateTabBarShapes();
1188}
1189
1190static inline QTabBar::Shape tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position)
1191{
1192 const bool rounded = (shape == QTabWidget::Rounded);
1193 if (position == QTabWidget::North)
1194 return rounded ? QTabBar::RoundedNorth : QTabBar::TriangularNorth;
1195 if (position == QTabWidget::South)
1196 return rounded ? QTabBar::RoundedSouth : QTabBar::TriangularSouth;
1197 if (position == QTabWidget::East)
1198 return rounded ? QTabBar::RoundedEast : QTabBar::TriangularEast;
1199 if (position == QTabWidget::West)
1200 return rounded ? QTabBar::RoundedWest : QTabBar::TriangularWest;
1201 return QTabBar::RoundedNorth;
1202}
1203#endif // QT_NO_TABWIDGET
1204
1205#ifndef QT_NO_TABBAR
1206void QMainWindowLayout::updateTabBarShapes()
1207{
1208#ifndef QT_NO_TABWIDGET
1209 const QTabWidget::TabPosition vertical[] = {
1210 QTabWidget::West,
1211 QTabWidget::East,
1212 QTabWidget::North,
1213 QTabWidget::South
1214 };
1215#else
1216 const QTabBar::Shape vertical[] = {
1217 QTabBar::RoundedWest,
1218 QTabBar::RoundedEast,
1219 QTabBar::RoundedNorth,
1220 QTabBar::RoundedSouth
1221 };
1222#endif
1223
1224 QDockAreaLayout &layout = layoutState.dockAreaLayout;
1225
1226 for (int i = 0; i < QInternal::DockCount; ++i) {
1227#ifndef QT_NO_TABWIDGET
1228 QTabWidget::TabPosition pos = verticalTabsEnabled ? vertical[i] : tabPositions[i];
1229 QTabBar::Shape shape = tabBarShapeFrom(_tabShape, pos);
1230#else
1231 QTabBar::Shape shape = verticalTabsEnabled ? vertical[i] : QTabBar::RoundedSouth;
1232#endif
1233 layout.docks[i].setTabBarShape(shape);
1234 }
1235}
1236#endif // QT_NO_TABBAR
1237
1238void QMainWindowLayout::splitDockWidget(QDockWidget *after,
1239 QDockWidget *dockwidget,
1240 Qt::Orientation orientation)
1241{
1242 addChildWidget(dockwidget);
1243 layoutState.dockAreaLayout.splitDockWidget(after, dockwidget, orientation);
1244 emit dockwidget->dockLocationChanged(dockWidgetArea(after));
1245 invalidate();
1246}
1247
1248Qt::DockWidgetArea QMainWindowLayout::dockWidgetArea(QDockWidget *widget) const
1249{
1250 QList<int> pathToWidget = layoutState.dockAreaLayout.indexOf(widget);
1251 if (pathToWidget.isEmpty())
1252 return Qt::NoDockWidgetArea;
1253 return toDockWidgetArea(pathToWidget.first());
1254}
1255
1256void QMainWindowLayout::keepSize(QDockWidget *w)
1257{
1258 layoutState.dockAreaLayout.keepSize(w);
1259}
1260
1261#ifndef QT_NO_TABBAR
1262
1263class QMainWindowTabBar : public QTabBar
1264{
1265public:
1266 QMainWindowTabBar(QWidget *parent);
1267protected:
1268 bool event(QEvent *e);
1269};
1270
1271QMainWindowTabBar::QMainWindowTabBar(QWidget *parent)
1272 : QTabBar(parent)
1273{
1274 setExpanding(false);
1275}
1276
1277bool QMainWindowTabBar::event(QEvent *e)
1278{
1279 // show the tooltip if tab is too small to fit label
1280
1281 if (e->type() != QEvent::ToolTip)
1282 return QTabBar::event(e);
1283 QSize size = this->size();
1284 QSize hint = sizeHint();
1285 if (shape() == QTabBar::RoundedWest || shape() == QTabBar::RoundedEast) {
1286 size.transpose();
1287 hint.transpose();
1288 }
1289 if (size.width() < hint.width())
1290 return QTabBar::event(e);
1291 e->accept();
1292 return true;
1293}
1294
1295QTabBar *QMainWindowLayout::getTabBar()
1296{
1297 QTabBar *result = 0;
1298 if (!unusedTabBars.isEmpty()) {
1299 result = unusedTabBars.takeLast();
1300 } else {
1301 result = new QMainWindowTabBar(parentWidget());
1302 result->setDrawBase(true);
1303 result->setElideMode(Qt::ElideRight);
1304 result->setDocumentMode(_documentMode);
1305 connect(result, SIGNAL(currentChanged(int)), this, SLOT(tabChanged()));
1306 }
1307
1308 usedTabBars.insert(result);
1309 return result;
1310}
1311
1312// Allocates a new separator widget if needed
1313QWidget *QMainWindowLayout::getSeparatorWidget()
1314{
1315 QWidget *result = 0;
1316 if (!unusedSeparatorWidgets.isEmpty()) {
1317 result = unusedSeparatorWidgets.takeLast();
1318 } else {
1319 result = new QWidget(parentWidget());
1320 result->setAttribute(Qt::WA_MouseNoMask, true);
1321 result->setAutoFillBackground(false);
1322 result->setObjectName(QLatin1String("qt_qmainwindow_extended_splitter"));
1323 }
1324 usedSeparatorWidgets.insert(result);
1325 return result;
1326}
1327
1328void QMainWindowLayout::tabChanged()
1329{
1330 QTabBar *tb = qobject_cast<QTabBar*>(sender());
1331 if (tb == 0)
1332 return;
1333 QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(tb);
1334 if (info == 0)
1335 return;
1336 info->apply(false);
1337
1338 if (QWidget *w = centralWidget())
1339 w->raise();
1340}
1341#endif // QT_NO_TABBAR
1342
1343bool QMainWindowLayout::startSeparatorMove(const QPoint &pos)
1344{
1345 movingSeparator = layoutState.dockAreaLayout.findSeparator(pos);
1346
1347 if (movingSeparator.isEmpty())
1348 return false;
1349
1350 savedState = layoutState;
1351 movingSeparatorPos = movingSeparatorOrigin = pos;
1352
1353 return true;
1354}
1355
1356bool QMainWindowLayout::separatorMove(const QPoint &pos)
1357{
1358 if (movingSeparator.isEmpty())
1359 return false;
1360 movingSeparatorPos = pos;
1361 separatorMoveTimer.start(0, this);
1362 return true;
1363}
1364
1365bool QMainWindowLayout::endSeparatorMove(const QPoint&)
1366{
1367 bool result = !movingSeparator.isEmpty();
1368 movingSeparator.clear();
1369 savedState.clear();
1370 return result;
1371}
1372
1373void QMainWindowLayout::raise(QDockWidget *widget)
1374{
1375 QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(widget);
1376 if (info == 0)
1377 return;
1378#ifndef QT_NO_TABBAR
1379 if (!info->tabbed)
1380 return;
1381 info->setCurrentTab(widget);
1382#endif
1383}
1384
1385#endif // QT_NO_DOCKWIDGET
1386
1387
1388/******************************************************************************
1389** QMainWindowLayoutState - layout interface
1390*/
1391
1392int QMainWindowLayout::count() const
1393{
1394 qWarning("QMainWindowLayout::count: ?");
1395 return 0; //#################################################
1396}
1397
1398QLayoutItem *QMainWindowLayout::itemAt(int index) const
1399{
1400 int x = 0;
1401
1402 if (QLayoutItem *ret = layoutState.itemAt(index, &x))
1403 return ret;
1404
1405 if (statusbar && x++ == index)
1406 return statusbar;
1407
1408 return 0;
1409}
1410
1411QLayoutItem *QMainWindowLayout::takeAt(int index)
1412{
1413 int x = 0;
1414
1415 if (QLayoutItem *ret = layoutState.takeAt(index, &x)) {
1416 // the widget might in fact have been destroyed by now
1417 if (QWidget *w = ret->widget()) {
1418 widgetAnimator.abort(w);
1419 if (w == pluggingWidget)
1420 pluggingWidget = 0;
1421 }
1422
1423 if (savedState.isValid() ) {
1424 //we need to remove the item also from the saved state to prevent crash
1425 savedState.remove(ret);
1426 //Also, the item may be contained several times as a gap item.
1427 layoutState.remove(ret);
1428 }
1429
1430#ifndef QT_NO_TOOLBAR
1431 if (!currentGapPos.isEmpty() && currentGapPos.first() == 0) {
1432 currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex();
1433 if (!currentGapPos.isEmpty()) {
1434 currentGapPos.prepend(0);
1435 currentGapRect = layoutState.itemRect(currentGapPos);
1436 }
1437 }
1438#endif
1439
1440 return ret;
1441 }
1442
1443 if (statusbar && x++ == index) {
1444 QLayoutItem *ret = statusbar;
1445 statusbar = 0;
1446 return ret;
1447 }
1448
1449 return 0;
1450}
1451
1452void QMainWindowLayout::setGeometry(const QRect &_r)
1453{
1454 if (savedState.isValid())
1455 return;
1456
1457 QRect r = _r;
1458
1459 QLayout::setGeometry(r);
1460
1461 if (statusbar) {
1462 QRect sbr(QPoint(0, 0),
1463 QSize(r.width(), statusbar->heightForWidth(r.width()))
1464 .expandedTo(statusbar->minimumSize()));
1465 sbr.moveBottom(r.bottom());
1466 QRect vr = QStyle::visualRect(parentWidget()->layoutDirection(), _r, sbr);
1467 statusbar->setGeometry(vr);
1468 r.setBottom(sbr.top() - 1);
1469 }
1470
1471 layoutState.rect = r;
1472 layoutState.fitLayout();
1473 applyState(layoutState, false);
1474}
1475
1476void QMainWindowLayout::addItem(QLayoutItem *)
1477{ qWarning("QMainWindowLayout::addItem: Please use the public QMainWindow API instead"); }
1478
1479QSize QMainWindowLayout::sizeHint() const
1480{
1481 if (!szHint.isValid()) {
1482 szHint = layoutState.sizeHint();
1483 const QSize sbHint = statusbar ? statusbar->sizeHint() : QSize(0, 0);
1484 szHint = QSize(qMax(sbHint.width(), szHint.width()),
1485 sbHint.height() + szHint.height());
1486 }
1487 return szHint;
1488}
1489
1490QSize QMainWindowLayout::minimumSize() const
1491{
1492 if (!minSize.isValid()) {
1493 minSize = layoutState.minimumSize();
1494 const QSize sbMin = statusbar ? statusbar->minimumSize() : QSize(0, 0);
1495 minSize = QSize(qMax(sbMin.width(), minSize.width()),
1496 sbMin.height() + minSize.height());
1497#ifdef Q_WS_MAC
1498 const QSize storedSize = minSize;
1499 int minWidth = 0;
1500 foreach (QToolBar *toolbar, qtoolbarsInUnifiedToolbarList) {
1501 minWidth += toolbar->sizeHint().width() + 20;
1502 }
1503 minSize = QSize(qMax(minWidth, storedSize.width()), storedSize.height());
1504#endif
1505 }
1506 return minSize;
1507}
1508
1509void QMainWindowLayout::invalidate()
1510{
1511 QLayout::invalidate();
1512 minSize = szHint = QSize();
1513}
1514
1515/******************************************************************************
1516** QMainWindowLayout - remaining stuff
1517*/
1518
1519static void fixToolBarOrientation(QLayoutItem *item, int dockPos)
1520{
1521#ifndef QT_NO_TOOLBAR
1522 QToolBar *toolBar = qobject_cast<QToolBar*>(item->widget());
1523 if (toolBar == 0)
1524 return;
1525
1526 QRect oldGeo = toolBar->geometry();
1527
1528 QInternal::DockPosition pos
1529 = static_cast<QInternal::DockPosition>(dockPos);
1530 Qt::Orientation o = pos == QInternal::TopDock || pos == QInternal::BottomDock
1531 ? Qt::Horizontal : Qt::Vertical;
1532 if (o != toolBar->orientation())
1533 toolBar->setOrientation(o);
1534
1535 QSize hint = toolBar->sizeHint().boundedTo(toolBar->maximumSize())
1536 .expandedTo(toolBar->minimumSize());
1537
1538 if (toolBar->size() != hint) {
1539 QRect newGeo(oldGeo.topLeft(), hint);
1540 if (toolBar->layoutDirection() == Qt::RightToLeft)
1541 newGeo.moveRight(oldGeo.right());
1542 toolBar->setGeometry(newGeo);
1543 }
1544
1545#else
1546 Q_UNUSED(item);
1547 Q_UNUSED(dockPos);
1548#endif
1549}
1550
1551void QMainWindowLayout::revert(QLayoutItem *widgetItem)
1552{
1553 if (!savedState.isValid())
1554 return;
1555
1556 QWidget *widget = widgetItem->widget();
1557 layoutState = savedState;
1558 currentGapPos = layoutState.indexOf(widget);
1559 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
1560 layoutState.unplug(currentGapPos);
1561 layoutState.fitLayout();
1562 currentGapRect = layoutState.itemRect(currentGapPos);
1563
1564 plug(widgetItem);
1565}
1566
1567bool QMainWindowLayout::plug(QLayoutItem *widgetItem)
1568{
1569 if (!parentWidget()->isVisible() || parentWidget()->isMinimized() || currentGapPos.isEmpty())
1570 return false;
1571
1572 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
1573
1574 QWidget *widget = widgetItem->widget();
1575
1576 QList<int> previousPath = layoutState.indexOf(widget);
1577
1578 QLayoutItem *it = layoutState.plug(currentGapPos);
1579 Q_ASSERT(it == widgetItem);
1580 Q_UNUSED(it);
1581 if (!previousPath.isEmpty())
1582 layoutState.remove(previousPath);
1583
1584 pluggingWidget = widget;
1585 QRect globalRect = currentGapRect;
1586 globalRect.moveTopLeft(parentWidget()->mapToGlobal(globalRect.topLeft()));
1587#ifndef QT_NO_DOCKWIDGET
1588 if (qobject_cast<QDockWidget*>(widget) != 0) {
1589 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(widget->layout());
1590 if (layout->nativeWindowDeco()) {
1591 globalRect.adjust(0, layout->titleHeight(), 0, 0);
1592 } else {
1593 int fw = widget->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, widget);
1594 globalRect.adjust(-fw, -fw, fw, fw);
1595 }
1596 }
1597#endif
1598 widgetAnimator.animate(widget, globalRect, dockOptions & QMainWindow::AnimatedDocks);
1599
1600 return true;
1601}
1602
1603void QMainWindowLayout::animationFinished(QWidget *widget)
1604{
1605 //this function is called from within the Widget Animator whenever an animation is finished
1606 //on a certain widget
1607#ifndef QT_NO_TOOLBAR
1608 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
1609 QToolBarLayout *tbl = qobject_cast<QToolBarLayout*>(tb->layout());
1610 if (tbl->animating) {
1611 tbl->animating = false;
1612 if (tbl->expanded)
1613 tbl->layoutActions(tb->size());
1614 tb->update();
1615 }
1616 }
1617#endif
1618
1619 if (widget == pluggingWidget) {
1620
1621#ifndef QT_NO_DOCKWIDGET
1622 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget))
1623 dw->d_func()->plug(currentGapRect);
1624#endif
1625#ifndef QT_NO_TOOLBAR
1626 if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
1627 tb->d_func()->plug(currentGapRect);
1628#endif
1629
1630#ifndef QT_NO_DOCKWIDGET
1631#ifndef QT_NO_TABBAR
1632 if (qobject_cast<QDockWidget*>(widget) != 0) {
1633 // info() might return null if the widget is destroyed while
1634 // animating but before the animationFinished signal is received.
1635 if (QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(widget))
1636 info->setCurrentTab(widget);
1637 }
1638#endif
1639#endif
1640
1641 savedState.clear();
1642 currentGapPos.clear();
1643 pluggingWidget = 0;
1644 //applying the state will make sure that the currentGap is updated correctly
1645 //and all the geometries (especially the one from the central widget) is correct
1646 layoutState.apply(false);
1647 }
1648
1649 if (!widgetAnimator.animating()) {
1650 //all animations are finished
1651#ifndef QT_NO_DOCKWIDGET
1652 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
1653#ifndef QT_NO_TABBAR
1654 foreach (QTabBar *tab_bar, usedTabBars)
1655 tab_bar->show();
1656#endif // QT_NO_TABBAR
1657#endif // QT_NO_DOCKWIDGET
1658 }
1659
1660 updateGapIndicator();
1661}
1662
1663void QMainWindowLayout::restore(bool keepSavedState)
1664{
1665 if (!savedState.isValid())
1666 return;
1667
1668 layoutState = savedState;
1669 applyState(layoutState);
1670 if (!keepSavedState)
1671 savedState.clear();
1672 currentGapPos.clear();
1673 pluggingWidget = 0;
1674 updateGapIndicator();
1675}
1676
1677QMainWindowLayout::QMainWindowLayout(QMainWindow *mainwindow)
1678 : QLayout(mainwindow)
1679 , layoutState(mainwindow)
1680 , savedState(mainwindow)
1681 , dockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowTabbedDocks)
1682 , statusbar(0)
1683#ifndef QT_NO_DOCKWIDGET
1684#ifndef QT_NO_TABBAR
1685 , _documentMode(false)
1686 , verticalTabsEnabled(false)
1687#ifndef QT_NO_TABWIDGET
1688 , _tabShape(QTabWidget::Rounded)
1689#endif
1690#endif
1691#endif // QT_NO_DOCKWIDGET
1692 , widgetAnimator(this)
1693 , pluggingWidget(0)
1694#ifndef QT_NO_RUBBERBAND
1695 , gapIndicator(new QRubberBand(QRubberBand::Rectangle, mainwindow))
1696#endif //QT_NO_RUBBERBAND
1697#ifdef Q_WS_MAC
1698 , blockVisiblityCheck(false)
1699#endif
1700{
1701#ifndef QT_NO_DOCKWIDGET
1702#ifndef QT_NO_TABBAR
1703 sep = mainwindow->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent, 0, mainwindow);
1704#endif
1705
1706#ifndef QT_NO_TABWIDGET
1707 for (int i = 0; i < QInternal::DockCount; ++i)
1708 tabPositions[i] = QTabWidget::South;
1709#endif
1710#endif // QT_NO_DOCKWIDGET
1711
1712#ifndef QT_NO_RUBBERBAND
1713 // For accessibility to identify this special widget.
1714 gapIndicator->setObjectName(QLatin1String("qt_rubberband"));
1715 gapIndicator->hide();
1716#endif
1717 pluggingWidget = 0;
1718
1719 setObjectName(mainwindow->objectName() + QLatin1String("_layout"));
1720}
1721
1722QMainWindowLayout::~QMainWindowLayout()
1723{
1724 layoutState.deleteAllLayoutItems();
1725 layoutState.deleteCentralWidgetItem();
1726
1727#ifdef Q_WS_MAC
1728 cleanUpMacToolbarItems();
1729#endif
1730
1731 delete statusbar;
1732}
1733
1734void QMainWindowLayout::setDockOptions(QMainWindow::DockOptions opts)
1735{
1736 if (opts == dockOptions)
1737 return;
1738
1739 dockOptions = opts;
1740
1741#ifndef QT_NO_DOCKWIDGET
1742 setVerticalTabsEnabled(opts & QMainWindow::VerticalTabs);
1743#endif
1744
1745 invalidate();
1746}
1747
1748#ifndef QT_NO_STATUSBAR
1749QStatusBar *QMainWindowLayout::statusBar() const
1750{ return statusbar ? qobject_cast<QStatusBar *>(statusbar->widget()) : 0; }
1751
1752void QMainWindowLayout::setStatusBar(QStatusBar *sb)
1753{
1754 if (sb)
1755 addChildWidget(sb);
1756 delete statusbar;
1757 statusbar = sb ? new QWidgetItemV2(sb) : 0;
1758 invalidate();
1759}
1760#endif // QT_NO_STATUSBAR
1761
1762QWidget *QMainWindowLayout::centralWidget() const
1763{
1764 return layoutState.centralWidget();
1765}
1766
1767void QMainWindowLayout::setCentralWidget(QWidget *widget)
1768{
1769 if (widget != 0)
1770 addChildWidget(widget);
1771 layoutState.setCentralWidget(widget);
1772 if (savedState.isValid()) {
1773#ifndef QT_NO_DOCKWIDGET
1774 savedState.dockAreaLayout.centralWidgetItem = layoutState.dockAreaLayout.centralWidgetItem;
1775#else
1776 savedState.centralWidgetItem = layoutState.centralWidgetItem;
1777#endif
1778 }
1779 invalidate();
1780}
1781
1782QLayoutItem *QMainWindowLayout::unplug(QWidget *widget)
1783{
1784 QList<int> path = layoutState.indexOf(widget);
1785 if (path.isEmpty())
1786 return 0;
1787
1788 QLayoutItem *item = layoutState.item(path);
1789 if (widget->isWindow())
1790 return item;
1791
1792 QRect r = layoutState.itemRect(path);
1793 savedState = layoutState;
1794
1795#ifndef QT_NO_DOCKWIDGET
1796 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) {
1797 dw->d_func()->unplug(r);
1798 }
1799#endif
1800#ifndef QT_NO_TOOLBAR
1801 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
1802 tb->d_func()->unplug(r);
1803 }
1804#endif
1805
1806
1807 layoutState.unplug(path ,&savedState);
1808 savedState.fitLayout();
1809 currentGapPos = path;
1810 currentGapRect = r;
1811 updateGapIndicator();
1812
1813 fixToolBarOrientation(item, currentGapPos.at(1));
1814
1815 return item;
1816}
1817
1818void QMainWindowLayout::updateGapIndicator()
1819{
1820#ifndef QT_NO_RUBBERBAND
1821 gapIndicator->setVisible(!widgetAnimator.animating() && !currentGapPos.isEmpty());
1822 gapIndicator->setGeometry(currentGapRect);
1823#endif
1824}
1825
1826QList<int> QMainWindowLayout::hover(QLayoutItem *widgetItem, const QPoint &mousePos)
1827{
1828 if (!parentWidget()->isVisible() || parentWidget()->isMinimized()
1829 || pluggingWidget != 0 || widgetItem == 0)
1830 return QList<int>();
1831
1832 QWidget *widget = widgetItem->widget();
1833 QPoint pos = parentWidget()->mapFromGlobal(mousePos);
1834
1835 if (!savedState.isValid())
1836 savedState = layoutState;
1837
1838 QList<int> path = savedState.gapIndex(widget, pos);
1839
1840 if (!path.isEmpty()) {
1841 bool allowed = false;
1842
1843#ifndef QT_NO_DOCKWIDGET
1844 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget))
1845 allowed = dw->isAreaAllowed(toDockWidgetArea(path.at(1)));
1846#endif
1847#ifndef QT_NO_TOOLBAR
1848 if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
1849 allowed = tb->isAreaAllowed(toToolBarArea(path.at(1)));
1850#endif
1851
1852 if (!allowed)
1853 path.clear();
1854 }
1855
1856 if (path == currentGapPos)
1857 return currentGapPos; // the gap is already there
1858
1859 currentGapPos = path;
1860 if (path.isEmpty()) {
1861 fixToolBarOrientation(widgetItem, 2); // 2 = top dock, ie. horizontal
1862 restore(true);
1863 return QList<int>();
1864 }
1865
1866 fixToolBarOrientation(widgetItem, currentGapPos.at(1));
1867
1868 QMainWindowLayoutState newState = savedState;
1869
1870 if (!newState.insertGap(path, widgetItem)) {
1871 restore(true); // not enough space
1872 return QList<int>();
1873 }
1874
1875 QSize min = newState.minimumSize();
1876 QSize size = newState.rect.size();
1877
1878 if (min.width() > size.width() || min.height() > size.height()) {
1879 restore(true);
1880 return QList<int>();
1881 }
1882
1883 newState.fitLayout();
1884
1885 currentGapRect = newState.gapRect(currentGapPos);
1886
1887#ifndef QT_NO_DOCKWIDGET
1888 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
1889#endif
1890 layoutState = newState;
1891 applyState(layoutState);
1892
1893 updateGapIndicator();
1894
1895 return path;
1896}
1897
1898void QMainWindowLayout::applyState(QMainWindowLayoutState &newState, bool animate)
1899{
1900#ifndef QT_NO_DOCKWIDGET
1901#ifndef QT_NO_TABBAR
1902 QSet<QTabBar*> used = newState.dockAreaLayout.usedTabBars();
1903 QSet<QTabBar*> retired = usedTabBars - used;
1904 usedTabBars = used;
1905 foreach (QTabBar *tab_bar, retired) {
1906 tab_bar->hide();
1907 while (tab_bar->count() > 0)
1908 tab_bar->removeTab(0);
1909 unusedTabBars.append(tab_bar);
1910 }
1911
1912 if (sep == 1) {
1913 QSet<QWidget*> usedSeps = newState.dockAreaLayout.usedSeparatorWidgets();
1914 QSet<QWidget*> retiredSeps = usedSeparatorWidgets - usedSeps;
1915 usedSeparatorWidgets = usedSeps;
1916 foreach (QWidget *sepWidget, retiredSeps) {
1917 unusedSeparatorWidgets.append(sepWidget);
1918 }
1919 }
1920
1921
1922#endif // QT_NO_TABBAR
1923#endif // QT_NO_DOCKWIDGET
1924 newState.apply(dockOptions & QMainWindow::AnimatedDocks && animate);
1925}
1926
1927void QMainWindowLayout::saveState(QDataStream &stream) const
1928{
1929 layoutState.saveState(stream);
1930}
1931
1932bool QMainWindowLayout::restoreState(QDataStream &stream)
1933{
1934 savedState = layoutState;
1935 layoutState.clear();
1936 layoutState.rect = savedState.rect;
1937
1938 if (!layoutState.restoreState(stream, savedState)) {
1939 layoutState.deleteAllLayoutItems();
1940 layoutState = savedState;
1941 if (parentWidget()->isVisible())
1942 applyState(layoutState, false); // hides tabBars allocated by newState
1943 return false;
1944 }
1945
1946 if (parentWidget()->isVisible()) {
1947 layoutState.fitLayout();
1948 applyState(layoutState, false);
1949 }
1950
1951 savedState.deleteAllLayoutItems();
1952 savedState.clear();
1953
1954#ifndef QT_NO_DOCKWIDGET
1955 if (parentWidget()->isVisible()) {
1956#ifndef QT_NO_TABBAR
1957 foreach (QTabBar *tab_bar, usedTabBars)
1958 tab_bar->show();
1959
1960#endif
1961 }
1962#endif // QT_NO_DOCKWIDGET
1963
1964 return true;
1965}
1966
1967
1968// Returns if this toolbar *should* be using HIToolbar. Won't work for all in between cases
1969// for example, you have a toolbar in the top area and then you suddenly turn on
1970// HIToolbar.
1971bool QMainWindowLayout::usesHIToolBar(QToolBar *toolbar) const
1972{
1973#ifndef Q_WS_MAC
1974 Q_UNUSED(toolbar);
1975 return false;
1976#else
1977 return qtoolbarsInUnifiedToolbarList.contains(toolbar)
1978 || ((toolBarArea(toolbar) == Qt::TopToolBarArea)
1979 && layoutState.mainWindow->unifiedTitleAndToolBarOnMac());
1980#endif
1981}
1982
1983void QMainWindowLayout::timerEvent(QTimerEvent *e)
1984{
1985#ifndef QT_NO_DOCKWIDGET
1986 if (e->timerId() == separatorMoveTimer.timerId()) {
1987 //let's move the separators
1988 separatorMoveTimer.stop();
1989 if (movingSeparator.isEmpty())
1990 return;
1991 if (movingSeparatorOrigin == movingSeparatorPos)
1992 return;
1993
1994 //when moving the separator, we need to update the previous position
1995 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
1996
1997 layoutState = savedState;
1998 layoutState.dockAreaLayout.separatorMove(movingSeparator, movingSeparatorOrigin,
1999 movingSeparatorPos);
2000 movingSeparatorPos = movingSeparatorOrigin;
2001 }
2002#endif
2003 QLayout::timerEvent(e);
2004}
2005
2006
2007QT_END_NAMESPACE
2008
2009#endif // QT_NO_MAINWINDOW
Note: See TracBrowser for help on using the repository browser.