2017-03-23 17:23:53 +08:00
|
|
|
/*******************************************************************************
|
2017-06-10 04:04:02 +08:00
|
|
|
** Qt Advanced Docking System
|
2017-03-23 17:23:53 +08:00
|
|
|
** Copyright (C) 2017 Uwe Kindler
|
2017-06-10 04:04:02 +08:00
|
|
|
**
|
|
|
|
** This library is free software; you can redistribute it and/or
|
|
|
|
** modify it under the terms of the GNU Lesser General Public
|
|
|
|
** License as published by the Free Software Foundation; either
|
|
|
|
** version 2.1 of the License, or (at your option) any later version.
|
|
|
|
**
|
|
|
|
** This library is distributed in the hope that it will be useful,
|
2017-03-23 17:23:53 +08:00
|
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2017-06-10 04:04:02 +08:00
|
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
** Lesser General Public License for more details.
|
|
|
|
**
|
|
|
|
** You should have received a copy of the GNU Lesser General Public
|
|
|
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
2017-03-23 17:23:53 +08:00
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
/// \file DockAreaWidget.cpp
|
|
|
|
/// \author Uwe Kindler
|
|
|
|
/// \date 24.02.2017
|
|
|
|
/// \brief Implementation of CDockAreaWidget class
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
// INCLUDES
|
|
|
|
//============================================================================
|
2018-08-24 19:41:58 +08:00
|
|
|
#include <DockWidgetTab.h>
|
2017-03-23 17:23:53 +08:00
|
|
|
#include "DockAreaWidget.h"
|
|
|
|
|
|
|
|
#include <QStackedLayout>
|
|
|
|
#include <QScrollBar>
|
|
|
|
#include <QScrollArea>
|
|
|
|
#include <QWheelEvent>
|
|
|
|
#include <QStyle>
|
|
|
|
#include <QPushButton>
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QMenu>
|
|
|
|
#include <QSplitter>
|
2017-12-30 01:18:16 +08:00
|
|
|
#include <QXmlStreamWriter>
|
2018-09-07 17:10:14 +08:00
|
|
|
#include <QVector>
|
2018-10-10 21:15:59 +08:00
|
|
|
#include <QList>
|
|
|
|
|
2017-03-23 17:23:53 +08:00
|
|
|
|
|
|
|
#include "DockContainerWidget.h"
|
|
|
|
#include "DockWidget.h"
|
|
|
|
#include "FloatingDockContainer.h"
|
|
|
|
#include "DockManager.h"
|
|
|
|
#include "DockOverlay.h"
|
2018-08-24 19:41:58 +08:00
|
|
|
#include "DockAreaTabBar.h"
|
2018-09-14 14:46:10 +08:00
|
|
|
#include "DockSplitter.h"
|
2017-03-23 17:23:53 +08:00
|
|
|
|
2018-10-10 21:15:59 +08:00
|
|
|
#include <iostream>
|
|
|
|
|
2017-03-23 17:23:53 +08:00
|
|
|
|
|
|
|
namespace ads
|
|
|
|
{
|
|
|
|
static const char* const INDEX_PROPERTY = "index";
|
|
|
|
static const char* const ACTION_PROPERTY = "action";
|
2018-09-07 17:10:14 +08:00
|
|
|
static const char* const DOCKWIDGET_PROPERTY = "dockwidget";
|
2017-03-23 17:23:53 +08:00
|
|
|
static const int APPEND = -1;
|
|
|
|
|
|
|
|
|
2018-10-10 21:15:59 +08:00
|
|
|
/**
|
|
|
|
* Default stack area layout
|
|
|
|
*/
|
|
|
|
class CStackedDockAreaLayout
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
QStackedLayout* Layout;
|
|
|
|
|
|
|
|
public:
|
|
|
|
CStackedDockAreaLayout(QBoxLayout* ParentLayout)
|
|
|
|
{
|
|
|
|
Layout = new QStackedLayout();
|
|
|
|
Layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
Layout->setSpacing(0);
|
|
|
|
Layout->setSizeConstraint(QLayout::SetNoConstraint);
|
|
|
|
ParentLayout->addLayout(Layout, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int count() const
|
|
|
|
{
|
|
|
|
return Layout->count();
|
|
|
|
}
|
|
|
|
|
|
|
|
void insertWidget(int index, QWidget* Widget)
|
|
|
|
{
|
|
|
|
Layout->insertWidget(index, Widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
void removeWidget(QWidget* Widget)
|
|
|
|
{
|
|
|
|
Layout->removeWidget(Widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
void setCurrentIndex(int Index)
|
|
|
|
{
|
|
|
|
Layout->setCurrentIndex(Index);
|
|
|
|
}
|
|
|
|
|
|
|
|
int currentIndex() const
|
|
|
|
{
|
|
|
|
return Layout->currentIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
QWidget* currentWidget() const
|
|
|
|
{
|
|
|
|
return Layout->currentWidget();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isEmpty() const
|
|
|
|
{
|
|
|
|
return Layout->isEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
int indexOf(QWidget* w) const
|
|
|
|
{
|
|
|
|
return Layout->indexOf(w);
|
|
|
|
}
|
|
|
|
|
|
|
|
QWidget* widget(int index) const
|
|
|
|
{
|
|
|
|
return Layout->widget(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
QRect geometry() const
|
|
|
|
{
|
|
|
|
return Layout->geometry();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* New dock area layout
|
|
|
|
*/
|
|
|
|
class CDockAreaLayout
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
QBoxLayout* m_ParentLayout;
|
|
|
|
QList<QWidget*> m_Widgets;
|
|
|
|
int m_CurrentIndex = -1;
|
|
|
|
QWidget* m_CurrentWidget = nullptr;
|
|
|
|
|
|
|
|
public:
|
|
|
|
CDockAreaLayout(QBoxLayout* ParentLayout)
|
|
|
|
: m_ParentLayout(ParentLayout)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int count() const
|
|
|
|
{
|
|
|
|
return m_Widgets.count();
|
|
|
|
}
|
|
|
|
|
|
|
|
void insertWidget(int index, QWidget* Widget)
|
|
|
|
{
|
2018-10-11 16:55:36 +08:00
|
|
|
Widget->setParent(0);
|
2018-10-10 21:15:59 +08:00
|
|
|
if (index < 0)
|
|
|
|
{
|
|
|
|
index = m_Widgets.count();
|
|
|
|
}
|
|
|
|
m_Widgets.insert(index, Widget);
|
|
|
|
if (m_CurrentIndex < 0)
|
|
|
|
{
|
|
|
|
setCurrentIndex(index);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (index <= m_CurrentIndex )
|
|
|
|
{
|
|
|
|
++m_CurrentIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void removeWidget(QWidget* Widget)
|
|
|
|
{
|
|
|
|
if (currentWidget() == Widget)
|
|
|
|
{
|
|
|
|
auto LayoutItem = m_ParentLayout->takeAt(1);
|
|
|
|
if (LayoutItem)
|
|
|
|
{
|
|
|
|
LayoutItem->widget()->setParent(0);
|
|
|
|
}
|
2018-10-12 17:51:35 +08:00
|
|
|
m_CurrentWidget = nullptr;
|
|
|
|
m_CurrentIndex = -1;
|
2018-10-10 21:15:59 +08:00
|
|
|
}
|
|
|
|
m_Widgets.removeOne(Widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
QWidget* currentWidget() const
|
|
|
|
{
|
|
|
|
return m_CurrentWidget;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setCurrentIndex(int index)
|
|
|
|
{
|
2018-10-11 19:07:27 +08:00
|
|
|
std::cout << "CDockAreaLayout::setCurrentIndex " << index << std::endl;
|
2018-10-10 21:15:59 +08:00
|
|
|
QWidget *prev = currentWidget();
|
|
|
|
QWidget *next = widget(index);
|
|
|
|
if (!next || (next == prev && !m_CurrentWidget))
|
|
|
|
{
|
2018-10-11 19:07:27 +08:00
|
|
|
std::cout << "return" << std::endl;
|
2018-10-10 21:15:59 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool reenableUpdates = false;
|
|
|
|
QWidget *parent = m_ParentLayout->parentWidget();
|
|
|
|
|
|
|
|
if (parent && parent->updatesEnabled())
|
|
|
|
{
|
|
|
|
reenableUpdates = true;
|
|
|
|
parent->setUpdatesEnabled(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << "m_ParentLayout->addWidget(next)" << std::endl;
|
|
|
|
auto LayoutItem = m_ParentLayout->takeAt(1);
|
|
|
|
if (LayoutItem)
|
|
|
|
{
|
|
|
|
LayoutItem->widget()->setParent(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_ParentLayout->addWidget(next);
|
|
|
|
if (prev)
|
|
|
|
{
|
|
|
|
prev->hide();
|
|
|
|
}
|
|
|
|
m_CurrentIndex = index;
|
|
|
|
m_CurrentWidget = next;
|
|
|
|
|
|
|
|
|
|
|
|
if (reenableUpdates)
|
|
|
|
{
|
|
|
|
parent->setUpdatesEnabled(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int currentIndex() const
|
|
|
|
{
|
|
|
|
return m_CurrentIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isEmpty() const
|
|
|
|
{
|
|
|
|
return m_Widgets.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
int indexOf(QWidget* w) const
|
|
|
|
{
|
|
|
|
return m_Widgets.indexOf(w);
|
|
|
|
}
|
|
|
|
|
|
|
|
QWidget* widget(int index) const
|
|
|
|
{
|
|
|
|
return (index < m_Widgets.size()) ? m_Widgets.at(index) : nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
QRect geometry() const
|
|
|
|
{
|
|
|
|
return m_Widgets.empty() ? QRect() : currentWidget()->geometry();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using DockAreaLayout = CDockAreaLayout;
|
|
|
|
|
|
|
|
|
2017-03-23 17:23:53 +08:00
|
|
|
/**
|
|
|
|
* Private data class of CDockAreaWidget class (pimpl)
|
|
|
|
*/
|
|
|
|
struct DockAreaWidgetPrivate
|
|
|
|
{
|
|
|
|
CDockAreaWidget* _this;
|
|
|
|
QBoxLayout* Layout;
|
|
|
|
QFrame* TitleBar;
|
|
|
|
QBoxLayout* TopLayout;
|
2018-10-10 21:15:59 +08:00
|
|
|
DockAreaLayout* ContentsLayout;
|
2018-08-24 19:41:58 +08:00
|
|
|
CDockAreaTabBar* TabBar;
|
2017-03-23 17:23:53 +08:00
|
|
|
QPushButton* TabsMenuButton;
|
|
|
|
QPushButton* CloseButton;
|
2018-10-10 21:15:59 +08:00
|
|
|
//int TabsLayoutInitCount;
|
2017-03-23 17:23:53 +08:00
|
|
|
CDockManager* DockManager = nullptr;
|
2018-09-07 17:10:14 +08:00
|
|
|
bool MenuOutdated = true;
|
2017-03-23 17:23:53 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Private data constructor
|
|
|
|
*/
|
|
|
|
DockAreaWidgetPrivate(CDockAreaWidget* _public);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates the layout for top area with tabs and close button
|
|
|
|
*/
|
|
|
|
void createTabBar();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the dock widget with the given index
|
|
|
|
*/
|
|
|
|
CDockWidget* dockWidgetAt(int index)
|
|
|
|
{
|
|
|
|
return dynamic_cast<CDockWidget*>(ContentsLayout->widget(index));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Convenience function to ease title widget access by index
|
|
|
|
*/
|
2018-09-07 18:56:20 +08:00
|
|
|
CDockWidgetTab* tabWidgetAt(int index)
|
2017-03-23 17:23:53 +08:00
|
|
|
{
|
2018-09-07 17:10:14 +08:00
|
|
|
return dockWidgetAt(index)->tabWidget();
|
2017-03-23 17:23:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds a tabs menu entry for the given dock widget
|
|
|
|
* If menu is 0, a menu entry is added to the menu of the TabsMenuButton
|
|
|
|
* member. If menu is a valid menu pointer, the entry will be added to
|
|
|
|
* the given menu
|
|
|
|
*/
|
|
|
|
void addTabsMenuEntry(CDockWidget* DockWidget, int Index = -1, QMenu* menu = 0);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the tab action of the given dock widget
|
|
|
|
*/
|
|
|
|
QAction* dockWidgetTabAction(CDockWidget* DockWidget) const
|
|
|
|
{
|
|
|
|
return qvariant_cast<QAction*>(DockWidget->property(ACTION_PROPERTY));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the index of the given dock widget
|
|
|
|
*/
|
|
|
|
int dockWidgetIndex(CDockWidget* DockWidget) const
|
|
|
|
{
|
|
|
|
return DockWidget->property(INDEX_PROPERTY).toInt();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update the tabs menu if dock widget order changed or if dock widget has
|
|
|
|
* been removed
|
|
|
|
*/
|
2018-09-07 17:10:14 +08:00
|
|
|
void markTabsMenuOutdated();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates the tabs menu if it is outdated
|
|
|
|
*/
|
2017-03-23 17:23:53 +08:00
|
|
|
void updateTabsMenu();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates the tab bar visibility depending on the number of dock widgets
|
|
|
|
* in this area
|
|
|
|
*/
|
|
|
|
void updateTabBar();
|
|
|
|
};
|
|
|
|
// struct DockAreaWidgetPrivate
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
DockAreaWidgetPrivate::DockAreaWidgetPrivate(CDockAreaWidget* _public) :
|
|
|
|
_this(_public)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void DockAreaWidgetPrivate::createTabBar()
|
|
|
|
{
|
|
|
|
TitleBar = new QFrame(_this);
|
|
|
|
TitleBar->setObjectName("dockAreaTitleBar");
|
|
|
|
TopLayout = new QBoxLayout(QBoxLayout::LeftToRight);
|
|
|
|
TopLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
TopLayout->setSpacing(0);
|
|
|
|
TitleBar->setLayout(TopLayout);
|
|
|
|
Layout->addWidget(TitleBar);
|
2018-10-10 21:15:59 +08:00
|
|
|
TitleBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
2017-03-23 17:23:53 +08:00
|
|
|
|
2018-08-24 19:41:58 +08:00
|
|
|
TabBar = new CDockAreaTabBar(_this);
|
|
|
|
TopLayout->addWidget(TabBar, 1);
|
2018-10-12 17:51:35 +08:00
|
|
|
_this->connect(TabBar, SIGNAL(currentChanged(int)), SLOT(setCurrentIndex(int)));
|
2018-10-12 15:17:14 +08:00
|
|
|
_this->connect(TabBar, SIGNAL(tabMoved(int, int)), SLOT(reorderDockWidget(int, int)));
|
2017-03-23 17:23:53 +08:00
|
|
|
|
|
|
|
TabsMenuButton = new QPushButton();
|
|
|
|
TabsMenuButton->setObjectName("tabsMenuButton");
|
|
|
|
TabsMenuButton->setFlat(true);
|
|
|
|
TabsMenuButton->setIcon(_this->style()->standardIcon(QStyle::SP_TitleBarUnshadeButton));
|
|
|
|
TabsMenuButton->setMaximumWidth(TabsMenuButton->iconSize().width());
|
2018-09-07 17:10:14 +08:00
|
|
|
QMenu* TabsMenu = new QMenu(TabsMenuButton);
|
|
|
|
_this->connect(TabsMenu, SIGNAL(aboutToShow()), SLOT(onTabsMenuAboutToShow()));
|
|
|
|
TabsMenuButton->setMenu(TabsMenu);
|
2017-03-23 17:23:53 +08:00
|
|
|
TopLayout->addWidget(TabsMenuButton, 0);
|
2018-08-28 19:25:44 +08:00
|
|
|
TabsMenuButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
2017-03-23 17:23:53 +08:00
|
|
|
_this->connect(TabsMenuButton->menu(), SIGNAL(triggered(QAction*)),
|
|
|
|
SLOT(onTabsMenuActionTriggered(QAction*)));
|
|
|
|
|
|
|
|
CloseButton = new QPushButton();
|
|
|
|
CloseButton->setObjectName("closeButton");
|
|
|
|
CloseButton->setFlat(true);
|
|
|
|
CloseButton->setIcon(_this->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
|
|
|
|
CloseButton->setToolTip(_this->tr("Close"));
|
|
|
|
CloseButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
|
|
TopLayout->addWidget(CloseButton, 0);
|
|
|
|
_this->connect(CloseButton, SIGNAL(clicked()), SLOT(onCloseButtonClicked()));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void DockAreaWidgetPrivate::updateTabBar()
|
|
|
|
{
|
|
|
|
CDockContainerWidget* Container = _this->dockContainer();
|
|
|
|
if (!Container)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-09-26 15:57:36 +08:00
|
|
|
TitleBar->setVisible(!Container->isFloating() || !Container->hasTopLevelDockWidget());
|
2017-03-23 17:23:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void DockAreaWidgetPrivate::addTabsMenuEntry(CDockWidget* DockWidget,
|
|
|
|
int Index, QMenu* menu)
|
|
|
|
{
|
|
|
|
menu = menu ? menu : TabsMenuButton->menu();
|
|
|
|
QAction* Action;
|
|
|
|
if (Index >= 0 && Index < menu->actions().count())
|
|
|
|
{
|
2018-08-27 21:40:01 +08:00
|
|
|
Action = new QAction(DockWidget->icon(), DockWidget->windowTitle());
|
2017-03-23 17:23:53 +08:00
|
|
|
menu->insertAction(menu->actions().at(Index), Action);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-08-27 21:40:01 +08:00
|
|
|
Action = menu->addAction(DockWidget->icon(), DockWidget->windowTitle());
|
2017-03-23 17:23:53 +08:00
|
|
|
}
|
2018-09-07 17:10:14 +08:00
|
|
|
Action->setProperty(DOCKWIDGET_PROPERTY, QVariant::fromValue(DockWidget));
|
2017-03-23 17:23:53 +08:00
|
|
|
QVariant vAction = QVariant::fromValue(Action);
|
|
|
|
DockWidget->setProperty(ACTION_PROPERTY, vAction);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-07 17:10:14 +08:00
|
|
|
//============================================================================
|
|
|
|
void DockAreaWidgetPrivate::markTabsMenuOutdated()
|
|
|
|
{
|
|
|
|
MenuOutdated = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-23 17:23:53 +08:00
|
|
|
//============================================================================
|
|
|
|
void DockAreaWidgetPrivate::updateTabsMenu()
|
|
|
|
{
|
2018-09-07 17:10:14 +08:00
|
|
|
if (!MenuOutdated)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-23 17:23:53 +08:00
|
|
|
QMenu* menu = TabsMenuButton->menu();
|
|
|
|
menu->clear();
|
|
|
|
for (int i = 0; i < ContentsLayout->count(); ++i)
|
|
|
|
{
|
2018-09-07 17:10:14 +08:00
|
|
|
if (dockWidgetAt(i)->isClosed())
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2017-03-23 17:23:53 +08:00
|
|
|
addTabsMenuEntry(dockWidgetAt(i), APPEND, menu);
|
|
|
|
}
|
2018-09-07 17:10:14 +08:00
|
|
|
|
|
|
|
MenuOutdated = false;
|
2017-03-23 17:23:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
CDockAreaWidget::CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget* parent) :
|
|
|
|
QFrame(parent),
|
|
|
|
d(new DockAreaWidgetPrivate(this))
|
|
|
|
{
|
|
|
|
d->DockManager = DockManager;
|
|
|
|
d->Layout = new QBoxLayout(QBoxLayout::TopToBottom);
|
|
|
|
d->Layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
d->Layout->setSpacing(0);
|
|
|
|
setLayout(d->Layout);
|
|
|
|
|
|
|
|
d->createTabBar();
|
2018-10-10 21:15:59 +08:00
|
|
|
d->ContentsLayout = new DockAreaLayout(d->Layout);
|
2017-03-23 17:23:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
CDockAreaWidget::~CDockAreaWidget()
|
|
|
|
{
|
2017-03-28 18:01:27 +08:00
|
|
|
qDebug() << "~CDockAreaWidget()";
|
2018-10-10 21:15:59 +08:00
|
|
|
delete d->ContentsLayout;
|
2017-03-23 17:23:53 +08:00
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
CDockManager* CDockAreaWidget::dockManager() const
|
|
|
|
{
|
|
|
|
return d->DockManager;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
CDockContainerWidget* CDockAreaWidget::dockContainer() const
|
|
|
|
{
|
2018-10-10 21:15:59 +08:00
|
|
|
return internal::findParent<CDockContainerWidget*>(this);
|
2017-03-23 17:23:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaWidget::addDockWidget(CDockWidget* DockWidget)
|
|
|
|
{
|
|
|
|
insertDockWidget(d->ContentsLayout->count(), DockWidget);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget,
|
|
|
|
bool Activate)
|
|
|
|
{
|
|
|
|
d->ContentsLayout->insertWidget(index, DockWidget);
|
2018-09-07 17:10:14 +08:00
|
|
|
DockWidget->tabWidget()->setDockAreaWidget(this);
|
|
|
|
auto TabWidget = DockWidget->tabWidget();
|
2018-10-10 21:15:59 +08:00
|
|
|
d->TabBar->insertTab(index, TabWidget);
|
2018-09-07 18:38:11 +08:00
|
|
|
TabWidget->setVisible(!DockWidget->isClosed());
|
2017-03-23 17:23:53 +08:00
|
|
|
DockWidget->setProperty(INDEX_PROPERTY, index);
|
2018-10-10 21:15:59 +08:00
|
|
|
d->markTabsMenuOutdated();
|
2017-03-23 17:23:53 +08:00
|
|
|
if (Activate)
|
|
|
|
{
|
|
|
|
setCurrentIndex(index);
|
|
|
|
}
|
|
|
|
DockWidget->setDockArea(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget)
|
|
|
|
{
|
2017-03-28 18:01:27 +08:00
|
|
|
qDebug() << "CDockAreaWidget::removeDockWidget";
|
2018-09-14 19:21:29 +08:00
|
|
|
auto NextOpenDockWidget = nextOpenDockWidget(DockWidget);
|
2018-09-07 17:10:14 +08:00
|
|
|
|
2017-03-23 17:23:53 +08:00
|
|
|
d->ContentsLayout->removeWidget(DockWidget);
|
2018-09-14 19:21:29 +08:00
|
|
|
auto TabWidget = DockWidget->tabWidget();
|
|
|
|
TabWidget->hide();
|
2018-10-10 21:15:59 +08:00
|
|
|
d->TabBar->removeTab(TabWidget);
|
2018-09-14 19:21:29 +08:00
|
|
|
if (NextOpenDockWidget)
|
2018-09-07 17:10:14 +08:00
|
|
|
{
|
2018-09-14 19:21:29 +08:00
|
|
|
setCurrentDockWidget(NextOpenDockWidget);
|
2018-09-07 17:10:14 +08:00
|
|
|
d->markTabsMenuOutdated();
|
|
|
|
}
|
2018-09-14 19:21:29 +08:00
|
|
|
else if (d->ContentsLayout->isEmpty())
|
2017-03-23 17:23:53 +08:00
|
|
|
{
|
2017-03-28 18:01:27 +08:00
|
|
|
qDebug() << "Dock Area empty";
|
2017-03-23 17:23:53 +08:00
|
|
|
dockContainer()->removeDockArea(this);
|
2018-09-14 19:21:29 +08:00
|
|
|
this->deleteLater();
|
2017-03-23 17:23:53 +08:00
|
|
|
}
|
2018-09-14 19:21:29 +08:00
|
|
|
else
|
2018-09-14 14:46:10 +08:00
|
|
|
{
|
|
|
|
// if contents layout is not empty but there are no more open dock
|
|
|
|
// widgets, then we need to hide the dock area because it does not
|
|
|
|
// contain any visible content
|
|
|
|
hideAreaWithNoVisibleContent();
|
|
|
|
}
|
2017-03-23 17:23:53 +08:00
|
|
|
|
|
|
|
d->updateTabBar();
|
|
|
|
DockWidget->setDockArea(nullptr);
|
2018-09-14 19:21:29 +08:00
|
|
|
|
|
|
|
#if (ADS_DEBUG_LEVEL > 0)
|
|
|
|
CDockContainerWidget* DockContainer = dockContainer();
|
2017-03-28 14:48:44 +08:00
|
|
|
DockContainer->dumpLayout();
|
2018-09-14 19:21:29 +08:00
|
|
|
#endif
|
2017-03-23 17:23:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-14 14:46:10 +08:00
|
|
|
//============================================================================
|
|
|
|
void CDockAreaWidget::hideAreaWithNoVisibleContent()
|
|
|
|
{
|
|
|
|
this->hide();
|
|
|
|
|
|
|
|
// Hide empty parent splitter
|
|
|
|
auto Splitter = internal::findParent<CDockSplitter*>(this);
|
|
|
|
while (Splitter && Splitter->isVisible())
|
|
|
|
{
|
|
|
|
if (!Splitter->hasVisibleContent())
|
|
|
|
{
|
|
|
|
Splitter->hide();
|
|
|
|
}
|
|
|
|
Splitter = internal::findParent<CDockSplitter*>(Splitter);
|
|
|
|
}
|
|
|
|
|
|
|
|
//Hide empty floating widget
|
|
|
|
CDockContainerWidget* Container = this->dockContainer();
|
|
|
|
if (Container->isFloating() && Container->openedDockAreas().isEmpty())
|
|
|
|
{
|
|
|
|
CFloatingDockContainer* FloatingWidget = internal::findParent<CFloatingDockContainer*>(Container);
|
|
|
|
FloatingWidget->hide();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaWidget::hideAreaIfNoVisibleContent()
|
|
|
|
{
|
|
|
|
if (openedDockWidgets().isEmpty())
|
|
|
|
{
|
|
|
|
hideAreaIfNoVisibleContent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-23 17:23:53 +08:00
|
|
|
//============================================================================
|
|
|
|
void CDockAreaWidget::onCloseButtonClicked()
|
|
|
|
{
|
|
|
|
currentDockWidget()->toggleView(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
CDockWidget* CDockAreaWidget::currentDockWidget() const
|
|
|
|
{
|
|
|
|
return dockWidget(currentIndex());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaWidget::setCurrentDockWidget(CDockWidget* DockWidget)
|
|
|
|
{
|
2018-09-07 18:38:11 +08:00
|
|
|
int Index = index(DockWidget);
|
2017-03-23 17:23:53 +08:00
|
|
|
if (Index < 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2018-10-11 19:07:27 +08:00
|
|
|
|
|
|
|
if (dockManager()->isRestoringState())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-23 17:23:53 +08:00
|
|
|
setCurrentIndex(Index);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaWidget::setCurrentIndex(int index)
|
|
|
|
{
|
2018-10-11 19:07:27 +08:00
|
|
|
std::cout << "CDockAreaWidget::setCurrentIndex " << index << std::endl;
|
2018-10-10 21:15:59 +08:00
|
|
|
if (index < 0 || index > (d->TabBar->count() - 1))
|
2017-03-23 17:23:53 +08:00
|
|
|
{
|
|
|
|
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
|
|
|
|
return;
|
2018-08-10 19:48:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
emit currentChanging(index);
|
2018-10-10 21:15:59 +08:00
|
|
|
d->TabBar->setCurrentIndex(index);
|
2018-10-11 16:55:36 +08:00
|
|
|
CDockWidgetTab* CurrentTab = d->TabBar->currentTab();
|
|
|
|
auto Features = CurrentTab->dockWidget()->features();
|
2018-10-10 21:15:59 +08:00
|
|
|
d->CloseButton->setVisible(Features.testFlag(CDockWidget::DockWidgetClosable));
|
2017-03-23 17:23:53 +08:00
|
|
|
|
2018-10-11 19:07:27 +08:00
|
|
|
d->ContentsLayout->setCurrentIndex(index);
|
|
|
|
d->ContentsLayout->currentWidget()->show();
|
2017-03-23 17:23:53 +08:00
|
|
|
emit currentChanged(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
int CDockAreaWidget::currentIndex() const
|
|
|
|
{
|
|
|
|
return d->ContentsLayout->currentIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
QRect CDockAreaWidget::titleAreaGeometry() const
|
|
|
|
{
|
|
|
|
return d->TopLayout->geometry();
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
QRect CDockAreaWidget::contentAreaGeometry() const
|
|
|
|
{
|
|
|
|
return d->ContentsLayout->geometry();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
2018-09-07 18:38:11 +08:00
|
|
|
int CDockAreaWidget::index(CDockWidget* DockWidget)
|
2017-03-23 17:23:53 +08:00
|
|
|
{
|
|
|
|
return d->ContentsLayout->indexOf(DockWidget);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
QList<CDockWidget*> CDockAreaWidget::dockWidgets() const
|
|
|
|
{
|
|
|
|
QList<CDockWidget*> DockWidgetList;
|
|
|
|
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
|
|
|
{
|
|
|
|
DockWidgetList.append(dockWidget(i));
|
|
|
|
}
|
|
|
|
return DockWidgetList;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-14 14:46:10 +08:00
|
|
|
//============================================================================
|
|
|
|
int CDockAreaWidget::openDockWidgetsCount() const
|
|
|
|
{
|
|
|
|
int Count = 0;
|
|
|
|
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
|
|
|
{
|
|
|
|
if (!dockWidget(i)->isClosed())
|
|
|
|
{
|
|
|
|
++Count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-23 17:23:53 +08:00
|
|
|
//============================================================================
|
|
|
|
QList<CDockWidget*> CDockAreaWidget::openedDockWidgets() const
|
|
|
|
{
|
|
|
|
QList<CDockWidget*> DockWidgetList;
|
|
|
|
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
|
|
|
{
|
|
|
|
CDockWidget* DockWidget = dockWidget(i);
|
|
|
|
if (!DockWidget->isClosed())
|
|
|
|
{
|
|
|
|
DockWidgetList.append(dockWidget(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return DockWidgetList;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
int CDockAreaWidget::indexOfContentByTitlePos(const QPoint& p, QWidget* exclude) const
|
|
|
|
{
|
|
|
|
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
|
|
|
{
|
2018-09-07 18:56:20 +08:00
|
|
|
auto TabWidget = d->tabWidgetAt(i);
|
|
|
|
if (TabWidget->isVisible() && TabWidget->geometry().contains(p) && (!exclude || TabWidget != exclude))
|
2017-03-23 17:23:53 +08:00
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
2018-09-14 14:46:10 +08:00
|
|
|
int CDockAreaWidget::dockWidgetsCount() const
|
2017-03-23 17:23:53 +08:00
|
|
|
{
|
|
|
|
return d->ContentsLayout->count();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
CDockWidget* CDockAreaWidget::dockWidget(int Index) const
|
|
|
|
{
|
|
|
|
return dynamic_cast<CDockWidget*>(d->ContentsLayout->widget(Index));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaWidget::reorderDockWidget(int fromIndex, int toIndex)
|
|
|
|
{
|
|
|
|
if (fromIndex >= d->ContentsLayout->count() || fromIndex < 0
|
|
|
|
|| toIndex >= d->ContentsLayout->count() || toIndex < 0 || fromIndex == toIndex)
|
|
|
|
{
|
|
|
|
qDebug() << "Invalid index for tab movement" << fromIndex << toIndex;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-10-10 21:15:59 +08:00
|
|
|
auto Widget = d->ContentsLayout->widget(fromIndex);
|
|
|
|
d->ContentsLayout->removeWidget(Widget);
|
|
|
|
d->ContentsLayout->insertWidget(toIndex, Widget);
|
2018-10-12 16:41:19 +08:00
|
|
|
setCurrentIndex(toIndex);
|
2017-03-23 17:23:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-07 17:10:14 +08:00
|
|
|
//============================================================================
|
|
|
|
void CDockAreaWidget::toggleDockWidgetView(CDockWidget* DockWidget, bool Open)
|
|
|
|
{
|
|
|
|
Q_UNUSED(DockWidget);
|
|
|
|
Q_UNUSED(Open);
|
2018-09-26 15:57:36 +08:00
|
|
|
updateTabBarVisibility();
|
2018-09-07 17:10:14 +08:00
|
|
|
d->markTabsMenuOutdated();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-23 17:23:53 +08:00
|
|
|
//============================================================================
|
|
|
|
void CDockAreaWidget::onTabsMenuActionTriggered(QAction* Action)
|
|
|
|
{
|
2018-09-07 17:10:14 +08:00
|
|
|
QVariant vDockWidget = Action->property(DOCKWIDGET_PROPERTY);
|
|
|
|
CDockWidget* DockWidget = vDockWidget.value<CDockWidget*>();
|
|
|
|
setCurrentDockWidget(DockWidget);
|
2017-03-23 17:23:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
2018-09-26 15:57:36 +08:00
|
|
|
void CDockAreaWidget::updateTabBarVisibility()
|
2017-03-23 17:23:53 +08:00
|
|
|
{
|
|
|
|
d->updateTabBar();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-23 22:57:15 +08:00
|
|
|
//============================================================================
|
2017-12-30 01:18:16 +08:00
|
|
|
void CDockAreaWidget::saveState(QXmlStreamWriter& s) const
|
2017-03-23 22:57:15 +08:00
|
|
|
{
|
2017-12-30 01:18:16 +08:00
|
|
|
s.writeStartElement("DockAreaWidget");
|
|
|
|
s.writeAttribute("Tabs", QString::number(d->ContentsLayout->count()));
|
|
|
|
s.writeAttribute("CurrentIndex", QString::number(d->ContentsLayout->currentIndex()));
|
2017-03-28 18:01:27 +08:00
|
|
|
qDebug() << "CDockAreaWidget::saveState TabCount: " << d->ContentsLayout->count()
|
|
|
|
<< " CurrentIndex: " << d->ContentsLayout->currentIndex();
|
2017-03-23 22:57:15 +08:00
|
|
|
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
|
|
|
{
|
2017-12-30 01:18:16 +08:00
|
|
|
dockWidget(i)->saveState(s);
|
2017-03-23 22:57:15 +08:00
|
|
|
}
|
2017-12-30 01:18:16 +08:00
|
|
|
s.writeEndElement();
|
2017-03-23 22:57:15 +08:00
|
|
|
}
|
|
|
|
|
2018-09-07 17:10:14 +08:00
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
CDockWidget* CDockAreaWidget::nextOpenDockWidget(CDockWidget* DockWidget) const
|
|
|
|
{
|
|
|
|
auto OpenDockWidgets = openedDockWidgets();
|
2018-09-26 15:57:36 +08:00
|
|
|
if (OpenDockWidgets.count() > 1 || (OpenDockWidgets.count() == 1 && OpenDockWidgets[0] != DockWidget))
|
2018-09-07 17:10:14 +08:00
|
|
|
{
|
|
|
|
CDockWidget* NextDockWidget;
|
|
|
|
if (OpenDockWidgets.last() == DockWidget)
|
|
|
|
{
|
|
|
|
NextDockWidget = OpenDockWidgets[OpenDockWidgets.count() - 2];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int NextIndex = OpenDockWidgets.indexOf(DockWidget) + 1;
|
|
|
|
NextDockWidget = OpenDockWidgets[NextIndex];
|
|
|
|
}
|
|
|
|
|
|
|
|
return NextDockWidget;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaWidget::onTabsMenuAboutToShow()
|
|
|
|
{
|
|
|
|
d->updateTabsMenu();
|
|
|
|
}
|
|
|
|
|
2017-03-23 17:23:53 +08:00
|
|
|
} // namespace ads
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// EOF DockAreaWidget.cpp
|