diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dd8178d4..61a4ab6f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -122,7 +122,7 @@ test-pep8: - pip3 install -r ./requirements.txt - pip3 install -U -r ./requirements.txt - pip3 install pycodestyle - - pycodestyle ./src + - pycodestyle --exclude="*_to_*.py" ./src allow_failure: true ######### diff --git a/src/Model/Friction/Friction.py b/src/Model/Friction/Friction.py index ecc4a559..d3be3cf5 100644 --- a/src/Model/Friction/Friction.py +++ b/src/Model/Friction/Friction.py @@ -24,6 +24,7 @@ from Model.Tools.PamhyrDB import SQLSubModel logger = logging.getLogger() + class Friction(SQLSubModel): def __init__(self, name: str = "", status=None): super(Friction, self).__init__() diff --git a/src/Model/Geometry/ProfileXYZ.py b/src/Model/Geometry/ProfileXYZ.py index 495fbac1..34146bc1 100644 --- a/src/Model/Geometry/ProfileXYZ.py +++ b/src/Model/Geometry/ProfileXYZ.py @@ -437,42 +437,57 @@ class ProfileXYZ(Profile, SQLSubModel): return abs(rg.dist(rd)) def get_water_limits(self, z): -#============================================================================== -# détermination des points limites RG et RD pour un niveau d'eau donné -# -# irg et ird sont les premiers indices en partant des rives gauche et -# droite qui correspondent à des points sous la surface de l'eau -# ptX et ptY sont les points interpolés où le plan d'eau intersecte le profil -# known_level est le niveau d'eau pour lequel on a obtenu irg, ird, ptX et ptY -#============================================================================== + # ==================================================================== + # détermination des points limites RG et RD pour un niveau + # d'eau donné + # + # irg et ird sont les premiers indices en partant des rives + # gauche et droite qui correspondent à des points sous la + # surface de l'eau ptX et ptY sont les points interpolés où + # le plan d'eau intersecte le profil known_level est le + # niveau d'eau pour lequel on a obtenu irg, ird, ptX et ptY + # ==================================================================== + # initialisation - irg = -1 ; ird = -1 + irg = -1 + ird = -1 + for i in range(self.number_points): if self.point(i).z <= z: irg = i + for i in reversed(range(self.number_points)): if self.point(i).z <= z: ird = i + # interpolation des points ptX et ptY - if (irg < self.number_points-1): - x=np.interp(z, - [self.point(irg).z,self.point(irg+1).z], - [self.point(irg).x,self.point(irg+1).x]) - y=np.interp(z, - [self.point(irg).z,self.point(irg+1).z], - [self.point(irg).y,self.point(irg+1).y]) - ptX=PointXYZ(x,y,z) + if (irg < self.number_points - 1): + x = np.interp( + z, + [self.point(irg).z, self.point(irg + 1).z], + [self.point(irg).x, self.point(irg + 1).x] + ) + y = np.interp( + z, + [self.point(irg).z, self.point(irg + 1).z], + [self.point(irg).y, self.point(irg + 1).y] + ) + ptX = PointXYZ(x, y, z) else: ptX = self.point(0) if (ird > 0): - x=np.interp(z, - [self.point(ird-1).z,self.point(ird).z], - [self.point(ird-1).x,self.point(ird).x]) - y=np.interp(z, - [self.point(ird).z,self.point(ird-1).z], - [self.point(ird).y,self.point(ird-1).y]) - ptY=PointXYZ(x,y,z) + x = np.interp( + z, + [self.point(ird-1).z, self.point(ird).z], + [self.point(ird-1).x, self.point(ird).x] + ) + y = np.interp( + z, + [self.point(ird).z, self.point(ird - 1).z], + [self.point(ird).y, self.point(ird - 1).y] + ) + ptY = PointXYZ(x, y, z) else: - ptY = self.point(self.number_points-1) + ptY = self.point(self.number_points - 1) - return ptX,ptY + return ptX, ptY diff --git a/src/Model/HydraulicStructures/Basic/HydraulicStructures.py b/src/Model/HydraulicStructures/Basic/HydraulicStructures.py index 691cf60c..e624d2ef 100644 --- a/src/Model/HydraulicStructures/Basic/HydraulicStructures.py +++ b/src/Model/HydraulicStructures/Basic/HydraulicStructures.py @@ -29,6 +29,7 @@ from Model.HydraulicStructures.Basic.Value import ( logger = logging.getLogger() + class BasicHS(SQLSubModel): _sub_classes = [ BHSValue, @@ -142,7 +143,7 @@ class BasicHS(SQLSubModel): data['bhs_id'] = self.id execute( - "DELETE FROM hydraulic_structures_basic_value "+ + "DELETE FROM hydraulic_structures_basic_value " + f"WHERE bhs = {bhs_id}" ) diff --git a/src/Model/HydraulicStructures/Basic/Types.py b/src/Model/HydraulicStructures/Basic/Types.py index a976aaa3..98ded30b 100644 --- a/src/Model/HydraulicStructures/Basic/Types.py +++ b/src/Model/HydraulicStructures/Basic/Types.py @@ -16,18 +16,22 @@ # -*- coding: utf-8 -*- -from Model.Except import NotImplementedMethodeError - from Model.HydraulicStructures.Basic.HydraulicStructures import ( BasicHS ) + from Model.HydraulicStructures.Basic.Value import ( BHSValue ) + class NotDefined(BasicHS): - def __init__(self, id: int = -1, name: str = "", status=None): - super(NotDefined, self).__init__(id=id, name=name, status=status) + def __init__(self, id: int = -1, name: str = "", + status=None): + super(NotDefined, self).__init__( + id=id, name=name, + status=status + ) self._type = "ND" self._data = [ diff --git a/src/Model/HydraulicStructures/Basic/Value.py b/src/Model/HydraulicStructures/Basic/Value.py index dccd41e5..ebf4744e 100644 --- a/src/Model/HydraulicStructures/Basic/Value.py +++ b/src/Model/HydraulicStructures/Basic/Value.py @@ -18,11 +18,12 @@ from Model.Tools.PamhyrDB import SQLSubModel + class BHSValue(SQLSubModel): _sub_classes = [] _id_cnt = 0 - def __init__(self, name: str = "", type = float, value = 0.0, + def __init__(self, name: str = "", type=float, value=0.0, status=None): super(BHSValue, self).__init__() @@ -117,7 +118,7 @@ class BHSValue(SQLSubModel): "hydraulic_structures_basic_value(name, type, value, bhs) " + "VALUES (" + f"'{self._db_format(self._name)}', " + - f"'{self._db_format(self._type_to_str(self._type))}', "+ + f"'{self._db_format(self._type_to_str(self._type))}', " + f"'{self._db_format(self._value)}', " + f"{bhs_id}" + ")" diff --git a/src/Model/HydraulicStructures/HydraulicStructures.py b/src/Model/HydraulicStructures/HydraulicStructures.py index 6d1a4734..3cb68f97 100644 --- a/src/Model/HydraulicStructures/HydraulicStructures.py +++ b/src/Model/HydraulicStructures/HydraulicStructures.py @@ -30,6 +30,7 @@ from Model.HydraulicStructures.Basic.Types import ( logger = logging.getLogger() + class HydraulicStructure(SQLSubModel): _sub_classes = [ BasicHS, @@ -55,7 +56,10 @@ class HydraulicStructure(SQLSubModel): self._enabled = True self._data = [] - HydraulicStructure._id_cnt = max(HydraulicStructure._id_cnt + 1, self.id) + HydraulicStructure._id_cnt = max( + HydraulicStructure._id_cnt + 1, + self.id + ) @classmethod def _db_create(cls, execute): diff --git a/src/Model/HydraulicStructures/HydraulicStructuresList.py b/src/Model/HydraulicStructures/HydraulicStructuresList.py index 0e1039fd..549d8074 100644 --- a/src/Model/HydraulicStructures/HydraulicStructuresList.py +++ b/src/Model/HydraulicStructures/HydraulicStructuresList.py @@ -22,6 +22,7 @@ from tools import trace, timer from Model.Tools.PamhyrList import PamhyrModelList from Model.HydraulicStructures.HydraulicStructures import HydraulicStructure + class HydraulicStructureList(PamhyrModelList): _sub_classes = [ HydraulicStructure, diff --git a/src/Model/InitialConditions/InitialConditions.py b/src/Model/InitialConditions/InitialConditions.py index 439445fa..a71f3133 100644 --- a/src/Model/InitialConditions/InitialConditions.py +++ b/src/Model/InitialConditions/InitialConditions.py @@ -376,7 +376,7 @@ class InitialConditions(SQLSubModel): * (abs(incline) ** (0.5))) ) - elevation= max( + elevation = max( profile.z_min() + height, previous_elevation ) @@ -422,7 +422,7 @@ class InitialConditions(SQLSubModel): ((width * 0.8) * strickler * (abs(incline) ** (0.5))) ) ** (0.6) - elevation= max( + elevation = max( profile.z_min() + height, previous_elevation ) diff --git a/src/Model/Network/Graph.py b/src/Model/Network/Graph.py index e3616d0e..7836a89c 100644 --- a/src/Model/Network/Graph.py +++ b/src/Model/Network/Graph.py @@ -213,7 +213,7 @@ class Graph(object): def is_enable_edge(self, edge): return edge._enable - #def get_edge_id(self, reach): + # def get_edge_id(self, reach): # for i, e in enumerate(self.enable_edges): # if e.id == reach.id: # return i diff --git a/src/Model/Reservoir/Reservoir.py b/src/Model/Reservoir/Reservoir.py index 97a63113..ebf7e24c 100644 --- a/src/Model/Reservoir/Reservoir.py +++ b/src/Model/Reservoir/Reservoir.py @@ -94,7 +94,11 @@ class Reservoir(SQLSubModel): new_reservoir._node = None if node_id != -1: - new_reservoir._node = next(filter(lambda n: n.id == node_id, data["nodes"])) + new_reservoir._node = next( + filter( + lambda n: n.id == node_id, data["nodes"] + ) + ) new_data = [] table = execute( diff --git a/src/Model/River.py b/src/Model/River.py index 2ba5a54f..99cf8d21 100644 --- a/src/Model/River.py +++ b/src/Model/River.py @@ -242,7 +242,9 @@ class River(Graph, SQLSubModel): self._parameters = {} self._sediment_layers = SedimentLayerList(status=self._status) self._reservoir = ReservoirList(status=self._status) - self._hydraulic_structures = HydraulicStructureList(status=self._status) + self._hydraulic_structures = HydraulicStructureList( + status=self._status + ) @classmethod def _db_create(cls, execute): diff --git a/src/Model/Tools/PamhyrDict.py b/src/Model/Tools/PamhyrDict.py index c8cab70a..31bc12a6 100644 --- a/src/Model/Tools/PamhyrDict.py +++ b/src/Model/Tools/PamhyrDict.py @@ -67,7 +67,7 @@ class PamhyrModelDict(SQLSubModel): if key in self._dict: v = self._dict[key] - if type(v) == types.GeneratorType: + if type(v) is types.GeneratorType: return list(v) return v diff --git a/src/Solver/Mage.py b/src/Solver/Mage.py index 5dc59207..7326d674 100644 --- a/src/Solver/Mage.py +++ b/src/Solver/Mage.py @@ -453,9 +453,20 @@ class Mage(CommandLineSolver): for hs in hydraulic_structures: if hs.reach.is_enable: reach_id = study.river.get_edge_id(hs.reach) - params = [p.value for p in hs.basic_hydraulic_structure.param] - param_str = ' '.join([f'{p.value:>10.3f}' for p in hs.basic_hydraulic_structure.param]) - f.write(f"{hs.basic_hydraulic_structure.type} {reach_id} {hs.kp:>12.3f} {params} {hs.name}\n") + params = [ + p.value for p in hs.basic_hydraulic_structure.param + ] + param_str = ' '.join( + [ + f'{p.value:>10.3f}' + for p in hs.basic_hydraulic_structure.param + ] + ) + f.write( + f"{hs.basic_hydraulic_structure.type} " + + f"{reach_id} {hs.kp:>12.3f} {params} " + + "{hs.name}\n" + ) return files @@ -465,7 +476,11 @@ class Mage(CommandLineSolver): qlog.put("Export REP file") # Write header - with mage_file_open(os.path.join(repertory, f"{name}.REP"), "w+") as f: + with mage_file_open( + os.path.join( + repertory, f"{name}.REP" + ), "w+" + ) as f: f.write("confirmation=non\n") for file in files: @@ -832,12 +847,13 @@ class Mage8(Mage): # Set data for profile RI reach.set(ri, timestamp, key, d) if key == "Z": - profile = study.river.current_reach().reach.profile(ri) - ptX,ptY = profile.get_water_limits(d) + profile = study.river\ + .current_reach()\ + .reach.profile(ri) + ptX, ptY = profile.get_water_limits(d) reach.set(ri, timestamp, "ptX", ptX) reach.set(ri, timestamp, "ptY", ptY) - endline() end = newline().size <= 0 diff --git a/src/View/BoundaryCondition/Edit/Window.py b/src/View/BoundaryCondition/Edit/Window.py index ccec087b..4bdbb5ae 100644 --- a/src/View/BoundaryCondition/Edit/Window.py +++ b/src/View/BoundaryCondition/Edit/Window.py @@ -160,7 +160,7 @@ class EditBoundaryConditionWindow(PamhyrWindow): table_headers=headers, editable_headers=self._data.header, delegates={ - #"time": self._delegate_time, + # "time": self._delegate_time, }, data=self._data, undo=self._undo_stack, diff --git a/src/View/BoundaryCondition/Table.py b/src/View/BoundaryCondition/Table.py index 024dc288..aad78fc3 100644 --- a/src/View/BoundaryCondition/Table.py +++ b/src/View/BoundaryCondition/Table.py @@ -115,13 +115,13 @@ class ComboBoxDelegate(QItemDelegate): class TableModel(PamhyrTableModel): - def __init__(self, trad = None, **kwargs): + def __init__(self, trad=None, **kwargs): self._trad = trad self._long_types = {} if self._trad is not None: self._long_types = self._trad.get_dict("long_types") - super(TableModel, self).__init__(trad = trad, **kwargs) + super(TableModel, self).__init__(trad=trad, **kwargs) def _setup_lst(self): self._lst = self._data.boundary_condition diff --git a/src/View/HydraulicStructures/BasicHydraulicStructures/Table.py b/src/View/HydraulicStructures/BasicHydraulicStructures/Table.py index 0522af55..983a5ad0 100644 --- a/src/View/HydraulicStructures/BasicHydraulicStructures/Table.py +++ b/src/View/HydraulicStructures/BasicHydraulicStructures/Table.py @@ -18,3 +18,160 @@ import logging import traceback + +from tools import trace, timer + +from PyQt5.QtCore import ( + Qt, QVariant, QAbstractTableModel, + QCoreApplication, QModelIndex, pyqtSlot, + QRect, +) + +from PyQt5.QtWidgets import ( + QDialogButtonBox, QPushButton, QLineEdit, + QFileDialog, QTableView, QAbstractItemView, + QUndoStack, QShortcut, QAction, QItemDelegate, + QComboBox, +) + +from View.Tools.PamhyrTable import PamhyrTableModel + +from View.HydraulicStructures.BasicHydraulicStructures.UndoCommand import ( + SetNameCommand, SetTypeCommand, + AddCommand, DelCommand, +) +from Model.HydraulicStructures.Basic.Types import BHS_types + +logger = logging.getLogger() + +_translate = QCoreApplication.translate + + +class ComboBoxDelegate(QItemDelegate): + def __init__(self, data=None, trad=None, parent=None): + super(ComboBoxDelegate, self).__init__(parent) + + self._data = data + self._trad = trad + + self._long_types = {} + if self._trad is not None: + self._long_types = self._trad.get_dict("long_types") + + def createEditor(self, parent, option, index): + self.editor = QComboBox(parent) + + + lst = list( + map( + lambda k: self._long_types[k], BHS_types.keys() + ) + ) + self.editor.addItems( + lst + ) + + self.editor.setCurrentText(index.data(Qt.DisplayRole)) + return self.editor + + def setEditorData(self, editor, index): + value = index.data(Qt.DisplayRole) + self.editor.currentTextChanged.connect(self.currentItemChanged) + + def setModelData(self, editor, model, index): + text = str(editor.currentText()) + model.setData(index, text) + editor.close() + editor.deleteLater() + + def updateEditorGeometry(self, editor, option, index): + r = QRect(option.rect) + if self.editor.windowFlags() & Qt.Popup: + if editor.parent() is not None: + r.setTopLeft(self.editor.parent().mapToGlobal(r.topLeft())) + editor.setGeometry(r) + + @pyqtSlot() + def currentItemChanged(self): + self.commitData.emit(self.sender()) + + +class TableModel(PamhyrTableModel): + def _setup_lst(self): + self._lst = self._data.basic_structures + + def rowCount(self, parent): + return len(self._lst) + + def data(self, index, role): + if role != Qt.ItemDataRole.DisplayRole: + return QVariant() + + row = index.row() + column = index.column() + + if self._headers[column] == "name": + return self._lst[row].name + elif self._headers[column] == "type": + n = self._lst[row].type + + return QVariant() + + def setData(self, index, value, role=Qt.EditRole): + if not index.isValid() or role != Qt.EditRole: + return False + + row = index.row() + column = index.column() + + try: + if self._headers[column] == "name": + self._undo.push( + SetNameCommand( + self._data, row, value + ) + ) + elif self._headers[column] == "type": + self._undo.push( + SetTypeCommand( + self._data, row, type + ) + ) + except Exception as e: + logger.info(e) + logger.debug(traceback.format_exc()) + + self.dataChanged.emit(index, index) + return True + + def add(self, row, parent=QModelIndex()): + self.beginInsertRows(parent, row, row - 1) + + self._undo.push( + AddCommand( + self._data, row + ) + ) + + self.endInsertRows() + self.layoutChanged.emit() + + def delete(self, rows, parent=QModelIndex()): + self.beginRemoveRows(parent, rows[0], rows[-1]) + + self._undo.push( + DelCommand( + self._data, rows + ) + ) + + self.endRemoveRows() + self.layoutChanged.emit() + + def undo(self): + self._undo.undo() + self.layoutChanged.emit() + + def redo(self): + self._undo.redo() + self.layoutChanged.emit() diff --git a/src/View/HydraulicStructures/BasicHydraulicStructures/Translate.py b/src/View/HydraulicStructures/BasicHydraulicStructures/Translate.py index f2d74d02..b267fc42 100644 --- a/src/View/HydraulicStructures/BasicHydraulicStructures/Translate.py +++ b/src/View/HydraulicStructures/BasicHydraulicStructures/Translate.py @@ -21,3 +21,17 @@ from PyQt5.QtCore import QCoreApplication from View.Tools.PamhyrTranslate import PamhyrTranslate _translate = QCoreApplication.translate + + +class BasicHydraulicStructuresTranslate(PamhyrTranslate): + def __init__(self): + super(BasicHydraulicStructuresTranslate, self).__init__() + + self._sub_dict["long_types"] = { + "ND": _translate("BasicHydraulicStructures", "Not defined"), + } + + self._sub_dict["table_headers"] = { + "name": _translate("BasicHydraulicStructures", "Name"), + "type": _translate("BasicHydraulicStructures", "Type"), + } diff --git a/src/View/HydraulicStructures/BasicHydraulicStructures/UndoCommand.py b/src/View/HydraulicStructures/BasicHydraulicStructures/UndoCommand.py index ca18efaa..2d7e4067 100644 --- a/src/View/HydraulicStructures/BasicHydraulicStructures/UndoCommand.py +++ b/src/View/HydraulicStructures/BasicHydraulicStructures/UndoCommand.py @@ -15,3 +15,104 @@ # along with this program. If not, see . # -*- coding: utf-8 -*- + +from copy import deepcopy +from tools import trace, timer + +from PyQt5.QtWidgets import ( + QMessageBox, QUndoCommand, QUndoStack, +) + + +class SetNameCommand(QUndoCommand): + def __init__(self, hs, index, new_value): + QUndoCommand.__init__(self) + + self._hs = hs + self._index = index + self._old = self._hs.basic_structure(self._index).name + self._new = str(new_value) + + def undo(self): + self._hs.basic_structure(self._index).name = self._old + + def redo(self): + self._hs.basic_structure(self._index).name = self._new + + +class SetTypeCommand(QUndoCommand): + def __init__(self, hs, index, reach): + QUndoCommand.__init__(self) + + self._hs = hs + self._index = index + self._type = _type + self._old = self._hs.basic_structure(self._index) + self._new = self._hs.basic_structure(self._index)\ + .convert(self._type) + + def undo(self): + self._hs.basic_structure(self._index).convert(self._old) + + def redo(self): + self._hs.basic_structure(self._index).convert(self._new) + + +class AddCommand(QUndoCommand): + def __init__(self, hs, index): + QUndoCommand.__init__(self) + + self._hs = hs + + self._index = index + self._new = None + + def undo(self): + self._hs.delete_i([self._index]) + + def redo(self): + if self._new is None: + self._new = self._hs.add(self._index) + else: + self._hs.insert(self._index, self._new) + + +class DelCommand(QUndoCommand): + def __init__(self, hs, rows): + QUndoCommand.__init__(self) + + self._hs = hs + + self._rows = rows + + self._bhs = [] + for row in rows: + self._bhs.append((row, self._hs.basic_structure(row))) + + def undo(self): + for row, el in self._bhs: + self._hs.insert(row, el) + + def redo(self): + self._hs.delete_i(self._rows) + + +class PasteCommand(QUndoCommand): + def __init__(self, hs, row, h_s): + QUndoCommand.__init__(self) + + self._hs = hs + + self._row = row + self._bhs = deepcopy(h_s) + self._bhs.reverse() + + def undo(self): + self._hs.delete_i( + self._tab, + range(self._row, self._row + len(self._bhs)) + ) + + def redo(self): + for r in self._bhs: + self._hs.insert(self._row, r) diff --git a/src/View/HydraulicStructures/BasicHydraulicStructures/Window.py b/src/View/HydraulicStructures/BasicHydraulicStructures/Window.py index 43e78cef..a555c2bf 100644 --- a/src/View/HydraulicStructures/BasicHydraulicStructures/Window.py +++ b/src/View/HydraulicStructures/BasicHydraulicStructures/Window.py @@ -15,3 +15,207 @@ # along with this program. If not, see . # -*- coding: utf-8 -*- + +import logging + +from tools import timer, trace + +from View.Tools.PamhyrWindow import PamhyrWindow + +from PyQt5 import QtCore +from PyQt5.QtCore import ( + Qt, QVariant, QAbstractTableModel, QCoreApplication, + pyqtSlot, pyqtSignal, QItemSelectionModel, +) + +from PyQt5.QtWidgets import ( + QDialogButtonBox, QPushButton, QLineEdit, + QFileDialog, QTableView, QAbstractItemView, + QUndoStack, QShortcut, QAction, QItemDelegate, + QHeaderView, QDoubleSpinBox, QVBoxLayout, QCheckBox +) + +from View.Tools.Plot.PamhyrCanvas import MplCanvas +from View.Tools.Plot.PamhyrToolbar import PamhyrPlotToolbar + +from View.HydraulicStructures.PlotAC import PlotAC + +from View.HydraulicStructures.BasicHydraulicStructures.Table import ( + TableModel, ComboBoxDelegate +) + +from View.Network.GraphWidget import GraphWidget +from View.HydraulicStructures.BasicHydraulicStructures.Translate import BasicHydraulicStructuresTranslate + +_translate = QCoreApplication.translate + +logger = logging.getLogger() + + +class BasicHydraulicStructuresWindow(PamhyrWindow): + _pamhyr_ui = "BasicHydraulicStructures" + _pamhyr_name = "Basic Hydraulic Structures" + + def __init__(self, data=None, study=None, config=None, parent=None): + name = self._pamhyr_name + " - " + study.name + + super(BasicHydraulicStructuresWindow, self).__init__( + title=name, + study=study, + config=config, + trad=BasicHydraulicStructuresTranslate(), + parent=parent + ) + + self._hash_data.append(data) + + self._hs = data + + self.setup_table() + self.setup_checkbox() + self.setup_plot() + self.setup_connections() + + def setup_table(self): + self._table = None + + self._delegate_type = ComboBoxDelegate( + trad=self._trad, + parent=self + ) + + table = self.find(QTableView, f"tableView") + self._table = TableModel( + table_view=table, + table_headers=self._trad.get_dict("table_headers"), + editable_headers=["name", "type"], + delegates={ + "type": self._delegate_type, + }, + trad=self._trad, + data=self._hs, + undo=self._undo_stack, + ) + + selectionModel = table.selectionModel() + index = table.model().index(0, 0) + + selectionModel.select( + index, + QItemSelectionModel.Rows | + QItemSelectionModel.ClearAndSelect | + QItemSelectionModel.Select + ) + table.scrollTo(index) + + def setup_checkbox(self): + self._checkbox = self.find(QCheckBox, f"checkBox") + self._set_checkbox_state() + + def setup_plot(self): + self.canvas = MplCanvas(width=5, height=4, dpi=100) + self.canvas.setObjectName("canvas") + self.toolbar = PamhyrPlotToolbar( + self.canvas, self + ) + self.plot_layout = self.find(QVBoxLayout, "verticalLayout") + self.plot_layout.addWidget(self.toolbar) + self.plot_layout.addWidget(self.canvas) + + self.plot_ac = PlotAC( + canvas=self.canvas, + river=self._study.river, + reach=None, + profile=None, + toolbar=self.toolbar + ) + self.plot_ac.draw() + + def setup_connections(self): + self.find(QAction, "action_add").triggered.connect(self.add) + self.find(QAction, "action_delete").triggered.connect(self.delete) + self._checkbox.stateChanged.connect(self._set_basic_structure_state) + + table = self.find(QTableView, "tableView") + table.selectionModel()\ + .selectionChanged\ + .connect(self.update) + + def index_selected(self): + table = self.find(QTableView, "tableView") + r = table.selectionModel()\ + .selectedRows() + if len(r)>0: + return r[0] + else: + return None + + def index_selected_row(self): + table = self.find(QTableView, "tableView") + r = table.selectionModel()\ + .selectedRows() + if len(r)>0: + return r[0].row() + else: + return None + + def index_selected_rows(self): + table = self.find(QTableView, "tableView") + return list( + # Delete duplicate + set( + map( + lambda i: i.row(), + table.selectedIndexes() + ) + ) + ) + + def add(self): + rows = self.index_selected_rows() + if len(self._hs) == 0 or len(rows) == 0: + self._table.add(0) + else: + self._table.add(rows[0]) + + def delete(self): + rows = self.index_selected_rows() + if len(rows) == 0: + return + + self._table.delete(rows) + + def _copy(self): + logger.info("TODO: copy") + + def _paste(self): + logger.info("TODO: paste") + + def _undo(self): + self._table.undo() + + def _redo(self): + self._table.redo() + + def _set_checkbox_state(self): + row = self.index_selected_row() + if row is None: + self._checkbox.setEnabled(False) + self._checkbox.setChecked(True) + else: + self._checkbox.setEnabled(True) + self._checkbox.setChecked(self._hs.basic_structure(row).enabled) + + def _set_basic_structure_state(self): + row = self.index_selected_row() + if row is None: + self._checkbox.setEnabled(False) + else: + self._hs.basic_structure(row).enabled = self._checkbox.isChecked() + + def update(self): + self._set_checkbox_state() + self._update_clear_plot() + + def _update_clear_plot(self): + rows = self.index_selected_rows() diff --git a/src/View/HydraulicStructures/PlotAC.py b/src/View/HydraulicStructures/PlotAC.py index 35584203..028d6573 100644 --- a/src/View/HydraulicStructures/PlotAC.py +++ b/src/View/HydraulicStructures/PlotAC.py @@ -126,5 +126,5 @@ class PlotAC(PamhyrPlot): def clear(self): if self.line_kp is not None: - self.line_kp.set_data([],[]) + self.line_kp.set_data([], []) self.canvas.figure.canvas.draw_idle() diff --git a/src/View/HydraulicStructures/PlotKPC.py b/src/View/HydraulicStructures/PlotKPC.py index 15a5a1a4..d3070c88 100644 --- a/src/View/HydraulicStructures/PlotKPC.py +++ b/src/View/HydraulicStructures/PlotKPC.py @@ -110,7 +110,6 @@ class PlotKPC(PamhyrPlot): color='red', lw=1. ) - self.canvas.figure.tight_layout() self.canvas.figure.canvas.draw_idle() if self.toolbar is not None: @@ -144,16 +143,15 @@ class PlotKPC(PamhyrPlot): def clear(self): if self.profile is not None: - self.profile.set_data([],[]) + self.profile.set_data([], []) if self.line_kp_zmin_zmax is not None: self.line_kp_zmin_zmax.remove() self.line_kp_zmin_zmax = None if self.line_kp_zmin is not None: - self.line_kp_zmin.set_data([],[]) + self.line_kp_zmin.set_data([], []) self.canvas.figure.canvas.draw_idle() def clear_profile(self): if self.profile is not None: - self.profile.set_data([],[]) + self.profile.set_data([], []) self.canvas.figure.canvas.draw_idle() - diff --git a/src/View/HydraulicStructures/Table.py b/src/View/HydraulicStructures/Table.py index e61d9094..58e08684 100644 --- a/src/View/HydraulicStructures/Table.py +++ b/src/View/HydraulicStructures/Table.py @@ -59,7 +59,9 @@ class ComboBoxDelegate(QItemDelegate): val = [] if self._mode == "kp": - reach = self._data.hydraulic_structures.get(index.row()).input_reach + reach = self._data.hydraulic_structures\ + .get(index.row())\ + .input_reach if reach is not None: val = list( map( @@ -138,6 +140,7 @@ class TableModel(PamhyrTableModel): row = index.row() column = index.column() + na = _translate("Hydraulic structure", "Not associated") try: if self._headers[column] == "name": @@ -147,12 +150,18 @@ class TableModel(PamhyrTableModel): ) ) elif self._headers[column] == "reach": + if value == na: + value = None + self._undo.push( SetReachCommand( self._lst, row, self._data.edge(value) ) ) elif self._headers[column] == "kp": + if value == na: + value = None + self._undo.push( SetKpCommand( self._lst, row, value diff --git a/src/View/HydraulicStructures/UndoCommand.py b/src/View/HydraulicStructures/UndoCommand.py index 75e2886b..826cd268 100644 --- a/src/View/HydraulicStructures/UndoCommand.py +++ b/src/View/HydraulicStructures/UndoCommand.py @@ -99,6 +99,7 @@ class SetEnabledCommand(QUndoCommand): logger.info(f"Undo {self._old} -> {self._new}") self._h_s_lst.get(self._index).enabled = self._new + class AddCommand(QUndoCommand): def __init__(self, h_s_lst, index): QUndoCommand.__init__(self) diff --git a/src/View/HydraulicStructures/Window.py b/src/View/HydraulicStructures/Window.py index ce90eafd..7c139dd3 100644 --- a/src/View/HydraulicStructures/Window.py +++ b/src/View/HydraulicStructures/Window.py @@ -84,13 +84,13 @@ class HydraulicStructuresWindow(PamhyrWindow): trad=self._trad, data=self._study.river, parent=self, - mode = "reaches" + mode="reaches" ) self._delegate_kp = ComboBoxDelegate( trad=self._trad, data=self._study.river, parent=self, - mode = "kp" + mode="kp" ) table = self.find(QTableView, f"tableView") @@ -177,7 +177,7 @@ class HydraulicStructuresWindow(PamhyrWindow): table = self.find(QTableView, "tableView") r = table.selectionModel().selectedRows() - if len(r)>0: + if len(r) > 0: return r[0] else: return None @@ -186,7 +186,7 @@ class HydraulicStructuresWindow(PamhyrWindow): table = self.find(QTableView, "tableView") r = table.selectionModel().selectedRows() - if len(r)>0: + if len(r) > 0: return r[0].row() else: return None @@ -233,7 +233,8 @@ class HydraulicStructuresWindow(PamhyrWindow): rows = self.index_selected_rows() for row in rows: data = self._hs_lst.get(row) - + print(row) + print(data) if self.sub_window_exists( BasicHydraulicStructuresWindow, data=[self._study, None, data] @@ -266,37 +267,43 @@ class HydraulicStructuresWindow(PamhyrWindow): def update(self): self._set_checkbox_state() + self._update_clear_plot() + def _update_clear_plot(self): rows = self.index_selected_rows() - if len(rows) > 0 and len(self._hs_lst) > 0: - reach = self._hs_lst.get(rows[0]).input_reach - else: - reach=None - self.plot_kpc.clear() - self.plot_ac.clear() + if len(rows) == 0 or len(self._hs_lst) == 0: + self._update_clear_all() return - profile_kp = self._hs_lst.get(rows[0]).input_kp - if profile_kp is None or profile_kp == "Not associated": - profile = None - self.plot_ac.clear() - self.plot_kpc.clear_profile() - else: - profile = reach.reach.get_profiles_from_kp(float(profile_kp)) - - if reach is not None and reach != "Not associated": + reach = self._hs_lst.get(rows[0]).input_reach + if reach is not None: self.plot_kpc.set_reach(reach) self.plot_ac.set_reach(reach) - else: - self.plot_kpc.clear() - self.plot_ac.clear() - return + profile_kp = self._hs_lst.get(rows[0]).input_kp + if profile_kp is not None: + profiles = reach.reach\ + .get_profiles_from_kp( + float(profile_kp) + ) - if profile is not None: - self.plot_kpc.set_profile(profile[0]) - self.plot_ac.set_profile(profile[0]) + if profiles is not None: + profile = profiles[0] + + self.plot_kpc.set_profile(profile) + self.plot_ac.set_profile(profile) + else: + self._update_clear_profile() + else: + self._update_clear_profile() else: - self.plot_ac.clear() - self.plot_kpc.clear_profile() + self._update_clear_all() + + def _update_clear_all(self): + self.plot_kpc.clear() + self.plot_ac.clear() + + def _update_clear_profile(self): + self.plot_ac.clear() + self.plot_kpc.clear_profile() diff --git a/src/View/LateralContribution/Edit/Window.py b/src/View/LateralContribution/Edit/Window.py index 745fd15e..897703a4 100644 --- a/src/View/LateralContribution/Edit/Window.py +++ b/src/View/LateralContribution/Edit/Window.py @@ -101,7 +101,7 @@ class EditLateralContributionWindow(PamhyrWindow): table_headers=headers, editable_headers=self._data.header, delegates={ - #"time": self._delegate_time, + # "time": self._delegate_time, }, data=self._data, undo=self._undo_stack, diff --git a/src/View/MainWindow.py b/src/View/MainWindow.py index a9d98062..89df56f3 100644 --- a/src/View/MainWindow.py +++ b/src/View/MainWindow.py @@ -195,7 +195,8 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): "action_menu_edit_geometry": self.open_geometry, "action_menu_boundary_conditions": self.open_boundary_cond, "action_menu_edit_reservoirs": self.open_reservoir, - "action_menu_edit_hydraulic_structures": self.open_hydraulic_structures, + "action_menu_edit_hydraulic_structures": + self.open_hydraulic_structures, "action_menu_initial_conditions": self.open_initial_conditions, "action_menu_edit_friction": self.open_frictions, "action_menu_edit_lateral_contribution": self.open_lateral_contrib, @@ -282,8 +283,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): Nothing """ self.update_enable_action() - # Maximise window - #self.showMaximized() + # self.showMaximized() def set_debug_lvl(self, debug=True): if debug: @@ -638,7 +638,10 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): ): return - hydraulic_structures = HydraulicStructuresWindow(study=self._study, parent=self) + hydraulic_structures = HydraulicStructuresWindow( + study=self._study, + parent=self + ) hydraulic_structures.show() def open_lateral_contrib(self): @@ -648,7 +651,10 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): ): return - lateral = LateralContributionWindow(study=self._study, parent=self) + lateral = LateralContributionWindow( + study=self._study, + parent=self + ) lateral.show() def open_stricklers(self): diff --git a/src/View/Reservoir/Edit/Plot.py b/src/View/Reservoir/Edit/Plot.py index 8f8f49b8..8c75a199 100644 --- a/src/View/Reservoir/Edit/Plot.py +++ b/src/View/Reservoir/Edit/Plot.py @@ -69,7 +69,7 @@ class Plot(PamhyrPlot): ) # Plot label - #header = self.data.header + # header = self.data.header self.canvas.axes.set_xlabel( self._table_headers["z"], color='black', fontsize=10 ) diff --git a/src/View/Reservoir/Edit/Window.py b/src/View/Reservoir/Edit/Window.py index 34724bea..865ae6c8 100644 --- a/src/View/Reservoir/Edit/Window.py +++ b/src/View/Reservoir/Edit/Window.py @@ -88,18 +88,13 @@ class EditReservoirWindow(PamhyrWindow): def setup_table(self): headers = {} table_headers = self._trad.get_dict("table_headers") - #for h in self._data.header: - #headers[h] = table_headers[h] table = self.find(QTableView, "tableView") self._table = TableModel( table_view=table, table_headers=table_headers, editable_headers=table_headers, - #editable_headers=self._data.header, - delegates={ - #"time": self._delegate_time, - }, + delegates={}, data=self._data, undo=self._undo_stack, opt_data=self._study.time_system @@ -181,7 +176,7 @@ class EditReservoirWindow(PamhyrWindow): rows = self.index_selected_rows() table = [] - #table.append(self._data.header) + # table.append(self._data.header) table.append(self._trad.get_dict("table_headers")) data = self._data.data diff --git a/src/View/Results/PlotH.py b/src/View/Results/PlotH.py index 5709efb4..3494cfa5 100644 --- a/src/View/Results/PlotH.py +++ b/src/View/Results/PlotH.py @@ -175,12 +175,12 @@ class PlotH(PamhyrPlot): def set_timestamp(self, timestamp): self._current_timestamp = timestamp - #self.update() + # self.update() def update(self): reach = self.results.river.reach(self._current_reach_id) profile = reach.profile(self._current_profile_id) x = self.ts y = profile.get_key("Q") - self._line.set_data(x,y) + self._line.set_data(x, y) self.canvas.figure.canvas.draw_idle() diff --git a/src/View/Results/PlotKPC.py b/src/View/Results/PlotKPC.py index 93f91c9f..34ed91f9 100644 --- a/src/View/Results/PlotKPC.py +++ b/src/View/Results/PlotKPC.py @@ -105,8 +105,14 @@ class PlotKPC(PamhyrPlot): ) self.profile, = self.canvas.axes.plot( - [kp[self._current_profile_id], kp[self._current_profile_id]], - [z_max[self._current_profile_id],z_min[self._current_profile_id]], + [ + kp[self._current_profile_id], + kp[self._current_profile_id] + ], + [ + z_max[self._current_profile_id], + z_min[self._current_profile_id] + ], color='red', lw=1. ) @@ -137,7 +143,13 @@ class PlotKPC(PamhyrPlot): z_min = reach.geometry.get_z_min() z_max = reach.geometry.get_z_max() self.profile.set_data( - [kp[self._current_profile_id], kp[self._current_profile_id]], - [z_max[self._current_profile_id],z_min[self._current_profile_id]] + [ + kp[self._current_profile_id], + kp[self._current_profile_id] + ], + [ + z_max[self._current_profile_id], + z_min[self._current_profile_id] + ] ) self.canvas.figure.canvas.draw_idle() diff --git a/src/View/Results/PlotXY.py b/src/View/Results/PlotXY.py index 559fd9a6..3d0e2281 100644 --- a/src/View/Results/PlotXY.py +++ b/src/View/Results/PlotXY.py @@ -136,10 +136,14 @@ class PlotXY(PamhyrPlot): poly_x = [0] poly_y = [0] - self.fill = self.canvas.axes.fill(poly_x, poly_y, color='skyblue', alpha=0.7) + self.fill = self.canvas.axes.fill( + poly_x, poly_y, + color='skyblue', + alpha=0.7 + ) - #self.canvas.axes.autoscale_view(True, True, True) - #self.canvas.axes.autoscale() + # self.canvas.axes.autoscale_view(True, True, True) + # self.canvas.axes.autoscale() self.canvas.figure.tight_layout() self.canvas.figure.canvas.draw_idle() if self.toolbar is not None: @@ -166,7 +170,7 @@ class PlotXY(PamhyrPlot): # Current profile profile = reach.profile(self._current_profile_id).geometry - self.plot_selected.set_data(profile.x(),profile.y()) + self.plot_selected.set_data(profile.x(), profile.y()) self.plot_selected.set_visible(True) self.canvas.draw_idle() @@ -196,12 +200,12 @@ class PlotXY(PamhyrPlot): poly_r_x.append(ptY.x) poly_r_y.append(ptY.y) - #self.canvas.axes.plot( - #x, y, lw=1., - #color='b', - #markersize=1, - #marker='o' - #) + # self.canvas.axes.plot( + # x, y, lw=1., + # color='b', + # markersize=1, + # marker='o' + # ) poly_x = poly_l_x + list(reversed(poly_r_x)) poly_y = poly_l_y + list(reversed(poly_r_y)) diff --git a/src/View/Results/Window.py b/src/View/Results/Window.py index 9933f189..68a38b34 100644 --- a/src/View/Results/Window.py +++ b/src/View/Results/Window.py @@ -125,9 +125,13 @@ class ResultsWindow(PamhyrWindow): self._slider_time.setValue(len(self._timestamps) - 1) self._icon_start = QIcon() - self._icon_start.addPixmap(QPixmap('./src/View/ui/ressources/media-playback-start.png')) + self._icon_start.addPixmap( + QPixmap('./src/View/ui/ressources/media-playback-start.png') + ) self._icon_pause = QIcon() - self._icon_pause.addPixmap(QPixmap('./src/View/ui/ressources/media-playback-pause.png')) + self._icon_pause.addPixmap( + QPixmap('./src/View/ui/ressources/media-playback-pause.png') + ) self._button_play = self.find(QPushButton, f"playButton") self._button_play.setIcon(self._icon_start) self._button_back = self.find(QPushButton, f"backButton") diff --git a/src/tools.py b/src/tools.py index b6f78857..1ad8c382 100644 --- a/src/tools.py +++ b/src/tools.py @@ -67,6 +67,7 @@ def logger_color_reset(): return f"{Style.RESET_ALL}" return "" + def logger_exception(exception): logger.error( f"[{Fore.RED}ERROR{Style.RESET_ALL}] " + diff --git a/tests.sh b/tests.sh index 06c8fd84..ff235027 100755 --- a/tests.sh +++ b/tests.sh @@ -16,7 +16,7 @@ cd .. echo " PEP8" -pycodestyle ./src +pycodestyle --exclude="*_to_*.py" ./src if [ $? -eq 0 ] then