/****************************************************************************
**
** Copyright (C) 2010 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 "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(const QList<int> &path, QLayoutItem *item)
{
if (path.isEmpty())
return false;
int i = path.first();
#ifndef QT_NO_TOOLBAR
if (i == 0) {
Q_ASSERT(qobject_cast<QToolBar*>(item->widget()) != 0);
return toolBarAreaLayout.insertGap(path.mid(1), item);
}
#endif
#ifndef QT_NO_DOCKWIDGET
if (i == 1) {
Q_ASSERT(qobject_cast<QDockWidget*>(item->widget()) != 0);
return dockAreaLayout.insertGap(path.mid(1), item);
}
#endif //QT_NO_DOCKWIDGET
return false;
}
void QMainWindowLayoutState::remove(const QList<int> &path)
{
int i = path.first();
#ifndef QT_NO_TOOLBAR
if (i == 0)
toolBarAreaLayout.remove(path.mid(1));
#endif
#ifndef QT_NO_DOCKWIDGET
if (i == 1)
dockAreaLayout.remove(path.mid(1));
#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();
#endif
rect = QRect();
}
bool QMainWindowLayoutState::isValid() const
{
return rect.isValid();
}
QLayoutItem *QMainWindowLayoutState::item(const QList<int> &path)
{
int i = path.first();
#ifndef QT_NO_TOOLBAR
if (i == 0)
return toolBarAreaLayout.item(path.mid(1)).widgetItem;
#endif
#ifndef QT_NO_DOCKWIDGET
if (i == 1)
return dockAreaLayout.item(path.mid(1)).widgetItem;
#endif //QT_NO_DOCKWIDGET
return 0;
}
QRect QMainWindowLayoutState::itemRect(const QList<int> &path) const
{
int i = path.first();
#ifndef QT_NO_TOOLBAR
if (i == 0)
return toolBarAreaLayout.itemRect(path.mid(1));
#endif
#ifndef QT_NO_DOCKWIDGET
if (i == 1)
return dockAreaLayout.itemRect(path.mid(1));
#endif //QT_NO_DOCKWIDGET
return QRect();
}
QRect QMainWindowLayoutState::gapRect(const QList<int> &path) const
{
int i = path.first();
#ifndef QT_NO_TOOLBAR
if (i == 0)
return toolBarAreaLayout.itemRect(path.mid(1));
#endif
#ifndef QT_NO_DOCKWIDGET
if (i == 1)
return dockAreaLayout.gapRect(path.mid(1));
#endif //QT_NO_DOCKWIDGET
return QRect();
}
QLayoutItem *QMainWindowLayoutState::plug(const QList<int> &path)
{
int i = path.first();
#ifndef QT_NO_TOOLBAR
if (i == 0)
return toolBarAreaLayout.plug(path.mid(1));
#endif
#ifndef QT_NO_DOCKWIDGET
if (i == 1)
return dockAreaLayout.plug(path.mid(1));
#endif //QT_NO_DOCKWIDGET
return 0;
}
QLayoutItem *QMainWindowLayoutState::unplug(const QList<int> &path, QMainWindowLayoutState *other)
{
int i = path.first();
#ifdef QT_NO_TOOLBAR
Q_UNUSED(other);
#else
if (i == 0)
return toolBarAreaLayout.unplug(path.mid(1), other ? &other->toolBarAreaLayout : 0);
#endif
#ifndef QT_NO_DOCKWIDGET
if (i == 1)
return dockAreaLayout.unplug(path.mid(1));
#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()
{
bool updateNonUnifiedParts = true;
#ifdef Q_WS_MAC
if (layoutState.mainWindow->unifiedTitleAndToolBarOnMac()) {
// If we hit this case, someone has pressed the "toolbar button" which will
// toggle the unified toolbar visiblity, because that's what the user wants.
// We might be in a situation where someone has hidden all the toolbars
// beforehand (maybe in construction), but now they've hit this button and
// and are expecting the items to show. What do we do?
// 1) Check the visibility of all the toolbars, if one is visible, do nothing, this
// preserves what people would expect (these toolbars were visible when I clicked last time).
// 2) If NONE are visible, then show them all. Again, this preserves the user expectation
// of, "I want to see the toolbars." The user may get more toolbars than expected, but this
// is better seeing nothing.
// Don't worry about any of this if we are going invisible. This does mean we may get
// into issues when switching into and out of fullscreen mode, but this is probably minor.
// If we ever need to do hiding, that would have to be taken care of after the unified toolbar
// has finished hiding.
// People can of course handle the QEvent::ToolBarChange event themselves and do
// WHATEVER they want if they don't like what we are doing (though the unified toolbar
// will fire regardless).
// Check if we REALLY need to update the geometry below. If we only have items in the
// unified toolbar, all the docks will be empty, so there's very little point
// in doing the geometry as Apple will do it (we also avoid flicker in Cocoa as well).
// FWIW, layoutState.toolBarAreaLayout.visible and the state of the unified toolbar
// visibility can get out of sync. I really don't think it's a big issue. It is kept
// to a minimum because we only change the visibility if we absolutely must.
// update the "non unified parts."
updateNonUnifiedParts = !layoutState.toolBarAreaLayout.isEmpty();
// We get this function before the unified toolbar does its thing.
// So, the value will be opposite of what we expect.
bool goingVisible = !macWindowToolbarIsVisible(qt_mac_window_for(layoutState.mainWindow));
if (goingVisible) {
const int ToolBarCount = qtoolbarsInUnifiedToolbarList.size();
bool needAllVisible = true;
for (int i = 0; i < ToolBarCount; ++i) {
if (!qtoolbarsInUnifiedToolbarList.at(i)->isHidden()) {
needAllVisible = false;
break;
}
}
if (needAllVisible) {
QBoolBlocker blocker(blockVisiblityCheck); // Disable the visibilty check because
// the toggle has already happened.
for (int i = 0; i < ToolBarCount; ++i)
qtoolbarsInUnifiedToolbarList.at(i)->setVisible(true);
}
}
if (!updateNonUnifiedParts)
layoutState.toolBarAreaLayout.visible = goingVisible;
}
#endif
if (updateNonUnifiedParts) {
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);
} 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(0, this);
return true;
}
bool QMainWindowLayout::endSeparatorMove(const QPoint&)
{
bool result = !movingSeparator.isEmpty();
movingSeparator.clear();
savedState.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(parentWidget()->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);
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);
return true;
}
void QMainWindowLayout::animationFinished(QWidget *widget)
{
//this function is called from within the Widget Animator whenever an animation is finished
//on a certain widget
#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) {
#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
savedState.clear();
currentGapPos.clear();
pluggingWidget = 0;
//applying the state will make sure that the currentGap is updated correctly
//and all the geometries (especially the one from the central widget) is correct
layoutState.apply(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
}
if (!widgetAnimator.animating()) {
//all animations are finished
#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::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
, widgetAnimator(this)
, pluggingWidget(0)
#ifndef QT_NO_RUBBERBAND
, gapIndicator(new QRubberBand(QRubberBand::Rectangle, mainwindow))
#endif //QT_NO_RUBBERBAND
#ifdef Q_WS_MAC
, blockVisiblityCheck(false)
#endif
{
#ifndef QT_NO_DOCKWIDGET
#ifndef QT_NO_TABBAR
sep = mainwindow->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent, 0, mainwindow);
#endif
#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
// For accessibility to identify this special widget.
gapIndicator->setObjectName(QLatin1String("qt_rubberband"));
gapIndicator->hide();
#endif
pluggingWidget = 0;
setObjectName(mainwindow->objectName() + QLatin1String("_layout"));
}
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;
savedState.dockAreaLayout.fallbackToSizeHints = true;
#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
gapIndicator->setVisible(!widgetAnimator.animating() && !currentGapPos.isEmpty());
gapIndicator->setGeometry(currentGapRect);
#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
}
void QMainWindowLayout::timerEvent(QTimerEvent *e)
{
#ifndef QT_NO_DOCKWIDGET
if (e->timerId() == separatorMoveTimer.timerId()) {
//let's move the separators
separatorMoveTimer.stop();
if (movingSeparator.isEmpty())
return;
if (movingSeparatorOrigin == movingSeparatorPos)
return;
//when moving the separator, we need to update the previous position
parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
layoutState = savedState;
layoutState.dockAreaLayout.separatorMove(movingSeparator, movingSeparatorOrigin,
movingSeparatorPos);
movingSeparatorPos = movingSeparatorOrigin;
}
#endif
QLayout::timerEvent(e);
}
QT_END_NAMESPACE
#endif // QT_NO_MAINWINDOW