Added new and delete component actions
This commit is contained in:
106
src/bedit_gui/commands/component_command.py
Normal file
106
src/bedit_gui/commands/component_command.py
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
from PySide6.QtGui import QUndoCommand
|
||||||
|
|
||||||
|
from bedit_core.models import Component, ComponentID, Connection, ConnectionID, EquationImplementation, Graph, GraphImplementation, Interface
|
||||||
|
|
||||||
|
|
||||||
|
class AddEmptyGraphComponent(QUndoCommand):
|
||||||
|
def __init__(self, document: object, parent: Component) -> None:
|
||||||
|
super().__init__("Add graph component")
|
||||||
|
if not isinstance(parent.implementation, GraphImplementation):
|
||||||
|
raise TypeError("parent component must have a graph implementation")
|
||||||
|
self.document = document
|
||||||
|
self.graph = parent.implementation.graph
|
||||||
|
self.component_id = ComponentID()
|
||||||
|
self.component = Component(name="New Graph Component", interface=Interface(), parameters={}, implementation=GraphImplementation(Graph()))
|
||||||
|
|
||||||
|
def redo(self) -> None:
|
||||||
|
self.graph.components[self.component_id] = self.component
|
||||||
|
self.document.model_changed.emit(self.document.model)
|
||||||
|
|
||||||
|
def undo(self) -> None:
|
||||||
|
del self.graph.components[self.component_id]
|
||||||
|
self.document.model_changed.emit(self.document.model)
|
||||||
|
|
||||||
|
|
||||||
|
class AddEmptyEquationComponent(QUndoCommand):
|
||||||
|
def __init__(self, document: object, parent: Component) -> None:
|
||||||
|
super().__init__("Add equation component")
|
||||||
|
if not isinstance(parent.implementation, GraphImplementation):
|
||||||
|
raise TypeError("parent component must have a graph implementation")
|
||||||
|
self.document = document
|
||||||
|
self.graph = parent.implementation.graph
|
||||||
|
self.component_id = ComponentID()
|
||||||
|
self.component = Component(name="New Equation Component", interface=Interface(), parameters={}, implementation=EquationImplementation())
|
||||||
|
|
||||||
|
def redo(self) -> None:
|
||||||
|
self.graph.components[self.component_id] = self.component
|
||||||
|
self.document.model_changed.emit(self.document.model)
|
||||||
|
|
||||||
|
def undo(self) -> None:
|
||||||
|
del self.graph.components[self.component_id]
|
||||||
|
self.document.model_changed.emit(self.document.model)
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteComponent(QUndoCommand):
|
||||||
|
def __init__(self, document: object, component: Component) -> None:
|
||||||
|
super().__init__("Delete component")
|
||||||
|
self.document = document
|
||||||
|
self.component = component
|
||||||
|
self.components, self.component_id, self.parent_graph = self._find_component(document.model.root, component)
|
||||||
|
self.component_index = list(self.components).index(self.component_id)
|
||||||
|
port_ids = set(component.interface.ports)
|
||||||
|
self.connections: list[tuple[int, ConnectionID, Connection]] = []
|
||||||
|
if self.parent_graph is not None:
|
||||||
|
for index, (connection_id, connection) in enumerate(self.parent_graph.connections.items()):
|
||||||
|
if connection.source in port_ids or connection.target in port_ids:
|
||||||
|
self.connections.append((index, connection_id, connection))
|
||||||
|
self.icons = {}
|
||||||
|
for component_id in self._component_ids(self.component_id, component):
|
||||||
|
icon = document.stored_component_icon(component_id)
|
||||||
|
if icon is not None:
|
||||||
|
self.icons[component_id] = icon
|
||||||
|
|
||||||
|
def redo(self) -> None:
|
||||||
|
if self.parent_graph is not None:
|
||||||
|
for _, connection_id, _ in self.connections:
|
||||||
|
self.parent_graph.connections.pop(connection_id, None)
|
||||||
|
self.components.pop(self.component_id, None)
|
||||||
|
self.document.model_changed.emit(self.document.model)
|
||||||
|
for component_id in self.icons:
|
||||||
|
self.document._set_component_icon(component_id, None)
|
||||||
|
|
||||||
|
def undo(self) -> None:
|
||||||
|
self._restore_item(self.components, self.component_id, self.component, self.component_index)
|
||||||
|
if self.parent_graph is not None:
|
||||||
|
for index, connection_id, connection in self.connections:
|
||||||
|
self._restore_item(self.parent_graph.connections, connection_id, connection, index)
|
||||||
|
self.document.model_changed.emit(self.document.model)
|
||||||
|
for component_id, icon in self.icons.items():
|
||||||
|
self.document._set_component_icon(component_id, icon)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _find_component(cls, components: dict[ComponentID, Component], target: Component, parent_graph: Graph | None = None) -> tuple[dict[ComponentID, Component], ComponentID, Graph | None]:
|
||||||
|
for component_id, component in components.items():
|
||||||
|
if component is target:
|
||||||
|
return components, component_id, parent_graph
|
||||||
|
if isinstance(component.implementation, GraphImplementation):
|
||||||
|
try:
|
||||||
|
return cls._find_component(component.implementation.graph.components, target, component.implementation.graph)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
raise ValueError("component is not part of this document")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _component_ids(cls, component_id: ComponentID, component: Component) -> list[ComponentID]:
|
||||||
|
component_ids = [component_id]
|
||||||
|
if isinstance(component.implementation, GraphImplementation):
|
||||||
|
for child_id, child in component.implementation.graph.components.items():
|
||||||
|
component_ids.extend(cls._component_ids(child_id, child))
|
||||||
|
return component_ids
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _restore_item(items: dict, item_id: object, item: object, index: int) -> None:
|
||||||
|
values = list(items.items())
|
||||||
|
values.insert(index, (item_id, item))
|
||||||
|
items.clear()
|
||||||
|
items.update(values)
|
||||||
@@ -112,6 +112,11 @@ class DocumentTreeController(QObject):
|
|||||||
edit_interface = menu.addAction("Edit Interface")
|
edit_interface = menu.addAction("Edit Interface")
|
||||||
edit_params = menu.addAction("Edit Parameters")
|
edit_params = menu.addAction("Edit Parameters")
|
||||||
edit_icon = menu.addAction("Edit Icon")
|
edit_icon = menu.addAction("Edit Icon")
|
||||||
|
menu.addSeparator()
|
||||||
|
add_graph_component = menu.addAction("Add Graph Component")
|
||||||
|
add_equation_component = menu.addAction("Add Equation Component")
|
||||||
|
menu.addSeparator()
|
||||||
|
delete_component = menu.addAction("Delete Component")
|
||||||
selected = menu.exec(
|
selected = menu.exec(
|
||||||
self.window.ui.documentTree.viewport().mapToGlobal(position)
|
self.window.ui.documentTree.viewport().mapToGlobal(position)
|
||||||
)
|
)
|
||||||
@@ -121,6 +126,12 @@ class DocumentTreeController(QObject):
|
|||||||
self._edit_params(component)
|
self._edit_params(component)
|
||||||
elif selected is edit_icon:
|
elif selected is edit_icon:
|
||||||
self._edit_icon(component)
|
self._edit_icon(component)
|
||||||
|
elif selected is add_graph_component:
|
||||||
|
self._add_graph_component(component)
|
||||||
|
elif selected is add_equation_component:
|
||||||
|
self._add_equation_component(component)
|
||||||
|
elif selected is delete_component:
|
||||||
|
self._delete_component(component)
|
||||||
|
|
||||||
def _edit_interface(self, component: Component) -> None:
|
def _edit_interface(self, component: Component) -> None:
|
||||||
dialog = self.interface_editor_factory(
|
dialog = self.interface_editor_factory(
|
||||||
@@ -149,3 +160,12 @@ class DocumentTreeController(QObject):
|
|||||||
def _icon_editor_closed(self, editor: IconEditorWindow, *_args: object) -> None:
|
def _icon_editor_closed(self, editor: IconEditorWindow, *_args: object) -> None:
|
||||||
if editor in self._icon_editors:
|
if editor in self._icon_editors:
|
||||||
self._icon_editors.remove(editor)
|
self._icon_editors.remove(editor)
|
||||||
|
|
||||||
|
def _add_graph_component(self, component: Component) -> None:
|
||||||
|
self.document.add_empty_graph_component(component)
|
||||||
|
|
||||||
|
def _add_equation_component(self, component: Component) -> None:
|
||||||
|
self.document.add_empty_equation_component(component)
|
||||||
|
|
||||||
|
def _delete_component(self, component: Component) -> None:
|
||||||
|
self.document.delete_component(component)
|
||||||
|
|||||||
@@ -6,13 +6,14 @@ from pathlib import Path
|
|||||||
from PySide6.QtCore import QObject, Signal
|
from PySide6.QtCore import QObject, Signal
|
||||||
from PySide6.QtGui import QUndoStack
|
from PySide6.QtGui import QUndoStack
|
||||||
|
|
||||||
from bedit_core.models import ID, Component, ComponentID, GraphImplementation, Port, PortID, Parameter, ParameterID
|
from bedit_core.models import ID, Component, ComponentID, GraphImplementation, Port, PortID, Parameter, ParameterID, EquationImplementation
|
||||||
from bedit_core.models import Document as CoreDocument
|
from bedit_core.models import Document as CoreDocument
|
||||||
from bedit_gui.commands.change_icon_command import ChangeIconCommand
|
from bedit_gui.commands.change_icon_command import ChangeIconCommand
|
||||||
from bedit_gui.commands.port_commands import AddPortCommand, ChangePortCommand, RemovePortCommand
|
from bedit_gui.commands.port_commands import AddPortCommand, ChangePortCommand, RemovePortCommand
|
||||||
from bedit_gui.commands.param_commands import AddParamCommand, ChangeParamCommand, RemoveParamCommand
|
from bedit_gui.commands.param_commands import AddParamCommand, ChangeParamCommand, RemoveParamCommand
|
||||||
from bedit_gui.commands.rename_component_command import RenameComponentCommand
|
from bedit_gui.commands.rename_component_command import RenameComponentCommand
|
||||||
from bedit_gui.commands.rename_document_command import RenameDocumentCommand
|
from bedit_gui.commands.rename_document_command import RenameDocumentCommand
|
||||||
|
from bedit_gui.commands.component_command import AddEmptyGraphComponent, AddEmptyEquationComponent, DeleteComponent
|
||||||
from bedit_gui.models import Icon, IconDatabase
|
from bedit_gui.models import Icon, IconDatabase
|
||||||
from bedit_gui.services import document_files
|
from bedit_gui.services import document_files
|
||||||
|
|
||||||
@@ -195,3 +196,14 @@ class Document(QObject):
|
|||||||
for command in commands:
|
for command in commands:
|
||||||
self.undo_stack.push(command)
|
self.undo_stack.push(command)
|
||||||
self.undo_stack.endMacro()
|
self.undo_stack.endMacro()
|
||||||
|
|
||||||
|
def add_empty_graph_component(self, component: Component) -> None:
|
||||||
|
if isinstance(component.implementation, GraphImplementation):
|
||||||
|
self.undo_stack.push(AddEmptyGraphComponent(self, component))
|
||||||
|
|
||||||
|
def add_empty_equation_component(self, component: Component) -> None:
|
||||||
|
if isinstance(component.implementation, GraphImplementation):
|
||||||
|
self.undo_stack.push(AddEmptyEquationComponent(self, component))
|
||||||
|
|
||||||
|
def delete_component(self, component: Component) -> None:
|
||||||
|
self.undo_stack.push(DeleteComponent(self, component))
|
||||||
|
|||||||
Reference in New Issue
Block a user