diff --git a/AdvancedDockingSystem/include/ads/ContainerWidget.h b/AdvancedDockingSystem/include/ads/ContainerWidget.h index ea6e803..1017b9d 100644 --- a/AdvancedDockingSystem/include/ads/ContainerWidget.h +++ b/AdvancedDockingSystem/include/ads/ContainerWidget.h @@ -89,7 +89,8 @@ private: void addSection(SectionWidget* section); SectionWidget* sectionAt(const QPoint& pos) const; 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& floatings); bool restoreSectionWidgets(QDataStream& in, QSplitter* currentSplitter, QList& sections); bool takeContent(const SectionContent::RefPtr& sc, InternalContentData& data); diff --git a/AdvancedDockingSystem/include/ads/SectionContent.h b/AdvancedDockingSystem/include/ads/SectionContent.h index 9dddaf2..10a989e 100644 --- a/AdvancedDockingSystem/include/ads/SectionContent.h +++ b/AdvancedDockingSystem/include/ads/SectionContent.h @@ -10,29 +10,43 @@ #include "ads/API.h" ADS_NAMESPACE_BEGIN +class ContainerWidget; class SectionContent { friend class ContainerWidget; private: - SectionContent(QWidget* title, QWidget* content, const QString& uniqueName = QString()); ///< Do not use! + SectionContent(); + SectionContent(const SectionContent&); + SectionContent& operator=(const SectionContent&); public: typedef QSharedPointer RefPtr; typedef QWeakPointer WeakPtr; + /*! + * Creates new content, associates it to container and takes ownership of + * title- and content- 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(); int uid() const; QString uniqueName() const; + ContainerWidget* containerWidget() const; QWidget* titleWidget() const; QWidget* contentWidget() const; - static RefPtr newSectionContent(QWidget* title, QWidget* content, const QString& uniqueName = QString()); - private: const int _uid; - const QString _uniqueName; + QString _uniqueName; + ContainerWidget* _container; QPointer _title; QPointer _content; diff --git a/AdvancedDockingSystem/src/ContainerWidget.cpp b/AdvancedDockingSystem/src/ContainerWidget.cpp index 4a56577..0bb390a 100644 --- a/AdvancedDockingSystem/src/ContainerWidget.cpp +++ b/AdvancedDockingSystem/src/ContainerWidget.cpp @@ -131,14 +131,7 @@ QByteArray ContainerWidget::saveState() const out << (quint32) 1; // Version // Save state of floating contents - 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(); - } + saveFloatingWidgets(out); // Walk through layout for splitters // Well.. there actually shouldn't be more than one @@ -147,7 +140,7 @@ QByteArray ContainerWidget::saveState() const QLayoutItem* li = _mainLayout->itemAt(i); if (!li->widget()) continue; - saveGeometryWalk(out, li->widget()); + saveSectionWidgets(out, li->widget()); } return ba; @@ -187,12 +180,49 @@ bool ContainerWidget::restoreState(const QByteArray& data) 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 leftContents; + + // Collect all contents which has been restored + QList 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 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; _sections = sections; - // TODO Handle contents which are not mentioned by deserialized data - // ... - // Delete old objects QLayoutItem* old = _mainLayout->takeAt(0); _mainLayout->addWidget(_splitter); @@ -450,7 +480,19 @@ SectionWidget* ContainerWidget::dropContentOuterHelper(QLayout* l, const Interna 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; SectionWidget* sw = NULL; @@ -467,7 +509,7 @@ void ContainerWidget::saveGeometryWalk(QDataStream& out, QWidget* widget) const out << sp->sizes(); for (int i = 0; i < sp->count(); ++i) { - saveGeometryWalk(out, sp->widget(i)); + saveSectionWidgets(out, sp->widget(i)); } } else if ((sw = dynamic_cast(widget)) != NULL) @@ -538,12 +580,20 @@ bool ContainerWidget::restoreSectionWidgets(QDataStream& in, QSplitter* currentS if (!restoreSectionWidgets(in, sp, sections)) return false; } - sp->setSizes(sizes); + if (sp->count() <= 0) + { + delete sp; + sp = NULL; + } + else if (sp) + { + sp->setSizes(sizes); - if (!currentSplitter) - _splitter = sp; - else - currentSplitter->addWidget(sp); + if (!currentSplitter) + _splitter = sp; + else + currentSplitter->addWidget(sp); + } } // Section else if (type == 2) @@ -575,9 +625,17 @@ bool ContainerWidget::restoreSectionWidgets(QDataStream& in, QSplitter* currentS sw->addContent(sc); } - sw->setCurrentIndex(currentIndex); - currentSplitter->addWidget(sw); - sections.append(sw); + if (sw->contents().isEmpty()) + { + delete sw; + sw = NULL; + } + else if (sw) + { + sw->setCurrentIndex(currentIndex); + currentSplitter->addWidget(sw); + sections.append(sw); + } } // Unknown else @@ -601,7 +659,8 @@ bool ContainerWidget::takeContent(const SectionContent::RefPtr& sc, InternalCont for (int i = 0; i < _floatings.count() && !found; ++i) { found = _floatings.at(i)->content()->uid() == sc->uid(); - _floatings.at(i)->takeContent(data); + if (found) + _floatings.at(i)->takeContent(data); } return found; diff --git a/AdvancedDockingSystem/src/SectionContent.cpp b/AdvancedDockingSystem/src/SectionContent.cpp index 66ff449..1a62ed9 100644 --- a/AdvancedDockingSystem/src/SectionContent.cpp +++ b/AdvancedDockingSystem/src/SectionContent.cpp @@ -1,5 +1,6 @@ #include "ads/SectionContent.h" +#include #include ADS_NAMESPACE_BEGIN @@ -8,14 +9,42 @@ int SectionContent::NextUid = 1; QHash SectionContent::LookupMap; QHash SectionContent::LookupMapByName; -SectionContent::SectionContent(QWidget* title, QWidget* content, const QString& uniqueName) : - _uid(NextUid++), - _uniqueName(uniqueName), - _title(title), - _content(content) +SectionContent::SectionContent() : + _uid(NextUid++) { } +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 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() { LookupMap.remove(_uid); @@ -34,6 +63,11 @@ QString SectionContent::uniqueName() const return _uniqueName; } +ContainerWidget* SectionContent::containerWidget() const +{ + return _container; +} + QWidget* SectionContent::titleWidget() const { return _title; @@ -44,13 +78,4 @@ QWidget* SectionContent::contentWidget() const return _content; } -SectionContent::RefPtr SectionContent::newSectionContent(QWidget* title, QWidget* content, const QString& uniqueName) -{ - QSharedPointer 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 diff --git a/AdvancedDockingSystemDemo/src/mainwindow.cpp b/AdvancedDockingSystemDemo/src/mainwindow.cpp index 2e9f0b5..836991d 100644 --- a/AdvancedDockingSystemDemo/src/mainwindow.cpp +++ b/AdvancedDockingSystemDemo/src/mainwindow.cpp @@ -19,7 +19,7 @@ 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(); QBoxLayout* bl = new QBoxLayout(QBoxLayout::TopToBottom); @@ -32,18 +32,18 @@ static ADS_NS::SectionContent::RefPtr createLongTextLabelSC() bl->addWidget(l); 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(); 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(); // QFileSystemModel* m = new QFileSystemModel(w); @@ -51,7 +51,7 @@ static ADS_NS::SectionContent::RefPtr createFileSystemTreeSC() // w->setModel(m); 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) @@ -98,10 +98,13 @@ MainWindow::MainWindow(QWidget *parent) : // Test #1: Use high-level public API if (true) { - ADS_NS::SectionWidget* sw1 = _container->addSectionContent(createLongTextLabelSC()); - ADS_NS::SectionWidget* sw2 = _container->addSectionContent(createCalendarSC(), sw1, ADS_NS::BottomDropArea); - ADS_NS::SectionWidget* sw3 = _container->addSectionContent(createFileSystemTreeSC(), NULL, ADS_NS::RightDropArea); - ADS_NS::SectionWidget* sw4 = _container->addSectionContent(createCalendarSC()); + ADS_NS::SectionWidget* sw1 = _container->addSectionContent(createLongTextLabelSC(_container)); + _container->addSectionContent(createCalendarSC(_container), sw1, ADS_NS::BottomDropArea); + _container->addSectionContent(createFileSystemTreeSC(_container), NULL, ADS_NS::RightDropArea); + _container->addSectionContent(createCalendarSC(_container)); +// _container->addSectionContent(createLongTextLabelSC(_container)); +// _container->addSectionContent(createLongTextLabelSC(_container)); +// _container->addSectionContent(createLongTextLabelSC(_container)); } // Default window geometry diff --git a/README.md b/README.md index d2842d8..17aba38 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Sorted by priority - [x] Serialize and Deserialize state/size/positions of dockings - [x] Make compatible with Qt 4.5 (\*ROFL!\*) - [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 - [ ] 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