Started implementing serialization and deserialization

This commit is contained in:
Uwe Kindler 2017-03-23 15:57:15 +01:00
parent 16bd1a3bd2
commit 1cd1e7d6ec
14 changed files with 353 additions and 53 deletions

View File

@ -2,6 +2,8 @@
#include "ui_mainwindow.h"
#include <iostream>
#include <QTime>
#include <QLabel>
#include <QTextEdit>
@ -10,6 +12,7 @@
#include <QTreeView>
#include <QFileSystemModel>
#include <QBoxLayout>
#include <QSettings>
#include "DockManager.h"
#include "DockWidget.h"
@ -40,6 +43,7 @@ static ads::CDockWidget* createLongTextLabelDockWidget(QMenu* ViewMenu)
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Label %1").arg(LabelCount++));
DockWidget->setWidget(l);
DockWidget->setObjectName(DockWidget->windowTitle());
ViewMenu->addAction(DockWidget->toggleViewAction());
return DockWidget;
}
@ -50,6 +54,7 @@ static ads::CDockWidget* createCalendarDockWidget(QMenu* ViewMenu)
QCalendarWidget* w = new QCalendarWidget();
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Calendar %1").arg(CalendarCount++));
DockWidget->setWidget(w);
DockWidget->setObjectName(DockWidget->windowTitle());
ViewMenu->addAction(DockWidget->toggleViewAction());
return DockWidget;
}
@ -64,6 +69,7 @@ static ads::CDockWidget* createFileSystemTreeDockWidget(QMenu* ViewMenu)
w->setModel(m);
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Filesystem %1").arg(FileSystemCount++));
DockWidget->setWidget(w);
DockWidget->setObjectName(DockWidget->windowTitle());
ViewMenu->addAction(DockWidget->toggleViewAction());
return DockWidget;
}
@ -113,3 +119,29 @@ void MainWindow::createContent()
}
void MainWindow::closeEvent(QCloseEvent* event)
{
QSettings Settings("Settings.ini", QSettings::IniFormat);
Settings.setValue("mainWindow/Geometry", saveGeometry());
Settings.setValue("mainWindow/DockingState", m_DockManager->saveState());
QMainWindow::closeEvent(event);
}
void MainWindow::on_actionSaveState_triggered(bool)
{
std::cout << "MainWindow::on_actionSaveState_triggered" << std::endl;
QSettings Settings("Settings.ini", QSettings::IniFormat);
Settings.setValue("mainWindow/Geometry", saveGeometry());
Settings.setValue("mainWindow/DockingState", m_DockManager->saveState());
}
void MainWindow::on_actionRestoreState_triggered(bool)
{
std::cout << "MainWindow::on_actionRestoreState_triggered" << std::endl;
QSettings Settings("Settings.ini", QSettings::IniFormat);
restoreGeometry(Settings.value("mainWindow/Geometry").toByteArray());
m_DockManager->restoreState(Settings.value("mainWindow/DockingState").toByteArray());
}

View File

@ -11,7 +11,8 @@ class MainWindow;
class MainWindow : public QMainWindow
{
Q_OBJECT
protected:
virtual void closeEvent(QCloseEvent* event) override;
public:
explicit MainWindow(QWidget *parent = 0);
virtual ~MainWindow();
@ -20,6 +21,10 @@ private:
Ui::MainWindow *ui;
ads::CDockManager* m_DockManager;
void createContent();
private slots:
void on_actionSaveState_triggered(bool);
void on_actionRestoreState_triggered(bool);
};
#endif // MAINWINDOW_H

View File

@ -29,6 +29,8 @@
<string>File</string>
</property>
<addaction name="actionExit"/>
<addaction name="actionSaveState"/>
<addaction name="actionRestoreState"/>
</widget>
<widget class="QMenu" name="menuView">
<property name="title">
@ -49,6 +51,16 @@
<string>Exit</string>
</property>
</action>
<action name="actionSaveState">
<property name="text">
<string>Save State</string>
</property>
</action>
<action name="actionRestoreState">
<property name="text">
<string>Restore State</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>

View File

@ -706,6 +706,17 @@ void CDockAreaWidget::onDockWidgetViewToggled(bool Open)
auto DockWidget = dynamic_cast<CDockWidget*>(sender());
}
//============================================================================
void CDockAreaWidget::saveState(QDataStream& stream) const
{
stream << d->ContentsLayout->count() << d->ContentsLayout->currentIndex();
for (int i = 0; i < d->ContentsLayout->count(); ++i)
{
dockWidget(i)->saveState(stream);
}
}
} // namespace ads
//---------------------------------------------------------------------------

View File

@ -161,6 +161,11 @@ public:
*/
void setCurrentDockWidget(CDockWidget* DockWidget);
/**
* Saves the state into the given stream
*/
void saveState(QDataStream& Stream) const;
public slots:
/**
* This sets the index position of the current tab page.

View File

@ -41,6 +41,7 @@
#include "DockWidget.h"
#include "FloatingDockContainer.h"
#include "DockOverlay.h"
#include "DockStateSerialization.h"
#include "ads_globals.h"
#include <iostream>
@ -113,6 +114,16 @@ struct DockContainerWidgetPrivate
* Adds new dock areas to the internal dock area list
*/
void addDockAreasToList(const QList<CDockAreaWidget*> NewDockAreas);
/**
* Save state of child nodes
*/
void saveChildNodesState(QDataStream& Stream, QWidget* Widget);
/**
* Restore state of child nodes
*/
void restoreChildNodes(QDataStream& Stream, QWidget* Parent);
}; // struct DockContainerWidgetPrivate
@ -284,6 +295,74 @@ void DockContainerWidgetPrivate::addDockAreasToList(const QList<CDockAreaWidget*
}
//============================================================================
void DockContainerWidgetPrivate::saveChildNodesState(QDataStream& stream, QWidget* Widget)
{
QSplitter* Splitter = dynamic_cast<QSplitter*>(Widget);
if (Splitter)
{
stream << NodeSplitter << Splitter->orientation() << Splitter->count();
std::cout << "NodeSplitter " << Splitter->orientation() << std::endl;
for (int i = 0; i < Splitter->count(); ++i)
{
saveChildNodesState(stream, Splitter->widget(i));
}
}
else
{
CDockAreaWidget* DockArea = dynamic_cast<CDockAreaWidget*>(Widget);
if (DockArea)
{
std::cout << "NodeDockArea " << std::endl;
DockArea->saveState(stream);
}
}
}
//============================================================================
void DockContainerWidgetPrivate::restoreChildNodes(QDataStream& stream, QWidget* Parent)
{
int NodeType;
stream >> NodeType;
QSplitter* ParentSplitter = dynamic_cast<QSplitter*>(Parent);
if (NodeSplitter == NodeType)
{
int Orientation;
int Count;
stream >> Orientation >> Count;
std::cout << "Restore NodeSplitter " << Orientation << std::endl;
QSplitter* Splitter = internal::newSplitter((Qt::Orientation)Orientation);
if (ParentSplitter)
{
ParentSplitter->addWidget(Splitter);
}
else
{
Parent->layout()->addWidget(Splitter);
}
for (int i = 0; i < Count; ++i)
{
restoreChildNodes(stream, Splitter);
}
}
else
{
std::cout << "Restore NodeDockArea " << std::endl;
CDockAreaWidget* DockArea = new CDockAreaWidget(DockManager, _this);
if (ParentSplitter)
{
ParentSplitter->addWidget(DockArea);
}
else
{
Parent->layout()->addWidget(DockArea);
}
DockAreas.append(DockArea);
}
}
//============================================================================
CDockAreaWidget* DockContainerWidgetPrivate::dockWidgetIntoContainer(DockWidgetArea area,
CDockWidget* Dockwidget)
@ -301,7 +380,7 @@ void DockContainerWidgetPrivate::addDockArea(CDockAreaWidget* NewDockArea, DockW
auto InsertParam = internal::dockAreaInsertParameters(area);
if (DockAreas.isEmpty())
{
Layout->addWidget(NewDockArea, 0, 0);
_this->layout()->addWidget(NewDockArea);
}
else if (DockAreas.count() == 1)
{
@ -604,6 +683,51 @@ QList<CDockAreaWidget*> CDockContainerWidget::openedDockAreas() const
}
//============================================================================
void CDockContainerWidget::saveState(QDataStream& stream) const
{
std::cout << "CDockContainerWidget::saveState" << std::endl;
stream << isFloating();
if (isFloating())
{
CFloatingDockContainer* FloatingWidget = internal::findParent<CFloatingDockContainer*>(this);
stream << FloatingWidget->saveGeometry();
}
QWidget* RootChild = d->Layout->itemAt(0)->widget();
if (RootChild)
{
d->saveChildNodesState(stream, RootChild);
}
}
//============================================================================
bool CDockContainerWidget::restoreState(QDataStream& stream)
{
bool IsFloating;
stream >> IsFloating;
if (isFloating())
{
std::cout << "Restore floating widget" << std::endl;
CFloatingDockContainer* FloatingWidget = internal::findParent<CFloatingDockContainer*>(this);
QByteArray Geometry;
stream >> Geometry;
FloatingWidget->restoreGeometry(Geometry);
FloatingWidget->show();
}
QWidget* RootChild = d->Layout->itemAt(0)->widget();
if (RootChild)
{
d->DockAreas.clear();
delete RootChild;
}
d->restoreChildNodes(stream, this);
return true;
}
} // namespace ads
//---------------------------------------------------------------------------

View File

@ -134,6 +134,16 @@ public:
*/
bool isFloating() const;
/**
* Saves the state into the given stream
*/
void saveState(QDataStream& Stream) const;
/**
* Restores the state from given stream
*/
bool restoreState(QDataStream& Stream);
signals:
/**
* This signal is emitted if one or multiple dock areas has been added to

View File

@ -40,6 +40,13 @@
namespace ads
{
// sentinel values used to validate state data
enum VersionMarkers
{
VersionMarker = 0xff
};
/**
* Private data class of CDockManager class (pimpl)
*/
@ -55,6 +62,11 @@ struct DockManagerPrivate
* Private data constructor
*/
DockManagerPrivate(CDockManager* _public);
/**
* Restores a non existing container from stream
*/
bool restoreContainer(QDataStream& Stream);
};
// struct DockManagerPrivate
@ -66,6 +78,14 @@ DockManagerPrivate::DockManagerPrivate(CDockManager* _public) :
}
//============================================================================
bool DockManagerPrivate::restoreContainer(QDataStream& Stream)
{
std::cout << "restoreContainer" << std::endl;
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(_this);
}
//============================================================================
CDockManager::CDockManager(QWidget *parent) :
CDockContainerWidget(this, parent),
@ -160,6 +180,61 @@ unsigned int CDockManager::zOrderIndex() const
{
return 0;
}
//============================================================================
QByteArray CDockManager::saveState(int version) const
{
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << VersionMarker;
stream << version;
stream << d->Containers.count();
for (auto Container : d->Containers)
{
Container->saveState(stream);
}
return data;
}
//============================================================================
bool CDockManager::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 != VersionMarker || v != version)
{
return false;
}
int ContainerCount;
stream >> ContainerCount;
std::cout << "ContainerCount " << ContainerCount << std::endl;
for (int i = 0; i < ContainerCount; ++i)
{
if (i >= d->Containers.count())
{
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(this);
}
std::cout << "d->Containers[i]->restoreState " << i << std::endl;
d->Containers[i]->restoreState(stream);
}
return true;
}
} // namespace ads
//---------------------------------------------------------------------------

View File

@ -114,6 +114,20 @@ public:
* any floating widget
*/
virtual unsigned int zOrderIndex() const;
/**
* Saves the current state of the dockmanger and all its dock widgets
*/
QByteArray saveState(int version = 0) const;
/**
* Restores the state of this dockmanagers dockwidgets.
* The version number is compared with that stored in state. If they do
* not match, the dockmanager's state is left unchanged, and this function
* returns false; otherwise, the state is restored, and this function
* returns true.
*/
bool restoreState(const QByteArray &state, int version = 0);
}; // class DockManager
} // namespace ads
//-----------------------------------------------------------------------------

View File

View File

@ -0,0 +1,44 @@
#ifndef DockStateSerializationH
#define DockStateSerializationH
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
//============================================================================
/// \file DockStateSerialization.h
/// \author Uwe Kindler
/// \date 26.02.2017
/// \brief
//============================================================================
//============================================================================
// INCLUDES
//============================================================================
namespace ads
{
enum eDockTreeNodeType
{
NodeSplitter,
NodeDockArea
};
} // namespace ads
//-----------------------------------------------------------------------------
#endif // DockManagerH

View File

@ -63,23 +63,12 @@ struct DockWidgetPrivate
CDockAreaWidget* DockArea = nullptr;
QAction* ToggleViewAction;
bool Closed = false;
struct CapturedState
{
QString DockTreePosition;
QRect GlobalGeometry;
QPointer<CDockContainerWidget> DockContainer;
} CapturedState;
/**
* Private data constructor
*/
DockWidgetPrivate(CDockWidget* _public);
/**
* Saves the current state into CapturedState variable
*/
void capturedState();
/**
* Show dock widget
*/
@ -116,40 +105,6 @@ DockWidgetPrivate::DockWidgetPrivate(CDockWidget* _public) :
}
//============================================================================
void DockWidgetPrivate::capturedState()
{
QString DockTreePosition;
QTextStream stream(&DockTreePosition);
QPoint GlobalTopLeft = _this->mapToGlobal(_this->geometry().topLeft());
QRect Rect(GlobalTopLeft, _this->geometry().size());
CapturedState.GlobalGeometry = Rect;
CapturedState.DockContainer = _this->dockContainer();
QWidget* Widget = DockArea;
QSplitter* splitter = internal::findParent<QSplitter*>(Widget);
QStack<QString> SplitterData;
while (splitter)
{
SplitterData.push(QString("%1%2")
.arg((splitter->orientation() == Qt::Horizontal) ? "H" : "V")
.arg(splitter->indexOf(Widget)));
Widget = splitter;
splitter = internal::findParent<QSplitter*>(Widget);
}
QString Separator;
while (!SplitterData.isEmpty())
{
stream << Separator << SplitterData.pop();
Separator = " ";
}
this->CapturedState.DockTreePosition = DockTreePosition;
std::cout << "SerializedPosition: " << DockTreePosition.toStdString() << std::endl;
}
//============================================================================
void DockWidgetPrivate::showDockWidget()
{
@ -398,6 +353,15 @@ void CDockWidget::setDockArea(CDockAreaWidget* DockArea)
}
//============================================================================
void CDockWidget::saveState(QDataStream& stream) const
{
std::cout << "CDockWidget::saveState " << objectName().toStdString()
<< " closed " << d->Closed << std::endl;
stream << objectName() << d->Closed;
}
} // namespace ads
//---------------------------------------------------------------------------

View File

@ -75,6 +75,11 @@ protected:
*/
void setToggleViewActionChecked(bool Checked);
/**
* Saves the state into the given stream
*/
void saveState(QDataStream& Stream) const;
public:
enum DockWidgetFeature
{
@ -167,7 +172,6 @@ public:
*/
QAction* toggleViewAction() const;
public slots:
/**
* This property controls whether the dock widget is open or closed.

View File

@ -55,11 +55,6 @@ private slots:
void onDockAreasAddedOrRemoved();
void onDockAreaCurrentChanged(int Index);
protected:
/**
* Private constructor that is called from public constructors
*/
CFloatingDockContainer(CDockManager* DockManager);
protected: // reimplements QWidget
virtual void changeEvent(QEvent *event) override;
@ -71,6 +66,11 @@ protected: // reimplements QWidget
virtual bool eventFilter(QObject *watched, QEvent *event) override;
public:
/**
* Create empty flatingb widget - required for restore state
*/
CFloatingDockContainer(CDockManager* DockManager);
/**
* Create floating widget with the given dock area
*/