src/gui/widgets/qdockarealayout.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/widgets/qdockarealayout.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,3317 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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
+
+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
+
+QDockAreaLayoutInfo::QDockAreaLayoutInfo()
+    : sep(0), dockPos(QInternal::LeftDock), o(Qt::Horizontal), mainWindow(0)
+#ifndef QT_NO_TABBAR
+    , tabbed(false), tabBar(0), tabBarShape(QTabBar::RoundedSouth), tabBarVisible(false)
+#endif
+{
+}
+
+QDockAreaLayoutInfo::QDockAreaLayoutInfo(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)), tabBarVisible(false)
+#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
+    if (tabbed) {
+        QSize tbm = tabBarMinimumSize();
+        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
+    if (tabbed) {
+        QSize tbh = tabBarSizeHint();
+        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;
+            QRect r = subinfo == 0 ? dockedGeometry(widgetItem->widget()) : 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.subinfo = new_info;
+            item.widgetItem = 0;
+
+            QDockAreaLayoutItem new_item
+                = widgetItem == 0
+                    ? QDockAreaLayoutItem(subinfo)
+                    : QDockAreaLayoutItem(widgetItem);
+            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.at(index).subinfo == 0)
+        return this;
+    return item_list.at(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 = qobject_cast<QMainWindowLayout*>(mainWindow->layout());
+    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 (tabBarVisible) {
+            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);
+            }
+        }
+    }
+
+    if (sep == 1)
+        updateSeparatorWidgets();
+}
+
+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);
+        }
+    }
+}
+
+#ifdef Q_WS_MAC
+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;
+}
+#endif
+
+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);
+                    }
+                } else {
+                    int dummy;
+                    stream >> item.pos >> item.size >> dummy >> dummy;
+                    if (!testing) {
+                        widget->setFloating(false);
+                        widget->setVisible(flags & StateFlagVisible);
+                    }
+                }
+
+                if (!testing) {
+                    item_list.append(item);
+                }
+            }
+        } else if (nextMarker == SequenceMarker) {
+            int dummy;
+#ifdef QT_NO_TABBAR
+            const int tabBarShape = 0;
+#endif
+            QDockAreaLayoutInfo *info = new QDockAreaLayoutInfo(sep, dockPos, o,
+                                                                tabBarShape, mainWindow);
+            QDockAreaLayoutItem item(info);
+            stream >> item.pos >> item.size >> dummy >> dummy;
+            if (!info->restoreState(stream, widgets, testing))
+                return false;
+
+            if (!testing) {
+                item_list.append(item);
+            }
+        } else {
+            return false;
+        }
+    }
+
+#ifndef QT_NO_TABBAR
+    if (!testing && tabbed && index >= 0 && index < item_list.count()) {
+        updateTabBar();
+        setCurrentTabId(tabId(item_list.at(index)));
+    }
+#endif
+    if (!testing && sep == 1)
+        updateSeparatorWidgets();
+
+    return true;
+}
+
+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);
+}
+
+#ifndef QT_NO_TABBAR
+void QDockAreaLayoutInfo::updateTabBar() const
+{
+    if (!tabbed)
+        return;
+
+    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);
+
+    that->tabBarVisible = ( (gap ? 1 : 0) + tabBar->count()) > 1;
+
+    if (changed || !tabBarMin.isValid() | !tabBarHint.isValid()) {
+        that->tabBarMin = tabBar->minimumSizeHint();
+        that->tabBarHint = tabBar->sizeHint();
+    }
+}
+
+void QDockAreaLayoutInfo::setTabBarShape(int shape)
+{
+    if (shape == tabBarShape)
+        return;
+    tabBarShape = shape;
+    if (tabBar != 0) {
+        tabBar->setShape(static_cast<QTabBar::Shape>(shape));
+        tabBarMin = QSize();
+        tabBarHint = QSize();
+    }
+
+    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 (!tabbed)
+        return QSize(0, 0);
+
+    updateTabBar();
+
+    return tabBarMin;
+}
+
+QSize QDockAreaLayoutInfo::tabBarSizeHint() const
+{
+    if (!tabbed)
+        return QSize(0, 0);
+
+    updateTabBar();
+
+    return tabBarHint;
+}
+
+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 (tabBarVisible) {
+        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)
+{
+    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]);
+        }
+    }
+
+    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);
+    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())
+        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())
+        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())
+        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())
+        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);
+
+    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->show();
+//    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
+        = qobject_cast<QMainWindowLayout*>(mainWindow->layout())->widgetAnimator;
+
+    for (int i = 0; i < QInternal::DockCount; ++i)
+        docks[i].apply(animate);
+    if (centralWidgetItem != 0 && !centralWidgetItem->isEmpty()) {
+        widgetAnimator.animate(centralWidgetItem->widget(), centralWidgetRect,
+                                animate);
+    }
+
+    if (sep == 1)
+        updateSeparatorWidgets();
+}
+
+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;
+}
+
+// Sets the correct positions for the seperator 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 = qobject_cast<QMainWindowLayout*>(mainWindow->layout())->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);
+}
+
+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;
+}
+#endif
+
+// 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;
+}
+
+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;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DOCKWIDGET