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