Updates high level api usage of ContainerWidget.

This commit is contained in:
mfreiholz 2016-02-15 10:28:42 +01:00
parent 1befbace4b
commit 77d05431c6
8 changed files with 271 additions and 121 deletions

View File

@ -31,13 +31,37 @@ class ContainerWidget : public QFrame
public:
explicit ContainerWidget(QWidget *parent = NULL);
//
// Public API
//
Qt::Orientation orientation() const;
void setOrientation(Qt::Orientation orientation);
void dropContent(const InternalContentData& data, SectionWidget* targetSection, DropArea area);
/*!
* Adds the section-content <em>sc</em> to this container-widget into the section-widget <em>sw</em>.
* If <em>sw</em> is not NULL, the <em>area</em> is used to indicate how the content should be arranged.
* Returns a pointer to the SectionWidget of the added SectionContent. Do not use it for anything else than adding more
* SectionContent elements with this method.
*/
SectionWidget* addSectionContent(const SectionContent::RefPtr& sc, SectionWidget* sw = NULL, DropArea area = CenterDropArea);
void addSection(SectionWidget* section);
/*!
* Creates a QMenu based on available SectionContents.
* The ownership is needs to be handled by the caller.
*/
QMenu* createContextMenu() const;
//
// Internal Stuff Begins Here
//
// splitSections splits "section1" and "section2" with given "orientation".
// The "section2" element is moved to the "section1" element.
void splitSections(SectionWidget* section1, SectionWidget* section2, Qt::Orientation orientation = Qt::Horizontal);
SectionWidget* dropContent(const InternalContentData& data, SectionWidget* targetSection, DropArea area, bool autoActive = true);
void addSection(SectionWidget* section);
SectionWidget* sectionAt(const QPoint& pos) const;
// Drop areas for the ContainerWidget
@ -50,12 +74,17 @@ public:
QByteArray saveState() const;
bool restoreState(const QByteArray& data);
QMenu* createContextMenu() const;
private:
void saveGeometryWalk(QDataStream& out, QWidget* widget) const;
bool restoreGeometryWalk(QDataStream& in, QSplitter* currentSplitter = NULL);
// takeContent searches all section-widgets and floating-widgets for "sc" and takes
// the ownership of it and passes it to "data" object.
bool takeContent(const SectionContent::RefPtr& sc, InternalContentData& data);
private slots:
void onActionToggleSectionContentVisibility(bool visible);
signals:
void orientationChanged();

View File

@ -26,11 +26,10 @@ public:
FloatingWidget(ContainerWidget* container, SectionContent::RefPtr sc, SectionTitleWidget* titleWidget, SectionContentWidget* contentWidget, QWidget* parent = NULL);
virtual ~FloatingWidget();
InternalContentData takeContent();
SectionContent::RefPtr content() const { return _content; }
protected:
virtual void closeEvent(QCloseEvent* e);
public://private:
bool takeContent(InternalContentData& data);
private:
ContainerWidget* _container;

View File

@ -39,7 +39,7 @@ public:
const QList<SectionContent::RefPtr>& contents() const { return _contents; }
void addContent(SectionContent::RefPtr c);
void addContent(const InternalContentData& data, bool autoActivate);
InternalContentData take(int uid, bool del = true);
bool take(int uid, InternalContentData& data);
int indexOfContent(SectionContent::RefPtr c) const;
int indexOfContentByTitlePos(const QPoint& pos, QWidget* exclude = NULL) const;

View File

@ -1,5 +1,7 @@
#include "ads/ContainerWidget.h"
#include "ads/Internal.h"
#include "ads/SectionTitleWidget.h"
#include "ads/SectionContentWidget.h"
#include <QPaintEvent>
#include <QPainter>
@ -21,7 +23,7 @@ static QSplitter* newSplitter(Qt::Orientation orientation = Qt::Horizontal, QWid
return s;
}
static void dropContentOuterHelper(ContainerWidget* cw, QLayout* l, const InternalContentData& data, Qt::Orientation orientation, bool append)
static SectionWidget* dropContentOuterHelper(ContainerWidget* cw, QLayout* l, const InternalContentData& data, Qt::Orientation orientation, bool append)
{
SectionWidget* sw = new SectionWidget(cw);
sw->addContent(data, true);
@ -70,6 +72,7 @@ static void dropContentOuterHelper(ContainerWidget* cw, QLayout* l, const Intern
#endif
}
}
return sw;
}
///////////////////////////////////////////////////////////////////////
@ -100,29 +103,125 @@ void ContainerWidget::setOrientation(Qt::Orientation orientation)
}
}
void ContainerWidget::dropContent(const InternalContentData& data, SectionWidget* targetSection, DropArea area)
SectionWidget* ContainerWidget::addSectionContent(const SectionContent::RefPtr& sc, SectionWidget* sw, DropArea area)
{
if (!sw)
{
if (_sections.isEmpty())
{ // Create default section
sw = new SectionWidget(this);
addSection(sw);
}
else if (area == CenterDropArea)
// Use existing default section
sw = _sections.first();
}
// Drop it based on "area"
InternalContentData data;
data.content = sc;
data.titleWidget = new SectionTitleWidget(sc, NULL);
data.contentWidget = new SectionContentWidget(sc, NULL);
return dropContent(data, sw, area, false);
}
QMenu* ContainerWidget::createContextMenu() const
{
QMenu* m = new QMenu(NULL);
// Contents of SectionWidgets
for (int i = 0; i < _sections.size(); ++i)
{
SectionWidget* sw = _sections.at(i);
QList<SectionContent::RefPtr> contents = sw->contents();
foreach (const SectionContent::RefPtr& c, contents)
{
QAction* a = m->addAction(QIcon(), c->uniqueName());
a->setProperty("uid", c->uid());
a->setProperty("type", "section");
a->setCheckable(true);
a->setChecked(c->titleWidget()->isVisible());
#if QT_VERSION >= 0x050000
QObject::connect(a, &QAction::toggled, this, &ContainerWidget::onActionToggleSectionContentVisibility);
#else
QObject::connect(a, SIGNAL(toggled(bool)), this, SLOT(onActionToggleSectionContentVisibility(bool)));
#endif
}
}
// Contents of FloatingWidgets
if (_floatingWidgets.size())
{
if (m->actions().size())
m->addSeparator();
for (int i = 0; i < _floatingWidgets.size(); ++i)
{
FloatingWidget* fw = _floatingWidgets.at(i);
SectionContent::RefPtr c = fw->content();
QAction* a = m->addAction(QIcon(), c->uniqueName());
a->setProperty("uid", c->uid());
a->setProperty("type", "floating");
a->setCheckable(true);
a->setChecked(fw->isVisible());
#if QT_VERSION >= 0x050000
QObject::connect(a, &QAction::toggled, fw, &FloatingWidget::setVisible);
#else
QObject::connect(a, SIGNAL(toggled(bool)), fw, SLOT(setVisible(bool)));
#endif
}
}
return m;
}
///////////////////////////////////////////////////////////////////////
// PRIVATE API BEGINS HERE
///////////////////////////////////////////////////////////////////////
void ContainerWidget::splitSections(SectionWidget* s1, SectionWidget* s2, Qt::Orientation orientation)
{
addSection(s1);
if (!s2)
s2 = new SectionWidget(this);
addSection(s2);
QSplitter* currentSplitter = findParentSplitter(s1);
if (currentSplitter)
{
const int index = currentSplitter->indexOf(s1);
QSplitter* splitter = newSplitter(orientation, this);
splitter->addWidget(s1);
splitter->addWidget(s2);
currentSplitter->insertWidget(index, splitter);
}
}
SectionWidget* ContainerWidget::dropContent(const InternalContentData& data, SectionWidget* targetSection, DropArea area, bool autoActive)
{
SectionWidget* ret = NULL;
// Drop on outer area
if (!targetSection)
{
switch (area)
{
case TopDropArea:
dropContentOuterHelper(this, _mainLayout, data, Qt::Vertical, false);
ret = dropContentOuterHelper(this, _mainLayout, data, Qt::Vertical, false);
break;
case RightDropArea:
dropContentOuterHelper(this, _mainLayout, data, Qt::Horizontal, true);
ret = dropContentOuterHelper(this, _mainLayout, data, Qt::Horizontal, true);
break;
case BottomDropArea:
dropContentOuterHelper(this, _mainLayout, data, Qt::Vertical, true);
ret = dropContentOuterHelper(this, _mainLayout, data, Qt::Vertical, true);
break;
case LeftDropArea:
dropContentOuterHelper(this, _mainLayout, data, Qt::Horizontal, false);
ret = dropContentOuterHelper(this, _mainLayout, data, Qt::Horizontal, false);
break;
default:
return;
return NULL;
}
return;
return NULL;
}
QSplitter* targetSectionSplitter = findParentSplitter(targetSection);
@ -147,6 +246,7 @@ void ContainerWidget::dropContent(const InternalContentData& data, SectionWidget
s->addWidget(targetSection);
targetSectionSplitter->insertWidget(index, s);
}
ret = sw;
break;
}
case RightDropArea:
@ -166,6 +266,7 @@ void ContainerWidget::dropContent(const InternalContentData& data, SectionWidget
s->addWidget(sw);
targetSectionSplitter->insertWidget(index, s);
}
ret = sw;
break;
}
case BottomDropArea:
@ -185,6 +286,7 @@ void ContainerWidget::dropContent(const InternalContentData& data, SectionWidget
s->addWidget(sw);
targetSectionSplitter->insertWidget(index, s);
}
ret = sw;
break;
}
case LeftDropArea:
@ -204,16 +306,19 @@ void ContainerWidget::dropContent(const InternalContentData& data, SectionWidget
targetSectionSplitter->insertWidget(index, s);
s->addWidget(targetSection);
}
ret = sw;
break;
}
case CenterDropArea:
{
targetSection->addContent(data, true);
targetSection->addContent(data, autoActive);
ret = targetSection;
break;
}
default:
break;
}
return ret;
}
void ContainerWidget::addSection(SectionWidget* section)
@ -232,22 +337,6 @@ void ContainerWidget::addSection(SectionWidget* section)
_splitter->addWidget(section);
}
void ContainerWidget::splitSections(SectionWidget* s1, SectionWidget* s2, Qt::Orientation orientation)
{
addSection(s1);
addSection(s2);
QSplitter* currentSplitter = findParentSplitter(s1);
if (currentSplitter)
{
const int index = currentSplitter->indexOf(s1);
QSplitter* splitter = newSplitter(orientation, this);
splitter->addWidget(s1);
splitter->addWidget(s2);
currentSplitter->insertWidget(index, splitter);
}
}
SectionWidget* ContainerWidget::sectionAt(const QPoint& pos) const
{
const QPoint gpos = mapToGlobal(pos);
@ -307,6 +396,17 @@ QByteArray ContainerWidget::saveState() const
continue;
saveGeometryWalk(out, li->widget());
}
// Save state of FloatingWidgets
out << _floatingWidgets.count();
for (int i = 0; i < _floatingWidgets.count(); ++i)
{
FloatingWidget* fw = _floatingWidgets.at(i);
out << fw->content()->uniqueName();
out << fw->isVisible();
out << fw->saveGeometry();
}
return ba;
}
@ -328,6 +428,7 @@ bool ContainerWidget::restoreState(const QByteArray& data)
QList<SectionWidget*> currentSections = _sections;
_sections.clear();
// Restore splitters and section widgets
const bool success = restoreGeometryWalk(in, NULL);
if (success)
{
@ -336,47 +437,30 @@ bool ContainerWidget::restoreState(const QByteArray& data)
delete old;
qDeleteAll(currentSections);
}
// Restore floating widgets
int fwCount = 0;
in >> fwCount;
for (int i = 0; i < fwCount; ++i)
{
QString uname;
bool visible = false;
QRect geom;
in >> uname >> visible >> geom;
SectionContent::RefPtr sc = SectionContent::LookupMapByName.value(uname).toStrongRef();
if (!sc)
{
qWarning() << "Can not find floating widget section-content" << uname;
continue;
}
// FloatingWidget* fw = new FloatingWidget(this, sc,)
}
return success;
}
QMenu* ContainerWidget::createContextMenu() const
{
QMenu* m = new QMenu(const_cast<ContainerWidget*>(this));
// Contents of SectionWidgets
for (int i = 0; i < _sections.size(); ++i)
{
SectionWidget* sw = _sections.at(i);
QList<SectionContent::RefPtr> contents = sw->contents();
foreach (const SectionContent::RefPtr& c, contents)
{
m->addAction(QIcon(), QString("Content %1").arg(c->uid()));
}
}
// Contents of FloatingWidgets
if (_floatingWidgets.size())
{
if (m->actions().size())
m->addSeparator();
for (int i = 0; i < _floatingWidgets.size(); ++i)
{
FloatingWidget* fw = _floatingWidgets.at(i);
SectionContent::RefPtr c = fw->content();
QAction* a = m->addAction(QIcon(), QString("Floating %1").arg(c->uid()));
a->setCheckable(true);
a->setChecked(fw->isVisible());
#if QT_VERSION >= 0x050000
QObject::connect(a, &QAction::toggled, fw, &FloatingWidget::setVisible);
#else
QObject::connect(a, SIGNAL(toggled(bool)), fw, SLOT(setVisible(bool)));
#endif
}
}
return m;
}
void ContainerWidget::saveGeometryWalk(QDataStream& out, QWidget* widget) const
{
QSplitter* sp = NULL;
@ -448,7 +532,7 @@ bool ContainerWidget::restoreGeometryWalk(QDataStream& in, QSplitter* currentSpl
in >> currentIndex >> count;
SectionWidget* sw = new SectionWidget(this);
// sw->setGeometry(geom);
// sw->setGeometry(geom);
for (int i = 0; i < count; ++i)
{
QString name;
@ -469,4 +553,32 @@ bool ContainerWidget::restoreGeometryWalk(QDataStream& in, QSplitter* currentSpl
return true;
}
bool ContainerWidget::takeContent(const SectionContent::RefPtr& sc, InternalContentData& data)
{
// Search in sections
bool found = false;
for (int i = 0; i < _sections.count() && !found; ++i)
{
found = _sections.at(i)->take(sc->uid(), data);
}
// Search in floating widgets
for (int i = 0; i < _floatingWidgets.count() && !found; ++i)
{
found = _floatingWidgets.at(i)->content()->uid() == sc->uid();
_floatingWidgets.at(i)->takeContent(data);
}
return found;
}
void ContainerWidget::onActionToggleSectionContentVisibility(bool visible)
{
QAction* a = qobject_cast<QAction*>(sender());
if (!a)
return;
const int uid = a->property("uid").toInt();
qDebug() << "Change visibility of" << uid << visible;
}
ADS_NAMESPACE_END

View File

@ -22,13 +22,13 @@ FloatingWidget::FloatingWidget(ContainerWidget* container, SectionContent::RefPt
_titleWidget(titleWidget),
_contentWidget(contentWidget)
{
QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom, this);
QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom);
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
setLayout(l);
// Title + Controls
_titleLayout = new QBoxLayout(QBoxLayout::LeftToRight, this);
_titleLayout = new QBoxLayout(QBoxLayout::LeftToRight);
_titleLayout->addWidget(titleWidget, 1);
l->addLayout(_titleLayout, 0);
@ -62,9 +62,8 @@ FloatingWidget::~FloatingWidget()
_container->_floatingWidgets.removeAll(this);
}
InternalContentData FloatingWidget::takeContent()
bool FloatingWidget::takeContent(InternalContentData& data)
{
InternalContentData data;
data.content = _content;
data.titleWidget = _titleWidget;
data.contentWidget = _contentWidget;
@ -75,11 +74,7 @@ InternalContentData FloatingWidget::takeContent()
layout()->removeWidget(_contentWidget);
_contentWidget = NULL;
return data;
}
void FloatingWidget::closeEvent(QCloseEvent*)
{
return true;
}
ADS_NAMESPACE_END

View File

@ -83,14 +83,15 @@ void SectionTitleWidget::mouseReleaseEvent(QMouseEvent* ev)
if (loc != InvalidDropArea)
{
#if !defined(ADS_ANIMATIONS_ENABLED)
InternalContentData data = _fw->takeContent();
InternalContentData data;
_fw->takeContent(data);
_fw->deleteLater();
#if QT_VERSION >= 0x050000
_fw.clear();
#else
_fw = 0;
#endif
cw->dropContent(data, sw, loc);
cw->dropContent(data, sw, loc, true);
#else
QPropertyAnimation* moveAnim = new QPropertyAnimation(_fw, "pos", this);
moveAnim->setStartValue(_fw->pos());
@ -132,14 +133,15 @@ void SectionTitleWidget::mouseReleaseEvent(QMouseEvent* ev)
if (dropArea != DropArea::InvalidDropArea)
{
#if !defined(ADS_ANIMATIONS_ENABLED)
InternalContentData data = _fw->takeContent();
InternalContentData data;
_fw->takeContent(data);
_fw->deleteLater();
#if QT_VERSION >= 0x050000
_fw.clear();
#else
_fw = 0;
#endif
cw->dropContent(data, NULL, dropArea);
cw->dropContent(data, NULL, dropArea, true);
#else
#endif
}
@ -224,7 +226,12 @@ void SectionTitleWidget::mouseMoveEvent(QMouseEvent* ev)
&& !section->titleAreaGeometry().contains(section->mapFromGlobal(ev->globalPos())))
{
// Create floating widget.
InternalContentData data = section->take(_content->uid(), false);
InternalContentData data;
if (!section->take(_content->uid(), data))
{
qWarning() << "THIS SHOULD NOT HAPPEN!!" << _content->uid() << _content->uniqueName();
return;
}
_fw = new FloatingWidget(cw, data.content, data.titleWidget, data.contentWidget, cw);
_fw->resize(section->size());

View File

@ -145,10 +145,8 @@ void SectionWidget::addContent(const InternalContentData& data, bool autoActivat
// take removes a widget from the SectionWidget but does not delete
// the used SectionTitle- and SectionContent-Widget. Instead it returns
// these objects.
InternalContentData SectionWidget::take(int uid, bool del)
bool SectionWidget::take(int uid, InternalContentData& data)
{
InternalContentData data;
// Find SectionContent.
SectionContent::RefPtr sc;
int index = -1;
@ -160,6 +158,8 @@ InternalContentData SectionWidget::take(int uid, bool del)
sc = _contents.takeAt(i);
break;
}
if (!sc)
return false;
// Title wrapper widget (TAB)
SectionTitleWidget* title = _sectionTitles.takeAt(index);
@ -167,8 +167,8 @@ InternalContentData SectionWidget::take(int uid, bool del)
{
_tabsLayout->removeWidget(title);
title->disconnect(this);
if (del)
title->deleteLater();
// if (del)
// title->deleteLater();
}
// Content wrapper widget (CONTENT)
@ -177,8 +177,8 @@ InternalContentData SectionWidget::take(int uid, bool del)
{
_contentsLayout->removeWidget(content);
content->disconnect(this);
if (del)
content->deleteLater();
// if (del)
// content->deleteLater();
}
// Select the previous tab as activeTab.
@ -193,7 +193,7 @@ InternalContentData SectionWidget::take(int uid, bool del)
data.content = sc;
data.titleWidget = title;
data.contentWidget = content;
return data;
return !data.content.isNull();
}
int SectionWidget::indexOfContent(SectionContent::RefPtr c) const

View File

@ -46,9 +46,9 @@ static ADS_NS::SectionContent::RefPtr createCalendarSC()
static ADS_NS::SectionContent::RefPtr createFileSystemTreeSC()
{
QTreeView* w = new QTreeView();
// QFileSystemModel* m = new QFileSystemModel(w);
// m->setRootPath(QDir::currentPath());
// w->setModel(m);
// QFileSystemModel* m = new QFileSystemModel(w);
// m->setRootPath(QDir::currentPath());
// 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));
@ -91,31 +91,47 @@ MainWindow::MainWindow(QWidget *parent) :
QObject::connect(ui->actionAddSectionContent, SIGNAL(triggered(bool)), this, SLOT(onActionAddSectionContentTriggered()));
#endif
// CREATE SOME TESTING DOCKS
_container = new ADS_NS::ContainerWidget();
_container->setOrientation(Qt::Vertical);
setCentralWidget(_container);
ADS_NS::SectionWidget* section = NULL;
// Test #1: Use low-level API
// if (true)
// {
// ADS_NS::SectionWidget* section = NULL;
section = new ADS_NS::SectionWidget(_container);
section->addContent(createLongTextLabelSC());
_container->addSection(section);
// section = new ADS_NS::SectionWidget(_container);
// section->addContent(createLongTextLabelSC());
// _container->addSection(section);
section = new ADS_NS::SectionWidget(_container);
section->addContent(createCalendarSC());
_container->addSection(section);
// section = new ADS_NS::SectionWidget(_container);
// section->addContent(createCalendarSC());
// _container->addSection(section);
section = new ADS_NS::SectionWidget(_container);
section->addContent(createFileSystemTreeSC());
_container->addSection(section);
// section = new ADS_NS::SectionWidget(_container);
// section->addContent(createFileSystemTreeSC());
// _container->addSection(section);
section = new ADS_NS::SectionWidget(_container);
section->addContent(createCalendarSC());
_container->addSection(section);
// section = new ADS_NS::SectionWidget(_container);
// section->addContent(createCalendarSC());
// _container->addSection(section);
// }
restoreGeometry(loadDataHelper("MainWindow"));
_container->restoreState(loadDataHelper("ContainerWidget"));
// Test #2: 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());
}
// Default window geometry
resize(800, 600);
// Restore window geometry and ContainerWidget state from last session
// restoreGeometry(loadDataHelper("MainWindow"));
// _container->restoreState(loadDataHelper("ContainerWidget"));
}
MainWindow::~MainWindow()
@ -126,14 +142,6 @@ MainWindow::~MainWindow()
void MainWindow::onActionAddSectionContentTriggered()
{
return;
// auto titleWidget = new IconTitleWidget(QIcon(), QString("Title"));
// auto contentWidget = createRandomWidget(-1, -1);
// auto content = ADS_NS::SectionContent::newSectionContent(titleWidget, contentWidget);
// auto section = new ADS_NS::SectionWidget(_container);
// _container->addSection(section);
// section->addContent(content);
}
void MainWindow::contextMenuEvent(QContextMenuEvent* e)