diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/gui/widgets/qmainwindowlayout.cpp | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'src/gui/widgets/qmainwindowlayout.cpp')
-rw-r--r-- | src/gui/widgets/qmainwindowlayout.cpp | 1986 |
1 files changed, 1986 insertions, 0 deletions
diff --git a/src/gui/widgets/qmainwindowlayout.cpp b/src/gui/widgets/qmainwindowlayout.cpp new file mode 100644 index 0000000..768446e --- /dev/null +++ b/src/gui/widgets/qmainwindowlayout.cpp @@ -0,0 +1,1986 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmainwindowlayout_p.h" +#include "qdockarealayout_p.h" + +#ifndef QT_NO_MAINWINDOW +#include "qdockwidget.h" +#include "qdockwidget_p.h" +#include "qtoolbar_p.h" +#include "qmainwindow.h" +#include "qmainwindowlayout_p.h" +#include "qtoolbar.h" +#include "qtoolbarlayout_p.h" +#include "qwidgetanimator_p.h" +#include "qrubberband.h" +#include "qdockwidget_p.h" +#include "qtabbar_p.h" + +#include <qapplication.h> +#include <qstatusbar.h> +#include <qstring.h> +#include <qstyle.h> +#include <qvarlengtharray.h> +#include <qstack.h> +#include <qmap.h> +#include <qtimer.h> + +#include <qdebug.h> + +#include <private/qapplication_p.h> +#include <private/qlayoutengine_p.h> +#ifdef Q_WS_MAC +# include <private/qcore_mac_p.h> +# include <private/qt_cocoa_helpers_mac_p.h> +#endif + +#ifdef Q_DEBUG_MAINWINDOW_LAYOUT +# include <QTextStream> +#endif + +QT_BEGIN_NAMESPACE + +/****************************************************************************** +** debug +*/ + +#if defined(Q_DEBUG_MAINWINDOW_LAYOUT) && !defined(QT_NO_DOCKWIDGET) + +static QTextStream qout(stderr, QIODevice::WriteOnly); + +static void dumpLayout(QTextStream &qout, const QDockAreaLayoutInfo &layout, QString indent); + +static void dumpLayout(QTextStream &qout, const QDockAreaLayoutItem &item, QString indent) +{ + qout << indent << "QDockAreaLayoutItem: " + << "pos: " << item.pos << " size:" << item.size + << " gap:" << (item.flags & QDockAreaLayoutItem::GapItem) + << " keepSize:" << (item.flags & QDockAreaLayoutItem::KeepSize) << '\n'; + indent += QLatin1String(" "); + if (item.widgetItem != 0) { + qout << indent << "widget: " + << item.widgetItem->widget()->metaObject()->className() + << ' ' << item.widgetItem->widget()->windowTitle() << '\n'; + } else if (item.subinfo != 0) { + qout << indent << "subinfo:\n"; + dumpLayout(qout, *item.subinfo, indent + QLatin1String(" ")); + } else if (item.placeHolderItem != 0) { + QRect r = item.placeHolderItem->topLevelRect; + qout << indent << "placeHolder: " + << "pos: " << item.pos << " size:" << item.size + << " gap:" << (item.flags & QDockAreaLayoutItem::GapItem) + << " keepSize:" << (item.flags & QDockAreaLayoutItem::KeepSize) + << " objectName:" << item.placeHolderItem->objectName + << " hidden:" << item.placeHolderItem->hidden + << " window:" << item.placeHolderItem->window + << " rect:" << r.x() << ',' << r.y() << ' ' + << r.width() << 'x' << r.height() << '\n'; + } + qout.flush(); +} + +static void dumpLayout(QTextStream &qout, const QDockAreaLayoutInfo &layout, QString indent) +{ + qout << indent << "QDockAreaLayoutInfo: " + << layout.rect.left() << ',' + << layout.rect.top() << ' ' + << layout.rect.width() << 'x' + << layout.rect.height() + << " orient:" << layout.o + << " tabbed:" << layout.tabbed + << " tbshape:" << layout.tabBarShape << '\n'; + + indent += QLatin1String(" "); + + for (int i = 0; i < layout.item_list.count(); ++i) { + qout << indent << "Item: " << i << '\n'; + dumpLayout(qout, layout.item_list.at(i), indent + QLatin1String(" ")); + } + qout.flush(); +}; + +static void dumpLayout(QTextStream &qout, const QDockAreaLayout &layout, QString indent) +{ + qout << indent << "QDockAreaLayout: " + << layout.rect.left() << ',' + << layout.rect.top() << ' ' + << layout.rect.width() << 'x' + << layout.rect.height() << '\n'; + + qout << indent << "TopDockArea:\n"; + dumpLayout(qout, layout.docks[QInternal::TopDock], indent + QLatin1String(" ")); + qout << indent << "LeftDockArea:\n"; + dumpLayout(qout, layout.docks[QInternal::LeftDock], indent + QLatin1String(" ")); + qout << indent << "RightDockArea:\n"; + dumpLayout(qout, layout.docks[QInternal::RightDock], indent + QLatin1String(" ")); + qout << indent << "BottomDockArea:\n"; + dumpLayout(qout, layout.docks[QInternal::BottomDock], indent + QLatin1String(" ")); + + qout.flush(); +}; + +void qt_dumpLayout(QTextStream &qout, QMainWindow *window) +{ + QMainWindowLayout *layout = qobject_cast<QMainWindowLayout*>(window->layout()); + dumpLayout(qout, layout->layoutState.dockAreaLayout, QString()); +} + +#endif // Q_DEBUG_MAINWINDOW_LAYOUT && !QT_NO_DOCKWIDGET + +/****************************************************************************** +** QMainWindowLayoutState +*/ + +// we deal with all the #ifndefferry here so QMainWindowLayout code is clean + +QMainWindowLayoutState::QMainWindowLayoutState(QMainWindow *win) + : +#ifndef QT_NO_TOOLBAR + toolBarAreaLayout(win), +#endif +#ifndef QT_NO_DOCKWIDGET + dockAreaLayout(win) +#else + centralWidgetItem(0) +#endif + +{ + mainWindow = win; +} + +QSize QMainWindowLayoutState::sizeHint() const +{ + + QSize result(0, 0); + +#ifndef QT_NO_DOCKWIDGET + result = dockAreaLayout.sizeHint(); +#else + if (centralWidgetItem != 0) + result = centralWidgetItem->sizeHint(); +#endif + +#ifndef QT_NO_TOOLBAR + result = toolBarAreaLayout.sizeHint(result); +#endif // QT_NO_TOOLBAR + + return result; +} + +QSize QMainWindowLayoutState::minimumSize() const +{ + QSize result(0, 0); + +#ifndef QT_NO_DOCKWIDGET + result = dockAreaLayout.minimumSize(); +#else + if (centralWidgetItem != 0) + result = centralWidgetItem->minimumSize(); +#endif + +#ifndef QT_NO_TOOLBAR + result = toolBarAreaLayout.minimumSize(result); +#endif // QT_NO_TOOLBAR + + return result; +} + +void QMainWindowLayoutState::apply(bool animated) +{ +#ifndef QT_NO_TOOLBAR + toolBarAreaLayout.apply(animated); +#endif + +#ifndef QT_NO_DOCKWIDGET +// dumpLayout(dockAreaLayout, QString()); + dockAreaLayout.apply(animated); +#else + if (centralWidgetItem != 0) { + QMainWindowLayout *layout = qobject_cast<QMainWindowLayout*>(mainWindow->layout()); + Q_ASSERT(layout != 0); + layout->widgetAnimator->animate(centralWidgetItem->widget(), centralWidgetRect, animated); + } +#endif +} + +void QMainWindowLayoutState::fitLayout() +{ + QRect r; +#ifdef QT_NO_TOOLBAR + r = rect; +#else + toolBarAreaLayout.rect = rect; + r = toolBarAreaLayout.fitLayout(); +#endif // QT_NO_TOOLBAR + +#ifndef QT_NO_DOCKWIDGET + dockAreaLayout.rect = r; + dockAreaLayout.fitLayout(); +#else + centralWidgetRect = r; +#endif +} + +void QMainWindowLayoutState::deleteAllLayoutItems() +{ +#ifndef QT_NO_TOOLBAR + toolBarAreaLayout.deleteAllLayoutItems(); +#endif + +#ifndef QT_NO_DOCKWIDGET + dockAreaLayout.deleteAllLayoutItems(); +#endif +} + +void QMainWindowLayoutState::deleteCentralWidgetItem() +{ +#ifndef QT_NO_DOCKWIDGET + delete dockAreaLayout.centralWidgetItem; + dockAreaLayout.centralWidgetItem = 0; +#else + delete centralWidgetItem; + centralWidgetItem = 0; +#endif +} + +QLayoutItem *QMainWindowLayoutState::itemAt(int index, int *x) const +{ +#ifndef QT_NO_TOOLBAR + if (QLayoutItem *ret = toolBarAreaLayout.itemAt(x, index)) + return ret; +#endif + +#ifndef QT_NO_DOCKWIDGET + if (QLayoutItem *ret = dockAreaLayout.itemAt(x, index)) + return ret; +#else + if (centralWidgetItem != 0 && (*x)++ == index) + return centralWidgetItem; +#endif + + return 0; +} + +QLayoutItem *QMainWindowLayoutState::takeAt(int index, int *x) +{ +#ifndef QT_NO_TOOLBAR + if (QLayoutItem *ret = toolBarAreaLayout.takeAt(x, index)) + return ret; +#endif + +#ifndef QT_NO_DOCKWIDGET + if (QLayoutItem *ret = dockAreaLayout.takeAt(x, index)) + return ret; +#else + if (centralWidgetItem != 0 && (*x)++ == index) { + QLayoutItem *ret = centralWidgetItem; + centralWidgetItem = 0; + return ret; + } +#endif + + return 0; +} + +QList<int> QMainWindowLayoutState::indexOf(QWidget *widget) const +{ + QList<int> result; + +#ifndef QT_NO_TOOLBAR + // is it a toolbar? + if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) { + result = toolBarAreaLayout.indexOf(toolBar); + if (!result.isEmpty()) + result.prepend(0); + return result; + } +#endif + +#ifndef QT_NO_DOCKWIDGET + // is it a dock widget? + if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(widget)) { + result = dockAreaLayout.indexOf(dockWidget); + if (!result.isEmpty()) + result.prepend(1); + return result; + } +#endif //QT_NO_DOCKWIDGET + + return result; +} + +bool QMainWindowLayoutState::contains(QWidget *widget) const +{ +#ifndef QT_NO_DOCKWIDGET + if (dockAreaLayout.centralWidgetItem != 0 && dockAreaLayout.centralWidgetItem->widget() == widget) + return true; + if (!dockAreaLayout.indexOf(widget).isEmpty()) + return true; +#else + if (centralWidgetItem != 0 && centralWidgetItem->widget() == widget) + return true; +#endif + +#ifndef QT_NO_TOOLBAR + if (!toolBarAreaLayout.indexOf(widget).isEmpty()) + return true; +#endif + return false; +} + +void QMainWindowLayoutState::setCentralWidget(QWidget *widget) +{ + QLayoutItem *item = 0; + //make sure we remove the widget + deleteCentralWidgetItem(); + + if (widget != 0) + item = new QWidgetItemV2(widget); + +#ifndef QT_NO_DOCKWIDGET + dockAreaLayout.centralWidgetItem = item; +#else + centralWidgetItem = item; +#endif +} + +QWidget *QMainWindowLayoutState::centralWidget() const +{ + QLayoutItem *item = 0; + +#ifndef QT_NO_DOCKWIDGET + item = dockAreaLayout.centralWidgetItem; +#else + item = centralWidgetItem; +#endif + + if (item != 0) + return item->widget(); + return 0; +} + +QList<int> QMainWindowLayoutState::gapIndex(QWidget *widget, + const QPoint &pos) const +{ + QList<int> result; + +#ifndef QT_NO_TOOLBAR + // is it a toolbar? + if (qobject_cast<QToolBar*>(widget) != 0) { + result = toolBarAreaLayout.gapIndex(pos); + if (!result.isEmpty()) + result.prepend(0); + return result; + } +#endif + +#ifndef QT_NO_DOCKWIDGET + // is it a dock widget? + if (qobject_cast<QDockWidget *>(widget) != 0) { + result = dockAreaLayout.gapIndex(pos); + if (!result.isEmpty()) + result.prepend(1); + return result; + } +#endif //QT_NO_DOCKWIDGET + + return result; +} + +bool QMainWindowLayoutState::insertGap(QList<int> path, QLayoutItem *item) +{ + if (path.isEmpty()) + return false; + + int i = path.takeFirst(); + +#ifndef QT_NO_TOOLBAR + if (i == 0) { + Q_ASSERT(qobject_cast<QToolBar*>(item->widget()) != 0); + return toolBarAreaLayout.insertGap(path, item); + } +#endif + +#ifndef QT_NO_DOCKWIDGET + if (i == 1) { + Q_ASSERT(qobject_cast<QDockWidget*>(item->widget()) != 0); + return dockAreaLayout.insertGap(path, item); + } +#endif //QT_NO_DOCKWIDGET + + return false; +} + +void QMainWindowLayoutState::remove(QList<int> path) +{ + int i = path.takeFirst(); + +#ifndef QT_NO_TOOLBAR + if (i == 0) + toolBarAreaLayout.remove(path); +#endif + +#ifndef QT_NO_DOCKWIDGET + if (i == 1) + dockAreaLayout.remove(path); +#endif //QT_NO_DOCKWIDGET +} + +void QMainWindowLayoutState::remove(QLayoutItem *item) +{ +#ifndef QT_NO_TOOLBAR + toolBarAreaLayout.remove(item); +#endif + +#ifndef QT_NO_DOCKWIDGET + // is it a dock widget? + if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(item->widget())) { + QList<int> path = dockAreaLayout.indexOf(dockWidget); + if (!path.isEmpty()) + dockAreaLayout.remove(path); + } +#endif //QT_NO_DOCKWIDGET +} + +void QMainWindowLayoutState::clear() +{ +#ifndef QT_NO_TOOLBAR + toolBarAreaLayout.clear(); +#endif + +#ifndef QT_NO_DOCKWIDGET + dockAreaLayout.clear(); +#else + centralWidgetRect = QRect(0, 0, -1, -1); +#endif + + rect = QRect(0, 0, -1, -1); +} + +bool QMainWindowLayoutState::isValid() const +{ + return rect.isValid(); +} + +QLayoutItem *QMainWindowLayoutState::item(QList<int> path) +{ + int i = path.takeFirst(); + +#ifndef QT_NO_TOOLBAR + if (i == 0) + return toolBarAreaLayout.item(path).widgetItem; +#endif + +#ifndef QT_NO_DOCKWIDGET + if (i == 1) + return dockAreaLayout.item(path).widgetItem; +#endif //QT_NO_DOCKWIDGET + + return 0; +} + +QRect QMainWindowLayoutState::itemRect(QList<int> path) const +{ + int i = path.takeFirst(); + +#ifndef QT_NO_TOOLBAR + if (i == 0) + return toolBarAreaLayout.itemRect(path); +#endif + +#ifndef QT_NO_DOCKWIDGET + if (i == 1) + return dockAreaLayout.itemRect(path); +#endif //QT_NO_DOCKWIDGET + + return QRect(); +} + +QRect QMainWindowLayoutState::gapRect(QList<int> path) const +{ + int i = path.takeFirst(); + +#ifndef QT_NO_TOOLBAR + if (i == 0) + return toolBarAreaLayout.itemRect(path); +#endif + +#ifndef QT_NO_DOCKWIDGET + if (i == 1) + return dockAreaLayout.gapRect(path); +#endif //QT_NO_DOCKWIDGET + + return QRect(); +} + +QLayoutItem *QMainWindowLayoutState::plug(QList<int> path) +{ + int i = path.takeFirst(); + +#ifndef QT_NO_TOOLBAR + if (i == 0) + return toolBarAreaLayout.plug(path); +#endif + +#ifndef QT_NO_DOCKWIDGET + if (i == 1) + return dockAreaLayout.plug(path); +#endif //QT_NO_DOCKWIDGET + + return 0; +} + +QLayoutItem *QMainWindowLayoutState::unplug(QList<int> path, QMainWindowLayoutState *other) +{ + int i = path.takeFirst(); + +#ifdef QT_NO_TOOLBAR + Q_UNUSED(other); +#else + if (i == 0) + return toolBarAreaLayout.unplug(path, other ? &other->toolBarAreaLayout : 0); +#endif + +#ifndef QT_NO_DOCKWIDGET + if (i == 1) + return dockAreaLayout.unplug(path); +#endif //QT_NO_DOCKWIDGET + + return 0; +} + +void QMainWindowLayoutState::saveState(QDataStream &stream) const +{ +#ifndef QT_NO_DOCKWIDGET + dockAreaLayout.saveState(stream); +#endif +#ifndef QT_NO_TOOLBAR + toolBarAreaLayout.saveState(stream); +#endif +} + +template <typename T> +static QList<T> findChildrenHelper(const QObject *o) +{ + const QObjectList &list = o->children(); + QList<T> result; + + for (int i=0; i < list.size(); ++i) { + if (T t = qobject_cast<T>(list[i])) { + result.append(t); + } + } + + return result; +} + +//pre4.3 tests the format that was used before 4.3 +bool QMainWindowLayoutState::checkFormat(QDataStream &stream, bool pre43) +{ +#ifdef QT_NO_TOOLBAR + Q_UNUSED(pre43); +#endif + while (!stream.atEnd()) { + uchar marker; + stream >> marker; + switch(marker) + { +#ifndef QT_NO_TOOLBAR + case QToolBarAreaLayout::ToolBarStateMarker: + case QToolBarAreaLayout::ToolBarStateMarkerEx: + { + QList<QToolBar *> toolBars = findChildrenHelper<QToolBar*>(mainWindow); + if (!toolBarAreaLayout.restoreState(stream, toolBars, marker, + pre43 /*testing 4.3 format*/, true /*testing*/)) { + return false; + } + } + break; +#endif // QT_NO_TOOLBAR + +#ifndef QT_NO_DOCKWIDGET + case QDockAreaLayout::DockWidgetStateMarker: + { + QList<QDockWidget *> dockWidgets = findChildrenHelper<QDockWidget*>(mainWindow); + if (!dockAreaLayout.restoreState(stream, dockWidgets, true /*testing*/)) { + return false; + } + } + break; +#endif + default: + //there was an error during the parsing + return false; + }// switch + } //while + + //everything went fine: it must be a pre-4.3 saved state + return true; +} + +bool QMainWindowLayoutState::restoreState(QDataStream &_stream, + const QMainWindowLayoutState &oldState) +{ + //make a copy of the data so that we can read it more than once + QByteArray copy; + while(!_stream.atEnd()) { + int length = 1024; + QByteArray ba(length, '\0'); + length = _stream.readRawData(ba.data(), ba.size()); + ba.resize(length); + copy += ba; + } + + QDataStream ds(copy); + const bool oldFormat = !checkFormat(ds, false); + if (oldFormat) { + //we should try with the old format + QDataStream ds2(copy); + if (!checkFormat(ds2, true)) { + return false; //format unknown + } + } + + QDataStream stream(copy); + + while (!stream.atEnd()) { + uchar marker; + stream >> marker; + switch(marker) + { +#ifndef QT_NO_DOCKWIDGET + case QDockAreaLayout::DockWidgetStateMarker: + { + QList<QDockWidget *> dockWidgets = findChildrenHelper<QDockWidget*>(mainWindow); + if (!dockAreaLayout.restoreState(stream, dockWidgets)) + return false; + + for (int i = 0; i < dockWidgets.size(); ++i) { + QDockWidget *w = dockWidgets.at(i); + QList<int> path = dockAreaLayout.indexOf(w); + if (path.isEmpty()) { + QList<int> oldPath = oldState.dockAreaLayout.indexOf(w); + if (oldPath.isEmpty()) { + continue; + } + QDockAreaLayoutInfo *info = dockAreaLayout.info(oldPath); + if (info == 0) { + continue; + } + info->item_list.append(QDockAreaLayoutItem(new QDockWidgetItem(w))); + } + } + } + break; +#endif // QT_NO_DOCKWIDGET + +#ifndef QT_NO_TOOLBAR + case QToolBarAreaLayout::ToolBarStateMarker: + case QToolBarAreaLayout::ToolBarStateMarkerEx: + { + QList<QToolBar *> toolBars = findChildrenHelper<QToolBar*>(mainWindow); + if (!toolBarAreaLayout.restoreState(stream, toolBars, marker, oldFormat)) + return false; + + for (int i = 0; i < toolBars.size(); ++i) { + QToolBar *w = toolBars.at(i); + QList<int> path = toolBarAreaLayout.indexOf(w); + if (path.isEmpty()) { + QList<int> oldPath = oldState.toolBarAreaLayout.indexOf(w); + if (oldPath.isEmpty()) { + continue; + } + toolBarAreaLayout.docks[oldPath.at(0)].insertToolBar(0, w); + } + } + } + break; +#endif //QT_NO_TOOLBAR + default: + return false; + }// switch + } //while + + + return true; +} + +/****************************************************************************** +** QMainWindowLayoutState - toolbars +*/ + +#ifndef QT_NO_TOOLBAR + +static inline void validateToolBarArea(Qt::ToolBarArea &area) +{ + switch (area) { + case Qt::LeftToolBarArea: + case Qt::RightToolBarArea: + case Qt::TopToolBarArea: + case Qt::BottomToolBarArea: + break; + default: + area = Qt::TopToolBarArea; + } +} + +static QInternal::DockPosition toDockPos(Qt::ToolBarArea area) +{ + switch (area) { + case Qt::LeftToolBarArea: return QInternal::LeftDock; + case Qt::RightToolBarArea: return QInternal::RightDock; + case Qt::TopToolBarArea: return QInternal::TopDock; + case Qt::BottomToolBarArea: return QInternal::BottomDock; + default: + break; + } + + return QInternal::DockCount; +} + +static Qt::ToolBarArea toToolBarArea(QInternal::DockPosition pos) +{ + switch (pos) { + case QInternal::LeftDock: return Qt::LeftToolBarArea; + case QInternal::RightDock: return Qt::RightToolBarArea; + case QInternal::TopDock: return Qt::TopToolBarArea; + case QInternal::BottomDock: return Qt::BottomToolBarArea; + default: break; + } + return Qt::NoToolBarArea; +} + +static inline Qt::ToolBarArea toToolBarArea(int pos) +{ + return toToolBarArea(static_cast<QInternal::DockPosition>(pos)); +} + +void QMainWindowLayout::addToolBarBreak(Qt::ToolBarArea area) +{ + validateToolBarArea(area); + + layoutState.toolBarAreaLayout.addToolBarBreak(toDockPos(area)); + if (savedState.isValid()) + savedState.toolBarAreaLayout.addToolBarBreak(toDockPos(area)); + + invalidate(); +} + +void QMainWindowLayout::insertToolBarBreak(QToolBar *before) +{ + layoutState.toolBarAreaLayout.insertToolBarBreak(before); + if (savedState.isValid()) + savedState.toolBarAreaLayout.insertToolBarBreak(before); + invalidate(); +} + +void QMainWindowLayout::removeToolBarBreak(QToolBar *before) +{ + layoutState.toolBarAreaLayout.removeToolBarBreak(before); + if (savedState.isValid()) + savedState.toolBarAreaLayout.removeToolBarBreak(before); + invalidate(); +} + +void QMainWindowLayout::moveToolBar(QToolBar *toolbar, int pos) +{ + layoutState.toolBarAreaLayout.moveToolBar(toolbar, pos); + if (savedState.isValid()) + savedState.toolBarAreaLayout.moveToolBar(toolbar, pos); + invalidate(); +} + +/* Removes the toolbar from the mainwindow so that it can be added again. Does not + explicitly hide the toolbar. */ +void QMainWindowLayout::removeToolBar(QToolBar *toolbar) +{ + if (toolbar) { + QObject::disconnect(parentWidget(), SIGNAL(iconSizeChanged(QSize)), + toolbar, SLOT(_q_updateIconSize(QSize))); + QObject::disconnect(parentWidget(), SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)), + toolbar, SLOT(_q_updateToolButtonStyle(Qt::ToolButtonStyle))); + +#ifdef Q_WS_MAC + if (usesHIToolBar(toolbar)) { + removeFromMacToolbar(toolbar); + } else +#endif // Q_WS_MAC + { + removeWidget(toolbar); + } + } +} + +/*! + Adds \a toolbar to \a area, continuing the current line. +*/ +void QMainWindowLayout::addToolBar(Qt::ToolBarArea area, + QToolBar *toolbar, + bool) +{ + validateToolBarArea(area); +#ifdef Q_WS_MAC + if ((area == Qt::TopToolBarArea) + && layoutState.mainWindow->unifiedTitleAndToolBarOnMac()) { + insertIntoMacToolbar(0, toolbar); + } else +#endif + { + //let's add the toolbar to the layout + addChildWidget(toolbar); + QLayoutItem * item = layoutState.toolBarAreaLayout.addToolBar(toDockPos(area), toolbar); + if (savedState.isValid() && item) { + // copy the toolbar also in the saved state + savedState.toolBarAreaLayout.insertItem(toDockPos(area), item); + } + invalidate(); + + //this ensures that the toolbar has the right window flags (not floating any more) + toolbar->d_func()->updateWindowFlags(false /*floating*/); + } +} + +/*! + Adds \a toolbar before \a before +*/ +void QMainWindowLayout::insertToolBar(QToolBar *before, QToolBar *toolbar) +{ +#ifdef Q_WS_MAC + if (usesHIToolBar(before)) { + insertIntoMacToolbar(before, toolbar); + } else +#endif // Q_WS_MAC + { + addChildWidget(toolbar); + QLayoutItem * item = layoutState.toolBarAreaLayout.insertToolBar(before, toolbar); + if (savedState.isValid() && item) { + // copy the toolbar also in the saved state + savedState.toolBarAreaLayout.insertItem(before, item); + } + if (!currentGapPos.isEmpty() && currentGapPos.first() == 0) { + currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex(); + if (!currentGapPos.isEmpty()) { + currentGapPos.prepend(0); + currentGapRect = layoutState.itemRect(currentGapPos); + } + } + invalidate(); + } +} + +Qt::ToolBarArea QMainWindowLayout::toolBarArea(QToolBar *toolbar) const +{ + QInternal::DockPosition pos = layoutState.toolBarAreaLayout.findToolBar(toolbar); + switch (pos) { + case QInternal::LeftDock: return Qt::LeftToolBarArea; + case QInternal::RightDock: return Qt::RightToolBarArea; + case QInternal::TopDock: return Qt::TopToolBarArea; + case QInternal::BottomDock: return Qt::BottomToolBarArea; + default: break; + } +#ifdef Q_WS_MAC + if (pos == QInternal::DockCount) { + if (qtoolbarsInUnifiedToolbarList.contains(toolbar)) + return Qt::TopToolBarArea; + } +#endif + return Qt::NoToolBarArea; +} + +bool QMainWindowLayout::toolBarBreak(QToolBar *toolBar) const +{ + return layoutState.toolBarAreaLayout.toolBarBreak(toolBar); +} + +void QMainWindowLayout::getStyleOptionInfo(QStyleOptionToolBar *option, QToolBar *toolBar) const +{ + option->toolBarArea = toolBarArea(toolBar); + layoutState.toolBarAreaLayout.getStyleOptionInfo(option, toolBar); +} + +void QMainWindowLayout::toggleToolBarsVisible() +{ + layoutState.toolBarAreaLayout.visible = !layoutState.toolBarAreaLayout.visible; + if (!layoutState.mainWindow->isMaximized()){ + QPoint topLeft = parentWidget()->geometry().topLeft(); + QRect r = parentWidget()->geometry(); + r = layoutState.toolBarAreaLayout.rectHint(r); + r.moveTo(topLeft); + parentWidget()->setGeometry(r); +// widgetAnimator->animate(parentWidget(), r, true); + } else{ + update(); + } +} + +#endif // QT_NO_TOOLBAR + +/****************************************************************************** +** QMainWindowLayoutState - dock areas +*/ + +#ifndef QT_NO_DOCKWIDGET + +static inline void validateDockWidgetArea(Qt::DockWidgetArea &area) +{ + switch (area) { + case Qt::LeftDockWidgetArea: + case Qt::RightDockWidgetArea: + case Qt::TopDockWidgetArea: + case Qt::BottomDockWidgetArea: + break; + default: + area = Qt::LeftDockWidgetArea; + } +} + +static QInternal::DockPosition toDockPos(Qt::DockWidgetArea area) +{ + switch (area) { + case Qt::LeftDockWidgetArea: return QInternal::LeftDock; + case Qt::RightDockWidgetArea: return QInternal::RightDock; + case Qt::TopDockWidgetArea: return QInternal::TopDock; + case Qt::BottomDockWidgetArea: return QInternal::BottomDock; + default: + break; + } + + return QInternal::DockCount; +} + +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; +} + +inline static Qt::DockWidgetArea toDockWidgetArea(int pos) +{ + return toDockWidgetArea(static_cast<QInternal::DockPosition>(pos)); +} + +void QMainWindowLayout::setCorner(Qt::Corner corner, Qt::DockWidgetArea area) +{ + if (layoutState.dockAreaLayout.corners[corner] == area) + return; + layoutState.dockAreaLayout.corners[corner] = area; + if (savedState.isValid()) + savedState.dockAreaLayout.corners[corner] = area; + invalidate(); +} + +Qt::DockWidgetArea QMainWindowLayout::corner(Qt::Corner corner) const +{ + return layoutState.dockAreaLayout.corners[corner]; +} + +void QMainWindowLayout::addDockWidget(Qt::DockWidgetArea area, + QDockWidget *dockwidget, + Qt::Orientation orientation) +{ + addChildWidget(dockwidget); + + // If we are currently moving a separator, then we need to abort the move, since each + // time we move the mouse layoutState is replaced by savedState modified by the move. + if (!movingSeparator.isEmpty()) + endSeparatorMove(movingSeparatorPos); + + layoutState.dockAreaLayout.addDockWidget(toDockPos(area), dockwidget, orientation); + emit dockwidget->dockLocationChanged(area); + invalidate(); +} + +void QMainWindowLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second) +{ + addChildWidget(second); + layoutState.dockAreaLayout.tabifyDockWidget(first, second); + emit second->dockLocationChanged(dockWidgetArea(first)); + invalidate(); +} + +bool QMainWindowLayout::restoreDockWidget(QDockWidget *dockwidget) +{ + addChildWidget(dockwidget); + if (!layoutState.dockAreaLayout.restoreDockWidget(dockwidget)) + return false; + emit dockwidget->dockLocationChanged(dockWidgetArea(dockwidget)); + invalidate(); + return true; +} + +#ifndef QT_NO_TABBAR +bool QMainWindowLayout::documentMode() const +{ + return _documentMode; +} + +void QMainWindowLayout::setDocumentMode(bool enabled) +{ + if (_documentMode == enabled) + return; + + _documentMode = enabled; + + // Update the document mode for all tab bars + foreach (QTabBar *bar, usedTabBars) + bar->setDocumentMode(_documentMode); + foreach (QTabBar *bar, unusedTabBars) + bar->setDocumentMode(_documentMode); +} +#endif // QT_NO_TABBAR + +void QMainWindowLayout::setVerticalTabsEnabled(bool enabled) +{ +#ifdef QT_NO_TABBAR + Q_UNUSED(enabled); +#else + if (verticalTabsEnabled == enabled) + return; + + verticalTabsEnabled = enabled; + + updateTabBarShapes(); +#endif // QT_NO_TABBAR +} + +#ifndef QT_NO_TABWIDGET +QTabWidget::TabShape QMainWindowLayout::tabShape() const +{ + return _tabShape; +} + +void QMainWindowLayout::setTabShape(QTabWidget::TabShape tabShape) +{ + if (_tabShape == tabShape) + return; + + _tabShape = tabShape; + + updateTabBarShapes(); +} + +QTabWidget::TabPosition QMainWindowLayout::tabPosition(Qt::DockWidgetArea area) const +{ + return tabPositions[toDockPos(area)]; +} + +void QMainWindowLayout::setTabPosition(Qt::DockWidgetAreas areas, QTabWidget::TabPosition tabPosition) +{ + const Qt::DockWidgetArea dockWidgetAreas[] = { + Qt::TopDockWidgetArea, + Qt::LeftDockWidgetArea, + Qt::BottomDockWidgetArea, + Qt::RightDockWidgetArea + }; + const QInternal::DockPosition dockPositions[] = { + QInternal::TopDock, + QInternal::LeftDock, + QInternal::BottomDock, + QInternal::RightDock + }; + + for (int i = 0; i < QInternal::DockCount; ++i) + if (areas & dockWidgetAreas[i]) + tabPositions[dockPositions[i]] = tabPosition; + + updateTabBarShapes(); +} + +static inline QTabBar::Shape tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position) +{ + const bool rounded = (shape == QTabWidget::Rounded); + if (position == QTabWidget::North) + return rounded ? QTabBar::RoundedNorth : QTabBar::TriangularNorth; + if (position == QTabWidget::South) + return rounded ? QTabBar::RoundedSouth : QTabBar::TriangularSouth; + if (position == QTabWidget::East) + return rounded ? QTabBar::RoundedEast : QTabBar::TriangularEast; + if (position == QTabWidget::West) + return rounded ? QTabBar::RoundedWest : QTabBar::TriangularWest; + return QTabBar::RoundedNorth; +} +#endif // QT_NO_TABWIDGET + +#ifndef QT_NO_TABBAR +void QMainWindowLayout::updateTabBarShapes() +{ +#ifndef QT_NO_TABWIDGET + const QTabWidget::TabPosition vertical[] = { + QTabWidget::West, + QTabWidget::East, + QTabWidget::North, + QTabWidget::South + }; +#else + const QTabBar::Shape vertical[] = { + QTabBar::RoundedWest, + QTabBar::RoundedEast, + QTabBar::RoundedNorth, + QTabBar::RoundedSouth + }; +#endif + + QDockAreaLayout &layout = layoutState.dockAreaLayout; + + for (int i = 0; i < QInternal::DockCount; ++i) { +#ifndef QT_NO_TABWIDGET + QTabWidget::TabPosition pos = verticalTabsEnabled ? vertical[i] : tabPositions[i]; + QTabBar::Shape shape = tabBarShapeFrom(_tabShape, pos); +#else + QTabBar::Shape shape = verticalTabsEnabled ? vertical[i] : QTabBar::RoundedSouth; +#endif + layout.docks[i].setTabBarShape(shape); + } +} +#endif // QT_NO_TABBAR + +void QMainWindowLayout::splitDockWidget(QDockWidget *after, + QDockWidget *dockwidget, + Qt::Orientation orientation) +{ + addChildWidget(dockwidget); + layoutState.dockAreaLayout.splitDockWidget(after, dockwidget, orientation); + emit dockwidget->dockLocationChanged(dockWidgetArea(after)); + invalidate(); +} + +Qt::DockWidgetArea QMainWindowLayout::dockWidgetArea(QDockWidget *widget) const +{ + QList<int> pathToWidget = layoutState.dockAreaLayout.indexOf(widget); + if (pathToWidget.isEmpty()) + return Qt::NoDockWidgetArea; + return toDockWidgetArea(pathToWidget.first()); +} + +void QMainWindowLayout::keepSize(QDockWidget *w) +{ + layoutState.dockAreaLayout.keepSize(w); +} + +#ifndef QT_NO_TABBAR + +class QMainWindowTabBar : public QTabBar +{ +public: + QMainWindowTabBar(QWidget *parent); +protected: + bool event(QEvent *e); +}; + +QMainWindowTabBar::QMainWindowTabBar(QWidget *parent) + : QTabBar(parent) +{ + setExpanding(false); +} + +bool QMainWindowTabBar::event(QEvent *e) +{ + // show the tooltip if tab is too small to fit label + + if (e->type() != QEvent::ToolTip) + return QTabBar::event(e); + QSize size = this->size(); + QSize hint = sizeHint(); + if (shape() == QTabBar::RoundedWest || shape() == QTabBar::RoundedEast) { + size.transpose(); + hint.transpose(); + } + if (size.width() < hint.width()) + return QTabBar::event(e); + e->accept(); + return true; +} + +QTabBar *QMainWindowLayout::getTabBar() +{ + QTabBar *result = 0; + if (!unusedTabBars.isEmpty()) { + result = unusedTabBars.takeLast(); + } else { + result = new QMainWindowTabBar(parentWidget()); + result->setDrawBase(true); + result->setElideMode(Qt::ElideRight); + result->setDocumentMode(_documentMode); + connect(result, SIGNAL(currentChanged(int)), this, SLOT(tabChanged())); + } + + usedTabBars.insert(result); + return result; +} + +// Allocates a new separator widget if needed +QWidget *QMainWindowLayout::getSeparatorWidget() +{ + QWidget *result = 0; + if (!unusedSeparatorWidgets.isEmpty()) { + result = unusedSeparatorWidgets.takeLast(); + } else { + result = new QWidget(parentWidget()); + result->setAttribute(Qt::WA_MouseNoMask, true); + result->setAutoFillBackground(false); + result->setObjectName(QLatin1String("qt_qmainwindow_extended_splitter")); + } + usedSeparatorWidgets.insert(result); + return result; +} + +void QMainWindowLayout::tabChanged() +{ + QTabBar *tb = qobject_cast<QTabBar*>(sender()); + if (tb == 0) + return; + QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(tb); + if (info == 0) + return; + info->apply(false); + + if (QWidget *w = centralWidget()) + w->raise(); +} +#endif // QT_NO_TABBAR + +bool QMainWindowLayout::startSeparatorMove(const QPoint &pos) +{ + movingSeparator = layoutState.dockAreaLayout.findSeparator(pos); + + if (movingSeparator.isEmpty()) + return false; + + savedState = layoutState; + movingSeparatorPos = movingSeparatorOrigin = pos; + + return true; +} + +bool QMainWindowLayout::separatorMove(const QPoint &pos) +{ + if (movingSeparator.isEmpty()) + return false; + movingSeparatorPos = pos; + separatorMoveTimer->start(); + return true; +} + +void QMainWindowLayout::doSeparatorMove() +{ + if (movingSeparator.isEmpty()) + return; + if (movingSeparatorOrigin == movingSeparatorPos) + return; + + layoutState = savedState; + layoutState.dockAreaLayout.separatorMove(movingSeparator, movingSeparatorOrigin, + movingSeparatorPos, + &separatorMoveCache); + movingSeparatorPos = movingSeparatorOrigin; +} + +bool QMainWindowLayout::endSeparatorMove(const QPoint&) +{ + bool result = !movingSeparator.isEmpty(); + movingSeparator.clear(); + savedState.clear(); + separatorMoveCache.clear(); + return result; +} + +void QMainWindowLayout::raise(QDockWidget *widget) +{ + QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(widget); + if (info == 0) + return; +#ifndef QT_NO_TABBAR + if (!info->tabbed) + return; + info->setCurrentTab(widget); +#endif +} + +#endif // QT_NO_DOCKWIDGET + + +/****************************************************************************** +** QMainWindowLayoutState - layout interface +*/ + +int QMainWindowLayout::count() const +{ + qWarning("QMainWindowLayout::count: ?"); + return 0; //################################################# +} + +QLayoutItem *QMainWindowLayout::itemAt(int index) const +{ + int x = 0; + + if (QLayoutItem *ret = layoutState.itemAt(index, &x)) + return ret; + + if (statusbar && x++ == index) + return statusbar; + + return 0; +} + +QLayoutItem *QMainWindowLayout::takeAt(int index) +{ + int x = 0; + + if (QLayoutItem *ret = layoutState.takeAt(index, &x)) { + // the widget might in fact have been destroyed by now + if (QWidget *w = ret->widget()) { + widgetAnimator->abort(w); + if (w == pluggingWidget) + pluggingWidget = 0; + } + + if (savedState.isValid() ) { + //we need to remove the item also from the saved state to prevent crash + savedState.remove(ret); + //Also, the item may be contained several times as a gap item. + layoutState.remove(ret); + } + +#ifndef QT_NO_TOOLBAR + if (!currentGapPos.isEmpty() && currentGapPos.first() == 0) { + currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex(); + if (!currentGapPos.isEmpty()) { + currentGapPos.prepend(0); + currentGapRect = layoutState.itemRect(currentGapPos); + } + } +#endif + + return ret; + } + + if (statusbar && x++ == index) { + QLayoutItem *ret = statusbar; + statusbar = 0; + return ret; + } + + return 0; +} + +void QMainWindowLayout::setGeometry(const QRect &_r) +{ + if (savedState.isValid()) + return; + + QRect r = _r; + + QLayout::setGeometry(r); + + if (statusbar) { + QRect sbr(QPoint(0, 0), + QSize(r.width(), statusbar->heightForWidth(r.width())) + .expandedTo(statusbar->minimumSize())); + sbr.moveBottom(r.bottom()); + QRect vr = QStyle::visualRect(QApplication::layoutDirection(), _r, sbr); + statusbar->setGeometry(vr); + r.setBottom(sbr.top() - 1); + } + + layoutState.rect = r; + layoutState.fitLayout(); + applyState(layoutState, false); +} + +void QMainWindowLayout::addItem(QLayoutItem *) +{ qWarning("QMainWindowLayout::addItem: Please use the public QMainWindow API instead"); } + +QSize QMainWindowLayout::sizeHint() const +{ + if (!szHint.isValid()) { + szHint = layoutState.sizeHint(); + const QSize sbHint = statusbar ? statusbar->sizeHint() : QSize(0, 0); + szHint = QSize(qMax(sbHint.width(), szHint.width()), + sbHint.height() + szHint.height()); + } + return szHint; +} + +QSize QMainWindowLayout::minimumSize() const +{ + if (!minSize.isValid()) { + minSize = layoutState.minimumSize(); + const QSize sbMin = statusbar ? statusbar->minimumSize() : QSize(0, 0); + minSize = QSize(qMax(sbMin.width(), minSize.width()), + sbMin.height() + minSize.height()); +#ifdef Q_WS_MAC + const QSize storedSize = minSize; + int minWidth = 0; + foreach (QToolBar *toolbar, qtoolbarsInUnifiedToolbarList) { + minWidth += toolbar->sizeHint().width() + 20; + } + minSize = QSize(qMax(minWidth, storedSize.width()), storedSize.height()); +#endif + } + return minSize; +} + +void QMainWindowLayout::invalidate() +{ + QLayout::invalidate(); + minSize = szHint = QSize(); +} + +/****************************************************************************** +** QMainWindowLayout - remaining stuff +*/ + +static void fixToolBarOrientation(QLayoutItem *item, int dockPos) +{ +#ifndef QT_NO_TOOLBAR + QToolBar *toolBar = qobject_cast<QToolBar*>(item->widget()); + if (toolBar == 0) + return; + + QRect oldGeo = toolBar->geometry(); + + QInternal::DockPosition pos + = static_cast<QInternal::DockPosition>(dockPos); + Qt::Orientation o = pos == QInternal::TopDock || pos == QInternal::BottomDock + ? Qt::Horizontal : Qt::Vertical; + if (o != toolBar->orientation()) + toolBar->setOrientation(o); + + QSize hint = toolBar->sizeHint().boundedTo(toolBar->maximumSize()) + .expandedTo(toolBar->minimumSize()); + + if (toolBar->size() != hint) { + QRect newGeo(oldGeo.topLeft(), hint); + if (toolBar->layoutDirection() == Qt::RightToLeft) + newGeo.moveRight(oldGeo.right()); + toolBar->setGeometry(newGeo); + } + +#else + Q_UNUSED(item); + Q_UNUSED(dockPos); +#endif +} + +void QMainWindowLayout::revert(QLayoutItem *widgetItem) +{ + if (!savedState.isValid()) + return; + + QWidget *widget = widgetItem->widget(); + layoutState = savedState; + currentGapPos = layoutState.indexOf(widget); + fixToolBarOrientation(widgetItem, currentGapPos.at(1)); + layoutState.unplug(currentGapPos); + layoutState.fitLayout(); + currentGapRect = layoutState.itemRect(currentGapPos); + + plug(widgetItem); +} + +bool QMainWindowLayout::plug(QLayoutItem *widgetItem) +{ + if (!parentWidget()->isVisible() || parentWidget()->isMinimized() || currentGapPos.isEmpty()) + return false; + + fixToolBarOrientation(widgetItem, currentGapPos.at(1)); + + QWidget *widget = widgetItem->widget(); + + QList<int> previousPath = layoutState.indexOf(widget); + + QLayoutItem *it = layoutState.plug(currentGapPos); + Q_ASSERT(it == widgetItem); + Q_UNUSED(it); + if (!previousPath.isEmpty()) + layoutState.remove(previousPath); + + if (dockOptions & QMainWindow::AnimatedDocks) { + pluggingWidget = widget; + QRect globalRect = currentGapRect; + globalRect.moveTopLeft(parentWidget()->mapToGlobal(globalRect.topLeft())); +#ifndef QT_NO_DOCKWIDGET + if (qobject_cast<QDockWidget*>(widget) != 0) { + QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(widget->layout()); + if (layout->nativeWindowDeco()) { + globalRect.adjust(0, layout->titleHeight(), 0, 0); + } else { + int fw = widget->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, widget); + globalRect.adjust(-fw, -fw, fw, fw); + } + } +#endif + widgetAnimator->animate(widget, globalRect, + dockOptions & QMainWindow::AnimatedDocks); + } else { +#ifndef QT_NO_DOCKWIDGET + if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) + dw->d_func()->plug(currentGapRect); +#endif +#ifndef QT_NO_TOOLBAR + if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) + tb->d_func()->plug(currentGapRect); +#endif + applyState(layoutState); + savedState.clear(); +#ifndef QT_NO_DOCKWIDGET + parentWidget()->update(layoutState.dockAreaLayout.separatorRegion()); +#endif + currentGapPos.clear(); + updateGapIndicator(); + } + + return true; +} + +void QMainWindowLayout::allAnimationsFinished() +{ +#ifndef QT_NO_DOCKWIDGET + parentWidget()->update(layoutState.dockAreaLayout.separatorRegion()); + +#ifndef QT_NO_TABBAR + foreach (QTabBar *tab_bar, usedTabBars) + tab_bar->show(); +#endif // QT_NO_TABBAR +#endif // QT_NO_DOCKWIDGET + + updateGapIndicator(); +} + +void QMainWindowLayout::animationFinished(QWidget *widget) +{ + + /* This signal is delivered from QWidgetAnimator over a qeued connection. The problem is that + the widget can be deleted. This is handled as follows: + + The animator only ever animates widgets that have been added to this layout. If a widget + is deleted during animation, the widget's destructor removes the widget form this layout. + This in turn aborts the animation (see takeAt()) and this signal will never be delivered. + + If the widget is deleted after the animation is finished but before this qeued signal + is delivered, the widget is no longer in the layout and we catch it here. The key is that + QMainWindowLayoutState::contains() never dereferences the pointer. */ + + if (!layoutState.contains(widget)) + return; + +#ifndef QT_NO_TOOLBAR + if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) { + QToolBarLayout *tbl = qobject_cast<QToolBarLayout*>(tb->layout()); + if (tbl->animating) { + tbl->animating = false; + if (tbl->expanded) + tbl->layoutActions(tb->size()); + tb->update(); + } + } +#endif + + if (widget != pluggingWidget) + return; + +#ifndef QT_NO_DOCKWIDGET + if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) + dw->d_func()->plug(currentGapRect); +#endif +#ifndef QT_NO_TOOLBAR + if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) + tb->d_func()->plug(currentGapRect); +#endif + + applyState(layoutState, false); +#ifndef QT_NO_DOCKWIDGET +#ifndef QT_NO_TABBAR + if (qobject_cast<QDockWidget*>(widget) != 0) { + // info() might return null if the widget is destroyed while + // animating but before the animationFinished signal is received. + if (QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(widget)) + info->setCurrentTab(widget); + } +#endif +#endif + savedState.clear(); + currentGapPos.clear(); + pluggingWidget = 0; + updateGapIndicator(); +} + +void QMainWindowLayout::restore(bool keepSavedState) +{ + if (!savedState.isValid()) + return; + + layoutState = savedState; + applyState(layoutState); + if (!keepSavedState) + savedState.clear(); + currentGapPos.clear(); + pluggingWidget = 0; + updateGapIndicator(); +} + +QMainWindowLayout::QMainWindowLayout(QMainWindow *mainwindow) + : QLayout(mainwindow) + , layoutState(mainwindow) + , savedState(mainwindow) + , dockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowTabbedDocks) + , statusbar(0) +#ifndef QT_NO_DOCKWIDGET +#ifndef QT_NO_TABBAR + , _documentMode(false) + , verticalTabsEnabled(false) +#ifndef QT_NO_TABWIDGET + , _tabShape(QTabWidget::Rounded) +#endif +#endif +#endif // QT_NO_DOCKWIDGET +{ +#ifndef QT_NO_DOCKWIDGET +#ifndef QT_NO_TABBAR + sep = mainwindow->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent, 0, mainwindow); +#endif + separatorMoveTimer = new QTimer(this); + separatorMoveTimer->setSingleShot(true); + separatorMoveTimer->setInterval(0); + connect(separatorMoveTimer, SIGNAL(timeout()), this, SLOT(doSeparatorMove())); + +#ifndef QT_NO_TABWIDGET + for (int i = 0; i < QInternal::DockCount; ++i) + tabPositions[i] = QTabWidget::South; +#endif +#endif // QT_NO_DOCKWIDGET + +#ifndef QT_NO_RUBBERBAND + gapIndicator = new QRubberBand(QRubberBand::Rectangle, mainwindow); + // For accessibility to identify this special widget. + gapIndicator->setObjectName(QLatin1String("qt_rubberband")); + + gapIndicator->hide(); +#endif + pluggingWidget = 0; + + setObjectName(mainwindow->objectName() + QLatin1String("_layout")); + widgetAnimator = new QWidgetAnimator(this); + connect(widgetAnimator, SIGNAL(finished(QWidget*)), + this, SLOT(animationFinished(QWidget*)), Qt::QueuedConnection); + connect(widgetAnimator, SIGNAL(finishedAll()), + this, SLOT(allAnimationsFinished())); +} + +QMainWindowLayout::~QMainWindowLayout() +{ + layoutState.deleteAllLayoutItems(); + layoutState.deleteCentralWidgetItem(); + +#ifdef Q_WS_MAC + cleanUpMacToolbarItems(); +#endif + + delete statusbar; +} + +void QMainWindowLayout::setDockOptions(QMainWindow::DockOptions opts) +{ + if (opts == dockOptions) + return; + + dockOptions = opts; + +#ifndef QT_NO_DOCKWIDGET + setVerticalTabsEnabled(opts & QMainWindow::VerticalTabs); +#endif + + invalidate(); +} + +#ifndef QT_NO_STATUSBAR +QStatusBar *QMainWindowLayout::statusBar() const +{ return statusbar ? qobject_cast<QStatusBar *>(statusbar->widget()) : 0; } + +void QMainWindowLayout::setStatusBar(QStatusBar *sb) +{ + if (sb) + addChildWidget(sb); + delete statusbar; + statusbar = sb ? new QWidgetItemV2(sb) : 0; + invalidate(); +} +#endif // QT_NO_STATUSBAR + +QWidget *QMainWindowLayout::centralWidget() const +{ + return layoutState.centralWidget(); +} + +void QMainWindowLayout::setCentralWidget(QWidget *widget) +{ + if (widget != 0) + addChildWidget(widget); + layoutState.setCentralWidget(widget); + if (savedState.isValid()) { +#ifndef QT_NO_DOCKWIDGET + savedState.dockAreaLayout.centralWidgetItem = layoutState.dockAreaLayout.centralWidgetItem; +#else + savedState.centralWidgetItem = layoutState.centralWidgetItem; +#endif + } + invalidate(); +} + +QLayoutItem *QMainWindowLayout::unplug(QWidget *widget) +{ + QList<int> path = layoutState.indexOf(widget); + if (path.isEmpty()) + return 0; + + QLayoutItem *item = layoutState.item(path); + if (widget->isWindow()) + return item; + + QRect r = layoutState.itemRect(path); + savedState = layoutState; + +#ifndef QT_NO_DOCKWIDGET + if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) { + dw->d_func()->unplug(r); + } +#endif +#ifndef QT_NO_TOOLBAR + if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) { + tb->d_func()->unplug(r); + } +#endif + + + layoutState.unplug(path ,&savedState); + savedState.fitLayout(); + currentGapPos = path; + currentGapRect = r; + updateGapIndicator(); + + fixToolBarOrientation(item, currentGapPos.at(1)); + + return item; +} + +void QMainWindowLayout::updateGapIndicator() +{ +#ifndef QT_NO_RUBBERBAND + if (widgetAnimator->animating() || currentGapPos.isEmpty()) { + gapIndicator->hide(); + } else { + if (gapIndicator->geometry() != currentGapRect) + gapIndicator->setGeometry(currentGapRect); + if (!gapIndicator->isVisible()) + gapIndicator->show(); + } +#endif +} + +QList<int> QMainWindowLayout::hover(QLayoutItem *widgetItem, const QPoint &mousePos) +{ + if (!parentWidget()->isVisible() || parentWidget()->isMinimized() + || pluggingWidget != 0 || widgetItem == 0) + return QList<int>(); + + QWidget *widget = widgetItem->widget(); + QPoint pos = parentWidget()->mapFromGlobal(mousePos); + + if (!savedState.isValid()) + savedState = layoutState; + + QList<int> path = savedState.gapIndex(widget, pos); + + if (!path.isEmpty()) { + bool allowed = false; + +#ifndef QT_NO_DOCKWIDGET + if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) + allowed = dw->isAreaAllowed(toDockWidgetArea(path.at(1))); +#endif +#ifndef QT_NO_TOOLBAR + if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) + allowed = tb->isAreaAllowed(toToolBarArea(path.at(1))); +#endif + + if (!allowed) + path.clear(); + } + + if (path == currentGapPos) + return currentGapPos; // the gap is already there + + currentGapPos = path; + if (path.isEmpty()) { + fixToolBarOrientation(widgetItem, 2); // 2 = top dock, ie. horizontal + restore(true); + return QList<int>(); + } + + fixToolBarOrientation(widgetItem, currentGapPos.at(1)); + + QMainWindowLayoutState newState = savedState; + + if (!newState.insertGap(path, widgetItem)) { + restore(true); // not enough space + return QList<int>(); + } + + QSize min = newState.minimumSize(); + QSize size = newState.rect.size(); + + if (min.width() > size.width() || min.height() > size.height()) { + restore(true); + return QList<int>(); + } + + newState.fitLayout(); + + currentGapRect = newState.gapRect(currentGapPos); + +#ifndef QT_NO_DOCKWIDGET + parentWidget()->update(layoutState.dockAreaLayout.separatorRegion()); +#endif + layoutState = newState; + applyState(layoutState); + + updateGapIndicator(); + + return path; +} + +void QMainWindowLayout::applyState(QMainWindowLayoutState &newState, bool animate) +{ +#ifndef QT_NO_DOCKWIDGET +#ifndef QT_NO_TABBAR + QSet<QTabBar*> used = newState.dockAreaLayout.usedTabBars(); + QSet<QTabBar*> retired = usedTabBars - used; + usedTabBars = used; + foreach (QTabBar *tab_bar, retired) { + tab_bar->hide(); + while (tab_bar->count() > 0) + tab_bar->removeTab(0); + unusedTabBars.append(tab_bar); + } + + if (sep == 1) { + QSet<QWidget*> usedSeps = newState.dockAreaLayout.usedSeparatorWidgets(); + QSet<QWidget*> retiredSeps = usedSeparatorWidgets - usedSeps; + usedSeparatorWidgets = usedSeps; + foreach (QWidget *sepWidget, retiredSeps) { + unusedSeparatorWidgets.append(sepWidget); + } + } + + +#endif // QT_NO_TABBAR +#endif // QT_NO_DOCKWIDGET + newState.apply(dockOptions & QMainWindow::AnimatedDocks && animate); +} + +void QMainWindowLayout::saveState(QDataStream &stream) const +{ + layoutState.saveState(stream); +} + +bool QMainWindowLayout::restoreState(QDataStream &stream) +{ + savedState = layoutState; + layoutState.clear(); + layoutState.rect = savedState.rect; + + if (!layoutState.restoreState(stream, savedState)) { + layoutState.deleteAllLayoutItems(); + layoutState = savedState; + if (parentWidget()->isVisible()) + applyState(layoutState, false); // hides tabBars allocated by newState + return false; + } + + if (parentWidget()->isVisible()) { + layoutState.fitLayout(); + applyState(layoutState, false); + } + + savedState.deleteAllLayoutItems(); + savedState.clear(); + +#ifndef QT_NO_DOCKWIDGET + if (parentWidget()->isVisible()) { +#ifndef QT_NO_TABBAR + foreach (QTabBar *tab_bar, usedTabBars) + tab_bar->show(); + +#endif + } +#endif // QT_NO_DOCKWIDGET + + return true; +} + + +// Returns if this toolbar *should* be using HIToolbar. Won't work for all in between cases +// for example, you have a toolbar in the top area and then you suddenly turn on +// HIToolbar. +bool QMainWindowLayout::usesHIToolBar(QToolBar *toolbar) const +{ +#ifndef Q_WS_MAC + Q_UNUSED(toolbar); + return false; +#else + return qtoolbarsInUnifiedToolbarList.contains(toolbar) + || ((toolBarArea(toolbar) == Qt::TopToolBarArea) + && layoutState.mainWindow->unifiedTitleAndToolBarOnMac()); +#endif +} + +QT_END_NAMESPACE + +#endif // QT_NO_MAINWINDOW |