summaryrefslogtreecommitdiffstats
path: root/src/widgets/widgets/qdockarealayout.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/widgets/qdockarealayout.cpp')
-rw-r--r--src/widgets/widgets/qdockarealayout.cpp3334
1 files changed, 3334 insertions, 0 deletions
diff --git a/src/widgets/widgets/qdockarealayout.cpp b/src/widgets/widgets/qdockarealayout.cpp
new file mode 100644
index 0000000000..223421dfb2
--- /dev/null
+++ b/src/widgets/widgets/qdockarealayout.cpp
@@ -0,0 +1,3334 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtGui/qapplication.h"
+#include "QtGui/qwidget.h"
+#include "QtGui/qtabbar.h"
+#include "QtGui/qstyle.h"
+#include "QtGui/qdesktopwidget.h"
+#include "QtCore/qvariant.h"
+#include "qdockarealayout_p.h"
+#include "qdockwidget.h"
+#include "qmainwindow.h"
+#include "qwidgetanimator_p.h"
+#include "qmainwindowlayout_p.h"
+#include "qdockwidget_p.h"
+#include <private/qlayoutengine_p.h>
+
+#include <qpainter.h>
+#include <qstyleoption.h>
+
+#ifndef QT_NO_DOCKWIDGET
+
+QT_BEGIN_NAMESPACE
+
+// qmainwindow.cpp
+extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
+
+enum { StateFlagVisible = 1, StateFlagFloating = 2 };
+
+/******************************************************************************
+** QPlaceHolderItem
+*/
+
+QPlaceHolderItem::QPlaceHolderItem(QWidget *w)
+{
+ objectName = w->objectName();
+ hidden = w->isHidden();
+ window = w->isWindow();
+ if (window)
+ topLevelRect = w->geometry();
+}
+
+/******************************************************************************
+** QDockAreaLayoutItem
+*/
+
+QDockAreaLayoutItem::QDockAreaLayoutItem(QLayoutItem *_widgetItem)
+ : widgetItem(_widgetItem), subinfo(0), placeHolderItem(0), pos(0), size(-1), flags(NoFlags)
+{
+}
+
+QDockAreaLayoutItem::QDockAreaLayoutItem(QDockAreaLayoutInfo *_subinfo)
+ : widgetItem(0), subinfo(_subinfo), placeHolderItem(0), pos(0), size(-1), flags(NoFlags)
+{
+}
+
+QDockAreaLayoutItem::QDockAreaLayoutItem(QPlaceHolderItem *_placeHolderItem)
+ : widgetItem(0), subinfo(0), placeHolderItem(_placeHolderItem), pos(0), size(-1), flags(NoFlags)
+{
+}
+
+QDockAreaLayoutItem::QDockAreaLayoutItem(const QDockAreaLayoutItem &other)
+ : widgetItem(other.widgetItem), subinfo(0), placeHolderItem(0), pos(other.pos),
+ size(other.size), flags(other.flags)
+{
+ if (other.subinfo != 0)
+ subinfo = new QDockAreaLayoutInfo(*other.subinfo);
+ else if (other.placeHolderItem != 0)
+ placeHolderItem = new QPlaceHolderItem(*other.placeHolderItem);
+}
+
+QDockAreaLayoutItem::~QDockAreaLayoutItem()
+{
+ delete subinfo;
+ delete placeHolderItem;
+}
+
+bool QDockAreaLayoutItem::skip() const
+{
+ if (placeHolderItem != 0)
+ return true;
+
+ if (flags & GapItem)
+ return false;
+
+ if (widgetItem != 0)
+ return widgetItem->isEmpty();
+
+ if (subinfo != 0) {
+ for (int i = 0; i < subinfo->item_list.count(); ++i) {
+ if (!subinfo->item_list.at(i).skip())
+ return false;
+ }
+ }
+
+ return true;
+}
+
+QSize QDockAreaLayoutItem::minimumSize() const
+{
+ if (widgetItem != 0) {
+ int left, top, right, bottom;
+ widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom);
+ return widgetItem->minimumSize() + QSize(left+right, top+bottom);
+ }
+ if (subinfo != 0)
+ return subinfo->minimumSize();
+ return QSize(0, 0);
+}
+
+QSize QDockAreaLayoutItem::maximumSize() const
+{
+ if (widgetItem != 0) {
+ int left, top, right, bottom;
+ widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom);
+ return widgetItem->maximumSize()+ QSize(left+right, top+bottom);
+ }
+ if (subinfo != 0)
+ return subinfo->maximumSize();
+ return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
+}
+
+bool QDockAreaLayoutItem::hasFixedSize(Qt::Orientation o) const
+{
+ return perp(o, minimumSize()) == perp(o, maximumSize());
+}
+
+bool QDockAreaLayoutItem::expansive(Qt::Orientation o) const
+{
+ if ((flags & GapItem) || placeHolderItem != 0)
+ return false;
+ if (widgetItem != 0)
+ return ((widgetItem->expandingDirections() & o) == o);
+ if (subinfo != 0)
+ return subinfo->expansive(o);
+ return false;
+}
+
+QSize QDockAreaLayoutItem::sizeHint() const
+{
+ if (placeHolderItem != 0)
+ return QSize(0, 0);
+ if (widgetItem != 0) {
+ int left, top, right, bottom;
+ widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom);
+ return widgetItem->sizeHint() + QSize(left+right, top+bottom);
+ }
+ if (subinfo != 0)
+ return subinfo->sizeHint();
+ return QSize(-1, -1);
+}
+
+QDockAreaLayoutItem
+ &QDockAreaLayoutItem::operator = (const QDockAreaLayoutItem &other)
+{
+ widgetItem = other.widgetItem;
+ if (other.subinfo == 0)
+ subinfo = 0;
+ else
+ subinfo = new QDockAreaLayoutInfo(*other.subinfo);
+
+ delete placeHolderItem;
+ if (other.placeHolderItem == 0)
+ placeHolderItem = 0;
+ else
+ placeHolderItem = new QPlaceHolderItem(*other.placeHolderItem);
+
+ pos = other.pos;
+ size = other.size;
+ flags = other.flags;
+
+ return *this;
+}
+
+/******************************************************************************
+** QDockAreaLayoutInfo
+*/
+
+#ifndef QT_NO_TABBAR
+static quintptr tabId(const QDockAreaLayoutItem &item)
+{
+ if (item.widgetItem == 0)
+ return 0;
+ return reinterpret_cast<quintptr>(item.widgetItem->widget());
+}
+#endif
+
+static const int zero = 0;
+
+QDockAreaLayoutInfo::QDockAreaLayoutInfo()
+ : sep(&zero), dockPos(QInternal::LeftDock), o(Qt::Horizontal), mainWindow(0)
+#ifndef QT_NO_TABBAR
+ , tabbed(false), tabBar(0), tabBarShape(QTabBar::RoundedSouth)
+#endif
+{
+}
+
+QDockAreaLayoutInfo::QDockAreaLayoutInfo(const int *_sep, QInternal::DockPosition _dockPos,
+ Qt::Orientation _o, int tbshape,
+ QMainWindow *window)
+ : sep(_sep), dockPos(_dockPos), o(_o), mainWindow(window)
+#ifndef QT_NO_TABBAR
+ , tabbed(false), tabBar(0), tabBarShape(static_cast<QTabBar::Shape>(tbshape))
+#endif
+{
+#ifdef QT_NO_TABBAR
+ Q_UNUSED(tbshape);
+#endif
+}
+
+QSize QDockAreaLayoutInfo::size() const
+{
+ return isEmpty() ? QSize(0, 0) : rect.size();
+}
+
+void QDockAreaLayoutInfo::clear()
+{
+ item_list.clear();
+ rect = QRect();
+#ifndef QT_NO_TABBAR
+ tabbed = false;
+ tabBar = 0;
+#endif
+}
+
+bool QDockAreaLayoutInfo::isEmpty() const
+{
+ return next(-1) == -1;
+}
+
+QSize QDockAreaLayoutInfo::minimumSize() const
+{
+ if (isEmpty())
+ return QSize(0, 0);
+
+ int a = 0, b = 0;
+ bool first = true;
+ for (int i = 0; i < item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.skip())
+ continue;
+
+ QSize min_size = item.minimumSize();
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ a = qMax(a, pick(o, min_size));
+ } else
+#endif
+ {
+ if (!first)
+ a += *sep;
+ a += pick(o, min_size);
+ }
+ b = qMax(b, perp(o, min_size));
+
+ first = false;
+ }
+
+ QSize result;
+ rpick(o, result) = a;
+ rperp(o, result) = b;
+
+#ifndef QT_NO_TABBAR
+ QSize tbm = tabBarMinimumSize();
+ if (!tbm.isNull()) {
+ switch (tabBarShape) {
+ case QTabBar::RoundedNorth:
+ case QTabBar::RoundedSouth:
+ case QTabBar::TriangularNorth:
+ case QTabBar::TriangularSouth:
+ result.rheight() += tbm.height();
+ result.rwidth() = qMax(tbm.width(), result.width());
+ break;
+ case QTabBar::RoundedEast:
+ case QTabBar::RoundedWest:
+ case QTabBar::TriangularEast:
+ case QTabBar::TriangularWest:
+ result.rheight() = qMax(tbm.height(), result.height());
+ result.rwidth() += tbm.width();
+ break;
+ default:
+ break;
+ }
+ }
+#endif // QT_NO_TABBAR
+
+ return result;
+}
+
+QSize QDockAreaLayoutInfo::maximumSize() const
+{
+ if (isEmpty())
+ return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
+
+ int a = 0, b = QWIDGETSIZE_MAX;
+#ifndef QT_NO_TABBAR
+ if (tabbed)
+ a = QWIDGETSIZE_MAX;
+#endif
+
+ int min_perp = 0;
+
+ bool first = true;
+ for (int i = 0; i < item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.skip())
+ continue;
+
+ QSize max_size = item.maximumSize();
+ min_perp = qMax(min_perp, perp(o, item.minimumSize()));
+
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ a = qMin(a, pick(o, max_size));
+ } else
+#endif
+ {
+ if (!first)
+ a += *sep;
+ a += pick(o, max_size);
+ }
+ b = qMin(b, perp(o, max_size));
+
+ a = qMin(a, int(QWIDGETSIZE_MAX));
+ b = qMin(b, int(QWIDGETSIZE_MAX));
+
+ first = false;
+ }
+
+ b = qMax(b, min_perp);
+
+ QSize result;
+ rpick(o, result) = a;
+ rperp(o, result) = b;
+
+#ifndef QT_NO_TABBAR
+ QSize tbh = tabBarSizeHint();
+ if (!tbh.isNull()) {
+ switch (tabBarShape) {
+ case QTabBar::RoundedNorth:
+ case QTabBar::RoundedSouth:
+ result.rheight() += tbh.height();
+ break;
+ case QTabBar::RoundedEast:
+ case QTabBar::RoundedWest:
+ result.rwidth() += tbh.width();
+ break;
+ default:
+ break;
+ }
+ }
+#endif // QT_NO_TABBAR
+
+ return result;
+}
+
+QSize QDockAreaLayoutInfo::sizeHint() const
+{
+ if (isEmpty())
+ return QSize(0, 0);
+
+ int a = 0, b = 0;
+ int min_perp = 0;
+ int max_perp = QWIDGETSIZE_MAX;
+ const QDockAreaLayoutItem *previous = 0;
+ for (int i = 0; i < item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.skip())
+ continue;
+
+ bool gap = item.flags & QDockAreaLayoutItem::GapItem;
+
+ QSize size_hint = item.sizeHint();
+ min_perp = qMax(min_perp, perp(o, item.minimumSize()));
+ max_perp = qMin(max_perp, perp(o, item.maximumSize()));
+
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ a = qMax(a, gap ? item.size : pick(o, size_hint));
+ } else
+#endif
+ {
+ if (previous && !gap && !(previous->flags & QDockAreaLayoutItem::GapItem)
+ && !previous->hasFixedSize(o)) {
+ a += *sep;
+ }
+ a += gap ? item.size : pick(o, size_hint);
+ }
+ b = qMax(b, perp(o, size_hint));
+
+ previous = &item;
+ }
+
+ max_perp = qMax(max_perp, min_perp);
+ b = qMax(b, min_perp);
+ b = qMin(b, max_perp);
+
+ QSize result;
+ rpick(o, result) = a;
+ rperp(o, result) = b;
+
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ QSize tbh = tabBarSizeHint();
+ switch (tabBarShape) {
+ case QTabBar::RoundedNorth:
+ case QTabBar::RoundedSouth:
+ case QTabBar::TriangularNorth:
+ case QTabBar::TriangularSouth:
+ result.rheight() += tbh.height();
+ result.rwidth() = qMax(tbh.width(), result.width());
+ break;
+ case QTabBar::RoundedEast:
+ case QTabBar::RoundedWest:
+ case QTabBar::TriangularEast:
+ case QTabBar::TriangularWest:
+ result.rheight() = qMax(tbh.height(), result.height());
+ result.rwidth() += tbh.width();
+ break;
+ default:
+ break;
+ }
+ }
+#endif // QT_NO_TABBAR
+
+ return result;
+}
+
+bool QDockAreaLayoutInfo::expansive(Qt::Orientation o) const
+{
+ for (int i = 0; i < item_list.size(); ++i) {
+ if (item_list.at(i).expansive(o))
+ return true;
+ }
+ return false;
+}
+
+/* QDockAreaLayoutInfo::maximumSize() doesn't return the real max size. For example,
+ if the layout is empty, it returns QWIDGETSIZE_MAX. This is so that empty dock areas
+ don't constrain the size of the QMainWindow, but sometimes we really need to know the
+ maximum size. Also, these functions take into account widgets that want to keep their
+ size (f.ex. when they are hidden and then shown, they should not change size).
+*/
+
+static int realMinSize(const QDockAreaLayoutInfo &info)
+{
+ int result = 0;
+ bool first = true;
+ for (int i = 0; i < info.item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = info.item_list.at(i);
+ if (item.skip())
+ continue;
+
+ int min = 0;
+ if ((item.flags & QDockAreaLayoutItem::KeepSize) && item.size != -1)
+ min = item.size;
+ else
+ min = pick(info.o, item.minimumSize());
+
+ if (!first)
+ result += *info.sep;
+ result += min;
+
+ first = false;
+ }
+
+ return result;
+}
+
+static int realMaxSize(const QDockAreaLayoutInfo &info)
+{
+ int result = 0;
+ bool first = true;
+ for (int i = 0; i < info.item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = info.item_list.at(i);
+ if (item.skip())
+ continue;
+
+ int max = 0;
+ if ((item.flags & QDockAreaLayoutItem::KeepSize) && item.size != -1)
+ max = item.size;
+ else
+ max = pick(info.o, item.maximumSize());
+
+ if (!first)
+ result += *info.sep;
+ result += max;
+
+ if (result >= QWIDGETSIZE_MAX)
+ return QWIDGETSIZE_MAX;
+
+ first = false;
+ }
+
+ return result;
+}
+
+void QDockAreaLayoutInfo::fitItems()
+{
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ return;
+ }
+#endif
+
+ QVector<QLayoutStruct> layout_struct_list(item_list.size()*2);
+ int j = 0;
+
+ int size = pick(o, rect.size());
+ int min_size = realMinSize(*this);
+ int max_size = realMaxSize(*this);
+ int last_index = -1;
+
+ const QDockAreaLayoutItem *previous = 0;
+ for (int i = 0; i < item_list.size(); ++i) {
+ QDockAreaLayoutItem &item = item_list[i];
+ if (item.skip())
+ continue;
+
+ bool gap = item.flags & QDockAreaLayoutItem::GapItem;
+ if (previous && !gap) {
+ if (!(previous->flags & QDockAreaLayoutItem::GapItem)) {
+ QLayoutStruct &ls = layout_struct_list[j++];
+ ls.init();
+ ls.minimumSize = ls.maximumSize = ls.sizeHint = previous->hasFixedSize(o) ? 0 : *sep;
+ ls.empty = false;
+ }
+ }
+
+ if (item.flags & QDockAreaLayoutItem::KeepSize) {
+ // Check if the item can keep its size, without violating size constraints
+ // of other items.
+
+ if (size < min_size) {
+ // There is too little space to keep this widget's size
+ item.flags &= ~QDockAreaLayoutItem::KeepSize;
+ min_size -= item.size;
+ min_size += pick(o, item.minimumSize());
+ min_size = qMax(0, min_size);
+ } else if (size > max_size) {
+ // There is too much space to keep this widget's size
+ item.flags &= ~QDockAreaLayoutItem::KeepSize;
+ max_size -= item.size;
+ max_size += pick(o, item.maximumSize());
+ max_size = qMin<int>(QWIDGETSIZE_MAX, max_size);
+ }
+ }
+
+ last_index = j;
+ QLayoutStruct &ls = layout_struct_list[j++];
+ ls.init();
+ ls.empty = false;
+ if (item.flags & QDockAreaLayoutItem::KeepSize) {
+ ls.minimumSize = ls.maximumSize = ls.sizeHint = item.size;
+ ls.expansive = false;
+ ls.stretch = 0;
+ } else {
+ ls.maximumSize = pick(o, item.maximumSize());
+ ls.expansive = item.expansive(o);
+ ls.minimumSize = pick(o, item.minimumSize());
+ ls.sizeHint = item.size == -1 ? pick(o, item.sizeHint()) : item.size;
+ ls.stretch = ls.expansive ? ls.sizeHint : 0;
+ }
+
+ item.flags &= ~QDockAreaLayoutItem::KeepSize;
+ previous = &item;
+ }
+ layout_struct_list.resize(j);
+
+ // If there is more space than the widgets can take (due to maximum size constraints),
+ // we detect it here and stretch the last widget to take up the rest of the space.
+ if (size > max_size && last_index != -1) {
+ layout_struct_list[last_index].maximumSize = QWIDGETSIZE_MAX;
+ layout_struct_list[last_index].expansive = true;
+ }
+
+ qGeomCalc(layout_struct_list, 0, j, pick(o, rect.topLeft()), size, 0);
+
+ j = 0;
+ bool prev_gap = false;
+ bool first = true;
+ for (int i = 0; i < item_list.size(); ++i) {
+ QDockAreaLayoutItem &item = item_list[i];
+ if (item.skip())
+ continue;
+
+ bool gap = item.flags & QDockAreaLayoutItem::GapItem;
+ if (!first && !gap && !prev_gap)
+ ++j;
+
+ const QLayoutStruct &ls = layout_struct_list.at(j++);
+ item.size = ls.size;
+ item.pos = ls.pos;
+
+ if (item.subinfo != 0) {
+ item.subinfo->rect = itemRect(i);
+ item.subinfo->fitItems();
+ }
+
+ prev_gap = gap;
+ first = false;
+ }
+}
+
+static QInternal::DockPosition dockPosHelper(const QRect &rect, const QPoint &_pos,
+ Qt::Orientation o,
+ bool nestingEnabled,
+ QDockAreaLayoutInfo::TabMode tabMode)
+{
+ if (tabMode == QDockAreaLayoutInfo::ForceTabs)
+ return QInternal::DockCount;
+
+ QPoint pos = _pos - rect.topLeft();
+
+ int x = pos.x();
+ int y = pos.y();
+ int w = rect.width();
+ int h = rect.height();
+
+ if (tabMode != QDockAreaLayoutInfo::NoTabs) {
+ // is it in the center?
+ if (nestingEnabled) {
+ /* 2/3
+ +--------------+
+ | |
+ | CCCCCCCC |
+ 2/3 | CCCCCCCC |
+ | CCCCCCCC |
+ | |
+ +--------------+ */
+
+ QRect center(w/6, h/6, 2*w/3, 2*h/3);
+ if (center.contains(pos))
+ return QInternal::DockCount;
+ } else if (o == Qt::Horizontal) {
+ /* 2/3
+ +--------------+
+ | CCCCCCCC |
+ | CCCCCCCC |
+ | CCCCCCCC |
+ | CCCCCCCC |
+ | CCCCCCCC |
+ +--------------+ */
+
+ if (x > w/6 && x < w*5/6)
+ return QInternal::DockCount;
+ } else {
+ /*
+ +--------------+
+ | |
+ 2/3 |CCCCCCCCCCCCCC|
+ |CCCCCCCCCCCCCC|
+ | |
+ +--------------+ */
+ if (y > h/6 && y < 5*h/6)
+ return QInternal::DockCount;
+ }
+ }
+
+ // not in the center. which edge?
+ if (nestingEnabled) {
+ if (o == Qt::Horizontal) {
+ /* 1/3 1/3 1/3
+ +------------+ (we've already ruled out the center)
+ |LLLLTTTTRRRR|
+ |LLLLTTTTRRRR|
+ |LLLLBBBBRRRR|
+ |LLLLBBBBRRRR|
+ +------------+ */
+
+ if (x < w/3)
+ return QInternal::LeftDock;
+ if (x > 2*w/3)
+ return QInternal::RightDock;
+ if (y < h/2)
+ return QInternal::TopDock;
+ return QInternal::BottomDock;
+ } else {
+ /* +------------+ (we've already ruled out the center)
+ 1/3 |TTTTTTTTTTTT|
+ |LLLLLLRRRRRR|
+ 1/3 |LLLLLLRRRRRR|
+ 1/3 |BBBBBBBBBBBB|
+ +------------+ */
+
+ if (y < h/3)
+ return QInternal::TopDock;
+ if (y > 2*h/3)
+ return QInternal::BottomDock;
+ if (x < w/2)
+ return QInternal::LeftDock;
+ return QInternal::RightDock;
+ }
+ } else {
+ if (o == Qt::Horizontal) {
+ return x < w/2
+ ? QInternal::LeftDock
+ : QInternal::RightDock;
+ } else {
+ return y < h/2
+ ? QInternal::TopDock
+ : QInternal::BottomDock;
+ }
+ }
+}
+
+QList<int> QDockAreaLayoutInfo::gapIndex(const QPoint& _pos,
+ bool nestingEnabled, TabMode tabMode) const
+{
+ QList<int> result;
+ QRect item_rect;
+ int item_index = 0;
+
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ item_rect = tabContentRect();
+ } else
+#endif
+ {
+ int pos = pick(o, _pos);
+
+ int last = -1;
+ for (int i = 0; i < item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.skip())
+ continue;
+
+ last = i;
+
+ if (item.pos + item.size < pos)
+ continue;
+
+ if (item.subinfo != 0
+#ifndef QT_NO_TABBAR
+ && !item.subinfo->tabbed
+#endif
+ ) {
+ result = item.subinfo->gapIndex(_pos, nestingEnabled,
+ tabMode);
+ result.prepend(i);
+ return result;
+ }
+
+ item_rect = itemRect(i);
+ item_index = i;
+ break;
+ }
+
+ if (item_rect.isNull()) {
+ result.append(last + 1);
+ return result;
+ }
+ }
+
+ Q_ASSERT(!item_rect.isNull());
+
+ QInternal::DockPosition dock_pos
+ = dockPosHelper(item_rect, _pos, o, nestingEnabled, tabMode);
+
+ switch (dock_pos) {
+ case QInternal::LeftDock:
+ if (o == Qt::Horizontal)
+ result << item_index;
+ else
+ result << item_index << 0; // this subinfo doesn't exist yet, but insertGap()
+ // handles this by inserting it
+ break;
+ case QInternal::RightDock:
+ if (o == Qt::Horizontal)
+ result << item_index + 1;
+ else
+ result << item_index << 1;
+ break;
+ case QInternal::TopDock:
+ if (o == Qt::Horizontal)
+ result << item_index << 0;
+ else
+ result << item_index;
+ break;
+ case QInternal::BottomDock:
+ if (o == Qt::Horizontal)
+ result << item_index << 1;
+ else
+ result << item_index + 1;
+ break;
+ case QInternal::DockCount:
+ result << (-item_index - 1) << 0; // negative item_index means "on top of"
+ // -item_index - 1, insertGap()
+ // will insert a tabbed subinfo
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+static inline int shrink(QLayoutStruct &ls, int delta)
+{
+ if (ls.empty)
+ return 0;
+ int old_size = ls.size;
+ ls.size = qMax(ls.size - delta, ls.minimumSize);
+ return old_size - ls.size;
+}
+
+static inline int grow(QLayoutStruct &ls, int delta)
+{
+ if (ls.empty)
+ return 0;
+ int old_size = ls.size;
+ ls.size = qMin(ls.size + delta, ls.maximumSize);
+ return ls.size - old_size;
+}
+
+static int separatorMoveHelper(QVector<QLayoutStruct> &list, int index, int delta, int sep)
+{
+ // adjust sizes
+ int pos = -1;
+ for (int i = 0; i < list.size(); ++i) {
+ const QLayoutStruct &ls = list.at(i);
+ if (!ls.empty) {
+ pos = ls.pos;
+ break;
+ }
+ }
+ if (pos == -1)
+ return 0;
+
+ if (delta > 0) {
+ int growlimit = 0;
+ for (int i = 0; i<=index; ++i) {
+ const QLayoutStruct &ls = list.at(i);
+ if (ls.empty)
+ continue;
+ if (ls.maximumSize == QLAYOUTSIZE_MAX) {
+ growlimit = QLAYOUTSIZE_MAX;
+ break;
+ }
+ growlimit += ls.maximumSize - ls.size;
+ }
+ if (delta > growlimit)
+ delta = growlimit;
+
+ int d = 0;
+ for (int i = index + 1; d < delta && i < list.count(); ++i)
+ d += shrink(list[i], delta - d);
+ delta = d;
+ d = 0;
+ for (int i = index; d < delta && i >= 0; --i)
+ d += grow(list[i], delta - d);
+ } else if (delta < 0) {
+ int growlimit = 0;
+ for (int i = index + 1; i < list.count(); ++i) {
+ const QLayoutStruct &ls = list.at(i);
+ if (ls.empty)
+ continue;
+ if (ls.maximumSize == QLAYOUTSIZE_MAX) {
+ growlimit = QLAYOUTSIZE_MAX;
+ break;
+ }
+ growlimit += ls.maximumSize - ls.size;
+ }
+ if (-delta > growlimit)
+ delta = -growlimit;
+
+ int d = 0;
+ for (int i = index; d < -delta && i >= 0; --i)
+ d += shrink(list[i], -delta - d);
+ delta = -d;
+ d = 0;
+ for (int i = index + 1; d < -delta && i < list.count(); ++i)
+ d += grow(list[i], -delta - d);
+ }
+
+ // adjust positions
+ bool first = true;
+ for (int i = 0; i < list.size(); ++i) {
+ QLayoutStruct &ls = list[i];
+ if (ls.empty) {
+ ls.pos = pos + (first ? 0 : sep);
+ continue;
+ }
+ if (!first)
+ pos += sep;
+ ls.pos = pos;
+ pos += ls.size;
+ first = false;
+ }
+
+ return delta;
+}
+
+int QDockAreaLayoutInfo::separatorMove(int index, int delta)
+{
+#ifndef QT_NO_TABBAR
+ Q_ASSERT(!tabbed);
+#endif
+
+ QVector<QLayoutStruct> list(item_list.size());
+ for (int i = 0; i < list.size(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ QLayoutStruct &ls = list[i];
+ Q_ASSERT(!(item.flags & QDockAreaLayoutItem::GapItem));
+ if (item.skip()) {
+ ls.empty = true;
+ } else {
+ const int separatorSpace = item.hasFixedSize(o) ? 0 : *sep;
+ ls.empty = false;
+ ls.pos = item.pos;
+ ls.size = item.size + separatorSpace;
+ ls.minimumSize = pick(o, item.minimumSize()) + separatorSpace;
+ ls.maximumSize = pick(o, item.maximumSize()) + separatorSpace;
+
+ }
+ }
+
+ //the separator space has been added to the size, so we pass 0 as a parameter
+ delta = separatorMoveHelper(list, index, delta, 0 /*separator*/);
+
+ for (int i = 0; i < list.size(); ++i) {
+ QDockAreaLayoutItem &item = item_list[i];
+ if (item.skip())
+ continue;
+ QLayoutStruct &ls = list[i];
+ const int separatorSpace = item.hasFixedSize(o) ? 0 : *sep;
+ item.size = ls.size - separatorSpace;
+ item.pos = ls.pos;
+ if (item.subinfo != 0) {
+ item.subinfo->rect = itemRect(i);
+ item.subinfo->fitItems();
+ }
+ }
+
+ return delta;
+}
+
+void QDockAreaLayoutInfo::unnest(int index)
+{
+ QDockAreaLayoutItem &item = item_list[index];
+ if (item.subinfo == 0)
+ return;
+ if (item.subinfo->item_list.count() > 1)
+ return;
+
+ if (item.subinfo->item_list.count() == 0) {
+ item_list.removeAt(index);
+ } else if (item.subinfo->item_list.count() == 1) {
+ QDockAreaLayoutItem &child = item.subinfo->item_list.first();
+ if (child.widgetItem != 0) {
+ item.widgetItem = child.widgetItem;
+ delete item.subinfo;
+ item.subinfo = 0;
+ } else if (child.subinfo != 0) {
+ QDockAreaLayoutInfo *tmp = item.subinfo;
+ item.subinfo = child.subinfo;
+ child.subinfo = 0;
+ tmp->item_list.clear();
+ delete tmp;
+ }
+ }
+}
+
+void QDockAreaLayoutInfo::remove(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+
+ if (path.count() > 1) {
+ const int index = path.first();
+ QDockAreaLayoutItem &item = item_list[index];
+ Q_ASSERT(item.subinfo != 0);
+ item.subinfo->remove(path.mid(1));
+ unnest(index);
+ } else {
+ int index = path.first();
+ item_list.removeAt(index);
+ }
+}
+
+QLayoutItem *QDockAreaLayoutInfo::plug(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+
+ int index = path.first();
+ if (index < 0)
+ index = -index - 1;
+
+ if (path.count() > 1) {
+ const QDockAreaLayoutItem &item = item_list.at(index);
+ Q_ASSERT(item.subinfo != 0);
+ return item.subinfo->plug(path.mid(1));
+ }
+
+ QDockAreaLayoutItem &item = item_list[index];
+
+ Q_ASSERT(item.widgetItem != 0);
+ Q_ASSERT(item.flags & QDockAreaLayoutItem::GapItem);
+ item.flags &= ~QDockAreaLayoutItem::GapItem;
+
+ QRect result;
+
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ } else
+#endif
+ {
+ int prev = this->prev(index);
+ int next = this->next(index);
+
+ if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem)) {
+ item.pos += *sep;
+ item.size -= *sep;
+ }
+ if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem))
+ item.size -= *sep;
+
+ QPoint pos;
+ rpick(o, pos) = item.pos;
+ rperp(o, pos) = perp(o, rect.topLeft());
+ QSize s;
+ rpick(o, s) = item.size;
+ rperp(o, s) = perp(o, rect.size());
+ result = QRect(pos, s);
+ }
+
+ return item.widgetItem;
+}
+
+QLayoutItem *QDockAreaLayoutInfo::unplug(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+
+ const int index = path.first();
+ if (path.count() > 1) {
+ const QDockAreaLayoutItem &item = item_list.at(index);
+ Q_ASSERT(item.subinfo != 0);
+ return item.subinfo->unplug(path.mid(1));
+ }
+
+ QDockAreaLayoutItem &item = item_list[index];
+ int prev = this->prev(index);
+ int next = this->next(index);
+
+ Q_ASSERT(!(item.flags & QDockAreaLayoutItem::GapItem));
+ item.flags |= QDockAreaLayoutItem::GapItem;
+
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ } else
+#endif
+ {
+ if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem)) {
+ item.pos -= *sep;
+ item.size += *sep;
+ }
+ if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem))
+ item.size += *sep;
+ }
+
+ return item.widgetItem;
+}
+
+#ifndef QT_NO_TABBAR
+
+quintptr QDockAreaLayoutInfo::currentTabId() const
+{
+ if (!tabbed || tabBar == 0)
+ return 0;
+
+ int index = tabBar->currentIndex();
+ if (index == -1)
+ return 0;
+
+ return qvariant_cast<quintptr>(tabBar->tabData(index));
+}
+
+void QDockAreaLayoutInfo::setCurrentTab(QWidget *widget)
+{
+ setCurrentTabId(reinterpret_cast<quintptr>(widget));
+}
+
+void QDockAreaLayoutInfo::setCurrentTabId(quintptr id)
+{
+ if (!tabbed || tabBar == 0)
+ return;
+
+ for (int i = 0; i < tabBar->count(); ++i) {
+ if (qvariant_cast<quintptr>(tabBar->tabData(i)) == id) {
+ tabBar->setCurrentIndex(i);
+ return;
+ }
+ }
+}
+
+#endif // QT_NO_TABBAR
+
+static QRect dockedGeometry(QWidget *widget)
+{
+ int titleHeight = 0;
+
+ QDockWidgetLayout *layout
+ = qobject_cast<QDockWidgetLayout*>(widget->layout());
+ if(layout != 0 && layout->nativeWindowDeco())
+ titleHeight = layout->titleHeight();
+
+ QRect result = widget->geometry();
+ result.adjust(0, -titleHeight, 0, 0);
+ return result;
+}
+
+bool QDockAreaLayoutInfo::insertGap(const QList<int> &path, QLayoutItem *dockWidgetItem)
+{
+ Q_ASSERT(!path.isEmpty());
+
+ bool insert_tabbed = false;
+ int index = path.first();
+ if (index < 0) {
+ insert_tabbed = true;
+ index = -index - 1;
+ }
+
+// dump(qDebug() << "insertGap() before:" << index << tabIndex, *this, QString());
+
+ if (path.count() > 1) {
+ QDockAreaLayoutItem &item = item_list[index];
+
+ if (item.subinfo == 0
+#ifndef QT_NO_TABBAR
+ || (item.subinfo->tabbed && !insert_tabbed)
+#endif
+ ) {
+
+ // this is not yet a nested layout - make it
+
+ QDockAreaLayoutInfo *subinfo = item.subinfo;
+ QLayoutItem *widgetItem = item.widgetItem;
+ QPlaceHolderItem *placeHolderItem = item.placeHolderItem;
+ QRect r = subinfo == 0 ? widgetItem ? dockedGeometry(widgetItem->widget()) : placeHolderItem->topLevelRect : subinfo->rect;
+
+ Qt::Orientation opposite = o == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal;
+#ifdef QT_NO_TABBAR
+ const int tabBarShape = 0;
+#endif
+ QDockAreaLayoutInfo *new_info
+ = new QDockAreaLayoutInfo(sep, dockPos, opposite, tabBarShape, mainWindow);
+
+ //item become a new top-level
+ item.subinfo = new_info;
+ item.widgetItem = 0;
+ item.placeHolderItem = 0;
+
+ QDockAreaLayoutItem new_item
+ = widgetItem == 0
+ ? QDockAreaLayoutItem(subinfo)
+ : widgetItem ? QDockAreaLayoutItem(widgetItem) : QDockAreaLayoutItem(placeHolderItem);
+ new_item.size = pick(opposite, r.size());
+ new_item.pos = pick(opposite, r.topLeft());
+ new_info->item_list.append(new_item);
+#ifndef QT_NO_TABBAR
+ if (insert_tabbed) {
+ new_info->tabbed = true;
+ }
+#endif
+ }
+
+ return item.subinfo->insertGap(path.mid(1), dockWidgetItem);
+ }
+
+ // create the gap item
+ QDockAreaLayoutItem gap_item;
+ gap_item.flags |= QDockAreaLayoutItem::GapItem;
+ gap_item.widgetItem = dockWidgetItem; // so minimumSize(), maximumSize() and
+ // sizeHint() will work
+#ifndef QT_NO_TABBAR
+ if (!tabbed)
+#endif
+ {
+ int prev = this->prev(index);
+ int next = this->next(index - 1);
+ // find out how much space we have in the layout
+ int space = 0;
+ if (isEmpty()) {
+ // I am an empty dock area, therefore I am a top-level dock area.
+ switch (dockPos) {
+ case QInternal::LeftDock:
+ case QInternal::RightDock:
+ if (o == Qt::Vertical) {
+ // the "size" is the height of the dock area (remember we are empty)
+ space = pick(Qt::Vertical, rect.size());
+ } else {
+ space = pick(Qt::Horizontal, dockWidgetItem->widget()->size());
+ }
+ break;
+ case QInternal::TopDock:
+ case QInternal::BottomDock:
+ default:
+ if (o == Qt::Horizontal) {
+ // the "size" is width of the dock area
+ space = pick(Qt::Horizontal, rect.size());
+ } else {
+ space = pick(Qt::Vertical, dockWidgetItem->widget()->size());
+ }
+ break;
+ }
+ } else {
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.skip())
+ continue;
+ Q_ASSERT(!(item.flags & QDockAreaLayoutItem::GapItem));
+ space += item.size - pick(o, item.minimumSize());
+ }
+ }
+
+ // find the actual size of the gap
+ int gap_size = 0;
+ int sep_size = 0;
+ if (isEmpty()) {
+ gap_size = space;
+ sep_size = 0;
+ } else {
+ QRect r = dockedGeometry(dockWidgetItem->widget());
+ gap_size = pick(o, r.size());
+ if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem))
+ sep_size += *sep;
+ if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem))
+ sep_size += *sep;
+ }
+ if (gap_size + sep_size > space)
+ gap_size = pick(o, gap_item.minimumSize());
+ gap_item.size = gap_size + sep_size;
+ }
+
+ // finally, insert the gap
+ item_list.insert(index, gap_item);
+
+// dump(qDebug() << "insertGap() after:" << index << tabIndex, *this, QString());
+
+ return true;
+}
+
+QDockAreaLayoutInfo *QDockAreaLayoutInfo::info(QWidget *widget)
+{
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.skip())
+ continue;
+
+#ifndef QT_NO_TABBAR
+ if (tabbed && widget == tabBar)
+ return this;
+#endif
+
+ if (item.widgetItem != 0 && item.widgetItem->widget() == widget)
+ return this;
+
+ if (item.subinfo != 0) {
+ if (QDockAreaLayoutInfo *result = item.subinfo->info(widget))
+ return result;
+ }
+ }
+
+ return 0;
+}
+
+QDockAreaLayoutInfo *QDockAreaLayoutInfo::info(const QList<int> &path)
+{
+ int index = path.first();
+ if (index < 0)
+ index = -index - 1;
+ if (index >= item_list.count())
+ return this;
+ if (path.count() == 1 || item_list[index].subinfo == 0)
+ return this;
+ return item_list[index].subinfo->info(path.mid(1));
+}
+
+QRect QDockAreaLayoutInfo::itemRect(int index) const
+{
+ const QDockAreaLayoutItem &item = item_list.at(index);
+
+ if (item.skip())
+ return QRect();
+
+ QRect result;
+
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ if (tabId(item) == currentTabId())
+ result = tabContentRect();
+ } else
+#endif
+ {
+ QPoint pos;
+ rpick(o, pos) = item.pos;
+ rperp(o, pos) = perp(o, rect.topLeft());
+ QSize s;
+ rpick(o, s) = item.size;
+ rperp(o, s) = perp(o, rect.size());
+ result = QRect(pos, s);
+ }
+
+ return result;
+}
+
+QRect QDockAreaLayoutInfo::itemRect(const QList<int> &path) const
+{
+ Q_ASSERT(!path.isEmpty());
+
+ const int index = path.first();
+ if (path.count() > 1) {
+ const QDockAreaLayoutItem &item = item_list.at(index);
+ Q_ASSERT(item.subinfo != 0);
+ return item.subinfo->itemRect(path.mid(1));
+ }
+
+ return itemRect(index);
+}
+
+QRect QDockAreaLayoutInfo::separatorRect(int index) const
+{
+#ifndef QT_NO_TABBAR
+ if (tabbed)
+ return QRect();
+#endif
+
+ const QDockAreaLayoutItem &item = item_list.at(index);
+ if (item.skip())
+ return QRect();
+
+ QPoint pos = rect.topLeft();
+ rpick(o, pos) = item.pos + item.size;
+ QSize s = rect.size();
+ rpick(o, s) = *sep;
+
+ return QRect(pos, s);
+}
+
+QRect QDockAreaLayoutInfo::separatorRect(const QList<int> &path) const
+{
+ Q_ASSERT(!path.isEmpty());
+
+ const int index = path.first();
+ if (path.count() > 1) {
+ const QDockAreaLayoutItem &item = item_list.at(index);
+ Q_ASSERT(item.subinfo != 0);
+ return item.subinfo->separatorRect(path.mid(1));
+ }
+ return separatorRect(index);
+}
+
+QList<int> QDockAreaLayoutInfo::findSeparator(const QPoint &_pos) const
+{
+#ifndef QT_NO_TABBAR
+ if (tabbed)
+ return QList<int>();
+#endif
+
+ int pos = pick(o, _pos);
+
+ for (int i = 0; i < item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.skip() || (item.flags & QDockAreaLayoutItem::GapItem))
+ continue;
+
+ if (item.pos + item.size > pos) {
+ if (item.subinfo != 0) {
+ QList<int> result = item.subinfo->findSeparator(_pos);
+ if (!result.isEmpty()) {
+ result.prepend(i);
+ return result;
+ } else {
+ return QList<int>();
+ }
+ }
+ }
+
+ int next = this->next(i);
+ if (next == -1 || (item_list.at(next).flags & QDockAreaLayoutItem::GapItem))
+ continue;
+
+ QRect sepRect = separatorRect(i);
+ if (!sepRect.isNull() && *sep == 1)
+ sepRect.adjust(-2, -2, 2, 2);
+ //we also make sure we don't find a separator that's not there
+ if (sepRect.contains(_pos) && !item.hasFixedSize(o)) {
+ return QList<int>() << i;
+ }
+
+ }
+
+ return QList<int>();
+}
+
+QList<int> QDockAreaLayoutInfo::indexOfPlaceHolder(const QString &objectName) const
+{
+ for (int i = 0; i < item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+
+ if (item.subinfo != 0) {
+ QList<int> result = item.subinfo->indexOfPlaceHolder(objectName);
+ if (!result.isEmpty()) {
+ result.prepend(i);
+ return result;
+ }
+ continue;
+ }
+
+ if (item.placeHolderItem != 0 && item.placeHolderItem->objectName == objectName) {
+ QList<int> result;
+ result << i;
+ return result;
+ }
+ }
+
+ return QList<int>();
+}
+
+QList<int> QDockAreaLayoutInfo::indexOf(QWidget *widget) const
+{
+ for (int i = 0; i < item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+
+ if (item.placeHolderItem != 0)
+ continue;
+
+ if (item.subinfo != 0) {
+ QList<int> result = item.subinfo->indexOf(widget);
+ if (!result.isEmpty()) {
+ result.prepend(i);
+ return result;
+ }
+ continue;
+ }
+
+ if (!(item.flags & QDockAreaLayoutItem::GapItem) && item.widgetItem->widget() == widget) {
+ QList<int> result;
+ result << i;
+ return result;
+ }
+ }
+
+ return QList<int>();
+}
+
+QMainWindowLayout *QDockAreaLayoutInfo::mainWindowLayout() const
+{
+ QMainWindowLayout *result = qt_mainwindow_layout(mainWindow);
+ Q_ASSERT(result != 0);
+ return result;
+}
+
+bool QDockAreaLayoutInfo::hasFixedSize() const
+{
+ return perp(o, minimumSize()) == perp(o, maximumSize());
+}
+
+
+void QDockAreaLayoutInfo::apply(bool animate)
+{
+ QWidgetAnimator &widgetAnimator = mainWindowLayout()->widgetAnimator;
+
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ QRect tab_rect;
+ QSize tbh = tabBarSizeHint();
+
+ if (!tbh.isNull()) {
+ switch (tabBarShape) {
+ case QTabBar::RoundedNorth:
+ case QTabBar::TriangularNorth:
+ tab_rect = QRect(rect.left(), rect.top(), rect.width(), tbh.height());
+ break;
+ case QTabBar::RoundedSouth:
+ case QTabBar::TriangularSouth:
+ tab_rect = QRect(rect.left(), rect.bottom() - tbh.height() + 1,
+ rect.width(), tbh.height());
+ break;
+ case QTabBar::RoundedEast:
+ case QTabBar::TriangularEast:
+ tab_rect = QRect(rect.right() - tbh.width() + 1, rect.top(),
+ tbh.width(), rect.height());
+ break;
+ case QTabBar::RoundedWest:
+ case QTabBar::TriangularWest:
+ tab_rect = QRect(rect.left(), rect.top(),
+ tbh.width(), rect.height());
+ break;
+ default:
+ break;
+ }
+ }
+
+ widgetAnimator.animate(tabBar, tab_rect, animate);
+ }
+#endif // QT_NO_TABBAR
+
+ for (int i = 0; i < item_list.size(); ++i) {
+ QDockAreaLayoutItem &item = item_list[i];
+
+ if (item.flags & QDockAreaLayoutItem::GapItem)
+ continue;
+
+ if (item.subinfo != 0) {
+ item.subinfo->apply(animate);
+ continue;
+ }
+
+ if (item.skip())
+ continue;
+
+ Q_ASSERT(item.widgetItem);
+ QRect r = itemRect(i);
+ QWidget *w = item.widgetItem->widget();
+
+ QRect geo = w->geometry();
+ widgetAnimator.animate(w, r, animate);
+ if (!w->isHidden() && w->window()->isVisible()) {
+ QDockWidget *dw = qobject_cast<QDockWidget*>(w);
+ if (!r.isValid() && geo.right() >= 0 && geo.bottom() >= 0) {
+ dw->lower();
+ emit dw->visibilityChanged(false);
+ } else if (r.isValid()
+ && (geo.right() < 0 || geo.bottom() < 0)) {
+ emit dw->visibilityChanged(true);
+ }
+ }
+ }
+#ifndef QT_NO_TABBAR
+ if (*sep == 1)
+ updateSeparatorWidgets();
+#endif //QT_NO_TABBAR
+}
+
+static void paintSep(QPainter *p, QWidget *w, const QRect &r, Qt::Orientation o, bool mouse_over)
+{
+ QStyleOption opt(0);
+ opt.state = QStyle::State_None;
+ if (w->isEnabled())
+ opt.state |= QStyle::State_Enabled;
+ if (o != Qt::Horizontal)
+ opt.state |= QStyle::State_Horizontal;
+ if (mouse_over)
+ opt.state |= QStyle::State_MouseOver;
+ opt.rect = r;
+ opt.palette = w->palette();
+
+ w->style()->drawPrimitive(QStyle::PE_IndicatorDockWidgetResizeHandle, &opt, p, w);
+}
+
+QRegion QDockAreaLayoutInfo::separatorRegion() const
+{
+ QRegion result;
+
+ if (isEmpty())
+ return result;
+#ifndef QT_NO_TABBAR
+ if (tabbed)
+ return result;
+#endif
+
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+
+ if (item.skip())
+ continue;
+
+ int next = this->next(i);
+
+ if (item.subinfo)
+ result |= item.subinfo->separatorRegion();
+
+ if (next == -1)
+ break;
+ result |= separatorRect(i);
+ }
+
+ return result;
+}
+
+void QDockAreaLayoutInfo::paintSeparators(QPainter *p, QWidget *widget,
+ const QRegion &clip,
+ const QPoint &mouse) const
+{
+ if (isEmpty())
+ return;
+#ifndef QT_NO_TABBAR
+ if (tabbed)
+ return;
+#endif
+
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+
+ if (item.skip())
+ continue;
+
+ int next = this->next(i);
+ if ((item.flags & QDockAreaLayoutItem::GapItem)
+ || (next != -1 && (item_list.at(next).flags & QDockAreaLayoutItem::GapItem)))
+ continue;
+
+ if (item.subinfo) {
+ if (clip.contains(item.subinfo->rect))
+ item.subinfo->paintSeparators(p, widget, clip, mouse);
+ }
+
+ if (next == -1)
+ break;
+ QRect r = separatorRect(i);
+ if (clip.contains(r) && !item.hasFixedSize(o))
+ paintSep(p, widget, r, o, r.contains(mouse));
+ }
+}
+
+int QDockAreaLayoutInfo::next(int index) const
+{
+ for (int i = index + 1; i < item_list.size(); ++i) {
+ if (!item_list.at(i).skip())
+ return i;
+ }
+ return -1;
+}
+
+int QDockAreaLayoutInfo::prev(int index) const
+{
+ for (int i = index - 1; i >= 0; --i) {
+ if (!item_list.at(i).skip())
+ return i;
+ }
+ return -1;
+}
+
+void QDockAreaLayoutInfo::tab(int index, QLayoutItem *dockWidgetItem)
+{
+#ifdef QT_NO_TABBAR
+ Q_UNUSED(index);
+ Q_UNUSED(dockWidgetItem);
+#else
+ if (tabbed) {
+ item_list.append(QDockAreaLayoutItem(dockWidgetItem));
+ updateTabBar();
+ setCurrentTab(dockWidgetItem->widget());
+ } else {
+ QDockAreaLayoutInfo *new_info
+ = new QDockAreaLayoutInfo(sep, dockPos, o, tabBarShape, mainWindow);
+ item_list[index].subinfo = new_info;
+ new_info->item_list.append(item_list.at(index).widgetItem);
+ item_list[index].widgetItem = 0;
+ new_info->item_list.append(dockWidgetItem);
+ new_info->tabbed = true;
+ new_info->updateTabBar();
+ new_info->setCurrentTab(dockWidgetItem->widget());
+ }
+#endif // QT_NO_TABBAR
+}
+
+void QDockAreaLayoutInfo::split(int index, Qt::Orientation orientation,
+ QLayoutItem *dockWidgetItem)
+{
+ if (orientation == o) {
+ item_list.insert(index + 1, QDockAreaLayoutItem(dockWidgetItem));
+ } else {
+#ifdef QT_NO_TABBAR
+ const int tabBarShape = 0;
+#endif
+ QDockAreaLayoutInfo *new_info
+ = new QDockAreaLayoutInfo(sep, dockPos, orientation, tabBarShape, mainWindow);
+ item_list[index].subinfo = new_info;
+ new_info->item_list.append(item_list.at(index).widgetItem);
+ item_list[index].widgetItem = 0;
+ new_info->item_list.append(dockWidgetItem);
+ }
+}
+
+QDockAreaLayoutItem &QDockAreaLayoutInfo::item(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+ const int index = path.first();
+ if (path.count() > 1) {
+ const QDockAreaLayoutItem &item = item_list[index];
+ Q_ASSERT(item.subinfo != 0);
+ return item.subinfo->item(path.mid(1));
+ }
+ return item_list[index];
+}
+
+QLayoutItem *QDockAreaLayoutInfo::itemAt(int *x, int index) const
+{
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.placeHolderItem != 0)
+ continue;
+ if (item.subinfo) {
+ if (QLayoutItem *ret = item.subinfo->itemAt(x, index))
+ return ret;
+ } else if (item.widgetItem) {
+ if ((*x)++ == index)
+ return item.widgetItem;
+ }
+ }
+ return 0;
+}
+
+QLayoutItem *QDockAreaLayoutInfo::takeAt(int *x, int index)
+{
+ for (int i = 0; i < item_list.count(); ++i) {
+ QDockAreaLayoutItem &item = item_list[i];
+ if (item.placeHolderItem != 0)
+ continue;
+ else if (item.subinfo) {
+ if (QLayoutItem *ret = item.subinfo->takeAt(x, index)) {
+ unnest(i);
+ return ret;
+ }
+ } else if (item.widgetItem) {
+ if ((*x)++ == index) {
+ item.placeHolderItem = new QPlaceHolderItem(item.widgetItem->widget());
+ QLayoutItem *ret = item.widgetItem;
+ item.widgetItem = 0;
+ if (item.size != -1)
+ item.flags |= QDockAreaLayoutItem::KeepSize;
+ return ret;
+ }
+ }
+ }
+ return 0;
+}
+
+void QDockAreaLayoutInfo::deleteAllLayoutItems()
+{
+ for (int i = 0; i < item_list.count(); ++i) {
+ QDockAreaLayoutItem &item= item_list[i];
+ if (item.subinfo) {
+ item.subinfo->deleteAllLayoutItems();
+ } else {
+ delete item.widgetItem;
+ item.widgetItem = 0;
+ }
+ }
+}
+
+void QDockAreaLayoutInfo::saveState(QDataStream &stream) const
+{
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ stream << (uchar) TabMarker;
+
+ // write the index in item_list of the widget that's currently on top.
+ quintptr id = currentTabId();
+ int index = -1;
+ for (int i = 0; i < item_list.count(); ++i) {
+ if (tabId(item_list.at(i)) == id) {
+ index = i;
+ break;
+ }
+ }
+ stream << index;
+ } else
+#endif // QT_NO_TABBAR
+ {
+ stream << (uchar) SequenceMarker;
+ }
+
+ stream << (uchar) o << item_list.count();
+
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.widgetItem != 0) {
+ stream << (uchar) WidgetMarker;
+ QWidget *w = item.widgetItem->widget();
+ QString name = w->objectName();
+ if (name.isEmpty()) {
+ qWarning("QMainWindow::saveState(): 'objectName' not set for QDockWidget %p '%s;",
+ w, qPrintable(w->windowTitle()));
+ }
+ stream << name;
+
+ uchar flags = 0;
+ if (!w->isHidden())
+ flags |= StateFlagVisible;
+ if (w->isWindow())
+ flags |= StateFlagFloating;
+ stream << flags;
+
+ if (w->isWindow()) {
+ stream << w->x() << w->y() << w->width() << w->height();
+ } else {
+ stream << item.pos << item.size << pick(o, item.minimumSize())
+ << pick(o, item.maximumSize());
+ }
+ } else if (item.placeHolderItem != 0) {
+ stream << (uchar) WidgetMarker;
+ stream << item.placeHolderItem->objectName;
+ uchar flags = 0;
+ if (!item.placeHolderItem->hidden)
+ flags |= StateFlagVisible;
+ if (item.placeHolderItem->window)
+ flags |= StateFlagFloating;
+ stream << flags;
+ if (item.placeHolderItem->window) {
+ QRect r = item.placeHolderItem->topLevelRect;
+ stream << r.x() << r.y() << r.width() << r.height();
+ } else {
+ stream << item.pos << item.size << (int)0 << (int)0;
+ }
+ } else if (item.subinfo != 0) {
+ stream << (uchar) SequenceMarker << item.pos << item.size << pick(o, item.minimumSize()) << pick(o, item.maximumSize());
+ item.subinfo->saveState(stream);
+ }
+ }
+}
+
+static Qt::DockWidgetArea toDockWidgetArea(QInternal::DockPosition pos)
+{
+ switch (pos) {
+ case QInternal::LeftDock: return Qt::LeftDockWidgetArea;
+ case QInternal::RightDock: return Qt::RightDockWidgetArea;
+ case QInternal::TopDock: return Qt::TopDockWidgetArea;
+ case QInternal::BottomDock: return Qt::BottomDockWidgetArea;
+ default: break;
+ }
+ return Qt::NoDockWidgetArea;
+}
+
+static QRect constrainedRect(QRect rect, const QRect &desktop)
+{
+ if (desktop.isValid()) {
+ rect.setWidth(qMin(rect.width(), desktop.width()));
+ rect.setHeight(qMin(rect.height(), desktop.height()));
+ rect.moveLeft(qMax(rect.left(), desktop.left()));
+ rect.moveTop(qMax(rect.top(), desktop.top()));
+ rect.moveRight(qMin(rect.right(), desktop.right()));
+ rect.moveBottom(qMin(rect.bottom(), desktop.bottom()));
+ }
+
+ return rect;
+}
+
+bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList<QDockWidget*> &widgets, bool testing)
+{
+ uchar marker;
+ stream >> marker;
+ if (marker != TabMarker && marker != SequenceMarker)
+ return false;
+
+#ifndef QT_NO_TABBAR
+ tabbed = marker == TabMarker;
+
+ int index = -1;
+ if (tabbed)
+ stream >> index;
+#endif
+
+ uchar orientation;
+ stream >> orientation;
+ o = static_cast<Qt::Orientation>(orientation);
+
+ int cnt;
+ stream >> cnt;
+
+ for (int i = 0; i < cnt; ++i) {
+ uchar nextMarker;
+ stream >> nextMarker;
+ if (nextMarker == WidgetMarker) {
+ QString name;
+ uchar flags;
+ stream >> name >> flags;
+ if (name.isEmpty()) {
+ int dummy;
+ stream >> dummy >> dummy >> dummy >> dummy;
+ continue;
+ }
+
+ QDockWidget *widget = 0;
+ for (int j = 0; j < widgets.count(); ++j) {
+ if (widgets.at(j)->objectName() == name) {
+ widget = widgets.takeAt(j);
+ break;
+ }
+ }
+
+ if (widget == 0) {
+ QPlaceHolderItem *placeHolder = new QPlaceHolderItem;
+ QDockAreaLayoutItem item(placeHolder);
+
+ placeHolder->objectName = name;
+ placeHolder->window = flags & StateFlagFloating;
+ placeHolder->hidden = !(flags & StateFlagVisible);
+ if (placeHolder->window) {
+ int x, y, w, h;
+ stream >> x >> y >> w >> h;
+ placeHolder->topLevelRect = QRect(x, y, w, h);
+ } else {
+ int dummy;
+ stream >> item.pos >> item.size >> dummy >> dummy;
+ }
+ if (item.size != -1)
+ item.flags |= QDockAreaLayoutItem::KeepSize;
+ if (!testing)
+ item_list.append(item);
+ } else {
+ QDockAreaLayoutItem item(new QDockWidgetItem(widget));
+ if (flags & StateFlagFloating) {
+ bool drawer = false;
+#ifdef Q_WS_MAC // drawer support
+ extern bool qt_mac_is_macdrawer(const QWidget *); //qwidget_mac.cpp
+ extern bool qt_mac_set_drawer_preferred_edge(QWidget *, Qt::DockWidgetArea); //qwidget_mac.cpp
+ drawer = qt_mac_is_macdrawer(widget);
+#endif
+
+ if (!testing) {
+ widget->hide();
+ if (!drawer)
+ widget->setFloating(true);
+ }
+
+ int x, y, w, h;
+ stream >> x >> y >> w >> h;
+
+#ifdef Q_WS_MAC // drawer support
+ if (drawer) {
+ mainWindow->window()->createWinId();
+ widget->window()->createWinId();
+ qt_mac_set_drawer_preferred_edge(widget, toDockWidgetArea(dockPos));
+ } else
+#endif
+ if (!testing) {
+ QRect r(x, y, w, h);
+ QDesktopWidget *desktop = QApplication::desktop();
+ if (desktop->isVirtualDesktop())
+ r = constrainedRect(r, desktop->screenGeometry(desktop->screenNumber(r.topLeft())));
+ else
+ r = constrainedRect(r, desktop->screenGeometry(widget));
+ widget->move(r.topLeft());
+ widget->resize(r.size());
+ }
+
+ if (!testing) {
+ widget->setVisible(flags & StateFlagVisible);
+ item_list.append(item);
+ }
+ } else {
+ int dummy;
+ stream >> item.pos >> item.size >> dummy >> dummy;
+ if (!testing) {
+ item_list.append(item);
+ widget->setFloating(false);
+ widget->setVisible(flags & StateFlagVisible);
+ emit widget->dockLocationChanged(toDockWidgetArea(dockPos));
+ }
+ }
+ if (testing) {
+ //was it is not really added to the layout, we need to delete the object here
+ delete item.widgetItem;
+ }
+ }
+ } else if (nextMarker == SequenceMarker) {
+ int dummy;
+#ifdef QT_NO_TABBAR
+ const int tabBarShape = 0;
+#endif
+ QDockAreaLayoutItem item(new QDockAreaLayoutInfo(sep, dockPos, o,
+ tabBarShape, mainWindow));
+ stream >> item.pos >> item.size >> dummy >> dummy;
+ //we need to make sure the element is in the list so the dock widget can eventually be docked correctly
+ if (!testing)
+ item_list.append(item);
+
+ //here we need to make sure we change the item in the item_list
+ QDockAreaLayoutItem &lastItem = testing ? item : item_list.last();
+
+ if (!lastItem.subinfo->restoreState(stream, widgets, testing))
+ return false;
+
+ } else {
+ return false;
+ }
+ }
+
+#ifndef QT_NO_TABBAR
+ if (!testing && tabbed && index >= 0 && index < item_list.count()) {
+ updateTabBar();
+ setCurrentTabId(tabId(item_list.at(index)));
+ }
+ if (!testing && *sep == 1)
+ updateSeparatorWidgets();
+#endif
+
+ return true;
+}
+
+#ifndef QT_NO_TABBAR
+void QDockAreaLayoutInfo::updateSeparatorWidgets() const
+{
+ if (tabbed) {
+ separatorWidgets.clear();
+ return;
+ }
+
+ int j = 0;
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+
+ if (item.skip())
+ continue;
+
+ int next = this->next(i);
+ if ((item.flags & QDockAreaLayoutItem::GapItem)
+ || (next != -1 && (item_list.at(next).flags & QDockAreaLayoutItem::GapItem)))
+ continue;
+
+ if (item.subinfo) {
+ item.subinfo->updateSeparatorWidgets();
+ }
+
+ if (next == -1)
+ break;
+
+ QWidget *sepWidget;
+ if (j < separatorWidgets.size() && separatorWidgets.at(j)) {
+ sepWidget = separatorWidgets.at(j);
+ } else {
+ sepWidget = mainWindowLayout()->getSeparatorWidget();
+ separatorWidgets.append(sepWidget);
+ }
+ j++;
+
+#ifndef QT_MAC_USE_COCOA
+ sepWidget->raise();
+#endif
+ QRect sepRect = separatorRect(i).adjusted(-2, -2, 2, 2);
+ sepWidget->setGeometry(sepRect);
+ sepWidget->setMask( QRegion(separatorRect(i).translated( - sepRect.topLeft())));
+ sepWidget->show();
+ }
+
+ for (int k = j; k < separatorWidgets.size(); ++k) {
+ separatorWidgets[k]->hide();
+ }
+ separatorWidgets.resize(j);
+ Q_ASSERT(separatorWidgets.size() == j);
+}
+#endif //QT_NO_TABBAR
+
+#ifndef QT_NO_TABBAR
+//returns whether the tabbar is visible or not
+bool QDockAreaLayoutInfo::updateTabBar() const
+{
+ if (!tabbed)
+ return false;
+
+ QDockAreaLayoutInfo *that = const_cast<QDockAreaLayoutInfo*>(this);
+
+ if (that->tabBar == 0) {
+ that->tabBar = mainWindowLayout()->getTabBar();
+ that->tabBar->setShape(static_cast<QTabBar::Shape>(tabBarShape));
+ that->tabBar->setDrawBase(true);
+ }
+
+ bool blocked = tabBar->blockSignals(true);
+ bool gap = false;
+
+ int tab_idx = 0;
+ bool changed = false;
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.skip())
+ continue;
+ if (item.flags & QDockAreaLayoutItem::GapItem) {
+ gap = true;
+ continue;
+ }
+ if (item.widgetItem == 0)
+ continue;
+
+ QDockWidget *dw = qobject_cast<QDockWidget*>(item.widgetItem->widget());
+ QString title = dw->d_func()->fixedWindowTitle;
+ quintptr id = tabId(item);
+ if (tab_idx == tabBar->count()) {
+ tabBar->insertTab(tab_idx, title);
+#ifndef QT_NO_TOOLTIP
+ tabBar->setTabToolTip(tab_idx, title);
+#endif
+ tabBar->setTabData(tab_idx, id);
+ changed = true;
+ } else if (qvariant_cast<quintptr>(tabBar->tabData(tab_idx)) != id) {
+ if (tab_idx + 1 < tabBar->count()
+ && qvariant_cast<quintptr>(tabBar->tabData(tab_idx + 1)) == id)
+ tabBar->removeTab(tab_idx);
+ else {
+ tabBar->insertTab(tab_idx, title);
+#ifndef QT_NO_TOOLTIP
+ tabBar->setTabToolTip(tab_idx, title);
+#endif
+ tabBar->setTabData(tab_idx, id);
+ }
+ changed = true;
+ }
+
+ if (title != tabBar->tabText(tab_idx)) {
+ tabBar->setTabText(tab_idx, title);
+#ifndef QT_NO_TOOLTIP
+ tabBar->setTabToolTip(tab_idx, title);
+#endif
+ changed = true;
+ }
+
+ ++tab_idx;
+ }
+
+ while (tab_idx < tabBar->count()) {
+ tabBar->removeTab(tab_idx);
+ changed = true;
+ }
+
+ tabBar->blockSignals(blocked);
+
+ //returns if the tabbar is visible or not
+ return ( (gap ? 1 : 0) + tabBar->count()) > 1;
+}
+
+void QDockAreaLayoutInfo::setTabBarShape(int shape)
+{
+ if (shape == tabBarShape)
+ return;
+ tabBarShape = shape;
+ if (tabBar != 0)
+ tabBar->setShape(static_cast<QTabBar::Shape>(shape));
+
+ for (int i = 0; i < item_list.count(); ++i) {
+ QDockAreaLayoutItem &item = item_list[i];
+ if (item.subinfo != 0)
+ item.subinfo->setTabBarShape(shape);
+ }
+}
+
+QSize QDockAreaLayoutInfo::tabBarMinimumSize() const
+{
+ if (!updateTabBar())
+ return QSize(0, 0);
+
+ return tabBar->minimumSizeHint();
+}
+
+QSize QDockAreaLayoutInfo::tabBarSizeHint() const
+{
+ if (!updateTabBar())
+ return QSize(0, 0);
+
+ return tabBar->sizeHint();
+}
+
+QSet<QTabBar*> QDockAreaLayoutInfo::usedTabBars() const
+{
+ QSet<QTabBar*> result;
+
+ if (tabbed) {
+ updateTabBar();
+ result.insert(tabBar);
+ }
+
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.subinfo != 0)
+ result += item.subinfo->usedTabBars();
+ }
+
+ return result;
+}
+
+// returns a set of all used separator widgets for this dockarelayout info
+// and all subinfos
+QSet<QWidget*> QDockAreaLayoutInfo::usedSeparatorWidgets() const
+{
+ QSet<QWidget*> result;
+
+ for (int i = 0; i < separatorWidgets.count(); ++i)
+ result << separatorWidgets.at(i);
+
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.subinfo != 0)
+ result += item.subinfo->usedSeparatorWidgets();
+ }
+
+ return result;
+}
+
+QRect QDockAreaLayoutInfo::tabContentRect() const
+{
+ if (!tabbed)
+ return QRect();
+
+ QRect result = rect;
+ QSize tbh = tabBarSizeHint();
+
+ if (!tbh.isNull()) {
+ switch (tabBarShape) {
+ case QTabBar::RoundedNorth:
+ case QTabBar::TriangularNorth:
+ result.adjust(0, tbh.height(), 0, 0);
+ break;
+ case QTabBar::RoundedSouth:
+ case QTabBar::TriangularSouth:
+ result.adjust(0, 0, 0, -tbh.height());
+ break;
+ case QTabBar::RoundedEast:
+ case QTabBar::TriangularEast:
+ result.adjust(0, 0, -tbh.width(), 0);
+ break;
+ case QTabBar::RoundedWest:
+ case QTabBar::TriangularWest:
+ result.adjust(tbh.width(), 0, 0, 0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return result;
+}
+#endif // QT_NO_TABBAR
+
+/******************************************************************************
+** QDockAreaLayout
+*/
+
+QDockAreaLayout::QDockAreaLayout(QMainWindow *win) : fallbackToSizeHints(true)
+{
+ mainWindow = win;
+ sep = win->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent, 0, win);
+#ifndef QT_NO_TABBAR
+ const int tabShape = QTabBar::RoundedSouth;
+#else
+ const int tabShape = 0;
+#endif
+ docks[QInternal::LeftDock]
+ = QDockAreaLayoutInfo(&sep, QInternal::LeftDock, Qt::Vertical, tabShape, win);
+ docks[QInternal::RightDock]
+ = QDockAreaLayoutInfo(&sep, QInternal::RightDock, Qt::Vertical, tabShape, win);
+ docks[QInternal::TopDock]
+ = QDockAreaLayoutInfo(&sep, QInternal::TopDock, Qt::Horizontal, tabShape, win);
+ docks[QInternal::BottomDock]
+ = QDockAreaLayoutInfo(&sep, QInternal::BottomDock, Qt::Horizontal, tabShape, win);
+ centralWidgetItem = 0;
+
+
+ corners[Qt::TopLeftCorner] = Qt::TopDockWidgetArea;
+ corners[Qt::TopRightCorner] = Qt::TopDockWidgetArea;
+ corners[Qt::BottomLeftCorner] = Qt::BottomDockWidgetArea;
+ corners[Qt::BottomRightCorner] = Qt::BottomDockWidgetArea;
+}
+
+bool QDockAreaLayout::isValid() const
+{
+ return rect.isValid();
+}
+
+void QDockAreaLayout::saveState(QDataStream &stream) const
+{
+ stream << (uchar) DockWidgetStateMarker;
+ int cnt = 0;
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ if (!docks[i].item_list.isEmpty())
+ ++cnt;
+ }
+ stream << cnt;
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ if (docks[i].item_list.isEmpty())
+ continue;
+ stream << i << docks[i].rect.size();
+ docks[i].saveState(stream);
+ }
+
+ stream << centralWidgetRect.size();
+
+ for (int i = 0; i < 4; ++i)
+ stream << static_cast<int>(corners[i]);
+}
+
+bool QDockAreaLayout::restoreState(QDataStream &stream, const QList<QDockWidget*> &_dockwidgets, bool testing)
+{
+ QList<QDockWidget*> dockwidgets = _dockwidgets;
+
+ int cnt;
+ stream >> cnt;
+ for (int i = 0; i < cnt; ++i) {
+ int pos;
+ stream >> pos;
+ QSize size;
+ stream >> size;
+ if (!testing) {
+ docks[pos].rect = QRect(QPoint(0, 0), size);
+ }
+ if (!docks[pos].restoreState(stream, dockwidgets, testing)) {
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return false;
+ }
+ }
+
+ QSize size;
+ stream >> size;
+ centralWidgetRect = QRect(QPoint(0, 0), size);
+
+ bool ok = stream.status() == QDataStream::Ok;
+
+ if (ok) {
+ int cornerData[4];
+ for (int i = 0; i < 4; ++i)
+ stream >> cornerData[i];
+ if (stream.status() == QDataStream::Ok) {
+ for (int i = 0; i < 4; ++i)
+ corners[i] = static_cast<Qt::DockWidgetArea>(cornerData[i]);
+ }
+
+ if (!testing)
+ fallbackToSizeHints = false;
+ }
+
+ return ok;
+}
+
+QList<int> QDockAreaLayout::indexOfPlaceHolder(const QString &objectName) const
+{
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ QList<int> result = docks[i].indexOfPlaceHolder(objectName);
+ if (!result.isEmpty()) {
+ result.prepend(i);
+ return result;
+ }
+ }
+ return QList<int>();
+}
+
+QList<int> QDockAreaLayout::indexOf(QWidget *dockWidget) const
+{
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ QList<int> result = docks[i].indexOf(dockWidget);
+ if (!result.isEmpty()) {
+ result.prepend(i);
+ return result;
+ }
+ }
+ return QList<int>();
+}
+
+QList<int> QDockAreaLayout::gapIndex(const QPoint &pos) const
+{
+ QMainWindow::DockOptions opts = mainWindow->dockOptions();
+ bool nestingEnabled = opts & QMainWindow::AllowNestedDocks;
+ QDockAreaLayoutInfo::TabMode tabMode = QDockAreaLayoutInfo::NoTabs;
+#ifndef QT_NO_TABBAR
+ if (opts & QMainWindow::AllowTabbedDocks
+ || opts & QMainWindow::VerticalTabs)
+ tabMode = QDockAreaLayoutInfo::AllowTabs;
+ if (opts & QMainWindow::ForceTabbedDocks)
+ tabMode = QDockAreaLayoutInfo::ForceTabs;
+
+ if (tabMode == QDockAreaLayoutInfo::ForceTabs)
+ nestingEnabled = false;
+#endif
+
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &info = docks[i];
+
+ if (!info.isEmpty() && info.rect.contains(pos)) {
+ QList<int> result
+ = docks[i].gapIndex(pos, nestingEnabled, tabMode);
+ if (!result.isEmpty())
+ result.prepend(i);
+ return result;
+ }
+ }
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &info = docks[i];
+
+ if (info.isEmpty()) {
+ QRect r;
+ switch (i) {
+ case QInternal::LeftDock:
+ r = QRect(rect.left(), rect.top(), EmptyDropAreaSize, rect.height());
+ break;
+ case QInternal::RightDock:
+ r = QRect(rect.right() - EmptyDropAreaSize, rect.top(),
+ EmptyDropAreaSize, rect.height());
+ break;
+ case QInternal::TopDock:
+ r = QRect(rect.left(), rect.top(), rect.width(), EmptyDropAreaSize);
+ break;
+ case QInternal::BottomDock:
+ r = QRect(rect.left(), rect.bottom() - EmptyDropAreaSize,
+ rect.width(), EmptyDropAreaSize);
+ break;
+ }
+ if (r.contains(pos)) {
+ if (opts & QMainWindow::ForceTabbedDocks && !info.item_list.isEmpty()) {
+ //in case of ForceTabbedDocks, we pass -1 in order to force the gap to be tabbed
+ //it mustn't be completely empty otherwise it won't work
+ return QList<int>() << i << -1 << 0;
+ } else {
+ return QList<int>() << i << 0;
+ }
+ }
+ }
+ }
+
+ return QList<int>();
+}
+
+QList<int> QDockAreaLayout::findSeparator(const QPoint &pos) const
+{
+ QList<int> result;
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &info = docks[i];
+ if (info.isEmpty())
+ continue;
+ QRect rect = separatorRect(i);
+ if (!rect.isNull() && sep == 1)
+ rect.adjust(-2, -2, 2, 2);
+ if (rect.contains(pos) && !info.hasFixedSize()) {
+ result << i;
+ break;
+ } else if (info.rect.contains(pos)) {
+ result = docks[i].findSeparator(pos);
+ if (!result.isEmpty()) {
+ result.prepend(i);
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+QDockAreaLayoutInfo *QDockAreaLayout::info(QWidget *widget)
+{
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ if (QDockAreaLayoutInfo *result = docks[i].info(widget))
+ return result;
+ }
+
+ return 0;
+}
+
+QDockAreaLayoutInfo *QDockAreaLayout::info(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+ const int index = path.first();
+ Q_ASSERT(index >= 0 && index < QInternal::DockCount);
+
+ if (path.count() == 1)
+ return &docks[index];
+
+ return docks[index].info(path.mid(1));
+}
+
+const QDockAreaLayoutInfo *QDockAreaLayout::info(const QList<int> &path) const
+{
+ return const_cast<QDockAreaLayout*>(this)->info(path);
+}
+
+QDockAreaLayoutItem &QDockAreaLayout::item(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+ const int index = path.first();
+ Q_ASSERT(index >= 0 && index < QInternal::DockCount);
+ return docks[index].item(path.mid(1));
+}
+
+QRect QDockAreaLayout::itemRect(const QList<int> &path) const
+{
+ Q_ASSERT(!path.isEmpty());
+ const int index = path.first();
+ Q_ASSERT(index >= 0 && index < QInternal::DockCount);
+ return docks[index].itemRect(path.mid(1));
+}
+
+QRect QDockAreaLayout::separatorRect(int index) const
+{
+ const QDockAreaLayoutInfo &dock = docks[index];
+ if (dock.isEmpty())
+ return QRect();
+ QRect r = dock.rect;
+ switch (index) {
+ case QInternal::LeftDock:
+ return QRect(r.right() + 1, r.top(), sep, r.height());
+ case QInternal::RightDock:
+ return QRect(r.left() - sep, r.top(), sep, r.height());
+ case QInternal::TopDock:
+ return QRect(r.left(), r.bottom() + 1, r.width(), sep);
+ case QInternal::BottomDock:
+ return QRect(r.left(), r.top() - sep, r.width(), sep);
+ default:
+ break;
+ }
+ return QRect();
+}
+
+QRect QDockAreaLayout::separatorRect(const QList<int> &path) const
+{
+ Q_ASSERT(!path.isEmpty());
+
+ const int index = path.first();
+ Q_ASSERT(index >= 0 && index < QInternal::DockCount);
+
+ if (path.count() == 1)
+ return separatorRect(index);
+ else
+ return docks[index].separatorRect(path.mid(1));
+}
+
+bool QDockAreaLayout::insertGap(const QList<int> &path, QLayoutItem *dockWidgetItem)
+{
+ Q_ASSERT(!path.isEmpty());
+ const int index = path.first();
+ Q_ASSERT(index >= 0 && index < QInternal::DockCount);
+ return docks[index].insertGap(path.mid(1), dockWidgetItem);
+}
+
+QLayoutItem *QDockAreaLayout::plug(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+ const int index = path.first();
+ Q_ASSERT(index >= 0 && index < QInternal::DockCount);
+ return docks[index].plug(path.mid(1));
+}
+
+QLayoutItem *QDockAreaLayout::unplug(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+ const int index = path.first();
+ Q_ASSERT(index >= 0 && index < QInternal::DockCount);
+ return docks[index].unplug(path.mid(1));
+}
+
+void QDockAreaLayout::remove(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+ const int index = path.first();
+ Q_ASSERT(index >= 0 && index < QInternal::DockCount);
+ docks[index].remove(path.mid(1));
+}
+
+static inline int qMin(int i1, int i2, int i3) { return qMin(i1, qMin(i2, i3)); }
+static inline int qMax(int i1, int i2, int i3) { return qMax(i1, qMax(i2, i3)); }
+
+void QDockAreaLayout::getGrid(QVector<QLayoutStruct> *_ver_struct_list,
+ QVector<QLayoutStruct> *_hor_struct_list)
+{
+ QSize center_hint(0, 0);
+ QSize center_min(0, 0);
+ const bool have_central = centralWidgetItem != 0 && !centralWidgetItem->isEmpty();
+ if (have_central) {
+ center_hint = centralWidgetRect.size();
+ if (!center_hint.isValid())
+ center_hint = centralWidgetItem->sizeHint();
+ center_min = centralWidgetItem->minimumSize();
+ }
+
+ QRect center_rect = rect;
+ if (!docks[QInternal::LeftDock].isEmpty())
+ center_rect.setLeft(rect.left() + docks[QInternal::LeftDock].rect.width() + sep);
+ if (!docks[QInternal::TopDock].isEmpty())
+ center_rect.setTop(rect.top() + docks[QInternal::TopDock].rect.height() + sep);
+ if (!docks[QInternal::RightDock].isEmpty())
+ center_rect.setRight(rect.right() - docks[QInternal::RightDock].rect.width() - sep);
+ if (!docks[QInternal::BottomDock].isEmpty())
+ center_rect.setBottom(rect.bottom() - docks[QInternal::BottomDock].rect.height() - sep);
+
+ QSize left_hint = docks[QInternal::LeftDock].size();
+ if (left_hint.isNull() || fallbackToSizeHints)
+ left_hint = docks[QInternal::LeftDock].sizeHint();
+ QSize left_min = docks[QInternal::LeftDock].minimumSize();
+ QSize left_max = docks[QInternal::LeftDock].maximumSize();
+ left_hint = left_hint.boundedTo(left_max).expandedTo(left_min);
+
+ QSize right_hint = docks[QInternal::RightDock].size();
+ if (right_hint.isNull() || fallbackToSizeHints)
+ right_hint = docks[QInternal::RightDock].sizeHint();
+ QSize right_min = docks[QInternal::RightDock].minimumSize();
+ QSize right_max = docks[QInternal::RightDock].maximumSize();
+ right_hint = right_hint.boundedTo(right_max).expandedTo(right_min);
+
+ QSize top_hint = docks[QInternal::TopDock].size();
+ if (top_hint.isNull() || fallbackToSizeHints)
+ top_hint = docks[QInternal::TopDock].sizeHint();
+ QSize top_min = docks[QInternal::TopDock].minimumSize();
+ QSize top_max = docks[QInternal::TopDock].maximumSize();
+ top_hint = top_hint.boundedTo(top_max).expandedTo(top_min);
+
+ QSize bottom_hint = docks[QInternal::BottomDock].size();
+ if (bottom_hint.isNull() || fallbackToSizeHints)
+ bottom_hint = docks[QInternal::BottomDock].sizeHint();
+ QSize bottom_min = docks[QInternal::BottomDock].minimumSize();
+ QSize bottom_max = docks[QInternal::BottomDock].maximumSize();
+ bottom_hint = bottom_hint.boundedTo(bottom_max).expandedTo(bottom_min);
+
+ fallbackToSizeHints = false;
+
+ if (_ver_struct_list != 0) {
+ QVector<QLayoutStruct> &ver_struct_list = *_ver_struct_list;
+ ver_struct_list.resize(3);
+
+ // top --------------------------------------------------
+ ver_struct_list[0].init();
+ ver_struct_list[0].stretch = 0;
+ ver_struct_list[0].sizeHint = top_hint.height();
+ ver_struct_list[0].minimumSize = top_min.height();
+ ver_struct_list[0].maximumSize = top_max.height();
+ ver_struct_list[0].expansive = false;
+ ver_struct_list[0].empty = docks[QInternal::TopDock].isEmpty();
+ ver_struct_list[0].pos = docks[QInternal::TopDock].rect.top();
+ ver_struct_list[0].size = docks[QInternal::TopDock].rect.height();
+
+ // center --------------------------------------------------
+ ver_struct_list[1].init();
+ ver_struct_list[1].stretch = center_hint.height();
+
+ bool tl_significant = corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea
+ || docks[QInternal::TopDock].isEmpty();
+ bool bl_significant = corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea
+ || docks[QInternal::BottomDock].isEmpty();
+ bool tr_significant = corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea
+ || docks[QInternal::TopDock].isEmpty();
+ bool br_significant = corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea
+ || docks[QInternal::BottomDock].isEmpty();
+
+ int left = (tl_significant && bl_significant) ? left_hint.height() : 0;
+ int right = (tr_significant && br_significant) ? right_hint.height() : 0;
+ ver_struct_list[1].sizeHint = qMax(left, center_hint.height(), right);
+
+ left = (tl_significant && bl_significant) ? left_min.height() : 0;
+ right = (tr_significant && br_significant) ? right_min.height() : 0;
+ ver_struct_list[1].minimumSize = qMax(left, center_min.height(), right);
+ ver_struct_list[1].maximumSize = have_central ? QWIDGETSIZE_MAX : 0;
+ ver_struct_list[1].expansive = have_central;
+ ver_struct_list[1].empty = docks[QInternal::LeftDock].isEmpty()
+ && !have_central
+ && docks[QInternal::RightDock].isEmpty();
+ ver_struct_list[1].pos = center_rect.top();
+ ver_struct_list[1].size = center_rect.height();
+
+ // bottom --------------------------------------------------
+ ver_struct_list[2].init();
+ ver_struct_list[2].stretch = 0;
+ ver_struct_list[2].sizeHint = bottom_hint.height();
+ ver_struct_list[2].minimumSize = bottom_min.height();
+ ver_struct_list[2].maximumSize = bottom_max.height();
+ ver_struct_list[2].expansive = false;
+ ver_struct_list[2].empty = docks[QInternal::BottomDock].isEmpty();
+ ver_struct_list[2].pos = docks[QInternal::BottomDock].rect.top();
+ ver_struct_list[2].size = docks[QInternal::BottomDock].rect.height();
+
+ for (int i = 0; i < 3; ++i) {
+ ver_struct_list[i].sizeHint
+ = qMax(ver_struct_list[i].sizeHint, ver_struct_list[i].minimumSize);
+ }
+ }
+
+ if (_hor_struct_list != 0) {
+ QVector<QLayoutStruct> &hor_struct_list = *_hor_struct_list;
+ hor_struct_list.resize(3);
+
+ // left --------------------------------------------------
+ hor_struct_list[0].init();
+ hor_struct_list[0].stretch = 0;
+ hor_struct_list[0].sizeHint = left_hint.width();
+ hor_struct_list[0].minimumSize = left_min.width();
+ hor_struct_list[0].maximumSize = left_max.width();
+ hor_struct_list[0].expansive = false;
+ hor_struct_list[0].empty = docks[QInternal::LeftDock].isEmpty();
+ hor_struct_list[0].pos = docks[QInternal::LeftDock].rect.left();
+ hor_struct_list[0].size = docks[QInternal::LeftDock].rect.width();
+
+ // center --------------------------------------------------
+ hor_struct_list[1].init();
+ hor_struct_list[1].stretch = center_hint.width();
+
+ bool tl_significant = corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea
+ || docks[QInternal::LeftDock].isEmpty();
+ bool tr_significant = corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea
+ || docks[QInternal::RightDock].isEmpty();
+ bool bl_significant = corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea
+ || docks[QInternal::LeftDock].isEmpty();
+ bool br_significant = corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea
+ || docks[QInternal::RightDock].isEmpty();
+
+ int top = (tl_significant && tr_significant) ? top_hint.width() : 0;
+ int bottom = (bl_significant && br_significant) ? bottom_hint.width() : 0;
+ hor_struct_list[1].sizeHint = qMax(top, center_hint.width(), bottom);
+
+ top = (tl_significant && tr_significant) ? top_min.width() : 0;
+ bottom = (bl_significant && br_significant) ? bottom_min.width() : 0;
+ hor_struct_list[1].minimumSize = qMax(top, center_min.width(), bottom);
+
+ hor_struct_list[1].maximumSize = have_central ? QWIDGETSIZE_MAX : 0;
+ hor_struct_list[1].expansive = have_central;
+ hor_struct_list[1].empty = !have_central;
+ hor_struct_list[1].pos = center_rect.left();
+ hor_struct_list[1].size = center_rect.width();
+
+ // right --------------------------------------------------
+ hor_struct_list[2].init();
+ hor_struct_list[2].stretch = 0;
+ hor_struct_list[2].sizeHint = right_hint.width();
+ hor_struct_list[2].minimumSize = right_min.width();
+ hor_struct_list[2].maximumSize = right_max.width();
+ hor_struct_list[2].expansive = false;
+ hor_struct_list[2].empty = docks[QInternal::RightDock].isEmpty();
+ hor_struct_list[2].pos = docks[QInternal::RightDock].rect.left();
+ hor_struct_list[2].size = docks[QInternal::RightDock].rect.width();
+
+ for (int i = 0; i < 3; ++i) {
+ hor_struct_list[i].sizeHint
+ = qMax(hor_struct_list[i].sizeHint, hor_struct_list[i].minimumSize);
+ }
+ }
+}
+
+void QDockAreaLayout::setGrid(QVector<QLayoutStruct> *ver_struct_list,
+ QVector<QLayoutStruct> *hor_struct_list)
+{
+
+ // top ---------------------------------------------------
+
+ if (!docks[QInternal::TopDock].isEmpty()) {
+ QRect r = docks[QInternal::TopDock].rect;
+ if (hor_struct_list != 0) {
+ r.setLeft(corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea
+ || docks[QInternal::LeftDock].isEmpty()
+ ? rect.left() : hor_struct_list->at(1).pos);
+ r.setRight(corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea
+ || docks[QInternal::RightDock].isEmpty()
+ ? rect.right() : hor_struct_list->at(2).pos - sep - 1);
+ }
+ if (ver_struct_list != 0) {
+ r.setTop(rect.top());
+ r.setBottom(ver_struct_list->at(1).pos - sep - 1);
+ }
+ docks[QInternal::TopDock].rect = r;
+ docks[QInternal::TopDock].fitItems();
+ }
+
+ // bottom ---------------------------------------------------
+
+ if (!docks[QInternal::BottomDock].isEmpty()) {
+ QRect r = docks[QInternal::BottomDock].rect;
+ if (hor_struct_list != 0) {
+ r.setLeft(corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea
+ || docks[QInternal::LeftDock].isEmpty()
+ ? rect.left() : hor_struct_list->at(1).pos);
+ r.setRight(corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea
+ || docks[QInternal::RightDock].isEmpty()
+ ? rect.right() : hor_struct_list->at(2).pos - sep - 1);
+ }
+ if (ver_struct_list != 0) {
+ r.setTop(ver_struct_list->at(2).pos);
+ r.setBottom(rect.bottom());
+ }
+ docks[QInternal::BottomDock].rect = r;
+ docks[QInternal::BottomDock].fitItems();
+ }
+
+ // left ---------------------------------------------------
+
+ if (!docks[QInternal::LeftDock].isEmpty()) {
+ QRect r = docks[QInternal::LeftDock].rect;
+ if (hor_struct_list != 0) {
+ r.setLeft(rect.left());
+ r.setRight(hor_struct_list->at(1).pos - sep - 1);
+ }
+ if (ver_struct_list != 0) {
+ r.setTop(corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea
+ || docks[QInternal::TopDock].isEmpty()
+ ? rect.top() : ver_struct_list->at(1).pos);
+ r.setBottom(corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea
+ || docks[QInternal::BottomDock].isEmpty()
+ ? rect.bottom() : ver_struct_list->at(2).pos - sep - 1);
+ }
+ docks[QInternal::LeftDock].rect = r;
+ docks[QInternal::LeftDock].fitItems();
+ }
+
+ // right ---------------------------------------------------
+
+ if (!docks[QInternal::RightDock].isEmpty()) {
+ QRect r = docks[QInternal::RightDock].rect;
+ if (hor_struct_list != 0) {
+ r.setLeft(hor_struct_list->at(2).pos);
+ r.setRight(rect.right());
+ }
+ if (ver_struct_list != 0) {
+ r.setTop(corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea
+ || docks[QInternal::TopDock].isEmpty()
+ ? rect.top() : ver_struct_list->at(1).pos);
+ r.setBottom(corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea
+ || docks[QInternal::BottomDock].isEmpty()
+ ? rect.bottom() : ver_struct_list->at(2).pos - sep - 1);
+ }
+ docks[QInternal::RightDock].rect = r;
+ docks[QInternal::RightDock].fitItems();
+ }
+
+ // center ---------------------------------------------------
+
+ if (hor_struct_list != 0) {
+ centralWidgetRect.setLeft(hor_struct_list->at(1).pos);
+ centralWidgetRect.setWidth(hor_struct_list->at(1).size);
+ }
+ if (ver_struct_list != 0) {
+ centralWidgetRect.setTop(ver_struct_list->at(1).pos);
+ centralWidgetRect.setHeight(ver_struct_list->at(1).size);
+ }
+}
+
+void QDockAreaLayout::fitLayout()
+{
+ QVector<QLayoutStruct> ver_struct_list(3);
+ QVector<QLayoutStruct> hor_struct_list(3);
+ getGrid(&ver_struct_list, &hor_struct_list);
+
+ qGeomCalc(ver_struct_list, 0, 3, rect.top(), rect.height(), sep);
+ qGeomCalc(hor_struct_list, 0, 3, rect.left(), rect.width(), sep);
+
+ setGrid(&ver_struct_list, &hor_struct_list);
+}
+
+void QDockAreaLayout::clear()
+{
+ for (int i = 0; i < QInternal::DockCount; ++i)
+ docks[i].clear();
+
+ rect = QRect();
+ centralWidgetRect = QRect();
+}
+
+QSize QDockAreaLayout::sizeHint() const
+{
+ int left_sep = 0;
+ int right_sep = 0;
+ int top_sep = 0;
+ int bottom_sep = 0;
+
+ if (centralWidgetItem != 0) {
+ left_sep = docks[QInternal::LeftDock].isEmpty() ? 0 : sep;
+ right_sep = docks[QInternal::RightDock].isEmpty() ? 0 : sep;
+ top_sep = docks[QInternal::TopDock].isEmpty() ? 0 : sep;
+ bottom_sep = docks[QInternal::BottomDock].isEmpty() ? 0 : sep;
+ }
+
+ QSize left = docks[QInternal::LeftDock].sizeHint() + QSize(left_sep, 0);
+ QSize right = docks[QInternal::RightDock].sizeHint() + QSize(right_sep, 0);
+ QSize top = docks[QInternal::TopDock].sizeHint() + QSize(0, top_sep);
+ QSize bottom = docks[QInternal::BottomDock].sizeHint() + QSize(0, bottom_sep);
+ QSize center = centralWidgetItem == 0 ? QSize(0, 0) : centralWidgetItem->sizeHint();
+
+ int row1 = top.width();
+ int row2 = left.width() + center.width() + right.width();
+ int row3 = bottom.width();
+ int col1 = left.height();
+ int col2 = top.height() + center.height() + bottom.height();
+ int col3 = right.height();
+
+ if (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea)
+ row1 += left.width();
+ else
+ col1 += top.height();
+
+ if (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea)
+ row1 += right.width();
+ else
+ col3 += top.height();
+
+ if (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea)
+ row3 += left.width();
+ else
+ col1 += bottom.height();
+
+ if (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea)
+ row3 += right.width();
+ else
+ col3 += bottom.height();
+
+ return QSize(qMax(row1, row2, row3), qMax(col1, col2, col3));
+}
+
+QSize QDockAreaLayout::minimumSize() const
+{
+ int left_sep = 0;
+ int right_sep = 0;
+ int top_sep = 0;
+ int bottom_sep = 0;
+
+ if (centralWidgetItem != 0) {
+ left_sep = docks[QInternal::LeftDock].isEmpty() ? 0 : sep;
+ right_sep = docks[QInternal::RightDock].isEmpty() ? 0 : sep;
+ top_sep = docks[QInternal::TopDock].isEmpty() ? 0 : sep;
+ bottom_sep = docks[QInternal::BottomDock].isEmpty() ? 0 : sep;
+ }
+
+ QSize left = docks[QInternal::LeftDock].minimumSize() + QSize(left_sep, 0);
+ QSize right = docks[QInternal::RightDock].minimumSize() + QSize(right_sep, 0);
+ QSize top = docks[QInternal::TopDock].minimumSize() + QSize(0, top_sep);
+ QSize bottom = docks[QInternal::BottomDock].minimumSize() + QSize(0, bottom_sep);
+ QSize center = centralWidgetItem == 0 ? QSize(0, 0) : centralWidgetItem->minimumSize();
+
+ int row1 = top.width();
+ int row2 = left.width() + center.width() + right.width();
+ int row3 = bottom.width();
+ int col1 = left.height();
+ int col2 = top.height() + center.height() + bottom.height();
+ int col3 = right.height();
+
+ if (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea)
+ row1 += left.width();
+ else
+ col1 += top.height();
+
+ if (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea)
+ row1 += right.width();
+ else
+ col3 += top.height();
+
+ if (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea)
+ row3 += left.width();
+ else
+ col1 += bottom.height();
+
+ if (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea)
+ row3 += right.width();
+ else
+ col3 += bottom.height();
+
+ return QSize(qMax(row1, row2, row3), qMax(col1, col2, col3));
+}
+
+bool QDockAreaLayout::restoreDockWidget(QDockWidget *dockWidget)
+{
+ QList<int> index = indexOfPlaceHolder(dockWidget->objectName());
+ if (index.isEmpty())
+ return false;
+
+ QDockAreaLayoutItem &item = this->item(index);
+ QPlaceHolderItem *placeHolder = item.placeHolderItem;
+ Q_ASSERT(placeHolder != 0);
+
+ item.widgetItem = new QDockWidgetItem(dockWidget);
+
+ if (placeHolder->window) {
+ QDesktopWidget desktop;
+ QRect r = constrainedRect(placeHolder->topLevelRect, desktop.screenGeometry(dockWidget));
+ dockWidget->d_func()->setWindowState(true, true, r);
+ }
+ dockWidget->setVisible(!placeHolder->hidden);
+#ifdef Q_WS_X11
+ if (placeHolder->window) // gets rid of the X11BypassWindowManager window flag
+ dockWidget->d_func()->setWindowState(true);
+#endif
+
+ item.placeHolderItem = 0;
+ delete placeHolder;
+
+ return true;
+}
+
+void QDockAreaLayout::addDockWidget(QInternal::DockPosition pos, QDockWidget *dockWidget,
+ Qt::Orientation orientation)
+{
+ QLayoutItem *dockWidgetItem = new QDockWidgetItem(dockWidget);
+ QDockAreaLayoutInfo &info = docks[pos];
+ if (orientation == info.o || info.item_list.count() <= 1) {
+ // empty dock areas, or dock areas containing exactly one widget can have their orientation
+ // switched.
+ info.o = orientation;
+
+ QDockAreaLayoutItem new_item(dockWidgetItem);
+ info.item_list.append(new_item);
+#ifndef QT_NO_TABBAR
+ if (info.tabbed && !new_item.skip()) {
+ info.updateTabBar();
+ info.setCurrentTabId(tabId(new_item));
+ }
+#endif
+ } else {
+#ifndef QT_NO_TABBAR
+ int tbshape = info.tabBarShape;
+#else
+ int tbshape = 0;
+#endif
+ QDockAreaLayoutInfo new_info(&sep, pos, orientation, tbshape, mainWindow);
+ new_info.item_list.append(new QDockAreaLayoutInfo(info));
+ new_info.item_list.append(dockWidgetItem);
+ info = new_info;
+ }
+
+ QList<int> index = indexOfPlaceHolder(dockWidget->objectName());
+ if (!index.isEmpty())
+ remove(index);
+}
+
+void QDockAreaLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
+{
+ QList<int> path = indexOf(first);
+ if (path.isEmpty())
+ return;
+
+ QDockAreaLayoutInfo *info = this->info(path);
+ Q_ASSERT(info != 0);
+ info->tab(path.last(), new QDockWidgetItem(second));
+
+ QList<int> index = indexOfPlaceHolder(second->objectName());
+ if (!index.isEmpty())
+ remove(index);
+}
+
+void QDockAreaLayout::splitDockWidget(QDockWidget *after,
+ QDockWidget *dockWidget,
+ Qt::Orientation orientation)
+{
+ QList<int> path = indexOf(after);
+ if (path.isEmpty())
+ return;
+
+ QDockAreaLayoutInfo *info = this->info(path);
+ Q_ASSERT(info != 0);
+ info->split(path.last(), orientation, new QDockWidgetItem(dockWidget));
+
+ QList<int> index = indexOfPlaceHolder(dockWidget->objectName());
+ if (!index.isEmpty())
+ remove(index);
+}
+
+void QDockAreaLayout::apply(bool animate)
+{
+ QWidgetAnimator &widgetAnimator = qt_mainwindow_layout(mainWindow)->widgetAnimator;
+
+ for (int i = 0; i < QInternal::DockCount; ++i)
+ docks[i].apply(animate);
+ if (centralWidgetItem != 0 && !centralWidgetItem->isEmpty()) {
+ widgetAnimator.animate(centralWidgetItem->widget(), centralWidgetRect,
+ animate);
+ }
+#ifndef QT_NO_TABBAR
+ if (sep == 1)
+ updateSeparatorWidgets();
+#endif //QT_NO_TABBAR
+}
+
+void QDockAreaLayout::paintSeparators(QPainter *p, QWidget *widget,
+ const QRegion &clip,
+ const QPoint &mouse) const
+{
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &dock = docks[i];
+ if (dock.isEmpty())
+ continue;
+ QRect r = separatorRect(i);
+ if (clip.contains(r) && !dock.hasFixedSize()) {
+ Qt::Orientation opposite = dock.o == Qt::Horizontal
+ ? Qt::Vertical : Qt::Horizontal;
+ paintSep(p, widget, r, opposite, r.contains(mouse));
+ }
+ if (clip.contains(dock.rect))
+ dock.paintSeparators(p, widget, clip, mouse);
+ }
+}
+
+QRegion QDockAreaLayout::separatorRegion() const
+{
+ QRegion result;
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &dock = docks[i];
+ if (dock.isEmpty())
+ continue;
+ result |= separatorRect(i);
+ result |= dock.separatorRegion();
+ }
+
+ return result;
+}
+
+int QDockAreaLayout::separatorMove(const QList<int> &separator, const QPoint &origin,
+ const QPoint &dest)
+{
+ int delta = 0;
+ int index = separator.last();
+
+ if (separator.count() > 1) {
+ QDockAreaLayoutInfo *info = this->info(separator);
+ delta = pick(info->o, dest - origin);
+ if (delta != 0)
+ delta = info->separatorMove(index, delta);
+ info->apply(false);
+ return delta;
+ }
+
+ QVector<QLayoutStruct> list;
+
+ if (index == QInternal::LeftDock || index == QInternal::RightDock)
+ getGrid(0, &list);
+ else
+ getGrid(&list, 0);
+
+ int sep_index = index == QInternal::LeftDock || index == QInternal::TopDock
+ ? 0 : 1;
+ Qt::Orientation o = index == QInternal::LeftDock || index == QInternal::RightDock
+ ? Qt::Horizontal
+ : Qt::Vertical;
+
+ delta = pick(o, dest - origin);
+ delta = separatorMoveHelper(list, sep_index, delta, sep);
+
+ if (index == QInternal::LeftDock || index == QInternal::RightDock)
+ setGrid(0, &list);
+ else
+ setGrid(&list, 0);
+
+ apply(false);
+
+ return delta;
+}
+
+#ifndef QT_NO_TABBAR
+// Sets the correct positions for the separator widgets
+// Allocates new sepearator widgets with getSeparatorWidget
+void QDockAreaLayout::updateSeparatorWidgets() const
+{
+ int j = 0;
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &dock = docks[i];
+ if (dock.isEmpty())
+ continue;
+
+ QWidget *sepWidget;
+ if (j < separatorWidgets.size()) {
+ sepWidget = separatorWidgets.at(j);
+ } else {
+ sepWidget = qt_mainwindow_layout(mainWindow)->getSeparatorWidget();
+ separatorWidgets.append(sepWidget);
+ }
+ j++;
+
+#ifndef QT_MAC_USE_COCOA
+ sepWidget->raise();
+#endif
+ QRect sepRect = separatorRect(i).adjusted(-2, -2, 2, 2);
+ sepWidget->setGeometry(sepRect);
+ sepWidget->setMask( QRegion(separatorRect(i).translated( - sepRect.topLeft())));
+ sepWidget->show();
+ }
+ for (int i = j; i < separatorWidgets.size(); ++i)
+ separatorWidgets.at(i)->hide();
+
+ separatorWidgets.resize(j);
+}
+#endif //QT_NO_TABBAR
+
+QLayoutItem *QDockAreaLayout::itemAt(int *x, int index) const
+{
+ Q_ASSERT(x != 0);
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &dock = docks[i];
+ if (QLayoutItem *ret = dock.itemAt(x, index))
+ return ret;
+ }
+
+ if (centralWidgetItem && (*x)++ == index)
+ return centralWidgetItem;
+
+ return 0;
+}
+
+QLayoutItem *QDockAreaLayout::takeAt(int *x, int index)
+{
+ Q_ASSERT(x != 0);
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ QDockAreaLayoutInfo &dock = docks[i];
+ if (QLayoutItem *ret = dock.takeAt(x, index))
+ return ret;
+ }
+
+ if (centralWidgetItem && (*x)++ == index) {
+ QLayoutItem *ret = centralWidgetItem;
+ centralWidgetItem = 0;
+ return ret;
+ }
+
+ return 0;
+}
+
+void QDockAreaLayout::deleteAllLayoutItems()
+{
+ for (int i = 0; i < QInternal::DockCount; ++i)
+ docks[i].deleteAllLayoutItems();
+}
+
+#ifndef QT_NO_TABBAR
+QSet<QTabBar*> QDockAreaLayout::usedTabBars() const
+{
+ QSet<QTabBar*> result;
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &dock = docks[i];
+ result += dock.usedTabBars();
+ }
+ return result;
+}
+
+// Returns the set of all used separator widgets
+QSet<QWidget*> QDockAreaLayout::usedSeparatorWidgets() const
+{
+ QSet<QWidget*> result;
+
+ for (int i = 0; i < separatorWidgets.count(); ++i)
+ result << separatorWidgets.at(i);
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &dock = docks[i];
+ result += dock.usedSeparatorWidgets();
+ }
+ return result;
+}
+#endif
+
+QRect QDockAreaLayout::gapRect(const QList<int> &path) const
+{
+ const QDockAreaLayoutInfo *info = this->info(path);
+ if (info == 0)
+ return QRect();
+ const QList<QDockAreaLayoutItem> &item_list = info->item_list;
+ Qt::Orientation o = info->o;
+ int index = path.last();
+ if (index < 0 || index >= item_list.count())
+ return QRect();
+ const QDockAreaLayoutItem &item = item_list.at(index);
+ if (!(item.flags & QDockAreaLayoutItem::GapItem))
+ return QRect();
+
+ QRect result;
+
+#ifndef QT_NO_TABBAR
+ if (info->tabbed) {
+ result = info->tabContentRect();
+ } else
+#endif
+ {
+ int pos = item.pos;
+ int size = item.size;
+
+ int prev = info->prev(index);
+ int next = info->next(index);
+
+ if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem)) {
+ pos += sep;
+ size -= sep;
+ }
+ if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem))
+ size -= sep;
+
+ QPoint p;
+ rpick(o, p) = pos;
+ rperp(o, p) = perp(o, info->rect.topLeft());
+ QSize s;
+ rpick(o, s) = size;
+ rperp(o, s) = perp(o, info->rect.size());
+
+ result = QRect(p, s);
+ }
+
+ return result;
+}
+
+void QDockAreaLayout::keepSize(QDockWidget *w)
+{
+ QList<int> path = indexOf(w);
+ if (path.isEmpty())
+ return;
+ QDockAreaLayoutItem &item = this->item(path);
+ if (item.size != -1)
+ item.flags |= QDockAreaLayoutItem::KeepSize;
+}
+
+void QDockAreaLayout::styleChangedEvent()
+{
+ sep = mainWindow->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent, 0, mainWindow);
+ fitLayout();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DOCKWIDGET