From e61dede7f895059fd119fd6f352d9ceaec4679ef Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 5 May 2026 12:33:41 +0200 Subject: [PATCH 01/15] add Dylan in contributors --- AUTHORS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 269a1325..1451eb9c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,3 +1,4 @@ Sylvain COULIBALY, INRAE, 2020 - 2022 Théophile TERRAZ, INRAE, 2022 - 2024 -Pierre-Antoine ROUBY, INRAE, 2023 - 2025 \ No newline at end of file +Pierre-Antoine ROUBY, INRAE, 2023 - 2025 +Dylan JEANNIN, INRAE, 2026 \ No newline at end of file From 99cb2883a1c3255153fde74b8726e4a5a1ac0094 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 5 May 2026 12:34:44 +0200 Subject: [PATCH 02/15] display seconds in LateralContributionAdisTS data (edition window) --- src/tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools.py b/src/tools.py index 9ea2fb80..b4de6800 100644 --- a/src/tools.py +++ b/src/tools.py @@ -321,7 +321,7 @@ def timestamp_to_old_pamhyr_date_adists(time: int): minutes = (dt.seconds % 3600) // 60 seconds = dt.seconds % 60 - s = f"{dt.days:>3}:{hours:>2}:{minutes:>2}" + s = f"{dt.days:>3}:{hours:>2}:{minutes:>2}:{seconds:>2}" s = s.replace(" ", "0") return s From 11e1302e057ad1b3681e92962e9c9965cd022722 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 5 May 2026 17:50:45 +0200 Subject: [PATCH 03/15] fix add/del/undo/redo in edit BoundaryConditionsAdisTS + quick fix in edit LateralContributionsAdisTS --- .../BoundaryConditionAdisTS.py | 28 ++++++++++++----- .../LateralContributionAdisTS.py | 11 +++++-- .../BoundaryConditionsAdisTS/Edit/Table.py | 29 ++++++++++++++++-- .../Edit/UndoCommand.py | 5 ++-- .../LateralContributionsAdisTS/Edit/Table.py | 30 ++++++++++++++++++- .../Edit/UndoCommand.py | 6 ++-- 6 files changed, 90 insertions(+), 19 deletions(-) diff --git a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py index a83d49b5..9a4ecf9b 100644 --- a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py +++ b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py @@ -143,9 +143,9 @@ class Data(SQLSubModel): table = execute( "SELECT pamhyr_id, deleted, data0, data1, scenario FROM " + "boundary_condition_data_adists " + - f"WHERE bca = {bca.id} " + - f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " + - f"AND scenario = {scenario.id}" + f"WHERE scenario = {scenario.id} " + + # f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " + + f"AND bca = {bca.id}" ) if table is not None: @@ -188,8 +188,8 @@ class Data(SQLSubModel): execute( "INSERT INTO " + "boundary_condition_data_adists(" + - "pamhyr_id, data0, data1, bca, scenario) " + - f"VALUES ({self.id}, '{data0}', {data1}, {bca.id}, " + + "pamhyr_id, deleted, data0, data1, bca, scenario) " + + f"VALUES ({self.id}, {self._db_format(self.is_deleted())}, '{data0}', {data1}, {bca.id}, " + f"{self._status.scenario_id})" ) @@ -437,7 +437,14 @@ class BoundaryConditionAdisTS(SQLSubModel): d._data_traversal(predicate, modifier, data) def __len__(self): - return len(self._data) + return len( + list( + filter( + lambda el: el is not None and not el.is_deleted(), + self._data + ) + ) + ) @classmethod def time_convert(cls, data): @@ -493,7 +500,12 @@ class BoundaryConditionAdisTS(SQLSubModel): @property def data(self): - return self._data.copy() + return list( + filter( + lambda el: el is not None and not el.is_deleted(), + self._data + ) + ) @property def _default_0(self): @@ -537,7 +549,7 @@ class BoundaryConditionAdisTS(SQLSubModel): def delete_i(self, indexes): self._data = list( map( - lambda e: e[1], + lambda e: e[1].set_as_deleted(), filter( lambda e: e[0] not in indexes, enumerate(self.data) diff --git a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py index 302093e9..b2b903cf 100644 --- a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py +++ b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py @@ -410,7 +410,7 @@ class LateralContributionAdisTS(SQLSubModel): return len( list( filter( - lambda el: not el.is_deleted(), + lambda el: el is not None and not el.is_deleted(), self._data ) ) @@ -456,7 +456,12 @@ class LateralContributionAdisTS(SQLSubModel): @property def data(self): - return self._data.copy() + return list( + filter( + lambda el: el is not None and not el.is_deleted(), + self._data + ) + ) @property def begin_rk(self): @@ -497,7 +502,7 @@ class LateralContributionAdisTS(SQLSubModel): def delete_i(self, indexes): self._data = list( map( - lambda e: e[1], + lambda e: e[1].set_as_deleted(), filter( lambda e: e[0] not in indexes, enumerate(self.data) diff --git a/src/View/BoundaryConditionsAdisTS/Edit/Table.py b/src/View/BoundaryConditionsAdisTS/Edit/Table.py index 13f1aa2c..03bf059c 100644 --- a/src/View/BoundaryConditionsAdisTS/Edit/Table.py +++ b/src/View/BoundaryConditionsAdisTS/Edit/Table.py @@ -50,6 +50,22 @@ logger = logging.getLogger() class TableModel(PamhyrTableModel): + def get_true_data_row(self, row): + if len(self._data.data) > 0: + bc = self._data.data[row] + else: + return 0 + + return next( + map( + lambda e: e[0], + filter( + lambda e: e[1] == bc, + enumerate(self._data._data) + ) + ), 0 + ) + def data(self, index, role): if role == Qt.TextAlignmentRole: return Qt.AlignHCenter | Qt.AlignVCenter @@ -63,6 +79,7 @@ class TableModel(PamhyrTableModel): value = QVariant() if 0 <= column < 2: + row = self.get_true_data_row(row) v = self._data._data[row][column] if self._data._types[column] == float: value = f"{v:.4f}" @@ -84,6 +101,8 @@ class TableModel(PamhyrTableModel): column = index.column() try: + row = self.get_true_data_row(row) + self._undo.push( SetDataCommand( self._data, row, column, value @@ -110,14 +129,20 @@ class TableModel(PamhyrTableModel): def delete(self, rows, parent=QModelIndex()): self.beginRemoveRows(parent, rows[0], rows[-1]) - + _rows = list( + map( + lambda r: self.get_true_data_row(r), + rows + ) + ) self._undo.push( DelCommand( - self._data, rows + self._data, _rows ) ) self.endRemoveRows() + self.layoutChanged.emit() def sort(self, _reverse, parent=QModelIndex()): self.layoutAboutToBeChanged.emit() diff --git a/src/View/BoundaryConditionsAdisTS/Edit/UndoCommand.py b/src/View/BoundaryConditionsAdisTS/Edit/UndoCommand.py index e4858bb1..1319a105 100644 --- a/src/View/BoundaryConditionsAdisTS/Edit/UndoCommand.py +++ b/src/View/BoundaryConditionsAdisTS/Edit/UndoCommand.py @@ -80,10 +80,11 @@ class DelCommand(QUndoCommand): def undo(self): for row, el in self._bc: - self._data.insert(row, el) + el.set_as_not_deleted() def redo(self): - self._data.delete_i(self._rows) + for row, el in self._bc: + el.set_as_deleted() class PasteCommand(QUndoCommand): diff --git a/src/View/LateralContributionsAdisTS/Edit/Table.py b/src/View/LateralContributionsAdisTS/Edit/Table.py index af5d144e..4dc431f8 100644 --- a/src/View/LateralContributionsAdisTS/Edit/Table.py +++ b/src/View/LateralContributionsAdisTS/Edit/Table.py @@ -52,6 +52,23 @@ logger = logging.getLogger() class TableModel(PamhyrTableModel): + def get_true_data_row(self, row): + + if len(self._data.data) > 0: + lc = self._data.data[row] + else: + return 0 + + return next( + map( + lambda e: e[0], + filter( + lambda e: e[1] == lc, + enumerate(self._data._data) + ) + ), 0 + ) + def data(self, index, role): if role == Qt.TextAlignmentRole: return Qt.AlignHCenter | Qt.AlignVCenter @@ -65,6 +82,7 @@ class TableModel(PamhyrTableModel): value = QVariant() if 0 <= column < 2: + row = self.get_true_data_row(row) v = self._data._data[row][column] if self._data._types[column] == float: value = f"{v:.4f}" @@ -86,6 +104,8 @@ class TableModel(PamhyrTableModel): column = index.column() try: + row = self.get_true_data_row(row) + self._undo.push( SetDataCommand( self._data, row, column, value @@ -113,10 +133,18 @@ class TableModel(PamhyrTableModel): def delete(self, rows, parent=QModelIndex()): self.beginRemoveRows(parent, rows[0], rows[-1]) + _rows = list( + map( + lambda r: self.get_true_data_row(r), + rows + ) + ) + self._undo.push( DelCommand( - self._data, rows + self._data, _rows ) ) self.endRemoveRows() + self.layoutChanged.emit() diff --git a/src/View/LateralContributionsAdisTS/Edit/UndoCommand.py b/src/View/LateralContributionsAdisTS/Edit/UndoCommand.py index 88fe63ad..86005e98 100644 --- a/src/View/LateralContributionsAdisTS/Edit/UndoCommand.py +++ b/src/View/LateralContributionsAdisTS/Edit/UndoCommand.py @@ -76,8 +76,8 @@ class DelCommand(QUndoCommand): def undo(self): for row, el in self._lc: - self._data._data.insert(row, el) + el.set_as_not_deleted() def redo(self): - for row in self._rows: - del self._data._data[row] + for row, el in self._lc: + el.set_as_deleted() From 7565d8ee956102d60e1875194a6359341b11487b Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 5 May 2026 17:51:49 +0200 Subject: [PATCH 04/15] fix pep8 --- src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py index 9a4ecf9b..f48f3209 100644 --- a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py +++ b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py @@ -189,7 +189,8 @@ class Data(SQLSubModel): "INSERT INTO " + "boundary_condition_data_adists(" + "pamhyr_id, deleted, data0, data1, bca, scenario) " + - f"VALUES ({self.id}, {self._db_format(self.is_deleted())}, '{data0}', {data1}, {bca.id}, " + + f"VALUES ({self.id}, {self._db_format(self.is_deleted())}, " + + f"'{data0}', {data1}, {bca.id}, " + f"{self._status.scenario_id})" ) From faff877c804e9f89a86a3599b680930a8969ceeb Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 11 May 2026 12:52:33 +0200 Subject: [PATCH 05/15] stab window DIF AdisTS (undo / redo / add / delete / save / load), all should work correctly --- src/Model/DIFAdisTS/DIFAdisTS.py | 20 ++++++++++---------- src/Model/DIFAdisTS/DIFAdisTSSpec.py | 17 +++++++++-------- src/View/DIFAdisTS/Table.py | 27 +++++++++++++++++++++++---- src/View/DIFAdisTS/UndoCommand.py | 11 +++++------ src/View/DIFAdisTS/Window.py | 20 ++++++++++++++++++-- 5 files changed, 65 insertions(+), 30 deletions(-) diff --git a/src/Model/DIFAdisTS/DIFAdisTS.py b/src/Model/DIFAdisTS/DIFAdisTS.py index 341f71d9..113bbc70 100644 --- a/src/Model/DIFAdisTS/DIFAdisTS.py +++ b/src/Model/DIFAdisTS/DIFAdisTS.py @@ -142,24 +142,24 @@ class DIFAdisTS(SQLSubModel): enabled = (next(it) == 1) owner_scenario = next(it) - dif = cls( + DIF = cls( id=pid, name=name, status=status, owner_scenario=owner_scenario, ) - dif.method = method - dif.dif = dif - dif.b = b - dif.c = c - dif.enabled = enabled + DIF.method = method + DIF.dif = dif + DIF.b = b + DIF.c = c + DIF.enabled = enabled data['dif_default_id'] = pid - dif._data = DIFAdisTSSpec._db_load(execute, data) + DIF._data = DIFAdisTSSpec._db_load(execute, data) loaded.add(pid) - new.append(dif) + new.append(DIF) data["scenario"] = scenario.parent new += cls._db_load(execute, data) @@ -190,7 +190,7 @@ class DIFAdisTS(SQLSubModel): b = self.b c = -1. - if self.dif is not None: + if self.c is not None: c = self.c sql = ( @@ -201,7 +201,7 @@ class DIFAdisTS(SQLSubModel): "VALUES (" + f"{self.id}, '{self._db_format(self._name)}', " + f"'{self._db_format(self._method)}', " + - f"{dif.id}, {b}, {c}, {self._enabled}, " + + f"{dif}, {b}, {c}, {self._enabled}, " + f"{self._status.scenario_id}" + ")" ) diff --git a/src/Model/DIFAdisTS/DIFAdisTSSpec.py b/src/Model/DIFAdisTS/DIFAdisTSSpec.py index ea43585d..85e8f6c0 100644 --- a/src/Model/DIFAdisTS/DIFAdisTSSpec.py +++ b/src/Model/DIFAdisTS/DIFAdisTSSpec.py @@ -33,15 +33,15 @@ class DIFAdisTSSpec(SQLSubModel): _id_cnt = 0 def __init__(self, id: int = -1, method: str = "", - status=None): + status=None, owner_scenario=-1): super(DIFAdisTSSpec, self).__init__() self._status = status if id == -1: - self.id = DIFAdisTSSpec._id_cnt + self._id = DIFAdisTSSpec._id_cnt else: - self.id = id + self._id = id self._method = method self._reach = None @@ -52,7 +52,7 @@ class DIFAdisTSSpec(SQLSubModel): self._c = None self._enabled = True - DIFAdisTSSpec._id_cnt = max(DIFAdisTSSpec._id_cnt + 1, self.id) + DIFAdisTSSpec._id_cnt = max(DIFAdisTSSpec._id_cnt + 1, self._id) @classmethod def _db_create(cls, execute, ext=""): @@ -195,7 +195,7 @@ class DIFAdisTSSpec(SQLSubModel): new_spec.c = c new_spec.enabled = enabled - loaded.add(pid) + loaded.add(id) new.append(new_spec) data["scenario"] = scenario.parent @@ -210,22 +210,23 @@ class DIFAdisTSSpec(SQLSubModel): dif_default = data['dif_default_id'] - execute( + sql = ( "INSERT INTO " + "dif_adists_spec(pamhyr_id, deleted, " + "dif_default, method, reach, " + "start_rk, end_rk, dif, b, c, enabled, scenario) " + "VALUES (" + - f"{self.id}, {self._db_format(self.is_deleted())}" + + f"{self.id}, {self._db_format(self.is_deleted())}, " + f"{dif_default}, " + f"'{self._db_format(self._method)}', " + f"{self._reach}, " + f"{self._start_rk}, {self._end_rk}, " + f"{self._dif}, {self._b}, {self._c}, " + - f"{self._enabled}" + + f"{self._enabled}, " + f"{self._status.scenario_id}" + ")" ) + execute(sql) return True diff --git a/src/View/DIFAdisTS/Table.py b/src/View/DIFAdisTS/Table.py index 51bff003..b9b51c5d 100644 --- a/src/View/DIFAdisTS/Table.py +++ b/src/View/DIFAdisTS/Table.py @@ -118,9 +118,16 @@ class DIFTableModel(PamhyrTableModel): super(DIFTableModel, self).__init__(data=data, **kwargs) self._data = data + if self._undo is not None: + self._undo.indexChanged.connect(lambda _: self.update()) def _setup_lst(self): - self._lst = self._data._data + self._lst = list( + filter( + lambda dif: dif._deleted is False, + self._data._data + ) + ) def rowCount(self, parent): return len(self._lst) @@ -183,7 +190,10 @@ class DIFTableModel(PamhyrTableModel): if self._headers[column] != "reach": self._undo.push( SetCommandSpec( - self._lst, row, self._headers[column], value + self._lst, + row, + self._headers[column], + value ) ) elif self._headers[column] == "reach": @@ -211,25 +221,34 @@ class DIFTableModel(PamhyrTableModel): ) ) + self._setup_lst() self.endInsertRows() self.layoutChanged.emit() def delete(self, rows, parent=QModelIndex()): self.beginRemoveRows(parent, rows[0], rows[-1]) + data_rows = { + id(dif): i for i, dif in enumerate(self._data._data) + } self._undo.push( DelCommand( - self._data, self._lst, rows + self._data, + self._data._data, + [data_rows[id(self._lst[row])] for row in rows + if 0 <= row < len(self._lst)] ) ) - + self._setup_lst() self.endRemoveRows() self.layoutChanged.emit() def undo(self): self._undo.undo() + self._setup_lst() self.layoutChanged.emit() def redo(self): self._undo.redo() + self._setup_lst() self.layoutChanged.emit() diff --git a/src/View/DIFAdisTS/UndoCommand.py b/src/View/DIFAdisTS/UndoCommand.py index 81078251..6f543485 100644 --- a/src/View/DIFAdisTS/UndoCommand.py +++ b/src/View/DIFAdisTS/UndoCommand.py @@ -136,11 +136,11 @@ class SetCommandSpec(QUndoCommand): class AddCommand(QUndoCommand): - def __init__(self, data, ics_spec, index): + def __init__(self, data, dif_spec, index): QUndoCommand.__init__(self) self._data = data - self._ics_spec = ics_spec + self._dif_spec = dif_spec self._index = index self._new = None @@ -155,17 +155,16 @@ class AddCommand(QUndoCommand): class DelCommand(QUndoCommand): - def __init__(self, data, ics_spec, rows): + def __init__(self, data, dif_spec, rows): QUndoCommand.__init__(self) self._data = data - self._ics_spec = ics_spec + self._dif_spec = dif_spec self._rows = rows - # self._data = data self._ic = [] for row in rows: - self._ic.append((row, self._ics_spec[row])) + self._ic.append((row, self._dif_spec[row])) self._ic.sort() def undo(self): diff --git a/src/View/DIFAdisTS/Window.py b/src/View/DIFAdisTS/Window.py index 2fa531c3..7191491f 100644 --- a/src/View/DIFAdisTS/Window.py +++ b/src/View/DIFAdisTS/Window.py @@ -51,6 +51,8 @@ from View.DIFAdisTS.Table import ( DIFTableModel, ComboBoxDelegate, ) +from View.DIFAdisTS.UndoCommand import SetCommand + from View.DIFAdisTS.translate import DIFAdisTSTranslate from Solver.Mage import Mage8 @@ -272,11 +274,25 @@ class DIFAdisTSWindow(PamhyrWindow): self._update() def _undo(self): - self._table.undo() + undo_stack = self._undo_stack + if undo_stack is None or not undo_stack.canUndo(): + return + + if isinstance(undo_stack.command(undo_stack.index() - 1), SetCommand): + self._table.undo() + else: + self._table_spec.undo() self._update() def _redo(self): - self._table.redo() + undo_stack = self._undo_stack + if undo_stack is None or not undo_stack.canRedo(): + return + + if isinstance(undo_stack.command(undo_stack.index()), SetCommand): + self._table.redo() + else: + self._table_spec.redo() self._update() def add(self): From a8b260ad38ab216eb06c2bd74c760093f639aeef Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 11 May 2026 13:49:54 +0200 Subject: [PATCH 06/15] debug crash when double clic on PK combobox when no reach is selected (DIF window) --- src/View/DIFAdisTS/Table.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/View/DIFAdisTS/Table.py b/src/View/DIFAdisTS/Table.py index b9b51c5d..df95fb7a 100644 --- a/src/View/DIFAdisTS/Table.py +++ b/src/View/DIFAdisTS/Table.py @@ -62,9 +62,12 @@ class ComboBoxDelegate(QItemDelegate): if self._mode == "rk": reach_id = self._ic_spec_lst[index.row()].reach - reach = next(filter( - lambda edge: edge.id == reach_id, self._data.edges() - )) + reach = next( + filter( + lambda edge: edge.id == reach_id, self._data.edges() + ), + None + ) if reach_id is not None: val = list( From 92fae0e13f9028c097de0bd50f7e632a7f78cf8b Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 11 May 2026 14:06:07 +0200 Subject: [PATCH 07/15] rename variable to keep consistency --- src/View/DIFAdisTS/UndoCommand.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/View/DIFAdisTS/UndoCommand.py b/src/View/DIFAdisTS/UndoCommand.py index 6f543485..0939beeb 100644 --- a/src/View/DIFAdisTS/UndoCommand.py +++ b/src/View/DIFAdisTS/UndoCommand.py @@ -162,13 +162,13 @@ class DelCommand(QUndoCommand): self._dif_spec = dif_spec self._rows = rows - self._ic = [] + self._dif = [] for row in rows: - self._ic.append((row, self._dif_spec[row])) - self._ic.sort() + self._dif.append((row, self._dif_spec[row])) + self._dif.sort() def undo(self): - for row, el in self._ic: + for row, el in self._dif: self._data.insert(row, el) def redo(self): From e3de7e7100f6b6c14c23887346ebed62758864b2 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 11 May 2026 14:07:38 +0200 Subject: [PATCH 08/15] rename variable to keep consistency --- src/View/DIFAdisTS/Table.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/View/DIFAdisTS/Table.py b/src/View/DIFAdisTS/Table.py index df95fb7a..433c7d93 100644 --- a/src/View/DIFAdisTS/Table.py +++ b/src/View/DIFAdisTS/Table.py @@ -46,21 +46,21 @@ _translate = QCoreApplication.translate class ComboBoxDelegate(QItemDelegate): - def __init__(self, data=None, ic_spec_lst=None, + def __init__(self, data=None, dif_spec_lst=None, trad=None, parent=None, mode="reaches"): super(ComboBoxDelegate, self).__init__(parent) self._data = data self._mode = mode self._trad = trad - self._ic_spec_lst = ic_spec_lst + self._dif_spec_lst = dif_spec_lst def createEditor(self, parent, option, index): self.editor = QComboBox(parent) val = [] if self._mode == "rk": - reach_id = self._ic_spec_lst[index.row()].reach + reach_id = self._dif_spec_lst[index.row()].reach reach = next( filter( From 606b9919e377d21330100c0b7d9b6f584ddf6939 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 11 May 2026 14:58:42 +0200 Subject: [PATCH 09/15] stab window D90 AdisTS (undo / redo / add / delete / save / load), all should work correctly --- src/View/D90AdisTS/Table.py | 16 ++++++++++++---- src/View/D90AdisTS/Window.py | 22 +++++++++++++++++++--- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/View/D90AdisTS/Table.py b/src/View/D90AdisTS/Table.py index 090a5a8b..f926bf41 100644 --- a/src/View/D90AdisTS/Table.py +++ b/src/View/D90AdisTS/Table.py @@ -62,9 +62,12 @@ class ComboBoxDelegate(QItemDelegate): if self._mode == "rk": reach_id = self._d90_spec_lst[index.row()].reach - reach = next(filter( - lambda edge: edge.id == reach_id, self._data.edges() - )) + reach = next( + filter( + lambda edge: edge.id == reach_id, self._data.edges() + ), + None + ) if reach_id is not None: val = list( @@ -116,6 +119,8 @@ class D90TableModel(PamhyrTableModel): super(D90TableModel, self).__init__(data=data, **kwargs) self._data = data + if self._undo is not None: + self._undo.indexChanged.connect(lambda _: self.update()) def _setup_lst(self): self._lst = list( @@ -216,7 +221,8 @@ class D90TableModel(PamhyrTableModel): DelCommand( self._data, self._data._data, - [data_rows[id(self._lst[row])] for row in rows] + [data_rows[id(self._lst[row])] for row in rows + if 0 <= row < len(self._lst)] ) ) @@ -226,8 +232,10 @@ class D90TableModel(PamhyrTableModel): def undo(self): self._undo.undo() + self._setup_lst() self.layoutChanged.emit() def redo(self): self._undo.redo() + self._setup_lst() self.layoutChanged.emit() diff --git a/src/View/D90AdisTS/Window.py b/src/View/D90AdisTS/Window.py index cb36d690..0af4f4b6 100644 --- a/src/View/D90AdisTS/Window.py +++ b/src/View/D90AdisTS/Window.py @@ -43,7 +43,7 @@ from PyQt5.QtWidgets import ( from Modules import Modules -from View.InitialConditionsAdisTS.UndoCommand import ( +from View.D90AdisTS.UndoCommand import ( SetCommand, ) @@ -264,11 +264,27 @@ class D90AdisTSWindow(PamhyrWindow): self._update() def _undo(self): - self._table.undo() + undo_stack = self._undo_stack + if undo_stack is None or not undo_stack.canUndo(): + return + + if isinstance(undo_stack.command(undo_stack.index() - 1), SetCommand): + self._table.undo() + else: + self._table_spec.undo() + self._update() def _redo(self): - self._table.redo() + undo_stack = self._undo_stack + if undo_stack is None or not undo_stack.canRedo(): + return + + if isinstance(undo_stack.command(undo_stack.index()), SetCommand): + self._table.redo() + else: + self._table_spec.redo() + self._update() def add(self): From c38e3ee446c2d1310b832cf8adbe0b50f10068b9 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 11 May 2026 14:59:14 +0200 Subject: [PATCH 10/15] correct pep8 rules --- src/View/D90AdisTS/Table.py | 2 +- src/View/D90AdisTS/Window.py | 4 ++-- src/View/DIFAdisTS/Table.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/View/D90AdisTS/Table.py b/src/View/D90AdisTS/Table.py index f926bf41..71614dce 100644 --- a/src/View/D90AdisTS/Table.py +++ b/src/View/D90AdisTS/Table.py @@ -222,7 +222,7 @@ class D90TableModel(PamhyrTableModel): self._data, self._data._data, [data_rows[id(self._lst[row])] for row in rows - if 0 <= row < len(self._lst)] + if 0 <= row < len(self._lst)] ) ) diff --git a/src/View/D90AdisTS/Window.py b/src/View/D90AdisTS/Window.py index 0af4f4b6..3f76bca3 100644 --- a/src/View/D90AdisTS/Window.py +++ b/src/View/D90AdisTS/Window.py @@ -267,12 +267,12 @@ class D90AdisTSWindow(PamhyrWindow): undo_stack = self._undo_stack if undo_stack is None or not undo_stack.canUndo(): return - + if isinstance(undo_stack.command(undo_stack.index() - 1), SetCommand): self._table.undo() else: self._table_spec.undo() - + self._update() def _redo(self): diff --git a/src/View/DIFAdisTS/Table.py b/src/View/DIFAdisTS/Table.py index 433c7d93..12e8d382 100644 --- a/src/View/DIFAdisTS/Table.py +++ b/src/View/DIFAdisTS/Table.py @@ -238,8 +238,8 @@ class DIFTableModel(PamhyrTableModel): DelCommand( self._data, self._data._data, - [data_rows[id(self._lst[row])] for row in rows - if 0 <= row < len(self._lst)] + [data_rows[id(self._lst[row])] for row in rows + if 0 <= row < len(self._lst)] ) ) self._setup_lst() From b1daadf9f2d6a771fb43319ba506a2b667610746 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 11 May 2026 14:59:48 +0200 Subject: [PATCH 11/15] rename variables for DIF to keep consistency --- src/View/DIFAdisTS/Window.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/View/DIFAdisTS/Window.py b/src/View/DIFAdisTS/Window.py index 7191491f..304cce3b 100644 --- a/src/View/DIFAdisTS/Window.py +++ b/src/View/DIFAdisTS/Window.py @@ -102,7 +102,7 @@ class DIFAdisTSWindow(PamhyrWindow): self._delegate_method = ComboBoxDelegate( trad=self._trad, data=self._study.river, - ic_spec_lst=self._data[0]._data, + dif_spec_lst=self._data[0]._data, parent=self, mode="method" ) @@ -146,14 +146,14 @@ class DIFAdisTSWindow(PamhyrWindow): self._delegate_reach = ComboBoxDelegate( trad=self._trad, data=self._study.river, - ic_spec_lst=self._data[0]._data, + dif_spec_lst=self._data[0]._data, parent=self, mode="reaches" ) self._delegate_rk = ComboBoxDelegate( trad=self._trad, data=self._study.river, - ic_spec_lst=self._data[0]._data, + dif_spec_lst=self._data[0]._data, parent=self, mode="rk" ) From b450796df592334e9db4ba3743ea1b2feb64f3b2 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 11 May 2026 16:14:35 +0200 Subject: [PATCH 12/15] stab window InitialCond AdisTS (undo / redo / add / delete / save / load), all should work correctly --- src/View/InitialConditionsAdisTS/Table.py | 2 ++ src/View/InitialConditionsAdisTS/Window.py | 20 ++++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/View/InitialConditionsAdisTS/Table.py b/src/View/InitialConditionsAdisTS/Table.py index b84beed1..005b8161 100644 --- a/src/View/InitialConditionsAdisTS/Table.py +++ b/src/View/InitialConditionsAdisTS/Table.py @@ -245,8 +245,10 @@ class InitialConditionTableModel(PamhyrTableModel): def undo(self): self._undo.undo() + self._setup_lst() self.layoutChanged.emit() def redo(self): self._undo.redo() + self._setup_lst() self.layoutChanged.emit() diff --git a/src/View/InitialConditionsAdisTS/Window.py b/src/View/InitialConditionsAdisTS/Window.py index 2f7ddacc..a38ad0ff 100644 --- a/src/View/InitialConditionsAdisTS/Window.py +++ b/src/View/InitialConditionsAdisTS/Window.py @@ -273,11 +273,27 @@ class InitialConditionsAdisTSWindow(PamhyrWindow): self._update() def _undo(self): - self._table.undo() + undo_stack = self._undo_stack + if undo_stack is None or not undo_stack.canUndo(): + return + + if isinstance(undo_stack.command(undo_stack.index() - 1), SetCommand): + self._table.undo() + else: + self._table_spec.undo() + self._update() def _redo(self): - self._table.redo() + undo_stack = self._undo_stack + if undo_stack is None or not undo_stack.canRedo(): + return + + if isinstance(undo_stack.command(undo_stack.index()), SetCommand): + self._table.redo() + else: + self._table_spec.redo() + self._update() def add(self): From 7c3de520d901e776073bc1bc6f6aed909b36ec06 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 12 May 2026 08:39:58 +0200 Subject: [PATCH 13/15] delete old references to pollutants in BoundaryConditionsAdisTS window --- src/View/BoundaryConditionsAdisTS/Table.py | 2 +- src/View/BoundaryConditionsAdisTS/UndoCommand.py | 16 ---------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/src/View/BoundaryConditionsAdisTS/Table.py b/src/View/BoundaryConditionsAdisTS/Table.py index 34633e0b..6f7f54a0 100644 --- a/src/View/BoundaryConditionsAdisTS/Table.py +++ b/src/View/BoundaryConditionsAdisTS/Table.py @@ -43,7 +43,7 @@ from View.Tools.PamhyrTable import PamhyrTableModel from View.BoundaryConditionsAdisTS.UndoCommand import ( SetNodeCommand, SetTypeCommand, - AddCommand, DelCommand, SetPolCommand + AddCommand, DelCommand ) from View.BoundaryCondition.translate import BC_types diff --git a/src/View/BoundaryConditionsAdisTS/UndoCommand.py b/src/View/BoundaryConditionsAdisTS/UndoCommand.py index f1531d71..d7ac21a1 100644 --- a/src/View/BoundaryConditionsAdisTS/UndoCommand.py +++ b/src/View/BoundaryConditionsAdisTS/UndoCommand.py @@ -62,22 +62,6 @@ class SetTypeCommand(QUndoCommand): self._bcs.get(self._index).type = self._new -class SetPolCommand(QUndoCommand): - def __init__(self, bcs, index, pollutant): - QUndoCommand.__init__(self) - - self._bcs = bcs - self._index = index - self._old = self._bcs.get(self._index).pollutant - self._new = pollutant - - def undo(self): - self._bcs.get(self._index).pollutant = self._old - - def redo(self): - self._bcs.get(self._index).pollutant = self._new - - class AddCommand(QUndoCommand): def __init__(self, pollutant, bcs, index): QUndoCommand.__init__(self) From 726b81bf12adb7d82bd588de854a412ee66944a3 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 12 May 2026 08:40:35 +0200 Subject: [PATCH 14/15] debug undo after add LateralContributionAdisTS --- src/View/LateralContributionsAdisTS/UndoCommand.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/View/LateralContributionsAdisTS/UndoCommand.py b/src/View/LateralContributionsAdisTS/UndoCommand.py index 08cf408a..8366f927 100644 --- a/src/View/LateralContributionsAdisTS/UndoCommand.py +++ b/src/View/LateralContributionsAdisTS/UndoCommand.py @@ -91,7 +91,7 @@ class AddCommand(QUndoCommand): self._new = None def undo(self): - self._lcs.delete_i(self._index) + self._lcs.delete_i([self._index]) def redo(self): if self._new is None: From 084c22836b3538d3d2861c958f72f774de606e3b Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 12 May 2026 13:48:14 +0200 Subject: [PATCH 15/15] debug undo after deletion of BCA --- src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py | 4 ++-- src/View/BoundaryConditionsAdisTS/UndoCommand.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py index f48f3209..5376cba1 100644 --- a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py +++ b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py @@ -548,11 +548,11 @@ class BoundaryConditionAdisTS(SQLSubModel): self.modified() def delete_i(self, indexes): - self._data = list( + list( map( lambda e: e[1].set_as_deleted(), filter( - lambda e: e[0] not in indexes, + lambda e: e[0] in indexes, enumerate(self.data) ) ) diff --git a/src/View/BoundaryConditionsAdisTS/UndoCommand.py b/src/View/BoundaryConditionsAdisTS/UndoCommand.py index d7ac21a1..63a340ee 100644 --- a/src/View/BoundaryConditionsAdisTS/UndoCommand.py +++ b/src/View/BoundaryConditionsAdisTS/UndoCommand.py @@ -90,7 +90,7 @@ class DelCommand(QUndoCommand): self._bc = [] for row in rows: - self._bc.append((row, self._bcs.get(row))) + self._bc.append((row, self._bcs._lst[row])) self._bc.sort() def undo(self):