From 496aec211e2dbeef9c7238f8b85a4fd85d89d181 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 27 Sep 2018 16:21:14 +0200 Subject: [PATCH] Added new signals restoringState(), stateRestored(), openingPerspective(), perspectiveOpened(), improved restore state function to protect against multiple calls and to prevent show() events for all CDockWidgets and content if the widgets are removed from internal stack layout --- src/DockManager.cpp | 203 +++++++++++++++++++++++++++----------------- src/DockManager.h | 25 +++++- src/DockWidget.h | 1 + 3 files changed, 148 insertions(+), 81 deletions(-) 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;