source: trunk/src/gui/widgets/qtoolbararealayout.cpp@ 966

Last change on this file since 966 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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