File: dockindock.py

package info (click to toggle)
qt-advanced-docking-system 3.8.3-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 13,600 kB
  • sloc: cpp: 11,678; python: 2,623; makefile: 12
file content (203 lines) | stat: -rw-r--r-- 8,645 bytes parent folder | download
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)")