2016-02-02 22:01:48 +08:00
|
|
|
#include "ads/SectionWidget.h"
|
2015-12-09 19:21:38 +08:00
|
|
|
|
|
|
|
#include <QApplication>
|
|
|
|
#include <QBoxLayout>
|
|
|
|
#include <QStackedLayout>
|
|
|
|
#include <QMouseEvent>
|
|
|
|
#include <QDragEnterEvent>
|
|
|
|
#include <QMimeData>
|
|
|
|
#include <QPainter>
|
|
|
|
#include <QStyle>
|
2016-02-12 15:00:31 +08:00
|
|
|
#include <QSplitter>
|
2016-02-18 22:06:00 +08:00
|
|
|
#include <QPushButton>
|
2015-12-09 19:21:38 +08:00
|
|
|
|
|
|
|
#if defined(ADS_ANIMATIONS_ENABLED)
|
|
|
|
#include <QGraphicsDropShadowEffect>
|
|
|
|
#endif
|
|
|
|
|
2016-02-12 15:00:31 +08:00
|
|
|
#include "ads/Internal.h"
|
2016-02-02 22:01:48 +08:00
|
|
|
#include "ads/DropOverlay.h"
|
|
|
|
#include "ads/SectionContent.h"
|
|
|
|
#include "ads/SectionTitleWidget.h"
|
|
|
|
#include "ads/SectionContentWidget.h"
|
|
|
|
#include "ads/FloatingWidget.h"
|
|
|
|
#include "ads/ContainerWidget.h"
|
2015-12-09 19:21:38 +08:00
|
|
|
|
|
|
|
ADS_NAMESPACE_BEGIN
|
|
|
|
|
2016-02-24 03:51:19 +08:00
|
|
|
//int SectionWidget::NextUid = 1;
|
|
|
|
//QHash<int, SectionWidget*> SectionWidget::LookupMap;
|
|
|
|
//QHash<ContainerWidget*, QHash<int, SectionWidget*> > SectionWidget::LookupMapByContainer;
|
2015-12-09 19:21:38 +08:00
|
|
|
|
|
|
|
SectionWidget::SectionWidget(ContainerWidget* parent) :
|
|
|
|
QFrame(parent),
|
2016-02-24 03:51:19 +08:00
|
|
|
_uid(GetNextUid()),
|
2016-02-18 22:06:00 +08:00
|
|
|
_container(parent),
|
|
|
|
_tabsLayout(NULL),
|
|
|
|
_contentsLayout(NULL),
|
|
|
|
_mousePressTitleWidget(NULL)
|
2015-12-09 19:21:38 +08:00
|
|
|
{
|
2016-02-12 14:15:10 +08:00
|
|
|
QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom);
|
2015-12-09 19:21:38 +08:00
|
|
|
l->setContentsMargins(0, 0, 0, 0);
|
|
|
|
l->setSpacing(0);
|
|
|
|
setLayout(l);
|
|
|
|
|
|
|
|
_tabsLayout = new QBoxLayout(QBoxLayout::LeftToRight);
|
|
|
|
_tabsLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
_tabsLayout->setSpacing(0);
|
|
|
|
_tabsLayout->addStretch(1);
|
|
|
|
l->addLayout(_tabsLayout);
|
|
|
|
|
2016-02-18 22:06:00 +08:00
|
|
|
QPushButton* closeButton = new QPushButton();
|
|
|
|
closeButton->setObjectName("closeButton");
|
|
|
|
closeButton->setFlat(true);
|
|
|
|
closeButton->setIcon(style()->standardIcon(QStyle::SP_TitleBarCloseButton));
|
|
|
|
closeButton->setToolTip(tr("Close"));
|
|
|
|
closeButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
|
|
_tabsLayout->addWidget(closeButton);
|
2016-04-11 13:27:02 +08:00
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
2016-02-18 22:06:00 +08:00
|
|
|
QObject::connect(closeButton, &QPushButton::clicked, this, &SectionWidget::onCloseButtonClicked);
|
|
|
|
#else
|
|
|
|
QObject::connect(closeButton, SIGNAL(clicked(bool)), this, SLOT(onCloseButtonClicked()));
|
|
|
|
#endif
|
|
|
|
|
2015-12-09 19:21:38 +08:00
|
|
|
_contentsLayout = new QStackedLayout();
|
|
|
|
_contentsLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
_contentsLayout->setSpacing(0);
|
|
|
|
l->addLayout(_contentsLayout, 1);
|
|
|
|
|
|
|
|
#if defined(ADS_ANIMATIONS_ENABLED)
|
2016-02-12 14:15:10 +08:00
|
|
|
QGraphicsDropShadowEffect* shadow = new QGraphicsDropShadowEffect(this);
|
2015-12-09 19:21:38 +08:00
|
|
|
shadow->setOffset(0, 0);
|
|
|
|
shadow->setBlurRadius(8);
|
|
|
|
setGraphicsEffect(shadow);
|
|
|
|
#endif
|
|
|
|
|
2016-02-26 19:43:14 +08:00
|
|
|
SWLookupMapById(_container).insert(_uid, this);
|
2015-12-09 19:21:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SectionWidget::~SectionWidget()
|
|
|
|
{
|
2016-02-26 19:43:14 +08:00
|
|
|
if (_container)
|
|
|
|
{
|
|
|
|
SWLookupMapById(_container).remove(_uid);
|
|
|
|
_container->_sections.removeAll(this); // Note: I don't like this here, but we have to remove it from list...
|
|
|
|
}
|
2015-12-09 19:21:38 +08:00
|
|
|
|
|
|
|
// Delete empty QSplitter.
|
2016-02-12 14:15:10 +08:00
|
|
|
QSplitter* splitter = findParentSplitter(this);
|
2015-12-09 19:21:38 +08:00
|
|
|
if (splitter && splitter->count() == 0)
|
|
|
|
{
|
|
|
|
splitter->deleteLater();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int SectionWidget::uid() const
|
|
|
|
{
|
|
|
|
return _uid;
|
|
|
|
}
|
|
|
|
|
2016-02-17 16:59:11 +08:00
|
|
|
ContainerWidget* SectionWidget::containerWidget() const
|
|
|
|
{
|
|
|
|
return _container;
|
|
|
|
}
|
|
|
|
|
2015-12-09 19:21:38 +08:00
|
|
|
QRect SectionWidget::titleAreaGeometry() const
|
|
|
|
{
|
|
|
|
return _tabsLayout->geometry();
|
|
|
|
}
|
|
|
|
|
|
|
|
QRect SectionWidget::contentAreaGeometry() const
|
|
|
|
{
|
|
|
|
return _contentsLayout->geometry();
|
|
|
|
}
|
|
|
|
|
2016-02-18 22:06:00 +08:00
|
|
|
void SectionWidget::addContent(const SectionContent::RefPtr& c)
|
2015-12-09 19:21:38 +08:00
|
|
|
{
|
|
|
|
_contents.append(c);
|
|
|
|
|
2016-02-12 14:15:10 +08:00
|
|
|
SectionTitleWidget* title = new SectionTitleWidget(c, NULL);
|
2015-12-09 19:21:38 +08:00
|
|
|
_sectionTitles.append(title);
|
2016-02-18 22:06:00 +08:00
|
|
|
_tabsLayout->insertWidget(_tabsLayout->count() - 2, title);
|
2016-04-11 13:27:02 +08:00
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
2015-12-09 19:21:38 +08:00
|
|
|
QObject::connect(title, &SectionTitleWidget::clicked, this, &SectionWidget::onSectionTitleClicked);
|
2016-02-12 15:00:31 +08:00
|
|
|
#else
|
|
|
|
QObject::connect(title, SIGNAL(clicked()), this, SLOT(onSectionTitleClicked()));
|
|
|
|
#endif
|
2015-12-09 19:21:38 +08:00
|
|
|
|
2016-02-12 14:15:10 +08:00
|
|
|
SectionContentWidget* content = new SectionContentWidget(c, NULL);
|
2015-12-09 19:21:38 +08:00
|
|
|
_sectionContents.append(content);
|
|
|
|
_contentsLayout->addWidget(content);
|
|
|
|
|
|
|
|
// Active first TAB.
|
|
|
|
if (_contents.size() == 1)
|
|
|
|
setCurrentIndex(0);
|
|
|
|
// Switch to newest.
|
|
|
|
// else
|
|
|
|
// setCurrentIndex(_contentsLayout->count() - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SectionWidget::addContent(const InternalContentData& data, bool autoActivate)
|
|
|
|
{
|
|
|
|
_contents.append(data.content);
|
|
|
|
|
2016-03-04 13:50:22 +08:00
|
|
|
// Add title-widget to tab-bar
|
|
|
|
// #FIX: Make it visible, since it is possible that it was hidden previously.
|
2015-12-09 19:21:38 +08:00
|
|
|
_sectionTitles.append(data.titleWidget);
|
2016-02-18 22:06:00 +08:00
|
|
|
_tabsLayout->insertWidget(_tabsLayout->count() - 2, data.titleWidget);
|
2016-03-04 13:50:22 +08:00
|
|
|
data.titleWidget->setVisible(true);
|
2016-04-11 13:27:02 +08:00
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
2015-12-09 19:21:38 +08:00
|
|
|
QObject::connect(data.titleWidget, &SectionTitleWidget::clicked, this, &SectionWidget::onSectionTitleClicked);
|
2016-02-12 15:00:31 +08:00
|
|
|
#else
|
|
|
|
QObject::connect(data.titleWidget, SIGNAL(clicked()), this, SLOT(onSectionTitleClicked()));
|
|
|
|
#endif
|
2015-12-09 19:21:38 +08:00
|
|
|
|
2016-03-04 13:50:22 +08:00
|
|
|
// Add content-widget to stack.
|
|
|
|
// Visibility is managed by QStackedWidget.
|
2015-12-09 19:21:38 +08:00
|
|
|
_sectionContents.append(data.contentWidget);
|
|
|
|
_contentsLayout->addWidget(data.contentWidget);
|
|
|
|
|
2016-03-04 13:50:22 +08:00
|
|
|
// Activate first TAB.
|
2015-12-09 19:21:38 +08:00
|
|
|
if (_contents.size() == 1)
|
|
|
|
setCurrentIndex(0);
|
2016-03-04 13:50:22 +08:00
|
|
|
// Switch to just added TAB.
|
2015-12-09 19:21:38 +08:00
|
|
|
else if (autoActivate)
|
2016-02-18 22:06:00 +08:00
|
|
|
setCurrentIndex(_contents.count() - 1);
|
2016-03-04 13:50:22 +08:00
|
|
|
// Mark it as inactive tab.
|
2016-02-19 19:00:39 +08:00
|
|
|
else
|
|
|
|
data.titleWidget->setActiveTab(false); // or: setCurrentIndex(currentIndex())
|
2015-12-09 19:21:38 +08:00
|
|
|
}
|
|
|
|
|
2016-02-15 18:13:58 +08:00
|
|
|
bool SectionWidget::takeContent(int uid, InternalContentData& data)
|
2015-12-09 19:21:38 +08:00
|
|
|
{
|
|
|
|
// Find SectionContent.
|
|
|
|
SectionContent::RefPtr sc;
|
|
|
|
int index = -1;
|
|
|
|
for (int i = 0; i < _contents.count(); i++)
|
|
|
|
{
|
|
|
|
if (_contents[i]->uid() != uid)
|
|
|
|
continue;
|
|
|
|
index = i;
|
|
|
|
sc = _contents.takeAt(i);
|
|
|
|
break;
|
|
|
|
}
|
2016-02-15 17:28:42 +08:00
|
|
|
if (!sc)
|
|
|
|
return false;
|
2015-12-09 19:21:38 +08:00
|
|
|
|
|
|
|
// Title wrapper widget (TAB)
|
2016-02-12 14:15:10 +08:00
|
|
|
SectionTitleWidget* title = _sectionTitles.takeAt(index);
|
2015-12-09 19:21:38 +08:00
|
|
|
if (title)
|
|
|
|
{
|
|
|
|
_tabsLayout->removeWidget(title);
|
|
|
|
title->disconnect(this);
|
2016-02-18 22:06:00 +08:00
|
|
|
title->setParent(_container);
|
2015-12-09 19:21:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Content wrapper widget (CONTENT)
|
2016-02-12 14:15:10 +08:00
|
|
|
SectionContentWidget* content = _sectionContents.takeAt(index);
|
2015-12-09 19:21:38 +08:00
|
|
|
if (content)
|
|
|
|
{
|
|
|
|
_contentsLayout->removeWidget(content);
|
|
|
|
content->disconnect(this);
|
2016-02-18 22:06:00 +08:00
|
|
|
content->setParent(_container);
|
2015-12-09 19:21:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Select the previous tab as activeTab.
|
|
|
|
if (_contents.size() > 0 && title->isActiveTab())
|
|
|
|
{
|
|
|
|
if (index > 0)
|
|
|
|
setCurrentIndex(index - 1);
|
|
|
|
else
|
|
|
|
setCurrentIndex(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
data.content = sc;
|
|
|
|
data.titleWidget = title;
|
|
|
|
data.contentWidget = content;
|
2016-02-15 17:28:42 +08:00
|
|
|
return !data.content.isNull();
|
2015-12-09 19:21:38 +08:00
|
|
|
}
|
|
|
|
|
2016-02-18 22:06:00 +08:00
|
|
|
int SectionWidget::indexOfContent(const SectionContent::RefPtr& c) const
|
2016-02-02 15:24:12 +08:00
|
|
|
{
|
|
|
|
return _contents.indexOf(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
int SectionWidget::indexOfContentByTitlePos(const QPoint& p, QWidget* exclude) const
|
|
|
|
{
|
|
|
|
int index = -1;
|
|
|
|
for (int i = 0; i < _sectionTitles.size(); ++i)
|
|
|
|
{
|
|
|
|
if (_sectionTitles[i]->geometry().contains(p) && (exclude == NULL || _sectionTitles[i] != exclude))
|
|
|
|
{
|
|
|
|
index = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
2016-02-11 21:51:38 +08:00
|
|
|
int SectionWidget::currentIndex() const
|
|
|
|
{
|
|
|
|
return _contentsLayout->currentIndex();
|
|
|
|
}
|
|
|
|
|
2016-02-02 15:24:12 +08:00
|
|
|
void SectionWidget::moveContent(int from, int to)
|
|
|
|
{
|
|
|
|
if (from >= _contents.size() || from < 0 || to >= _contents.size() || to < 0 || from == to)
|
|
|
|
{
|
|
|
|
qCritical() << "Invalid index for tab movement" << from << to;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SectionContent::RefPtr sc = _contents.at(from);
|
|
|
|
_contents.move(from, to);
|
|
|
|
_sectionTitles.move(from, to);
|
|
|
|
_sectionContents.move(from, to);
|
|
|
|
|
|
|
|
QLayoutItem* liFrom = NULL;
|
|
|
|
|
|
|
|
liFrom = _tabsLayout->takeAt(from);
|
2016-04-11 13:27:02 +08:00
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
2016-02-02 15:24:12 +08:00
|
|
|
_tabsLayout->insertItem(to, liFrom);
|
2016-02-12 15:00:31 +08:00
|
|
|
#else
|
|
|
|
_tabsLayout->insertWidget(to, liFrom->widget());
|
|
|
|
delete liFrom;
|
|
|
|
liFrom = NULL;
|
|
|
|
#endif
|
2016-02-02 15:24:12 +08:00
|
|
|
|
|
|
|
liFrom = _contentsLayout->takeAt(from);
|
|
|
|
_contentsLayout->insertWidget(to, liFrom->widget());
|
|
|
|
delete liFrom;
|
|
|
|
}
|
|
|
|
|
2015-12-09 19:21:38 +08:00
|
|
|
void SectionWidget::setCurrentIndex(int index)
|
|
|
|
{
|
2016-02-19 19:00:39 +08:00
|
|
|
if (index < 0 || index > _contents.count() - 1)
|
|
|
|
{
|
|
|
|
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set active TAB
|
2015-12-09 19:21:38 +08:00
|
|
|
for (int i = 0; i < _tabsLayout->count(); ++i)
|
|
|
|
{
|
2016-02-12 14:15:10 +08:00
|
|
|
QLayoutItem* item = _tabsLayout->itemAt(i);
|
2015-12-09 19:21:38 +08:00
|
|
|
if (item->widget())
|
|
|
|
{
|
2016-02-12 14:15:10 +08:00
|
|
|
SectionTitleWidget* stw = dynamic_cast<SectionTitleWidget*>(item->widget());
|
2016-02-18 22:06:00 +08:00
|
|
|
if (stw)
|
|
|
|
{
|
|
|
|
if (i == index)
|
|
|
|
stw->setActiveTab(true);
|
|
|
|
else
|
|
|
|
stw->setActiveTab(false);
|
|
|
|
}
|
2015-12-09 19:21:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-19 19:00:39 +08:00
|
|
|
// Set active CONTENT
|
2015-12-09 19:21:38 +08:00
|
|
|
_contentsLayout->setCurrentIndex(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SectionWidget::onSectionTitleClicked()
|
|
|
|
{
|
2016-02-12 14:15:10 +08:00
|
|
|
SectionTitleWidget* stw = qobject_cast<SectionTitleWidget*>(sender());
|
2015-12-09 19:21:38 +08:00
|
|
|
if (stw)
|
|
|
|
{
|
2016-02-12 14:15:10 +08:00
|
|
|
int index = _tabsLayout->indexOf(stw);
|
2015-12-09 19:21:38 +08:00
|
|
|
setCurrentIndex(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-18 22:06:00 +08:00
|
|
|
void SectionWidget::onCloseButtonClicked()
|
|
|
|
{
|
|
|
|
const int index = currentIndex();
|
|
|
|
if (index < 0 || index > _contents.size() - 1)
|
|
|
|
return;
|
|
|
|
SectionContent::RefPtr sc = _contents.at(index);
|
|
|
|
if (sc.isNull())
|
|
|
|
return;
|
|
|
|
_container->hideSectionContent(sc);
|
|
|
|
}
|
|
|
|
|
2016-02-24 03:51:19 +08:00
|
|
|
int SectionWidget::GetNextUid()
|
|
|
|
{
|
|
|
|
static int NextUid = 0;
|
|
|
|
return ++NextUid;
|
|
|
|
}
|
|
|
|
|
2016-02-26 19:43:14 +08:00
|
|
|
//QHash<int, SectionWidget*>& SectionWidget::GetLookupMap()
|
|
|
|
//{
|
|
|
|
// static QHash<int, SectionWidget*> LookupMap;
|
|
|
|
// return LookupMap;
|
2016-02-24 03:51:19 +08:00
|
|
|
|
2016-02-26 19:43:14 +08:00
|
|
|
//}
|
2016-02-24 03:51:19 +08:00
|
|
|
|
2016-02-26 19:43:14 +08:00
|
|
|
//QHash<ContainerWidget*, QHash<int, SectionWidget*> >& SectionWidget::GetLookupMapByContainer()
|
|
|
|
//{
|
|
|
|
// static QHash<ContainerWidget*, QHash<int, SectionWidget*> > LookupMapByContainer;
|
|
|
|
// return LookupMapByContainer;
|
|
|
|
//}
|
2016-02-24 03:51:19 +08:00
|
|
|
|
2016-02-12 14:15:10 +08:00
|
|
|
ADS_NAMESPACE_END
|