From ffa0105d3ecb16180c5e1423dda92c6fc6cbccea Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 13 Apr 2021 07:05:17 +0200 Subject: [PATCH 1/4] Fixed emission perspectiveListChanged signal after loading of perspective list and added perspectiveListLoaded signal --- .settings/language.settings.xml | 2 +- examples/emptydockarea/mainwindow.cpp | 2 +- src/DockManager.cpp | 2 ++ src/DockManager.h | 9 ++++++++- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index 908591c..c8d87f4 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -5,7 +5,7 @@ - + diff --git a/examples/emptydockarea/mainwindow.cpp b/examples/emptydockarea/mainwindow.cpp index c8975a8..afdcfe9 100644 --- a/examples/emptydockarea/mainwindow.cpp +++ b/examples/emptydockarea/mainwindow.cpp @@ -68,7 +68,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); auto TableArea = DockManager->addDockWidget(DockWidgetArea::LeftDockWidgetArea, TableDockWidget); - //DockManager->addDockWidget(DockWidgetArea::BottomDockWidgetArea, TableDockWidget, TableArea); + DockManager->addDockWidget(DockWidgetArea::BottomDockWidgetArea, TableDockWidget, TableArea); ui->menuView->addAction(TableDockWidget->toggleViewAction()); QTableWidget* propertiesTable = new QTableWidget(); diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 4b14f9a..45df361 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -912,6 +912,8 @@ void CDockManager::loadPerspectives(QSettings& Settings) } Settings.endArray(); + Q_EMIT perspectiveListChanged(); + Q_EMIT perspectiveListLoaded(); } diff --git a/src/DockManager.h b/src/DockManager.h index 9681d09..390e283 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -521,10 +521,17 @@ public Q_SLOTS: Q_SIGNALS: /** - * This signal is emitted if the list of perspectives changed + * This signal is emitted if the list of perspectives changed. + * The list of perspectives changes if perspectives are added, removed + * or if the perspective list has been loaded */ void perspectiveListChanged(); + /** + * This signal is emitted if the perspective list has been loaded + */ + void perspectiveListLoaded(); + /** * This signal is emitted if perspectives have been removed */ From 2f041a0eed885a6ac7da72ec8b1182ec64b76d9f Mon Sep 17 00:00:00 2001 From: jporcher Date: Tue, 20 Apr 2021 14:25:30 +0200 Subject: [PATCH 2/4] Fix memory leaks (#314) --- src/DockManager.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 45df361..42f61b8 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -505,6 +505,20 @@ CDockManager::CDockManager(QWidget *parent) : //============================================================================ CDockManager::~CDockManager() { + // fix memory leaks, see https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues/307 + std::vector areas; + for ( int i = 0; i != dockAreaCount(); ++i ) + { + areas.push_back( dockArea(i) ); + } + for ( auto area : areas ) + { + for ( auto widget : area->dockWidgets() ) + delete widget; + + delete area; + } + auto FloatingWidgets = d->FloatingWidgets; for (auto FloatingWidget : FloatingWidgets) { From 0e8e5636544b4aa37a0d7041802350e4a608f947 Mon Sep 17 00:00:00 2001 From: jporcher Date: Wed, 21 Apr 2021 06:37:19 +0200 Subject: [PATCH 3/4] Add dockindock example (#308) * Add dockdepth1 example * Fix compilation (include assert.h) * Replace dockdepth1 by dockindock --- examples/dockindock/CMakeLists.txt | 28 ++ examples/dockindock/dockindock.cpp | 296 +++++++++++++++++ examples/dockindock/dockindock.h | 80 +++++ examples/dockindock/dockindock.pro | 35 ++ examples/dockindock/dockindockmanager.cpp | 359 +++++++++++++++++++++ examples/dockindock/dockindockmanager.h | 96 ++++++ examples/dockindock/main.cpp | 11 + 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 | 3 +- 14 files changed, 1427 insertions(+), 1 deletion(-) create mode 100644 examples/dockindock/CMakeLists.txt create mode 100644 examples/dockindock/dockindock.cpp create mode 100644 examples/dockindock/dockindock.h create mode 100644 examples/dockindock/dockindock.pro create mode 100644 examples/dockindock/dockindockmanager.cpp create mode 100644 examples/dockindock/dockindockmanager.h create mode 100644 examples/dockindock/main.cpp 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/dockindock/CMakeLists.txt b/examples/dockindock/CMakeLists.txt new file mode 100644 index 0000000..c2a70b6 --- /dev/null +++ b/examples/dockindock/CMakeLists.txt @@ -0,0 +1,28 @@ +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(DockInDock WIN32 + dockindock.cpp + dockindockmanager.cpp + perspectiveactions.cpp + perspectives.cpp + main.cpp + mainframe.cpp +) +target_include_directories(SimpleExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src") +target_link_libraries(SimpleExample PRIVATE qtadvanceddocking) +target_link_libraries(SimpleExample PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets) +set_target_properties(SimpleExample PROPERTIES + AUTOMOC ON + AUTORCC ON + AUTOUIC ON + CXX_STANDARD 14 + CXX_STANDARD_REQUIRED ON + CXX_EXTENSIONS OFF + VERSION ${VERSION_SHORT} + EXPORT_NAME "Qt Advanced Docking System Simple Example" + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin" +) 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/dockindock/dockindock.pro b/examples/dockindock/dockindock.pro new file mode 100644 index 0000000..45242d1 --- /dev/null +++ b/examples/dockindock/dockindock.pro @@ -0,0 +1,35 @@ +ADS_OUT_ROOT = $${OUT_PWD}/../.. + +QT += core gui widgets + +TARGET = DockInDock +DESTDIR = $${ADS_OUT_ROOT}/lib +TEMPLATE = app +CONFIG += c++14 +CONFIG += debug_and_release +adsBuildStatic { + DEFINES += ADS_STATIC +} + +DEFINES += QT_DEPRECATED_WARNINGS + +SOURCES += \ + dockindock.cpp \ + dockindockmanager.cpp \ + perspectiveactions.cpp \ + perspectives.cpp \ + main.cpp \ + mainframe.cpp + +HEADERS += \ + dockindock.h \ + dockindockmanager.h \ + perspectiveactions.h \ + perspectives.h \ + mainframe.h + +LIBS += -L$${ADS_OUT_ROOT}/lib +include(../../ads.pri) +INCLUDEPATH += ../../src +DEPENDPATH += ../../src + 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/dockindock/main.cpp b/examples/dockindock/main.cpp new file mode 100644 index 0000000..83e8bb7 --- /dev/null +++ b/examples/dockindock/main.cpp @@ -0,0 +1,11 @@ +#include +#include "../../examples/simple/MainWindow.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} 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 86ac5b0..e8680f9 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -5,4 +5,5 @@ SUBDIRS = \ simple \ sidebar \ deleteonclose \ - emptydockarea + emptydockarea \ + dockindock From b39cd2d81be371bd65f1a9f5200c128c76df7461 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 27 Apr 2021 07:47:03 +0200 Subject: [PATCH 4/4] Fixed emptydockarea example --- examples/emptydockarea/mainwindow.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/emptydockarea/mainwindow.cpp b/examples/emptydockarea/mainwindow.cpp index afdcfe9..2dbe99c 100644 --- a/examples/emptydockarea/mainwindow.cpp +++ b/examples/emptydockarea/mainwindow.cpp @@ -56,7 +56,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); DockManager->addDockWidgetTabToArea(TableDockWidget, CentralDockArea); - //auto TableArea = DockManager->addDockWidget(DockWidgetArea::LeftDockWidgetArea, TableDockWidget); + auto TableArea = DockManager->addDockWidget(DockWidgetArea::LeftDockWidgetArea, TableDockWidget); ui->menuView->addAction(TableDockWidget->toggleViewAction()); table = new QTableWidget(); @@ -67,7 +67,6 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); - auto TableArea = DockManager->addDockWidget(DockWidgetArea::LeftDockWidgetArea, TableDockWidget); DockManager->addDockWidget(DockWidgetArea::BottomDockWidgetArea, TableDockWidget, TableArea); ui->menuView->addAction(TableDockWidget->toggleViewAction());