new text mode editor
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
import json
|
||||
from copy import deepcopy
|
||||
from pathlib import Path
|
||||
|
||||
@@ -13,7 +12,7 @@ from PySide6.QtWidgets import (
|
||||
QTabWidget,
|
||||
)
|
||||
|
||||
from bedit.core.model import Component, Port
|
||||
from bedit.core.model import Component, Parameter
|
||||
from bedit.core.serializer import JsonDocumentSerializer
|
||||
from bedit.gui.controllers.document import DocumentController
|
||||
from bedit.gui.dialogs.component_options import ComponentOptionsDialog
|
||||
@@ -40,6 +39,7 @@ class MainWindow(QMainWindow):
|
||||
self.ui = Ui_MainWindow()
|
||||
self.ui.setupUi(self)
|
||||
self.settings = application_settings()
|
||||
self._applying_text_definition = False
|
||||
|
||||
self.libraries = LibraryRepository(self)
|
||||
self.document_controller = DocumentController(self)
|
||||
@@ -108,12 +108,18 @@ class MainWindow(QMainWindow):
|
||||
self.ui.lineToolButton.clicked.connect(lambda: self.set_graph_tool("line"))
|
||||
self.ui.textToolButton.clicked.connect(lambda: self.set_graph_tool("text"))
|
||||
self.ui.rotateToolButton.clicked.connect(self.ui.graphView.rotate_selected)
|
||||
self.ui.applyJsonButton.clicked.connect(self.apply_json)
|
||||
self.ui.textDefinitionEditor.definitionEdited.connect(
|
||||
self.apply_text_definition
|
||||
)
|
||||
self.document_controller.activeGraphChanged.connect(self._active_graph_changed)
|
||||
self.document_controller.textDefinitionChanged.connect(
|
||||
self._text_definition_changed
|
||||
)
|
||||
|
||||
def _connect_actions(self) -> None:
|
||||
self.ui.actionNew.triggered.connect(self.new_document)
|
||||
self.ui.actionOpen.triggered.connect(self.open_document)
|
||||
self.ui.actionReloadLibraries.triggered.connect(self.reload_libraries)
|
||||
self.ui.actionSave.triggered.connect(self.save_document)
|
||||
self.ui.actionSaveAs.triggered.connect(self.save_document_as)
|
||||
self.ui.actionClose.triggered.connect(self.close_document)
|
||||
@@ -189,7 +195,6 @@ class MainWindow(QMainWindow):
|
||||
self.ui.navigateUpButton.setEnabled(False)
|
||||
self.ui.workspaceModeLabel.setText("")
|
||||
self.ui.workspaceStack.setCurrentWidget(self.ui.emptyPage)
|
||||
self.ui.applyJsonButton.setVisible(False)
|
||||
self._set_graph_controls_visible(False)
|
||||
self._update_edit_actions()
|
||||
return
|
||||
@@ -199,13 +204,14 @@ class MainWindow(QMainWindow):
|
||||
)
|
||||
is_graph = component.implementation_kind == "graph"
|
||||
self.ui.workspaceModeLabel.setText("Graph" if is_graph else "Text")
|
||||
self.ui.workspaceStack.setCurrentWidget(self.ui.graphPage if is_graph else self.ui.jsonPage)
|
||||
self.ui.applyJsonButton.setVisible(not is_graph)
|
||||
self.ui.workspaceStack.setCurrentWidget(
|
||||
self.ui.graphPage if is_graph else self.ui.textPage
|
||||
)
|
||||
self._set_graph_controls_visible(is_graph)
|
||||
if is_graph:
|
||||
self.set_graph_tool("pointer")
|
||||
else:
|
||||
self._load_source_json()
|
||||
self._load_text_definition()
|
||||
self._update_edit_actions()
|
||||
|
||||
def _update_edit_actions(self) -> None:
|
||||
@@ -259,62 +265,70 @@ class MainWindow(QMainWindow):
|
||||
"text": self.ui.textToolButton,
|
||||
}[mode].setChecked(True)
|
||||
|
||||
def _load_source_json(self) -> None:
|
||||
def _load_text_definition(self) -> None:
|
||||
component = self.document_controller.active_component
|
||||
if component is None:
|
||||
return
|
||||
text = json.dumps(
|
||||
{
|
||||
"inputs": [port.to_dict() for port in component.inputs],
|
||||
"outputs": [port.to_dict() for port in component.outputs],
|
||||
"source": component.source,
|
||||
},
|
||||
indent=2,
|
||||
self.ui.textDefinitionEditor.set_definition(
|
||||
component.source.get("equations", ""),
|
||||
component.inputs,
|
||||
component.outputs,
|
||||
[
|
||||
Parameter.from_dict(parameter)
|
||||
for parameter in component.source.get("parameters", [])
|
||||
],
|
||||
)
|
||||
self.ui.jsonEditor.setPlainText(text)
|
||||
self.ui.jsonEditor.document().setModified(False)
|
||||
|
||||
def _resolve_source_edits(self) -> bool:
|
||||
component = self.document_controller.active_component
|
||||
if (
|
||||
component is None
|
||||
or component.implementation_kind != "text"
|
||||
or not self.ui.jsonEditor.document().isModified()
|
||||
or not self.ui.textDefinitionEditor.is_modified
|
||||
):
|
||||
return True
|
||||
answer = QMessageBox.question(
|
||||
self,
|
||||
"Apply text component changes?",
|
||||
"The text component has unapplied input, output, or source changes.",
|
||||
"The text component has unapplied equation, port, or parameter changes.",
|
||||
QMessageBox.StandardButton.Apply
|
||||
| QMessageBox.StandardButton.Discard
|
||||
| QMessageBox.StandardButton.Cancel,
|
||||
)
|
||||
if answer == QMessageBox.StandardButton.Apply:
|
||||
return self.apply_json()
|
||||
return self.apply_text_definition()
|
||||
return answer == QMessageBox.StandardButton.Discard
|
||||
|
||||
@Slot()
|
||||
def apply_json(self) -> bool:
|
||||
def apply_text_definition(self) -> bool:
|
||||
try:
|
||||
data = json.loads(self.ui.jsonEditor.toPlainText())
|
||||
if not isinstance(data, dict):
|
||||
raise ValueError("The text component JSON must be an object")
|
||||
if not isinstance(data.get("inputs"), list):
|
||||
raise ValueError("'inputs' must be a list")
|
||||
if not isinstance(data.get("outputs"), list):
|
||||
raise ValueError("'outputs' must be a list")
|
||||
if not isinstance(data.get("source"), dict):
|
||||
raise ValueError("'source' must be an object")
|
||||
inputs = [Port.from_dict(item) for item in data["inputs"]]
|
||||
outputs = [Port.from_dict(item) for item in data["outputs"]]
|
||||
self.document_controller.replace_active_text_definition(inputs, outputs, data["source"])
|
||||
except (TypeError, ValueError, json.JSONDecodeError) as error:
|
||||
QMessageBox.critical(self, "Invalid text component JSON", str(error))
|
||||
inputs, outputs = self.ui.textDefinitionEditor.ports
|
||||
self._applying_text_definition = True
|
||||
try:
|
||||
self.document_controller.replace_active_text_definition(
|
||||
inputs,
|
||||
outputs,
|
||||
self.ui.textDefinitionEditor.equations,
|
||||
self.ui.textDefinitionEditor.parameters,
|
||||
)
|
||||
finally:
|
||||
self._applying_text_definition = False
|
||||
except (TypeError, ValueError) as error:
|
||||
QMessageBox.critical(self, "Invalid text component", str(error))
|
||||
return False
|
||||
self._load_source_json()
|
||||
self.ui.textDefinitionEditor.set_modified(False)
|
||||
return True
|
||||
|
||||
@Slot(str)
|
||||
def _text_definition_changed(self, component_id: str) -> None:
|
||||
component = self.document_controller.active_component
|
||||
if (
|
||||
component is not None
|
||||
and component.id == component_id
|
||||
and not self._applying_text_definition
|
||||
):
|
||||
self._load_text_definition()
|
||||
|
||||
def _maybe_save(self) -> bool:
|
||||
if self.document_controller.document is None:
|
||||
return True
|
||||
@@ -436,9 +450,9 @@ class MainWindow(QMainWindow):
|
||||
ports_action = menu.addAction("Port Options…")
|
||||
delete_action = menu.addAction("Delete")
|
||||
selected = menu.exec(tree_view.viewport().mapToGlobal(position))
|
||||
if selected is graph_action:
|
||||
if graph_action is not None and selected is graph_action:
|
||||
self.document_controller.add_child(component_id, "graph")
|
||||
elif selected is text_action:
|
||||
elif text_action is not None and selected is text_action:
|
||||
self.document_controller.add_child(component_id, "text")
|
||||
elif selected is options_action:
|
||||
self.show_component_options(component_id)
|
||||
@@ -521,15 +535,18 @@ class MainWindow(QMainWindow):
|
||||
return
|
||||
dialog = ComponentOptionsDialog(component, self)
|
||||
if dialog.exec() == dialog.DialogCode.Accepted:
|
||||
self.document_controller.edit_component_appearance(
|
||||
component_id,
|
||||
dialog.ui.nameEdit.text().strip(),
|
||||
dialog.edited_icon,
|
||||
dialog.edited_inputs,
|
||||
dialog.edited_outputs,
|
||||
dialog.ui.showSubtreeCheckBox.isChecked(),
|
||||
dialog.ui.showNameCheckBox.isChecked(),
|
||||
)
|
||||
try:
|
||||
self.document_controller.edit_component_appearance(
|
||||
component_id,
|
||||
dialog.ui.nameEdit.text().strip(),
|
||||
dialog.edited_icon,
|
||||
dialog.edited_inputs,
|
||||
dialog.edited_outputs,
|
||||
dialog.ui.showSubtreeCheckBox.isChecked(),
|
||||
dialog.ui.showNameCheckBox.isChecked(),
|
||||
)
|
||||
except ValueError as error:
|
||||
QMessageBox.warning(self, "Cannot rename component", str(error))
|
||||
|
||||
@Slot(str, str)
|
||||
def show_port_options(self, port_id: str, direction: str) -> None:
|
||||
|
||||
Reference in New Issue
Block a user