diff --git a/src/DockManager.cpp b/src/DockManager.cpp index fa0abb2..2796bbf 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -72,6 +71,7 @@ struct DockManagerPrivate QMap ViewMenuGroups; QMenu* ViewMenu; CDockManager::eViewMenuInsertionOrder MenuInsertionOrder = CDockManager::MenuAlphabeticallySorted; + bool RestoringState = false; /** * Private data constructor @@ -87,7 +87,12 @@ struct DockManagerPrivate /** * Restores the state */ - bool restoreState(const QByteArray &state, int version, bool Testing = internal::Restore); + bool restoreStateFromXml(const QByteArray &state, int version, bool Testing = internal::Restore); + + /** + * Restore state + */ + bool restoreState(const QByteArray &state, int version); /** * Restores the container with the given index @@ -151,12 +156,12 @@ bool DockManagerPrivate::restoreContainer(int Index, QXmlStreamReader& stream, b //============================================================================ bool DockManagerPrivate::checkFormat(const QByteArray &state, int version) { - return restoreState(state, version, internal::RestoreTesting); + return restoreStateFromXml(state, version, internal::RestoreTesting); } //============================================================================ -bool DockManagerPrivate::restoreState(const QByteArray &state, int version, +bool DockManagerPrivate::restoreStateFromXml(const QByteArray &state, int version, bool Testing) { if (state.isEmpty()) @@ -209,6 +214,89 @@ bool DockManagerPrivate::restoreState(const QByteArray &state, int version, } +//============================================================================ +bool DockManagerPrivate::restoreState(const QByteArray &state, int version) +{ + if (!checkFormat(state, version)) + { + qDebug() << "checkFormat: Error checking format!!!!!!!"; + return false; + } + + for (auto DockWidget : DockWidgetsMap) + { + DockWidget->setProperty("dirty", true); + } + + if (!restoreStateFromXml(state, version)) + { + qDebug() << "restoreState: Error restoring state!!!!!!!"; + return false; + } + + // All dock widgets, that have not been processed in the restore state + // function are invisible to the user now and have no assigned dock area + // They do not belong to any dock container, until the user toggles the + // toggle view action the next time + for (auto DockWidget : DockWidgetsMap) + { + if (DockWidget->property("dirty").toBool()) + { + DockWidget->flagAsUnassigned(); + } + else + { + DockWidget->toggleViewInternal(!DockWidget->property("closed").toBool()); + } + } + + // Now all dock areas are properly restored and we setup the index of + // The dock areas because the previous toggleView() action has changed + // the dock area index + for (auto DockContainer : Containers) + { + for (int i = 0; i < DockContainer->dockAreaCount(); ++i) + { + CDockAreaWidget* DockArea = DockContainer->dockArea(i); + int CurrentIndex = DockArea->property("currentIndex").toInt(); + int DockWidgetCount = DockArea->dockWidgetsCount(); + if (CurrentIndex < DockWidgetCount && DockWidgetCount > 1 && CurrentIndex > -1) + { + auto DockWidget = DockArea->dockWidget(CurrentIndex); + if (!DockWidget->isClosed()) + { + DockArea->setCurrentIndex(CurrentIndex); + } + } + } + } + + // Finally we need to send the topLevelChanged() signals for all dock + // widgets if top level changed + for (auto DockContainer : Containers) + { + CDockWidget* TopLevelDockWidget = DockContainer->topLevelDockWidget(); + if (TopLevelDockWidget) + { + TopLevelDockWidget->emitTopLevelChanged(true); + } + else + { + for (int i = 0; i < DockContainer->dockAreaCount(); ++i) + { + auto DockArea = DockContainer->dockArea(i); + for (auto DockWidget : DockArea->dockWidgets()) + { + DockWidget->emitTopLevelChanged(false); + } + } + } + } + + return true; +} + + //============================================================================ void DockManagerPrivate::addActionToMenu(QAction* Action, QMenu* Menu, bool InsertSorted) { @@ -360,84 +448,37 @@ QByteArray CDockManager::saveState(eXmlMode XmlMode, int version) const //============================================================================ bool CDockManager::restoreState(const QByteArray &state, int version) { - if (!d->checkFormat(state, version)) - { - qDebug() << "checkFormat: Error checking format!!!!!!!"; - return false; - } + // Prevent multiple calls as long as state is not restore. This may + // happen, if QApplication::processEvents() is called somewhere + if (d->RestoringState) + { + return false; + } - for (auto DockWidget : d->DockWidgetsMap) - { - DockWidget->setProperty("dirty", true); - } + // We hide the complete dock manager here. Restoring the state means + // that DockWidgets are removed from the DockArea internal stack layout + // which in turn means, that each time a widget is removed the stack + // will show and raise the next available widget which in turn + // triggers show events for the dock widgets. To avoid this we hide the + // dock manager. Because there will be no processing of application + // events until this function is finished, the user will not see this + // hiding + bool IsVisible = this->isVisibleTo(parentWidget()); + if (IsVisible) + { + hide(); + } + d->RestoringState = true; + emit restoringState(); + bool Result = d->restoreState(state, version); + d->RestoringState = false; + emit stateRestored(); + if (IsVisible) + { + show(); + } - if (!d->restoreState(state, version)) - { - qDebug() << "restoreState: Error restoring state!!!!!!!"; - return false; - } - - // All dock widgets, that have not been processed in the restore state - // function are invisible to the user now and have no assigned dock area - // They do not belong to any dock container, until the user toggles the - // toggle view action the next time - for (auto DockWidget : d->DockWidgetsMap) - { - if (DockWidget->property("dirty").toBool()) - { - DockWidget->flagAsUnassigned(); - } - else - { - DockWidget->toggleViewInternal(!DockWidget->property("closed").toBool()); - } - } - - // Now all dock areas are properly restored and we setup the index of - // The dock areas because the previous toggleView() action has changed - // the dock area index - for (auto DockContainer : d->Containers) - { - for (int i = 0; i < DockContainer->dockAreaCount(); ++i) - { - CDockAreaWidget* DockArea = DockContainer->dockArea(i); - int CurrentIndex = DockArea->property("currentIndex").toInt(); - int DockWidgetCount = DockArea->dockWidgetsCount(); - if (CurrentIndex < DockWidgetCount && DockWidgetCount > 1 && CurrentIndex > -1) - { - auto DockWidget = DockArea->dockWidget(CurrentIndex); - if (!DockWidget->isClosed()) - { - DockArea->setCurrentIndex(CurrentIndex); - } - } - } - } - - // Finally we need to send the topLevelChanged() signals for all dock - // widgets if top level changed - for (auto DockContainer : d->Containers) - { - CDockWidget* TopLevelDockWidget = DockContainer->topLevelDockWidget(); - if (TopLevelDockWidget) - { - TopLevelDockWidget->emitTopLevelChanged(true); - } - else - { - for (int i = 0; i < DockContainer->dockAreaCount(); ++i) - { - auto DockArea = DockContainer->dockArea(i); - for (auto DockWidget : DockArea->dockWidgets()) - { - DockWidget->emitTopLevelChanged(false); - } - } - } - } - - emit stateChanged(); - return true; + return Result; } @@ -505,7 +546,9 @@ void CDockManager::openPerspective(const QString& PerspectiveName) return; } + emit openingPerspective(PerspectiveName); restoreState(Iterator.value()); + emit perspectiveOpened(PerspectiveName); } diff --git a/src/DockManager.h b/src/DockManager.h index 9ceeeef..e3e5fb3 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -276,12 +276,35 @@ signals: */ void perspectiveListChanged(); + /** + * This signal is emitted, if the restore function is called, just before + * the dock manager starts restoring the state. + * If this function is called, nothing has changed yet + */ + void restoringState(); + /** * This signal is emitted if the state changed in restoreState. * The signal is emitted if the restoreState() function is called or * if the openPerspective() function is called */ - void stateChanged(); + void stateRestored(); + + /** + * This signal is emitted, if the dock manager starts opening a + * perspective. + * Opening a perspective may take more than a second if there are + * many complex widgets. The application may use this signal + * to show some progress indicator or to change the mouse cursor + * into a busy cursor. + */ + void openingPerspective(const QString& PerspectiveName); + + /** + * This signal is emitted if the dock manager finished opening a + * perspective + */ + void perspectiveOpened(const QString& PerspectiveName); }; // class DockManager } // namespace ads //----------------------------------------------------------------------------- diff --git a/src/DockWidget.h b/src/DockWidget.h index 2018c4c..73da7c9 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -68,6 +68,7 @@ protected: friend class CDockAreaWidget; friend class CFloatingDockContainer; friend class CDockManager; + friend struct DockManagerPrivate; friend struct DockContainerWidgetPrivate; friend class CDockAreaTabBar; friend class CDockWidgetTab;