mirror of
https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System.git
synced 2024-11-15 13:15:43 +08:00
Refactors: Move save/restore impl into separate methods.
Updates SectionContent API: Its only possible to use it as shared pointer (RefPtr), Copies not possible. Handle missing or too many content references in restore procecure.
This commit is contained in:
parent
1b91fe241b
commit
eaff4f3d4e
@ -89,7 +89,8 @@ private:
|
|||||||
void addSection(SectionWidget* section);
|
void addSection(SectionWidget* section);
|
||||||
SectionWidget* sectionAt(const QPoint& pos) const;
|
SectionWidget* sectionAt(const QPoint& pos) const;
|
||||||
SectionWidget* dropContentOuterHelper(QLayout* l, const InternalContentData& data, Qt::Orientation orientation, bool append);
|
SectionWidget* dropContentOuterHelper(QLayout* l, const InternalContentData& data, Qt::Orientation orientation, bool append);
|
||||||
void saveGeometryWalk(QDataStream& out, QWidget* widget) const;
|
void saveFloatingWidgets(QDataStream& out) const;
|
||||||
|
void saveSectionWidgets(QDataStream& out, QWidget* widget) const;
|
||||||
bool restoreFloatingWidgets(QDataStream& in, QList<FloatingWidget*>& floatings);
|
bool restoreFloatingWidgets(QDataStream& in, QList<FloatingWidget*>& floatings);
|
||||||
bool restoreSectionWidgets(QDataStream& in, QSplitter* currentSplitter, QList<SectionWidget*>& sections);
|
bool restoreSectionWidgets(QDataStream& in, QSplitter* currentSplitter, QList<SectionWidget*>& sections);
|
||||||
bool takeContent(const SectionContent::RefPtr& sc, InternalContentData& data);
|
bool takeContent(const SectionContent::RefPtr& sc, InternalContentData& data);
|
||||||
|
@ -10,29 +10,43 @@
|
|||||||
#include "ads/API.h"
|
#include "ads/API.h"
|
||||||
|
|
||||||
ADS_NAMESPACE_BEGIN
|
ADS_NAMESPACE_BEGIN
|
||||||
|
class ContainerWidget;
|
||||||
|
|
||||||
class SectionContent
|
class SectionContent
|
||||||
{
|
{
|
||||||
friend class ContainerWidget;
|
friend class ContainerWidget;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SectionContent(QWidget* title, QWidget* content, const QString& uniqueName = QString()); ///< Do not use!
|
SectionContent();
|
||||||
|
SectionContent(const SectionContent&);
|
||||||
|
SectionContent& operator=(const SectionContent&);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef QSharedPointer<SectionContent> RefPtr;
|
typedef QSharedPointer<SectionContent> RefPtr;
|
||||||
typedef QWeakPointer<SectionContent> WeakPtr;
|
typedef QWeakPointer<SectionContent> WeakPtr;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Creates new content, associates it to <em>container</em> and takes ownership of
|
||||||
|
* <em>title</em>- and <em>content</em>- widgets.
|
||||||
|
* \param uniqueName An unique identifier across the entire process.
|
||||||
|
* \param container The parent ContainerWidget in which this content will be active.
|
||||||
|
* \param title The widget to use as title.
|
||||||
|
* \param content The widget to use as content.
|
||||||
|
* \return May return a invalid ref-pointer in case of invalid parameters.
|
||||||
|
*/
|
||||||
|
static RefPtr newSectionContent(const QString& uniqueName, ContainerWidget* container, QWidget* title, QWidget* content);
|
||||||
|
|
||||||
virtual ~SectionContent();
|
virtual ~SectionContent();
|
||||||
int uid() const;
|
int uid() const;
|
||||||
QString uniqueName() const;
|
QString uniqueName() const;
|
||||||
|
ContainerWidget* containerWidget() const;
|
||||||
QWidget* titleWidget() const;
|
QWidget* titleWidget() const;
|
||||||
QWidget* contentWidget() const;
|
QWidget* contentWidget() const;
|
||||||
|
|
||||||
static RefPtr newSectionContent(QWidget* title, QWidget* content, const QString& uniqueName = QString());
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const int _uid;
|
const int _uid;
|
||||||
const QString _uniqueName;
|
QString _uniqueName;
|
||||||
|
ContainerWidget* _container;
|
||||||
QPointer<QWidget> _title;
|
QPointer<QWidget> _title;
|
||||||
QPointer<QWidget> _content;
|
QPointer<QWidget> _content;
|
||||||
|
|
||||||
|
@ -131,14 +131,7 @@ QByteArray ContainerWidget::saveState() const
|
|||||||
out << (quint32) 1; // Version
|
out << (quint32) 1; // Version
|
||||||
|
|
||||||
// Save state of floating contents
|
// Save state of floating contents
|
||||||
out << _floatings.count();
|
saveFloatingWidgets(out);
|
||||||
for (int i = 0; i < _floatings.count(); ++i)
|
|
||||||
{
|
|
||||||
FloatingWidget* fw = _floatings.at(i);
|
|
||||||
out << fw->content()->uniqueName();
|
|
||||||
out << fw->saveGeometry();
|
|
||||||
out << fw->isVisible();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Walk through layout for splitters
|
// Walk through layout for splitters
|
||||||
// Well.. there actually shouldn't be more than one
|
// Well.. there actually shouldn't be more than one
|
||||||
@ -147,7 +140,7 @@ QByteArray ContainerWidget::saveState() const
|
|||||||
QLayoutItem* li = _mainLayout->itemAt(i);
|
QLayoutItem* li = _mainLayout->itemAt(i);
|
||||||
if (!li->widget())
|
if (!li->widget())
|
||||||
continue;
|
continue;
|
||||||
saveGeometryWalk(out, li->widget());
|
saveSectionWidgets(out, li->widget());
|
||||||
}
|
}
|
||||||
|
|
||||||
return ba;
|
return ba;
|
||||||
@ -187,12 +180,49 @@ bool ContainerWidget::restoreState(const QByteArray& data)
|
|||||||
qWarning() << "Could not restore sections completely";
|
qWarning() << "Could not restore sections completely";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle SectionContent which is not mentioned by deserialized data.
|
||||||
|
// What shall we do with it? For now: Simply drop them into the first SectionWidget.
|
||||||
|
if (true)
|
||||||
|
{
|
||||||
|
QList<SectionContent::RefPtr> leftContents;
|
||||||
|
|
||||||
|
// Collect all contents which has been restored
|
||||||
|
QList<SectionContent::RefPtr> contents;
|
||||||
|
for (int i = 0; i < floatings.count(); ++i)
|
||||||
|
contents.append(floatings.at(i)->content());
|
||||||
|
for (int i = 0; i < sections.count(); ++i)
|
||||||
|
for (int j = 0; j < sections.at(i)->contents().count(); ++j)
|
||||||
|
contents.append(sections.at(i)->contents().at(j));
|
||||||
|
|
||||||
|
// Compare restored contents with available contents
|
||||||
|
const QList<SectionContent::WeakPtr> allContents = SectionContent::LookupMap.values();
|
||||||
|
for (int i = 0; i < allContents.count(); ++i)
|
||||||
|
{
|
||||||
|
const SectionContent::RefPtr sc = allContents.at(i).toStrongRef();
|
||||||
|
if (sc.isNull() || sc->containerWidget() != this)
|
||||||
|
continue;
|
||||||
|
if (contents.contains(sc))
|
||||||
|
continue;
|
||||||
|
leftContents.append(sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// What should we do with a drunken sailor.. what should.. erm..
|
||||||
|
// .. we do with the left-contents?
|
||||||
|
if (!_sections.isEmpty())
|
||||||
|
{
|
||||||
|
for (int i = 0; i < leftContents.count(); ++i)
|
||||||
|
{
|
||||||
|
const SectionContent::RefPtr sc = leftContents.at(i);
|
||||||
|
InternalContentData data;
|
||||||
|
this->takeContent(sc, data);
|
||||||
|
sections.first()->addContent(sc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_floatings = floatings;
|
_floatings = floatings;
|
||||||
_sections = sections;
|
_sections = sections;
|
||||||
|
|
||||||
// TODO Handle contents which are not mentioned by deserialized data
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// Delete old objects
|
// Delete old objects
|
||||||
QLayoutItem* old = _mainLayout->takeAt(0);
|
QLayoutItem* old = _mainLayout->takeAt(0);
|
||||||
_mainLayout->addWidget(_splitter);
|
_mainLayout->addWidget(_splitter);
|
||||||
@ -450,7 +480,19 @@ SectionWidget* ContainerWidget::dropContentOuterHelper(QLayout* l, const Interna
|
|||||||
return sw;
|
return sw;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainerWidget::saveGeometryWalk(QDataStream& out, QWidget* widget) const
|
void ContainerWidget::saveFloatingWidgets(QDataStream& out) const
|
||||||
|
{
|
||||||
|
out << _floatings.count();
|
||||||
|
for (int i = 0; i < _floatings.count(); ++i)
|
||||||
|
{
|
||||||
|
FloatingWidget* fw = _floatings.at(i);
|
||||||
|
out << fw->content()->uniqueName();
|
||||||
|
out << fw->saveGeometry();
|
||||||
|
out << fw->isVisible();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContainerWidget::saveSectionWidgets(QDataStream& out, QWidget* widget) const
|
||||||
{
|
{
|
||||||
QSplitter* sp = NULL;
|
QSplitter* sp = NULL;
|
||||||
SectionWidget* sw = NULL;
|
SectionWidget* sw = NULL;
|
||||||
@ -467,7 +509,7 @@ void ContainerWidget::saveGeometryWalk(QDataStream& out, QWidget* widget) const
|
|||||||
out << sp->sizes();
|
out << sp->sizes();
|
||||||
for (int i = 0; i < sp->count(); ++i)
|
for (int i = 0; i < sp->count(); ++i)
|
||||||
{
|
{
|
||||||
saveGeometryWalk(out, sp->widget(i));
|
saveSectionWidgets(out, sp->widget(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((sw = dynamic_cast<SectionWidget*>(widget)) != NULL)
|
else if ((sw = dynamic_cast<SectionWidget*>(widget)) != NULL)
|
||||||
@ -538,6 +580,13 @@ bool ContainerWidget::restoreSectionWidgets(QDataStream& in, QSplitter* currentS
|
|||||||
if (!restoreSectionWidgets(in, sp, sections))
|
if (!restoreSectionWidgets(in, sp, sections))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (sp->count() <= 0)
|
||||||
|
{
|
||||||
|
delete sp;
|
||||||
|
sp = NULL;
|
||||||
|
}
|
||||||
|
else if (sp)
|
||||||
|
{
|
||||||
sp->setSizes(sizes);
|
sp->setSizes(sizes);
|
||||||
|
|
||||||
if (!currentSplitter)
|
if (!currentSplitter)
|
||||||
@ -545,6 +594,7 @@ bool ContainerWidget::restoreSectionWidgets(QDataStream& in, QSplitter* currentS
|
|||||||
else
|
else
|
||||||
currentSplitter->addWidget(sp);
|
currentSplitter->addWidget(sp);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Section
|
// Section
|
||||||
else if (type == 2)
|
else if (type == 2)
|
||||||
{
|
{
|
||||||
@ -575,10 +625,18 @@ bool ContainerWidget::restoreSectionWidgets(QDataStream& in, QSplitter* currentS
|
|||||||
|
|
||||||
sw->addContent(sc);
|
sw->addContent(sc);
|
||||||
}
|
}
|
||||||
|
if (sw->contents().isEmpty())
|
||||||
|
{
|
||||||
|
delete sw;
|
||||||
|
sw = NULL;
|
||||||
|
}
|
||||||
|
else if (sw)
|
||||||
|
{
|
||||||
sw->setCurrentIndex(currentIndex);
|
sw->setCurrentIndex(currentIndex);
|
||||||
currentSplitter->addWidget(sw);
|
currentSplitter->addWidget(sw);
|
||||||
sections.append(sw);
|
sections.append(sw);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Unknown
|
// Unknown
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -601,6 +659,7 @@ bool ContainerWidget::takeContent(const SectionContent::RefPtr& sc, InternalCont
|
|||||||
for (int i = 0; i < _floatings.count() && !found; ++i)
|
for (int i = 0; i < _floatings.count() && !found; ++i)
|
||||||
{
|
{
|
||||||
found = _floatings.at(i)->content()->uid() == sc->uid();
|
found = _floatings.at(i)->content()->uid() == sc->uid();
|
||||||
|
if (found)
|
||||||
_floatings.at(i)->takeContent(data);
|
_floatings.at(i)->takeContent(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "ads/SectionContent.h"
|
#include "ads/SectionContent.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
|
||||||
ADS_NAMESPACE_BEGIN
|
ADS_NAMESPACE_BEGIN
|
||||||
@ -8,14 +9,42 @@ int SectionContent::NextUid = 1;
|
|||||||
QHash<int, SectionContent::WeakPtr> SectionContent::LookupMap;
|
QHash<int, SectionContent::WeakPtr> SectionContent::LookupMap;
|
||||||
QHash<QString, SectionContent::WeakPtr> SectionContent::LookupMapByName;
|
QHash<QString, SectionContent::WeakPtr> SectionContent::LookupMapByName;
|
||||||
|
|
||||||
SectionContent::SectionContent(QWidget* title, QWidget* content, const QString& uniqueName) :
|
SectionContent::SectionContent() :
|
||||||
_uid(NextUid++),
|
_uid(NextUid++)
|
||||||
_uniqueName(uniqueName),
|
|
||||||
_title(title),
|
|
||||||
_content(content)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SectionContent::RefPtr SectionContent::newSectionContent(const QString& uniqueName, ContainerWidget* container, QWidget* title, QWidget* content)
|
||||||
|
{
|
||||||
|
if (uniqueName.isEmpty())
|
||||||
|
{
|
||||||
|
qFatal("Can not create SectionContent with empty uniqueName");
|
||||||
|
return RefPtr();
|
||||||
|
}
|
||||||
|
else if (LookupMapByName.contains(uniqueName))
|
||||||
|
{
|
||||||
|
qFatal("Can not create SectionContent with already used uniqueName");
|
||||||
|
return RefPtr();
|
||||||
|
}
|
||||||
|
else if (!container || !title || !content)
|
||||||
|
{
|
||||||
|
qFatal("Can not create SectionContent with NULL values");
|
||||||
|
return RefPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<SectionContent> sc(new SectionContent());
|
||||||
|
sc->_uniqueName = uniqueName;
|
||||||
|
sc->_container = container;
|
||||||
|
sc->_title = title;
|
||||||
|
sc->_content = content;
|
||||||
|
|
||||||
|
LookupMap.insert(sc->uid(), sc);
|
||||||
|
if (!sc->uniqueName().isEmpty())
|
||||||
|
LookupMapByName.insert(sc->uniqueName(), sc);
|
||||||
|
|
||||||
|
return sc;
|
||||||
|
}
|
||||||
|
|
||||||
SectionContent::~SectionContent()
|
SectionContent::~SectionContent()
|
||||||
{
|
{
|
||||||
LookupMap.remove(_uid);
|
LookupMap.remove(_uid);
|
||||||
@ -34,6 +63,11 @@ QString SectionContent::uniqueName() const
|
|||||||
return _uniqueName;
|
return _uniqueName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContainerWidget* SectionContent::containerWidget() const
|
||||||
|
{
|
||||||
|
return _container;
|
||||||
|
}
|
||||||
|
|
||||||
QWidget* SectionContent::titleWidget() const
|
QWidget* SectionContent::titleWidget() const
|
||||||
{
|
{
|
||||||
return _title;
|
return _title;
|
||||||
@ -44,13 +78,4 @@ QWidget* SectionContent::contentWidget() const
|
|||||||
return _content;
|
return _content;
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionContent::RefPtr SectionContent::newSectionContent(QWidget* title, QWidget* content, const QString& uniqueName)
|
|
||||||
{
|
|
||||||
QSharedPointer<SectionContent> sc(new SectionContent(title, content, uniqueName));
|
|
||||||
LookupMap.insert(sc->uid(), sc);
|
|
||||||
if (!sc->uniqueName().isEmpty())
|
|
||||||
LookupMapByName.insert(sc->uniqueName(), sc);
|
|
||||||
return sc;
|
|
||||||
}
|
|
||||||
|
|
||||||
ADS_NAMESPACE_END
|
ADS_NAMESPACE_END
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
static int CONTENT_COUNT = 0;
|
static int CONTENT_COUNT = 0;
|
||||||
|
|
||||||
static ADS_NS::SectionContent::RefPtr createLongTextLabelSC()
|
static ADS_NS::SectionContent::RefPtr createLongTextLabelSC(ADS_NS::ContainerWidget* container)
|
||||||
{
|
{
|
||||||
QWidget* w = new QWidget();
|
QWidget* w = new QWidget();
|
||||||
QBoxLayout* bl = new QBoxLayout(QBoxLayout::TopToBottom);
|
QBoxLayout* bl = new QBoxLayout(QBoxLayout::TopToBottom);
|
||||||
@ -32,18 +32,18 @@ static ADS_NS::SectionContent::RefPtr createLongTextLabelSC()
|
|||||||
bl->addWidget(l);
|
bl->addWidget(l);
|
||||||
|
|
||||||
const int index = ++CONTENT_COUNT;
|
const int index = ++CONTENT_COUNT;
|
||||||
return ADS_NS::SectionContent::newSectionContent(new IconTitleWidget(QIcon(), QString("Label %1").arg(index)), w, QString("uname-%1").arg(index));
|
return ADS_NS::SectionContent::newSectionContent(QString("uname-%1").arg(index), container, new IconTitleWidget(QIcon(), QString("Label %1").arg(index)), w);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ADS_NS::SectionContent::RefPtr createCalendarSC()
|
static ADS_NS::SectionContent::RefPtr createCalendarSC(ADS_NS::ContainerWidget* container)
|
||||||
{
|
{
|
||||||
QCalendarWidget* w = new QCalendarWidget();
|
QCalendarWidget* w = new QCalendarWidget();
|
||||||
|
|
||||||
const int index = ++CONTENT_COUNT;
|
const int index = ++CONTENT_COUNT;
|
||||||
return ADS_NS::SectionContent::newSectionContent(new IconTitleWidget(QIcon(), QString("Calendar %1").arg(index)), w, QString("uname-%1").arg(index));
|
return ADS_NS::SectionContent::newSectionContent(QString("uname-%1").arg(index), container, new IconTitleWidget(QIcon(), QString("Calendar %1").arg(index)), w);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ADS_NS::SectionContent::RefPtr createFileSystemTreeSC()
|
static ADS_NS::SectionContent::RefPtr createFileSystemTreeSC(ADS_NS::ContainerWidget* container)
|
||||||
{
|
{
|
||||||
QTreeView* w = new QTreeView();
|
QTreeView* w = new QTreeView();
|
||||||
// QFileSystemModel* m = new QFileSystemModel(w);
|
// QFileSystemModel* m = new QFileSystemModel(w);
|
||||||
@ -51,7 +51,7 @@ static ADS_NS::SectionContent::RefPtr createFileSystemTreeSC()
|
|||||||
// w->setModel(m);
|
// w->setModel(m);
|
||||||
|
|
||||||
const int index = ++CONTENT_COUNT;
|
const int index = ++CONTENT_COUNT;
|
||||||
return ADS_NS::SectionContent::newSectionContent(new IconTitleWidget(QIcon(), QString("Filesystem %1").arg(index)), w, QString("uname-%1").arg(index));
|
return ADS_NS::SectionContent::newSectionContent(QString("uname-%1").arg(index), container, new IconTitleWidget(QIcon(), QString("Filesystem %1").arg(index)), w);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void storeDataHelper(const QString& fname, const QByteArray& ba)
|
static void storeDataHelper(const QString& fname, const QByteArray& ba)
|
||||||
@ -98,10 +98,13 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
// Test #1: Use high-level public API
|
// Test #1: Use high-level public API
|
||||||
if (true)
|
if (true)
|
||||||
{
|
{
|
||||||
ADS_NS::SectionWidget* sw1 = _container->addSectionContent(createLongTextLabelSC());
|
ADS_NS::SectionWidget* sw1 = _container->addSectionContent(createLongTextLabelSC(_container));
|
||||||
ADS_NS::SectionWidget* sw2 = _container->addSectionContent(createCalendarSC(), sw1, ADS_NS::BottomDropArea);
|
_container->addSectionContent(createCalendarSC(_container), sw1, ADS_NS::BottomDropArea);
|
||||||
ADS_NS::SectionWidget* sw3 = _container->addSectionContent(createFileSystemTreeSC(), NULL, ADS_NS::RightDropArea);
|
_container->addSectionContent(createFileSystemTreeSC(_container), NULL, ADS_NS::RightDropArea);
|
||||||
ADS_NS::SectionWidget* sw4 = _container->addSectionContent(createCalendarSC());
|
_container->addSectionContent(createCalendarSC(_container));
|
||||||
|
// _container->addSectionContent(createLongTextLabelSC(_container));
|
||||||
|
// _container->addSectionContent(createLongTextLabelSC(_container));
|
||||||
|
// _container->addSectionContent(createLongTextLabelSC(_container));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default window geometry
|
// Default window geometry
|
||||||
|
@ -28,7 +28,7 @@ Sorted by priority
|
|||||||
- [x] Serialize and Deserialize state/size/positions of dockings
|
- [x] Serialize and Deserialize state/size/positions of dockings
|
||||||
- [x] Make compatible with Qt 4.5 (\*ROFL!\*)
|
- [x] Make compatible with Qt 4.5 (\*ROFL!\*)
|
||||||
- [x] Save and restore FloatingWidget states
|
- [x] Save and restore FloatingWidget states
|
||||||
- [ ] Restore: Manage new or deleted SectionContent objects, which are not available
|
- [x] Restore: Manage new or deleted SectionContent objects, which are not available
|
||||||
- [ ] Show close button on right corner of SectionWidget
|
- [ ] Show close button on right corner of SectionWidget
|
||||||
- [ ] Drop indicator images should be fully visible over the DropOverlay rectangle
|
- [ ] Drop indicator images should be fully visible over the DropOverlay rectangle
|
||||||
- [ ] Pin contents: Pins a content and its title widget to the edge and opens on click/hover as long as it has focus
|
- [ ] Pin contents: Pins a content and its title widget to the edge and opens on click/hover as long as it has focus
|
||||||
|
Loading…
Reference in New Issue
Block a user