1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
|
import sys
from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QMessageBox,
QInputDialog, QMenu, QLineEdit)
from PyQt5.QtGui import QIcon
from PyQtAds import QtAds
from dockindockmanager import DockInDockManager
from perspectiveactions import LoadPerspectiveAction, RemovePerspectiveAction
class DockInDockWidget(QWidget):
def __init__(self, parent, perspectives_manager: 'PerspectivesManager', can_create_new_groups: bool = False, top_level_widget = None):
super().__init__(parent)
if top_level_widget is not None:
self.__can_create_new_groups = top_level_widget.can_create_new_groups
else:
self.__can_create_new_groups = can_create_new_groups
self.__top_level_dock_widget = top_level_widget if top_level_widget else self
self.__perspectives_manager = perspectives_manager
self.__new_perspective_default_name: str = ''
layout = QVBoxLayout(self)
layout.setContentsMargins(0,0,0,0)
self.__mgr = DockInDockManager(self)
layout.addWidget(self.__mgr)
def getManager(self) -> 'DockInDockManager':
return self.__mgr
def getTopLevelDockWidget(self) -> 'DockInDockWidget':
return self.__top_level_dock_widget
def canCreateNewGroups(self) -> bool:
return self.__can_create_new_groups
def getPerspectivesManager(self) -> 'PerspectivesManager':
return self.__perspectives_manager
def addTabWidget(self, widget: QWidget, name: str, after: QtAds.CDockAreaWidget, icon = QIcon()) -> QtAds.CDockAreaWidget:
for existing in self.getTopLevelDockWidget().getManager().allDockWidgets(True, True):
if existing[1].objectName() == name:
QMessageBox.critical(self, "Error", "Name '" + name + "' already in use")
return
dock_widget = QtAds.CDockWidget(name)
dock_widget.setWidget(widget)
dock_widget.setIcon(icon)
# Add the dock widget to the top dock widget area
return self.__mgr.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, after)
def isTopLevel(self) -> bool:
return not self.objectName()
def getGroupNameError(self, group_name: str) -> str:
if not group_name:
return "Group must have a non-empty name"
dock_managers = self.__mgr.allManagers(True, True)
for mgr in dock_managers:
if mgr.getGroupName() == group_name:
return "Group name '" + group_name + "' already used"
return ""
def createGroup(self, group_name: str, insert_pos: QtAds.CDockAreaWidget, icon = QIcon()) -> 'DockInDockWidget':
error = self.getGroupNameError(group_name)
if error:
QMessageBox.critical(None, "Error", error)
return
child = DockInDockWidget(self, self.__top_level_dock_widget, self.__perspectives_manager)
child.setObjectName(group_name)
dock_widget = QtAds.CDockWidget(group_name)
dock_widget.setWidget(child)
dock_widget.setIcon(icon)
insert_pos = self.__mgr.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, insert_pos)
return child, insert_pos
def destroyGroup(self, widget_to_remove: 'DockInDockWidget') -> None:
top_level_widget = widget_to_remove.getTopLevelDockWidget()
if top_level_widget and top_level_widget != widget_to_remove:
for dock_widget in widget_to_remove.getManager().getWidgetsInGUIOrder(): #don't use allDockWidgets to preserve sub-groups
MoveDockWidgetAction.move(dock_widget, top_level_widget.getManager())
assert not widget_to_remove.getManager().allDockWidgets(True, True)
# find widget's parent:
for dock_widget in top_level_widget.getManager().allDockWidgets(True, True):
if dockwidget[1].widget() == widget_to_remove:
dockwidget[0].removeDockWidget(dockwidget[1])
del dockwidget[1]
# delete widgetToRemove; automatically deleted when dockWidget is deleted
widget_to_remove = None
break
assert widget_to_remove == None
else:
assert False
def attachViewMenu(self, menu: QMenu) -> None:
menu.aboutToShow.connect(self.autoFillAttachedViewMenu)
def autoFillAttachedViewMenu(self) -> None:
menu = self.sender()
if menu:
menu.clear()
self.setupViewMenu(menu)
else:
assert False
def setupViewMenu(self, menu):
dock_managers = self.__mgr.allManagers(True, True)
has_perspectives_menu = False
if self.getTopLevelDockWidget() == self:
has_perspectives_menu = (self.__perspectives_manager != None)
else:
assert False
organize = menu
if has_perspectives_menu:
organize = menu.addMenu("Organize")
self.setupMenu(organize, dock_managers)
if has_perspectives_menu:
perspectives = menu.addMenu("Perspectives")
self.fillPerspectivesMenu(perspectives)
def setupMenu(self, menu: QMenu, move_to: 'list[DockInDockManager]') -> None:
self.__mgr.fillViewMenu(menu, move_to)
menu.addSeparator()
move_menu = menu.addMenu("Move")
self.__mgr.fillMoveMenu(move_menu, move_to)
def fillPerspectivesMenu(self, menu: QMenu):
menu.addAction("Create perspective...", self.createPerspective)
perspectives_names = []
if self.__perspectives_manager:
perspectives_names = self.__perspectives_manager.perspectiveNames()
if perspectives_names:
load = menu.addMenu("Load perspective")
for name in perspectives_names:
load.addAction(LoadPerspectiveAction(load, name, self))
remove = menu.addMenu("Remove perspective")
for name in perspectives_names:
remove.addAction(RemovePerspectiveAction(remove, name, self))
def setNewPerspectiveDefaultName(default_name: str) -> None:
self.__new_perspective_default_name = default_name
def createPerspective(self) -> None:
if not self.__perspectives_manager:
return
name = self.__new_perspective_default_name
if self.__new_perspective_default_name:
index = 2
while name in self.__perspectives_manager.perspectiveNames():
name = f"{self.__new_perspective_default_name}({index})"
index += 1
while True:
name, ok = QInputDialog.getText(None, "Create perspective", "Enter perspective name", QLineEdit.Normal, name)
if ok:
if not name:
QMessageBox.critical(None, "Error", "Perspective name cannot be empty")
continue
elif name in self.__perspectives_manager.perspectiveNames():
if QMessageBox.critical(None, "Error", f"Perspective '{name}' already exists, overwrite it?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) == QMessageBox.No:
continue
self.__perspectives_manager.addPerspective(name, self)
break
else:
break
def dumpStatus(self, echo: callable = print, widget: QtAds.CDockWidget = None, tab: str = '', suffix: str = '') -> str:
if widget is not None:
as_mgr = DockInDockManager.dockInAManager(widget)
if as_mgr:
as_mgr.parent().dumpStatus(tab=tab)
else:
echo(tab + widget.objectName() + suffix)
else:
echo(tab + "Group: " + self.getManager().getGroupName())
tab += " "
visible_widgets = set()
for widget in self.getManager().getWidgetsInGUIOrder():
visible_widgets.add(widget)
self.dumpStatus(widget=widget, tab=tab)
for closed in self.getManager().dockWidgetsMap().values():
if not closed in visible_widgets:
self.dumpStatus(widget=closed, tab=tab, suffix=" (closed)")
|