1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets 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 https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include <QWidgetItem>
41 #include <QToolBar>
42 #include <QStyleOption>
43 #include <QApplication>
44 #include <qdebug.h>
45 
46 #include "qtoolbararealayout_p.h"
47 #include "qmainwindowlayout_p.h"
48 #include "qwidgetanimator_p.h"
49 #include "qtoolbarlayout_p.h"
50 #include "qtoolbar_p.h"
51 
52 /******************************************************************************
53 ** QToolBarAreaLayoutItem
54 */
55 
56 QT_BEGIN_NAMESPACE
57 
58 // qmainwindow.cpp
59 extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *mainWindow);
60 
minimumSize() const61 QSize QToolBarAreaLayoutItem::minimumSize() const
62 {
63     if (skip())
64         return QSize(0, 0);
65     return qSmartMinSize(static_cast<QWidgetItem*>(widgetItem));
66 }
67 
sizeHint() const68 QSize QToolBarAreaLayoutItem::sizeHint() const
69 {
70     if (skip())
71         return QSize(0, 0);
72 
73     return realSizeHint();
74 }
75 
76 //returns the real size hint not taking into account the visibility of the widget
realSizeHint() const77 QSize QToolBarAreaLayoutItem::realSizeHint() const
78 {
79     QWidget *wid = widgetItem->widget();
80     QSize s = wid->sizeHint().expandedTo(wid->minimumSizeHint());
81     if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored)
82         s.setWidth(0);
83     if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored)
84         s.setHeight(0);
85     s = s.boundedTo(wid->maximumSize())
86         .expandedTo(wid->minimumSize());
87     return s;
88 }
89 
skip() const90 bool QToolBarAreaLayoutItem::skip() const
91 {
92     if (gap)
93         return false;
94     return widgetItem == nullptr || widgetItem->isEmpty();
95 }
96 
97 /******************************************************************************
98 ** QToolBarAreaLayoutLine
99 */
100 
QToolBarAreaLayoutLine(Qt::Orientation orientation)101 QToolBarAreaLayoutLine::QToolBarAreaLayoutLine(Qt::Orientation orientation)
102     : o(orientation)
103 {
104 }
105 
sizeHint() const106 QSize QToolBarAreaLayoutLine::sizeHint() const
107 {
108     int a = 0, b = 0;
109     for (int i = 0; i < toolBarItems.count(); ++i) {
110         const QToolBarAreaLayoutItem &item = toolBarItems.at(i);
111         if (item.skip())
112             continue;
113 
114         QSize sh = item.sizeHint();
115         a += item.preferredSize > 0 ? item.preferredSize : pick(o, sh);
116         b = qMax(b, perp(o, sh));
117     }
118 
119     QSize result;
120     rpick(o, result) = a;
121     rperp(o, result) = b;
122 
123     return result;
124 }
125 
minimumSize() const126 QSize QToolBarAreaLayoutLine::minimumSize() const
127 {
128     int a = 0, b = 0;
129     for (int i = 0; i < toolBarItems.count(); ++i) {
130         const QToolBarAreaLayoutItem &item = toolBarItems[i];
131         if (item.skip())
132             continue;
133 
134         QSize ms = item.minimumSize();
135         a += pick(o, ms);
136         b = qMax(b, perp(o, ms));
137     }
138 
139     QSize result;
140     rpick(o, result) = a;
141     rperp(o, result) = b;
142 
143     return result;
144 }
145 
fitLayout()146 void QToolBarAreaLayoutLine::fitLayout()
147 {
148     int last = -1;
149     int min = pick(o, minimumSize());
150     int space = pick(o, rect.size());
151     int extra = qMax(0, space - min);
152 
153     for (int i = 0; i < toolBarItems.count(); ++i) {
154         QToolBarAreaLayoutItem &item = toolBarItems[i];
155         if (item.skip())
156             continue;
157 
158         if (QToolBarLayout *tblayout = qobject_cast<QToolBarLayout*>(item.widgetItem->widget()->layout()))
159             tblayout->checkUsePopupMenu();
160 
161         const int itemMin = pick(o, item.minimumSize());
162         //preferredSize is the default if it is set, otherwise, we take the sizehint
163         item.size = item.preferredSize > 0 ? item.preferredSize : pick(o, item.sizeHint());
164 
165         //the extraspace is the space above the item minimum sizehint
166         const int extraSpace = qMin(item.size - itemMin, extra);
167         item.size = itemMin + extraSpace; //that is the real size
168 
169         extra -= extraSpace;
170 
171         last = i;
172     }
173 
174     // calculate the positions from the sizes
175     int pos = 0;
176     for (int i = 0; i < toolBarItems.count(); ++i) {
177         QToolBarAreaLayoutItem &item = toolBarItems[i];
178         if (item.skip())
179             continue;
180 
181         item.pos = pos;
182         if (i == last) // stretch the last item to the end of the line
183             item.size = qMax(0, pick(o, rect.size()) - item.pos);
184         pos += item.size;
185     }
186 }
187 
skip() const188 bool QToolBarAreaLayoutLine::skip() const
189 {
190     for (int i = 0; i < toolBarItems.count(); ++i) {
191         if (!toolBarItems.at(i).skip())
192             return false;
193     }
194     return true;
195 }
196 
197 /******************************************************************************
198 ** QToolBarAreaLayoutInfo
199 */
200 
QToolBarAreaLayoutInfo(QInternal::DockPosition pos)201 QToolBarAreaLayoutInfo::QToolBarAreaLayoutInfo(QInternal::DockPosition pos)
202     : dockPos(pos), dirty(false)
203 {
204     switch (pos) {
205         case QInternal::LeftDock:
206         case QInternal::RightDock:
207             o = Qt::Vertical;
208             break;
209         case QInternal::TopDock:
210         case QInternal::BottomDock:
211             o = Qt::Horizontal;
212             break;
213         default:
214             o = Qt::Horizontal;
215             break;
216     }
217 }
218 
sizeHint() const219 QSize QToolBarAreaLayoutInfo::sizeHint() const
220 {
221     int a = 0, b = 0;
222     for (int i = 0; i < lines.count(); ++i) {
223         const QToolBarAreaLayoutLine &l = lines.at(i);
224         if (l.skip())
225             continue;
226 
227         QSize hint = l.sizeHint();
228         a = qMax(a, pick(o, hint));
229         b += perp(o, hint);
230     }
231 
232     QSize result;
233     rpick(o, result) = a;
234     rperp(o, result) = b;
235 
236     return result;
237 }
238 
minimumSize() const239 QSize QToolBarAreaLayoutInfo::minimumSize() const
240 {
241     int a = 0, b = 0;
242     for (int i = 0; i < lines.count(); ++i) {
243         const QToolBarAreaLayoutLine &l = lines.at(i);
244         if (l.skip())
245             continue;
246 
247         QSize m = l.minimumSize();
248         a = qMax(a, pick(o, m));
249         b += perp(o, m);
250     }
251 
252     QSize result;
253     rpick(o, result) = a;
254     rperp(o, result) = b;
255 
256     return result;
257 }
258 
fitLayout()259 void QToolBarAreaLayoutInfo::fitLayout()
260 {
261     dirty = false;
262 
263     int b = 0;
264 
265     bool reverse = dockPos == QInternal::RightDock || dockPos == QInternal::BottomDock;
266 
267     int i = reverse ? lines.count() - 1 : 0;
268     for (;;) {
269         if ((reverse && i < 0) || (!reverse && i == lines.count()))
270             break;
271 
272         QToolBarAreaLayoutLine &l = lines[i];
273         if (!l.skip()) {
274             if (o == Qt::Horizontal) {
275                 l.rect.setLeft(rect.left());
276                 l.rect.setRight(rect.right());
277                 l.rect.setTop(b + rect.top());
278                 b += l.sizeHint().height();
279                 l.rect.setBottom(b - 1 + rect.top());
280             } else {
281                 l.rect.setTop(rect.top());
282                 l.rect.setBottom(rect.bottom());
283                 l.rect.setLeft(b + rect.left());
284                 b += l.sizeHint().width();
285                 l.rect.setRight(b - 1 + rect.left());
286             }
287 
288             l.fitLayout();
289         }
290 
291         i += reverse ? -1 : 1;
292     }
293 }
294 
insertToolBar(QToolBar * before,QToolBar * toolBar)295 QLayoutItem *QToolBarAreaLayoutInfo::insertToolBar(QToolBar *before, QToolBar *toolBar)
296 {
297     toolBar->setOrientation(o);
298     QLayoutItem *item = new QWidgetItemV2(toolBar);
299     insertItem(before, item);
300     return item;
301 }
302 
insertItem(QToolBar * before,QLayoutItem * item)303 void QToolBarAreaLayoutInfo::insertItem(QToolBar *before, QLayoutItem *item)
304 {
305     if (before == nullptr) {
306         if (lines.isEmpty())
307             lines.append(QToolBarAreaLayoutLine(o));
308         lines.last().toolBarItems.append(item);
309         return;
310     }
311 
312     for (int j = 0; j < lines.count(); ++j) {
313         QToolBarAreaLayoutLine &line = lines[j];
314 
315         for (int k = 0; k < line.toolBarItems.count(); ++k) {
316             if (line.toolBarItems.at(k).widgetItem->widget() == before) {
317                 line.toolBarItems.insert(k, item);
318                 return;
319             }
320         }
321     }
322 }
323 
removeToolBar(QToolBar * toolBar)324 void QToolBarAreaLayoutInfo::removeToolBar(QToolBar *toolBar)
325 {
326     for (int j = 0; j < lines.count(); ++j) {
327         QToolBarAreaLayoutLine &line = lines[j];
328 
329         for (int k = 0; k < line.toolBarItems.count(); ++k) {
330             QToolBarAreaLayoutItem &item = line.toolBarItems[k];
331             if (item.widgetItem->widget() == toolBar) {
332                 delete item.widgetItem;
333                 item.widgetItem = nullptr;
334                 line.toolBarItems.removeAt(k);
335 
336                 if (line.toolBarItems.isEmpty() && j < lines.count() - 1)
337                     lines.removeAt(j);
338 
339                 return;
340             }
341         }
342     }
343 }
344 
insertToolBarBreak(QToolBar * before)345 void QToolBarAreaLayoutInfo::insertToolBarBreak(QToolBar *before)
346 {
347     if (before == nullptr) {
348         if (!lines.isEmpty() && lines.constLast().toolBarItems.isEmpty())
349             return;
350         lines.append(QToolBarAreaLayoutLine(o));
351         return;
352     }
353 
354     for (int j = 0; j < lines.count(); ++j) {
355         QToolBarAreaLayoutLine &line = lines[j];
356 
357         for (int k = 0; k < line.toolBarItems.count(); ++k) {
358             if (line.toolBarItems.at(k).widgetItem->widget() == before) {
359                 if (k == 0)
360                     return;
361 
362                 QToolBarAreaLayoutLine newLine(o);
363                 newLine.toolBarItems = line.toolBarItems.mid(k);
364                 line.toolBarItems = line.toolBarItems.mid(0, k);
365                 lines.insert(j + 1, newLine);
366 
367                 return;
368             }
369         }
370     }
371 }
372 
removeToolBarBreak(QToolBar * before)373 void QToolBarAreaLayoutInfo::removeToolBarBreak(QToolBar *before)
374 {
375     for (int j = 0; j < lines.count(); ++j) {
376         const QToolBarAreaLayoutLine &line = lines.at(j);
377 
378         for (int k = 0; k < line.toolBarItems.count(); ++k) {
379             if (line.toolBarItems.at(k).widgetItem->widget() == before) {
380                 if (k != 0)
381                     return;
382                 if (j == 0)
383                     return;
384 
385                 lines[j - 1].toolBarItems += lines[j].toolBarItems;
386                 lines.removeAt(j);
387 
388                 return;
389             }
390         }
391     }
392 }
393 
moveToolBar(QToolBar * toolbar,int pos)394 void QToolBarAreaLayoutInfo::moveToolBar(QToolBar *toolbar, int pos)
395 {
396     if (dirty)
397         fitLayout();
398 
399     dirty = true;
400 
401     if (o == Qt::Vertical)
402         pos -= rect.top();
403 
404     //here we actually update the preferredSize for the line containing the toolbar so that we move it
405     for (int j = 0; j < lines.count(); ++j) {
406         QToolBarAreaLayoutLine &line = lines[j];
407 
408         int previousIndex = -1;
409         int minPos = 0;
410         for (int k = 0; k < line.toolBarItems.count(); ++k) {
411             QToolBarAreaLayoutItem &current = line.toolBarItems[k];
412             if (current.widgetItem->widget() == toolbar) {
413                 int newPos = current.pos;
414 
415                 if (previousIndex >= 0) {
416                     QToolBarAreaLayoutItem &previous = line.toolBarItems[previousIndex];
417                     if (pos < current.pos) {
418                         newPos = qMax(pos, minPos);
419                     } else {
420                         //we check the max value for the position (until everything at the right is "compressed")
421                         int maxPos = pick(o, rect.size());
422                         for(int l = k; l < line.toolBarItems.count(); ++l) {
423                             const QToolBarAreaLayoutItem &item = line.toolBarItems.at(l);
424                             if (!item.skip()) {
425                                 maxPos -= pick(o, item.minimumSize());
426                             }
427                         }
428                         newPos = qMin(pos, maxPos);
429                     }
430 
431                     //extra is the number of pixels to add to the previous toolbar
432                     int extra = newPos - current.pos;
433 
434                     //we check if the previous is near its size hint
435                     //in which case we try to stick to it
436                     const int diff = pick(o, previous.sizeHint()) - (previous.size + extra);
437                     if (qAbs(diff) < QApplication::startDragDistance()) {
438                         //we stick to the default place and size
439                         extra += diff;
440                     }
441 
442                     //update for the current item
443                     current.extendSize(line.o, -extra);
444 
445                     if (extra >= 0) {
446                         previous.extendSize(line.o, extra);
447                     } else {
448                         //we need to push the toolbars on the left starting with previous
449                         extra = -extra; // we just need to know the number of pixels
450                         ///at this point we need to get extra pixels from the toolbars at the left
451                         for(int l = previousIndex; l >=0; --l) {
452                             QToolBarAreaLayoutItem &item = line.toolBarItems[l];
453                             if (!item.skip()) {
454                                 const int minPreferredSize = pick(o, item.minimumSize());
455                                 const int margin =  item.size - minPreferredSize;
456                                 if (margin < extra) {
457                                     item.resize(line.o, minPreferredSize);
458                                     extra -= margin;
459                                 } else {
460                                     item.extendSize(line.o, -extra);
461                                     extra = 0;
462                                 }
463                             }
464                         }
465                         Q_ASSERT(extra == 0);
466                     }
467                 } else {
468                     //the item is the first one, it should be at position 0
469                 }
470 
471                 return;
472 
473             } else if (!current.skip()) {
474                 previousIndex = k;
475                 minPos += pick(o, current.minimumSize());
476             }
477         }
478     }
479 }
480 
481 
gapIndex(const QPoint & pos,int * minDistance) const482 QList<int> QToolBarAreaLayoutInfo::gapIndex(const QPoint &pos, int *minDistance) const
483 {
484     if (rect.contains(pos)) {
485         // <pos> is in QToolBarAreaLayout coordinates.
486         // <item.pos> is in local dockarea coordinates (see ~20 lines below)
487         // Since we're comparing p with item.pos, we put them in the same coordinate system.
488         const int p = pick(o, pos - rect.topLeft());
489 
490         for (int j = 0; j < lines.count(); ++j) {
491             const QToolBarAreaLayoutLine &line = lines.at(j);
492             if (line.skip())
493                 continue;
494             if (!line.rect.contains(pos))
495                 continue;
496 
497             int k = 0;
498             for (; k < line.toolBarItems.count(); ++k) {
499                 const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
500                 if (item.skip())
501                     continue;
502 
503                 int size = qMin(item.size, pick(o, item.sizeHint()));
504 
505                 if (p > item.pos + size)
506                     continue;
507                 if (p > item.pos + size/2)
508                     ++k;
509                 break;
510             }
511 
512             QList<int> result;
513             result << j << k;
514             *minDistance = 0; //we found a perfect match
515             return result;
516         }
517     } else {
518         const int dist = distance(pos);
519         //it will only return a path if the minDistance is higher than the current distance
520         if (dist >= 0 && *minDistance > dist) {
521             *minDistance = dist;
522 
523             QList<int> result;
524             result << lines.count() << 0;
525             return result;
526         }
527     }
528 
529     return QList<int>();
530 }
531 
insertGap(const QList<int> & path,QLayoutItem * item)532 bool QToolBarAreaLayoutInfo::insertGap(const QList<int> &path, QLayoutItem *item)
533 {
534     Q_ASSERT(path.count() == 2);
535     int j = path.first();
536     if (j == lines.count())
537         lines.append(QToolBarAreaLayoutLine(o));
538 
539     QToolBarAreaLayoutLine &line = lines[j];
540     const int k = path.at(1);
541 
542     QToolBarAreaLayoutItem gap_item;
543     gap_item.gap = true;
544     gap_item.widgetItem = item;
545 
546     //update the previous item's preferred size
547     for(int p = k - 1 ; p >= 0; --p) {
548         QToolBarAreaLayoutItem &previous = line.toolBarItems[p];
549         if (!previous.skip()) {
550             //we found the previous one
551             int previousSizeHint = pick(line.o, previous.sizeHint());
552             int previousExtraSpace = previous.size - previousSizeHint;
553 
554             if (previousExtraSpace > 0) {
555                 //in this case we reset the space
556                 previous.preferredSize = -1;
557                 previous.size = previousSizeHint;
558 
559                 gap_item.resize(o, previousExtraSpace);
560             }
561 
562             break;
563         }
564     }
565 
566     line.toolBarItems.insert(k, gap_item);
567     return true;
568 
569 }
570 
clear()571 void QToolBarAreaLayoutInfo::clear()
572 {
573     lines.clear();
574     rect = QRect();
575 }
576 
itemRect(const QList<int> & path) const577 QRect QToolBarAreaLayoutInfo::itemRect(const QList<int> &path) const
578 {
579     Q_ASSERT(path.count() == 2);
580     int j = path.at(0);
581     int k = path.at(1);
582 
583     const QToolBarAreaLayoutLine &line = lines.at(j);
584     const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
585 
586     QRect result = line.rect;
587 
588     if (o == Qt::Horizontal) {
589         result.setLeft(item.pos + line.rect.left());
590         result.setWidth(item.size);
591     } else {
592         result.setTop(item.pos + line.rect.top());
593         result.setHeight(item.size);
594     }
595 
596     return result;
597 }
598 
distance(const QPoint & pos) const599 int QToolBarAreaLayoutInfo::distance(const QPoint &pos) const
600 {
601     switch (dockPos) {
602         case QInternal::LeftDock:
603             if (pos.y() < rect.bottom())
604                 return pos.x() - rect.right();
605             break;
606         case QInternal::RightDock:
607             if (pos.y() < rect.bottom())
608                 return rect.left() - pos.x();
609             break;
610         case QInternal::TopDock:
611             if (pos.x() < rect.right())
612                 return pos.y() - rect.bottom();
613             break;
614         case QInternal::BottomDock:
615             if (pos.x() < rect.right())
616                 return rect.top() - pos.y();
617             break;
618 
619         case QInternal::DockCount:
620             break;
621     }
622     return -1;
623 }
624 
625 /******************************************************************************
626 ** QToolBarAreaLayout
627 */
628 
QToolBarAreaLayout(const QMainWindow * win)629 QToolBarAreaLayout::QToolBarAreaLayout(const QMainWindow *win) : mainWindow(win), visible(true)
630 {
631     for (int i = 0; i < QInternal::DockCount; ++i) {
632         QInternal::DockPosition pos = static_cast<QInternal::DockPosition>(i);
633         docks[i] = QToolBarAreaLayoutInfo(pos);
634     }
635 }
636 
fitLayout()637 QRect QToolBarAreaLayout::fitLayout()
638 {
639     if (!visible)
640         return rect;
641 
642     QSize left_hint = docks[QInternal::LeftDock].sizeHint();
643     QSize right_hint = docks[QInternal::RightDock].sizeHint();
644     QSize top_hint = docks[QInternal::TopDock].sizeHint();
645     QSize bottom_hint = docks[QInternal::BottomDock].sizeHint();
646 
647     QRect center = rect.adjusted(left_hint.width(), top_hint.height(),
648                                     -right_hint.width(), -bottom_hint.height());
649 
650     docks[QInternal::TopDock].rect = QRect(rect.left(), rect.top(),
651                                 rect.width(), top_hint.height());
652     docks[QInternal::LeftDock].rect = QRect(rect.left(), center.top(),
653                                 left_hint.width(), center.height());
654     docks[QInternal::RightDock].rect = QRect(center.right() + 1, center.top(),
655                                     right_hint.width(), center.height());
656     docks[QInternal::BottomDock].rect = QRect(rect.left(), center.bottom() + 1,
657                                     rect.width(), bottom_hint.height());
658 
659     docks[QInternal::TopDock].fitLayout();
660     docks[QInternal::LeftDock].fitLayout();
661     docks[QInternal::RightDock].fitLayout();
662     docks[QInternal::BottomDock].fitLayout();
663 
664     return center;
665 }
666 
minimumSize(const QSize & centerMin) const667 QSize QToolBarAreaLayout::minimumSize(const QSize &centerMin) const
668 {
669     if (!visible)
670         return centerMin;
671 
672     QSize result = centerMin;
673 
674     QSize left_min = docks[QInternal::LeftDock].minimumSize();
675     QSize right_min = docks[QInternal::RightDock].minimumSize();
676     QSize top_min = docks[QInternal::TopDock].minimumSize();
677     QSize bottom_min = docks[QInternal::BottomDock].minimumSize();
678 
679     result.setWidth(qMax(top_min.width(), result.width()));
680     result.setWidth(qMax(bottom_min.width(), result.width()));
681     result.setHeight(qMax(left_min.height(), result.height()));
682     result.setHeight(qMax(right_min.height(), result.height()));
683 
684     result.rwidth() += left_min.width() + right_min.width();
685     result.rheight() += top_min.height() + bottom_min.height();
686 
687     return result;
688 }
689 
sizeHint(const QSize & centerHint) const690 QSize QToolBarAreaLayout::sizeHint(const QSize &centerHint) const
691 {
692     if (!visible)
693         return centerHint;
694 
695     QSize result = centerHint;
696 
697     QSize left_hint = docks[QInternal::LeftDock].sizeHint();
698     QSize right_hint = docks[QInternal::RightDock].sizeHint();
699     QSize top_hint = docks[QInternal::TopDock].sizeHint();
700     QSize bottom_hint = docks[QInternal::BottomDock].sizeHint();
701 
702     result.setWidth(qMax(top_hint.width(), result.width()));
703     result.setWidth(qMax(bottom_hint.width(), result.width()));
704     result.setHeight(qMax(left_hint.height(), result.height()));
705     result.setHeight(qMax(right_hint.height(), result.height()));
706 
707     result.rwidth() += left_hint.width() + right_hint.width();
708     result.rheight() += top_hint.height() + bottom_hint.height();
709 
710     return result;
711 }
712 
rectHint(const QRect & r) const713 QRect QToolBarAreaLayout::rectHint(const QRect &r) const
714 {
715     int coef = visible ? 1 : -1;
716 
717     QRect result = r;
718 
719     QSize left_hint = docks[QInternal::LeftDock].sizeHint();
720     QSize right_hint = docks[QInternal::RightDock].sizeHint();
721     QSize top_hint = docks[QInternal::TopDock].sizeHint();
722     QSize bottom_hint = docks[QInternal::BottomDock].sizeHint();
723 
724     result.adjust(-left_hint.width()*coef, -top_hint.height()*coef,
725                     right_hint.width()*coef, bottom_hint.height()*coef);
726 
727     return result;
728 }
729 
itemAt(int * x,int index) const730 QLayoutItem *QToolBarAreaLayout::itemAt(int *x, int index) const
731 {
732     Q_ASSERT(x != nullptr);
733 
734     for (int i = 0; i < QInternal::DockCount; ++i) {
735         const QToolBarAreaLayoutInfo &dock = docks[i];
736 
737         for (int j = 0; j < dock.lines.count(); ++j) {
738             const QToolBarAreaLayoutLine &line = dock.lines.at(j);
739 
740             for (int k = 0; k < line.toolBarItems.count(); ++k) {
741                 if ((*x)++ == index)
742                     return line.toolBarItems.at(k).widgetItem;
743             }
744         }
745     }
746 
747     return nullptr;
748 }
749 
takeAt(int * x,int index)750 QLayoutItem *QToolBarAreaLayout::takeAt(int *x, int index)
751 {
752     Q_ASSERT(x != nullptr);
753 
754     for (int i = 0; i < QInternal::DockCount; ++i) {
755         QToolBarAreaLayoutInfo &dock = docks[i];
756 
757         for (int j = 0; j < dock.lines.count(); ++j) {
758             QToolBarAreaLayoutLine &line = dock.lines[j];
759 
760             for (int k = 0; k < line.toolBarItems.count(); ++k) {
761                 if ((*x)++ == index) {
762                     QLayoutItem *result = line.toolBarItems.takeAt(k).widgetItem;
763                     if (line.toolBarItems.isEmpty())
764                         dock.lines.removeAt(j);
765                     return result;
766                 }
767             }
768         }
769     }
770 
771     return nullptr;
772 }
773 
deleteAllLayoutItems()774 void QToolBarAreaLayout::deleteAllLayoutItems()
775 {
776     for (int i = 0; i < QInternal::DockCount; ++i) {
777         QToolBarAreaLayoutInfo &dock = docks[i];
778 
779         for (int j = 0; j < dock.lines.count(); ++j) {
780             QToolBarAreaLayoutLine &line = dock.lines[j];
781 
782             for (int k = 0; k < line.toolBarItems.count(); ++k) {
783                 QToolBarAreaLayoutItem &item = line.toolBarItems[k];
784                 if (!item.gap)
785                     delete item.widgetItem;
786                 item.widgetItem = nullptr;
787             }
788         }
789     }
790 }
791 
findToolBar(const QToolBar * toolBar) const792 QInternal::DockPosition QToolBarAreaLayout::findToolBar(const QToolBar *toolBar) const
793 {
794     for (int i = 0; i < QInternal::DockCount; ++i) {
795         const QToolBarAreaLayoutInfo &dock = docks[i];
796 
797         for (int j = 0; j < dock.lines.count(); ++j) {
798             const QToolBarAreaLayoutLine &line = dock.lines.at(j);
799 
800             for (int k = 0; k < line.toolBarItems.count(); ++k) {
801                 if (line.toolBarItems.at(k).widgetItem->widget() == toolBar)
802                     return static_cast<QInternal::DockPosition>(i);
803             }
804         }
805     }
806 
807     return QInternal::DockCount;
808 }
809 
insertToolBar(QToolBar * before,QToolBar * toolBar)810 QLayoutItem *QToolBarAreaLayout::insertToolBar(QToolBar *before, QToolBar *toolBar)
811 {
812     QInternal::DockPosition pos = findToolBar(before);
813     if (pos == QInternal::DockCount)
814         return nullptr;
815 
816     return docks[pos].insertToolBar(before, toolBar);
817 }
818 
removeToolBar(QToolBar * toolBar)819 void QToolBarAreaLayout::removeToolBar(QToolBar *toolBar)
820 {
821     QInternal::DockPosition pos = findToolBar(toolBar);
822     if (pos == QInternal::DockCount)
823         return;
824     docks[pos].removeToolBar(toolBar);
825 }
826 
addToolBar(QInternal::DockPosition pos,QToolBar * toolBar)827 QLayoutItem *QToolBarAreaLayout::addToolBar(QInternal::DockPosition pos, QToolBar *toolBar)
828 {
829     return docks[pos].insertToolBar(nullptr, toolBar);
830 }
831 
insertToolBarBreak(QToolBar * before)832 void QToolBarAreaLayout::insertToolBarBreak(QToolBar *before)
833 {
834     QInternal::DockPosition pos = findToolBar(before);
835     if (pos == QInternal::DockCount)
836         return;
837     docks[pos].insertToolBarBreak(before);
838 }
839 
removeToolBarBreak(QToolBar * before)840 void QToolBarAreaLayout::removeToolBarBreak(QToolBar *before)
841 {
842     QInternal::DockPosition pos = findToolBar(before);
843     if (pos == QInternal::DockCount)
844         return;
845     docks[pos].removeToolBarBreak(before);
846 }
847 
addToolBarBreak(QInternal::DockPosition pos)848 void QToolBarAreaLayout::addToolBarBreak(QInternal::DockPosition pos)
849 {
850     docks[pos].insertToolBarBreak(nullptr);
851 }
852 
moveToolBar(QToolBar * toolbar,int p)853 void QToolBarAreaLayout::moveToolBar(QToolBar *toolbar, int p)
854 {
855     QInternal::DockPosition pos = findToolBar(toolbar);
856     if (pos == QInternal::DockCount)
857         return;
858     docks[pos].moveToolBar(toolbar, p);
859 }
860 
861 
insertItem(QInternal::DockPosition pos,QLayoutItem * item)862 void QToolBarAreaLayout::insertItem(QInternal::DockPosition pos, QLayoutItem *item)
863 {
864     if (docks[pos].lines.isEmpty())
865         docks[pos].lines.append(QToolBarAreaLayoutLine(docks[pos].o));
866     docks[pos].lines.last().toolBarItems.append(item);
867 }
868 
insertItem(QToolBar * before,QLayoutItem * item)869 void QToolBarAreaLayout::insertItem(QToolBar *before, QLayoutItem *item)
870 {
871     QInternal::DockPosition pos = findToolBar(before);
872     if (pos == QInternal::DockCount)
873         return;
874 
875     docks[pos].insertItem(before, item);
876 }
877 
apply(bool animate)878 void QToolBarAreaLayout::apply(bool animate)
879 {
880     QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow);
881     Q_ASSERT(layout != nullptr);
882 
883     Qt::LayoutDirection dir = mainWindow->layoutDirection();
884 
885     for (int i = 0; i < QInternal::DockCount; ++i) {
886         const QToolBarAreaLayoutInfo &dock = docks[i];
887 
888         for (int j = 0; j < dock.lines.count(); ++j) {
889             const QToolBarAreaLayoutLine &line = dock.lines.at(j);
890             if (line.skip())
891                 continue;
892 
893             for (int k = 0; k < line.toolBarItems.count(); ++k) {
894                 const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
895                 if (item.skip() || item.gap)
896                     continue;
897 
898                 QRect geo;
899                 if (visible) {
900                     if (line.o == Qt::Horizontal) {
901                         geo.setTop(line.rect.top());
902                         geo.setBottom(line.rect.bottom());
903                         geo.setLeft(line.rect.left() + item.pos);
904                         geo.setRight(line.rect.left() + item.pos + item.size - 1);
905                     } else {
906                         geo.setLeft(line.rect.left());
907                         geo.setRight(line.rect.right());
908                         geo.setTop(line.rect.top() + item.pos);
909                         geo.setBottom(line.rect.top() + item.pos + item.size - 1);
910                     }
911                 }
912 
913                 QWidget *widget = item.widgetItem->widget();
914                 if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) {
915                     QToolBarLayout *tbl = qobject_cast<QToolBarLayout*>(toolBar->layout());
916                     if (tbl->expanded) {
917                         QPoint tr = geo.topRight();
918                         QSize size = tbl->expandedSize(geo.size());
919                         geo.setSize(size);
920                         geo.moveTopRight(tr);
921                         if (geo.bottom() > rect.bottom())
922                             geo.moveBottom(rect.bottom());
923                         if (geo.right() > rect.right())
924                             geo.moveRight(rect.right());
925                         if (geo.left() < 0)
926                             geo.moveLeft(0);
927                         if (geo.top() < 0)
928                             geo.moveTop(0);
929                     }
930                 }
931 
932                 if (visible && dock.o == Qt::Horizontal)
933                     geo = QStyle::visualRect(dir, line.rect, geo);
934 
935                 layout->widgetAnimator.animate(widget, geo, animate);
936             }
937         }
938     }
939 }
940 
toolBarBreak(QToolBar * toolBar) const941 bool QToolBarAreaLayout::toolBarBreak(QToolBar *toolBar) const
942 {
943     for (int i = 0; i < QInternal::DockCount; ++i) {
944         const QToolBarAreaLayoutInfo &dock = docks[i];
945 
946         for (int j = 0; j < dock.lines.count(); ++j) {
947             const QToolBarAreaLayoutLine &line = dock.lines.at(j);
948 
949             for (int k = 0; k < line.toolBarItems.count(); ++k) {
950                 if (line.toolBarItems.at(k).widgetItem->widget() == toolBar)
951                     return j > 0 && k == 0;
952             }
953         }
954     }
955 
956     return false;
957 }
958 
getStyleOptionInfo(QStyleOptionToolBar * option,QToolBar * toolBar) const959 void QToolBarAreaLayout::getStyleOptionInfo(QStyleOptionToolBar *option, QToolBar *toolBar) const
960 {
961     for (int i = 0; i < QInternal::DockCount; ++i) {
962         const QToolBarAreaLayoutInfo &dock = docks[i];
963 
964         for (int j = 0; j < dock.lines.count(); ++j) {
965             const QToolBarAreaLayoutLine &line = dock.lines.at(j);
966 
967             for (int k = 0; k < line.toolBarItems.count(); ++k) {
968                 if (line.toolBarItems.at(k).widgetItem->widget() == toolBar) {
969                     if (line.toolBarItems.count() == 1)
970                         option->positionWithinLine = QStyleOptionToolBar::OnlyOne;
971                     else if (k == 0)
972                         option->positionWithinLine = QStyleOptionToolBar::Beginning;
973                     else if (k == line.toolBarItems.count() - 1)
974                         option->positionWithinLine = QStyleOptionToolBar::End;
975                     else
976                         option->positionWithinLine = QStyleOptionToolBar::Middle;
977 
978                     if (dock.lines.count() == 1)
979                         option->positionOfLine = QStyleOptionToolBar::OnlyOne;
980                     else if (j == 0)
981                         option->positionOfLine = QStyleOptionToolBar::Beginning;
982                     else if (j == dock.lines.count() - 1)
983                         option->positionOfLine = QStyleOptionToolBar::End;
984                     else
985                         option->positionOfLine = QStyleOptionToolBar::Middle;
986 
987                     return;
988                 }
989             }
990         }
991     }
992 }
993 
indexOf(QWidget * toolBar) const994 QList<int> QToolBarAreaLayout::indexOf(QWidget *toolBar) const
995 {
996     QList<int> result;
997 
998     bool found = false;
999 
1000     for (int i = 0; i < QInternal::DockCount; ++i) {
1001         const QToolBarAreaLayoutInfo &dock = docks[i];
1002 
1003         for (int j = 0; j < dock.lines.count(); ++j) {
1004             const QToolBarAreaLayoutLine &line = dock.lines.at(j);
1005 
1006             for (int k = 0; k < line.toolBarItems.count(); ++k) {
1007                 const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
1008                 if (!item.gap && item.widgetItem->widget() == toolBar) {
1009                     found = true;
1010                     result.prepend(k);
1011                     break;
1012                 }
1013             }
1014 
1015             if (found) {
1016                 result.prepend(j);
1017                 break;
1018             }
1019         }
1020 
1021         if (found) {
1022             result.prepend(i);
1023             break;
1024         }
1025     }
1026 
1027     return result;
1028 }
1029 
1030 //this functions returns the path to the possible gapindex for the position pos
gapIndex(const QPoint & pos) const1031 QList<int> QToolBarAreaLayout::gapIndex(const QPoint &pos) const
1032 {
1033     Qt::LayoutDirection dir = mainWindow->layoutDirection();
1034     int minDistance = 80; // when a dock area is empty, how "wide" is it?
1035     QList<int> ret; //return value
1036     for (int i = 0; i < QInternal::DockCount; ++i) {
1037         QPoint p = pos;
1038         if (docks[i].o == Qt::Horizontal)
1039             p = QStyle::visualPos(dir, docks[i].rect, p);
1040         QList<int> result = docks[i].gapIndex(p, &minDistance);
1041         if (!result.isEmpty()) {
1042             result.prepend(i);
1043             ret = result;
1044         }
1045     }
1046 
1047     return ret;
1048 }
1049 
currentGapIndex() const1050 QList<int> QToolBarAreaLayout::currentGapIndex() const
1051 {
1052     for (int i = 0; i < QInternal::DockCount; ++i) {
1053         const QToolBarAreaLayoutInfo &dock = docks[i];
1054 
1055         for (int j = 0; j < dock.lines.count(); ++j) {
1056             const QToolBarAreaLayoutLine &line = dock.lines[j];
1057 
1058             for (int k = 0; k < line.toolBarItems.count(); k++) {
1059                 if (line.toolBarItems[k].gap) {
1060                     QList<int> result;
1061                     result << i << j << k;
1062                     return result;
1063                 }
1064             }
1065         }
1066     }
1067     return QList<int>();
1068 }
1069 
insertGap(const QList<int> & path,QLayoutItem * item)1070 bool QToolBarAreaLayout::insertGap(const QList<int> &path, QLayoutItem *item)
1071 {
1072     Q_ASSERT(path.count() == 3);
1073     const int i = path.first();
1074     Q_ASSERT(i >= 0 && i < QInternal::DockCount);
1075     return docks[i].insertGap(path.mid(1), item);
1076 }
1077 
remove(const QList<int> & path)1078 void QToolBarAreaLayout::remove(const QList<int> &path)
1079 {
1080     Q_ASSERT(path.count() == 3);
1081     QToolBarAreaLayoutInfo &dock = docks[path.at(0)];
1082     QToolBarAreaLayoutLine &line = dock.lines[path.at(1)];
1083     line.toolBarItems.removeAt(path.at(2));
1084     if (line.toolBarItems.isEmpty())
1085         dock.lines.removeAt(path.at(1));
1086 }
1087 
remove(QLayoutItem * item)1088 void QToolBarAreaLayout::remove(QLayoutItem *item)
1089 {
1090     for (int i = 0; i < QInternal::DockCount; ++i) {
1091         QToolBarAreaLayoutInfo &dock = docks[i];
1092 
1093         for (int j = 0; j < dock.lines.count(); ++j) {
1094             QToolBarAreaLayoutLine &line = dock.lines[j];
1095 
1096             for (int k = 0; k < line.toolBarItems.count(); k++) {
1097                 if (line.toolBarItems[k].widgetItem == item) {
1098                     line.toolBarItems.removeAt(k);
1099                     if (line.toolBarItems.isEmpty())
1100                         dock.lines.removeAt(j);
1101                     return;
1102                 }
1103             }
1104         }
1105     }
1106 }
1107 
clear()1108 void QToolBarAreaLayout::clear()
1109 {
1110     for (int i = 0; i < QInternal::DockCount; ++i)
1111         docks[i].clear();
1112     rect = QRect();
1113 }
1114 
item(const QList<int> & path)1115 QToolBarAreaLayoutItem *QToolBarAreaLayout::item(const QList<int> &path)
1116 {
1117     Q_ASSERT(path.count() == 3);
1118 
1119     if (path.at(0) < 0 || path.at(0) >= QInternal::DockCount)
1120         return nullptr;
1121     QToolBarAreaLayoutInfo &info = docks[path.at(0)];
1122     if (path.at(1) < 0 || path.at(1) >= info.lines.count())
1123         return nullptr;
1124     QToolBarAreaLayoutLine &line = info.lines[path.at(1)];
1125     if (path.at(2) < 0 || path.at(2) >= line.toolBarItems.count())
1126         return nullptr;
1127     return &(line.toolBarItems[path.at(2)]);
1128 }
1129 
itemRect(const QList<int> & path) const1130 QRect QToolBarAreaLayout::itemRect(const QList<int> &path) const
1131 {
1132     const int i = path.first();
1133 
1134     QRect r = docks[i].itemRect(path.mid(1));
1135     if (docks[i].o == Qt::Horizontal)
1136         r = QStyle::visualRect(mainWindow->layoutDirection(),
1137                                 docks[i].rect, r);
1138     return r;
1139 }
1140 
plug(const QList<int> & path)1141 QLayoutItem *QToolBarAreaLayout::plug(const QList<int> &path)
1142 {
1143     QToolBarAreaLayoutItem *item = this->item(path);
1144     if (Q_UNLIKELY(!item)) {
1145         qWarning() << "No item at" << path;
1146         return nullptr;
1147     }
1148     Q_ASSERT(item->gap);
1149     Q_ASSERT(item->widgetItem != nullptr);
1150     item->gap = false;
1151     return item->widgetItem;
1152 }
1153 
unplug(const QList<int> & path,QToolBarAreaLayout * other)1154 QLayoutItem *QToolBarAreaLayout::unplug(const QList<int> &path, QToolBarAreaLayout *other)
1155 {
1156     //other needs to be update as well
1157     Q_ASSERT(path.count() == 3);
1158     QToolBarAreaLayoutItem *item = this->item(path);
1159     Q_ASSERT(item);
1160 
1161     //update the leading space here
1162     QToolBarAreaLayoutInfo &info = docks[path.at(0)];
1163     QToolBarAreaLayoutLine &line = info.lines[path.at(1)];
1164     if (item->size != pick(line.o, item->realSizeHint())) {
1165         //the item doesn't have its default size
1166         //so we'll give this to the next item
1167         int newExtraSpace = 0;
1168         //let's iterate over the siblings of the current item that pare placed before it
1169         //we need to find just the one before
1170         for (int i = path.at(2) - 1; i >= 0; --i) {
1171             QToolBarAreaLayoutItem &previous = line.toolBarItems[i];
1172             if (!previous.skip()) {
1173                 //we need to check if it has a previous element and a next one
1174                 //the previous will get its size changed
1175                 for (int j = path.at(2) + 1; j < line.toolBarItems.count(); ++j) {
1176                     const QToolBarAreaLayoutItem &next = line.toolBarItems.at(j);
1177                     if (!next.skip()) {
1178                         newExtraSpace = next.pos - previous.pos - pick(line.o, previous.sizeHint());
1179                         previous.resize(line.o, next.pos - previous.pos);
1180                         break;
1181                     }
1182                 }
1183                 break;
1184             }
1185         }
1186 
1187         if (other) {
1188             QToolBarAreaLayoutInfo &info = other->docks[path.at(0)];
1189             QToolBarAreaLayoutLine &line = info.lines[path.at(1)];
1190             for (int i = path.at(2) - 1; i >= 0; --i) {
1191                 QToolBarAreaLayoutItem &previous = line.toolBarItems[i];
1192                 if (!previous.skip()) {
1193                     previous.resize(line.o, pick(line.o, previous.sizeHint()) + newExtraSpace);
1194                     break;
1195                 }
1196             }
1197 
1198         }
1199     }
1200 
1201     Q_ASSERT(!item->gap);
1202     item->gap = true;
1203     return item->widgetItem;
1204 }
1205 
unpackRect(uint geom0,uint geom1,bool * floating)1206 static QRect unpackRect(uint geom0, uint geom1, bool *floating)
1207 {
1208     *floating = geom0 & 1;
1209     if (!*floating)
1210         return QRect();
1211 
1212     geom0 >>= 1;
1213 
1214     int x = (int)(geom0 & 0x0000ffff) - 0x7FFF;
1215     int y = (int)(geom1 & 0x0000ffff) - 0x7FFF;
1216 
1217     geom0 >>= 16;
1218     geom1 >>= 16;
1219 
1220     int w = geom0 & 0x0000ffff;
1221     int h = geom1 & 0x0000ffff;
1222 
1223     return QRect(x, y, w, h);
1224 }
1225 
packRect(uint * geom0,uint * geom1,const QRect & rect,bool floating)1226 static void packRect(uint *geom0, uint *geom1, const QRect &rect, bool floating)
1227 {
1228     *geom0 = 0;
1229     *geom1 = 0;
1230 
1231     if (!floating)
1232         return;
1233 
1234     // The 0x7FFF is half of 0xFFFF. We add it so we can handle negative coordinates on
1235     // dual monitors. It's subtracted when unpacking.
1236 
1237     *geom0 |= qMax(0, rect.width()) & 0x0000ffff;
1238     *geom1 |= qMax(0, rect.height()) & 0x0000ffff;
1239 
1240     *geom0 <<= 16;
1241     *geom1 <<= 16;
1242 
1243     *geom0 |= qMax(0, rect.x() + 0x7FFF) & 0x0000ffff;
1244     *geom1 |= qMax(0, rect.y() + 0x7FFF) & 0x0000ffff;
1245 
1246     // yeah, we chop one bit off the width, but it still has a range up to 32512
1247 
1248     *geom0 <<= 1;
1249     *geom0 |= 1;
1250 }
1251 
1252 
saveState(QDataStream & stream) const1253 void QToolBarAreaLayout::saveState(QDataStream &stream) const
1254 {
1255     // save toolbar state
1256     stream << (uchar) ToolBarStateMarkerEx;
1257 
1258     int lineCount = 0;
1259     for (int i = 0; i < QInternal::DockCount; ++i)
1260         lineCount += docks[i].lines.count();
1261 
1262     stream << lineCount;
1263 
1264     for (int i = 0; i < QInternal::DockCount; ++i) {
1265         const QToolBarAreaLayoutInfo &dock = docks[i];
1266 
1267         for (int j = 0; j < dock.lines.count(); ++j) {
1268             const QToolBarAreaLayoutLine &line = dock.lines.at(j);
1269 
1270             stream << i << line.toolBarItems.count();
1271 
1272             for (int k = 0; k < line.toolBarItems.count(); ++k) {
1273                 const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
1274                 QWidget *widget = const_cast<QLayoutItem*>(item.widgetItem)->widget();
1275                 QString objectName = widget->objectName();
1276                 if (Q_UNLIKELY(objectName.isEmpty())) {
1277                     qWarning("QMainWindow::saveState(): 'objectName' not set for QToolBar %p '%s'",
1278                                 widget, widget->windowTitle().toLocal8Bit().constData());
1279                 }
1280                 stream << objectName;
1281                 // we store information as:
1282                 // 1st bit: 1 if shown
1283                 // 2nd bit: 1 if orientation is vertical (default is horizontal)
1284                 uchar shownOrientation = (uchar)!widget->isHidden();
1285                 if (QToolBar * tb= qobject_cast<QToolBar*>(widget)) {
1286                     if (tb->orientation() == Qt::Vertical)
1287                         shownOrientation |= 2;
1288                 }
1289                 stream << shownOrientation;
1290                 stream << item.pos;
1291                 //we store the preferred size. If the use rdidn't resize the toolbars it will be -1
1292                 stream << item.preferredSize;
1293 
1294                 uint geom0, geom1;
1295                 packRect(&geom0, &geom1, widget->geometry(), widget->isWindow());
1296                 stream << geom0 << geom1;
1297             }
1298         }
1299     }
1300 }
1301 
getInt(QDataStream & stream)1302 static inline int getInt(QDataStream &stream)
1303 {
1304     int x;
1305     stream >> x;
1306     return x;
1307 }
1308 
1309 
restoreState(QDataStream & stream,const QList<QToolBar * > & _toolBars,uchar tmarker,bool testing)1310 bool QToolBarAreaLayout::restoreState(QDataStream &stream, const QList<QToolBar*> &_toolBars, uchar tmarker, bool testing)
1311 {
1312     QList<QToolBar*> toolBars = _toolBars;
1313     int lines;
1314     stream >> lines;
1315 
1316     for (int j = 0; j < lines; ++j) {
1317         int pos;
1318         stream >> pos;
1319         if (pos < 0 || pos >= QInternal::DockCount)
1320             return false;
1321         int cnt;
1322         stream >> cnt;
1323 
1324         QToolBarAreaLayoutInfo &dock = docks[pos];
1325         const bool applyingLayout = !testing;
1326         QToolBarAreaLayoutLine line(dock.o);
1327 
1328         for (int k = 0; k < cnt; ++k) {
1329             QToolBarAreaLayoutItem item;
1330 
1331             QString objectName;
1332             stream >> objectName;
1333             uchar shown;
1334             stream >> shown;
1335             item.pos = getInt(stream);
1336             item.size = getInt(stream);
1337 
1338             /*
1339                4.3.0 added floating toolbars, but failed to add the ability to restore them.
1340                We need to store there geometry (four ints). We cannot change the format in a
1341                patch release (4.3.1) by adding ToolBarStateMarkerEx2 to signal extra data. So
1342                for now we'll pack it in the two legacy ints we no longer used in Qt4.3.0.
1343                In 4.4, we should add ToolBarStateMarkerEx2 and fix this properly.
1344             */
1345 
1346             QRect rect;
1347             bool floating = false;
1348             uint geom0, geom1;
1349             geom0 = getInt(stream);
1350             if (tmarker == ToolBarStateMarkerEx) {
1351                 geom1 = getInt(stream);
1352                 rect = unpackRect(geom0, geom1, &floating);
1353             }
1354 
1355             QToolBar *toolBar = nullptr;
1356             for (int x = 0; x < toolBars.count(); ++x) {
1357                 if (toolBars.at(x)->objectName() == objectName) {
1358                     toolBar = toolBars.takeAt(x);
1359                     break;
1360                 }
1361             }
1362             if (toolBar == nullptr) {
1363                 continue;
1364             }
1365 
1366             if (applyingLayout) {
1367                 item.widgetItem = new QWidgetItemV2(toolBar);
1368                 toolBar->setOrientation(floating ? ((shown & 2) ? Qt::Vertical : Qt::Horizontal) : dock.o);
1369                 toolBar->setVisible(shown & 1);
1370                 toolBar->d_func()->setWindowState(floating, true, rect);
1371 
1372                 item.preferredSize = item.size;
1373                 line.toolBarItems.append(item);
1374             }
1375         }
1376 
1377         if (applyingLayout) {
1378             dock.lines.append(line);
1379         }
1380     }
1381 
1382 
1383     return stream.status() == QDataStream::Ok;
1384 }
1385 
isEmpty() const1386 bool QToolBarAreaLayout::isEmpty() const
1387 {
1388     for (int i = 0; i < QInternal::DockCount; ++i) {
1389         if (!docks[i].lines.isEmpty())
1390             return false;
1391     }
1392     return true;
1393 }
1394 
1395 QT_END_NAMESPACE
1396