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

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

trunk: Merged in qt 4.6.1 sources.

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