From 2c7b5982b59805ecdf8029712aa916937f04f327 Mon Sep 17 00:00:00 2001 From: Jean Porcherot Date: Wed, 14 Apr 2021 15:36:00 +0200 Subject: [PATCH] Replace dockdepth1 by dockindock --- examples/dockdepth1/MainWindow.cpp | 63 --- examples/dockdepth1/MainWindow.h | 15 - examples/dockdepth1/innertabs.cpp | 173 --------- examples/dockdepth1/innertabs.h | 45 --- .../{dockdepth1 => dockindock}/CMakeLists.txt | 10 +- examples/dockindock/dockindock.cpp | 296 +++++++++++++++ examples/dockindock/dockindock.h | 80 ++++ .../dockindock.pro} | 16 +- examples/dockindock/dockindockmanager.cpp | 359 ++++++++++++++++++ examples/dockindock/dockindockmanager.h | 96 +++++ examples/{dockdepth1 => dockindock}/main.cpp | 0 examples/dockindock/mainframe.cpp | 76 ++++ examples/dockindock/mainframe.h | 30 ++ examples/dockindock/perspectiveactions.cpp | 39 ++ examples/dockindock/perspectiveactions.h | 38 ++ examples/dockindock/perspectives.cpp | 278 ++++++++++++++ examples/dockindock/perspectives.h | 59 +++ examples/examples.pro | 2 +- 18 files changed, 1369 insertions(+), 306 deletions(-) delete mode 100644 examples/dockdepth1/MainWindow.cpp delete mode 100644 examples/dockdepth1/MainWindow.h delete mode 100644 examples/dockdepth1/innertabs.cpp delete mode 100644 examples/dockdepth1/innertabs.h rename examples/{dockdepth1 => dockindock}/CMakeLists.txt (86%) create mode 100644 examples/dockindock/dockindock.cpp create mode 100644 examples/dockindock/dockindock.h rename examples/{dockdepth1/dockdepth1.pro => dockindock/dockindock.pro} (56%) create mode 100644 examples/dockindock/dockindockmanager.cpp create mode 100644 examples/dockindock/dockindockmanager.h rename examples/{dockdepth1 => dockindock}/main.cpp (100%) create mode 100644 examples/dockindock/mainframe.cpp create mode 100644 examples/dockindock/mainframe.h create mode 100644 examples/dockindock/perspectiveactions.cpp create mode 100644 examples/dockindock/perspectiveactions.h create mode 100644 examples/dockindock/perspectives.cpp create mode 100644 examples/dockindock/perspectives.h diff --git a/examples/dockdepth1/MainWindow.cpp b/examples/dockdepth1/MainWindow.cpp deleted file mode 100644 index 31b056c..0000000 --- a/examples/dockdepth1/MainWindow.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "../../examples/dockdepth1/MainWindow.h" -#include "../../examples/dockdepth1/innertabs.h" - -#include -#include - -#include "DockAreaWidget.h" - -MainWindow::MainWindow(QWidget *parent) : - QMainWindow(parent) -{ - resize( 400, 400 ); - - DockManagerWithInnerTabs* dockManager = new DockManagerWithInnerTabs(this); - - dockManager->attachViewMenu( menuBar()->addMenu( "View" ) ); - - ads::CDockAreaWidget* previousDockWidget = NULL; - for ( int i = 0; i != 3; ++i ) - { - // Create example content label - this can be any application specific - // widget - QLabel* l = new QLabel(); - l->setWordWrap(true); - l->setAlignment(Qt::AlignTop | Qt::AlignLeft); - l->setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. "); - - // Create a dock widget with the title Label 1 and set the created label - // as the dock widget content - ads::CDockWidget* DockWidget = new ads::CDockWidget("Label " + QString::number(i)); - DockWidget->setWidget(l); - - // Add the dock widget to the top dock widget area - previousDockWidget = dockManager->addDockWidget(ads::CenterDockWidgetArea, DockWidget, previousDockWidget); - } - - ads::CDockContainerWidget* groupManager = dockManager->createGroup( "Group", previousDockWidget ).second; - - previousDockWidget = NULL; - for ( int i = 0; i != 3; ++i ) - { - // Create example content label - this can be any application specific - // widget - QLabel* l = new QLabel(); - l->setWordWrap(true); - l->setAlignment(Qt::AlignTop | Qt::AlignLeft); - l->setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. "); - - // Create a dock widget with the title Label 1 and set the created label - // as the dock widget content - ads::CDockWidget* DockWidget = new ads::CDockWidget("Inner " + QString::number(i)); - DockWidget->setWidget(l); - - // Add the dock widget to the top dock widget area - previousDockWidget = groupManager->addDockWidget(ads::CenterDockWidgetArea, DockWidget, previousDockWidget); - } -} - -MainWindow::~MainWindow() -{ - -} - diff --git a/examples/dockdepth1/MainWindow.h b/examples/dockdepth1/MainWindow.h deleted file mode 100644 index f834c00..0000000 --- a/examples/dockdepth1/MainWindow.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit MainWindow(QWidget *parent = 0); - ~MainWindow(); -}; - -#endif // MAINWINDOW_H diff --git a/examples/dockdepth1/innertabs.cpp b/examples/dockdepth1/innertabs.cpp deleted file mode 100644 index 5811b7b..0000000 --- a/examples/dockdepth1/innertabs.cpp +++ /dev/null @@ -1,173 +0,0 @@ -#include "innertabs.h" - -#include "DockAreaWidget.h" - -#include -#include - -#include - -///////////////////////////////////// -// DockManagerWithInnerTabs -///////////////////////////////////// -void deleteAllChildren( ads::CDockContainerWidget* areaWidget ) -{ - // fix crash on close by manually deleting children - // maybe due to this issue: https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues/307 - - std::vector areas; - for ( int i = 0; i != areaWidget->dockAreaCount(); ++i ) - { - areas.push_back( areaWidget->dockArea(i) ); - } - - for ( auto area : areas ) - { - for ( auto widget : area->dockWidgets() ) - { - ads::CDockContainerWidget* subArea = dynamic_cast( widget->widget() ); - if ( subArea ) - deleteAllChildren( subArea ); - delete widget; - } - - delete area; - } -} - -DockManagerWithInnerTabs::~DockManagerWithInnerTabs() -{ - deleteAllChildren( this ); -} - -std::pair DockManagerWithInnerTabs::createGroup( const QString& groupName, ads::CDockAreaWidget*& insertPos ) -{ - ads::CDockWidget* groupedDockWidget = new ads::CDockWidget(groupName); - - ads::CDockContainerWidget* groupManager = new ads::CDockContainerWidget(this); - groupedDockWidget->setWidget(groupManager); - - insertPos = this->addDockWidget(ads::CenterDockWidgetArea, groupedDockWidget, insertPos); - - return { groupedDockWidget, groupManager }; -} - -void DockManagerWithInnerTabs::attachViewMenu( QMenu* menu ) -{ - connect( menu, SIGNAL(aboutToShow()), this, SLOT(autoFillAttachedViewMenu()) ); -} - -void DockManagerWithInnerTabs::autoFillAttachedViewMenu() -{ - QMenu* menu = dynamic_cast( QObject::sender() ); - - if ( menu ) - { - menu->clear(); - setupViewMenu( menu ); - } - else - { - assert( false ); - } -} - -bool SortFunc( ads::CDockWidget* left, ads::CDockWidget* right ) -{ - if ( left->windowTitle() == right->windowTitle() ) - { - assert( false ); - return left < right; - } - else - { - return left->windowTitle() < right->windowTitle(); - } -} - -void DockManagerWithInnerTabs::setupMenu( QMenu* menu, ads::CDockContainerWidget* areaWidget ) -{ - std::vector widgets; - - ads::CDockManager* dockManager = dynamic_cast( areaWidget ); - if ( dockManager ) - { - for ( ads::CFloatingDockContainer* floating : dockManager->floatingWidgets() ) - { - for ( auto floated : floating->dockWidgets() ) - widgets.push_back( floated ); - } - } - - for ( int i = 0; i != areaWidget->dockAreaCount(); ++i ) - { - for ( auto docked : areaWidget->dockArea(i)->dockWidgets() ) - widgets.push_back( docked ); - } - - std::sort( widgets.begin(), widgets.end(), SortFunc ); - - for ( auto widget : widgets ) - { - auto action = widget->toggleViewAction(); - - ads::CDockContainerWidget* subArea = dynamic_cast( widget->widget() ); - if ( subArea ) - { - auto subMenu = menu->addMenu( widget->windowTitle() ); - - subMenu->addAction( action ); - subMenu->addSeparator(); - - setupMenu( subMenu, subArea ); - } - else - { - menu->addAction(action); - } - } - - if ( dockManager ) - { - menu->addSeparator(); - int count = areaWidget->dockAreaCount(); - if ( count == 0 ) - { - menu->addAction( new CreateGroupAction( this, NULL, menu ) ); - } - else - { - for ( int i = 0; i != count; ++i ) - { - menu->addAction( new CreateGroupAction( this, areaWidget->dockArea(i), menu ) ); - } - } - } - // else, don't permit to add groups in groups - // that would be nice, but it's not handled correctly upon drag/drop of a widget, it cannot be dropped in the inner docking area -} - -void DockManagerWithInnerTabs::setupViewMenu( QMenu* menu ) -{ - setupMenu( menu, this ); -} - -///////////////////////////////////// -// CreateGroupAction -///////////////////////////////////// -CreateGroupAction::CreateGroupAction( DockManagerWithInnerTabs* manager, ads::CDockAreaWidget* insertPos, QMenu* menu ) : - QAction("New group...", menu), - m_manager( manager), - m_insertPos( insertPos ) -{ - connect( this, SIGNAL(triggered()), this, SLOT(createGroup()) ); -} - -void CreateGroupAction::createGroup() -{ - QString name = QInputDialog::getText( NULL, text(), "Enter group name" ); - if ( !name.isEmpty() ) - { - m_manager->createGroup( name, m_insertPos ); - } -} diff --git a/examples/dockdepth1/innertabs.h b/examples/dockdepth1/innertabs.h deleted file mode 100644 index 097ac14..0000000 --- a/examples/dockdepth1/innertabs.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include "DockManager.h" - -#include - -class DockManagerWithInnerTabs : public ads::CDockManager -{ - Q_OBJECT - -public: - using ads::CDockManager::CDockManager; - - ~DockManagerWithInnerTabs() override; - - std::pair createGroup( const QString& groupName, ads::CDockAreaWidget*& insertPos ); - - /** Manually fill a given view menu */ - void setupViewMenu( QMenu* menu ); - - /** Attach a view menu that will be automatically fill */ - void attachViewMenu( QMenu* menu ); - -private slots: - void autoFillAttachedViewMenu(); - -private: - void setupMenu( QMenu* menu, ads::CDockContainerWidget* areaWidget ); -}; - -class CreateGroupAction : public QAction -{ - Q_OBJECT -public: - CreateGroupAction( DockManagerWithInnerTabs* manager, ads::CDockAreaWidget* insertIn, QMenu* menu ); - -public slots: - void createGroup(); - -private: - DockManagerWithInnerTabs* m_manager; - ads::CDockAreaWidget* m_insertPos; -}; - - diff --git a/examples/dockdepth1/CMakeLists.txt b/examples/dockindock/CMakeLists.txt similarity index 86% rename from examples/dockdepth1/CMakeLists.txt rename to examples/dockindock/CMakeLists.txt index 6ca354a..c2a70b6 100644 --- a/examples/dockdepth1/CMakeLists.txt +++ b/examples/dockindock/CMakeLists.txt @@ -2,11 +2,13 @@ cmake_minimum_required(VERSION 3.5) project(ads_example_simple VERSION ${VERSION_SHORT}) find_package(Qt5 5.5 COMPONENTS Core Gui Widgets REQUIRED) set(CMAKE_INCLUDE_CURRENT_DIR ON) -add_executable(DockDepth1 WIN32 - innertabs.cpp +add_executable(DockInDock WIN32 + dockindock.cpp + dockindockmanager.cpp + perspectiveactions.cpp + perspectives.cpp main.cpp - MainWindow.cpp - MainWindow.ui + mainframe.cpp ) target_include_directories(SimpleExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src") target_link_libraries(SimpleExample PRIVATE qtadvanceddocking) diff --git a/examples/dockindock/dockindock.cpp b/examples/dockindock/dockindock.cpp new file mode 100644 index 0000000..cf9bbeb --- /dev/null +++ b/examples/dockindock/dockindock.cpp @@ -0,0 +1,296 @@ +#include "dockindock.h" +#include "perspectives.h" +#include "dockindockmanager.h" +#include "perspectiveactions.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace QtAdsUtl; + +DockInDockWidget::DockInDockWidget( QWidget* parent, bool canCreateNewGroups, PerspectivesManager* perspectivesManager ) : + DockInDockWidget( parent, (DockInDockWidget*)NULL, perspectivesManager ) +{ + m_canCreateNewGroups = canCreateNewGroups; + m_topLevelDockWidget = this; +} + +DockInDockWidget::DockInDockWidget( QWidget* parent, DockInDockWidget* topLevelDockWidget, PerspectivesManager* perspectivesManager ) : + baseClass( parent ), + m_topLevelDockWidget( topLevelDockWidget ), + m_canCreateNewGroups( (topLevelDockWidget) ? topLevelDockWidget->m_canCreateNewGroups : false ), + m_perspectivesManager( perspectivesManager ) +{ + QVBoxLayout* layout = new QVBoxLayout(this); + layout->setContentsMargins( 0,0,0,0 ); + layout->addWidget( m_mgr = new DockInDockManager(*this) ); +} + +DockInDockWidget::~DockInDockWidget() +{ + +} + +ads::CDockAreaWidget* DockInDockWidget::addTabWidget( QWidget* widget, const QString& name, ads::CDockAreaWidget* after ) +{ + return addTabWidget( widget, name, QIcon(), after ); +} + +ads::CDockAreaWidget* DockInDockWidget::addTabWidget( QWidget* widget, const QString& name, QIcon icon, ads::CDockAreaWidget* after ) +{ + for ( auto existing : getTopLevelDockWidget()->getManager()->allDockWidgets(true,true) ) + { + if ( existing.second->objectName() == name ) + { + QMessageBox::critical( this, "Error", "Name '" + name + "' already in use" ); + return NULL; + } + } + + ads::CDockWidget* DockWidget = new ads::CDockWidget(name); + DockWidget->setWidget(widget); + DockWidget->setIcon( icon ); + + // Add the dock widget to the top dock widget area + return m_mgr->addDockWidget(ads::CenterDockWidgetArea, DockWidget, after); +} + +bool DockInDockWidget::isTopLevel() +{ + return objectName().isEmpty(); +} + +QString DockInDockWidget::getGroupNameError( const QString& groupName ) +{ + if ( groupName.isEmpty() ) + { + return "Group must have a non-empty name"; + } + + std::vector dockManagers = m_mgr->allManagers( true, true ); + for ( auto mgr : dockManagers ) + { + if ( mgr->getGroupName() == groupName ) + return "Group name '" + groupName + "' already used"; + } + + return ""; +} + +DockInDockWidget* DockInDockWidget::createGroup( const QString& groupName, ads::CDockAreaWidget*& insertPos ) +{ + return createGroup( groupName, QIcon(), insertPos ); +} + +DockInDockWidget* DockInDockWidget::createGroup( const QString& groupName, QIcon icon, ads::CDockAreaWidget*& insertPos ) +{ + QString error = getGroupNameError( groupName ); + if ( !error.isEmpty() ) + { + QMessageBox::critical( NULL, "Error", error ); + return NULL; + } + + DockInDockWidget* child = new DockInDockWidget( this, m_topLevelDockWidget, m_perspectivesManager ); + child->setObjectName( groupName ); + + ads::CDockWidget* DockWidget = new ads::CDockWidget(groupName); + DockWidget->setWidget(child); + DockWidget->setIcon(icon); + + insertPos = m_mgr->addDockWidget(ads::CenterDockWidgetArea, DockWidget, insertPos); + + return child; +} + +void DockInDockWidget::destroyGroup( DockInDockWidget* widgetToRemove ) +{ + auto topLevelWidget = widgetToRemove->getTopLevelDockWidget(); + + if ( topLevelWidget && topLevelWidget != widgetToRemove ) + { + // reaffect all child docks to top-level + for ( auto dockwidget : widgetToRemove->getManager()->getWidgetsInGUIOrder() ) // don't use allDockWidgets to preserve sub-groups + { + MoveDockWidgetAction::move( dockwidget, topLevelWidget->getManager() ); + } + assert( widgetToRemove->getManager()->allDockWidgets( true, true ).empty() ); + + // find widget's parent: + for ( auto dockwidget : topLevelWidget->getManager()->allDockWidgets( true, true ) ) + { + if ( dockwidget.second->widget() == widgetToRemove ) + { + dockwidget.first->removeDockWidget( dockwidget.second ); + delete dockwidget.second; + //delete widgetToRemove; automatically deleted when dockWidget is deleted + widgetToRemove = NULL; + break; + } + } + + assert( widgetToRemove == NULL ); + } + else + { + assert( false ); + } +} + +void DockInDockWidget::attachViewMenu( QMenu* menu ) +{ + connect( menu, SIGNAL(aboutToShow()), this, SLOT(autoFillAttachedViewMenu()) ); +} + +void DockInDockWidget::autoFillAttachedViewMenu() +{ + QMenu* menu = dynamic_cast( QObject::sender() ); + + if ( menu ) + { + menu->clear(); + setupViewMenu( menu ); + } + else + { + assert( false ); + } +} + +void DockInDockWidget::setupViewMenu( QMenu* menu ) +{ + std::vector dockManagers = m_mgr->allManagers( true, true ); + + bool hasPerspectivesMenu = false; + if ( getTopLevelDockWidget() == this ) + hasPerspectivesMenu = (m_perspectivesManager != NULL); + else + assert( false ); + + QMenu* organize = menu; + if ( hasPerspectivesMenu ) + organize = menu->addMenu( "Organize" ); + + setupMenu( organize, dockManagers ); + + if ( hasPerspectivesMenu ) + { + QMenu* perspectives = menu->addMenu( "Perspectives" ); + fillPerspectivesMenu( perspectives ); + } +} + +void DockInDockWidget::setupMenu( QMenu* menu, const std::vector& moveTo ) +{ + m_mgr->fillViewMenu( menu, moveTo ); + menu->addSeparator(); + auto moveMenu = menu->addMenu( "Move" ); + m_mgr->fillMoveMenu( moveMenu, moveTo ); +} + +void DockInDockWidget::fillPerspectivesMenu( QMenu* menu ) +{ + menu->addAction( "Create perspective...", this, SLOT(createPerspective()) ); + + QStringList perspectiveNames; + if ( m_perspectivesManager ) + perspectiveNames = m_perspectivesManager->perspectiveNames(); + + if ( !perspectiveNames.isEmpty() ) + { + QMenu* load = menu->addMenu( "Load perspective" ); + for ( auto name : perspectiveNames ) + load->addAction( new LoadPerspectiveAction( load, name, *this ) ); + QMenu* remove = menu->addMenu( "Remove perspective" ); + for ( auto name : perspectiveNames ) + remove->addAction( new RemovePerspectiveAction( remove, name, *this ) ); + } +} + +void DockInDockWidget::setNewPerspectiveDefaultName( const QString& defaultName ) +{ + m_newPerspectiveDefaultName = defaultName; +} + +void DockInDockWidget::createPerspective() +{ + if ( !m_perspectivesManager ) + return; + + QString name = m_newPerspectiveDefaultName; + if ( !m_newPerspectiveDefaultName.isEmpty() ) + { + int index = 2; + while ( m_perspectivesManager->perspectiveNames().contains( name ) ) + { + name = m_newPerspectiveDefaultName + " (" + QString::number(index) + ")"; + ++index; + } + } + + while ( true ) + { + bool ok = false; + name = QInputDialog::getText( NULL, "Create perspective", "Enter perspective name", QLineEdit::Normal, name, &ok ); + if ( ok ) + { + if ( name.isEmpty() ) + { + QMessageBox::critical( NULL, "Error", "Perspective name cannot be empty" ); + continue; + } + else if ( m_perspectivesManager->perspectiveNames().contains( name ) ) + { + if ( QMessageBox::critical( NULL, "Error", "Perspective '" + name + "' already exists, overwrite it?", QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) == QMessageBox::No ) + continue; + } + + m_perspectivesManager->addPerspective( name, *this ); + break; + } + else + { + break; + } + } +} + +static void dumpStatus( std::ostream& str, ads::CDockWidget* widget, const std::string& tab, std::string suffix ) +{ + DockInDockManager* asMgr = DockInDockManager::dockInAManager( widget ); + if ( asMgr ) + { + asMgr->parent().dumpStatus( str, tab ); + } + else + { + str << tab << widget->objectName().toStdString() << suffix << std::endl; + } +} + +void DockInDockWidget::dumpStatus( std::ostream& str, std::string tab ) +{ + str << tab << "Group: " << getManager()->getGroupName().toStdString() << std::endl; + tab += " "; + std::set visibleWidgets; + for ( auto widget : getManager()->getWidgetsInGUIOrder() ) + { + visibleWidgets.insert( widget ); + ::dumpStatus( str, widget, tab, "" ); + } + + for ( auto closed : getManager()->dockWidgetsMap() ) + { + if ( visibleWidgets.find( closed ) == visibleWidgets.end() ) + { + ::dumpStatus( str, closed, tab, " (closed)" ); + } + } +} diff --git a/examples/dockindock/dockindock.h b/examples/dockindock/dockindock.h new file mode 100644 index 0000000..aaa9ffd --- /dev/null +++ b/examples/dockindock/dockindock.h @@ -0,0 +1,80 @@ +#pragma once + +#include +#include + +#include +#include + +class QMenu; + +namespace ads +{ + class CDockAreaWidget; +} + +namespace QtAdsUtl +{ + +class DockInDockManager; +class PerspectivesManager; +// tab of tab example for https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues/306 +class DockInDockWidget : public QWidget +{ + typedef QWidget baseClass; + + Q_OBJECT + +public: + DockInDockWidget( QWidget* parent, bool canCreateNewGroups, PerspectivesManager* perspectivesManager ); + ~DockInDockWidget() override; + + ads::CDockAreaWidget* addTabWidget( QWidget* widget, const QString& name, ads::CDockAreaWidget* after ); + DockInDockWidget* createGroup( const QString& groupName, ads::CDockAreaWidget*& insertPos ); + + ads::CDockAreaWidget* addTabWidget( QWidget* widget, const QString& name, QIcon icon, ads::CDockAreaWidget* after ); + DockInDockWidget* createGroup( const QString& groupName, QIcon icon, ads::CDockAreaWidget*& insertPos ); + + QString getGroupNameError( const QString& groupName ); + void destroyGroup( DockInDockWidget* widget ); + + /** Manually fill a given view menu */ + void setupViewMenu( QMenu* menu ); + + /** Attach a view menu that will be automatically fill */ + void attachViewMenu( QMenu* menu ); + + bool isTopLevel(); + void setupMenu( QMenu* menu, const std::vector& moveTo ); + + inline DockInDockManager* getManager() { return m_mgr; } + inline DockInDockWidget* getTopLevelDockWidget() { return m_topLevelDockWidget; } + + inline bool canCreateNewGroups() const { return m_canCreateNewGroups; } + + void dumpStatus( std::ostream& str, std::string tab = "" ); + + inline PerspectivesManager* getPerspectivesManager() { return m_perspectivesManager; } + + void setNewPerspectiveDefaultName( const QString& defaultName ); + +private slots: + void autoFillAttachedViewMenu(); + void createPerspective(); + +private: + DockInDockManager* m_mgr; + DockInDockWidget* m_topLevelDockWidget; + + bool m_canCreateNewGroups; + + DockInDockWidget( QWidget* parent, DockInDockWidget* topLevelDockWidget, PerspectivesManager* perspectivesManager ); + + PerspectivesManager* m_perspectivesManager; + QString m_newPerspectiveDefaultName; + + void fillPerspectivesMenu( QMenu* menu ); +}; + +} + diff --git a/examples/dockdepth1/dockdepth1.pro b/examples/dockindock/dockindock.pro similarity index 56% rename from examples/dockdepth1/dockdepth1.pro rename to examples/dockindock/dockindock.pro index a8ae279..45242d1 100644 --- a/examples/dockdepth1/dockdepth1.pro +++ b/examples/dockindock/dockindock.pro @@ -2,7 +2,7 @@ ADS_OUT_ROOT = $${OUT_PWD}/../.. QT += core gui widgets -TARGET = DockDepth1 +TARGET = DockInDock DESTDIR = $${ADS_OUT_ROOT}/lib TEMPLATE = app CONFIG += c++14 @@ -14,13 +14,19 @@ adsBuildStatic { DEFINES += QT_DEPRECATED_WARNINGS SOURCES += \ - innertabs.cpp \ + dockindock.cpp \ + dockindockmanager.cpp \ + perspectiveactions.cpp \ + perspectives.cpp \ main.cpp \ - MainWindow.cpp + mainframe.cpp HEADERS += \ - innertabs.h \ - MainWindow.h + dockindock.h \ + dockindockmanager.h \ + perspectiveactions.h \ + perspectives.h \ + mainframe.h LIBS += -L$${ADS_OUT_ROOT}/lib include(../../ads.pri) diff --git a/examples/dockindock/dockindockmanager.cpp b/examples/dockindock/dockindockmanager.cpp new file mode 100644 index 0000000..1850185 --- /dev/null +++ b/examples/dockindock/dockindockmanager.cpp @@ -0,0 +1,359 @@ +#include "dockindockmanager.h" +#include "dockindock.h" + +#include "DockAreaWidget.h" + +#include +#include +#include +#include + +#include + +using namespace QtAdsUtl; + +///////////////////////////////////// +// DockInDockManager +///////////////////////////////////// +void deleteAllChildrenToPreventLeak( ads::CDockContainerWidget* areaWidget ) +{ + // fix leaks: https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues/307 + + std::vector areas; + for ( int i = 0; i != areaWidget->dockAreaCount(); ++i ) + { + areas.push_back( areaWidget->dockArea(i) ); + } + + std::vector deleted; + for ( auto area : areas ) + { + for ( auto widget : area->dockWidgets() ) + { + ads::CDockContainerWidget* subArea = dynamic_cast( widget->widget() ); + if ( subArea ) + deleteAllChildrenToPreventLeak( subArea ); + delete widget; + } + + delete area; + } +} + +DockInDockManager::DockInDockManager( DockInDockWidget& parent ) : + baseClass( &parent ), + m_parent( parent ) +{ + +} + +DockInDockManager::~DockInDockManager() +{ + deleteAllChildrenToPreventLeak( this ); +} + +void DockInDockManager::fillViewMenu( QMenu* menu, const std::vector& moveTo ) +{ + auto widgetsMap = dockWidgetsMap(); + for ( auto iter = widgetsMap.begin(); iter != widgetsMap.end(); ++iter ) + { + auto widget = iter.value()->widget(); + auto action = iter.value()->toggleViewAction(); + + DockInDockWidget* asMgr = dynamic_cast( widget ); + if ( asMgr ) + { + auto subMenu = menu->addMenu( iter.key() ); + + subMenu->addAction( action ); + subMenu->addSeparator(); + + asMgr->setupMenu( subMenu, moveTo ); + } + else + { + menu->addAction(action); + } + } + + if ( parent().canCreateNewGroups() ) + { + // see how this works, to create it in the right place, + // and also to have load perspective work when some groups are missing + menu->addSeparator(); + menu->addAction( new QtAdsUtl::CreateChildDockAction( m_parent, menu ) ); + + if ( parent().getTopLevelDockWidget()->getManager() != this ) + menu->addAction( new QtAdsUtl::DestroyGroupAction( &m_parent, menu ) ); + } +} + +void DockInDockManager::fillMoveMenu( QMenu* menu, const std::vector& moveTo ) +{ + auto widgetsMap = dockWidgetsMap(); + for ( auto iter = widgetsMap.begin(); iter != widgetsMap.end(); ++iter ) + { + auto subMenu = menu->addMenu( iter.key() ); + + for ( auto mgr : moveTo ) + { + // iterate over all possible target managers + if ( mgr == this ) + { + // if dock is already in mgr, no reason to move it there + } + else if ( mgr == dockInAManager( iter.value() ) ) + { + // if target is the group itself, can't move it there, would make no sense + } + else + { + subMenu->addAction( new MoveDockWidgetAction( iter.value(), mgr, subMenu ) ); + } + } + } +} + +void DockInDockManager::addPerspectiveRec( const QString& name ) +{ + std::vector managers = allManagers( true, true ); + + for ( auto child : managers ) + child->addPerspective( name ); +} + +void DockInDockManager::openPerspectiveRec( const QString& name ) +{ + std::vector managers = allManagers( true, true ); + + for ( auto child : managers ) + child->openPerspective( name ); +} + +QString DockInDockManager::getGroupName() +{ + return parent().objectName(); +} + +#define CHILD_PREFIX QString("Child-") +QString DockInDockManager::getPersistGroupName() +{ + QString group = "Top"; + if ( !getGroupName().isEmpty() ) + group = CHILD_PREFIX + getGroupName(); + return group; +} + +QString DockInDockManager::getGroupNameFromPersistGroupName( QString persistGroupName ) +{ + if ( persistGroupName.startsWith( CHILD_PREFIX ) ) + { + persistGroupName = persistGroupName.mid( CHILD_PREFIX.size() ); + } + else + { + assert( false ); + } + return persistGroupName; +} + +void DockInDockManager::loadPerspectivesRec(QSettings& Settings) +{ + std::vector children = allManagers( true, true ); + + for ( auto mgr : children ) + { + Settings.beginGroup(mgr->getPersistGroupName()); + mgr->loadPerspectives( Settings ); + Settings.endGroup(); + } +} + +void DockInDockManager::savePerspectivesRec(QSettings& Settings) const +{ + std::vector children = allManagers( true, true ); + + for ( auto mgr : children ) + { + Settings.beginGroup(mgr->getPersistGroupName()); + mgr->savePerspectives( Settings ); + Settings.endGroup(); + } +} + +void DockInDockManager::removePerspectivesRec() +{ + std::vector managers = allManagers( true, true ); + + for ( auto child : managers ) + child->removePerspectives( child->perspectiveNames() ); +} + +DockInDockManager* DockInDockManager::dockInAManager( ads::CDockWidget* widget ) +{ + DockInDockWidget* dockWidget = widget ? dynamic_cast( widget->widget() ) : NULL; + return ( dockWidget ) ? dockWidget->getManager() : NULL; +} + +void DockInDockManager::childManagers( std::vector& managers, bool rec ) const +{ + auto widgets = getWidgetsInGUIOrder(); + for ( auto widget : widgets ) + { + DockInDockManager* asMgr = dockInAManager( widget ); + if ( asMgr ) + { + managers.push_back( asMgr ); + if ( rec ) + asMgr->childManagers( managers, rec ); + } + } +} + +std::vector DockInDockManager::allManagers( bool includeThis, bool rec ) const +{ + std::vector managers; + if ( includeThis ) + managers.push_back( const_cast(this) ); + childManagers( managers, rec ); + return managers; +} + +std::vector> DockInDockManager::allDockWidgets( bool includeThis, bool rec ) const +{ + std::vector> widgets; + for ( auto mgr : allManagers( includeThis, rec ) ) + { + for ( auto widget : mgr->getWidgetsInGUIOrder() ) + widgets.push_back( std::make_pair(mgr, widget) ); + } + return widgets; +} + +QMap DockInDockManager::getGroupContents() +{ + QMap result; + std::vector managers = allManagers( true, true ); + for ( auto mgr : managers ) + { + result[mgr->getPersistGroupName()] = mgr->dockWidgetsMap().keys(); + } + return result; +} + +ads::CDockAreaWidget* DockInDockManager::getInsertDefaultPos() +{ + ads::CDockAreaWidget* defaultPos = NULL; + if ( dockAreaCount() != 0 ) + defaultPos = dockArea(dockAreaCount()-1); + return defaultPos; +} + +std::vector DockInDockManager::getWidgetsInGUIOrder() const +{ + std::vector result; + result.reserve( dockWidgetsMap().size() ); + for ( int i = 0; i != dockAreaCount(); ++i ) + { + for ( auto widget : dockArea(i)->dockWidgets() ) + result.push_back( widget ); + } + return result; +} + +///////////////////////////////////// +// CreateChildDockAction +///////////////////////////////////// +CreateChildDockAction::CreateChildDockAction( DockInDockWidget& dockInDock, QMenu* menu ) : + QAction("New group...", menu), + m_dockInDock( dockInDock ) +{ + connect( this, SIGNAL(triggered()), this, SLOT(createGroup()) ); +} + +void CreateChildDockAction::createGroup() +{ + QString name = ""; + while ( true ) + { + bool ok = false; + name = QInputDialog::getText( NULL, this->text(), "Enter group name", QLineEdit::Normal, name, &ok ); + if ( ok ) + { + QString error = ""; + if ( m_dockInDock.getTopLevelDockWidget() ) + error = m_dockInDock.getTopLevelDockWidget()->getGroupNameError( name ); + else + assert( false ); + + if ( error.isEmpty() ) + { + ads::CDockAreaWidget* insertPos = NULL; + m_dockInDock.createGroup( name, insertPos ); + break; + } + else + { + QMessageBox::critical( NULL, "Error", error ); + continue; + } + } + else + { + break; + } + } +} + +///////////////////////////////////// +// DestroyGroupAction +///////////////////////////////////// +DestroyGroupAction::DestroyGroupAction( DockInDockWidget* widget, QMenu* menu ) : + QAction("Destroy " + widget->getManager()->getGroupName(), menu), + m_widget( widget ) +{ + connect( this, SIGNAL(triggered()), this, SLOT(destroyGroup()) ); +} + +void DestroyGroupAction::destroyGroup() +{ + m_widget->getTopLevelDockWidget()->destroyGroup( m_widget ); +} + + +///////////////////////////////////// +// MoveDockWidgetAction +///////////////////////////////////// +MoveDockWidgetAction::MoveDockWidgetAction( ads::CDockWidget* widget, DockInDockManager* moveTo, QMenu* menu ) : + QAction(menu), + m_widget( widget ), + m_moveTo( moveTo ) +{ + if ( moveTo->parent().isTopLevel() ) + { + setText( "To top" ); + } + else + { + setText( "To " + moveTo->parent().objectName() ); + } + connect( this, SIGNAL(triggered()), this, SLOT(move()) ); +} + +void MoveDockWidgetAction::move() +{ + move( m_widget, m_moveTo ); +} + +void MoveDockWidgetAction::move( ads::CDockWidget* widget, DockInDockManager* moveTo ) +{ + if ( widget && moveTo ) + { + widget->dockManager()->removeDockWidget( widget ); + moveTo->addDockWidget(ads::CenterDockWidgetArea, widget, moveTo->getInsertDefaultPos()); + } + else + { + assert( false ); + } +} diff --git a/examples/dockindock/dockindockmanager.h b/examples/dockindock/dockindockmanager.h new file mode 100644 index 0000000..886cb82 --- /dev/null +++ b/examples/dockindock/dockindockmanager.h @@ -0,0 +1,96 @@ +#pragma once + +#include "DockManager.h" + +#include +#include + +namespace QtAdsUtl +{ + +class DockInDockWidget; +class DockInDockManager : public ads::CDockManager +{ + Q_OBJECT + + typedef ads::CDockManager baseClass; + +public: + DockInDockManager( DockInDockWidget& parent ); + ~DockInDockManager() override; + + void fillViewMenu( QMenu* menu, const std::vector& moveTo ); + void fillMoveMenu( QMenu* menu, const std::vector& moveTo ); + + void addPerspectiveRec( const QString& name ); + void openPerspectiveRec( const QString& name ); + void removePerspectivesRec(); + void loadPerspectivesRec(QSettings& Settings); + void savePerspectivesRec(QSettings& Settings) const; + + static DockInDockManager* dockInAManager( ads::CDockWidget* widget ); + + inline DockInDockWidget& parent() { return m_parent; } + + void childManagers( std::vector& managers, bool rec ) const; + std::vector allManagers( bool includeThis, bool rec ) const; + std::vector> allDockWidgets( bool includeThis, bool rec ) const; + + QString getGroupName(); + QString getPersistGroupName(); + static QString getGroupNameFromPersistGroupName( QString persistGroupName ); + + QMap getGroupContents(); + + ads::CDockAreaWidget* getInsertDefaultPos(); + + std::vector getWidgetsInGUIOrder() const; + +private: + DockInDockWidget& m_parent; +}; + +class CreateChildDockAction : public QAction +{ + Q_OBJECT +public: + CreateChildDockAction( DockInDockWidget& dockInDock, QMenu* menu ); + +public slots: + void createGroup(); + +private: + DockInDockWidget& m_dockInDock; +}; + +class DestroyGroupAction : public QAction +{ + Q_OBJECT +public: + DestroyGroupAction( DockInDockWidget* widget, QMenu* menu ); + +public slots: + void destroyGroup(); + +private: + DockInDockWidget* m_widget; +}; + +class MoveDockWidgetAction : public QAction +{ + Q_OBJECT +public: + MoveDockWidgetAction( ads::CDockWidget* widget, DockInDockManager* moveTo, QMenu* menu ); + + static void move( ads::CDockWidget* widget, DockInDockManager* moveTo ); + +public slots: + void move(); + +private: + ads::CDockWidget* m_widget; + DockInDockManager* m_moveTo; +}; + +} + diff --git a/examples/dockdepth1/main.cpp b/examples/dockindock/main.cpp similarity index 100% rename from examples/dockdepth1/main.cpp rename to examples/dockindock/main.cpp diff --git a/examples/dockindock/mainframe.cpp b/examples/dockindock/mainframe.cpp new file mode 100644 index 0000000..3e8f26f --- /dev/null +++ b/examples/dockindock/mainframe.cpp @@ -0,0 +1,76 @@ +#include "mainframe.h" + +#include "dockindock.h" +#include "perspectives.h" + +#include +#include +#include +#include + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + m_perspectivesManager( new QtAdsUtl::PerspectivesManager( "persist" ) ) +{ + resize( 400, 400 ); + + setCentralWidget( m_dockManager = new QtAdsUtl::DockInDockWidget(this,true,m_perspectivesManager.get()) ); + + m_dockManager->attachViewMenu( menuBar()->addMenu( "View" ) ); + + ads::CDockAreaWidget* previousDockWidget = NULL; + for ( int i = 0; i != 3; ++i ) + { + // Create example content label - this can be any application specific + // widget + QLabel* l = new QLabel(); + l->setWordWrap(true); + l->setAlignment(Qt::AlignTop | Qt::AlignLeft); + l->setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. "); + + previousDockWidget = m_dockManager->addTabWidget( l, "Top label " + QString::number(i), previousDockWidget ); + } + + auto lastTopLevelDock = previousDockWidget; + + for ( int j = 0; j != 2; ++j ) + { + QtAdsUtl::DockInDockWidget* groupManager = m_dockManager->createGroup( "Group " + QString::number(j), lastTopLevelDock ); + + previousDockWidget = NULL; + for ( int i = 0; i != 3; ++i ) + { + // Create example content label - this can be any application specific + // widget + QLabel* l = new QLabel(); + l->setWordWrap(true); + l->setAlignment(Qt::AlignTop | Qt::AlignLeft); + l->setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. "); + + previousDockWidget = groupManager->addTabWidget( l, "ZInner " + QString::number(j) + "/" + QString::number(i), previousDockWidget ); + } + + // create sub-group + auto subGroup = groupManager->createGroup( "SubGroup " + QString::number(j), previousDockWidget ); + previousDockWidget = NULL; + for ( int i = 0; i != 3; ++i ) + { + // Create example content label - this can be any application specific + // widget + QLabel* l = new QLabel(); + l->setWordWrap(true); + l->setAlignment(Qt::AlignTop | Qt::AlignLeft); + l->setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. "); + + previousDockWidget = subGroup->addTabWidget( l, "SubInner " + QString::number(j) + "/" + QString::number(i), previousDockWidget ); + } + } + + m_perspectivesManager->loadPerspectives(); +} + +MainWindow::~MainWindow() +{ + m_perspectivesManager->savePerspectives(); +} + diff --git a/examples/dockindock/mainframe.h b/examples/dockindock/mainframe.h new file mode 100644 index 0000000..0305b36 --- /dev/null +++ b/examples/dockindock/mainframe.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include + +#include +namespace QtAdsUtl +{ + class DockInDockWidget; + class PerspectivesManager; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + + QtAdsUtl::DockInDockWidget* m_dockManager; + std::unique_ptr m_perspectivesManager; +}; + + + + + + diff --git a/examples/dockindock/perspectiveactions.cpp b/examples/dockindock/perspectiveactions.cpp new file mode 100644 index 0000000..1e088c8 --- /dev/null +++ b/examples/dockindock/perspectiveactions.cpp @@ -0,0 +1,39 @@ +#include "perspectiveactions.h" +#include "dockindock.h" +#include "perspectives.h" + +#include + +using namespace QtAdsUtl; + +////////////////////////////// +// LoadPerspectiveAction +////////////////////////////// +LoadPerspectiveAction::LoadPerspectiveAction( QMenu* parent, const QString& name, QtAdsUtl::DockInDockWidget& dockManager ) : + QAction( name, parent ), + name( name ), + dockManager( dockManager ) +{ + connect( this, SIGNAL(triggered()), this, SLOT(load()) ); +} + +void LoadPerspectiveAction::load() +{ + dockManager.getPerspectivesManager()->openPerspective( name, dockManager ); +} + +////////////////////////////// +// RemovePerspectiveAction +////////////////////////////// +RemovePerspectiveAction::RemovePerspectiveAction( QMenu* parent, const QString& name, QtAdsUtl::DockInDockWidget& dockManager ) : + QAction( name, parent ), + name( name ), + dockManager( dockManager ) +{ + connect( this, SIGNAL(triggered()), this, SLOT(remove()) ); +} + +void RemovePerspectiveAction::remove() +{ + dockManager.getPerspectivesManager()->removePerspective( name ); +} diff --git a/examples/dockindock/perspectiveactions.h b/examples/dockindock/perspectiveactions.h new file mode 100644 index 0000000..1614eab --- /dev/null +++ b/examples/dockindock/perspectiveactions.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +namespace QtAdsUtl +{ + +class DockInDockWidget; +class LoadPerspectiveAction : public QAction +{ + Q_OBJECT +public: + LoadPerspectiveAction( QMenu* parent, const QString& name, QtAdsUtl::DockInDockWidget& dockManager ); + +public slots: + void load(); + +private: + QString name; + QtAdsUtl::DockInDockWidget& dockManager; +}; + +class RemovePerspectiveAction : public QAction +{ + Q_OBJECT +public: + RemovePerspectiveAction( QMenu* parent, const QString& name, QtAdsUtl::DockInDockWidget& dockManager ); + +public slots: + void remove(); + +private: + QString name; + QtAdsUtl::DockInDockWidget& dockManager; +}; + +} + diff --git a/examples/dockindock/perspectives.cpp b/examples/dockindock/perspectives.cpp new file mode 100644 index 0000000..29002b3 --- /dev/null +++ b/examples/dockindock/perspectives.cpp @@ -0,0 +1,278 @@ +#include "perspectives.h" +#include "dockindock.h" +#include "dockindockmanager.h" + +#include +#include +#include + +#include + +#define GROUP_PREFIX QString("Group") + +using namespace QtAdsUtl; + +PerspectivesManager::PerspectivesManager( const QString& perspectivesFolder ) : + m_perspectivesFolder( perspectivesFolder ) +{ + +} + +PerspectivesManager::~PerspectivesManager() +{ + // remove temp files: + for ( auto perspective : m_perspectives ) + { + QString fileName = perspective.settings->fileName(); + perspective.settings.reset(); + QFile::remove(fileName); + } +} + + +QStringList PerspectivesManager::perspectiveNames() const +{ + return m_perspectives.keys(); +} + +void PerspectivesManager::addPerspective( const QString& name, DockInDockWidget& widget ) +{ + if ( !m_perspectivesFolder.isEmpty() ) + { + m_perspectives[name].settings = getSettingsObject( getSettingsFileName( name, true ) ); + m_perspectives[name].groups = widget.getManager()->getGroupContents(); + + // save perspective internally + widget.getManager()->addPerspectiveRec( name ); + // store it in QSettings object + widget.getManager()->savePerspectivesRec( *(m_perspectives[name].settings) ); + // remove internal perspectives + widget.getManager()->removePerspectives( widget.getManager()->perspectiveNames() ); + } + else + { + assert( false ); + } + + emit perspectivesListChanged(); +} + + +ads::CDockWidget* findWidget( QString name, const std::vector& managers ) +{ + for ( auto mgr : managers ) + { + auto widget = mgr->findDockWidget(name); + if ( widget ) + return widget; + } + return NULL; +} + +void PerspectivesManager::openPerspective( const QString& name, DockInDockWidget& widget ) +{ + assert( widget.getTopLevelDockWidget() == &widget ); + + if ( !m_perspectivesFolder.isEmpty() ) + { + if ( m_perspectives.contains( name ) ) + { + emit openingPerspective(); + + if ( widget.canCreateNewGroups() ) + { + auto curGroups = widget.getManager()->allManagers(true,true); + for ( auto group : m_perspectives[name].groups.keys() ) + { + bool found = false; + for ( auto curgroup : curGroups ) + { + if ( curgroup->getPersistGroupName() == group ) + { + found = true; + break; + } + } + if ( !found ) + { + group = DockInDockManager::getGroupNameFromPersistGroupName( group ); + + // restore group in file but not in GUI yet + ads::CDockAreaWidget* insertPos = NULL; + widget.createGroup( group, insertPos ); + } + } + + curGroups = widget.getManager()->allManagers(false,true); + for ( auto curgroup : curGroups ) + { + if ( !m_perspectives[name].groups.keys().contains( curgroup->getPersistGroupName() ) ) + { + widget.destroyGroup( &curgroup->parent() ); + } + } + } + + auto managers = widget.getManager()->allManagers(true,true); + for ( auto group : m_perspectives[name].groups.keys() ) + { + for ( auto mgr : managers ) + { + if ( mgr->getPersistGroupName() == group ) + { + for ( QString widgetName : m_perspectives[name].groups[group] ) + { + ads::CDockWidget* widget = findWidget( widgetName, { mgr } ); + if ( widget ) + { + // OK, widget is already in the good manager! + } + else + { + widget = findWidget( widgetName, managers ); + if ( widget ) + { + // move dock widget in the same group as it used to be when perspective was saved + // this guarantee load/open perspectives will work smartly + MoveDockWidgetAction::move( widget, mgr ); + } + } + } + } + } + } + + // internally load perspectives from QSettings + widget.getManager()->loadPerspectivesRec( *(m_perspectives[name].settings) ); + // load perspective (update GUI) + widget.getManager()->openPerspectiveRec( name ); + // remove internal perspectives + widget.getManager()->removePerspectives( widget.getManager()->perspectiveNames() ); + + emit openedPerspective(); + } + } + else + { + assert( false ); + } +} + +void PerspectivesManager::removePerspectives() +{ + m_perspectives.clear(); + emit perspectivesListChanged(); +} + +void PerspectivesManager::removePerspective( const QString& name ) +{ + m_perspectives.remove( name ); + emit perspectivesListChanged(); +} + +QString PerspectivesManager::getSettingsFileName( const QString& perspective, bool temp ) const +{ + auto name = ( perspective.isEmpty() ) ? "perspectives.ini" : "perspective_" + perspective + (temp?".tmp":".ini"); + + return m_perspectivesFolder + "/" + name; +} + +std::shared_ptr PerspectivesManager::getSettingsObject( const QString& filePath ) const +{ + return std::make_shared(filePath, QSettings::IniFormat); +} + +void PerspectivesManager::loadPerspectives() +{ + if ( !m_perspectivesFolder.isEmpty() ) + { + QDir().mkpath( m_perspectivesFolder ); + + m_perspectives.clear(); + + auto mainSettings = getSettingsObject( getSettingsFileName( "", false ) ); + std::string debug = mainSettings->fileName().toStdString(); + + int Size = mainSettings->beginReadArray("Perspectives"); + + for (int i = 0; i < Size; ++i) + { + mainSettings->setArrayIndex(i); + QString perspective = mainSettings->value("Name").toString(); + + if ( !perspective.isEmpty() ) + { + // load perspective file: + auto toLoad = getSettingsFileName( perspective, false ); + auto loaded = getSettingsFileName( perspective, true ); + +#ifdef _DEBUG + std::string debug1 = loaded.toStdString(); + std::string debug2 = toLoad.toStdString(); +#endif + + QFile::remove( loaded ); + if ( !QFile::copy( toLoad, loaded ) ) + assert( false ); + + m_perspectives[perspective].settings = getSettingsObject( loaded ); + + // load group info: + mainSettings->beginGroup(GROUP_PREFIX); + for ( auto key : mainSettings->allKeys() ) + m_perspectives[perspective].groups[key] = mainSettings->value( key ).toStringList(); + mainSettings->endGroup(); + } + else + { + assert( false ); + } + } + + mainSettings->endArray(); + } + + emit perspectivesListChanged(); +} + +void PerspectivesManager::savePerspectives() const +{ + if ( !m_perspectivesFolder.isEmpty() ) + { + auto mainSettings = getSettingsObject( getSettingsFileName( "", false ) ); + + // Save list of perspective and group organization + mainSettings->beginWriteArray("Perspectives", m_perspectives.size()); + int i = 0; + for ( auto perspective : m_perspectives.keys() ) + { + mainSettings->setArrayIndex(i); + mainSettings->setValue("Name", perspective); + mainSettings->beginGroup(GROUP_PREFIX); + for ( auto group : m_perspectives[perspective].groups.keys() ) + { + mainSettings->setValue( group, m_perspectives[perspective].groups[group] ); + } + mainSettings->endGroup(); + ++i; + } + mainSettings->endArray(); + + // Save perspectives themselves + for ( auto perspectiveName : m_perspectives.keys() ) + { + auto toSave = getSettingsFileName( perspectiveName, false ); + QSettings& settings = *(m_perspectives[perspectiveName].settings); + settings.sync(); + +#ifdef _DEBUG + std::string debug1 = settings.fileName().toStdString(); + std::string debug2 = toSave.toStdString(); +#endif + + QFile::remove( toSave ); + if ( !QFile::copy( settings.fileName(), toSave ) ) + assert( false ); + } + } +} diff --git a/examples/dockindock/perspectives.h b/examples/dockindock/perspectives.h new file mode 100644 index 0000000..42592fb --- /dev/null +++ b/examples/dockindock/perspectives.h @@ -0,0 +1,59 @@ +#pragma once + +#include +#include +#include + +#include + +class QMenu; +class QSettings; + +namespace QtAdsUtl +{ + +class DockInDockWidget; +class PerspectivesManager : public QObject +{ + Q_OBJECT + +public: + PerspectivesManager( const QString& perspectivesFolder ); + virtual ~PerspectivesManager(); + + QStringList perspectiveNames() const; + + void addPerspective( const QString& name, DockInDockWidget& widget ); + void openPerspective( const QString& name, DockInDockWidget& widget ); + void removePerspectives(); + void removePerspective( const QString& name ); + + void loadPerspectives(); + void savePerspectives() const; + +signals: + void perspectivesListChanged(); + void openingPerspective(); + void openedPerspective(); + +private: + + // Partially bypass ADS perspective management, store list here + // and then ADS will only have one perspective loaded + // this is because all docking widgets must exist when a perspective is loaded + // we will guarantee that! + class PerspectiveInfo + { + public: + std::shared_ptr settings; + QMap groups; + }; + QMap m_perspectives; + + QString m_perspectivesFolder; + QString getSettingsFileName( const QString& perspective, bool temp ) const; + std::shared_ptr getSettingsObject( const QString& filePath ) const; +}; + +} + diff --git a/examples/examples.pro b/examples/examples.pro index 9e579df..e8680f9 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -6,4 +6,4 @@ SUBDIRS = \ sidebar \ deleteonclose \ emptydockarea \ - dockdepth1 + dockindock