adists_num
Youcef AOUAD 2024-05-23 16:48:31 +02:00
parent f9fe5c9b6c
commit b56b8099ab
28 changed files with 1969 additions and 4 deletions

3
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

7
.idea/misc.xml Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.10 (pamhyr)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (pamhyr)" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/pamhyr.iml" filepath="$PROJECT_DIR$/.idea/pamhyr.iml" />
</modules>
</component>
</project>

14
.idea/pamhyr.iml Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.10 (pamhyr)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
</module>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

BIN
mage8/mage Executable file

Binary file not shown.

BIN
mage8/mage_as7 Executable file

Binary file not shown.

BIN
mage8/mage_extraire Executable file

Binary file not shown.

BIN
mage8/mage_extraire_gra Executable file

Binary file not shown.

BIN
mage8/mailleurTT Executable file

Binary file not shown.

BIN
src/.pamhyr Normal file

Binary file not shown.

View File

@ -101,8 +101,8 @@ class OutputKpAdists(SQLSubModel):
def _db_load(cls, execute, data=None): def _db_load(cls, execute, data=None):
new = [] new = []
reach = data["reach"] #reach = data["reach"]
profile = data["profile"] #profile = data["profile"]
status = data["status"] status = data["status"]
table = execute( table = execute(

View File

@ -24,7 +24,7 @@ from Model.OutputKpAdists.OutputKpAdists import OutputKpAdists
class OutputKpAdistsList(PamhyrModelList): class OutputKpAdistsList(PamhyrModelList):
_sub_classes = [OutputKpAdistsList] _sub_classes = [OutputKpAdists]
@classmethod @classmethod
def _db_load(cls, execute, data=None): def _db_load(cls, execute, data=None):

View File

@ -45,6 +45,8 @@ from Model.REPLine.REPLineList import REPLineList
from Solver.Solvers import solver_type_list from Solver.Solvers import solver_type_list
from Model.OutputKpAdists.OutputKpListAdists import OutputKpAdistsList
class RiverNode(Node, SQLSubModel): class RiverNode(Node, SQLSubModel):
_sub_classes = [] _sub_classes = []
@ -228,6 +230,7 @@ class River(Graph, SQLSubModel):
HydraulicStructureList, HydraulicStructureList,
AddFileList, AddFileList,
REPLineList, REPLineList,
OutputKpAdistsList,
] ]
def __init__(self, status=None): def __init__(self, status=None):
@ -251,6 +254,7 @@ class River(Graph, SQLSubModel):
) )
self._additional_files = AddFileList(status=self._status) self._additional_files = AddFileList(status=self._status)
self._rep_lines = REPLineList(status=self._status) self._rep_lines = REPLineList(status=self._status)
self._Output_kp_adists = OutputKpAdistsList(status=self._status)
@classmethod @classmethod
def _db_create(cls, execute): def _db_create(cls, execute):
@ -325,6 +329,10 @@ class River(Graph, SQLSubModel):
) )
new._rep_lines = REPLineList._db_load(execute, data) new._rep_lines = REPLineList._db_load(execute, data)
new._Output_kp_adists = OutputKpAdistsList._db_load(
execute, data
)
return new return new
def _db_save(self, execute, data=None): def _db_save(self, execute, data=None):
@ -344,6 +352,8 @@ class River(Graph, SQLSubModel):
for solver in self._parameters: for solver in self._parameters:
objs.append(self._parameters[solver]) objs.append(self._parameters[solver])
objs.append(self._Output_kp_adists)
self._save_submodel(execute, objs, data) self._save_submodel(execute, objs, data)
return True return True
@ -466,6 +476,10 @@ Last export at: @date."""
def parameters(self): def parameters(self):
return self._parameters return self._parameters
@property
def Output_kp_adists(self):
return self._Output_kp_adists
def get_params(self, solver): def get_params(self, solver):
if solver in self._parameters: if solver in self._parameters:
return self._parameters[solver] return self._parameters[solver]

View File

@ -81,6 +81,10 @@ class AdisTS(CommandLineSolver):
name = self._study.name name = self._study.name
return f"{name}.REP" return f"{name}.REP"
def log_file(self):
name = self._study.name
return f"{name}.TRA"
def _export_REP_additional_lines(self, study, rep_file): def _export_REP_additional_lines(self, study, rep_file):
lines = filter( lines = filter(
lambda line: line.is_enabled(), lambda line: line.is_enabled(),
@ -117,6 +121,25 @@ class AdisTS(CommandLineSolver):
return True return True
###########
# RESULTS #
###########
def read_bin(self, study, repertory, results, qlog=None, name="0"):
return
@timer
def results(self, study, repertory, qlog=None, name="0"):
results = Results(
study=study,
solver=self,
repertory=repertory,
name=name,
)
self.read_bin(study, repertory, results, qlog, name=name)
return results
################################ ################################
# Adis-TS in low coupling mode # # Adis-TS in low coupling mode #
################################ ################################

View File

@ -75,6 +75,7 @@ from View.CheckList.Window import CheckListWindow
from View.Results.Window import ResultsWindow from View.Results.Window import ResultsWindow
from View.Results.ReadingResultsDialog import ReadingResultsDialog from View.Results.ReadingResultsDialog import ReadingResultsDialog
from View.Debug.Window import ReplWindow from View.Debug.Window import ReplWindow
from View.OutputKpAdisTS.Window import OutputKpAdisTSWindow
# Optional internal display of documentation for make the application # Optional internal display of documentation for make the application
# package lighter... # package lighter...
@ -118,7 +119,7 @@ define_model_action = [
"action_menu_edit_hydraulic_structures", "action_menu_additional_file", "action_menu_edit_hydraulic_structures", "action_menu_additional_file",
"action_menu_results_last", "action_open_results_from_file", "action_menu_results_last", "action_open_results_from_file",
"action_menu_boundary_conditions_sediment", "action_menu_boundary_conditions_sediment",
"action_menu_rep_additional_lines", "action_menu_rep_additional_lines", "action_menu_output_kp",
] ]
action = ( action = (
@ -232,6 +233,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
""" """
actions = { actions = {
# Menu action # Menu action
"action_menu_output_kp": self.open_output_kp_adists,
"action_menu_config": self.open_configure, "action_menu_config": self.open_configure,
"action_menu_new": self.open_new_study, "action_menu_new": self.open_new_study,
"action_menu_edit": self.open_edit_study, "action_menu_edit": self.open_edit_study,
@ -860,6 +862,19 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
# SUB WINDOWS # # SUB WINDOWS #
############### ###############
def open_output_kp_adists(self):
if self.sub_window_exists(
OutputKpAdisTSWindow,
data=[self._study, None]
):
return
Output_Kp_AdisTS = OutputKpAdisTSWindow(
study=self._study,
parent=self
)
Output_Kp_AdisTS.show()
def open_configure(self): def open_configure(self):
"""Open configure window """Open configure window

View File

@ -0,0 +1,277 @@
# Table.py -- Pamhyr
# Copyright (C) 2023-2024 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 <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
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, QMessageBox,
)
from View.Tools.PamhyrTable import PamhyrTableModel
from View.HydraulicStructures.BasicHydraulicStructures.UndoCommand import (
SetNameCommand, SetTypeCommand,
SetEnabledCommand, AddCommand, DelCommand,
SetValueCommand,
)
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 __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)
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._data.basic_structure(row).name
elif self._headers[column] == "type":
return self._long_types[self._data.basic_structure(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":
old_type = self._data.basic_structure(row).type
if old_type == "ND" or self._question_set_type():
key = next(
k for k, v in self._long_types.items()
if v == value
)
self._undo.push(
SetTypeCommand(
self._data, row, BHS_types[key]
)
)
except Exception as e:
logger.error(e)
logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
def _question_set_type(self):
question = QMessageBox(self._parent)
question.setWindowTitle(self._trad['msg_type_change_title'])
question.setText(self._trad['msg_type_change_text'])
question.setStandardButtons(QMessageBox.Cancel | QMessageBox.Ok)
question.setIcon(QMessageBox.Question)
res = question.exec()
return res == QMessageBox.Ok
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 enabled(self, row, enabled, parent=QModelIndex()):
self._undo.push(
SetEnabledCommand(
self._lst, row, enabled
)
)
self.layoutChanged.emit()
def undo(self):
self._undo.undo()
self.layoutChanged.emit()
def redo(self):
self._undo.redo()
self.layoutChanged.emit()
class ParametersTableModel(PamhyrTableModel):
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")
self._hs_index = None
super(ParametersTableModel, self).__init__(trad=trad, **kwargs)
def rowCount(self, parent):
if self._hs_index is None:
return 0
return len(
self._data.basic_structure(self._hs_index)
)
def data(self, index, role):
if role != Qt.ItemDataRole.DisplayRole:
return QVariant()
if self._hs_index is None:
return QVariant()
row = index.row()
column = index.column()
hs = self._data.basic_structure(self._hs_index)
if self._headers[column] == "name":
return self._trad[hs.parameters[row].name]
elif self._headers[column] == "value":
return str(hs.parameters[row].value)
return QVariant()
def setData(self, index, value, role=Qt.EditRole):
if not index.isValid() or role != Qt.EditRole:
return False
if self._hs_index is None:
return QVariant()
row = index.row()
column = index.column()
try:
if self._headers[column] == "value":
self._undo.push(
SetValueCommand(
self._data.basic_structure(self._hs_index),
row, value
)
)
except Exception as e:
logger.error(e)
logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
def update_hs_index(self, index):
self._hs_index = index
self.layoutChanged.emit()

View File

@ -0,0 +1,155 @@
# translate.py -- Pamhyr
# Copyright (C) 2023-2024 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 <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
from View.Translate import MainTranslate
_translate = QCoreApplication.translate
class BasicHydraulicStructuresTranslate(MainTranslate):
def __init__(self):
super(BasicHydraulicStructuresTranslate, self).__init__()
self._dict["Basic Hydraulic Structures"] = _translate(
"BasicHydraulicStructures", "Basic Hydraulic Structures"
)
self._dict['msg_type_change_title'] = _translate(
"BasicHydraulicStructures",
"Change hydraulic structure type"
)
self._dict['msg_type_change_text'] = _translate(
"BasicHydraulicStructures",
"Do you want to change the hydraulic structure type and reset \
hydraulic structure values?"
)
# BHSValues translation
self._dict['width'] = self._dict["unit_width"]
self._dict['height'] = self._dict["unit_thickness"]
self._dict['elevation'] = self._dict["unit_elevation"]
self._dict['diameter'] = self._dict["unit_diameter"]
self._dict['discharge_coefficient'] = _translate(
"BasicHydraulicStructures", "Discharge coefficient"
)
self._dict['loading_elevation'] = _translate(
"BasicHydraulicStructures", "Upper elevation (m)"
)
self._dict['half-angle_tangent'] = _translate(
"BasicHydraulicStructures", "Half-angle tangent"
)
self._dict['maximal_loading_elevation'] = _translate(
"BasicHydraulicStructures", "Maximal loading elevation"
)
self._dict['siltation_height'] = _translate(
"BasicHydraulicStructures", "Siltation height (m)"
)
self._dict['top_of_the_vault'] = _translate(
"BasicHydraulicStructures", "Top of the vault (m)"
)
self._dict['bottom_of_the_vault'] = _translate(
"BasicHydraulicStructures", "Bottom of the vault (m)"
)
self._dict['opening'] = _translate(
"BasicHydraulicStructures", "Opening"
)
self._dict['maximal_opening'] = _translate(
"BasicHydraulicStructures", "Maximal opening"
)
self._dict['step_space'] = _translate(
"BasicHydraulicStructures", "Step space"
)
self._dict['weir'] = _translate(
"BasicHydraulicStructures", "Weir"
)
self._dict['coefficient'] = _translate(
"BasicHydraulicStructures", "Coefficient"
)
# Dummy parameters
self._dict['parameter_1'] = _translate(
"BasicHydraulicStructures", "Parameter 1"
)
self._dict['parameter_2'] = _translate(
"BasicHydraulicStructures", "Parameter 2"
)
self._dict['parameter_3'] = _translate(
"BasicHydraulicStructures", "Parameter 3"
)
self._dict['parameter_4'] = _translate(
"BasicHydraulicStructures", "Parameter 4"
)
self._dict['parameter_5'] = _translate(
"BasicHydraulicStructures", "Parameter 5"
)
# BHS types long names
self._sub_dict["long_types"] = {
"ND": self._dict["not_defined"],
"S1": _translate(
"BasicHydraulicStructures", "Discharge weir"
),
"S2": _translate(
"BasicHydraulicStructures", "Trapezoidal weir"
),
"S3": _translate(
"BasicHydraulicStructures", "Triangular weir"
),
"OR": _translate(
"BasicHydraulicStructures", "Rectangular orifice"
),
"OC": _translate(
"BasicHydraulicStructures", "Circular orifice"
),
"OV": _translate(
"BasicHydraulicStructures", "Vaulted orifice"
),
"V1": _translate(
"BasicHydraulicStructures", "Rectangular gate"
),
"V2": _translate(
"BasicHydraulicStructures", "Simplified rectangular gate"
),
"BO": _translate(
"BasicHydraulicStructures", "Borda-type head loss"
),
"CV": _translate(
"BasicHydraulicStructures", "Check valve"
),
"UD": _translate(
"BasicHydraulicStructures", "User defined"
),
}
# Tables
self._sub_dict["table_headers"] = {
"name": self._dict["name"],
"type": self._dict["type"],
}
self._sub_dict["table_headers_parameters"] = {
"name": self._dict["name"],
"value": self._dict["value"],
}

View File

@ -0,0 +1,153 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2023-2024 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 <https://www.gnu.org/licenses/>.
# -*- 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, new_type):
QUndoCommand.__init__(self)
self._hs = hs
self._index = index
self._type = new_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.delete_i([self._index])
self._hs.insert(self._index, self._old)
def redo(self):
self._hs.delete_i([self._index])
self._hs.insert(self._index, self._new)
class SetEnabledCommand(QUndoCommand):
def __init__(self, hs, index, enabled):
QUndoCommand.__init__(self)
self._hs = hs
self._index = index
self._old = not enabled
self._new = enabled
def undo(self):
self._hs.basic_structure(self._index).enabled = self._old
def redo(self):
self._hs.basic_structure(self._index).enabled = 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(range(self._row, self._row + len(self._bhs)))
def redo(self):
for r in self._bhs:
self._hs.insert(self._row, r)
####################################
# Basic hydraulic structure values #
####################################
class SetValueCommand(QUndoCommand):
def __init__(self, bhs, index, value):
QUndoCommand.__init__(self)
self._bhs = bhs
self._index = index
self._old = self._bhs.parameters[self._index].value
self._new = self._bhs.parameters[self._index].type(value)
def undo(self):
self._bhs.parameters[self._index].value = self._old
def redo(self):
self._bhs.parameters[self._index].value = self._new

View File

@ -0,0 +1,270 @@
# Window.py -- Pamhyr
# Copyright (C) 2023-2024 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 <https://www.gnu.org/licenses/>.
# -*- 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 (
ComboBoxDelegate, TableModel, ParametersTableModel,
)
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):
trad = BasicHydraulicStructuresTranslate()
name = " - ".join([
trad[self._pamhyr_name], data.name, study.name
])
super(BasicHydraulicStructuresWindow, self).__init__(
title=name,
study=study,
config=config,
trad=trad,
parent=parent
)
self._hash_data.append(data)
self._hs = data
self.setup_table()
self.setup_checkbox()
self.setup_plot()
self.setup_connections()
self.update()
def setup_table(self):
self.setup_table_bhs()
self.setup_table_bhs_parameters()
def setup_table_bhs(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,
parent=self,
)
selectionModel = table.selectionModel()
index = table.model().index(0, 0)
selectionModel.select(
index,
QItemSelectionModel.Rows |
QItemSelectionModel.ClearAndSelect |
QItemSelectionModel.Select
)
table.scrollTo(index)
def setup_table_bhs_parameters(self):
self._table_parameters = None
table = self.find(QTableView, f"tableView_2")
self._table_parameters = ParametersTableModel(
table_view=table,
table_headers=self._trad.get_dict("table_headers_parameters"),
editable_headers=["value"],
delegates={},
trad=self._trad,
data=self._hs,
undo=self._undo_stack,
parent=self,
)
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)
reach = self._hs.input_reach
profile_kp = self._hs.input_kp
if profile_kp is not None:
profiles = reach.reach.get_profiles_from_kp(float(profile_kp))
else:
profiles = None
if profiles is not None:
profile = profiles[0]
else:
profile = None
self.plot_ac = PlotAC(
canvas=self.canvas,
river=self._study.river,
reach=self._hs.input_reach,
profile=profile,
trad=self._trad,
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.clicked.connect(self._set_basic_structure_state)
table = self.find(QTableView, "tableView")
table.selectionModel()\
.selectionChanged\
.connect(self.update)
self._table.dataChanged.connect(self.update)
self._table.layoutChanged.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):
rows = self.index_selected_rows()
if len(rows) != 0:
for row in rows:
if row is not None:
self._table.enabled(
row,
self._checkbox.isChecked()
)
def update(self):
self._set_checkbox_state()
self._update_parameters_table()
def _update_parameters_table(self):
row = self.index_selected_row()
self._table_parameters.update_hs_index(row)

View File

@ -0,0 +1,120 @@
# PlotAC.py -- Pamhyr
# Copyright (C) 2023-2024 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 <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from tools import timer
from View.Tools.PamhyrPlot import PamhyrPlot
from matplotlib import pyplot as plt
class PlotAC(PamhyrPlot):
def __init__(self, canvas=None, trad=None, toolbar=None,
river=None, reach=None, profile=None,
parent=None):
super(PlotAC, self).__init__(
canvas=canvas,
trad=trad,
data=river,
toolbar=toolbar,
parent=parent
)
self._current_reach = reach
self._current_profile = profile
self.label_x = self._trad["x"]
self.label_y = self._trad["unit_elevation"]
self._isometric_axis = False
self._auto_relim_update = True
self._autoscale_update = True
@property
def river(self):
return self.data
@river.setter
def river(self, river):
self.data = river
@timer
def draw(self):
self.init_axes()
if self.data is None:
self.line_kp = None
return
if self._current_reach is None:
self.line_kp = None
return
self.draw_data()
self.idle()
self._init = True
def draw_data(self):
reach = self._current_reach
if self._current_profile is None:
self.line_kp = None
else:
profile = self._current_profile
x = profile.get_station()
z = profile.z()
self.line_kp, = self.canvas.axes.plot(
x, z,
color=self.color_plot_river_bottom,
**self.plot_default_kargs
)
def set_reach(self, reach):
self._current_reach = reach
self.update()
def set_profile(self, profile):
self._current_profile = profile
self.update()
def update(self):
if self.line_kp is None:
self.draw()
return
if self._current_reach is None or self._current_profile is None:
self.update_clear()
else:
self.update_data()
self.update_idle()
def update_data(self):
profile = self._current_profile
x = profile.get_station()
z = profile.z()
self.line_kp.set_data(x, z)
def clear(self):
self.update_clear()
def update_clear(self):
if self.line_kp is not None:
self.line_kp.set_data([], [])

View File

@ -0,0 +1,165 @@
# PlotKPC.py -- Pamhyr
# Copyright (C) 2023-2024 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 <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from tools import timer
from View.Tools.PamhyrPlot import PamhyrPlot
from PyQt5.QtCore import (
QCoreApplication
)
from matplotlib.collections import LineCollection
_translate = QCoreApplication.translate
class PlotKPC(PamhyrPlot):
def __init__(self, canvas=None, trad=None, toolbar=None,
river=None, reach=None, profile=None,
parent=None):
super(PlotKPC, self).__init__(
canvas=canvas,
trad=trad,
data=river,
toolbar=toolbar,
parent=parent
)
self._current_reach = reach
self._current_profile = profile
self.label_x = self._trad["unit_kp"]
self.label_y = self._trad["unit_elevation"]
self._isometric_axis = False
self._auto_relim_update = True
self._autoscale_update = True
@property
def river(self):
return self.data
@river.setter
def river(self, river):
self.data = river
@timer
def draw(self, highlight=None):
self.init_axes()
if self.data is None:
self.profile = None
self.line_kp_zmin_zmax = None
self.line_kp_zmin = None
return
if self._current_reach is None:
self.profile = None
self.line_kp_zmin_zmax = None
self.line_kp_zmin = None
return
self.draw_data()
self.draw_current()
self.idle()
self._init = True
def draw_data(self):
reach = self._current_reach
kp = reach.reach.get_kp()
z_min = reach.reach.get_z_min()
z_max = reach.reach.get_z_max()
self.line_kp_zmin, = self.canvas.axes.plot(
kp, z_min,
color=self.color_plot_river_bottom,
lw=1.
)
if len(kp) != 0:
self.line_kp_zmin_zmax = self.canvas.axes.vlines(
x=kp,
ymin=z_min, ymax=z_max,
color=self.color_plot,
lw=1.
)
def draw_current(self):
if self._current_profile is None:
self.profile = None
else:
kp = [self._current_profile.kp,
self._current_profile.kp]
min_max = [self._current_profile.z_min(),
self._current_profile.z_max()]
self.profile = self.canvas.axes.plot(
kp, min_max,
color=self.color_plot_current,
lw=1.
)
def set_reach(self, reach):
self._current_reach = reach
self._current_profile = None
self.update()
def set_profile(self, profile):
self._current_profile = profile
self.update_current_profile()
def update(self):
self.draw()
def update_current_profile(self):
reach = self._current_reach
kp = reach.reach.get_kp()
z_min = reach.reach.get_z_min()
z_max = reach.reach.get_z_max()
if self.profile is None:
self.draw()
else:
self.profile.set_data(
[self._current_profile.kp, self._current_profile.kp],
[self._current_profile.z_min(), self._current_profile.z_max()],
)
self.update_idle()
def clear(self):
if self.profile is not None:
self.profile[0].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.canvas.figure.canvas.draw_idle()
def clear_profile(self):
if self.profile is not None:
self.profile.set_data([], [])
self.canvas.figure.canvas.draw_idle()

View File

@ -0,0 +1,215 @@
# Table.py -- Pamhyr
# Copyright (C) 2023-2024 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 <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
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.UndoCommand import (
SetNameCommand, SetReachCommand, SetKpCommand,
SetEnabledCommand, AddCommand, DelCommand,
)
logger = logging.getLogger()
_translate = QCoreApplication.translate
class ComboBoxDelegate(QItemDelegate):
def __init__(self, data=None, trad=None, parent=None, mode="reaches"):
super(ComboBoxDelegate, self).__init__(parent)
self._data = data
self._trad = trad
self._mode = mode
def createEditor(self, parent, option, index):
self.editor = QComboBox(parent)
val = []
if self._mode == "kp":
reach = self._data.hydraulic_structures\
.get(index.row())\
.input_reach
if reach is not None:
val = list(
map(
lambda kp: str(kp), reach.reach.get_kp()
)
)
else:
val = list(
map(
lambda n: n.name, self._data.edges()
)
)
self.editor.addItems(
[self._trad['not_associated']] +
val
)
self.editor.setCurrentText(str(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._hydraulic_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.get(row).name
elif self._headers[column] == "reach":
n = self._lst.get(row).input_reach
if n is None:
return self._trad['not_associated']
return n.name
elif self._headers[column] == "kp":
n = self._lst.get(row).input_kp
if n is None:
return self._trad['not_associated']
return n
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()
na = self._trad['not_associated']
try:
if self._headers[column] == "name":
self._undo.push(
SetNameCommand(
self._lst, row, value
)
)
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
)
)
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._lst, row
)
)
self.endInsertRows()
self.layoutChanged.emit()
def delete(self, rows, parent=QModelIndex()):
self.beginRemoveRows(parent, rows[0], rows[-1])
self._undo.push(
DelCommand(
self._lst, rows
)
)
self.endRemoveRows()
self.layoutChanged.emit()
def enabled(self, row, enabled, parent=QModelIndex()):
self._undo.push(
SetEnabledCommand(
self._lst, row, enabled
)
)
self.layoutChanged.emit()
def undo(self):
self._undo.undo()
self.layoutChanged.emit()
def redo(self):
self._undo.redo()
self.layoutChanged.emit()

View File

@ -0,0 +1,40 @@
# translate.py -- Pamhyr
# Copyright (C) 2023-2024 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 <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
from View.Translate import MainTranslate
_translate = QCoreApplication.translate
class OutputKpAdisTSTranslate(MainTranslate):
def __init__(self):
super(OutputKpAdisTSTranslate, self).__init__()
self._dict["Output Kp"] = _translate(
"OutputKpAdisTS", "Output Kp"
)
self._dict["x"] = _translate("OutputKpAdisTS", "X (m)")
self._sub_dict["table_headers"] = {
"name": self._dict["name"],
"reach": self._dict["reach"],
"kp": self._dict["unit_kp"],
}

View File

@ -0,0 +1,159 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2023-2024 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 <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
import logging
from copy import deepcopy
from tools import trace, timer
from PyQt5.QtWidgets import (
QMessageBox, QUndoCommand, QUndoStack,
)
logger = logging.getLogger()
class SetNameCommand(QUndoCommand):
def __init__(self, h_s_lst, index, new_value):
QUndoCommand.__init__(self)
self._h_s_lst = h_s_lst
self._index = index
self._old = self._h_s_lst.get(self._index).name
self._new = str(new_value)
def undo(self):
self._h_s_lst.get(self._index).name = self._old
def redo(self):
self._h_s_lst.get(self._index).name = self._new
class SetReachCommand(QUndoCommand):
def __init__(self, h_s_lst, index, reach):
QUndoCommand.__init__(self)
self._h_s_lst = h_s_lst
self._index = index
self._old = self._h_s_lst.get(self._index).input_reach
self._new = reach
self._old_kp = self._h_s_lst.get(self._index).input_kp
self._new_kp = None
def undo(self):
i = self._h_s_lst.get(self._index)
i.input_reach = self._old
i.input_kp = self._old_kp
def redo(self):
i = self._h_s_lst.get(self._index)
i.input_reach = self._new
i.input_kp = self._new_kp
class SetKpCommand(QUndoCommand):
def __init__(self, h_s_lst, index, kp):
QUndoCommand.__init__(self)
self._h_s_lst = h_s_lst
self._index = index
self._old = self._h_s_lst.get(self._index).input_kp
self._new = kp
def undo(self):
self._h_s_lst.get(self._index).input_kp = self._old
def redo(self):
self._h_s_lst.get(self._index).input_kp = self._new
class SetEnabledCommand(QUndoCommand):
def __init__(self, h_s_lst, index, enabled):
QUndoCommand.__init__(self)
self._h_s_lst = h_s_lst
self._index = index
self._old = not enabled
self._new = enabled
def undo(self):
self._h_s_lst.get(self._index).enabled = self._old
def redo(self):
self._h_s_lst.get(self._index).enabled = self._new
class AddCommand(QUndoCommand):
def __init__(self, h_s_lst, index):
QUndoCommand.__init__(self)
self._h_s_lst = h_s_lst
self._index = index
self._new = None
def undo(self):
self._h_s_lst.delete_i([self._index])
def redo(self):
if self._new is None:
self._new = self._h_s_lst.new(self._h_s_lst, self._index)
else:
self._h_s_lst.insert(self._index, self._new)
class DelCommand(QUndoCommand):
def __init__(self, h_s_lst, rows):
QUndoCommand.__init__(self)
self._h_s_lst = h_s_lst
self._rows = rows
self._h_s = []
for row in rows:
self._h_s.append((row, self._h_s_lst.get(row)))
self._h_s.sort()
def undo(self):
for row, el in self._h_s:
self._h_s_lst.insert(row, el)
def redo(self):
self._h_s_lst.delete_i(self._rows)
class PasteCommand(QUndoCommand):
def __init__(self, h_s_lst, row, h_s):
QUndoCommand.__init__(self)
self._h_s_lst = h_s_lst
self._row = row
self._h_s = deepcopy(h_s)
self._h_s.reverse()
def undo(self):
self._h_s_lst.delete_i(
self._tab,
range(self._row, self._row + len(self._h_s))
)
def redo(self):
for r in self._h_s:
self._h_s_lst.insert(self._row, r)

View File

@ -0,0 +1,315 @@
# Window.py -- Pamhyr
# Copyright (C) 2023-2024 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 <https://www.gnu.org/licenses/>.
# -*- 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.OutputKpAdisTS.PlotAC import PlotAC
from View.OutputKpAdisTS.PlotKPC import PlotKPC
from View.OutputKpAdisTS.Table import (
TableModel, ComboBoxDelegate
)
from View.Network.GraphWidget import GraphWidget
from View.OutputKpAdisTS.Translate import OutputKpAdisTSTranslate
from View.OutputKpAdisTS.BasicHydraulicStructures.Window import (
BasicHydraulicStructuresWindow
)
logger = logging.getLogger()
class OutputKpAdisTSWindow(PamhyrWindow):
_pamhyr_ui = "OutputKpAdisTS"
_pamhyr_name = "Output Kp"
def __init__(self, study=None, config=None, parent=None):
trad = OutputKpAdisTSTranslate()
name = trad[self._pamhyr_name] + " - " + study.name
super(OutputKpAdisTSWindow, self).__init__(
title=name,
study=study,
config=config,
trad=trad,
parent=parent
)
self._hs_lst = self._study.river._hydraulic_structures
self.setup_table()
#self.setup_checkbox()
#self.setup_plots()
self.setup_connections()
#self.update()
def setup_table(self):
self._table = None
self._delegate_reach = ComboBoxDelegate(
trad=self._trad,
data=self._study.river,
parent=self,
mode="reaches"
)
self._delegate_kp = ComboBoxDelegate(
trad=self._trad,
data=self._study.river,
parent=self,
mode="kp"
)
table = self.find(QTableView, f"tableView")
self._table = TableModel(
table_view=table,
table_headers=self._trad.get_dict("table_headers"),
editable_headers=["name", "reach", "kp"],
delegates={
"reach": self._delegate_reach,
"kp": self._delegate_kp,
},
trad=self._trad,
data=self._study.river,
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_plots(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_kpc = PlotKPC(
canvas=self.canvas,
river=self._study.river,
reach=None,
profile=None,
trad=self._trad,
toolbar=self.toolbar
)
self.plot_kpc.draw()
self.canvas_2 = MplCanvas(width=5, height=4, dpi=100)
self.canvas_2.setObjectName("canvas_2")
self.toolbar_2 = PamhyrPlotToolbar(
self.canvas_2, self
)
self.plot_layout_2 = self.find(QVBoxLayout, "verticalLayout_2")
self.plot_layout_2.addWidget(self.toolbar_2)
self.plot_layout_2.addWidget(self.canvas_2)
self.plot_ac = PlotAC(
canvas=self.canvas_2,
river=self._study.river,
reach=None,
profile=None,
trad=self._trad,
toolbar=self.toolbar_2
)
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.find(QAction, "action_edit").triggered.connect(self.edit)
self._checkbox.clicked.connect(self._set_structure_state)
table = self.find(QTableView, "tableView")
table.selectionModel()\
.selectionChanged\
.connect(self.update)
self._table.dataChanged.connect(self.update)
self._table.layoutChanged.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_lst) == 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 edit(self):
rows = self.index_selected_rows()
for row in rows:
data = self._hs_lst.get(row)
if self.sub_window_exists(
BasicHydraulicStructuresWindow,
data=[self._study, None, data]
):
continue
win = BasicHydraulicStructuresWindow(
data=data,
study=self._study,
parent=self
)
win.show()
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_lst.get(row).enabled)
def _set_structure_state(self):
rows = self.index_selected_rows()
if len(rows) != 0:
for row in rows:
if row is not None:
self._table.enabled(
row,
self._checkbox.isChecked()
)
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 or len(self._hs_lst) == 0:
self._update_clear_all()
return
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)
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 len(profiles) != 0 and 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._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()