#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 ); } }