mirror of
https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System.git
synced 2024-12-24 07:21:32 +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);
|
||||
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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user