From ab2f775b95846ebaae5f913b0ffb4f349fc28cc9 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Wed, 8 Apr 2026 12:34:05 +0200 Subject: [PATCH 01/55] debug model InitialConditionsAdisTSSpec --- .../InitialConditionsAdisTS/InitialConditionsAdisTSSpec.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTSSpec.py b/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTSSpec.py index ed9cf0d3..e79c505a 100644 --- a/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTSSpec.py +++ b/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTSSpec.py @@ -31,7 +31,7 @@ class ICAdisTSSpec(SQLSubModel): _sub_classes = [] def __init__(self, id: int = -1, name: str = "", - status=None): + status=None, owner_scenario=None): super(ICAdisTSSpec, self).__init__() self._status = status @@ -194,7 +194,7 @@ class ICAdisTSSpec(SQLSubModel): new_spec.rate = rate new_spec.enabled = enabled - loaded.add(pid) + # loaded.add(pid) new.append(new_spec) data["scenario"] = scenario.parent @@ -211,7 +211,7 @@ class ICAdisTSSpec(SQLSubModel): sql = ( "INSERT INTO " + - "initial_conditions_adists_spec(id, deleted, " + + "initial_conditions_adists_spec(pamhyr_id, deleted, " + "ic_default, name, reach, " + "start_rk, end_rk, concentration, eg, em, ed, rate, " + "enabled, scenario) " + From 4f6e8249e00be9d96ad460680e3aaa6f5f16db0e Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Wed, 8 Apr 2026 14:33:02 +0200 Subject: [PATCH 02/55] correction erreur identifiant bdd --- .../LateralContributionsAdisTS/LateralContributionAdisTS.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py index 85b2e0ab..8c88f0e2 100644 --- a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py +++ b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py @@ -372,7 +372,7 @@ class LateralContributionAdisTS(SQLSubModel): execute( "INSERT INTO " + - "lateral_contribution_adists(id, deleted," + + "lateral_contribution_adists(pamhyr_id, deleted," + "pollutant, reach, begin_rk, end_rk, scenario) " + "VALUES (" + f"{self.id}, {self._db_format(self.is_deleted())}, " + From 63836527c782363fbda3ad4bc9b324ffe8a57ee6 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 13 Apr 2026 13:10:50 +0200 Subject: [PATCH 03/55] add d50/sigma in database + load/save data in UI --- .../BoundaryCondition/BoundaryCondition.py | 50 +++++++++++++++++-- src/Model/Study.py | 2 +- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/Model/BoundaryCondition/BoundaryCondition.py b/src/Model/BoundaryCondition/BoundaryCondition.py index 86f2cb6e..d1da739b 100644 --- a/src/Model/BoundaryCondition/BoundaryCondition.py +++ b/src/Model/BoundaryCondition/BoundaryCondition.py @@ -232,6 +232,8 @@ class BoundaryCondition(SQLSubModel): type TEXT NOT NULL, tab TEXT NOT NULL, node INTEGER, + d50 REAL DEFAULT 0.002, + sigma REAL DEFAULT 1, {Scenario.create_db_add_scenario()}, {Scenario.create_db_add_scenario_fk()}, FOREIGN KEY(node) REFERENCES river_node(pamhyr_id), @@ -258,6 +260,17 @@ class BoundaryCondition(SQLSubModel): "ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE" ) + if major == "0" and int(minor) <= 2: + if int(release) < 4: + execute( + "ALTER TABLE boundary_condition " + + "ADD COLUMN d50 REAL DEFAULT 0.002" + ) + execute( + "ALTER TABLE boundary_condition " + + "ADD COLUMN sigma REAL DEFAULT 1" + ) + return cls._update_submodel(execute, version, data) @classmethod @@ -316,7 +329,7 @@ class BoundaryCondition(SQLSubModel): return new table = execute( - "SELECT pamhyr_id, deleted, name, type, node, scenario " + + "SELECT pamhyr_id, deleted, name, type, node, d50, sigma, scenario " + "FROM boundary_condition " + f"WHERE tab = '{tab}' " + f"AND scenario = {scenario.id} " + @@ -331,6 +344,8 @@ class BoundaryCondition(SQLSubModel): name = next(it) t = next(it) node = next(it) + d50 = next(it) + sigma = next(it) owner_scenario = next(it) ctor = cls._get_ctor_from_type(t) @@ -342,7 +357,9 @@ class BoundaryCondition(SQLSubModel): ) if deleted: bc.set_as_deleted() - + if t=="SL": + bc.d50 = d50 + bc.sigma = sigma bc.node = None if node != -1: bc.node = next(filter(lambda n: n.id == node, nodes), None) @@ -374,16 +391,23 @@ class BoundaryCondition(SQLSubModel): node = -1 if self._node is not None: node = self._node.id - + + d50 = 0.002 + sigma = 1 + if self._type == "SL": + d50 = self._d50 + sigma = self._sigma + execute( "INSERT INTO " + "boundary_condition(" + - "pamhyr_id, deleted, name, type, tab, node, scenario" + + "pamhyr_id, deleted, name, type, tab, node, d50, sigma, scenario" + ") " + "VALUES (" + f"{self._pamhyr_id}, {self._db_format(self.is_deleted())}, " + f"'{self._db_format(self._name)}', " + f"'{self._db_format(self._type)}', '{tab}', {node}, " + + f"{d50}, {sigma}, " + f"{self._status.scenario_id}" + ")" ) @@ -467,6 +491,24 @@ class BoundaryCondition(SQLSubModel): def has_node(self): return self._node is not None + + @property + def d50(self): + return self._d50 + + @d50.setter + def d50(self, value): + self._d50 = float(value) + self.modified() + + @property + def sigma(self): + return self._sigma + + @sigma.setter + def sigma(self, value): + self._sigma = float(value) + self.modified() @property def header(self): diff --git a/src/Model/Study.py b/src/Model/Study.py index f32e90bf..23113ab9 100644 --- a/src/Model/Study.py +++ b/src/Model/Study.py @@ -37,7 +37,7 @@ logger = logging.getLogger() class Study(SQLModel): - _version = "0.2.3" + _version = "0.2.4" _sub_classes = [ Scenario, From 23361d142ee7e04a892efc606490d2ca74c11d71 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Thu, 16 Apr 2026 15:14:28 +0200 Subject: [PATCH 04/55] update model + view to display only BCAdisTS related to pollutant, and not the global list, todo: reconnect add/del buttons --- .../BoundaryConditionAdisTS.py | 4 +- src/Model/Pollutants/Pollutants.py | 16 ++++++- src/View/BoundaryConditionsAdisTS/Table.py | 44 +++++-------------- src/View/BoundaryConditionsAdisTS/Window.py | 25 ++++++----- .../BoundaryConditionsAdisTS/translate.py | 1 - src/View/Pollutants/Window.py | 37 ++++++++++------ 6 files changed, 66 insertions(+), 61 deletions(-) diff --git a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py index 24fa3cf2..c505e35d 100644 --- a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py +++ b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py @@ -312,6 +312,7 @@ class BoundaryConditionAdisTS(SQLSubModel): status = data['status'] nodes = data['nodes'] scenario = data["scenario"] + pollutant = data["pollutant"] loaded = data['loaded_pid'] if scenario is None: @@ -321,7 +322,8 @@ class BoundaryConditionAdisTS(SQLSubModel): "SELECT pamhyr_id, deleted, pollutant, type, node, scenario " + "FROM boundary_condition_adists " + f"WHERE scenario = {scenario.id} " + - f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " + f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " + + f"AND pollutant = {pollutant.id} " ) if table is not None: diff --git a/src/Model/Pollutants/Pollutants.py b/src/Model/Pollutants/Pollutants.py index ba5c3ac7..047ceb43 100644 --- a/src/Model/Pollutants/Pollutants.py +++ b/src/Model/Pollutants/Pollutants.py @@ -28,6 +28,7 @@ from tools import ( from Model.Tools.PamhyrDB import SQLSubModel from Model.Except import NotImplementedMethodeError from Model.Scenario import Scenario +from Model.BoundaryConditionsAdisTS.BoundaryConditionAdisTS import BoundaryConditionAdisTS logger = logging.getLogger() @@ -275,7 +276,8 @@ class PollutantCharacteristics(SQLSubModel): class Pollutants(SQLSubModel): - _sub_classes = [PollutantCharacteristics] + _sub_classes = [PollutantCharacteristics, + BoundaryConditionAdisTS] def __init__(self, id: int = -1, name: str = "", status=None, owner_scenario=-1): @@ -293,6 +295,11 @@ class Pollutants(SQLSubModel): self._enabled = True self._data = [] + self._boundary_conditions_adists = [] + + @property + def boundary_conditions_adists(self): + return self._boundary_conditions_adists @property def name(self): @@ -415,6 +422,10 @@ class Pollutants(SQLSubModel): new_pollutant._data = PollutantCharacteristics._db_load( execute, data=data ) + + new_pollutant._boundary_conditions_adists = BoundaryConditionAdisTS._db_load( + execute, data=data + ) loaded.add(pid) new.append(new_pollutant) @@ -455,6 +466,9 @@ class Pollutants(SQLSubModel): for d in self._data: ok &= d._db_save(execute, data) + for bc in self._boundary_conditions_adists: + ok &= bc._db_save(execute, data) + return ok def _data_traversal(self, diff --git a/src/View/BoundaryConditionsAdisTS/Table.py b/src/View/BoundaryConditionsAdisTS/Table.py index dd38b136..e4e79879 100644 --- a/src/View/BoundaryConditionsAdisTS/Table.py +++ b/src/View/BoundaryConditionsAdisTS/Table.py @@ -112,18 +112,21 @@ class ComboBoxDelegate(QItemDelegate): class TableModel(PamhyrTableModel): - def __init__(self, pollutant=None, bc_list=None, trad=None, **kwargs): + def __init__(self, bc_list=None, pollutant_bc_list=None, trad=None, **kwargs): self._trad = trad self._bc_list = bc_list - self._pollutant = pollutant + self._pollutant = pollutant_bc_list.id + self._pollutant_bc_list = pollutant_bc_list super(TableModel, self).__init__(trad=trad, **kwargs) + def _setup_lst(self): + self._lst = self._pollutant_bc_list.boundary_conditions_adists + def rowCount(self, parent): - return len(self._bc_list) + return len(self._lst) def data(self, index, role): - if role != Qt.ItemDataRole.DisplayRole: return QVariant() @@ -131,12 +134,12 @@ class TableModel(PamhyrTableModel): column = index.column() if self._headers[column] == "type": - n = self._bc_list.get(row).type + n = self._lst[row].type if n is None or n == "": return self._trad["not_associated"] return n elif self._headers[column] == "node": - n = self._bc_list.get(row).node + n = self._lst[row].node if n is None: return self._trad["not_associated"] tmp = next(filter(lambda x: x.id == n, self._data._nodes), None) @@ -144,18 +147,6 @@ class TableModel(PamhyrTableModel): return tmp.name else: return self._trad["not_associated"] - elif self._headers[column] == "pol": - n = self._bc_list.get(row).pollutant - if n is None or n == "not_associated" or n == "": - return self._trad["not_associated"] - tmp = next(filter(lambda x: x.id == n, - self._data._Pollutants.Pollutants_List - ), - None) - if tmp is not None: - return tmp.name - else: - return self._trad["not_associated"] return QVariant() @@ -179,22 +170,7 @@ class TableModel(PamhyrTableModel): self._bc_list, row, self._data.node(value) ) ) - elif self._headers[column] == "pol": - if value == self._trad["not_associated"]: - self._undo.push( - SetPolCommand( - self._bc_list, row, None - ) - ) - else: - pol = next(filter(lambda x: x.name == value, - self._data._Pollutants.Pollutants_List) - ) - self._undo.push( - SetPolCommand( - self._bc_list, row, pol.id - ) - ) + except Exception as e: logger.info(e) logger.debug(traceback.format_exc()) diff --git a/src/View/BoundaryConditionsAdisTS/Window.py b/src/View/BoundaryConditionsAdisTS/Window.py index 47039e81..8272efe5 100644 --- a/src/View/BoundaryConditionsAdisTS/Window.py +++ b/src/View/BoundaryConditionsAdisTS/Window.py @@ -58,11 +58,21 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow): _pamhyr_ui = "BoundaryConditionsAdisTS" _pamhyr_name = "Boundary conditions AdisTS" - def __init__(self, study=None, config=None, parent=None): + def __init__(self, data=None, pollutant_id=None, study=None, config=None, parent=None): + self._data = data + self._pollutant_id = pollutant_id + + _pollutants_lst = study._river._Pollutants.Pollutants_List + self._pollutant_name = next( + (x.name for x in _pollutants_lst if x.id == self._pollutant_id), + None + ) + trad = BCAdisTSTranslate() name = ( trad[self._pamhyr_name] + - " - " + study.name + " - " + study.name + + " - " + self._pollutant_name ) super(BoundaryConditionAdisTSWindow, self).__init__( @@ -73,7 +83,6 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow): parent=parent ) - self._pollutants_lst = self._study._river._Pollutants self._bcs = self._study.river.boundary_conditions_adists self.setup_graph() @@ -95,12 +104,6 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow): mode="node", parent=self ) - self._delegate_pol = ComboBoxDelegate( - trad=self._trad, - data=self._study.river, - mode="pol", - parent=self - ) table = self.find(QTableView, f"tableView") self._table = TableModel( @@ -110,10 +113,10 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow): delegates={ "type": self._delegate_type, "node": self._delegate_node, - "pol": self._delegate_pol, }, trad=self._trad, bc_list=self._study.river.boundary_conditions_adists, + pollutant_bc_list=self._data, undo=self._undo_stack, data=self._study.river ) @@ -156,7 +159,7 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow): ) def add(self): - self._table.add(len(self._bcs)) + self._table.add(len(self._data.boundary_conditions_adists)) def delete(self): rows = self.index_selected_rows() diff --git a/src/View/BoundaryConditionsAdisTS/translate.py b/src/View/BoundaryConditionsAdisTS/translate.py index e6ab6099..590c3511 100644 --- a/src/View/BoundaryConditionsAdisTS/translate.py +++ b/src/View/BoundaryConditionsAdisTS/translate.py @@ -34,5 +34,4 @@ class BCAdisTSTranslate(MainTranslate): self._sub_dict["table_headers"] = { "type": self._dict["type"], "node": _translate("BoundaryCondition", "Node"), - "pol": _translate("BoundaryCondition", "Pollutant") } diff --git a/src/View/Pollutants/Window.py b/src/View/Pollutants/Window.py index ee03ec1a..09cbdd87 100644 --- a/src/View/Pollutants/Window.py +++ b/src/View/Pollutants/Window.py @@ -222,21 +222,32 @@ class PollutantsWindow(PamhyrWindow): initial.show() def boundary_conditions(self): - - if self.sub_window_exists( - BoundaryConditionAdisTSWindow, - data=[self._study, None] - ): - bound = self.get_sub_window( - BoundaryConditionAdisTSWindow, - data=[self._study, None] - ) + rows = self.index_selected_rows() + if len(rows) == 0: return - bound = BoundaryConditionAdisTSWindow( - study=self._study, parent=self - ) - bound.show() + for row in rows: + pollutant_id = self._pollutants_lst.get(row).id + + bclist = self._study.river.boundary_conditions_adists.BCs_AdisTS_List + bcs_adists = [ + x for x in bclist + if x.pollutant == pollutant_id + ] + self._data = self._study.river.Pollutants.get(row) + if self.sub_window_exists( + BoundaryConditionAdisTSWindow, + data=[self._study, None, bcs_adists] + ): + return + + bound = BoundaryConditionAdisTSWindow( + study=self._study, + parent=self, + data=self._data, + pollutant_id=pollutant_id + ) + bound.show() def lateral_contrib(self): rows = self.index_selected_rows() From c2d28b011015757802e55d931b7b2eb071c2d1c8 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Thu, 16 Apr 2026 16:44:14 +0200 Subject: [PATCH 05/55] can use '.' caracter and not only ',' in Shift Geometry window --- src/View/Geometry/ShiftDialog.py | 33 ++++++++++++++++++++-- src/View/Tools/FlexibleDoubleSpinBox.py | 37 +++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 src/View/Tools/FlexibleDoubleSpinBox.py diff --git a/src/View/Geometry/ShiftDialog.py b/src/View/Geometry/ShiftDialog.py index 38744429..85ff029b 100644 --- a/src/View/Geometry/ShiftDialog.py +++ b/src/View/Geometry/ShiftDialog.py @@ -17,7 +17,8 @@ # -*- coding: utf-8 -*- from View.Tools.PamhyrWindow import PamhyrDialog - +from PyQt5.QtWidgets import QDoubleSpinBox +from View.Tools.FlexibleDoubleSpinBox import FlexibleDoubleSpinBox class ShiftDialog(PamhyrDialog): _pamhyr_ui = "GeometryReachShift" @@ -30,9 +31,37 @@ class ShiftDialog(PamhyrDialog): options=[], parent=parent ) - + + self._replace_spinboxes() self._init_default_values() + def _replace_spinboxes(self): + for name in ["doubleSpinBox_X", "doubleSpinBox_Y", "doubleSpinBox_Z"]: + old = self.find(QDoubleSpinBox, name) + + if old is None: + continue + + new = FlexibleDoubleSpinBox(old.parent()) + new.setObjectName(old.objectName()) + + # Copier propriétés utiles + new.setDecimals(old.decimals()) + new.setMinimum(old.minimum()) + new.setMaximum(old.maximum()) + new.setSingleStep(old.singleStep()) + new.setValue(old.value()) + new.setGeometry(old.geometry()) + + # Remplacement dans layout si présent + layout = old.parent().layout() + if layout is not None: + layout.replaceWidget(old, new) + + old.hide() + old.setParent(None) + old.deleteLater() + def _init_default_values(self): self._dx = 0.0 self._dy = 0.0 diff --git a/src/View/Tools/FlexibleDoubleSpinBox.py b/src/View/Tools/FlexibleDoubleSpinBox.py new file mode 100644 index 00000000..34332bef --- /dev/null +++ b/src/View/Tools/FlexibleDoubleSpinBox.py @@ -0,0 +1,37 @@ +# PamhyrWindow.py -- Pamhyr +# Copyright (C) 2023-2025 INRAE +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# -*- coding: utf-8 -*- + +import os +import logging + +from PyQt5.QtWidgets import QDoubleSpinBox + + +class FlexibleDoubleSpinBox(QDoubleSpinBox): + + def keyPressEvent(self, event): + if event.text() == ".": + # Simule une virgule à la place du point + event = type(event)( + event.type(), + event.key(), + event.modifiers(), + "," + ) + + super().keyPressEvent(event) \ No newline at end of file From 432c263cdf694c1bede0a44c0ebcc22dc7da30fd Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 20 Apr 2026 23:01:04 +0200 Subject: [PATCH 06/55] =?UTF-8?q?ajout=20automatique=20de=20l'extansion=20?= =?UTF-8?q?.st=20lorsque=20l'on=20ne=20le=20stipule=20pas=20manuellement?= =?UTF-8?q?=20dans=20l'export=20des=20tron=C3=A7ons?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/View/Geometry/Window.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/View/Geometry/Window.py b/src/View/Geometry/Window.py index 13f25e30..0f780035 100644 --- a/src/View/Geometry/Window.py +++ b/src/View/Geometry/Window.py @@ -20,6 +20,7 @@ import os import sys import time import pathlib +from pathlib import Path import logging from copy import deepcopy @@ -685,10 +686,18 @@ class GeometryWindow(PamhyrWindow): ) if filename != '' and filename is not None: - self._export_to_file_st(filename) + suffix = Path(filename).suffix + if suffix != "": + if suffix == ".st" or suffix == ".ST": + self._export_to_file_st(filename[:-3]) + else: + # TODO : prévenir l'utilisateur que le format n'est pas exportable + pass + else: + self._export_to_file_st(filename) def _export_to_file_st(self, filename): - with open(filename, "w+") as f: + with open(filename+".st", "w+") as f: f.write("# Exported from Pamhyr2\n") self._export_to_file_st_reach(f, self._reach) From 82eeb9a478999c9642eaeb0ebc8d3a5eca32f4b5 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 21 Apr 2026 01:22:08 +0200 Subject: [PATCH 07/55] inversion du sens de zoom avec la molette sur les graphs (contrintuitif auparavant) --- src/View/Network/GraphWidget.py | 2 +- src/View/Scenarios/GraphWidget.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/View/Network/GraphWidget.py b/src/View/Network/GraphWidget.py index 6f91e293..4157bb63 100644 --- a/src/View/Network/GraphWidget.py +++ b/src/View/Network/GraphWidget.py @@ -901,7 +901,7 @@ class GraphWidget(QGraphicsView): painter.drawRect(sceneRect) def wheelEvent(self, event): - self.scaleView(math.pow(2.0, -event.angleDelta().y() / 240.0)) + self.scaleView(math.pow(2.0, event.angleDelta().y() / 240.0)) def scaleView(self, scaleFactor): factor = self.transform().scale( diff --git a/src/View/Scenarios/GraphWidget.py b/src/View/Scenarios/GraphWidget.py index 7405bef0..65a1ced4 100644 --- a/src/View/Scenarios/GraphWidget.py +++ b/src/View/Scenarios/GraphWidget.py @@ -312,7 +312,7 @@ class GraphWidget(QGraphicsView): painter.drawRect(sceneRect) def wheelEvent(self, event): - self.scaleView(math.pow(2.0, -event.angleDelta().y() / 240.0)) + self.scaleView(math.pow(2.0, event.angleDelta().y() / 240.0)) def keyPressEvent(self, event): key = event.key() From 43eb486700111323c1b10b90e4331b21e7f17902 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 21 Apr 2026 10:20:24 +0200 Subject: [PATCH 08/55] =?UTF-8?q?zoom=20plus=20intuitif=20avec=20translati?= =?UTF-8?q?on=20du=20widget=20pour=20garder=20une=20coh=C3=A9rence=20dans?= =?UTF-8?q?=20le=20zoom?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/View/Network/GraphWidget.py | 13 ++++++++++++- src/View/Scenarios/GraphWidget.py | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/View/Network/GraphWidget.py b/src/View/Network/GraphWidget.py index 4157bb63..db877c06 100644 --- a/src/View/Network/GraphWidget.py +++ b/src/View/Network/GraphWidget.py @@ -901,7 +901,18 @@ class GraphWidget(QGraphicsView): painter.drawRect(sceneRect) def wheelEvent(self, event): - self.scaleView(math.pow(2.0, event.angleDelta().y() / 240.0)) + factor = math.pow(2.0, event.angleDelta().y() / 240.0) + + old_pos = self.mapToScene(event.pos()) + + self.scaleView(factor) + + new_pos = self.mapToScene(event.pos()) + + delta = old_pos - new_pos + + # Compensation pour garder le point sous la souris fixe + self.translate(delta.x(), delta.y()) def scaleView(self, scaleFactor): factor = self.transform().scale( diff --git a/src/View/Scenarios/GraphWidget.py b/src/View/Scenarios/GraphWidget.py index 65a1ced4..0fff07d3 100644 --- a/src/View/Scenarios/GraphWidget.py +++ b/src/View/Scenarios/GraphWidget.py @@ -312,7 +312,18 @@ class GraphWidget(QGraphicsView): painter.drawRect(sceneRect) def wheelEvent(self, event): - self.scaleView(math.pow(2.0, event.angleDelta().y() / 240.0)) + factor = math.pow(2.0, event.angleDelta().y() / 240.0) + + old_pos = self.mapToScene(event.pos()) + + self.scaleView(factor) + + new_pos = self.mapToScene(event.pos()) + + delta = old_pos - new_pos + + # Compensation pour garder le point sous la souris fixe + self.translate(delta.x(), delta.y()) def keyPressEvent(self, event): key = event.key() From 0701531d3725db893d47c3dabfbde29b4b835c69 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 21 Apr 2026 10:41:34 +0200 Subject: [PATCH 09/55] =?UTF-8?q?debug=20fonction=20SAVE=20des=20figures,?= =?UTF-8?q?=20qui=20utilisait=20une=20m=C3=A9thode=20Matplotlib,=20plut?= =?UTF-8?q?=C3=B4t=20qu'une=20m=C3=A9thode=20native=20Qt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/View/Tools/Plot/PamhyrToolbar.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/View/Tools/Plot/PamhyrToolbar.py b/src/View/Tools/Plot/PamhyrToolbar.py index 88c01951..593049a0 100644 --- a/src/View/Tools/Plot/PamhyrToolbar.py +++ b/src/View/Tools/Plot/PamhyrToolbar.py @@ -222,10 +222,11 @@ class PamhyrPlotToolbar(NavigationToolbar2QT): filters.append(new) filters = ';;'.join(filters) - file_name, _ = qt_compat._getSaveFileName( + file_name, _ = QtWidgets.QFileDialog.getSaveFileName( self.canvas.parent(), _translate("MainWindow_reach", "Select destination file"), - start, filters, + start, + filters, selected_filter ) From 870bb41ff740c813ae1caad490431f3f9aba0b04 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 21 Apr 2026 16:02:37 +0200 Subject: [PATCH 10/55] =?UTF-8?q?garde=20le=20zoom=20sur=20un=20graph=20ap?= =?UTF-8?q?r=C3=A8s=20rafraichissement=20des=20donn=C3=A9es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/View/BoundaryCondition/Edit/Plot.py | 2 +- src/View/BoundaryConditionsAdisTS/Edit/Plot.py | 2 +- src/View/Frictions/PlotRKZ.py | 2 +- src/View/Frictions/PlotStricklers.py | 2 +- src/View/Geometry/PlotAC.py | 2 +- src/View/HydraulicStructures/PlotAC.py | 2 +- src/View/HydraulicStructures/PlotRKC.py | 2 +- src/View/InitialConditions/PlotDRK.py | 2 +- src/View/InitialConditions/PlotDischarge.py | 2 +- src/View/LateralContribution/Edit/Plot.py | 2 +- src/View/LateralContributionsAdisTS/Edit/Plot.py | 2 +- src/View/PlotXY.py | 2 +- src/View/Reservoir/Edit/Plot.py | 2 +- src/View/Results/PlotAC.py | 2 +- src/View/Results/PlotRKC.py | 2 +- src/View/SedimentLayers/Edit/Plot.py | 2 +- src/View/SedimentLayers/Reach/Plot.py | 2 +- src/View/SedimentLayers/Reach/Profile/Plot.py | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/View/BoundaryCondition/Edit/Plot.py b/src/View/BoundaryCondition/Edit/Plot.py index ca0f753d..31b25f9b 100644 --- a/src/View/BoundaryCondition/Edit/Plot.py +++ b/src/View/BoundaryCondition/Edit/Plot.py @@ -54,7 +54,7 @@ class Plot(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False def custom_ticks(self): if self.data.header[0] != "time": diff --git a/src/View/BoundaryConditionsAdisTS/Edit/Plot.py b/src/View/BoundaryConditionsAdisTS/Edit/Plot.py index 174e7018..b320be27 100644 --- a/src/View/BoundaryConditionsAdisTS/Edit/Plot.py +++ b/src/View/BoundaryConditionsAdisTS/Edit/Plot.py @@ -55,7 +55,7 @@ class Plot(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False def custom_ticks(self): if self.data.header[0] != "time": diff --git a/src/View/Frictions/PlotRKZ.py b/src/View/Frictions/PlotRKZ.py index 0614a052..9e787cbc 100644 --- a/src/View/Frictions/PlotRKZ.py +++ b/src/View/Frictions/PlotRKZ.py @@ -43,7 +43,7 @@ class PlotRKZ(PlotRKC): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False self.parent = parent def onpick(self, event): diff --git a/src/View/Frictions/PlotStricklers.py b/src/View/Frictions/PlotStricklers.py index 7bdc3cd3..9abef064 100644 --- a/src/View/Frictions/PlotStricklers.py +++ b/src/View/Frictions/PlotStricklers.py @@ -50,7 +50,7 @@ class PlotStricklers(PamhyrPlot): self._auto_relim = False self._auto_relim_update = False - self._autoscale_update = True + self._autoscale_update = False @timer def draw(self, highlight=None): diff --git a/src/View/Geometry/PlotAC.py b/src/View/Geometry/PlotAC.py index cd1e3f76..1b846c5b 100644 --- a/src/View/Geometry/PlotAC.py +++ b/src/View/Geometry/PlotAC.py @@ -38,7 +38,7 @@ class PlotAC(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False self.label_x = self._trad["transverse_abscissa"] self.label_y = self._trad["unit_elevation"] diff --git a/src/View/HydraulicStructures/PlotAC.py b/src/View/HydraulicStructures/PlotAC.py index d8bfdb5b..7a51f66b 100644 --- a/src/View/HydraulicStructures/PlotAC.py +++ b/src/View/HydraulicStructures/PlotAC.py @@ -42,7 +42,7 @@ class PlotAC(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False @property def river(self): diff --git a/src/View/HydraulicStructures/PlotRKC.py b/src/View/HydraulicStructures/PlotRKC.py index 8ccdf148..d7ee4faf 100644 --- a/src/View/HydraulicStructures/PlotRKC.py +++ b/src/View/HydraulicStructures/PlotRKC.py @@ -50,7 +50,7 @@ class PlotRKC(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False self.parent = parent self.anotate_lst = [] diff --git a/src/View/InitialConditions/PlotDRK.py b/src/View/InitialConditions/PlotDRK.py index 6b4e81ad..76125391 100644 --- a/src/View/InitialConditions/PlotDRK.py +++ b/src/View/InitialConditions/PlotDRK.py @@ -47,7 +47,7 @@ class PlotDRK(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False @timer def draw(self, highlight=None): diff --git a/src/View/InitialConditions/PlotDischarge.py b/src/View/InitialConditions/PlotDischarge.py index 82adb880..5dad6092 100644 --- a/src/View/InitialConditions/PlotDischarge.py +++ b/src/View/InitialConditions/PlotDischarge.py @@ -37,7 +37,7 @@ class PlotDischarge(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False @timer def draw(self): diff --git a/src/View/LateralContribution/Edit/Plot.py b/src/View/LateralContribution/Edit/Plot.py index ca0f753d..31b25f9b 100644 --- a/src/View/LateralContribution/Edit/Plot.py +++ b/src/View/LateralContribution/Edit/Plot.py @@ -54,7 +54,7 @@ class Plot(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False def custom_ticks(self): if self.data.header[0] != "time": diff --git a/src/View/LateralContributionsAdisTS/Edit/Plot.py b/src/View/LateralContributionsAdisTS/Edit/Plot.py index ca0f753d..31b25f9b 100644 --- a/src/View/LateralContributionsAdisTS/Edit/Plot.py +++ b/src/View/LateralContributionsAdisTS/Edit/Plot.py @@ -54,7 +54,7 @@ class Plot(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False def custom_ticks(self): if self.data.header[0] != "time": diff --git a/src/View/PlotXY.py b/src/View/PlotXY.py index e51933ef..b498f3d4 100644 --- a/src/View/PlotXY.py +++ b/src/View/PlotXY.py @@ -68,7 +68,7 @@ class PlotXY(PamhyrPlot): self._isometric_axis = True self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False @timer def draw(self): diff --git a/src/View/Reservoir/Edit/Plot.py b/src/View/Reservoir/Edit/Plot.py index afb44ea2..9709c668 100644 --- a/src/View/Reservoir/Edit/Plot.py +++ b/src/View/Reservoir/Edit/Plot.py @@ -55,7 +55,7 @@ class Plot(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False @timer def draw(self): diff --git a/src/View/Results/PlotAC.py b/src/View/Results/PlotAC.py index bb188472..b2324a9b 100644 --- a/src/View/Results/PlotAC.py +++ b/src/View/Results/PlotAC.py @@ -56,7 +56,7 @@ class PlotAC(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False @property def results(self): diff --git a/src/View/Results/PlotRKC.py b/src/View/Results/PlotRKC.py index 065b42ca..2c09035c 100644 --- a/src/View/Results/PlotRKC.py +++ b/src/View/Results/PlotRKC.py @@ -59,7 +59,7 @@ class PlotRKC(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False @property def results(self): diff --git a/src/View/SedimentLayers/Edit/Plot.py b/src/View/SedimentLayers/Edit/Plot.py index 73a55b85..a9344333 100644 --- a/src/View/SedimentLayers/Edit/Plot.py +++ b/src/View/SedimentLayers/Edit/Plot.py @@ -49,7 +49,7 @@ class Plot(PamhyrPlot): self._auto_relim = False self._auto_relim_update = False - self._autoscale_update = True + self._autoscale_update = False @timer def draw(self): diff --git a/src/View/SedimentLayers/Reach/Plot.py b/src/View/SedimentLayers/Reach/Plot.py index 30adb2b7..0ab7aff4 100644 --- a/src/View/SedimentLayers/Reach/Plot.py +++ b/src/View/SedimentLayers/Reach/Plot.py @@ -53,7 +53,7 @@ class Plot(PamhyrPlot): self._auto_relim = False self._auto_relim_update = False - self._autoscale_update = True + self._autoscale_update = False @timer def draw(self): diff --git a/src/View/SedimentLayers/Reach/Profile/Plot.py b/src/View/SedimentLayers/Reach/Profile/Plot.py index 42d270e0..000295fd 100644 --- a/src/View/SedimentLayers/Reach/Profile/Plot.py +++ b/src/View/SedimentLayers/Reach/Profile/Plot.py @@ -53,7 +53,7 @@ class Plot(PamhyrPlot): self._auto_relim = False self._auto_relim_update = False - self._autoscale_update = True + self._autoscale_update = False @timer def draw(self): From b58d3e005d9742bc18d745eee127eadcc628928e Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 21 Apr 2026 16:55:04 +0200 Subject: [PATCH 11/55] =?UTF-8?q?desactivation=20du=20clic=20sur=20le=20gr?= =?UTF-8?q?aph=20du=20r=C3=A9seau=20hors=20de=20l'onglet=20d'=C3=A9dition?= =?UTF-8?q?=20du=20r=C3=A9seau=20(ex.=20BoundaryConditions...)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/View/Network/GraphWidget.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/View/Network/GraphWidget.py b/src/View/Network/GraphWidget.py index db877c06..83aa8014 100644 --- a/src/View/Network/GraphWidget.py +++ b/src/View/Network/GraphWidget.py @@ -925,6 +925,9 @@ class GraphWidget(QGraphicsView): self.scale(scaleFactor, scaleFactor) def mousePressEvent(self, event): + if self._only_display or self.graph._status.is_read_only(): + return + pos = self.mapToScene(event.pos()) self.clicked = True From d6f7755d12b8cdb1075e63826872eec3afef940e Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Wed, 22 Apr 2026 12:05:28 +0200 Subject: [PATCH 12/55] debug save BoundaryConditionsAdisTS --- .../BoundaryConditionAdisTS.py | 25 ++++++---- .../BoundaryConditionsAdisTSList.py | 10 ++-- .../Edit/UndoCommand.py | 4 +- src/View/BoundaryConditionsAdisTS/Table.py | 46 +++++++++++++++---- .../BoundaryConditionsAdisTS/UndoCommand.py | 2 +- src/View/BoundaryConditionsAdisTS/Window.py | 4 +- 6 files changed, 63 insertions(+), 28 deletions(-) diff --git a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py index c505e35d..60a070a7 100644 --- a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py +++ b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py @@ -312,19 +312,21 @@ class BoundaryConditionAdisTS(SQLSubModel): status = data['status'] nodes = data['nodes'] scenario = data["scenario"] - pollutant = data["pollutant"] + pollutant = data.get("pollutant") loaded = data['loaded_pid'] if scenario is None: return new - table = execute( - "SELECT pamhyr_id, deleted, pollutant, type, node, scenario " + + sql = ( + "SELECT pamhyr_id, deleted, pollutant, type, node, scenario " "FROM boundary_condition_adists " + - f"WHERE scenario = {scenario.id} " + - f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " + - f"AND pollutant = {pollutant.id} " + f"WHERE scenario = {scenario.id} " ) + if pollutant is not None: + sql += f"AND pollutant = {pollutant.id} " + + table = execute(sql) if table is not None: for row in table: @@ -349,7 +351,7 @@ class BoundaryConditionAdisTS(SQLSubModel): bc.type = bc_type bc.node = None - if row[3] != -1: + if node != -1: tmp = next( filter( lambda n: n.id == node, nodes @@ -513,7 +515,10 @@ class BoundaryConditionAdisTS(SQLSubModel): return (new_0, new_1) def add(self, index: int): - value = (self._default_0, self._default_1) + value = Data( + self._default_0, self._default_1, + status=self._status + ) self._data.insert(index, value) self._status.modified() return value @@ -554,9 +559,9 @@ class BoundaryConditionAdisTS(SQLSubModel): return lst def _set_i_c_v(self, index, column, value): - v = list(self._data[index]) + v = self._data[index] v[column] = self._types[column](value) - self._data[index] = tuple(v) + self._data[index] = v self._status.modified() def set_i_0(self, index: int, value): diff --git a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionsAdisTSList.py b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionsAdisTSList.py index 0d1d729f..4bb90dbc 100644 --- a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionsAdisTSList.py +++ b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionsAdisTSList.py @@ -38,9 +38,13 @@ class BoundaryConditionsAdisTSList(PamhyrModelList): if data is None: data = {} - new._lst = BoundaryConditionAdisTS._db_load( - execute, data - ) + previous_pollutant = data.get("pollutant") + data.pop("pollutant", None) + + new._lst = BoundaryConditionAdisTS._db_load(execute, data) + + if previous_pollutant is not None: + data["pollutant"] = previous_pollutant return new diff --git a/src/View/BoundaryConditionsAdisTS/Edit/UndoCommand.py b/src/View/BoundaryConditionsAdisTS/Edit/UndoCommand.py index a4170a20..e4858bb1 100644 --- a/src/View/BoundaryConditionsAdisTS/Edit/UndoCommand.py +++ b/src/View/BoundaryConditionsAdisTS/Edit/UndoCommand.py @@ -61,9 +61,7 @@ class AddCommand(QUndoCommand): def redo(self): if self._new is None: - self._new = self._data.insert(self._index, ( - self._data._types[0](0), self._data._types[1](0.0) - )) + self._new = self._data.add(self._index) else: self._data.insert(self._index, self._new) diff --git a/src/View/BoundaryConditionsAdisTS/Table.py b/src/View/BoundaryConditionsAdisTS/Table.py index e4e79879..f0552029 100644 --- a/src/View/BoundaryConditionsAdisTS/Table.py +++ b/src/View/BoundaryConditionsAdisTS/Table.py @@ -121,9 +121,25 @@ class TableModel(PamhyrTableModel): super(TableModel, self).__init__(trad=trad, **kwargs) def _setup_lst(self): - self._lst = self._pollutant_bc_list.boundary_conditions_adists + self._lst = list( + filter( + lambda bc: bc.pollutant == self._pollutant, + self._bc_list.lst + ) + ) - def rowCount(self, parent): + def get(self, row): + if row < 0 or row >= len(self._lst): + return None + return self._lst[row] + + def _global_row(self, row): + bc = self.get(row) + if bc is None: + return None + return self._bc_list.index(bc) + + def rowCount(self, parent=QModelIndex()): return len(self._lst) def data(self, index, role): @@ -159,15 +175,21 @@ class TableModel(PamhyrTableModel): try: if self._headers[column] == "type": + global_row = self._global_row(row) self._undo.push( SetTypeCommand( - self._bc_list, row, value + self._bc_list, global_row, value ) ) elif self._headers[column] == "node": + global_row = self._global_row(row) + node = next( + filter(lambda n: n.name == value, self._data.nodes()), + None + ) self._undo.push( SetNodeCommand( - self._bc_list, row, self._data.node(value) + self._bc_list, global_row, node ) ) @@ -179,33 +201,39 @@ class TableModel(PamhyrTableModel): return True def add(self, row, parent=QModelIndex()): - self.beginInsertRows(parent, row, row - 1) - + row = len(self._lst) + self.beginInsertRows(parent, row, row) self._undo.push( AddCommand( - self._pollutant, self._bc_list, row + self._pollutant, self._bc_list, len(self._bc_list) ) ) - + self._setup_lst() self.endInsertRows() self.layoutChanged.emit() def delete(self, rows, parent=QModelIndex()): self.beginRemoveRows(parent, rows[0], rows[-1]) + global_rows = list( + map(self._global_row, rows) + ) self._undo.push( DelCommand( - self._bc_list, rows + self._bc_list, global_rows ) ) + 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/BoundaryConditionsAdisTS/UndoCommand.py b/src/View/BoundaryConditionsAdisTS/UndoCommand.py index 9a8d8243..f1531d71 100644 --- a/src/View/BoundaryConditionsAdisTS/UndoCommand.py +++ b/src/View/BoundaryConditionsAdisTS/UndoCommand.py @@ -36,7 +36,7 @@ class SetNodeCommand(QUndoCommand): self._bcs = bcs self._index = index self._old = self._bcs.get(self._index).node - self._new = node.id + self._new = node.id if node is not None else None def undo(self): self._bcs.get(self._index).node = self._old diff --git a/src/View/BoundaryConditionsAdisTS/Window.py b/src/View/BoundaryConditionsAdisTS/Window.py index 8272efe5..4c95befe 100644 --- a/src/View/BoundaryConditionsAdisTS/Window.py +++ b/src/View/BoundaryConditionsAdisTS/Window.py @@ -159,7 +159,7 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow): ) def add(self): - self._table.add(len(self._data.boundary_conditions_adists)) + self._table.add(self._table.rowCount()) def delete(self): rows = self.index_selected_rows() @@ -183,7 +183,7 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow): def edit(self): rows = self.index_selected_rows() for row in rows: - data = self._bcs.get(row) + data = self._table.get(row) if data.node is None: continue From a4026d638657b465defc344238c3935a57544fed Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Wed, 22 Apr 2026 13:45:15 +0200 Subject: [PATCH 13/55] =?UTF-8?q?d=C3=A9sactivation=20temporaire=20de=20un?= =?UTF-8?q?do=20dans=20la=20fen=C3=AAtre=20r=C3=A9sultat=20qui=20fait=20cr?= =?UTF-8?q?ash=20Pamhyr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/View/Results/Window.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/View/Results/Window.py b/src/View/Results/Window.py index 822b64e0..9324f356 100644 --- a/src/View/Results/Window.py +++ b/src/View/Results/Window.py @@ -701,7 +701,8 @@ class ResultsWindow(PamhyrWindow): logger.info("TODO: paste") def _undo(self): - self._table.undo() + logger.info("TODO: undo") + # self._table.undo() def _redo(self): self._table.redo() From 9379f7a27d891ebb5e460fe29b22eecb7421ee01 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 27 Apr 2026 10:07:36 +0200 Subject: [PATCH 14/55] consistency with called functions in the file --- .../BoundaryConditionAdisTS.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py index 60a070a7..408e44a8 100644 --- a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py +++ b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py @@ -455,7 +455,7 @@ class BoundaryConditionAdisTS(SQLSubModel): @node.setter def node(self, node): self._node = node - self._status.modified() + self.modified() @property def header(self): @@ -464,7 +464,7 @@ class BoundaryConditionAdisTS(SQLSubModel): @header.setter def header(self, header): self._header = header - self._status.modified() + self.modified() @property def pollutant(self): @@ -473,7 +473,7 @@ class BoundaryConditionAdisTS(SQLSubModel): @pollutant.setter def pollutant(self, pollutant): self._pollutant = pollutant - self._status.modified() + self.modified() @property def type(self): @@ -482,7 +482,7 @@ class BoundaryConditionAdisTS(SQLSubModel): @type.setter def type(self, type): self._type = type - self._status.modified() + self.modified() @property def data(self): @@ -520,12 +520,12 @@ class BoundaryConditionAdisTS(SQLSubModel): status=self._status ) self._data.insert(index, value) - self._status.modified() + self.modified() return value def insert(self, index: int, value): self._data.insert(index, value) - self._status.modified() + self.modified() def delete_i(self, indexes): self._data = list( @@ -537,14 +537,14 @@ class BoundaryConditionAdisTS(SQLSubModel): ) ) ) - self._status.modified() + self.modified() def sort(self, _reverse=False, key=None): if key is None: self._data.sort(reverse=_reverse) else: self._data.sort(reverse=_reverse, key=key) - self._status.modified() + self.modified() def index(self, bc): self._data.index(bc) @@ -562,7 +562,7 @@ class BoundaryConditionAdisTS(SQLSubModel): v = self._data[index] v[column] = self._types[column](value) self._data[index] = v - self._status.modified() + self.modified() def set_i_0(self, index: int, value): self._set_i_c_v(index, 0, value) From a060dbd461e7c11aeab6631921d6c8a146b81021 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 27 Apr 2026 12:00:39 +0200 Subject: [PATCH 15/55] debug save db d90 --- src/Model/D90AdisTS/D90AdisTSSpec.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Model/D90AdisTS/D90AdisTSSpec.py b/src/Model/D90AdisTS/D90AdisTSSpec.py index 92f58f60..2b6277d1 100644 --- a/src/Model/D90AdisTS/D90AdisTSSpec.py +++ b/src/Model/D90AdisTS/D90AdisTSSpec.py @@ -196,12 +196,12 @@ class D90AdisTSSpec(SQLSubModel): "d90_default, name, reach, " + "start_rk, end_rk, d90, enabled, scenario) " + "VALUES (" + - f"{self.id}, {self._db_format(self.is_deleted())}" + + f"{self.id}, {self._db_format(self.is_deleted())}, " + f"{d90_default}, " + f"'{self._db_format(self._name_section)}', " + f"{self._reach}, " + f"{self._start_rk}, {self._end_rk}, " + - f"{self._d90}, {self._enabled}" + + f"{self._d90}, {self._enabled}, " + f"{self._status.scenario_id}" + ")" ) From eb7c4895ca002d35d1a9c5e3f566b30380f75e78 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 27 Apr 2026 15:43:32 +0200 Subject: [PATCH 16/55] fix delete for pollutants D90 --- src/Model/D90AdisTS/D90AdisTSSpec.py | 2 +- src/View/D90AdisTS/Table.py | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Model/D90AdisTS/D90AdisTSSpec.py b/src/Model/D90AdisTS/D90AdisTSSpec.py index 2b6277d1..5af1c4bb 100644 --- a/src/Model/D90AdisTS/D90AdisTSSpec.py +++ b/src/Model/D90AdisTS/D90AdisTSSpec.py @@ -167,7 +167,7 @@ class D90AdisTSSpec(SQLSubModel): owner_scenario=owner_scenario ) if deleted: - new_spec.is_deleted() + new_spec.set_as_deleted() new_spec.reach = reach new_spec.start_rk = start_rk diff --git a/src/View/D90AdisTS/Table.py b/src/View/D90AdisTS/Table.py index 47390a71..769c79b3 100644 --- a/src/View/D90AdisTS/Table.py +++ b/src/View/D90AdisTS/Table.py @@ -118,7 +118,12 @@ class D90TableModel(PamhyrTableModel): self._data = data def _setup_lst(self): - self._lst = self._data._data + self._lst = list( + filter( + lambda d90: d90._deleted == False, + self._data._data + ) + ) def rowCount(self, parent): return len(self._lst) @@ -203,12 +208,18 @@ class D90TableModel(PamhyrTableModel): def delete(self, rows, parent=QModelIndex()): self.beginRemoveRows(parent, rows[0], rows[-1]) + data_rows = { + id(d90): i for i, d90 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] ) ) + self._setup_lst() self.endRemoveRows() self.layoutChanged.emit() From 6b8d7c2df2802c374e0ed7ea24f5c8e15d571cbc Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 27 Apr 2026 15:44:57 +0200 Subject: [PATCH 17/55] clean useless data --- src/View/BoundaryConditionsAdisTS/Table.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/View/BoundaryConditionsAdisTS/Table.py b/src/View/BoundaryConditionsAdisTS/Table.py index f0552029..706edbc2 100644 --- a/src/View/BoundaryConditionsAdisTS/Table.py +++ b/src/View/BoundaryConditionsAdisTS/Table.py @@ -116,7 +116,6 @@ class TableModel(PamhyrTableModel): self._trad = trad self._bc_list = bc_list self._pollutant = pollutant_bc_list.id - self._pollutant_bc_list = pollutant_bc_list super(TableModel, self).__init__(trad=trad, **kwargs) From 55b200a48e81843e0a9afe97818d1ab64a31b8a5 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 27 Apr 2026 16:32:41 +0200 Subject: [PATCH 18/55] debug delete functionnality in InitialConditionsAdisTS --- .../InitialConditionsAdisTS.py | 53 ++++++++++++------- src/View/InitialConditionsAdisTS/Table.py | 15 +++++- .../InitialConditionsAdisTS/UndoCommand.py | 1 - 3 files changed, 48 insertions(+), 21 deletions(-) diff --git a/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTS.py b/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTS.py index c0088779..98b63fd5 100644 --- a/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTS.py +++ b/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTS.py @@ -267,7 +267,7 @@ class InitialConditionsAdisTS(SQLSubModel): @name.setter def name(self, name): self._name = name - self._status.modified() + self.modified() @property def pollutant(self): @@ -276,7 +276,7 @@ class InitialConditionsAdisTS(SQLSubModel): @pollutant.setter def pollutant(self, pollutant): self._pollutant = pollutant - self._status.modified() + self.modified() @property def concentration(self): @@ -285,7 +285,7 @@ class InitialConditionsAdisTS(SQLSubModel): @concentration.setter def concentration(self, concentration): self._concentration = concentration - self._status.modified() + self.modified() @property def eg(self): @@ -294,7 +294,7 @@ class InitialConditionsAdisTS(SQLSubModel): @eg.setter def eg(self, eg): self._eg = eg - self._status.modified() + self.modified() @property def em(self): @@ -303,7 +303,7 @@ class InitialConditionsAdisTS(SQLSubModel): @em.setter def em(self, em): self._em = em - self._status.modified() + self.modified() @property def ed(self): @@ -312,7 +312,7 @@ class InitialConditionsAdisTS(SQLSubModel): @ed.setter def ed(self, ed): self._ed = ed - self._status.modified() + self.modified() @property def enabled(self): @@ -321,28 +321,45 @@ class InitialConditionsAdisTS(SQLSubModel): @enabled.setter def enabled(self, enabled): self._enabled = enabled - self._status.modified() + self.modified() def new(self, index): n = ICAdisTSSpec(status=self._status) self._data.insert(index, n) - self._status.modified() + self.modified() return n def delete(self, data): - self._data = list( - filter( - lambda x: x not in data, - self._data + list( + map( + lambda x: x.set_as_deleted(), + data ) ) - self._status.modified() + self.modified() def delete_i(self, indexes): - for ind in indexes: - del self._data[ind] - self._status.modified() + list( + map( + lambda e: e[1].set_as_deleted(), + filter( + lambda e: e[0] in indexes, + enumerate(self._data) + ) + ) + ) + self.modified() def insert(self, index, data): - self._data.insert(index, data) - self._status.modified() + if data in self._data: + self.undelete([data]) + else: + self._data.insert(index, data) + + self.modified() + + def undelete(self, lst): + for x in lst: + x.set_as_not_deleted() + + self.modified() diff --git a/src/View/InitialConditionsAdisTS/Table.py b/src/View/InitialConditionsAdisTS/Table.py index 531ce00b..a926c961 100644 --- a/src/View/InitialConditionsAdisTS/Table.py +++ b/src/View/InitialConditionsAdisTS/Table.py @@ -117,7 +117,12 @@ class InitialConditionTableModel(PamhyrTableModel): self._data = data def _setup_lst(self): - self._lst = self._data._data + self._lst = list( + filter( + lambda ica: ica._deleted == False, + self._data._data + ) + ) def rowCount(self, parent): return len(self._lst) @@ -222,12 +227,18 @@ class InitialConditionTableModel(PamhyrTableModel): def delete(self, rows, parent=QModelIndex()): self.beginRemoveRows(parent, rows[0], rows[-1]) + data_rows = { + id(ica): i for i, ica 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] ) ) + self._setup_lst() self.endRemoveRows() self.layoutChanged.emit() diff --git a/src/View/InitialConditionsAdisTS/UndoCommand.py b/src/View/InitialConditionsAdisTS/UndoCommand.py index 5ef0b50e..984be6e7 100644 --- a/src/View/InitialConditionsAdisTS/UndoCommand.py +++ b/src/View/InitialConditionsAdisTS/UndoCommand.py @@ -181,7 +181,6 @@ class DelCommand(QUndoCommand): self._data = data self._ics_spec = ics_spec self._rows = rows - # self._data = data self._ic = [] for row in rows: From a8f95e23861a6ad7f9db96dea5d868771ff56030 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 27 Apr 2026 16:45:36 +0200 Subject: [PATCH 19/55] fix bug when add button didnt refresh the tab list in Initial conditions AdisTS and d90 --- src/View/D90AdisTS/Table.py | 1 + src/View/InitialConditionsAdisTS/Table.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/View/D90AdisTS/Table.py b/src/View/D90AdisTS/Table.py index 769c79b3..97d1dd0b 100644 --- a/src/View/D90AdisTS/Table.py +++ b/src/View/D90AdisTS/Table.py @@ -202,6 +202,7 @@ class D90TableModel(PamhyrTableModel): ) ) + self._setup_lst() self.endInsertRows() self.layoutChanged.emit() diff --git a/src/View/InitialConditionsAdisTS/Table.py b/src/View/InitialConditionsAdisTS/Table.py index a926c961..39ebe1c8 100644 --- a/src/View/InitialConditionsAdisTS/Table.py +++ b/src/View/InitialConditionsAdisTS/Table.py @@ -221,6 +221,7 @@ class InitialConditionTableModel(PamhyrTableModel): ) ) + self._setup_lst() self.endInsertRows() self.layoutChanged.emit() From 7a91969f410c9e192412541dfcba7980676ac746 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 28 Apr 2026 10:27:19 +0200 Subject: [PATCH 20/55] refacto variable names for D90 --- src/View/D90AdisTS/Table.py | 6 +++--- src/View/D90AdisTS/UndoCommand.py | 17 ++++++++--------- src/View/D90AdisTS/Window.py | 12 ++++++------ 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/View/D90AdisTS/Table.py b/src/View/D90AdisTS/Table.py index 97d1dd0b..69f76157 100644 --- a/src/View/D90AdisTS/Table.py +++ b/src/View/D90AdisTS/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, d90_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._d90_spec_lst = d90_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._d90_spec_lst[index.row()].reach reach = next(filter( lambda edge: edge.id == reach_id, self._data.edges() diff --git a/src/View/D90AdisTS/UndoCommand.py b/src/View/D90AdisTS/UndoCommand.py index 050bc675..23a2b6ac 100644 --- a/src/View/D90AdisTS/UndoCommand.py +++ b/src/View/D90AdisTS/UndoCommand.py @@ -112,11 +112,11 @@ class SetCommandSpec(QUndoCommand): class AddCommand(QUndoCommand): - def __init__(self, data, ics_spec, index): + def __init__(self, data, d90_spec, index): QUndoCommand.__init__(self) self._data = data - self._ics_spec = ics_spec + self._d90_spec = d90_spec self._index = index self._new = None @@ -131,21 +131,20 @@ class AddCommand(QUndoCommand): class DelCommand(QUndoCommand): - def __init__(self, data, ics_spec, rows): + def __init__(self, data, d90_spec, rows): QUndoCommand.__init__(self) self._data = data - self._ics_spec = ics_spec + self._d90_spec = d90_spec self._rows = rows - # self._data = data - self._ic = [] + self._d90 = [] for row in rows: - self._ic.append((row, self._ics_spec[row])) - self._ic.sort() + self._d90.append((row, self._d90_spec[row])) + self._d90.sort() def undo(self): - for row, el in self._ic: + for row, el in self._d90: self._data.insert(row, el) def redo(self): diff --git a/src/View/D90AdisTS/Window.py b/src/View/D90AdisTS/Window.py index 9cfb4f62..cb36d690 100644 --- a/src/View/D90AdisTS/Window.py +++ b/src/View/D90AdisTS/Window.py @@ -138,14 +138,14 @@ class D90AdisTSWindow(PamhyrWindow): self._delegate_reach = ComboBoxDelegate( trad=self._trad, data=self._study.river, - ic_spec_lst=self._data[0]._data, + d90_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, + d90_spec_lst=self._data[0]._data, parent=self, mode="rk" ) @@ -227,15 +227,15 @@ class D90AdisTSWindow(PamhyrWindow): table = list( map( - lambda eic: list( + lambda ed90: list( map( - lambda k: eic[1][k], + lambda k: ed90[1][k], ["rk", "discharge", "elevation"] ) ), filter( - lambda eic: eic[0] in rows, - enumerate(self._ics.lst()) + lambda ed90: ed90[0] in rows, + enumerate(self._d90.lst()) ) ) ) From cc500ceccfd80f32ed798e5941d49cf94ced7abe Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Wed, 8 Apr 2026 12:34:05 +0200 Subject: [PATCH 21/55] debug model InitialConditionsAdisTSSpec --- .../InitialConditionsAdisTS/InitialConditionsAdisTSSpec.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTSSpec.py b/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTSSpec.py index ed9cf0d3..e79c505a 100644 --- a/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTSSpec.py +++ b/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTSSpec.py @@ -31,7 +31,7 @@ class ICAdisTSSpec(SQLSubModel): _sub_classes = [] def __init__(self, id: int = -1, name: str = "", - status=None): + status=None, owner_scenario=None): super(ICAdisTSSpec, self).__init__() self._status = status @@ -194,7 +194,7 @@ class ICAdisTSSpec(SQLSubModel): new_spec.rate = rate new_spec.enabled = enabled - loaded.add(pid) + # loaded.add(pid) new.append(new_spec) data["scenario"] = scenario.parent @@ -211,7 +211,7 @@ class ICAdisTSSpec(SQLSubModel): sql = ( "INSERT INTO " + - "initial_conditions_adists_spec(id, deleted, " + + "initial_conditions_adists_spec(pamhyr_id, deleted, " + "ic_default, name, reach, " + "start_rk, end_rk, concentration, eg, em, ed, rate, " + "enabled, scenario) " + From e6d059bc19d2a86da75f0338c456c4eb02b7af4f Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Wed, 8 Apr 2026 14:33:02 +0200 Subject: [PATCH 22/55] correction erreur identifiant bdd --- .../LateralContributionsAdisTS/LateralContributionAdisTS.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py index 85b2e0ab..8c88f0e2 100644 --- a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py +++ b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py @@ -372,7 +372,7 @@ class LateralContributionAdisTS(SQLSubModel): execute( "INSERT INTO " + - "lateral_contribution_adists(id, deleted," + + "lateral_contribution_adists(pamhyr_id, deleted," + "pollutant, reach, begin_rk, end_rk, scenario) " + "VALUES (" + f"{self.id}, {self._db_format(self.is_deleted())}, " + From c498ed2d962db7e08c01823f7d5d65990fad32af Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 13 Apr 2026 13:10:50 +0200 Subject: [PATCH 23/55] add d50/sigma in database + load/save data in UI --- .../BoundaryCondition/BoundaryCondition.py | 50 +++++++++++++++++-- src/Model/Study.py | 2 +- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/Model/BoundaryCondition/BoundaryCondition.py b/src/Model/BoundaryCondition/BoundaryCondition.py index 86f2cb6e..d1da739b 100644 --- a/src/Model/BoundaryCondition/BoundaryCondition.py +++ b/src/Model/BoundaryCondition/BoundaryCondition.py @@ -232,6 +232,8 @@ class BoundaryCondition(SQLSubModel): type TEXT NOT NULL, tab TEXT NOT NULL, node INTEGER, + d50 REAL DEFAULT 0.002, + sigma REAL DEFAULT 1, {Scenario.create_db_add_scenario()}, {Scenario.create_db_add_scenario_fk()}, FOREIGN KEY(node) REFERENCES river_node(pamhyr_id), @@ -258,6 +260,17 @@ class BoundaryCondition(SQLSubModel): "ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE" ) + if major == "0" and int(minor) <= 2: + if int(release) < 4: + execute( + "ALTER TABLE boundary_condition " + + "ADD COLUMN d50 REAL DEFAULT 0.002" + ) + execute( + "ALTER TABLE boundary_condition " + + "ADD COLUMN sigma REAL DEFAULT 1" + ) + return cls._update_submodel(execute, version, data) @classmethod @@ -316,7 +329,7 @@ class BoundaryCondition(SQLSubModel): return new table = execute( - "SELECT pamhyr_id, deleted, name, type, node, scenario " + + "SELECT pamhyr_id, deleted, name, type, node, d50, sigma, scenario " + "FROM boundary_condition " + f"WHERE tab = '{tab}' " + f"AND scenario = {scenario.id} " + @@ -331,6 +344,8 @@ class BoundaryCondition(SQLSubModel): name = next(it) t = next(it) node = next(it) + d50 = next(it) + sigma = next(it) owner_scenario = next(it) ctor = cls._get_ctor_from_type(t) @@ -342,7 +357,9 @@ class BoundaryCondition(SQLSubModel): ) if deleted: bc.set_as_deleted() - + if t=="SL": + bc.d50 = d50 + bc.sigma = sigma bc.node = None if node != -1: bc.node = next(filter(lambda n: n.id == node, nodes), None) @@ -374,16 +391,23 @@ class BoundaryCondition(SQLSubModel): node = -1 if self._node is not None: node = self._node.id - + + d50 = 0.002 + sigma = 1 + if self._type == "SL": + d50 = self._d50 + sigma = self._sigma + execute( "INSERT INTO " + "boundary_condition(" + - "pamhyr_id, deleted, name, type, tab, node, scenario" + + "pamhyr_id, deleted, name, type, tab, node, d50, sigma, scenario" + ") " + "VALUES (" + f"{self._pamhyr_id}, {self._db_format(self.is_deleted())}, " + f"'{self._db_format(self._name)}', " + f"'{self._db_format(self._type)}', '{tab}', {node}, " + + f"{d50}, {sigma}, " + f"{self._status.scenario_id}" + ")" ) @@ -467,6 +491,24 @@ class BoundaryCondition(SQLSubModel): def has_node(self): return self._node is not None + + @property + def d50(self): + return self._d50 + + @d50.setter + def d50(self, value): + self._d50 = float(value) + self.modified() + + @property + def sigma(self): + return self._sigma + + @sigma.setter + def sigma(self, value): + self._sigma = float(value) + self.modified() @property def header(self): diff --git a/src/Model/Study.py b/src/Model/Study.py index f32e90bf..23113ab9 100644 --- a/src/Model/Study.py +++ b/src/Model/Study.py @@ -37,7 +37,7 @@ logger = logging.getLogger() class Study(SQLModel): - _version = "0.2.3" + _version = "0.2.4" _sub_classes = [ Scenario, From a68270ff67e9f3e195ee8cb8dbf3b5165da1ace2 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Thu, 16 Apr 2026 15:14:28 +0200 Subject: [PATCH 24/55] update model + view to display only BCAdisTS related to pollutant, and not the global list, todo: reconnect add/del buttons --- .../BoundaryConditionAdisTS.py | 4 +- src/Model/Pollutants/Pollutants.py | 16 ++++++- src/View/BoundaryConditionsAdisTS/Table.py | 44 +++++-------------- src/View/BoundaryConditionsAdisTS/Window.py | 25 ++++++----- .../BoundaryConditionsAdisTS/translate.py | 1 - src/View/Pollutants/Window.py | 37 ++++++++++------ 6 files changed, 66 insertions(+), 61 deletions(-) diff --git a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py index 24fa3cf2..c505e35d 100644 --- a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py +++ b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py @@ -312,6 +312,7 @@ class BoundaryConditionAdisTS(SQLSubModel): status = data['status'] nodes = data['nodes'] scenario = data["scenario"] + pollutant = data["pollutant"] loaded = data['loaded_pid'] if scenario is None: @@ -321,7 +322,8 @@ class BoundaryConditionAdisTS(SQLSubModel): "SELECT pamhyr_id, deleted, pollutant, type, node, scenario " + "FROM boundary_condition_adists " + f"WHERE scenario = {scenario.id} " + - f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " + f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " + + f"AND pollutant = {pollutant.id} " ) if table is not None: diff --git a/src/Model/Pollutants/Pollutants.py b/src/Model/Pollutants/Pollutants.py index ba5c3ac7..047ceb43 100644 --- a/src/Model/Pollutants/Pollutants.py +++ b/src/Model/Pollutants/Pollutants.py @@ -28,6 +28,7 @@ from tools import ( from Model.Tools.PamhyrDB import SQLSubModel from Model.Except import NotImplementedMethodeError from Model.Scenario import Scenario +from Model.BoundaryConditionsAdisTS.BoundaryConditionAdisTS import BoundaryConditionAdisTS logger = logging.getLogger() @@ -275,7 +276,8 @@ class PollutantCharacteristics(SQLSubModel): class Pollutants(SQLSubModel): - _sub_classes = [PollutantCharacteristics] + _sub_classes = [PollutantCharacteristics, + BoundaryConditionAdisTS] def __init__(self, id: int = -1, name: str = "", status=None, owner_scenario=-1): @@ -293,6 +295,11 @@ class Pollutants(SQLSubModel): self._enabled = True self._data = [] + self._boundary_conditions_adists = [] + + @property + def boundary_conditions_adists(self): + return self._boundary_conditions_adists @property def name(self): @@ -415,6 +422,10 @@ class Pollutants(SQLSubModel): new_pollutant._data = PollutantCharacteristics._db_load( execute, data=data ) + + new_pollutant._boundary_conditions_adists = BoundaryConditionAdisTS._db_load( + execute, data=data + ) loaded.add(pid) new.append(new_pollutant) @@ -455,6 +466,9 @@ class Pollutants(SQLSubModel): for d in self._data: ok &= d._db_save(execute, data) + for bc in self._boundary_conditions_adists: + ok &= bc._db_save(execute, data) + return ok def _data_traversal(self, diff --git a/src/View/BoundaryConditionsAdisTS/Table.py b/src/View/BoundaryConditionsAdisTS/Table.py index dd38b136..e4e79879 100644 --- a/src/View/BoundaryConditionsAdisTS/Table.py +++ b/src/View/BoundaryConditionsAdisTS/Table.py @@ -112,18 +112,21 @@ class ComboBoxDelegate(QItemDelegate): class TableModel(PamhyrTableModel): - def __init__(self, pollutant=None, bc_list=None, trad=None, **kwargs): + def __init__(self, bc_list=None, pollutant_bc_list=None, trad=None, **kwargs): self._trad = trad self._bc_list = bc_list - self._pollutant = pollutant + self._pollutant = pollutant_bc_list.id + self._pollutant_bc_list = pollutant_bc_list super(TableModel, self).__init__(trad=trad, **kwargs) + def _setup_lst(self): + self._lst = self._pollutant_bc_list.boundary_conditions_adists + def rowCount(self, parent): - return len(self._bc_list) + return len(self._lst) def data(self, index, role): - if role != Qt.ItemDataRole.DisplayRole: return QVariant() @@ -131,12 +134,12 @@ class TableModel(PamhyrTableModel): column = index.column() if self._headers[column] == "type": - n = self._bc_list.get(row).type + n = self._lst[row].type if n is None or n == "": return self._trad["not_associated"] return n elif self._headers[column] == "node": - n = self._bc_list.get(row).node + n = self._lst[row].node if n is None: return self._trad["not_associated"] tmp = next(filter(lambda x: x.id == n, self._data._nodes), None) @@ -144,18 +147,6 @@ class TableModel(PamhyrTableModel): return tmp.name else: return self._trad["not_associated"] - elif self._headers[column] == "pol": - n = self._bc_list.get(row).pollutant - if n is None or n == "not_associated" or n == "": - return self._trad["not_associated"] - tmp = next(filter(lambda x: x.id == n, - self._data._Pollutants.Pollutants_List - ), - None) - if tmp is not None: - return tmp.name - else: - return self._trad["not_associated"] return QVariant() @@ -179,22 +170,7 @@ class TableModel(PamhyrTableModel): self._bc_list, row, self._data.node(value) ) ) - elif self._headers[column] == "pol": - if value == self._trad["not_associated"]: - self._undo.push( - SetPolCommand( - self._bc_list, row, None - ) - ) - else: - pol = next(filter(lambda x: x.name == value, - self._data._Pollutants.Pollutants_List) - ) - self._undo.push( - SetPolCommand( - self._bc_list, row, pol.id - ) - ) + except Exception as e: logger.info(e) logger.debug(traceback.format_exc()) diff --git a/src/View/BoundaryConditionsAdisTS/Window.py b/src/View/BoundaryConditionsAdisTS/Window.py index 47039e81..8272efe5 100644 --- a/src/View/BoundaryConditionsAdisTS/Window.py +++ b/src/View/BoundaryConditionsAdisTS/Window.py @@ -58,11 +58,21 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow): _pamhyr_ui = "BoundaryConditionsAdisTS" _pamhyr_name = "Boundary conditions AdisTS" - def __init__(self, study=None, config=None, parent=None): + def __init__(self, data=None, pollutant_id=None, study=None, config=None, parent=None): + self._data = data + self._pollutant_id = pollutant_id + + _pollutants_lst = study._river._Pollutants.Pollutants_List + self._pollutant_name = next( + (x.name for x in _pollutants_lst if x.id == self._pollutant_id), + None + ) + trad = BCAdisTSTranslate() name = ( trad[self._pamhyr_name] + - " - " + study.name + " - " + study.name + + " - " + self._pollutant_name ) super(BoundaryConditionAdisTSWindow, self).__init__( @@ -73,7 +83,6 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow): parent=parent ) - self._pollutants_lst = self._study._river._Pollutants self._bcs = self._study.river.boundary_conditions_adists self.setup_graph() @@ -95,12 +104,6 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow): mode="node", parent=self ) - self._delegate_pol = ComboBoxDelegate( - trad=self._trad, - data=self._study.river, - mode="pol", - parent=self - ) table = self.find(QTableView, f"tableView") self._table = TableModel( @@ -110,10 +113,10 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow): delegates={ "type": self._delegate_type, "node": self._delegate_node, - "pol": self._delegate_pol, }, trad=self._trad, bc_list=self._study.river.boundary_conditions_adists, + pollutant_bc_list=self._data, undo=self._undo_stack, data=self._study.river ) @@ -156,7 +159,7 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow): ) def add(self): - self._table.add(len(self._bcs)) + self._table.add(len(self._data.boundary_conditions_adists)) def delete(self): rows = self.index_selected_rows() diff --git a/src/View/BoundaryConditionsAdisTS/translate.py b/src/View/BoundaryConditionsAdisTS/translate.py index e6ab6099..590c3511 100644 --- a/src/View/BoundaryConditionsAdisTS/translate.py +++ b/src/View/BoundaryConditionsAdisTS/translate.py @@ -34,5 +34,4 @@ class BCAdisTSTranslate(MainTranslate): self._sub_dict["table_headers"] = { "type": self._dict["type"], "node": _translate("BoundaryCondition", "Node"), - "pol": _translate("BoundaryCondition", "Pollutant") } diff --git a/src/View/Pollutants/Window.py b/src/View/Pollutants/Window.py index ee03ec1a..09cbdd87 100644 --- a/src/View/Pollutants/Window.py +++ b/src/View/Pollutants/Window.py @@ -222,21 +222,32 @@ class PollutantsWindow(PamhyrWindow): initial.show() def boundary_conditions(self): - - if self.sub_window_exists( - BoundaryConditionAdisTSWindow, - data=[self._study, None] - ): - bound = self.get_sub_window( - BoundaryConditionAdisTSWindow, - data=[self._study, None] - ) + rows = self.index_selected_rows() + if len(rows) == 0: return - bound = BoundaryConditionAdisTSWindow( - study=self._study, parent=self - ) - bound.show() + for row in rows: + pollutant_id = self._pollutants_lst.get(row).id + + bclist = self._study.river.boundary_conditions_adists.BCs_AdisTS_List + bcs_adists = [ + x for x in bclist + if x.pollutant == pollutant_id + ] + self._data = self._study.river.Pollutants.get(row) + if self.sub_window_exists( + BoundaryConditionAdisTSWindow, + data=[self._study, None, bcs_adists] + ): + return + + bound = BoundaryConditionAdisTSWindow( + study=self._study, + parent=self, + data=self._data, + pollutant_id=pollutant_id + ) + bound.show() def lateral_contrib(self): rows = self.index_selected_rows() From 04ea55e21a8426bfcf003b7ba1694f34b8e343f0 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Thu, 16 Apr 2026 16:44:14 +0200 Subject: [PATCH 25/55] can use '.' caracter and not only ',' in Shift Geometry window --- src/View/Geometry/ShiftDialog.py | 33 ++++++++++++++++++++-- src/View/Tools/FlexibleDoubleSpinBox.py | 37 +++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 src/View/Tools/FlexibleDoubleSpinBox.py diff --git a/src/View/Geometry/ShiftDialog.py b/src/View/Geometry/ShiftDialog.py index 38744429..85ff029b 100644 --- a/src/View/Geometry/ShiftDialog.py +++ b/src/View/Geometry/ShiftDialog.py @@ -17,7 +17,8 @@ # -*- coding: utf-8 -*- from View.Tools.PamhyrWindow import PamhyrDialog - +from PyQt5.QtWidgets import QDoubleSpinBox +from View.Tools.FlexibleDoubleSpinBox import FlexibleDoubleSpinBox class ShiftDialog(PamhyrDialog): _pamhyr_ui = "GeometryReachShift" @@ -30,9 +31,37 @@ class ShiftDialog(PamhyrDialog): options=[], parent=parent ) - + + self._replace_spinboxes() self._init_default_values() + def _replace_spinboxes(self): + for name in ["doubleSpinBox_X", "doubleSpinBox_Y", "doubleSpinBox_Z"]: + old = self.find(QDoubleSpinBox, name) + + if old is None: + continue + + new = FlexibleDoubleSpinBox(old.parent()) + new.setObjectName(old.objectName()) + + # Copier propriétés utiles + new.setDecimals(old.decimals()) + new.setMinimum(old.minimum()) + new.setMaximum(old.maximum()) + new.setSingleStep(old.singleStep()) + new.setValue(old.value()) + new.setGeometry(old.geometry()) + + # Remplacement dans layout si présent + layout = old.parent().layout() + if layout is not None: + layout.replaceWidget(old, new) + + old.hide() + old.setParent(None) + old.deleteLater() + def _init_default_values(self): self._dx = 0.0 self._dy = 0.0 diff --git a/src/View/Tools/FlexibleDoubleSpinBox.py b/src/View/Tools/FlexibleDoubleSpinBox.py new file mode 100644 index 00000000..34332bef --- /dev/null +++ b/src/View/Tools/FlexibleDoubleSpinBox.py @@ -0,0 +1,37 @@ +# PamhyrWindow.py -- Pamhyr +# Copyright (C) 2023-2025 INRAE +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# -*- coding: utf-8 -*- + +import os +import logging + +from PyQt5.QtWidgets import QDoubleSpinBox + + +class FlexibleDoubleSpinBox(QDoubleSpinBox): + + def keyPressEvent(self, event): + if event.text() == ".": + # Simule une virgule à la place du point + event = type(event)( + event.type(), + event.key(), + event.modifiers(), + "," + ) + + super().keyPressEvent(event) \ No newline at end of file From bc3ea9c4b9c359feb0a242a1617605eefdb39aa3 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 20 Apr 2026 23:01:04 +0200 Subject: [PATCH 26/55] =?UTF-8?q?ajout=20automatique=20de=20l'extansion=20?= =?UTF-8?q?.st=20lorsque=20l'on=20ne=20le=20stipule=20pas=20manuellement?= =?UTF-8?q?=20dans=20l'export=20des=20tron=C3=A7ons?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/View/Geometry/Window.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/View/Geometry/Window.py b/src/View/Geometry/Window.py index 13f25e30..0f780035 100644 --- a/src/View/Geometry/Window.py +++ b/src/View/Geometry/Window.py @@ -20,6 +20,7 @@ import os import sys import time import pathlib +from pathlib import Path import logging from copy import deepcopy @@ -685,10 +686,18 @@ class GeometryWindow(PamhyrWindow): ) if filename != '' and filename is not None: - self._export_to_file_st(filename) + suffix = Path(filename).suffix + if suffix != "": + if suffix == ".st" or suffix == ".ST": + self._export_to_file_st(filename[:-3]) + else: + # TODO : prévenir l'utilisateur que le format n'est pas exportable + pass + else: + self._export_to_file_st(filename) def _export_to_file_st(self, filename): - with open(filename, "w+") as f: + with open(filename+".st", "w+") as f: f.write("# Exported from Pamhyr2\n") self._export_to_file_st_reach(f, self._reach) From 8b6308d3c9a40596c82d10f9d396a7f650a4bf8d Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 21 Apr 2026 01:22:08 +0200 Subject: [PATCH 27/55] inversion du sens de zoom avec la molette sur les graphs (contrintuitif auparavant) --- src/View/Network/GraphWidget.py | 2 +- src/View/Scenarios/GraphWidget.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/View/Network/GraphWidget.py b/src/View/Network/GraphWidget.py index 6f91e293..4157bb63 100644 --- a/src/View/Network/GraphWidget.py +++ b/src/View/Network/GraphWidget.py @@ -901,7 +901,7 @@ class GraphWidget(QGraphicsView): painter.drawRect(sceneRect) def wheelEvent(self, event): - self.scaleView(math.pow(2.0, -event.angleDelta().y() / 240.0)) + self.scaleView(math.pow(2.0, event.angleDelta().y() / 240.0)) def scaleView(self, scaleFactor): factor = self.transform().scale( diff --git a/src/View/Scenarios/GraphWidget.py b/src/View/Scenarios/GraphWidget.py index 7405bef0..65a1ced4 100644 --- a/src/View/Scenarios/GraphWidget.py +++ b/src/View/Scenarios/GraphWidget.py @@ -312,7 +312,7 @@ class GraphWidget(QGraphicsView): painter.drawRect(sceneRect) def wheelEvent(self, event): - self.scaleView(math.pow(2.0, -event.angleDelta().y() / 240.0)) + self.scaleView(math.pow(2.0, event.angleDelta().y() / 240.0)) def keyPressEvent(self, event): key = event.key() From e21a64fcad3c6c21326124dbf00f2786f5d69eee Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 21 Apr 2026 10:20:24 +0200 Subject: [PATCH 28/55] =?UTF-8?q?zoom=20plus=20intuitif=20avec=20translati?= =?UTF-8?q?on=20du=20widget=20pour=20garder=20une=20coh=C3=A9rence=20dans?= =?UTF-8?q?=20le=20zoom?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/View/Network/GraphWidget.py | 13 ++++++++++++- src/View/Scenarios/GraphWidget.py | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/View/Network/GraphWidget.py b/src/View/Network/GraphWidget.py index 4157bb63..db877c06 100644 --- a/src/View/Network/GraphWidget.py +++ b/src/View/Network/GraphWidget.py @@ -901,7 +901,18 @@ class GraphWidget(QGraphicsView): painter.drawRect(sceneRect) def wheelEvent(self, event): - self.scaleView(math.pow(2.0, event.angleDelta().y() / 240.0)) + factor = math.pow(2.0, event.angleDelta().y() / 240.0) + + old_pos = self.mapToScene(event.pos()) + + self.scaleView(factor) + + new_pos = self.mapToScene(event.pos()) + + delta = old_pos - new_pos + + # Compensation pour garder le point sous la souris fixe + self.translate(delta.x(), delta.y()) def scaleView(self, scaleFactor): factor = self.transform().scale( diff --git a/src/View/Scenarios/GraphWidget.py b/src/View/Scenarios/GraphWidget.py index 65a1ced4..0fff07d3 100644 --- a/src/View/Scenarios/GraphWidget.py +++ b/src/View/Scenarios/GraphWidget.py @@ -312,7 +312,18 @@ class GraphWidget(QGraphicsView): painter.drawRect(sceneRect) def wheelEvent(self, event): - self.scaleView(math.pow(2.0, event.angleDelta().y() / 240.0)) + factor = math.pow(2.0, event.angleDelta().y() / 240.0) + + old_pos = self.mapToScene(event.pos()) + + self.scaleView(factor) + + new_pos = self.mapToScene(event.pos()) + + delta = old_pos - new_pos + + # Compensation pour garder le point sous la souris fixe + self.translate(delta.x(), delta.y()) def keyPressEvent(self, event): key = event.key() From aa6973813f6111417ea6c93017b8d2d107530bbf Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 21 Apr 2026 10:41:34 +0200 Subject: [PATCH 29/55] =?UTF-8?q?debug=20fonction=20SAVE=20des=20figures,?= =?UTF-8?q?=20qui=20utilisait=20une=20m=C3=A9thode=20Matplotlib,=20plut?= =?UTF-8?q?=C3=B4t=20qu'une=20m=C3=A9thode=20native=20Qt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/View/Tools/Plot/PamhyrToolbar.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/View/Tools/Plot/PamhyrToolbar.py b/src/View/Tools/Plot/PamhyrToolbar.py index 88c01951..593049a0 100644 --- a/src/View/Tools/Plot/PamhyrToolbar.py +++ b/src/View/Tools/Plot/PamhyrToolbar.py @@ -222,10 +222,11 @@ class PamhyrPlotToolbar(NavigationToolbar2QT): filters.append(new) filters = ';;'.join(filters) - file_name, _ = qt_compat._getSaveFileName( + file_name, _ = QtWidgets.QFileDialog.getSaveFileName( self.canvas.parent(), _translate("MainWindow_reach", "Select destination file"), - start, filters, + start, + filters, selected_filter ) From 8adf87858409aae2a5ffd14e605427812dab769f Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 21 Apr 2026 16:02:37 +0200 Subject: [PATCH 30/55] =?UTF-8?q?garde=20le=20zoom=20sur=20un=20graph=20ap?= =?UTF-8?q?r=C3=A8s=20rafraichissement=20des=20donn=C3=A9es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/View/BoundaryCondition/Edit/Plot.py | 2 +- src/View/BoundaryConditionsAdisTS/Edit/Plot.py | 2 +- src/View/Frictions/PlotRKZ.py | 2 +- src/View/Frictions/PlotStricklers.py | 2 +- src/View/Geometry/PlotAC.py | 2 +- src/View/HydraulicStructures/PlotAC.py | 2 +- src/View/HydraulicStructures/PlotRKC.py | 2 +- src/View/InitialConditions/PlotDRK.py | 2 +- src/View/InitialConditions/PlotDischarge.py | 2 +- src/View/LateralContribution/Edit/Plot.py | 2 +- src/View/LateralContributionsAdisTS/Edit/Plot.py | 2 +- src/View/PlotXY.py | 2 +- src/View/Reservoir/Edit/Plot.py | 2 +- src/View/Results/PlotAC.py | 2 +- src/View/Results/PlotRKC.py | 2 +- src/View/SedimentLayers/Edit/Plot.py | 2 +- src/View/SedimentLayers/Reach/Plot.py | 2 +- src/View/SedimentLayers/Reach/Profile/Plot.py | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/View/BoundaryCondition/Edit/Plot.py b/src/View/BoundaryCondition/Edit/Plot.py index ca0f753d..31b25f9b 100644 --- a/src/View/BoundaryCondition/Edit/Plot.py +++ b/src/View/BoundaryCondition/Edit/Plot.py @@ -54,7 +54,7 @@ class Plot(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False def custom_ticks(self): if self.data.header[0] != "time": diff --git a/src/View/BoundaryConditionsAdisTS/Edit/Plot.py b/src/View/BoundaryConditionsAdisTS/Edit/Plot.py index 174e7018..b320be27 100644 --- a/src/View/BoundaryConditionsAdisTS/Edit/Plot.py +++ b/src/View/BoundaryConditionsAdisTS/Edit/Plot.py @@ -55,7 +55,7 @@ class Plot(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False def custom_ticks(self): if self.data.header[0] != "time": diff --git a/src/View/Frictions/PlotRKZ.py b/src/View/Frictions/PlotRKZ.py index 0614a052..9e787cbc 100644 --- a/src/View/Frictions/PlotRKZ.py +++ b/src/View/Frictions/PlotRKZ.py @@ -43,7 +43,7 @@ class PlotRKZ(PlotRKC): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False self.parent = parent def onpick(self, event): diff --git a/src/View/Frictions/PlotStricklers.py b/src/View/Frictions/PlotStricklers.py index 7bdc3cd3..9abef064 100644 --- a/src/View/Frictions/PlotStricklers.py +++ b/src/View/Frictions/PlotStricklers.py @@ -50,7 +50,7 @@ class PlotStricklers(PamhyrPlot): self._auto_relim = False self._auto_relim_update = False - self._autoscale_update = True + self._autoscale_update = False @timer def draw(self, highlight=None): diff --git a/src/View/Geometry/PlotAC.py b/src/View/Geometry/PlotAC.py index cd1e3f76..1b846c5b 100644 --- a/src/View/Geometry/PlotAC.py +++ b/src/View/Geometry/PlotAC.py @@ -38,7 +38,7 @@ class PlotAC(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False self.label_x = self._trad["transverse_abscissa"] self.label_y = self._trad["unit_elevation"] diff --git a/src/View/HydraulicStructures/PlotAC.py b/src/View/HydraulicStructures/PlotAC.py index d8bfdb5b..7a51f66b 100644 --- a/src/View/HydraulicStructures/PlotAC.py +++ b/src/View/HydraulicStructures/PlotAC.py @@ -42,7 +42,7 @@ class PlotAC(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False @property def river(self): diff --git a/src/View/HydraulicStructures/PlotRKC.py b/src/View/HydraulicStructures/PlotRKC.py index 8ccdf148..d7ee4faf 100644 --- a/src/View/HydraulicStructures/PlotRKC.py +++ b/src/View/HydraulicStructures/PlotRKC.py @@ -50,7 +50,7 @@ class PlotRKC(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False self.parent = parent self.anotate_lst = [] diff --git a/src/View/InitialConditions/PlotDRK.py b/src/View/InitialConditions/PlotDRK.py index 6b4e81ad..76125391 100644 --- a/src/View/InitialConditions/PlotDRK.py +++ b/src/View/InitialConditions/PlotDRK.py @@ -47,7 +47,7 @@ class PlotDRK(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False @timer def draw(self, highlight=None): diff --git a/src/View/InitialConditions/PlotDischarge.py b/src/View/InitialConditions/PlotDischarge.py index 82adb880..5dad6092 100644 --- a/src/View/InitialConditions/PlotDischarge.py +++ b/src/View/InitialConditions/PlotDischarge.py @@ -37,7 +37,7 @@ class PlotDischarge(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False @timer def draw(self): diff --git a/src/View/LateralContribution/Edit/Plot.py b/src/View/LateralContribution/Edit/Plot.py index ca0f753d..31b25f9b 100644 --- a/src/View/LateralContribution/Edit/Plot.py +++ b/src/View/LateralContribution/Edit/Plot.py @@ -54,7 +54,7 @@ class Plot(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False def custom_ticks(self): if self.data.header[0] != "time": diff --git a/src/View/LateralContributionsAdisTS/Edit/Plot.py b/src/View/LateralContributionsAdisTS/Edit/Plot.py index ca0f753d..31b25f9b 100644 --- a/src/View/LateralContributionsAdisTS/Edit/Plot.py +++ b/src/View/LateralContributionsAdisTS/Edit/Plot.py @@ -54,7 +54,7 @@ class Plot(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False def custom_ticks(self): if self.data.header[0] != "time": diff --git a/src/View/PlotXY.py b/src/View/PlotXY.py index e51933ef..b498f3d4 100644 --- a/src/View/PlotXY.py +++ b/src/View/PlotXY.py @@ -68,7 +68,7 @@ class PlotXY(PamhyrPlot): self._isometric_axis = True self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False @timer def draw(self): diff --git a/src/View/Reservoir/Edit/Plot.py b/src/View/Reservoir/Edit/Plot.py index afb44ea2..9709c668 100644 --- a/src/View/Reservoir/Edit/Plot.py +++ b/src/View/Reservoir/Edit/Plot.py @@ -55,7 +55,7 @@ class Plot(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False @timer def draw(self): diff --git a/src/View/Results/PlotAC.py b/src/View/Results/PlotAC.py index bb188472..b2324a9b 100644 --- a/src/View/Results/PlotAC.py +++ b/src/View/Results/PlotAC.py @@ -56,7 +56,7 @@ class PlotAC(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False @property def results(self): diff --git a/src/View/Results/PlotRKC.py b/src/View/Results/PlotRKC.py index 065b42ca..2c09035c 100644 --- a/src/View/Results/PlotRKC.py +++ b/src/View/Results/PlotRKC.py @@ -59,7 +59,7 @@ class PlotRKC(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = True + self._autoscale_update = False @property def results(self): diff --git a/src/View/SedimentLayers/Edit/Plot.py b/src/View/SedimentLayers/Edit/Plot.py index 73a55b85..a9344333 100644 --- a/src/View/SedimentLayers/Edit/Plot.py +++ b/src/View/SedimentLayers/Edit/Plot.py @@ -49,7 +49,7 @@ class Plot(PamhyrPlot): self._auto_relim = False self._auto_relim_update = False - self._autoscale_update = True + self._autoscale_update = False @timer def draw(self): diff --git a/src/View/SedimentLayers/Reach/Plot.py b/src/View/SedimentLayers/Reach/Plot.py index 30adb2b7..0ab7aff4 100644 --- a/src/View/SedimentLayers/Reach/Plot.py +++ b/src/View/SedimentLayers/Reach/Plot.py @@ -53,7 +53,7 @@ class Plot(PamhyrPlot): self._auto_relim = False self._auto_relim_update = False - self._autoscale_update = True + self._autoscale_update = False @timer def draw(self): diff --git a/src/View/SedimentLayers/Reach/Profile/Plot.py b/src/View/SedimentLayers/Reach/Profile/Plot.py index 42d270e0..000295fd 100644 --- a/src/View/SedimentLayers/Reach/Profile/Plot.py +++ b/src/View/SedimentLayers/Reach/Profile/Plot.py @@ -53,7 +53,7 @@ class Plot(PamhyrPlot): self._auto_relim = False self._auto_relim_update = False - self._autoscale_update = True + self._autoscale_update = False @timer def draw(self): From d3e922af6ec12a1d998632d68a69f3f7d047f3a2 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 21 Apr 2026 16:55:04 +0200 Subject: [PATCH 31/55] =?UTF-8?q?desactivation=20du=20clic=20sur=20le=20gr?= =?UTF-8?q?aph=20du=20r=C3=A9seau=20hors=20de=20l'onglet=20d'=C3=A9dition?= =?UTF-8?q?=20du=20r=C3=A9seau=20(ex.=20BoundaryConditions...)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/View/Network/GraphWidget.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/View/Network/GraphWidget.py b/src/View/Network/GraphWidget.py index db877c06..83aa8014 100644 --- a/src/View/Network/GraphWidget.py +++ b/src/View/Network/GraphWidget.py @@ -925,6 +925,9 @@ class GraphWidget(QGraphicsView): self.scale(scaleFactor, scaleFactor) def mousePressEvent(self, event): + if self._only_display or self.graph._status.is_read_only(): + return + pos = self.mapToScene(event.pos()) self.clicked = True From 4408a8f368cf63aeb2859d4f2954ec7c10e10748 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Wed, 22 Apr 2026 12:05:28 +0200 Subject: [PATCH 32/55] debug save BoundaryConditionsAdisTS --- .../BoundaryConditionAdisTS.py | 25 ++++++---- .../BoundaryConditionsAdisTSList.py | 10 ++-- .../Edit/UndoCommand.py | 4 +- src/View/BoundaryConditionsAdisTS/Table.py | 46 +++++++++++++++---- .../BoundaryConditionsAdisTS/UndoCommand.py | 2 +- src/View/BoundaryConditionsAdisTS/Window.py | 4 +- 6 files changed, 63 insertions(+), 28 deletions(-) diff --git a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py index c505e35d..60a070a7 100644 --- a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py +++ b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py @@ -312,19 +312,21 @@ class BoundaryConditionAdisTS(SQLSubModel): status = data['status'] nodes = data['nodes'] scenario = data["scenario"] - pollutant = data["pollutant"] + pollutant = data.get("pollutant") loaded = data['loaded_pid'] if scenario is None: return new - table = execute( - "SELECT pamhyr_id, deleted, pollutant, type, node, scenario " + + sql = ( + "SELECT pamhyr_id, deleted, pollutant, type, node, scenario " "FROM boundary_condition_adists " + - f"WHERE scenario = {scenario.id} " + - f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " + - f"AND pollutant = {pollutant.id} " + f"WHERE scenario = {scenario.id} " ) + if pollutant is not None: + sql += f"AND pollutant = {pollutant.id} " + + table = execute(sql) if table is not None: for row in table: @@ -349,7 +351,7 @@ class BoundaryConditionAdisTS(SQLSubModel): bc.type = bc_type bc.node = None - if row[3] != -1: + if node != -1: tmp = next( filter( lambda n: n.id == node, nodes @@ -513,7 +515,10 @@ class BoundaryConditionAdisTS(SQLSubModel): return (new_0, new_1) def add(self, index: int): - value = (self._default_0, self._default_1) + value = Data( + self._default_0, self._default_1, + status=self._status + ) self._data.insert(index, value) self._status.modified() return value @@ -554,9 +559,9 @@ class BoundaryConditionAdisTS(SQLSubModel): return lst def _set_i_c_v(self, index, column, value): - v = list(self._data[index]) + v = self._data[index] v[column] = self._types[column](value) - self._data[index] = tuple(v) + self._data[index] = v self._status.modified() def set_i_0(self, index: int, value): diff --git a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionsAdisTSList.py b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionsAdisTSList.py index 0d1d729f..4bb90dbc 100644 --- a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionsAdisTSList.py +++ b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionsAdisTSList.py @@ -38,9 +38,13 @@ class BoundaryConditionsAdisTSList(PamhyrModelList): if data is None: data = {} - new._lst = BoundaryConditionAdisTS._db_load( - execute, data - ) + previous_pollutant = data.get("pollutant") + data.pop("pollutant", None) + + new._lst = BoundaryConditionAdisTS._db_load(execute, data) + + if previous_pollutant is not None: + data["pollutant"] = previous_pollutant return new diff --git a/src/View/BoundaryConditionsAdisTS/Edit/UndoCommand.py b/src/View/BoundaryConditionsAdisTS/Edit/UndoCommand.py index a4170a20..e4858bb1 100644 --- a/src/View/BoundaryConditionsAdisTS/Edit/UndoCommand.py +++ b/src/View/BoundaryConditionsAdisTS/Edit/UndoCommand.py @@ -61,9 +61,7 @@ class AddCommand(QUndoCommand): def redo(self): if self._new is None: - self._new = self._data.insert(self._index, ( - self._data._types[0](0), self._data._types[1](0.0) - )) + self._new = self._data.add(self._index) else: self._data.insert(self._index, self._new) diff --git a/src/View/BoundaryConditionsAdisTS/Table.py b/src/View/BoundaryConditionsAdisTS/Table.py index e4e79879..f0552029 100644 --- a/src/View/BoundaryConditionsAdisTS/Table.py +++ b/src/View/BoundaryConditionsAdisTS/Table.py @@ -121,9 +121,25 @@ class TableModel(PamhyrTableModel): super(TableModel, self).__init__(trad=trad, **kwargs) def _setup_lst(self): - self._lst = self._pollutant_bc_list.boundary_conditions_adists + self._lst = list( + filter( + lambda bc: bc.pollutant == self._pollutant, + self._bc_list.lst + ) + ) - def rowCount(self, parent): + def get(self, row): + if row < 0 or row >= len(self._lst): + return None + return self._lst[row] + + def _global_row(self, row): + bc = self.get(row) + if bc is None: + return None + return self._bc_list.index(bc) + + def rowCount(self, parent=QModelIndex()): return len(self._lst) def data(self, index, role): @@ -159,15 +175,21 @@ class TableModel(PamhyrTableModel): try: if self._headers[column] == "type": + global_row = self._global_row(row) self._undo.push( SetTypeCommand( - self._bc_list, row, value + self._bc_list, global_row, value ) ) elif self._headers[column] == "node": + global_row = self._global_row(row) + node = next( + filter(lambda n: n.name == value, self._data.nodes()), + None + ) self._undo.push( SetNodeCommand( - self._bc_list, row, self._data.node(value) + self._bc_list, global_row, node ) ) @@ -179,33 +201,39 @@ class TableModel(PamhyrTableModel): return True def add(self, row, parent=QModelIndex()): - self.beginInsertRows(parent, row, row - 1) - + row = len(self._lst) + self.beginInsertRows(parent, row, row) self._undo.push( AddCommand( - self._pollutant, self._bc_list, row + self._pollutant, self._bc_list, len(self._bc_list) ) ) - + self._setup_lst() self.endInsertRows() self.layoutChanged.emit() def delete(self, rows, parent=QModelIndex()): self.beginRemoveRows(parent, rows[0], rows[-1]) + global_rows = list( + map(self._global_row, rows) + ) self._undo.push( DelCommand( - self._bc_list, rows + self._bc_list, global_rows ) ) + 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/BoundaryConditionsAdisTS/UndoCommand.py b/src/View/BoundaryConditionsAdisTS/UndoCommand.py index 9a8d8243..f1531d71 100644 --- a/src/View/BoundaryConditionsAdisTS/UndoCommand.py +++ b/src/View/BoundaryConditionsAdisTS/UndoCommand.py @@ -36,7 +36,7 @@ class SetNodeCommand(QUndoCommand): self._bcs = bcs self._index = index self._old = self._bcs.get(self._index).node - self._new = node.id + self._new = node.id if node is not None else None def undo(self): self._bcs.get(self._index).node = self._old diff --git a/src/View/BoundaryConditionsAdisTS/Window.py b/src/View/BoundaryConditionsAdisTS/Window.py index 8272efe5..4c95befe 100644 --- a/src/View/BoundaryConditionsAdisTS/Window.py +++ b/src/View/BoundaryConditionsAdisTS/Window.py @@ -159,7 +159,7 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow): ) def add(self): - self._table.add(len(self._data.boundary_conditions_adists)) + self._table.add(self._table.rowCount()) def delete(self): rows = self.index_selected_rows() @@ -183,7 +183,7 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow): def edit(self): rows = self.index_selected_rows() for row in rows: - data = self._bcs.get(row) + data = self._table.get(row) if data.node is None: continue From b578e0c50ce509d14525a321ec0852c9481ffc0e Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Wed, 22 Apr 2026 13:45:15 +0200 Subject: [PATCH 33/55] =?UTF-8?q?d=C3=A9sactivation=20temporaire=20de=20un?= =?UTF-8?q?do=20dans=20la=20fen=C3=AAtre=20r=C3=A9sultat=20qui=20fait=20cr?= =?UTF-8?q?ash=20Pamhyr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/View/Results/Window.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/View/Results/Window.py b/src/View/Results/Window.py index 822b64e0..9324f356 100644 --- a/src/View/Results/Window.py +++ b/src/View/Results/Window.py @@ -701,7 +701,8 @@ class ResultsWindow(PamhyrWindow): logger.info("TODO: paste") def _undo(self): - self._table.undo() + logger.info("TODO: undo") + # self._table.undo() def _redo(self): self._table.redo() From fe39f07981b4864ac92a751ad339370d9c91082a Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 27 Apr 2026 10:07:36 +0200 Subject: [PATCH 34/55] consistency with called functions in the file --- .../BoundaryConditionAdisTS.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py index 60a070a7..408e44a8 100644 --- a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py +++ b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py @@ -455,7 +455,7 @@ class BoundaryConditionAdisTS(SQLSubModel): @node.setter def node(self, node): self._node = node - self._status.modified() + self.modified() @property def header(self): @@ -464,7 +464,7 @@ class BoundaryConditionAdisTS(SQLSubModel): @header.setter def header(self, header): self._header = header - self._status.modified() + self.modified() @property def pollutant(self): @@ -473,7 +473,7 @@ class BoundaryConditionAdisTS(SQLSubModel): @pollutant.setter def pollutant(self, pollutant): self._pollutant = pollutant - self._status.modified() + self.modified() @property def type(self): @@ -482,7 +482,7 @@ class BoundaryConditionAdisTS(SQLSubModel): @type.setter def type(self, type): self._type = type - self._status.modified() + self.modified() @property def data(self): @@ -520,12 +520,12 @@ class BoundaryConditionAdisTS(SQLSubModel): status=self._status ) self._data.insert(index, value) - self._status.modified() + self.modified() return value def insert(self, index: int, value): self._data.insert(index, value) - self._status.modified() + self.modified() def delete_i(self, indexes): self._data = list( @@ -537,14 +537,14 @@ class BoundaryConditionAdisTS(SQLSubModel): ) ) ) - self._status.modified() + self.modified() def sort(self, _reverse=False, key=None): if key is None: self._data.sort(reverse=_reverse) else: self._data.sort(reverse=_reverse, key=key) - self._status.modified() + self.modified() def index(self, bc): self._data.index(bc) @@ -562,7 +562,7 @@ class BoundaryConditionAdisTS(SQLSubModel): v = self._data[index] v[column] = self._types[column](value) self._data[index] = v - self._status.modified() + self.modified() def set_i_0(self, index: int, value): self._set_i_c_v(index, 0, value) From ac79fae1fbd0023cc19ebb96f005aec2c78646e7 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 27 Apr 2026 12:00:39 +0200 Subject: [PATCH 35/55] debug save db d90 --- src/Model/D90AdisTS/D90AdisTSSpec.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Model/D90AdisTS/D90AdisTSSpec.py b/src/Model/D90AdisTS/D90AdisTSSpec.py index 92f58f60..2b6277d1 100644 --- a/src/Model/D90AdisTS/D90AdisTSSpec.py +++ b/src/Model/D90AdisTS/D90AdisTSSpec.py @@ -196,12 +196,12 @@ class D90AdisTSSpec(SQLSubModel): "d90_default, name, reach, " + "start_rk, end_rk, d90, enabled, scenario) " + "VALUES (" + - f"{self.id}, {self._db_format(self.is_deleted())}" + + f"{self.id}, {self._db_format(self.is_deleted())}, " + f"{d90_default}, " + f"'{self._db_format(self._name_section)}', " + f"{self._reach}, " + f"{self._start_rk}, {self._end_rk}, " + - f"{self._d90}, {self._enabled}" + + f"{self._d90}, {self._enabled}, " + f"{self._status.scenario_id}" + ")" ) From df9e1ec42d73b5bdb5e69fb5615d1ca612e73711 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 27 Apr 2026 15:43:32 +0200 Subject: [PATCH 36/55] fix delete for pollutants D90 --- src/Model/D90AdisTS/D90AdisTSSpec.py | 2 +- src/View/D90AdisTS/Table.py | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Model/D90AdisTS/D90AdisTSSpec.py b/src/Model/D90AdisTS/D90AdisTSSpec.py index 2b6277d1..5af1c4bb 100644 --- a/src/Model/D90AdisTS/D90AdisTSSpec.py +++ b/src/Model/D90AdisTS/D90AdisTSSpec.py @@ -167,7 +167,7 @@ class D90AdisTSSpec(SQLSubModel): owner_scenario=owner_scenario ) if deleted: - new_spec.is_deleted() + new_spec.set_as_deleted() new_spec.reach = reach new_spec.start_rk = start_rk diff --git a/src/View/D90AdisTS/Table.py b/src/View/D90AdisTS/Table.py index 47390a71..769c79b3 100644 --- a/src/View/D90AdisTS/Table.py +++ b/src/View/D90AdisTS/Table.py @@ -118,7 +118,12 @@ class D90TableModel(PamhyrTableModel): self._data = data def _setup_lst(self): - self._lst = self._data._data + self._lst = list( + filter( + lambda d90: d90._deleted == False, + self._data._data + ) + ) def rowCount(self, parent): return len(self._lst) @@ -203,12 +208,18 @@ class D90TableModel(PamhyrTableModel): def delete(self, rows, parent=QModelIndex()): self.beginRemoveRows(parent, rows[0], rows[-1]) + data_rows = { + id(d90): i for i, d90 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] ) ) + self._setup_lst() self.endRemoveRows() self.layoutChanged.emit() From 1f97af9c037f65c59a15d10ea6cf38b5ee2c7c42 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 27 Apr 2026 15:44:57 +0200 Subject: [PATCH 37/55] clean useless data --- src/View/BoundaryConditionsAdisTS/Table.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/View/BoundaryConditionsAdisTS/Table.py b/src/View/BoundaryConditionsAdisTS/Table.py index f0552029..706edbc2 100644 --- a/src/View/BoundaryConditionsAdisTS/Table.py +++ b/src/View/BoundaryConditionsAdisTS/Table.py @@ -116,7 +116,6 @@ class TableModel(PamhyrTableModel): self._trad = trad self._bc_list = bc_list self._pollutant = pollutant_bc_list.id - self._pollutant_bc_list = pollutant_bc_list super(TableModel, self).__init__(trad=trad, **kwargs) From 4550fc95d77df91e0a90fb9412c8fbf4dda902b4 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 27 Apr 2026 16:32:41 +0200 Subject: [PATCH 38/55] debug delete functionnality in InitialConditionsAdisTS --- .../InitialConditionsAdisTS.py | 53 ++++++++++++------- src/View/InitialConditionsAdisTS/Table.py | 15 +++++- .../InitialConditionsAdisTS/UndoCommand.py | 1 - 3 files changed, 48 insertions(+), 21 deletions(-) diff --git a/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTS.py b/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTS.py index c0088779..98b63fd5 100644 --- a/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTS.py +++ b/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTS.py @@ -267,7 +267,7 @@ class InitialConditionsAdisTS(SQLSubModel): @name.setter def name(self, name): self._name = name - self._status.modified() + self.modified() @property def pollutant(self): @@ -276,7 +276,7 @@ class InitialConditionsAdisTS(SQLSubModel): @pollutant.setter def pollutant(self, pollutant): self._pollutant = pollutant - self._status.modified() + self.modified() @property def concentration(self): @@ -285,7 +285,7 @@ class InitialConditionsAdisTS(SQLSubModel): @concentration.setter def concentration(self, concentration): self._concentration = concentration - self._status.modified() + self.modified() @property def eg(self): @@ -294,7 +294,7 @@ class InitialConditionsAdisTS(SQLSubModel): @eg.setter def eg(self, eg): self._eg = eg - self._status.modified() + self.modified() @property def em(self): @@ -303,7 +303,7 @@ class InitialConditionsAdisTS(SQLSubModel): @em.setter def em(self, em): self._em = em - self._status.modified() + self.modified() @property def ed(self): @@ -312,7 +312,7 @@ class InitialConditionsAdisTS(SQLSubModel): @ed.setter def ed(self, ed): self._ed = ed - self._status.modified() + self.modified() @property def enabled(self): @@ -321,28 +321,45 @@ class InitialConditionsAdisTS(SQLSubModel): @enabled.setter def enabled(self, enabled): self._enabled = enabled - self._status.modified() + self.modified() def new(self, index): n = ICAdisTSSpec(status=self._status) self._data.insert(index, n) - self._status.modified() + self.modified() return n def delete(self, data): - self._data = list( - filter( - lambda x: x not in data, - self._data + list( + map( + lambda x: x.set_as_deleted(), + data ) ) - self._status.modified() + self.modified() def delete_i(self, indexes): - for ind in indexes: - del self._data[ind] - self._status.modified() + list( + map( + lambda e: e[1].set_as_deleted(), + filter( + lambda e: e[0] in indexes, + enumerate(self._data) + ) + ) + ) + self.modified() def insert(self, index, data): - self._data.insert(index, data) - self._status.modified() + if data in self._data: + self.undelete([data]) + else: + self._data.insert(index, data) + + self.modified() + + def undelete(self, lst): + for x in lst: + x.set_as_not_deleted() + + self.modified() diff --git a/src/View/InitialConditionsAdisTS/Table.py b/src/View/InitialConditionsAdisTS/Table.py index 531ce00b..a926c961 100644 --- a/src/View/InitialConditionsAdisTS/Table.py +++ b/src/View/InitialConditionsAdisTS/Table.py @@ -117,7 +117,12 @@ class InitialConditionTableModel(PamhyrTableModel): self._data = data def _setup_lst(self): - self._lst = self._data._data + self._lst = list( + filter( + lambda ica: ica._deleted == False, + self._data._data + ) + ) def rowCount(self, parent): return len(self._lst) @@ -222,12 +227,18 @@ class InitialConditionTableModel(PamhyrTableModel): def delete(self, rows, parent=QModelIndex()): self.beginRemoveRows(parent, rows[0], rows[-1]) + data_rows = { + id(ica): i for i, ica 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] ) ) + self._setup_lst() self.endRemoveRows() self.layoutChanged.emit() diff --git a/src/View/InitialConditionsAdisTS/UndoCommand.py b/src/View/InitialConditionsAdisTS/UndoCommand.py index 5ef0b50e..984be6e7 100644 --- a/src/View/InitialConditionsAdisTS/UndoCommand.py +++ b/src/View/InitialConditionsAdisTS/UndoCommand.py @@ -181,7 +181,6 @@ class DelCommand(QUndoCommand): self._data = data self._ics_spec = ics_spec self._rows = rows - # self._data = data self._ic = [] for row in rows: From e1c1f411c3046844331e26875d89641f570f7d00 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 27 Apr 2026 16:45:36 +0200 Subject: [PATCH 39/55] fix bug when add button didnt refresh the tab list in Initial conditions AdisTS and d90 --- src/View/D90AdisTS/Table.py | 1 + src/View/InitialConditionsAdisTS/Table.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/View/D90AdisTS/Table.py b/src/View/D90AdisTS/Table.py index 769c79b3..97d1dd0b 100644 --- a/src/View/D90AdisTS/Table.py +++ b/src/View/D90AdisTS/Table.py @@ -202,6 +202,7 @@ class D90TableModel(PamhyrTableModel): ) ) + self._setup_lst() self.endInsertRows() self.layoutChanged.emit() diff --git a/src/View/InitialConditionsAdisTS/Table.py b/src/View/InitialConditionsAdisTS/Table.py index a926c961..39ebe1c8 100644 --- a/src/View/InitialConditionsAdisTS/Table.py +++ b/src/View/InitialConditionsAdisTS/Table.py @@ -221,6 +221,7 @@ class InitialConditionTableModel(PamhyrTableModel): ) ) + self._setup_lst() self.endInsertRows() self.layoutChanged.emit() From cea4dcd9cb8be0f7baa6a9b6f961331509bfb2b9 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 28 Apr 2026 10:27:19 +0200 Subject: [PATCH 40/55] refacto variable names for D90 --- src/View/D90AdisTS/Table.py | 6 +++--- src/View/D90AdisTS/UndoCommand.py | 17 ++++++++--------- src/View/D90AdisTS/Window.py | 12 ++++++------ 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/View/D90AdisTS/Table.py b/src/View/D90AdisTS/Table.py index 97d1dd0b..69f76157 100644 --- a/src/View/D90AdisTS/Table.py +++ b/src/View/D90AdisTS/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, d90_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._d90_spec_lst = d90_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._d90_spec_lst[index.row()].reach reach = next(filter( lambda edge: edge.id == reach_id, self._data.edges() diff --git a/src/View/D90AdisTS/UndoCommand.py b/src/View/D90AdisTS/UndoCommand.py index 050bc675..23a2b6ac 100644 --- a/src/View/D90AdisTS/UndoCommand.py +++ b/src/View/D90AdisTS/UndoCommand.py @@ -112,11 +112,11 @@ class SetCommandSpec(QUndoCommand): class AddCommand(QUndoCommand): - def __init__(self, data, ics_spec, index): + def __init__(self, data, d90_spec, index): QUndoCommand.__init__(self) self._data = data - self._ics_spec = ics_spec + self._d90_spec = d90_spec self._index = index self._new = None @@ -131,21 +131,20 @@ class AddCommand(QUndoCommand): class DelCommand(QUndoCommand): - def __init__(self, data, ics_spec, rows): + def __init__(self, data, d90_spec, rows): QUndoCommand.__init__(self) self._data = data - self._ics_spec = ics_spec + self._d90_spec = d90_spec self._rows = rows - # self._data = data - self._ic = [] + self._d90 = [] for row in rows: - self._ic.append((row, self._ics_spec[row])) - self._ic.sort() + self._d90.append((row, self._d90_spec[row])) + self._d90.sort() def undo(self): - for row, el in self._ic: + for row, el in self._d90: self._data.insert(row, el) def redo(self): diff --git a/src/View/D90AdisTS/Window.py b/src/View/D90AdisTS/Window.py index 9cfb4f62..cb36d690 100644 --- a/src/View/D90AdisTS/Window.py +++ b/src/View/D90AdisTS/Window.py @@ -138,14 +138,14 @@ class D90AdisTSWindow(PamhyrWindow): self._delegate_reach = ComboBoxDelegate( trad=self._trad, data=self._study.river, - ic_spec_lst=self._data[0]._data, + d90_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, + d90_spec_lst=self._data[0]._data, parent=self, mode="rk" ) @@ -227,15 +227,15 @@ class D90AdisTSWindow(PamhyrWindow): table = list( map( - lambda eic: list( + lambda ed90: list( map( - lambda k: eic[1][k], + lambda k: ed90[1][k], ["rk", "discharge", "elevation"] ) ), filter( - lambda eic: eic[0] in rows, - enumerate(self._ics.lst()) + lambda ed90: ed90[0] in rows, + enumerate(self._d90.lst()) ) ) ) From 51dd6d27c51a1f42a72566eb2d5e0160792f65d9 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 28 Apr 2026 13:31:39 +0200 Subject: [PATCH 41/55] try fix ci pipeline --- .../BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py | 5 +++++ src/Model/Tools/PamhyrDB.py | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py index 408e44a8..fe047c5a 100644 --- a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py +++ b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py @@ -300,6 +300,11 @@ class BoundaryConditionAdisTS(SQLSubModel): if pol_id == -1: continue + if pol_id not in pid_pol: + # ⚠️ cas important : probablement déjà migré + print(f"[WARN] pol_id {pol_id} not in pid_pol → probably already migrated") + continue + execute( f"UPDATE boundary_condition_adists " + f"SET pollutant = {pid_pol[pol_id]} " + diff --git a/src/Model/Tools/PamhyrDB.py b/src/Model/Tools/PamhyrDB.py index 0a55cce5..265876f9 100644 --- a/src/Model/Tools/PamhyrDB.py +++ b/src/Model/Tools/PamhyrDB.py @@ -311,6 +311,11 @@ class SQLSubModel(PamhyrID): if node_id == -1: continue + if node_id not in nodes: + # ⚠️ cas important : probablement déjà migré + print(f"[WARN] node_id {node_id} not in nodes → probably already migrated") + continue + execute( f"UPDATE {table} " + f"SET node = {nodes[node_id]} " + From 61657198297e173fe8e26f6268ef4a0e0d6281c6 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 28 Apr 2026 14:30:40 +0200 Subject: [PATCH 42/55] warning popup when export format for geometry reach is not .st --- src/View/Geometry/Translate.py | 6 ++++++ src/View/Geometry/Window.py | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/View/Geometry/Translate.py b/src/View/Geometry/Translate.py index e0b567ba..3a2528af 100644 --- a/src/View/Geometry/Translate.py +++ b/src/View/Geometry/Translate.py @@ -91,3 +91,9 @@ class GeometryTranslate(MainTranslate): self._dict["Shift"] = _translate( "Geometry", "Shift" ) + self._dict["warning"] = _translate( + "Geometry", "Warning" + ) + self._dict["format_not_exportable"] = _translate( + "Geometry", "The format of the file is not exportable." + ) diff --git a/src/View/Geometry/Window.py b/src/View/Geometry/Window.py index 0f780035..89631518 100644 --- a/src/View/Geometry/Window.py +++ b/src/View/Geometry/Window.py @@ -691,7 +691,13 @@ class GeometryWindow(PamhyrWindow): if suffix == ".st" or suffix == ".ST": self._export_to_file_st(filename[:-3]) else: - # TODO : prévenir l'utilisateur que le format n'est pas exportable + # Warning popup when the format is not exportable + win = QtWidgets.QMessageBox() + win.setIcon(QtWidgets.QMessageBox.Warning) + win.setWindowTitle(self._trad["warning"]) + win.setText(self._trad["format_not_exportable"]) + win.exec() + pass else: self._export_to_file_st(filename) From 13a44264acfd38d36286d1c847bcfd867405ab33 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 28 Apr 2026 16:05:40 +0200 Subject: [PATCH 43/55] fix pep8 rules --- src/Model/BoundaryCondition/BoundaryCondition.py | 14 +++++++++----- .../BoundaryConditionAdisTS.py | 3 ++- src/Model/Pollutants/Pollutants.py | 13 +++++++++---- src/Model/Tools/PamhyrDB.py | 3 ++- src/View/BoundaryConditionsAdisTS/Table.py | 3 ++- src/View/BoundaryConditionsAdisTS/Window.py | 3 ++- src/View/D90AdisTS/Table.py | 2 +- src/View/Geometry/ShiftDialog.py | 3 ++- src/View/Geometry/Window.py | 2 +- src/View/InitialConditionsAdisTS/Table.py | 2 +- src/View/Pollutants/Window.py | 3 ++- src/View/Tools/FlexibleDoubleSpinBox.py | 4 ++-- 12 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/Model/BoundaryCondition/BoundaryCondition.py b/src/Model/BoundaryCondition/BoundaryCondition.py index d1da739b..fdc9c0a5 100644 --- a/src/Model/BoundaryCondition/BoundaryCondition.py +++ b/src/Model/BoundaryCondition/BoundaryCondition.py @@ -329,7 +329,8 @@ class BoundaryCondition(SQLSubModel): return new table = execute( - "SELECT pamhyr_id, deleted, name, type, node, d50, sigma, scenario " + + "SELECT pamhyr_id, deleted, name, type, node, d50, sigma, " + + "scenario " + "FROM boundary_condition " + f"WHERE tab = '{tab}' " + f"AND scenario = {scenario.id} " + @@ -355,11 +356,14 @@ class BoundaryCondition(SQLSubModel): status=data['status'], owner_scenario=owner_scenario ) + if deleted: bc.set_as_deleted() - if t=="SL": + + if t == "SL": bc.d50 = d50 bc.sigma = sigma + bc.node = None if node != -1: bc.node = next(filter(lambda n: n.id == node, nodes), None) @@ -391,13 +395,13 @@ class BoundaryCondition(SQLSubModel): node = -1 if self._node is not None: node = self._node.id - + d50 = 0.002 sigma = 1 if self._type == "SL": d50 = self._d50 sigma = self._sigma - + execute( "INSERT INTO " + "boundary_condition(" + @@ -491,7 +495,7 @@ class BoundaryCondition(SQLSubModel): def has_node(self): return self._node is not None - + @property def d50(self): return self._d50 diff --git a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py index fe047c5a..6dc3e836 100644 --- a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py +++ b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py @@ -302,7 +302,8 @@ class BoundaryConditionAdisTS(SQLSubModel): if pol_id not in pid_pol: # ⚠️ cas important : probablement déjà migré - print(f"[WARN] pol_id {pol_id} not in pid_pol → probably already migrated") + print(f"[WARN] pol_id {pol_id} not in pid_pol " + + f"→ probably already migrated") continue execute( diff --git a/src/Model/Pollutants/Pollutants.py b/src/Model/Pollutants/Pollutants.py index 047ceb43..72681f40 100644 --- a/src/Model/Pollutants/Pollutants.py +++ b/src/Model/Pollutants/Pollutants.py @@ -28,7 +28,9 @@ from tools import ( from Model.Tools.PamhyrDB import SQLSubModel from Model.Except import NotImplementedMethodeError from Model.Scenario import Scenario -from Model.BoundaryConditionsAdisTS.BoundaryConditionAdisTS import BoundaryConditionAdisTS +from Model.BoundaryConditionsAdisTS.BoundaryConditionAdisTS import ( + BoundaryConditionAdisTS, +) logger = logging.getLogger() @@ -422,9 +424,12 @@ class Pollutants(SQLSubModel): new_pollutant._data = PollutantCharacteristics._db_load( execute, data=data ) - - new_pollutant._boundary_conditions_adists = BoundaryConditionAdisTS._db_load( - execute, data=data + + new_pollutant._boundary_conditions_adists = ( + BoundaryConditionAdisTS._db_load( + execute, + data=data + ) ) loaded.add(pid) diff --git a/src/Model/Tools/PamhyrDB.py b/src/Model/Tools/PamhyrDB.py index 265876f9..9ca7257c 100644 --- a/src/Model/Tools/PamhyrDB.py +++ b/src/Model/Tools/PamhyrDB.py @@ -313,7 +313,8 @@ class SQLSubModel(PamhyrID): if node_id not in nodes: # ⚠️ cas important : probablement déjà migré - print(f"[WARN] node_id {node_id} not in nodes → probably already migrated") + print(f"[WARN] node_id {node_id} not in nodes " + + f"→ probably already migrated") continue execute( diff --git a/src/View/BoundaryConditionsAdisTS/Table.py b/src/View/BoundaryConditionsAdisTS/Table.py index 706edbc2..adde9683 100644 --- a/src/View/BoundaryConditionsAdisTS/Table.py +++ b/src/View/BoundaryConditionsAdisTS/Table.py @@ -112,7 +112,8 @@ class ComboBoxDelegate(QItemDelegate): class TableModel(PamhyrTableModel): - def __init__(self, bc_list=None, pollutant_bc_list=None, trad=None, **kwargs): + def __init__(self, bc_list=None, pollutant_bc_list=None, + trad=None, **kwargs): self._trad = trad self._bc_list = bc_list self._pollutant = pollutant_bc_list.id diff --git a/src/View/BoundaryConditionsAdisTS/Window.py b/src/View/BoundaryConditionsAdisTS/Window.py index 4c95befe..c35c9c60 100644 --- a/src/View/BoundaryConditionsAdisTS/Window.py +++ b/src/View/BoundaryConditionsAdisTS/Window.py @@ -58,7 +58,8 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow): _pamhyr_ui = "BoundaryConditionsAdisTS" _pamhyr_name = "Boundary conditions AdisTS" - def __init__(self, data=None, pollutant_id=None, study=None, config=None, parent=None): + def __init__(self, data=None, pollutant_id=None, study=None, + config=None, parent=None): self._data = data self._pollutant_id = pollutant_id diff --git a/src/View/D90AdisTS/Table.py b/src/View/D90AdisTS/Table.py index 69f76157..090a5a8b 100644 --- a/src/View/D90AdisTS/Table.py +++ b/src/View/D90AdisTS/Table.py @@ -120,7 +120,7 @@ class D90TableModel(PamhyrTableModel): def _setup_lst(self): self._lst = list( filter( - lambda d90: d90._deleted == False, + lambda d90: d90._deleted is False, self._data._data ) ) diff --git a/src/View/Geometry/ShiftDialog.py b/src/View/Geometry/ShiftDialog.py index 85ff029b..9368cd99 100644 --- a/src/View/Geometry/ShiftDialog.py +++ b/src/View/Geometry/ShiftDialog.py @@ -20,6 +20,7 @@ from View.Tools.PamhyrWindow import PamhyrDialog from PyQt5.QtWidgets import QDoubleSpinBox from View.Tools.FlexibleDoubleSpinBox import FlexibleDoubleSpinBox + class ShiftDialog(PamhyrDialog): _pamhyr_ui = "GeometryReachShift" _pamhyr_name = "Shift" @@ -31,7 +32,7 @@ class ShiftDialog(PamhyrDialog): options=[], parent=parent ) - + self._replace_spinboxes() self._init_default_values() diff --git a/src/View/Geometry/Window.py b/src/View/Geometry/Window.py index 89631518..ce4bc954 100644 --- a/src/View/Geometry/Window.py +++ b/src/View/Geometry/Window.py @@ -697,7 +697,7 @@ class GeometryWindow(PamhyrWindow): win.setWindowTitle(self._trad["warning"]) win.setText(self._trad["format_not_exportable"]) win.exec() - + pass else: self._export_to_file_st(filename) diff --git a/src/View/InitialConditionsAdisTS/Table.py b/src/View/InitialConditionsAdisTS/Table.py index 39ebe1c8..b84beed1 100644 --- a/src/View/InitialConditionsAdisTS/Table.py +++ b/src/View/InitialConditionsAdisTS/Table.py @@ -119,7 +119,7 @@ class InitialConditionTableModel(PamhyrTableModel): def _setup_lst(self): self._lst = list( filter( - lambda ica: ica._deleted == False, + lambda ica: ica._deleted is False, self._data._data ) ) diff --git a/src/View/Pollutants/Window.py b/src/View/Pollutants/Window.py index 09cbdd87..870f2fb5 100644 --- a/src/View/Pollutants/Window.py +++ b/src/View/Pollutants/Window.py @@ -229,7 +229,8 @@ class PollutantsWindow(PamhyrWindow): for row in rows: pollutant_id = self._pollutants_lst.get(row).id - bclist = self._study.river.boundary_conditions_adists.BCs_AdisTS_List + river = self._study.river + bclist = river.boundary_conditions_adists.BCs_AdisTS_List bcs_adists = [ x for x in bclist if x.pollutant == pollutant_id diff --git a/src/View/Tools/FlexibleDoubleSpinBox.py b/src/View/Tools/FlexibleDoubleSpinBox.py index 34332bef..74a1fbb6 100644 --- a/src/View/Tools/FlexibleDoubleSpinBox.py +++ b/src/View/Tools/FlexibleDoubleSpinBox.py @@ -23,7 +23,7 @@ from PyQt5.QtWidgets import QDoubleSpinBox class FlexibleDoubleSpinBox(QDoubleSpinBox): - + def keyPressEvent(self, event): if event.text() == ".": # Simule une virgule à la place du point @@ -34,4 +34,4 @@ class FlexibleDoubleSpinBox(QDoubleSpinBox): "," ) - super().keyPressEvent(event) \ No newline at end of file + super().keyPressEvent(event) From 2a7e322ee5dcbdbb8a95fa2d1f9b6c25164326c3 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 28 Apr 2026 16:44:33 +0200 Subject: [PATCH 44/55] fix name of window InitCondAdisTS to mention pollutant name --- src/View/BoundaryConditionsAdisTS/Window.py | 7 +++---- src/View/InitialConditionsAdisTS/Window.py | 9 +++++++-- src/View/Pollutants/Window.py | 3 ++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/View/BoundaryConditionsAdisTS/Window.py b/src/View/BoundaryConditionsAdisTS/Window.py index c35c9c60..03d73cfd 100644 --- a/src/View/BoundaryConditionsAdisTS/Window.py +++ b/src/View/BoundaryConditionsAdisTS/Window.py @@ -62,14 +62,13 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow): config=None, parent=None): self._data = data self._pollutant_id = pollutant_id - - _pollutants_lst = study._river._Pollutants.Pollutants_List + trad = BCAdisTSTranslate() + self._pollutant_name = next( - (x.name for x in _pollutants_lst if x.id == self._pollutant_id), + (x.name for x in study._river._Pollutants.Pollutants_List if x.id == self._pollutant_id), None ) - trad = BCAdisTSTranslate() name = ( trad[self._pamhyr_name] + " - " + study.name + diff --git a/src/View/InitialConditionsAdisTS/Window.py b/src/View/InitialConditionsAdisTS/Window.py index dce32696..34b99175 100644 --- a/src/View/InitialConditionsAdisTS/Window.py +++ b/src/View/InitialConditionsAdisTS/Window.py @@ -68,15 +68,20 @@ class InitialConditionsAdisTSWindow(PamhyrWindow): _pamhyr_ui = "InitialConditionsAdisTS" _pamhyr_name = "Initial condition AdisTS" - def __init__(self, data=None, study=None, config=None, parent=None): + def __init__(self, data=None, pollutant_id=None, study=None, config=None, parent=None): self._data = [] self._data.append(data) + self._pollutant_id = pollutant_id trad = IcAdisTSTranslate() + self._pollutant_name = next( + (x.name for x in study._river._Pollutants.Pollutants_List if x.id == self._pollutant_id), + None + ) name = ( trad[self._pamhyr_name] + " - " + study.name + - " - " + self._data[0].name + " - " + self._pollutant_name ) super(InitialConditionsAdisTSWindow, self).__init__( diff --git a/src/View/Pollutants/Window.py b/src/View/Pollutants/Window.py index 870f2fb5..53ed96e4 100644 --- a/src/View/Pollutants/Window.py +++ b/src/View/Pollutants/Window.py @@ -217,7 +217,8 @@ class PollutantsWindow(PamhyrWindow): initial = InitialConditionsAdisTSWindow( study=self._study, parent=self, - data=ics_adists + data=ics_adists, + pollutant_id=pollutant_id ) initial.show() From 9f26a7323c6893974705c785227957452f6fd3ed Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Wed, 29 Apr 2026 14:03:58 +0200 Subject: [PATCH 45/55] correction bug with saving data for lateral contributions adisTS --- .../LateralContributionsAdisTS/LateralContributionAdisTS.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py index 8c88f0e2..03f97607 100644 --- a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py +++ b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py @@ -372,12 +372,12 @@ class LateralContributionAdisTS(SQLSubModel): execute( "INSERT INTO " + - "lateral_contribution_adists(pamhyr_id, deleted," + + "lateral_contribution_adists(pamhyr_id, deleted, " + "pollutant, reach, begin_rk, end_rk, scenario) " + "VALUES (" + f"{self.id}, {self._db_format(self.is_deleted())}, " + f"{self._pollutant}, {self.reach}, " + - f"{self._begin_rk}, {self._end_rk}" + + f"{self._begin_rk}, {self._end_rk}, " + f"{self._status.scenario_id}" + ")" ) From b6895ae99c84d1c6a5fe302bc8abec54ac33f5eb Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Wed, 29 Apr 2026 14:09:34 +0200 Subject: [PATCH 46/55] correction bug with saving data for lateral contributions adisTS --- .../LateralContributionAdisTS.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py index 03f97607..5cafcdef 100644 --- a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py +++ b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py @@ -131,12 +131,14 @@ class Data(SQLSubModel): if scenario is None: return new + + lca = data["lca"] table = execute( "SELECT pamhyr_id, deleted, data0, data1 " + "FROM lateral_contribution_data_adists " + f"WHERE scenario = {scenario.id} " + - f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " + f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " + f"AND lca = '{lca.id}'" ) @@ -372,12 +374,12 @@ class LateralContributionAdisTS(SQLSubModel): execute( "INSERT INTO " + - "lateral_contribution_adists(pamhyr_id, deleted, " + + "lateral_contribution_adists(pamhyr_id, deleted," + "pollutant, reach, begin_rk, end_rk, scenario) " + "VALUES (" + f"{self.id}, {self._db_format(self.is_deleted())}, " + f"{self._pollutant}, {self.reach}, " + - f"{self._begin_rk}, {self._end_rk}, " + + f"{self._begin_rk}, {self._end_rk}" + f"{self._status.scenario_id}" + ")" ) From b3d631943cf7b8bd8b952b6e220236156c961fc7 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Wed, 29 Apr 2026 15:33:00 +0200 Subject: [PATCH 47/55] correction bug with saving data for lateral contributions adisTS --- .../LateralContributionsAdisTS/LateralContributionAdisTS.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py index 5cafcdef..859a4305 100644 --- a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py +++ b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py @@ -374,12 +374,12 @@ class LateralContributionAdisTS(SQLSubModel): execute( "INSERT INTO " + - "lateral_contribution_adists(pamhyr_id, deleted," + + "lateral_contribution_adists(pamhyr_id, deleted, " + "pollutant, reach, begin_rk, end_rk, scenario) " + "VALUES (" + f"{self.id}, {self._db_format(self.is_deleted())}, " + f"{self._pollutant}, {self.reach}, " + - f"{self._begin_rk}, {self._end_rk}" + + f"{self._begin_rk}, {self._end_rk}, " + f"{self._status.scenario_id}" + ")" ) From 2db1f4c7f7267e35e9b2d6a41e3f051f604cae75 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Thu, 30 Apr 2026 15:56:11 +0200 Subject: [PATCH 48/55] fix tab elts related to pollutants, and fix add/del functionnality for LateralContributionAdisTS --- .../LateralContributionAdisTS.py | 2 +- src/View/BoundaryConditionsAdisTS/Window.py | 5 ++- src/View/InitialConditionsAdisTS/Window.py | 6 ++- src/View/LateralContributionsAdisTS/Table.py | 44 +++++++++++++++++-- .../LateralContributionsAdisTS/UndoCommand.py | 15 +++---- src/View/LateralContributionsAdisTS/Window.py | 21 +++++++-- src/View/Pollutants/Window.py | 8 +++- 7 files changed, 79 insertions(+), 22 deletions(-) diff --git a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py index 859a4305..59572d65 100644 --- a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py +++ b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py @@ -131,7 +131,7 @@ class Data(SQLSubModel): if scenario is None: return new - + lca = data["lca"] table = execute( diff --git a/src/View/BoundaryConditionsAdisTS/Window.py b/src/View/BoundaryConditionsAdisTS/Window.py index 03d73cfd..439e2acf 100644 --- a/src/View/BoundaryConditionsAdisTS/Window.py +++ b/src/View/BoundaryConditionsAdisTS/Window.py @@ -63,9 +63,10 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow): self._data = data self._pollutant_id = pollutant_id trad = BCAdisTSTranslate() - + self._pollutant_name = next( - (x.name for x in study._river._Pollutants.Pollutants_List if x.id == self._pollutant_id), + (x.name for x in study._river._Pollutants.Pollutants_List + if x.id == self._pollutant_id), None ) diff --git a/src/View/InitialConditionsAdisTS/Window.py b/src/View/InitialConditionsAdisTS/Window.py index 34b99175..2f7ddacc 100644 --- a/src/View/InitialConditionsAdisTS/Window.py +++ b/src/View/InitialConditionsAdisTS/Window.py @@ -68,14 +68,16 @@ class InitialConditionsAdisTSWindow(PamhyrWindow): _pamhyr_ui = "InitialConditionsAdisTS" _pamhyr_name = "Initial condition AdisTS" - def __init__(self, data=None, pollutant_id=None, study=None, config=None, parent=None): + def __init__(self, data=None, pollutant_id=None, study=None, + config=None, parent=None): self._data = [] self._data.append(data) self._pollutant_id = pollutant_id trad = IcAdisTSTranslate() self._pollutant_name = next( - (x.name for x in study._river._Pollutants.Pollutants_List if x.id == self._pollutant_id), + (x.name for x in study._river._Pollutants.Pollutants_List + if x.id == self._pollutant_id), None ) name = ( diff --git a/src/View/LateralContributionsAdisTS/Table.py b/src/View/LateralContributionsAdisTS/Table.py index ede41f0b..1bd0b2b0 100644 --- a/src/View/LateralContributionsAdisTS/Table.py +++ b/src/View/LateralContributionsAdisTS/Table.py @@ -116,10 +116,22 @@ class TableModel(PamhyrTableModel): self._pollutant = pollutant super(TableModel, self).__init__(trad=trad, **kwargs) + self._setup_lst() def _setup_lst(self): - self._lst = self._data.lateral_contributions_adists.lst - self._tab = self._opt_data + if self._lcs_list is not None: + self._lcs_pol_list = [ + lcs for lcs in self._lcs_list.lst + if lcs.pollutant == self._pollutant + ] + + self._lst = list( + filter( + lambda x: x._deleted is False, + self._lcs_pol_list + ) + ) + # self._tab = self._opt_data self._long_types = self._trad.get_dict("long_types") def rowCount(self, parent): @@ -190,17 +202,43 @@ class TableModel(PamhyrTableModel): ) ) + self._setup_lst() self.endInsertRows() self.layoutChanged.emit() def delete(self, rows, parent=QModelIndex()): self.beginRemoveRows(parent, rows[0], rows[-1]) + global_rows = list( + map(self._global_row, rows) + ) self._undo.push( DelCommand( - self._lst, rows + self._lcs_list, global_rows ) ) + 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() + + def get(self, row): + if row < 0 or row >= len(self._lst): + return None + return self._lst[row] + + def _global_row(self, row): + bc = self.get(row) + if bc is None: + return None + return self._lcs_list.index(bc) diff --git a/src/View/LateralContributionsAdisTS/UndoCommand.py b/src/View/LateralContributionsAdisTS/UndoCommand.py index 04875d28..371d7408 100644 --- a/src/View/LateralContributionsAdisTS/UndoCommand.py +++ b/src/View/LateralContributionsAdisTS/UndoCommand.py @@ -91,13 +91,13 @@ class AddCommand(QUndoCommand): self._new = None def undo(self): - del self._lcs[self._index] + self._lcs.delete_i(self._index) def redo(self): if self._new is None: self._new = self._lcs.new(self._index, self._pollutant) else: - self._lcs_lst.insert(self._index, self._new) + self._lcs.insert(self._index, self._new) class DelCommand(QUndoCommand): @@ -107,15 +107,14 @@ class DelCommand(QUndoCommand): self._lcs = lcs self._rows = rows - self._bc = [] + self._lc = [] for row in rows: - self._bc.append((row, self._lcs[row])) - self._bc.sort() + self._lc.append((row, self._lcs.get(row))) + self._lc.sort() def undo(self): - for row, el in self._bc: + for row, el in self._lc: self._lcs.insert(row, el) def redo(self): - for row in self._rows: - del self._lcs[row] + self._lcs.delete_i(self._rows) diff --git a/src/View/LateralContributionsAdisTS/Window.py b/src/View/LateralContributionsAdisTS/Window.py index ded6a438..14926501 100644 --- a/src/View/LateralContributionsAdisTS/Window.py +++ b/src/View/LateralContributionsAdisTS/Window.py @@ -57,11 +57,24 @@ class LateralContributionAdisTSWindow(PamhyrWindow): _pamhyr_ui = "LateralContributionsAdisTS" _pamhyr_name = "Lateral contribution AdisTS" - def __init__(self, study=None, pollutant=None, config=None, parent=None): + def __init__(self, data=None, study=None, pollutant_id=None, + config=None, parent=None): + self._pollutant = pollutant_id + self._study = study + self._data = data trad = LCTranslate() - name = trad[self._pamhyr_name] + " - " + study.name - self._pollutant = pollutant + self._pollutant_name = next( + (x.name for x in study._river._Pollutants.Pollutants_List + if x.id == self._pollutant), + None + ) + + name = ( + trad[self._pamhyr_name] + + " - " + study.name + + " - " + self._pollutant_name + ) super(LateralContributionAdisTSWindow, self).__init__( title=name, @@ -110,7 +123,7 @@ class LateralContributionAdisTSWindow(PamhyrWindow): data=self._study.river, undo=self._undo_stack, trad=self._trad, - opt_data="liquid", + # opt_data="liquid", pollutant=self._pollutant, lcs_list=self._lcs, ) diff --git a/src/View/Pollutants/Window.py b/src/View/Pollutants/Window.py index 53ed96e4..75055462 100644 --- a/src/View/Pollutants/Window.py +++ b/src/View/Pollutants/Window.py @@ -258,6 +258,9 @@ class PollutantsWindow(PamhyrWindow): pollutant_id = self._pollutants_lst.get(rows[0]).id + lclist = self._study.river.lateral_contributions_adists.Lat_Cont_List + lcs_adists = [x for x in lclist if x.pollutant == pollutant_id] + if self.sub_window_exists( LateralContributionAdisTSWindow, data=[self._study, pollutant_id, None] @@ -266,8 +269,9 @@ class PollutantsWindow(PamhyrWindow): lateral = LateralContributionAdisTSWindow( study=self._study, - pollutant=pollutant_id, - parent=self + parent=self, + data=lcs_adists, + pollutant_id=pollutant_id, ) lateral.show() From f1dca727c6bf081cb29a4c8706c13ae48d61a02f Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 4 May 2026 11:11:23 +0200 Subject: [PATCH 49/55] rename edition BCadisTS and LCadisTS windows --- .../BoundaryConditionsAdisTS/Edit/Window.py | 20 ++++---- .../LateralContributionsAdisTS/Edit/Window.py | 46 +++++++++++-------- src/View/LateralContributionsAdisTS/Window.py | 5 +- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/src/View/BoundaryConditionsAdisTS/Edit/Window.py b/src/View/BoundaryConditionsAdisTS/Edit/Window.py index ca5e1eea..837f9f56 100644 --- a/src/View/BoundaryConditionsAdisTS/Edit/Window.py +++ b/src/View/BoundaryConditionsAdisTS/Edit/Window.py @@ -63,6 +63,16 @@ class EditBoundaryConditionWindow(PamhyrWindow): name = trad[self._pamhyr_name] + if self._data is not None: + n = self._data.node + node_name = next(filter( + lambda x: x.id == n, study.river._nodes + )).name + name += ( + f" - {study.name} " + + f"({node_name})" + ) + super(EditBoundaryConditionWindow, self).__init__( title=name, study=study, @@ -71,16 +81,6 @@ class EditBoundaryConditionWindow(PamhyrWindow): parent=parent ) - if self._data is not None: - n = self._data.node - node_name = next(filter( - lambda x: x.id == n, self._study.river._nodes - )).name - name += ( - f" - {study.name} " + - f"({node_name})" - ) - self._hash_data.append(data) self.setup_table() diff --git a/src/View/LateralContributionsAdisTS/Edit/Window.py b/src/View/LateralContributionsAdisTS/Edit/Window.py index ded461bb..01aa64fb 100644 --- a/src/View/LateralContributionsAdisTS/Edit/Window.py +++ b/src/View/LateralContributionsAdisTS/Edit/Window.py @@ -50,14 +50,38 @@ class EditLateralContributionAdisTSWindow(PamhyrWindow): _pamhyr_ui = "EditLateralContributionAdisTS" _pamhyr_name = "Edit lateral contribution AdisTS" - def __init__(self, data=None, - study=None, config=None, - parent=None): + def __init__(self, data=None, study=None, config=None, parent=None): self._data = data - trad = LCETranslate() + name = trad[self._pamhyr_name] + if self._data is not None: + if self._data.reach is not None: + reach_name = next(filter( + lambda reach: reach.id == self._data.reach, + study.river.reachs() + )).name + else: + reach_name = trad['not_associated'] + + if self._data.begin_rk is not None: + begin_rk = self._data.begin_rk + else: + begin_rk = trad['not_associated'] + + if self._data.end_rk is not None: + end_rk = self._data.end_rk + else: + end_rk = trad['not_associated'] + + name += ( + f" - {study.name} - " + + f"{reach_name} - " + + f"({begin_rk} - " + + f"{end_rk})" + ) + super(EditLateralContributionAdisTSWindow, self).__init__( title=name, study=study, @@ -66,20 +90,6 @@ class EditLateralContributionAdisTSWindow(PamhyrWindow): parent=parent ) - if self._data is not None: - if self._data.edge is not None: - edge_name = next(filter( - lambda edge: edge.id == self._data.edge, - self._study.river.edges() - )).name - else: - edge_name = trad['not_associated'] - - name += ( - f"{study.name} - " + - f"{edge_name})" - ) - self._hash_data.append(data) self.setup_table() diff --git a/src/View/LateralContributionsAdisTS/Window.py b/src/View/LateralContributionsAdisTS/Window.py index 14926501..d70b7254 100644 --- a/src/View/LateralContributionsAdisTS/Window.py +++ b/src/View/LateralContributionsAdisTS/Window.py @@ -250,8 +250,11 @@ class LateralContributionAdisTSWindow(PamhyrWindow): def edit(self): rows = self.index_selected_rows() + if not rows: + return + for row in rows: - data = self._lcs.lst[row] + data = self._table.get(row) if self.sub_window_exists( EditLateralContributionAdisTSWindow, From e615a6b9d45aef7bc43e2169f6848410d3b0033a Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 4 May 2026 13:03:18 +0200 Subject: [PATCH 50/55] debug index matching in delete function for LCAdisTS --- src/View/LateralContributionsAdisTS/Table.py | 18 +++++++++++++----- .../LateralContributionsAdisTS/UndoCommand.py | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/View/LateralContributionsAdisTS/Table.py b/src/View/LateralContributionsAdisTS/Table.py index 1bd0b2b0..04c1e933 100644 --- a/src/View/LateralContributionsAdisTS/Table.py +++ b/src/View/LateralContributionsAdisTS/Table.py @@ -121,7 +121,7 @@ class TableModel(PamhyrTableModel): def _setup_lst(self): if self._lcs_list is not None: self._lcs_pol_list = [ - lcs for lcs in self._lcs_list.lst + lcs for lcs in self._lcs_list._lst if lcs.pollutant == self._pollutant ] @@ -209,9 +209,14 @@ class TableModel(PamhyrTableModel): def delete(self, rows, parent=QModelIndex()): self.beginRemoveRows(parent, rows[0], rows[-1]) - global_rows = list( - map(self._global_row, rows) - ) + row_by_lc = { + id(lc): row for row, lc in enumerate(self._lcs_list._lst) + } + global_rows = [ + row_by_lc[id(self._lst[row])] + for row in rows + if 0 <= row < len(self._lst) + ] self._undo.push( DelCommand( self._lcs_list, global_rows @@ -241,4 +246,7 @@ class TableModel(PamhyrTableModel): bc = self.get(row) if bc is None: return None - return self._lcs_list.index(bc) + return next( + index for index, lcs in enumerate(self._lcs_list._lst) + if lcs is bc + ) diff --git a/src/View/LateralContributionsAdisTS/UndoCommand.py b/src/View/LateralContributionsAdisTS/UndoCommand.py index 371d7408..08cf408a 100644 --- a/src/View/LateralContributionsAdisTS/UndoCommand.py +++ b/src/View/LateralContributionsAdisTS/UndoCommand.py @@ -109,7 +109,7 @@ class DelCommand(QUndoCommand): self._lc = [] for row in rows: - self._lc.append((row, self._lcs.get(row))) + self._lc.append((row, self._lcs._lst[row])) self._lc.sort() def undo(self): From c014f0ef34c401c3a8d9331ee64d21ae7ae296fd Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 4 May 2026 14:51:34 +0200 Subject: [PATCH 51/55] erase old and useless methods --- src/View/LateralContributionsAdisTS/Table.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/View/LateralContributionsAdisTS/Table.py b/src/View/LateralContributionsAdisTS/Table.py index 04c1e933..dc3b614d 100644 --- a/src/View/LateralContributionsAdisTS/Table.py +++ b/src/View/LateralContributionsAdisTS/Table.py @@ -236,17 +236,3 @@ class TableModel(PamhyrTableModel): self._undo.redo() self._setup_lst() self.layoutChanged.emit() - - def get(self, row): - if row < 0 or row >= len(self._lst): - return None - return self._lst[row] - - def _global_row(self, row): - bc = self.get(row) - if bc is None: - return None - return next( - index for index, lcs in enumerate(self._lcs_list._lst) - if lcs is bc - ) From 102702e1df3b1621e63c7eaa88ccae33db5c8166 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Mon, 4 May 2026 14:52:31 +0200 Subject: [PATCH 52/55] fix delete function for BCAdisTS --- src/View/BoundaryConditionsAdisTS/Table.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/View/BoundaryConditionsAdisTS/Table.py b/src/View/BoundaryConditionsAdisTS/Table.py index adde9683..34633e0b 100644 --- a/src/View/BoundaryConditionsAdisTS/Table.py +++ b/src/View/BoundaryConditionsAdisTS/Table.py @@ -215,9 +215,14 @@ class TableModel(PamhyrTableModel): def delete(self, rows, parent=QModelIndex()): self.beginRemoveRows(parent, rows[0], rows[-1]) - global_rows = list( - map(self._global_row, rows) - ) + row_by_bc = { + id(bc): row for row, bc in enumerate(self._bc_list._lst) + } + global_rows = [ + row_by_bc[id(self._lst[row])] + for row in rows + if 0 <= row < len(self._lst) + ] self._undo.push( DelCommand( self._bc_list, global_rows From 30e34b68474f73ae038a290b9a815345a9a7cfb3 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 5 May 2026 10:28:30 +0200 Subject: [PATCH 53/55] debug add function and save/load in db for edit LCAdisTS window --- .../BoundaryConditionAdisTS.py | 1 + .../LateralContributionAdisTS.py | 66 +++++++++++++++++-- .../Edit/UndoCommand.py | 29 ++------ src/View/LateralContributionsAdisTS/Window.py | 2 +- 4 files changed, 68 insertions(+), 30 deletions(-) diff --git a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py index 6dc3e836..a83d49b5 100644 --- a/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py +++ b/src/Model/BoundaryConditionsAdisTS/BoundaryConditionAdisTS.py @@ -144,6 +144,7 @@ class Data(SQLSubModel): "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}" ) diff --git a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py index 59572d65..0913897c 100644 --- a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py +++ b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py @@ -135,7 +135,7 @@ class Data(SQLSubModel): lca = data["lca"] table = execute( - "SELECT pamhyr_id, deleted, data0, data1 " + + "SELECT pamhyr_id, deleted, data0, data1, scenario " + "FROM lateral_contribution_data_adists " + f"WHERE scenario = {scenario.id} " + f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " + @@ -152,16 +152,16 @@ class Data(SQLSubModel): data1 = next(it) owner_scenario = next(it) - data = cls( + lc = cls( data0, data1, id=pid, status=status, owner_scenario=owner_scenario ) if deleted: - data.set_as_deleted() + lc.set_as_deleted() loaded.add(pid) - new.append(data) + new.append(lc) data["scenario"] = scenario.parent new += cls._db_load(execute, data) @@ -177,7 +177,7 @@ class Data(SQLSubModel): execute( "INSERT INTO " + - "lateral_contribution_adists(pamhyr_id, deleted," + + "lateral_contribution_data_adists(pamhyr_id, deleted," + "data0, data1, lca, scenario) " + "VALUES (" + f"{self.id}, {self._db_format(self.is_deleted())}, " + @@ -384,6 +384,8 @@ class LateralContributionAdisTS(SQLSubModel): ")" ) + data["lca"] = self + ind = 0 for d in self._data: data["ind"] = ind @@ -473,3 +475,57 @@ class LateralContributionAdisTS(SQLSubModel): def end_rk(self, end_rk): self._end_rk = end_rk self.modified() + + @property + def _default_0(self): + return self._types[0](0) + + @property + def _default_1(self): + return self._types[1](0.0) + + def add(self, index: int): + value = Data(self._default_0, self._default_1, status=self._status) + self._data.insert(index, value) + self.modified() + return value + + def insert(self, index: int, data: Data): + self._data.insert(index, data) + self.modified() + + def delete_i(self, indexes): + self._data = list( + map( + lambda e: e[1], + filter( + lambda e: e[0] not in indexes, + enumerate(self.data) + ) + ) + ) + self.modified() + + def index(self, bc): + self._data.index(bc) + + def get_i(self, index: int): + return self._data[index] + + def get_range(self, _range): + lst = [] + for r in _range: + lst.append(r) + return lst + + def _set_i_c_v(self, index: int, column: int, value): + v = self._data[index] + v[column] = self._types[column](value) + self._data[index] = v + self.modified() + + def set_i_0(self, index: int, value): + self._set_i_c_v(index, 0, value) + + def set_i_1(self, index: int, value): + self._set_i_c_v(index, 1, value) diff --git a/src/View/LateralContributionsAdisTS/Edit/UndoCommand.py b/src/View/LateralContributionsAdisTS/Edit/UndoCommand.py index 427edf56..88fe63ad 100644 --- a/src/View/LateralContributionsAdisTS/Edit/UndoCommand.py +++ b/src/View/LateralContributionsAdisTS/Edit/UndoCommand.py @@ -34,29 +34,14 @@ class SetDataCommand(QUndoCommand): self._data = data self._index = index self._column = column - self._old = self._data._data[self._index][self._column] - _type = self._data._types[self._column] - self._new = _type(new_value) + self._old = self._data.get_i(self._index)[self._column] + self._new = new_value def undo(self): - if self._column == 0: - self._data._data[self._index] = ( - self._old, self._data._data[self._index][1] - ) - else: - self._data._data[self._index] = ( - self._data._data[self._index][0], self._old - ) + self._data._set_i_c_v(self._index, self._column, self._old) def redo(self): - if self._column == 0: - self._data._data[self._index] = ( - self._new, self._data._data[self._index][1] - ) - else: - self._data._data[self._index] = ( - self._data._data[self._index][0], self._new - ) + self._data._set_i_c_v(self._index, self._column, self._new) class AddCommand(QUndoCommand): @@ -72,11 +57,7 @@ class AddCommand(QUndoCommand): def redo(self): if self._new is None: - self._new = self._data._data.insert( - self._index, ( - self._data._types[0](0), self._data._types[1](0.0) - ) - ) + self._new = self._data.add(self._index) else: self._data._data.insert(self._index, self._new) diff --git a/src/View/LateralContributionsAdisTS/Window.py b/src/View/LateralContributionsAdisTS/Window.py index d70b7254..491c44f4 100644 --- a/src/View/LateralContributionsAdisTS/Window.py +++ b/src/View/LateralContributionsAdisTS/Window.py @@ -254,7 +254,7 @@ class LateralContributionAdisTSWindow(PamhyrWindow): return for row in rows: - data = self._table.get(row) + data = self._lcs.lst[row] if self.sub_window_exists( EditLateralContributionAdisTSWindow, From 377c5080389ca0fe29579a035738b526d77c72f9 Mon Sep 17 00:00:00 2001 From: Dylan Jeannin Date: Tue, 5 May 2026 10:29:13 +0200 Subject: [PATCH 54/55] correction pep8 --- .../LateralContributionAdisTS.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py index 0913897c..302093e9 100644 --- a/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py +++ b/src/Model/LateralContributionsAdisTS/LateralContributionAdisTS.py @@ -475,7 +475,7 @@ class LateralContributionAdisTS(SQLSubModel): def end_rk(self, end_rk): self._end_rk = end_rk self.modified() - + @property def _default_0(self): return self._types[0](0) @@ -493,7 +493,7 @@ class LateralContributionAdisTS(SQLSubModel): def insert(self, index: int, data: Data): self._data.insert(index, data) self.modified() - + def delete_i(self, indexes): self._data = list( map( @@ -511,13 +511,13 @@ class LateralContributionAdisTS(SQLSubModel): def get_i(self, index: int): return self._data[index] - + def get_range(self, _range): lst = [] for r in _range: lst.append(r) return lst - + def _set_i_c_v(self, index: int, column: int, value): v = self._data[index] v[column] = self._types[column](value) From cdcbbc2cf479d32767fd27667bf2ca8d1e2a1ea8 Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Rouby Date: Wed, 6 May 2026 11:03:56 +0200 Subject: [PATCH 55/55] doc: Remove watermark. --- doc/tools/PamhyrDoc.cls | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/tools/PamhyrDoc.cls b/doc/tools/PamhyrDoc.cls index 431f8942..6ef42acf 100644 --- a/doc/tools/PamhyrDoc.cls +++ b/doc/tools/PamhyrDoc.cls @@ -157,12 +157,12 @@ %% %% FIXME: Delete me for the first realease -\usepackage{draftwatermark} -\SetWatermarkLightness{0.8} -\SetWatermarkAngle{25} -\SetWatermarkScale{3} -\SetWatermarkFontSize{1cm} -\SetWatermarkText{Work in progress} +%% \usepackage{draftwatermark} +%% \SetWatermarkLightness{0.8} +%% \SetWatermarkAngle{25} +%% \SetWatermarkScale{3} +%% \SetWatermarkFontSize{1cm} +%% \SetWatermarkText{Work in progress} %% Icons