/**************************************************************************** ** ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtWidgets module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** 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, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, 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. ** ** ** $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 "qtoolbar.h" #include "qtoolbarlayout_p.h" #include "qwidgetanimator_p.h" #include "qrubberband.h" #include "qtabbar_p.h" #include #include #include #include #include #include #include #include #ifndef QT_NO_DEBUG_STREAM # include # include #endif #include #include #ifdef Q_WS_MAC # include # include #endif QT_BEGIN_NAMESPACE #ifndef QT_NO_DOCKWIDGET extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window); #endif /****************************************************************************** ** debug */ #if !defined(QT_NO_DOCKWIDGET) && !defined(QT_NO_DEBUG_STREAM) 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'; } } static void dumpLayout(QTextStream &qout, const QDockAreaLayoutInfo &layout, QString indent) { const QSize minSize = layout.minimumSize(); qout << indent << "QDockAreaLayoutInfo: " << layout.rect.left() << ',' << layout.rect.top() << ' ' << layout.rect.width() << 'x' << layout.rect.height() << " min size: " << minSize.width() << ',' << minSize.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(" ")); } } static void dumpLayout(QTextStream &qout, const QDockAreaLayout &layout) { qout << "QDockAreaLayout: " << layout.rect.left() << ',' << layout.rect.top() << ' ' << layout.rect.width() << 'x' << layout.rect.height() << '\n'; qout << "TopDockArea:\n"; dumpLayout(qout, layout.docks[QInternal::TopDock], QLatin1String(" ")); qout << "LeftDockArea:\n"; dumpLayout(qout, layout.docks[QInternal::LeftDock], QLatin1String(" ")); qout << "RightDockArea:\n"; dumpLayout(qout, layout.docks[QInternal::RightDock], QLatin1String(" ")); qout << "BottomDockArea:\n"; dumpLayout(qout, layout.docks[QInternal::BottomDock], QLatin1String(" ")); } QDebug operator<<(QDebug debug, const QDockAreaLayout &layout) { QString s; QTextStream str(&s); dumpLayout(str, layout); debug << s; return debug; } QDebug operator<<(QDebug debug, const QMainWindowLayout *layout) { debug << layout->layoutState.dockAreaLayout; return debug; } #endif // !defined(QT_NO_DOCKWIDGET) && !defined(QT_NO_DEBUG) /****************************************************************************** ** 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 = qt_mainwindow_layout(mainWindow); 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 QMainWindowLayoutState::indexOf(QWidget *widget) const { QList result; #ifndef QT_NO_TOOLBAR // is it a toolbar? if (QToolBar *toolBar = qobject_cast(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(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 QMainWindowLayoutState::gapIndex(QWidget *widget, const QPoint &pos) const { QList result; #ifndef QT_NO_TOOLBAR // is it a toolbar? if (qobject_cast(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(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 &path, QLayoutItem *item) { if (path.isEmpty()) return false; int i = path.first(); #ifndef QT_NO_TOOLBAR if (i == 0) { Q_ASSERT(qobject_cast(item->widget()) != 0); return toolBarAreaLayout.insertGap(path.mid(1), item); } #endif #ifndef QT_NO_DOCKWIDGET if (i == 1) { Q_ASSERT(qobject_cast(item->widget()) != 0); return dockAreaLayout.insertGap(path.mid(1), item); } #endif //QT_NO_DOCKWIDGET return false; } void QMainWindowLayoutState::remove(const QList &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(item->widget())) { QList 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 &path) { int i = path.first(); #ifndef QT_NO_TOOLBAR if (i == 0) { const QToolBarAreaLayoutItem *tbItem = toolBarAreaLayout.item(path.mid(1)); Q_ASSERT(tbItem); return tbItem->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 &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 &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 &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 &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 static QList findChildrenHelper(const QObject *o) { const QObjectList &list = o->children(); QList result; for (int i=0; i < list.size(); ++i) { if (T t = qobject_cast(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 toolBars = findChildrenHelper(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 dockWidgets = findChildrenHelper(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 dockWidgets = findChildrenHelper(mainWindow); if (!dockAreaLayout.restoreState(stream, dockWidgets)) return false; for (int i = 0; i < dockWidgets.size(); ++i) { QDockWidget *w = dockWidgets.at(i); QList path = dockAreaLayout.indexOf(w); if (path.isEmpty()) { QList 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 toolBars = findChildrenHelper(mainWindow); if (!toolBarAreaLayout.restoreState(stream, toolBars, marker, oldFormat)) return false; for (int i = 0; i < toolBars.size(); ++i) { QToolBar *w = toolBars.at(i); QList path = toolBarAreaLayout.indexOf(w); if (path.isEmpty()) { QList 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(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 visibility, 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 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(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 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(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; layoutState.dockAreaLayout.fallbackToSizeHints = 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&) { if (movingSeparator.isEmpty()) return false; movingSeparator.clear(); savedState.clear(); return true; } 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(item->widget()); if (toolBar == 0) return; QRect oldGeo = toolBar->geometry(); QInternal::DockPosition pos = static_cast(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 previousPath = layoutState.indexOf(widget); const QLayoutItem *it = layoutState.plug(currentGapPos); if (!it) return false; Q_ASSERT(it == widgetItem); if (!previousPath.isEmpty()) layoutState.remove(previousPath); pluggingWidget = widget; QRect globalRect = currentGapRect; globalRect.moveTopLeft(parentWidget()->mapToGlobal(globalRect.topLeft())); #ifndef QT_NO_DOCKWIDGET if (qobject_cast(widget) != 0) { QDockWidgetLayout *layout = qobject_cast(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(widget)) { QToolBarLayout *tbl = qobject_cast(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(widget)) dw->d_func()->plug(currentGapRect); #endif #ifndef QT_NO_TOOLBAR if (QToolBar *tb = qobject_cast(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(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 *parentLayout) : QLayout(parentLayout ? static_cast(0) : 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 { if (parentLayout) setParent(parentLayout); #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(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 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(widget)) { dw->d_func()->unplug(r); } #endif #ifndef QT_NO_TOOLBAR if (QToolBar *tb = qobject_cast(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 QMainWindowLayout::hover(QLayoutItem *widgetItem, const QPoint &mousePos) { if (!parentWidget()->isVisible() || parentWidget()->isMinimized() || pluggingWidget != 0 || widgetItem == 0) return QList(); QWidget *widget = widgetItem->widget(); QPoint pos = parentWidget()->mapFromGlobal(mousePos); if (!savedState.isValid()) savedState = layoutState; QList path = savedState.gapIndex(widget, pos); if (!path.isEmpty()) { bool allowed = false; #ifndef QT_NO_DOCKWIDGET if (QDockWidget *dw = qobject_cast(widget)) allowed = dw->isAreaAllowed(toDockWidgetArea(path.at(1))); #endif #ifndef QT_NO_TOOLBAR if (QToolBar *tb = qobject_cast(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(); } fixToolBarOrientation(widgetItem, currentGapPos.at(1)); QMainWindowLayoutState newState = savedState; if (!newState.insertGap(path, widgetItem)) { restore(true); // not enough space return QList(); } QSize min = newState.minimumSize(); QSize size = newState.rect.size(); if (min.width() > size.width() || min.height() > size.height()) { restore(true); return QList(); } 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 used = newState.dockAreaLayout.usedTabBars(); QSet 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 usedSeps = newState.dockAreaLayout.usedSeparatorWidgets(); QSet 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