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:
mfreiholz 2016-02-17 14:42:46 +01:00
parent 1b91fe241b
commit eaff4f3d4e
6 changed files with 155 additions and 53 deletions

View File

@ -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<FloatingWidget*>& floatings);
bool restoreSectionWidgets(QDataStream& in, QSplitter* currentSplitter, QList<SectionWidget*>& sections);
bool takeContent(const SectionContent::RefPtr& sc, InternalContentData& data);

View File

@ -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<SectionContent> RefPtr;
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();
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<QWidget> _title;
QPointer<QWidget> _content;

View File

@ -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<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;
_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<SectionWidget*>(widget)) != NULL)
@ -538,6 +580,13 @@ bool ContainerWidget::restoreSectionWidgets(QDataStream& in, QSplitter* currentS
if (!restoreSectionWidgets(in, sp, sections))
return false;
}
if (sp->count() <= 0)
{
delete sp;
sp = NULL;
}
else if (sp)
{
sp->setSizes(sizes);
if (!currentSplitter)
@ -545,6 +594,7 @@ bool ContainerWidget::restoreSectionWidgets(QDataStream& in, QSplitter* currentS
else
currentSplitter->addWidget(sp);
}
}
// Section
else if (type == 2)
{
@ -575,10 +625,18 @@ bool ContainerWidget::restoreSectionWidgets(QDataStream& in, QSplitter* currentS
sw->addContent(sc);
}
if (sw->contents().isEmpty())
{
delete sw;
sw = NULL;
}
else if (sw)
{
sw->setCurrentIndex(currentIndex);
currentSplitter->addWidget(sw);
sections.append(sw);
}
}
// Unknown
else
{
@ -601,6 +659,7 @@ 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();
if (found)
_floatings.at(i)->takeContent(data);
}

View File

@ -1,5 +1,6 @@
#include "ads/SectionContent.h"
#include <QDebug>
#include <QLabel>
ADS_NAMESPACE_BEGIN
@ -8,14 +9,42 @@ int SectionContent::NextUid = 1;
QHash<int, SectionContent::WeakPtr> SectionContent::LookupMap;
QHash<QString, SectionContent::WeakPtr> 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<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()
{
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<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

View File

@ -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

View File

@ -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