diff --git a/src/Model/Scenario.py b/src/Model/Scenario.py index 686f7ff4..1be93176 100644 --- a/src/Model/Scenario.py +++ b/src/Model/Scenario.py @@ -155,6 +155,9 @@ class Scenario(SQLSubModel): return scenarios def _db_save(self, execute, data=None): + if self.is_deleted(): + return self.drop_all(execute) + parent = 'NULL' if self.parent is not None: parent = self.parent._id @@ -174,6 +177,33 @@ class Scenario(SQLSubModel): return True + def drop_all(self, execute): + execute(f"DELETE FROM scenario WHERE id = {self.id}") + + tables = [ + "additional_files", + "boundary_condition", "boundary_condition_data", + "lateral_contribution", "lateral_contribution_data", + "friction", "stricklers", + "hydraulic_structures", + "hydraulic_structures_basic", "hydraulic_structures_basic_value", + "initial_conditions", + "sedimentary_layer", "sedimentary_layer_layer", + "reservoir", "reservoir_data", + "rep_lines", + "solver_parameter", + "geometry_pointXYZ", "geometry_profileXYZ", + "river_reach", "river_node" + ] + + for table in tables: + execute( + f"DELETE FROM {table} " + + f"WHERE scenario = {self.id}" + ) + + return True + @property def id(self): return self._id diff --git a/src/Model/Scenarios.py b/src/Model/Scenarios.py index 1bc8e961..8a755f21 100644 --- a/src/Model/Scenarios.py +++ b/src/Model/Scenarios.py @@ -68,3 +68,10 @@ class Scenarios(PamhyrModelDict): self._dict ) ) + + def delete(self, key): + el = self._dict.get(key) + if el is None: + return + + el.set_as_deleted() diff --git a/src/Model/Study.py b/src/Model/Study.py index 7126e9ff..09a49ee0 100644 --- a/src/Model/Study.py +++ b/src/Model/Study.py @@ -77,6 +77,8 @@ class Study(SQLModel): self._old_save_id = 0 + self._river_scenario_cache = {} + @classmethod def checkers(cls): lst = [ @@ -462,23 +464,29 @@ class Study(SQLModel): return new def reload_from_scenario(self, scenario): - def sql_exec(sql): - return self.execute( - sql, fetch_one=False, commit=True + if scenario in self._river_scenario_cache: + self._river = self._river_scenario_cache[scenario] + self.status.scenario = scenario + else: + def sql_exec(sql): + return self.execute( + sql, fetch_one=False, commit=True + ) + + self.status.scenario = scenario + data = { + "status": self.status, + "loaded_pid": set(), + "scenario": scenario + } + + # Reload river data + river = River._db_load( + sql_exec, + data=data ) - - self.status.scenario = scenario - data = { - "status": self.status, - "loaded_pid": set(), - "scenario": scenario - } - - # Reload river data - self._river = River._db_load( - sql_exec, - data=data - ) + self._river_scenario_cache[scenario] = river + self._river = self._river if reduce( lambda a, s: a or (s.parent is scenario), diff --git a/src/Model/Tools/PamhyrDB.py b/src/Model/Tools/PamhyrDB.py index c2ae9a68..ee18b00c 100644 --- a/src/Model/Tools/PamhyrDB.py +++ b/src/Model/Tools/PamhyrDB.py @@ -195,6 +195,9 @@ class SQLSubModel(PamhyrID): Returns: Nothing """ + if self._status is None: + return + self._owner_scenario = self._status.scenario_id self._status.modified() diff --git a/src/View/Scenarios/ContextMenu.py b/src/View/Scenarios/ContextMenu.py index 4090f85d..b7661a24 100644 --- a/src/View/Scenarios/ContextMenu.py +++ b/src/View/Scenarios/ContextMenu.py @@ -59,10 +59,10 @@ class ScenarioMenu(AbstractMenu): item = self._items[0] select = self._menu.addAction(self._trad["menu_select_scenario"]) - # delete = self._menu.addAction(self._trad["menu_del_scenario"]) + delete = self._menu.addAction(self._trad["menu_del_scenario"]) action = self._exec() if action == select: self._parent.select_scenario(item) - # if action == delete: - # self._parent.del_node(item) + if action == delete: + self._parent.delete_scenario(item) diff --git a/src/View/Scenarios/GraphWidget.py b/src/View/Scenarios/GraphWidget.py index 4afaacd5..41e3d406 100644 --- a/src/View/Scenarios/GraphWidget.py +++ b/src/View/Scenarios/GraphWidget.py @@ -265,6 +265,9 @@ class GraphWidget(QGraphicsView): self.edge_items = [] for scenar in self._study.scenarios.lst: + if scenar.is_deleted(): + continue + iscenar = ScenarioItem(scenar, self) self.scene().addItem(iscenar) self.scenarios_items[scenar] = iscenar @@ -294,7 +297,8 @@ class GraphWidget(QGraphicsView): def scenario_has_child(self, scenario): for scenar in self._study.scenarios.lst: if scenar.parent is scenario: - return True + if not scenar.is_deleted(): + return True return False @@ -409,23 +413,48 @@ class GraphWidget(QGraphicsView): return def fn(): + self._close_other_window() self._study.save() - self._study.reload_from_scenario(item.scenario) + self._undo.push( + SelectScenariosCommand( + self._study, + item.scenario + ) + ) + # 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): def fn(): + self._close_other_window() self._study.save() - scenario = self._study.new_scenario_from_current() - scenario.set_pos(pos.x(), pos.y()) + self._undo.push( + AddScenariosCommand( + self._study, + pos + ) + ) + # 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 delete_scenario(self, item): + def fn(): + self._close_other_window() + # self._study.save() + self._undo.push( + DeleteScenariosCommand( + self._study, + item.scenario + ) + ) + + self.exec_with_waiting_window(fn, "delete_scenario") self.changeScenario.emit(self.sender()) def _close_other_window(self): diff --git a/src/View/Scenarios/UndoCommand.py b/src/View/Scenarios/UndoCommand.py index e90a5d7e..baaf2542 100644 --- a/src/View/Scenarios/UndoCommand.py +++ b/src/View/Scenarios/UndoCommand.py @@ -25,32 +25,59 @@ from PyQt5.QtWidgets import ( class AddScenariosCommand(QUndoCommand): - def __init__(self, study, source): + def __init__(self, study, pos): QUndoCommand.__init__(self) self._study = study - self._source = source + self._pos = pos + self._new = None def undo(self): - logger.error(f"TODO {type(self)} : undo") + self._study.scenarios.delete(self._new.id) + self._study.reload_from_scenario(self._new.parent) def redo(self): - self._study.new_scenario_from_current(switch=False) + if self._new is None: + self._new = self._study.new_scenario_from_current() + self._new.set_pos(self._pos.x(), self._pos.y()) + else: + self._new.set_as_not_deleted() + self._study.reload_from_scenario(self._new) -class DelScenariosCommand(QUndoCommand): +class SelectScenariosCommand(QUndoCommand): + def __init__(self, study, new): + QUndoCommand.__init__(self) + + self._study = study + self._old = study.status.scenario + self._new = new + + def undo(self): + self._study.reload_from_scenario(self._old) + + def redo(self): + self._study.reload_from_scenario(self._new) + + +class DeleteScenariosCommand(QUndoCommand): def __init__(self, study, scenario): QUndoCommand.__init__(self) self._study = study self._scenario = scenario + self._reload = study.status.scenario == scenario def undo(self): - logger.error(f"TODO {type(self)} : undo") + self._scenario.set_as_not_deleted() + if self._reload: + self._study.reload_from_scenario(self._scenario) def redo(self): - logger.error(f"TODO {type(self)} : redo") + if self._reload: + self._study.reload_from_scenario(self._scenario.parent) + self._scenario.set_as_deleted() class SetCommand(QUndoCommand): def __init__(self, scenario, column, new_value): diff --git a/src/View/Scenarios/Window.py b/src/View/Scenarios/Window.py index b36da70c..e68f0a02 100644 --- a/src/View/Scenarios/Window.py +++ b/src/View/Scenarios/Window.py @@ -39,6 +39,7 @@ from PyQt5.QtWidgets import ( from Modules import Modules from Model.River import RiverNode, RiverReach, River +from View.WaitingDialog import WaitingDialog from View.Tools.PamhyrWindow import PamhyrWindow from View.Scenarios.GraphWidget import GraphWidget from View.Scenarios.UndoCommand import * @@ -114,11 +115,31 @@ class ScenariosWindow(PamhyrWindow): self._graph_widget.changeScenario.connect(self.update) def _undo(self): - self._undo_stack.undo() + def fn(): + self._undo_stack.undo() + + dlg = WaitingDialog( + payload_fn=fn, + title="undo_waiting", + trad=self._trad, + parent=self + ) + dlg.exec_() + self.update() def _redo(self): - self._undo_stack.redo() + def fn(): + self._undo_stack.redo() + + dlg = WaitingDialog( + payload_fn=fn, + title="redo_waiting", + trad=self._trad, + parent=self + ) + dlg.exec_() + self.update() def update(self): diff --git a/src/View/Scenarios/translate.py b/src/View/Scenarios/translate.py index d2bb92e5..9db2d9fe 100644 --- a/src/View/Scenarios/translate.py +++ b/src/View/Scenarios/translate.py @@ -37,6 +37,9 @@ class ScenariosTranslate(MainTranslate): self._dict["menu_add_scenario"] = _translate( "Scenarios", "Create new scenario from current scenario" ) + self._dict["menu_del_scenario"] = _translate( + "Scenarios", "Delete this scenario" + ) self._sub_dict["table_headers_scenarios"] = { # "id": self._dict['id'], @@ -48,6 +51,15 @@ class ScenariosTranslate(MainTranslate): self._dict["new_scenario"] = _translate( "Scenarios", "Create new scenario" ) + self._dict["delete_scenario"] = _translate( + "Scenarios", "Delete scenario" + ) self._dict["select_scenario"] = _translate( "Scenarios", "Select scenario" ) + self._dict["undo_waiting"] = _translate( + "Scenarios", "Undo ..." + ) + self._dict["redo_waiting"] = _translate( + "Scenarios", "Redo ..." + )