From 733c005eeaf5d3ff15e0f60d320f5c03472bad60 Mon Sep 17 00:00:00 2001 From: tassaron Date: Mon, 14 Aug 2017 18:41:45 -0400 Subject: [PATCH] undoable removeComponent action --- src/command.py | 1 + src/component.py | 3 +-- src/core.py | 36 ++++++++++++++++++++++++------------ src/gui/actions.py | 37 +++++++++++++++++++++++++++++++++++++ src/gui/mainwindow.py | 28 +++++++++++++++------------- src/gui/presetmanager.py | 7 +------ src/main.py | 4 ++-- 7 files changed, 81 insertions(+), 35 deletions(-) create mode 100644 src/gui/actions.py diff --git a/src/command.py b/src/command.py index 18f7408..4116c5a 100644 --- a/src/command.py +++ b/src/command.py @@ -19,6 +19,7 @@ class Command(QtCore.QObject): def __init__(self): QtCore.QObject.__init__(self) self.core = Core() + Core.mode = 'commandline' self.dataDir = self.core.dataDir self.canceled = False diff --git a/src/component.py b/src/component.py index cf3085c..0e5144c 100644 --- a/src/component.py +++ b/src/component.py @@ -59,9 +59,8 @@ class ComponentMetaclass(type(QtCore.QObject)): '''Intercepts the command() method to check for global args''' def commandWrapper(self, arg): if arg.startswith('preset='): - from presetmanager import getPresetDir _, preset = arg.split('=', 1) - path = os.path.join(getPresetDir(self), preset) + path = os.path.join(self.core.getPresetDir(self), preset) if not os.path.exists(path): print('Couldn\'t locate preset "%s"' % preset) quit(1) diff --git a/src/core.py b/src/core.py index 4dfb210..20b9c1d 100644 --- a/src/core.py +++ b/src/core.py @@ -64,31 +64,39 @@ class Core: for i, component in enumerate(self.selectedComponents): component.compPos = i - def insertComponent(self, compPos, moduleIndex, loader): + def insertComponent(self, compPos, component, loader): ''' Creates a new component using these args: - (compPos, moduleIndex in self.modules, MWindow/Command/Core obj) + (compPos, component obj or moduleIndex, MWindow/Command/Core obj) ''' if compPos < 0 or compPos > len(self.selectedComponents): compPos = len(self.selectedComponents) if len(self.selectedComponents) > 50: return None - log.debug('Inserting Component from module #%s' % moduleIndex) - component = self.modules[moduleIndex].Component( - moduleIndex, compPos, self + if type(component) is int: + # create component using module index in self.modules + moduleIndex = int(component) + log.debug('Creating new component from module #%s' % moduleIndex) + component = self.modules[moduleIndex].Component( + moduleIndex, compPos, self + ) + # init component's widget for loading/saving presets + component.widget(loader) + else: + moduleIndex = -1 + log.debug( + 'Inserting previously-created %s component' % component.name) + + component._error.connect( + loader.videoThreadError ) self.selectedComponents.insert( compPos, component ) self.componentListChanged() - self.selectedComponents[compPos]._error.connect( - loader.videoThreadError - ) - - # init component's widget for loading/saving presets - self.selectedComponents[compPos].widget(loader) - self.updateComponent(compPos) + if moduleIndex > -1: + self.updateComponent(compPos) if hasattr(loader, 'insertComponent'): loader.insertComponent(compPos) @@ -156,6 +164,10 @@ class Core: break return saveValueStore + def getPresetDir(self, comp): + '''Get the preset subdir for a particular version of a component''' + return os.path.join(Core.presetDir, str(comp), str(comp.version)) + def openProject(self, loader, filepath): ''' loader is the object calling this method which must have its own showMessage(**kwargs) method for displaying errors. diff --git a/src/gui/actions.py b/src/gui/actions.py new file mode 100644 index 0000000..5cf64e1 --- /dev/null +++ b/src/gui/actions.py @@ -0,0 +1,37 @@ +''' + QCommand classes for every undoable user action performed in the MainWindow +''' +from PyQt5.QtWidgets import QUndoCommand + + +class RemoveComponent(QUndoCommand): + def __init__(self, parent, selectedRows): + super().__init__('Remove component') + self.parent = parent + componentList = self.parent.window.listWidget_componentList + self.selectedRows = [ + componentList.row(selected) for selected in selectedRows + ] + self.components = [ + parent.core.selectedComponents[i] for i in self.selectedRows + ] + + def redo(self): + stackedWidget = self.parent.window.stackedWidget + componentList = self.parent.window.listWidget_componentList + for index in self.selectedRows: + stackedWidget.removeWidget(self.parent.pages[index]) + componentList.takeItem(index) + self.parent.core.removeComponent(index) + self.parent.pages.pop(index) + self.parent.changeComponentWidget() + self.parent.drawPreview() + + def undo(self): + componentList = self.parent.window.listWidget_componentList + for index, comp in zip(self.selectedRows, self.components): + self.parent.core.insertComponent( + index, comp, self.parent + ) + self.parent.drawPreview() + diff --git a/src/gui/mainwindow.py b/src/gui/mainwindow.py index af6e190..2edb750 100644 --- a/src/gui/mainwindow.py +++ b/src/gui/mainwindow.py @@ -16,9 +16,10 @@ import time import logging from core import Core -import preview_thread -from preview_win import PreviewWindow -from presetmanager import PresetManager +import gui.preview_thread as preview_thread +from gui.preview_win import PreviewWindow +from gui.presetmanager import PresetManager +from gui.actions import * from toolkit import disableWhenEncoding, disableWhenOpeningProject, checkOutput @@ -43,9 +44,12 @@ class MainWindow(QtWidgets.QMainWindow): QtWidgets.QMainWindow.__init__(self) self.window = window self.core = Core() + Core.mode = 'GUI' log.debug( 'Main thread id: {}'.format(int(QtCore.QThread.currentThreadId()))) + self.undoStack = QtWidgets.QUndoStack(self) + # widgets of component settings self.pages = [] self.lastAutosave = time.time() @@ -62,7 +66,7 @@ class MainWindow(QtWidgets.QMainWindow): self.presetManager = PresetManager( uic.loadUi( - os.path.join(Core.wd, 'presetmanager.ui')), self) + os.path.join(Core.wd, 'gui', 'presetmanager.ui')), self) # Create the preview window and its thread, queues, and timers log.debug('Creating preview window') @@ -298,6 +302,9 @@ class MainWindow(QtWidgets.QMainWindow): QtWidgets.QShortcut("Ctrl+A", self.window, self.openSaveProjectDialog) QtWidgets.QShortcut("Ctrl+O", self.window, self.openOpenProjectDialog) QtWidgets.QShortcut("Ctrl+N", self.window, self.createNewProject) + QtWidgets.QShortcut("Ctrl+Z", self.window, self.undoStack.undo) + QtWidgets.QShortcut("Ctrl+Y", self.window, self.undoStack.redo) + QtWidgets.QShortcut("Ctrl+Shift+Z", self.window, self.undoStack.redo) # Hotkeys for component list for inskey in ("Ctrl+T", QtCore.Qt.Key_Insert): @@ -685,15 +692,10 @@ class MainWindow(QtWidgets.QMainWindow): def removeComponent(self): componentList = self.window.listWidget_componentList - - for selected in componentList.selectedItems(): - index = componentList.row(selected) - self.window.stackedWidget.removeWidget(self.pages[index]) - componentList.takeItem(index) - self.core.removeComponent(index) - self.pages.pop(index) - self.changeComponentWidget() - self.drawPreview() + selected = componentList.selectedItems() + if selected: + action = RemoveComponent(self, selected) + self.undoStack.push(action) @disableWhenEncoding def moveComponent(self, change): diff --git a/src/gui/presetmanager.py b/src/gui/presetmanager.py index b1eeb34..1cc0887 100644 --- a/src/gui/presetmanager.py +++ b/src/gui/presetmanager.py @@ -302,7 +302,7 @@ class PresetManager(QtWidgets.QDialog): self.findPresets() self.drawPresetList() for i, comp in enumerate(self.core.selectedComponents): - if getPresetDir(comp) == path \ + if self.core.getPresetDir(comp) == path \ and comp.currentPreset == oldName: self.core.openPreset(newPath, i, newName) self.parent.updateComponentTitle(i, False) @@ -351,8 +351,3 @@ class PresetManager(QtWidgets.QDialog): def clearPresetListSelection(self): self.window.listWidget_presets.setCurrentRow(-1) - - -def getPresetDir(comp): - '''Get the preset subdir for a particular version of a component''' - return os.path.join(Core.presetDir, str(comp), str(comp.version)) diff --git a/src/main.py b/src/main.py index 3a6fbe7..c1278da 100644 --- a/src/main.py +++ b/src/main.py @@ -35,11 +35,11 @@ def main(): log.debug("Finished creating command object") elif mode == 'GUI': - from mainwindow import MainWindow + from gui.mainwindow import MainWindow import atexit import signal - window = uic.loadUi(os.path.join(wd, "mainwindow.ui")) + window = uic.loadUi(os.path.join(wd, "gui", "mainwindow.ui")) # window.adjustSize() desc = QtWidgets.QDesktopWidget() dpi = desc.physicalDpiX()