Qt-Advanced-Docking-System/AdvancedDockingSystem/src/SectionWidget.cpp

343 lines
8.8 KiB
C++

#include "ads/SectionWidget.h"
#include <QApplication>
#include <QBoxLayout>
#include <QStackedLayout>
#include <QMouseEvent>
#include <QDragEnterEvent>
#include <QMimeData>
#include <QPainter>
#include <QStyle>
#include <QSplitter>
#include <QPushButton>
#if defined(ADS_ANIMATIONS_ENABLED)
#include <QGraphicsDropShadowEffect>
#endif
#include "ads/Internal.h"
#include "ads/DropOverlay.h"
#include "ads/SectionContent.h"
#include "ads/SectionTitleWidget.h"
#include "ads/SectionContentWidget.h"
#include "ads/FloatingWidget.h"
#include "ads/ContainerWidget.h"
ADS_NAMESPACE_BEGIN
//int SectionWidget::NextUid = 1;
//QHash<int, SectionWidget*> SectionWidget::LookupMap;
//QHash<ContainerWidget*, QHash<int, SectionWidget*> > SectionWidget::LookupMapByContainer;
SectionWidget::SectionWidget(ContainerWidget* parent) :
QFrame(parent),
_uid(GetNextUid()),
_container(parent),
_tabsLayout(NULL),
_contentsLayout(NULL),
_mousePressTitleWidget(NULL)
{
QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom);
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);
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);
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
QObject::connect(closeButton, &QPushButton::clicked, this, &SectionWidget::onCloseButtonClicked);
#else
QObject::connect(closeButton, SIGNAL(clicked(bool)), this, SLOT(onCloseButtonClicked()));
#endif
_contentsLayout = new QStackedLayout();
_contentsLayout->setContentsMargins(0, 0, 0, 0);
_contentsLayout->setSpacing(0);
l->addLayout(_contentsLayout, 1);
#if defined(ADS_ANIMATIONS_ENABLED)
QGraphicsDropShadowEffect* shadow = new QGraphicsDropShadowEffect(this);
shadow->setOffset(0, 0);
shadow->setBlurRadius(8);
setGraphicsEffect(shadow);
#endif
SWLookupMapById(_container).insert(_uid, this);
}
SectionWidget::~SectionWidget()
{
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...
}
// Delete empty QSplitter.
QSplitter* splitter = findParentSplitter(this);
if (splitter && splitter->count() == 0)
{
splitter->deleteLater();
}
}
int SectionWidget::uid() const
{
return _uid;
}
ContainerWidget* SectionWidget::containerWidget() const
{
return _container;
}
QRect SectionWidget::titleAreaGeometry() const
{
return _tabsLayout->geometry();
}
QRect SectionWidget::contentAreaGeometry() const
{
return _contentsLayout->geometry();
}
void SectionWidget::addContent(const SectionContent::RefPtr& c)
{
_contents.append(c);
SectionTitleWidget* title = new SectionTitleWidget(c, NULL);
_sectionTitles.append(title);
_tabsLayout->insertWidget(_tabsLayout->count() - 2, title);
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
QObject::connect(title, &SectionTitleWidget::clicked, this, &SectionWidget::onSectionTitleClicked);
#else
QObject::connect(title, SIGNAL(clicked()), this, SLOT(onSectionTitleClicked()));
#endif
SectionContentWidget* content = new SectionContentWidget(c, NULL);
_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);
// Add title-widget to tab-bar
// #FIX: Make it visible, since it is possible that it was hidden previously.
_sectionTitles.append(data.titleWidget);
_tabsLayout->insertWidget(_tabsLayout->count() - 2, data.titleWidget);
data.titleWidget->setVisible(true);
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
QObject::connect(data.titleWidget, &SectionTitleWidget::clicked, this, &SectionWidget::onSectionTitleClicked);
#else
QObject::connect(data.titleWidget, SIGNAL(clicked()), this, SLOT(onSectionTitleClicked()));
#endif
// Add content-widget to stack.
// Visibility is managed by QStackedWidget.
_sectionContents.append(data.contentWidget);
_contentsLayout->addWidget(data.contentWidget);
// Activate first TAB.
if (_contents.size() == 1)
setCurrentIndex(0);
// Switch to just added TAB.
else if (autoActivate)
setCurrentIndex(_contents.count() - 1);
// Mark it as inactive tab.
else
data.titleWidget->setActiveTab(false); // or: setCurrentIndex(currentIndex())
}
bool SectionWidget::takeContent(int uid, InternalContentData& data)
{
// 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;
}
if (!sc)
return false;
// Title wrapper widget (TAB)
SectionTitleWidget* title = _sectionTitles.takeAt(index);
if (title)
{
_tabsLayout->removeWidget(title);
title->disconnect(this);
title->setParent(_container);
}
// Content wrapper widget (CONTENT)
SectionContentWidget* content = _sectionContents.takeAt(index);
if (content)
{
_contentsLayout->removeWidget(content);
content->disconnect(this);
content->setParent(_container);
}
// 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;
return !data.content.isNull();
}
int SectionWidget::indexOfContent(const SectionContent::RefPtr& c) const
{
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;
}
int SectionWidget::currentIndex() const
{
return _contentsLayout->currentIndex();
}
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);
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
_tabsLayout->insertItem(to, liFrom);
#else
_tabsLayout->insertWidget(to, liFrom->widget());
delete liFrom;
liFrom = NULL;
#endif
liFrom = _contentsLayout->takeAt(from);
_contentsLayout->insertWidget(to, liFrom->widget());
delete liFrom;
}
void SectionWidget::setCurrentIndex(int index)
{
if (index < 0 || index > _contents.count() - 1)
{
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
return;
}
// Set active TAB
for (int i = 0; i < _tabsLayout->count(); ++i)
{
QLayoutItem* item = _tabsLayout->itemAt(i);
if (item->widget())
{
SectionTitleWidget* stw = dynamic_cast<SectionTitleWidget*>(item->widget());
if (stw)
{
if (i == index)
stw->setActiveTab(true);
else
stw->setActiveTab(false);
}
}
}
// Set active CONTENT
_contentsLayout->setCurrentIndex(index);
}
void SectionWidget::onSectionTitleClicked()
{
SectionTitleWidget* stw = qobject_cast<SectionTitleWidget*>(sender());
if (stw)
{
int index = _tabsLayout->indexOf(stw);
setCurrentIndex(index);
}
}
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);
}
int SectionWidget::GetNextUid()
{
static int NextUid = 0;
return ++NextUid;
}
//QHash<int, SectionWidget*>& SectionWidget::GetLookupMap()
//{
// static QHash<int, SectionWidget*> LookupMap;
// return LookupMap;
//}
//QHash<ContainerWidget*, QHash<int, SectionWidget*> >& SectionWidget::GetLookupMapByContainer()
//{
// static QHash<ContainerWidget*, QHash<int, SectionWidget*> > LookupMapByContainer;
// return LookupMapByContainer;
//}
ADS_NAMESPACE_END