mirror of
https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System.git
synced 2024-12-26 16:01:36 +08:00
203 lines
8.8 KiB
Python
203 lines
8.8 KiB
Python
|
import os
|
||
|
import tempfile
|
||
|
import shutil
|
||
|
import atexit
|
||
|
|
||
|
from PyQt5.QtCore import pyqtSignal, QSettings, QObject
|
||
|
from PyQtAds import QtAds
|
||
|
|
||
|
from dockindockmanager import DockInDockManager
|
||
|
from dockindock import DockInDockWidget
|
||
|
|
||
|
GROUP_PREFIX = "Group"
|
||
|
|
||
|
def findWidget(name, managers: 'list[DockInDockManager]') -> QtAds.CDockWidget:
|
||
|
for mgr in managers:
|
||
|
widget = mgr.findDockWidget(name)
|
||
|
if widget:
|
||
|
return widget
|
||
|
|
||
|
|
||
|
class PerspectiveInfo:
|
||
|
# 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!
|
||
|
|
||
|
settings = QSettings()
|
||
|
groups: 'dict[str, list[str]]' = {}
|
||
|
|
||
|
|
||
|
class PerspectivesManager(QObject):
|
||
|
perspectivesListChanged = pyqtSignal()
|
||
|
openingPerspective = pyqtSignal()
|
||
|
openedPerspective = pyqtSignal()
|
||
|
|
||
|
def __init__(self, perspectives_folder):
|
||
|
super().__init__()
|
||
|
self.__perspectives_folder = perspectives_folder
|
||
|
self.__perspectives = {}
|
||
|
atexit.register(self.cleanup)
|
||
|
|
||
|
def cleanup(self):
|
||
|
for perspective in self.__perspectives.values():
|
||
|
filename = perspective.settings.fileName()
|
||
|
try:
|
||
|
os.remove(filename)
|
||
|
except FileNotFoundError:
|
||
|
pass
|
||
|
|
||
|
def perspectiveNames(self) -> 'list[str]':
|
||
|
return self.__perspectives.keys()
|
||
|
|
||
|
def addPerspective(self, name: str, widget: DockInDockWidget) -> None:
|
||
|
if self.__perspectives_folder:
|
||
|
self.__perspectives[name] = perspective = PerspectiveInfo()
|
||
|
perspective.settings = self.getSettingsObject(self.getSettingsFileName(name, True))
|
||
|
perspective.groups = widget.getManager().getGroupContents()
|
||
|
|
||
|
# save perspective internally
|
||
|
widget.getManager().addPerspectiveRec(name)
|
||
|
# store it in QSettings object
|
||
|
widget.getManager().savePerspectivesRec(perspective.settings)
|
||
|
# remove internal perspectives
|
||
|
widget.getManager().removePerspectives(widget.getManager().perspectiveNames())
|
||
|
|
||
|
self.perspectivesListChanged.emit()
|
||
|
|
||
|
def openPerspective(name: str, widget: DockInDockWidget) -> None:
|
||
|
assert widget.getTopLevelDockWidget() == widget
|
||
|
|
||
|
if self.__perspectives_folder:
|
||
|
if name in self.__perspectives:
|
||
|
self.openingPerspective.emit()
|
||
|
|
||
|
if widget.canCreateNewGroups():
|
||
|
cur_groups = widget.getManager().allManagers(True, True)
|
||
|
for group in self.__perspectives[name].groups.keys():
|
||
|
found = False
|
||
|
for curgroup in cur_groups:
|
||
|
if curgroup.getPerspectiveGroupName() == group:
|
||
|
found = True
|
||
|
break
|
||
|
if not found:
|
||
|
group = DockInDockManager.getGroupNameFromPersistGroupName(group)
|
||
|
|
||
|
# restore group in file but not in GUI yet
|
||
|
widget.createGroup(group, None)
|
||
|
|
||
|
cur_groups = widget.getManager().allManagers(False, True)
|
||
|
for curgroup in cur_groups:
|
||
|
if curgroup.getPersistGroupName() not in self.__perspectives[name].groups.keys():
|
||
|
widget.destroyGroup(curgroup.parent())
|
||
|
|
||
|
managers = widget.getManager().allManagers(True, True)
|
||
|
for group in self.__perspectives[name].groups().keys():
|
||
|
for mgr in managers:
|
||
|
if mgr.getPersistGroupName() == group:
|
||
|
for widget_name in self.__perspectives[name].groups[group]:
|
||
|
widget = findWidget(widget_name, [mgr])
|
||
|
if widget:
|
||
|
pass # OK, widget is already in the good manager!
|
||
|
else:
|
||
|
widget = findWidget(widget_name, 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(self.__perspectives[name].settings)
|
||
|
# load perspective (update GUI)
|
||
|
widget.getManager().openPerspectiveRec(name)
|
||
|
# remove internal perspectives
|
||
|
widget.getManager().removePerspectives(widget.getManager().perspectiveNames())
|
||
|
|
||
|
self.openedPerspective().emit()
|
||
|
else:
|
||
|
assert False
|
||
|
|
||
|
def removePerspectives(self) -> None:
|
||
|
self.__perspectives.clear()
|
||
|
self.perspectivesListChanged.emit()
|
||
|
|
||
|
def removePerspective(self, name: str) -> None:
|
||
|
del self.__perspectives[name]
|
||
|
self.perspectivesListChanged.emit()
|
||
|
|
||
|
def getSettingsFileName(self, perspective: str, temp: bool) -> str:
|
||
|
name = "perspectives.ini" if not perspective else f"perspectives_{perspective + '.tmp' if temp else perspective + '.ini'}"
|
||
|
|
||
|
return os.path.join(self.__perspectives_folder, name)
|
||
|
|
||
|
def getSettingsObject(self, file_path: str) -> QSettings:
|
||
|
return QSettings(file_path, QSettings.IniFormat)
|
||
|
|
||
|
def loadPerspectives(self) -> None:
|
||
|
if self.__perspectives_folder:
|
||
|
tempfile.mktemp(dir=self.__perspectives_folder)
|
||
|
|
||
|
self.__perspectives.clear()
|
||
|
|
||
|
main_settings = self.getSettingsObject(self.getSettingsFileName("", False))
|
||
|
debug = main_settings.fileName()
|
||
|
|
||
|
size = main_settings.beginReadArray("Perspectives")
|
||
|
|
||
|
for i in range(0, size):
|
||
|
main_settings.setArrayIndex(i)
|
||
|
perspective = main_settings.value("Name")
|
||
|
|
||
|
if perspective:
|
||
|
to_load = self.getSettingsFileName(perspective, False)
|
||
|
loaded = self.getSettingsFileName(perspective, True)
|
||
|
|
||
|
try:
|
||
|
os.remove(loaded)
|
||
|
except FileNotFoundError:
|
||
|
pass
|
||
|
if not shutil.copy(to_load, loaded):
|
||
|
assert False
|
||
|
|
||
|
self.__perspectives[perspective] = PerspectiveInfo()
|
||
|
self.__perspectives[perspective].settings = self.getSettingsObject(loaded)
|
||
|
|
||
|
# load group info:
|
||
|
main_settings.beginGroup(GROUP_PREFIX)
|
||
|
for key in main_settings.allKeys():
|
||
|
self.__perspectives[perspective].groups[key] = main_settings.value(key)
|
||
|
main_settings.endGroup()
|
||
|
else:
|
||
|
assert False
|
||
|
|
||
|
main_settings.endArray()
|
||
|
|
||
|
self.perspectivesListChanged.emit()
|
||
|
|
||
|
def savePerspectives(self) -> None:
|
||
|
if self.__perspectives_folder:
|
||
|
main_settings = self.getSettingsObject(self.getSettingsFileName("", False))
|
||
|
|
||
|
# Save list of perspective and group organization
|
||
|
main_settings.beginWriteArray("Perspectives", len(self.__perspectives))
|
||
|
for i, perspective in enumerate(self.__perspectives.keys()):
|
||
|
main_settings.setArrayIndex(i)
|
||
|
main_settings.setValue("Name", perspective)
|
||
|
main_settings.beginGroup(GROUP_PREFIX)
|
||
|
for group in self.__perspectives[perspective].groups.keys():
|
||
|
main_settings.setValue(group, list(self.__perspectives[perspective].groups[group]))
|
||
|
main_settings.endGroup()
|
||
|
main_settings.endArray()
|
||
|
|
||
|
# Save perspectives themselves
|
||
|
for perspective_name in self.__perspectives.keys():
|
||
|
to_save = self.getSettingsFileName(perspective_name, False)
|
||
|
settings = self.__perspectives[perspective_name].settings
|
||
|
settings.sync()
|
||
|
|
||
|
try:
|
||
|
os.remove(to_save)
|
||
|
except FileNotFoundError:
|
||
|
pass
|
||
|
if not shutil.copy(settings.fileName(), to_save):
|
||
|
assert False
|