From 8afa3d1e3089be8ea5b9d2abdf81987e55667871 Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Rouby Date: Tue, 3 Sep 2024 15:22:02 +0200 Subject: [PATCH] Pamhyr2, Scenario: Add Read only mode. --- src/Model/Status.py | 20 ++++++++++++++++++++ src/Model/Study.py | 24 ++++++++++++++++++++++++ src/View/Network/GraphWidget.py | 10 ++++++++-- src/View/Network/Window.py | 31 ++++++++++++++++++++----------- src/View/Scenarios/GraphWidget.py | 13 ++++++++++++- src/View/Scenarios/Window.py | 1 + src/View/Scenarios/translate.py | 2 +- src/View/Tools/ListedSubWindow.py | 7 +++++-- src/View/Tools/PamhyrWindow.py | 12 ++++++++++++ 9 files changed, 103 insertions(+), 17 deletions(-) diff --git a/src/Model/Status.py b/src/Model/Status.py index db632db1..881f0b10 100644 --- a/src/Model/Status.py +++ b/src/Model/Status.py @@ -18,12 +18,20 @@ import logging +from enum import Enum, auto + logger = logging.getLogger() +class Status(Enum): + EDIT = auto() + READ_ONLY = auto() + + class StudyStatus(object): def __init__(self, scenario=None): super(StudyStatus, self).__init__() + self._status = Status.EDIT self._scenario = scenario self._saved = True @@ -34,6 +42,18 @@ class StudyStatus(object): return self._scenario.id + def is_editable(self): + return self._status == Status.EDIT + + def set_as_editable(self): + self._status = Status.EDIT + + def is_read_only(self): + return self._status == Status.READ_ONLY + + def set_as_read_only(self): + self._status = Status.READ_ONLY + @property def scenario(self): return self._scenario diff --git a/src/Model/Study.py b/src/Model/Study.py index 80e47484..7126e9ff 100644 --- a/src/Model/Study.py +++ b/src/Model/Study.py @@ -22,6 +22,7 @@ import logging from datetime import datetime from tools import timer, timestamp +from functools import reduce from Model.Tools.PamhyrDB import SQLModel from Model.Scenarios import Scenarios @@ -94,6 +95,12 @@ class Study(SQLModel): def river(self): return self._river + def is_editable(self): + return self.status.is_editable() + + def is_read_only(self): + return self.status.is_read_only() + @property def is_saved(self): return self.status.is_saved() @@ -354,6 +361,13 @@ class Study(SQLModel): scenario = new.scenarios[int(scenario_id[0])] new.status.scenario = scenario + if reduce( + lambda a, s: a or (s.parent is scenario), + new.scenarios.lst, + False + ): + new.status.set_as_read_only() + data["scenario"] = scenario data["loaded_pid"] = set() @@ -444,6 +458,7 @@ class Study(SQLModel): if switch: self.status.scenario = new + self.status.set_as_editable() return new def reload_from_scenario(self, scenario): @@ -464,3 +479,12 @@ class Study(SQLModel): sql_exec, data=data ) + + if reduce( + lambda a, s: a or (s.parent is scenario), + self.scenarios.lst, + False + ): + self.status.set_as_read_only() + else: + self.status.set_as_editable() diff --git a/src/View/Network/GraphWidget.py b/src/View/Network/GraphWidget.py index 5b55d764..53ac9c15 100644 --- a/src/View/Network/GraphWidget.py +++ b/src/View/Network/GraphWidget.py @@ -883,6 +883,9 @@ class GraphWidget(QGraphicsView): super(GraphWidget, self).mousePressEvent(event) return + if self.graph._status.is_read_only(): + return + # Move item and select edge item if self._state == "move": self._selected_new_edge_src_node = None @@ -932,7 +935,7 @@ class GraphWidget(QGraphicsView): def mouseReleaseEvent(self, event): self.clicked = False - if self._only_display: + if self._only_display or self.graph._status.is_read_only(): return if self._state == "move": @@ -951,6 +954,9 @@ class GraphWidget(QGraphicsView): super(GraphWidget, self).mouseReleaseEvent(event) def mouseMoveEvent(self, event): + if self.graph._status.is_read_only(): + return + pos = self.mapToScene(event.pos()) # Selecte item on the fly @@ -1002,7 +1008,7 @@ class GraphWidget(QGraphicsView): # Contextual menu def contextMenuEvent(self, event): - if self._only_display: + if self._only_display or self.graph._status.is_read_only(): return pos = self.mapToScene(event.pos()) diff --git a/src/View/Network/Window.py b/src/View/Network/Window.py index eab8cae0..781c65ae 100644 --- a/src/View/Network/Window.py +++ b/src/View/Network/Window.py @@ -85,11 +85,18 @@ class NetworkWindow(PamhyrWindow): def setup_table(self): # Nodes table + if self._study.is_read_only: + node_editable_headers = [] + edge_editable_headers = [] + else: + node_editable_headers = ["name"] + edge_editable_headers = ["name", "node1", "node2"] + table = self.find(QTableView, "tableView_nodes") self._nodes_model = NodeTableModel( table_view=table, table_headers=self._table_headers_node, - editable_headers=["name"], + editable_headers=node_editable_headers, data=self._graph, undo=self._undo_stack, ) @@ -108,7 +115,7 @@ class NetworkWindow(PamhyrWindow): self._reachs_model = EdgeTableModel( table_view=table, table_headers=self._table_headers_edge, - editable_headers=["name", "node1", "node2"], + editable_headers=edge_editable_headers, delegates={ "node1": self.delegate_combobox, "node2": self.delegate_combobox, @@ -132,22 +139,24 @@ class NetworkWindow(PamhyrWindow): def setup_connections(self): self._nodes_model.dataChanged.connect(self.update) - self._nodes_model.dataChanged.connect(self._graph_widget.rename_nodes) self._reachs_model.dataChanged.connect( self._graph_widget.display_update) self._reachs_model.dataChanged.connect(self.update) self._graph_widget.changeEdge.connect(self.update) self._graph_widget.changeNode.connect(self.update) - self.find(QAction, "action_toolBar_add").setCheckable(True) - self.find(QAction, "action_toolBar_add").triggered.connect( - self.clicked_add - ) + if self._study.is_editable: + self._nodes_model.dataChanged.connect(self._graph_widget.rename_nodes) - self.find(QAction, "action_toolBar_del").setCheckable(True) - self.find(QAction, "action_toolBar_del").triggered.connect( - self.clicked_del - ) + self.find(QAction, "action_toolBar_add").setCheckable(True) + self.find(QAction, "action_toolBar_add").triggered.connect( + self.clicked_add + ) + + self.find(QAction, "action_toolBar_del").setCheckable(True) + self.find(QAction, "action_toolBar_del").triggered.connect( + self.clicked_del + ) def clicked_add(self): if self.get_action_checkable("action_toolBar_add"): diff --git a/src/View/Scenarios/GraphWidget.py b/src/View/Scenarios/GraphWidget.py index d5cc790a..4afaacd5 100644 --- a/src/View/Scenarios/GraphWidget.py +++ b/src/View/Scenarios/GraphWidget.py @@ -61,7 +61,7 @@ class ScenarioItem(QGraphicsTextItem): if self.graph.scenario_has_child(self.scenario): tag = "⛔ " - self.setPlainText(tag + self.scenario.name) + self.setHtml(tag + self.scenario.name) self.setDefaultTextColor(Qt.black) self.setFlag(QGraphicsItem.ItemIsMovable) @@ -412,7 +412,9 @@ class GraphWidget(QGraphicsView): self._study.save() self._study.reload_from_scenario(item.scenario) + self._close_other_window() self.exec_with_waiting_window(fn, "select_scenario") + self.changeScenario.emit(self.sender()) def new_scenario(self, pos): @@ -421,5 +423,14 @@ class GraphWidget(QGraphicsView): scenario = self._study.new_scenario_from_current() scenario.set_pos(pos.x(), pos.y()) + self._close_other_window() self.exec_with_waiting_window(fn, "new_scenario") + self.changeScenario.emit(self.sender()) + + def _close_other_window(self): + self.parent\ + .parent\ + ._close_sub_window( + exceptions=["Scenarios", "Debug REPL"] + ) diff --git a/src/View/Scenarios/Window.py b/src/View/Scenarios/Window.py index cfad5832..b36da70c 100644 --- a/src/View/Scenarios/Window.py +++ b/src/View/Scenarios/Window.py @@ -124,5 +124,6 @@ class ScenariosWindow(PamhyrWindow): def update(self): self._scenarios_model.update() self._graph_widget.display_update() + self._set_title() self._propagate_update(key=Modules.SCENARIOS) diff --git a/src/View/Scenarios/translate.py b/src/View/Scenarios/translate.py index 95bcd127..d2bb92e5 100644 --- a/src/View/Scenarios/translate.py +++ b/src/View/Scenarios/translate.py @@ -39,7 +39,7 @@ class ScenariosTranslate(MainTranslate): ) self._sub_dict["table_headers_scenarios"] = { - "id": self._dict['id'], + # "id": self._dict['id'], "name": self._dict['name'], "description": self._dict['description'], "parent": _translate("Scenarios", "Parent"), diff --git a/src/View/Tools/ListedSubWindow.py b/src/View/Tools/ListedSubWindow.py index d369c782..ee11a317 100644 --- a/src/View/Tools/ListedSubWindow.py +++ b/src/View/Tools/ListedSubWindow.py @@ -117,6 +117,9 @@ class ListedSubWindow(object): except Exception: return - def _close_sub_window(self): - for _, win in self._sub_win_list: + def _close_sub_window(self, exceptions=[]): + for name, win in self._sub_win_list: + if name in exceptions: + continue + win.close() diff --git a/src/View/Tools/PamhyrWindow.py b/src/View/Tools/PamhyrWindow.py index dcb4fdad..fc3ef96a 100644 --- a/src/View/Tools/PamhyrWindow.py +++ b/src/View/Tools/PamhyrWindow.py @@ -183,6 +183,18 @@ class PamhyrWindow(ASubMainWindow, ListedSubWindow, PamhyrWindowTools): self._set_title() self._set_icon() + def _set_title(self): + title = self._title + + if self._study.is_read_only(): + title = "⛔ " + title + + scenario = self._study.status.scenario + if scenario is not None and scenario.name != "default": + title += f" | {scenario.name}" + + self.ui.setWindowTitle(title) + def closeEvent(self, event): self._close_sub_window() self._propagate_update(Modules.WINDOW_LIST)