diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index 6adb5be..a8d9d50 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -5,7 +5,7 @@ - + diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 45ce63e..8697f19 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -122,9 +122,28 @@ struct DockContainerWidgetPrivate void saveChildNodesState(QDataStream& Stream, QWidget* Widget); /** - * Restore state of child nodes + * Restore state of child nodes. + * \param[in] Stream The data stream that contains the serialized state + * \param[out] CreatedWidget The widget created from parsed data + * \param[in] Testing If Testing is true, only the stream data is + * parsed without modifiying anything. */ - void restoreChildNodes(QDataStream& Stream, QWidget*& CreatedWidget); + bool restoreChildNodes(QDataStream& Stream, QWidget*& CreatedWidget, + bool Testing); + + /** + * Restores a splitter. + * \see restoreChildNodes() for details + */ + bool restoreSplitter(QDataStream& Stream, QWidget*& CreatedWidget, + bool Testing); + + /** + * Restores a dock area. + * \see restoreChildNodes() for details + */ + bool restoreDockArea(QDataStream& Stream, QWidget*& CreatedWidget, + bool Testing); }; // struct DockContainerWidgetPrivate @@ -290,7 +309,7 @@ void DockContainerWidgetPrivate::saveChildNodesState(QDataStream& stream, QWidge QSplitter* Splitter = dynamic_cast(Widget); if (Splitter) { - stream << NodeSplitter << Splitter->orientation() << Splitter->count(); + stream << internal::SplitterMarker << Splitter->orientation() << Splitter->count(); std::cout << "NodeSplitter orient: " << Splitter->orientation() << " WidgetCont: " << Splitter->count() << std::endl; for (int i = 0; i < Splitter->count(); ++i) @@ -301,7 +320,7 @@ void DockContainerWidgetPrivate::saveChildNodesState(QDataStream& stream, QWidge } else { - stream << NodeDockArea; + stream << internal::DockAreaMarker; CDockAreaWidget* DockArea = dynamic_cast(Widget); if (DockArea) { @@ -312,35 +331,43 @@ void DockContainerWidgetPrivate::saveChildNodesState(QDataStream& stream, QWidge //============================================================================ -void DockContainerWidgetPrivate::restoreChildNodes(QDataStream& stream, - QWidget*& CreatedWidget) +bool DockContainerWidgetPrivate::restoreSplitter(QDataStream& stream, + QWidget*& CreatedWidget, bool Testing) { - int NodeType; - stream >> NodeType; - if (NodeSplitter == NodeType) + int Orientation; + int WidgetCount; + stream >> Orientation >> WidgetCount; + std::cout << "Restore NodeSplitter Orientation: " << Orientation << + " WidgetCount: " << WidgetCount << std::endl; + QSplitter* Splitter = nullptr; + if (!Testing) { - int Orientation; - int WidgetCount; - stream >> Orientation >> WidgetCount; - std::cout << "Restore NodeSplitter Orientation: " << Orientation << - " WidgetCount: " << WidgetCount << std::endl; - QSplitter* Splitter = internal::newSplitter((Qt::Orientation)Orientation); - bool Visible = false; - for (int i = 0; i < WidgetCount; ++i) + Splitter = internal::newSplitter((Qt::Orientation)Orientation); + } + bool Visible = false; + for (int i = 0; i < WidgetCount; ++i) + { + QWidget* ChildNode; + if (!restoreChildNodes(stream, ChildNode, Testing)) { - QWidget* ChildNode; - restoreChildNodes(stream, ChildNode); - if (ChildNode) - { - Splitter->addWidget(ChildNode); - } - std::cout << "ChildNode isVisible " << ChildNode->isVisible() - << " isVisibleTo " << ChildNode->isVisibleTo(Splitter) << std::endl; - Visible |= ChildNode->isVisibleTo(Splitter); + return false; } - QList Sizes; - stream >> Sizes; + if (Testing) + { + continue; + } + + std::cout << "ChildNode isVisible " << ChildNode->isVisible() + << " isVisibleTo " << ChildNode->isVisibleTo(Splitter) << std::endl; + Splitter->addWidget(ChildNode); + Visible |= ChildNode->isVisibleTo(Splitter); + } + + QList Sizes; + stream >> Sizes; + if (!Testing) + { if (!Splitter->count()) { delete Splitter; @@ -355,43 +382,89 @@ void DockContainerWidgetPrivate::restoreChildNodes(QDataStream& stream, } else { - int Tabs; - int CurrentIndex; - stream >> Tabs >> CurrentIndex; - std::cout << "Restore NodeDockArea Tabs: " << Tabs << " CurrentIndex: " - << CurrentIndex << std::endl; + CreatedWidget = nullptr; + } + return true; +} - CDockAreaWidget* DockArea = new CDockAreaWidget(DockManager, _this); - for (int i = 0; i < Tabs; ++i) + +//============================================================================ +bool DockContainerWidgetPrivate::restoreDockArea(QDataStream& stream, + QWidget*& CreatedWidget, bool Testing) +{ + int Tabs; + int CurrentIndex; + stream >> Tabs >> CurrentIndex; + std::cout << "Restore NodeDockArea Tabs: " << Tabs << " CurrentIndex: " + << CurrentIndex << std::endl; + + CDockAreaWidget* DockArea = nullptr; + if (!Testing) + { + DockArea = new CDockAreaWidget(DockManager, _this); + } + + for (int i = 0; i < Tabs; ++i) + { + int Marker; + stream >> Marker; + if (Marker != internal::DockWidgetMarker) { - QString ObjectName; - bool Closed; - stream >> ObjectName >> Closed; - std::cout << "Restore DockWidget " << ObjectName.toStdString() << " Closed: " - << Closed << std::endl; - - CDockWidget* DockWidget = DockManager->findChild(ObjectName); - if (!DockWidget) - { - continue; - } - else - { - std::cout << "Dock Widget found - parent " << DockWidget->parent() - << std::endl; - DockArea->addDockWidget(DockWidget); - } - DockWidget->toggleView(!Closed); + return false; } - if (!DockArea->count()) + QString ObjectName; + bool Closed; + stream >> ObjectName >> Closed; + std::cout << "Restore DockWidget " << ObjectName.toStdString() << " Closed: " + << Closed << std::endl; + + CDockWidget* DockWidget = DockManager->findDockWidget(ObjectName); + if (!DockWidget || Testing) { - delete DockArea; - DockArea = nullptr; + continue; } - CreatedWidget = DockArea; - DockAreas.append(DockArea); - DockArea->setCurrentIndex(CurrentIndex); + + std::cout << "Dock Widget found - parent " << DockWidget->parent() + << std::endl; + DockArea->addDockWidget(DockWidget); + DockWidget->toggleView(!Closed); + } + + if (Testing) + { + return true; + } + + if (!DockArea->count()) + { + delete DockArea; + DockArea = nullptr; + } + CreatedWidget = DockArea; + DockAreas.append(DockArea); + DockArea->setCurrentIndex(CurrentIndex); + return true; +} + + +//============================================================================ +bool DockContainerWidgetPrivate::restoreChildNodes(QDataStream& stream, + QWidget*& CreatedWidget, bool Testing) +{ + int Marker; + stream >> Marker; + if (internal::SplitterMarker == Marker) + { + return restoreSplitter(stream, CreatedWidget, Testing); + } + else if (internal::DockAreaMarker == Marker) + { + return restoreDockArea(stream, CreatedWidget, Testing); + } + else + { + return false; } } @@ -700,6 +773,7 @@ void CDockContainerWidget::saveState(QDataStream& stream) const { std::cout << "CDockContainerWidget::saveState isFloating " << isFloating() << std::endl; + stream << internal::ContainerMarker; stream << isFloating(); if (isFloating()) { @@ -712,30 +786,52 @@ void CDockContainerWidget::saveState(QDataStream& stream) const //============================================================================ -bool CDockContainerWidget::restoreState(QDataStream& stream) +bool CDockContainerWidget::restoreState(QDataStream& stream, bool Testing) { bool IsFloating; + int Marker; + stream >> Marker; + if (Marker != internal::ContainerMarker) + { + return false; + } + stream >> IsFloating; std::cout << "Restore CDockContainerWidget Floating" << IsFloating << std::endl; QWidget* NewRootSplitter; - d->DockAreas.clear(); - if (isFloating()) + if (!Testing) { - std::cout << "Restore floating widget" << std::endl; - CFloatingDockContainer* FloatingWidget = internal::findParent(this); - QByteArray Geometry; - stream >> Geometry; - FloatingWidget->restoreGeometry(Geometry); - FloatingWidget->show(); + d->DockAreas.clear(); } - d->restoreChildNodes(stream, NewRootSplitter); + if (IsFloating) + { + std::cout << "Restore floating widget" << std::endl; + QByteArray Geometry; + stream >> Geometry; + if (!Testing) + { + CFloatingDockContainer* FloatingWidget = internal::findParent(this); + FloatingWidget->restoreGeometry(Geometry); + FloatingWidget->show(); + } + } + + if (!d->restoreChildNodes(stream, NewRootSplitter, Testing)) + { + return false; + } + + if (Testing) + { + return true; + } d->Layout->replaceWidget(d->RootSplitter, NewRootSplitter); QSplitter* OldRoot = d->RootSplitter; d->RootSplitter = dynamic_cast(NewRootSplitter); - delete OldRoot; + OldRoot->deleteLater(); return true; } diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 278a504..9d344bd 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -140,9 +140,12 @@ public: void saveState(QDataStream& Stream) const; /** - * Restores the state from given stream + * Restores the state from given stream. + * If Testing is true, the function only parses the data from the given + * stream but does not restore anything. You can use this check for + * faulty files before you start restoring the state */ - bool restoreState(QDataStream& Stream); + bool restoreState(QDataStream& Stream, bool Testing); signals: /** diff --git a/src/DockManager.cpp b/src/DockManager.cpp index e40766f..f3fdb4d 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -32,21 +32,19 @@ #include #include +#include #include #include "FloatingDockContainer.h" #include "DockOverlay.h" +#include "DockWidget.h" +#include "ads_globals.h" +#include "DockStateSerialization.h" namespace ads { -// sentinel values used to validate state data -enum VersionMarkers -{ - VersionMarker = 0xff -}; - /** * Private data class of CDockManager class (pimpl) */ @@ -57,6 +55,7 @@ struct DockManagerPrivate QList Containers; CDockOverlay* ContainerOverlay; CDockOverlay* DockAreaOverlay; + QMap DockWidgetsMap; /** * Private data constructor @@ -67,6 +66,17 @@ struct DockManagerPrivate * Restores a non existing container from stream */ bool restoreContainer(QDataStream& Stream); + + /** + * Checks if the given data stream is a valid docking system state + * file. + */ + bool checkFormat(const QByteArray &state, int version); + + /** + * Restores the state + */ + bool restoreState(const QByteArray &state, int version); }; // struct DockManagerPrivate @@ -83,6 +93,97 @@ bool DockManagerPrivate::restoreContainer(QDataStream& Stream) { std::cout << "restoreContainer" << std::endl; CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(_this); + return true; +} + + +//============================================================================ +bool DockManagerPrivate::checkFormat(const QByteArray &state, int version) +{ + if (state.isEmpty()) + { + return false; + } + QByteArray sd = state; + QDataStream stream(&sd, QIODevice::ReadOnly); + + int marker; + int v; + stream >> marker; + stream >> v; + + if (stream.status() != QDataStream::Ok || marker != internal::VersionMarker || v != version) + { + return false; + } + + int Result = true; + int ContainerCount; + stream >> ContainerCount; + std::cout << "ContainerCount " << ContainerCount << std::endl; + int i; + for (i = 0; i < ContainerCount; ++i) + { + if (!Containers[0]->restoreState(stream, internal::RestoreTesting)) + { + Result = false; + break; + } + } + + return Result; +} + + +//============================================================================ +bool DockManagerPrivate::restoreState(const QByteArray &state, int version) +{ + if (state.isEmpty()) + { + return false; + } + QByteArray sd = state; + QDataStream stream(&sd, QIODevice::ReadOnly); + + int marker; + int v; + stream >> marker; + stream >> v; + + if (stream.status() != QDataStream::Ok || marker != internal::VersionMarker || v != version) + { + return false; + } + + int Result = true; + int ContainerCount; + stream >> ContainerCount; + std::cout << "ContainerCount " << ContainerCount << std::endl; + int i; + for (i = 0; i < ContainerCount; ++i) + { + if (i >= Containers.count()) + { + CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(_this); + } + + std::cout << "d->Containers[i]->restoreState " << i << std::endl; + if (!Containers[i]->restoreState(stream, internal::Restore)) + { + Result = false; + break; + } + } + + // Delete remaining empty floating widgets + int FloatingWidgetIndex = i - 1; + int DeleteCount = FloatingWidgets.count() - FloatingWidgetIndex; + for (int i = 0; i < DeleteCount; ++i) + { + delete FloatingWidgets[FloatingWidgetIndex]; + } + + return Result; } @@ -187,7 +288,7 @@ QByteArray CDockManager::saveState(int version) const { QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); - stream << VersionMarker; + stream << internal::VersionMarker; stream << version; stream << d->Containers.count(); @@ -202,39 +303,36 @@ QByteArray CDockManager::saveState(int version) const //============================================================================ bool CDockManager::restoreState(const QByteArray &state, int version) { - if (state.isEmpty()) + if (!d->checkFormat(state, version)) { - return false; - } - QByteArray sd = state; - QDataStream stream(&sd, QIODevice::ReadOnly); - - int marker; - int v; - stream >> marker; - stream >> v; - - if (stream.status() != QDataStream::Ok || marker != VersionMarker || v != version) - { - return false; + std::cout << "checkFormat: Error checking format!!!!!!!" << std::endl; + return false; } - int ContainerCount; - stream >> ContainerCount; - std::cout << "ContainerCount " << ContainerCount << std::endl; - for (int i = 0; i < ContainerCount; ++i) + if (!d->restoreState(state, version)) { - if (i >= d->Containers.count()) - { - CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(this); - } - - std::cout << "d->Containers[i]->restoreState " << i << std::endl; - d->Containers[i]->restoreState(stream); + std::cout << "restoreState: Error restoring state!!!!!!!" << std::endl; + return false; } return true; } + + +//============================================================================ +CDockAreaWidget* CDockManager::addDockWidget(DockWidgetArea area, + CDockWidget* Dockwidget, CDockAreaWidget* DockAreaWidget) +{ + d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget); + return CDockContainerWidget::addDockWidget(area, Dockwidget, DockAreaWidget); +} + + +//============================================================================ +CDockWidget* CDockManager::findDockWidget(const QString& ObjectName) +{ + return d->DockWidgetsMap.value(ObjectName, nullptr); +} } // namespace ads //--------------------------------------------------------------------------- diff --git a/src/DockManager.h b/src/DockManager.h index 5192646..91db2d9 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -98,6 +98,23 @@ public: */ CDockOverlay* dockAreaOverlay() const; + /** + * Adds dockwidget into the given area. + * If DockAreaWidget is not null, then the area parameter indicates the area + * into the DockAreaWidget. If DockAreaWidget is null, the Dockwidget will + * be dropped into the container. + * \return Returns the dock area widget that contains the new DockWidget + */ + CDockAreaWidget* addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget, + CDockAreaWidget* DockAreaWidget = nullptr); + + /** + * Searches for a registered doc widget with the given ObjectName + * \return Return the found dock widget or nullptr if a dock widget with the + * given name is not registered + */ + CDockWidget* findDockWidget(const QString& ObjectName); + /** * Returns the list of all active and visible dock containers * Dock containers are the main dock manager and all floating widgets diff --git a/src/DockStateSerialization.h b/src/DockStateSerialization.h index 698f6e5..6d0fe6f 100644 --- a/src/DockStateSerialization.h +++ b/src/DockStateSerialization.h @@ -34,11 +34,22 @@ namespace ads { -enum eDockTreeNodeType + +namespace internal { - NodeSplitter, - NodeDockArea +// sentinel values used to validate state data +enum VersionMarkers +{ + VersionMarker = 0xff, + ContainerMarker = 0xfe, + SplitterMarker = 0xfd, + DockAreaMarker = 0xfc, + DockWidgetMarker = 0xfb }; + +static const bool RestoreTesting = true; +static const bool Restore = false; +} // internal } // namespace ads //----------------------------------------------------------------------------- #endif // DockManagerH diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index c49daad..a43c9c8 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -44,7 +44,7 @@ #include "DockAreaWidget.h" #include "DockManager.h" #include "FloatingDockContainer.h" - +#include "DockStateSerialization.h" #include "ads_globals.h" namespace ads @@ -356,6 +356,7 @@ void CDockWidget::setDockArea(CDockAreaWidget* DockArea) //============================================================================ void CDockWidget::saveState(QDataStream& stream) const { + stream << internal::DockWidgetMarker; std::cout << "CDockWidget::saveState " << objectName().toStdString() << " closed " << d->Closed << std::endl; stream << objectName() << d->Closed; diff --git a/src/ads_globals.h b/src/ads_globals.h index a1aea46..a79c947 100644 --- a/src/ads_globals.h +++ b/src/ads_globals.h @@ -51,8 +51,11 @@ enum DockWidgetArea }; Q_DECLARE_FLAGS(DockWidgetAreas, DockWidgetArea) + namespace internal { + + /** * Helper function to create new splitter widgets */