Merge branch 'master' into sediment

This commit is contained in:
Pierre-Antoine Rouby committed 2023-08-11 10:12:31 +02:00
commit 23fb3e6fb3
147 files changed
+6916 -1002

No files matched your search

+51 -5
View File
@@ -1,3 +1,19 @@
# ASubWindow.py -- Pamhyr
# Copyright (C) 2023 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 os
@@ -19,6 +35,7 @@ from PyQt5.QtWidgets import (
QRadioButton, QComboBox, QFileDialog,
QMessageBox, QTableView, QAction,
QDateTimeEdit, QWidget, QPlainTextEdit,
QLabel,
)
from PyQt5.QtCore import (
QTime, QDateTime,
@@ -61,13 +78,14 @@ class WindowToolKit(object):
return header, values
def file_dialog(self, select_file=True, callback=lambda x: None):
def file_dialog(self, select_file=True, callback=lambda x: None, directory=None):
"""Open a new file dialog and send result to callback function
Args:
select_file: Select a file if True, else select a dir
callback: The callback function with one arguments, files
selection list
directory: Defaut directory
Returns:
The returns of callback
@@ -80,6 +98,8 @@ class WindowToolKit(object):
mode = QFileDialog.FileMode.Directory
dialog.setFileMode(mode)
if directory is not None:
dialog.setDirectory(directory)
if dialog.exec_():
file_names = dialog.selectedFiles()
@@ -130,6 +150,30 @@ class ASubWindowFeatures(object):
return qtype
def get_label_text(self, name:str):
"""Get text of label component
Args:
label: The label component name
Returns:
Text
"""
return self.find(QLabel, name).text()
def set_label_text(self, name:str, text:str):
"""Set text of label component
Args:
text_edit: The label component name
text: The text
Returns:
Nothing
"""
self.find(QLabel, name).setText(text)
def set_line_edit_text(self, name:str, text:str):
"""Set text of line edit component
@@ -421,10 +465,12 @@ class ASubWindowFeatures(object):
class ASubMainWindow(QMainWindow, ASubWindowFeatures, WindowToolKit):
def __init__(self, name="", ui="dummy", parent=None):
super(ASubMainWindow, self).__init__(parent=parent)
self.ui = loadUi(
os.path.join(os.path.dirname(__file__), "ui", f"{ui}.ui"),
self
)
if ui is not None:
self.ui = loadUi(
os.path.join(os.path.dirname(__file__), "ui", f"{ui}.ui"),
self
)
self.name = name
self.parent = parent
if self.parent is not None:
+55
View File
@@ -1,8 +1,63 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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 os
import logging
from View.ASubWindow import ASubWindow
from PyQt5.QtCore import QCoreApplication
_translate = QCoreApplication.translate
logger = logging.getLogger()
class AboutWindow(ASubWindow):
def _path_file(self, filename):
return os.path.abspath(
os.path.join(
os.path.dirname(__file__),
"..", "..", filename
)
)
def __init__(self, title="About", parent=None):
super(AboutWindow, self).__init__(name=title, ui="about", parent=parent)
self.ui.setWindowTitle(title)
# Version
with open(self._path_file("VERSION"), "r") as f:
version = f.readline().strip()
logger.info(f"version: {version}")
label = self.get_label_text("label_version")
label = label.replace("@version", version)
self.set_label_text("label_version", label)
# Authors
with open(self._path_file("AUTHORS"), "r") as f:
label = ""
try:
while True:
author = next(f).strip()
logger.info(f"author: {author}")
label = f"\n - {author}" + label
except StopIteration:
label = _translate("About", "Contributors: ") + label
label = "Copyright © 2023 INRAE\n" + label
self.set_label_text("label_copyright", label)
+23
View File
@@ -1,5 +1,23 @@
# Plot.py -- Pamhyr
# Copyright (C) 2023 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 datetime import datetime
from tools import timer, trace
@@ -13,6 +31,8 @@ from View.BoundaryCondition.Edit.translate import *
_translate = QCoreApplication.translate
logger = logging.getLogger()
class Plot(APlot):
def __init__(self, canvas=None, data=None,
mode = "time", toolbar=None):
@@ -25,6 +45,9 @@ class Plot(APlot):
self._mode = mode
def custom_ticks(self):
if self.data.header[0] != "time":
return
t0 = datetime.fromtimestamp(0)
nb = len(self.data.data)
mod = int(nb / 5)
+25 -4
View File
@@ -1,6 +1,23 @@
# Table.py -- Pamhyr
# Copyright (C) 2023 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 datetime import date, time, datetime, timedelta
@@ -196,11 +213,15 @@ class TableModel(QAbstractTableModel):
row = index.row()
column = index.column()
self._undo.push(
SetDataCommand(
self._data, row, column, value
try:
self._undo.push(
SetDataCommand(
self._data, row, column, value
)
)
)
except Exception as e:
logger.info(e)
logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
+18 -1
View File
@@ -1,3 +1,19 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2023 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
@@ -17,7 +33,8 @@ class SetDataCommand(QUndoCommand):
self._index = index
self._column = column
self._old = self._data.get_i(self._index)[self._column]
self._new = new_value
_type = self._data.get_type_column(self._column)
self._new = _type(new_value)
def undo(self):
self._data._set_i_c_v(self._index, self._column, self._old)
+17 -1
View File
@@ -1,3 +1,19 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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, trace
@@ -55,7 +71,7 @@ class EditBoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
self._title = (
_translate("Edit boundary condition", self._title) +
f" - {self._study.name} " +
f" - {self._data.name} " +
f" - {self._data.name} ({self._data.id}) " +
f"({long_types[self._data.bctype]} - {node_name})"
)
@@ -1,3 +1,19 @@
# translate.py -- Pamhyr
# Copyright (C) 2023 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
+41 -16
View File
@@ -1,5 +1,24 @@
# Table.py -- Pamhyr
# Copyright (C) 2023 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 (
@@ -27,6 +46,8 @@ from View.BoundaryCondition.UndoCommand import (
)
from View.BoundaryCondition.translate import *
logger = logging.getLogger()
_translate = QCoreApplication.translate
class ComboBoxDelegate(QItemDelegate):
@@ -137,25 +158,29 @@ class TableModel(QAbstractTableModel):
row = index.row()
column = index.column()
if self._headers[column] == "name":
self._undo.push(
SetNameCommand(
self._bcs, self._tab,row, value
try:
if self._headers[column] == "name":
self._undo.push(
SetNameCommand(
self._bcs, self._tab,row, value
)
)
)
elif self._headers[column] == "type":
key = next(k for k, v in long_types.items() if v == value)
self._undo.push(
SetTypeCommand(
self._bcs, self._tab,row, BC_types[key]
elif self._headers[column] == "type":
key = next(k for k, v in long_types.items() if v == value)
self._undo.push(
SetTypeCommand(
self._bcs, self._tab,row, BC_types[key]
)
)
)
elif self._headers[column] == "node":
self._undo.push(
SetNodeCommand(
self._bcs, self._tab,row, self._data.node(value)
elif self._headers[column] == "node":
self._undo.push(
SetNodeCommand(
self._bcs, self._tab,row, self._data.node(value)
)
)
)
except Exception as e:
logger.info(e)
logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
+17 -1
View File
@@ -1,3 +1,19 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2023 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
@@ -18,7 +34,7 @@ class SetNameCommand(QUndoCommand):
self._tab = tab
self._index = index
self._old = self._bcs.get(self._tab, self._index).name
self._new = new_value
self._new = str(new_value)
def undo(self):
self._bcs.get(self._tab, self._index).name = self._old
+31 -7
View File
@@ -1,3 +1,19 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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
@@ -49,7 +65,7 @@ logger = logging.getLogger()
class BoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
def __init__(self, title="Boundary conditions", study=None, parent=None):
title = title + " - " + study.name
self._title = title + " - " + study.name
super(BoundaryConditionWindow, self).__init__(
name=title, ui="BoundaryConditions", parent=parent
@@ -63,7 +79,7 @@ class BoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
self.setup_graph()
self.setup_connections()
self.ui.setWindowTitle(title)
self.ui.setWindowTitle(self._title)
def setup_sc(self):
self._undo_stack = QUndoStack()
@@ -204,9 +220,17 @@ class BoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
tab = self.current_tab()
rows = self.index_selected_rows()
for row in rows:
win = EditBoundaryConditionWindow(
data=self._bcs.get(tab, row),
study=self._study,
parent=self
win = self.sub_win_filter_first(
"Edit boundary condition",
contain = [f"({self._bcs.get(tab, row).id})"]
)
win.show()
if win is None:
win = EditBoundaryConditionWindow(
data=self._bcs.get(tab, row),
study=self._study,
parent=self
)
win.show()
else:
win.activateWindow()
+16
View File
@@ -1,3 +1,19 @@
# translate.py -- Pamhyr
# Copyright (C) 2023 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
+16
View File
@@ -1,3 +1,19 @@
# Table.py -- Pamhyr
# Copyright (C) 2023 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 trace, timer
+16
View File
@@ -1,3 +1,19 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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 trace, timer
+16
View File
@@ -1,3 +1,19 @@
# Worker.py -- Pamhyr
# Copyright (C) 2023 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 time
+16
View File
@@ -1,3 +1,19 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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 View.ASubWindow import ASubWindow
+16
View File
@@ -1,3 +1,19 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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
+16
View File
@@ -1,3 +1,19 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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
+16
View File
@@ -1,3 +1,19 @@
# DummyWindow.py -- Pamhyr
# Copyright (C) 2023 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 View.ASubWindow import ASubWindow
+16
View File
@@ -1,3 +1,19 @@
# PlotStricklers.py -- Pamhyr
# Copyright (C) 2023 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, flatten
+50 -25
View File
@@ -1,5 +1,24 @@
# Table.py -- Pamhyr
# Copyright (C) 2023 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 (
@@ -24,6 +43,8 @@ from View.Frictions.UndoCommand import (
from View.Frictions.translate import *
logger = logging.getLogger()
_translate = QCoreApplication.translate
class ComboBoxDelegate(QItemDelegate):
@@ -132,36 +153,40 @@ class TableModel(QAbstractTableModel):
row = index.row()
column = index.column()
if self._headers[column] == "name":
self._undo.push(
SetNameCommand(
self._frictions, row, value
try:
if self._headers[column] == "name":
self._undo.push(
SetNameCommand(
self._frictions, row, value
)
)
)
elif self._headers[column] == "begin_kp":
self._undo.push(
SetBeginCommand(
self._frictions, row, value
elif self._headers[column] == "begin_kp":
self._undo.push(
SetBeginCommand(
self._frictions, row, value
)
)
)
elif self._headers[column] == "end_kp":
self._undo.push(
SetEndCommand(
self._frictions, row, value
elif self._headers[column] == "end_kp":
self._undo.push(
SetEndCommand(
self._frictions, row, value
)
)
)
elif self._headers[column] == "begin_strickler":
self._undo.push(
SetBeginStricklerCommand(
self._frictions, row, self._study.river.strickler(value)
elif self._headers[column] == "begin_strickler":
self._undo.push(
SetBeginStricklerCommand(
self._frictions, row, self._study.river.strickler(value)
)
)
)
elif self._headers[column] == "end_strickler":
self._undo.push(
SetEndStricklerCommand(
self._frictions, row, self._study.river.strickler(value)
elif self._headers[column] == "end_strickler":
self._undo.push(
SetEndStricklerCommand(
self._frictions, row, self._study.river.strickler(value)
)
)
)
except Exception as e:
logger.info(e)
logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
+19 -3
View File
@@ -1,3 +1,19 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2023 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
@@ -17,7 +33,7 @@ class SetNameCommand(QUndoCommand):
self._frictions = frictions
self._index = index
self._old = self._frictions.get(self._index).name
self._new = new_value
self._new = str(new_value)
def undo(self):
self._frictions.get(self._index).name = self._old
@@ -32,7 +48,7 @@ class SetBeginCommand(QUndoCommand):
self._frictions = frictions
self._index = index
self._old = self._frictions.get(self._index).begin_kp
self._new = new_value
self._new = float(new_value)
def undo(self):
self._frictions.get(self._index).begin_kp = float(self._old)
@@ -47,7 +63,7 @@ class SetEndCommand(QUndoCommand):
self._frictions = frictions
self._index = index
self._old = self._frictions.get(self._index).end_kp
self._new = new_value
self._new = float(new_value)
def undo(self):
self._frictions.get(self._index).end_kp = float(self._old)
+30 -6
View File
@@ -1,3 +1,19 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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
@@ -52,7 +68,7 @@ class FrictionsWindow(ASubMainWindow, ListedSubWindow):
self.setup_title(title)
super(FrictionsWindow, self).__init__(
name=self._title, ui="Frictions", parent=parent
name=title, ui="Frictions", parent=parent
)
self.setup_sc()
@@ -230,9 +246,17 @@ class FrictionsWindow(ASubMainWindow, ListedSubWindow):
self._table.redo()
def edit_stricklers(self):
self.strick = StricklersWindow(
study = self._study,
config = self.parent.conf,
parent = self
strick = self.sub_win_filter_first(
"Stricklers",
contain = []
)
self.strick.show()
if strick is None:
strick = StricklersWindow(
study = self._study,
config = self.parent.conf,
parent = self
)
strick.show()
else:
strick.activateWindow()
+16
View File
@@ -1,3 +1,19 @@
# translate.py -- Pamhyr
# Copyright (C) 2023 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
+16
View File
@@ -1,3 +1,19 @@
# PlotAC.py -- Pamhyr
# Copyright (C) 2023 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
+16
View File
@@ -1,3 +1,19 @@
# PlotKPC.py -- Pamhyr
# Copyright (C) 2023 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
+16
View File
@@ -1,3 +1,19 @@
# PlotXY.py -- Pamhyr
# Copyright (C) 2023 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, trace
+16
View File
@@ -1,3 +1,19 @@
# Plot.py -- Pamhyr
# Copyright (C) 2023 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
+52 -28
View File
@@ -1,6 +1,24 @@
# Table.py -- Pamhyr
# Copyright (C) 2023 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 numpy as np
import logging
import traceback
from tools import timer, trace
@@ -20,6 +38,8 @@ from Model.Geometry.ProfileXYZ import ProfileXYZ
from View.Geometry.Profile.UndoCommand import *
logger = logging.getLogger()
_translate = QCoreApplication.translate
@@ -132,38 +152,42 @@ class TableEditableModel(QAbstractTableModel):
column = index.column()
if role == Qt.EditRole:
if column == 0:
self._undo_stack.push(
SetXCommand(
self._profile, row,
self._profile.point(row).x,
value
try:
if column == 0:
self._undo_stack.push(
SetXCommand(
self._profile, row,
self._profile.point(row).x,
value
)
)
)
elif column == 1:
self._undo_stack.push(
SetYCommand(
self._profile, row,
self._profile.point(row).y,
value
elif column == 1:
self._undo_stack.push(
SetYCommand(
self._profile, row,
self._profile.point(row).y,
value
)
)
)
elif column == 2:
self._undo_stack.push(
SetZCommand(
self._profile, row,
self._profile.point(row).z,
value
elif column == 2:
self._undo_stack.push(
SetZCommand(
self._profile, row,
self._profile.point(row).z,
value
)
)
)
elif column == 3:
self._undo_stack.push(
SetNameCommand(
self._profile, row,
self._profile.point(row).name,
value
elif column == 3:
self._undo_stack.push(
SetNameCommand(
self._profile, row,
self._profile.point(row).name,
value
)
)
)
except Exception as e:
logger.info(e)
logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
+33 -1
View File
@@ -1,3 +1,19 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2023 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 trace, timer
@@ -16,9 +32,13 @@ class SetDataCommand(QUndoCommand):
self._profile = profile
self._index = index
self._old = old_value
self._new = new_value
self._new = self.type(new_value)
class SetXCommand(SetDataCommand):
def __init__(self, reach, index, old_value, new_value):
self.type = float
super(SetXCommand, self).__init__(reach, index, old_value, new_value)
def undo(self):
self._profile.point(self._index).x = self._old
@@ -26,6 +46,10 @@ class SetXCommand(SetDataCommand):
self._profile.point(self._index).x = self._new
class SetYCommand(SetDataCommand):
def __init__(self, reach, index, old_value, new_value):
self.type = float
super(SetYCommand, self).__init__(reach, index, old_value, new_value)
def undo(self):
self._profile.point(self._index).y = self._old
@@ -33,6 +57,10 @@ class SetYCommand(SetDataCommand):
self._profile.point(self._index).y = self._new
class SetZCommand(SetDataCommand):
def __init__(self, reach, index, old_value, new_value):
self.type = float
super(SetZCommand, self).__init__(reach, index, old_value, new_value)
def undo(self):
self._profile.point(self._index).z = self._old
@@ -40,6 +68,10 @@ class SetZCommand(SetDataCommand):
self._profile.point(self._index).z = self._new
class SetNameCommand(SetDataCommand):
def __init__(self, reach, index, old_value, new_value):
self.type = str
super(SetNameCommand, self).__init__(reach, index, old_value, new_value)
def undo(self):
self._profile.point(self._index).name = self._old
+27 -5
View File
@@ -1,3 +1,19 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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 copy
@@ -21,7 +37,7 @@ from PyQt5.QtWidgets import (
from Model.Geometry.Reach import Reach
from Model.Geometry.ProfileXYZ import ProfileXYZ
from View.ASubWindow import WindowToolKit
from View.ASubWindow import ASubMainWindow
from View.Geometry.Profile.mainwindow_ui_profile import Ui_MainWindow
from View.Geometry.Profile.Plot import Plot
from View.Geometry.Profile.Table import *
@@ -29,10 +45,14 @@ from View.Geometry.Profile.Table import *
_translate = QCoreApplication.translate
class ProfileWindow(QMainWindow, WindowToolKit):
def __init__(self, profile=None, parent=None):
class ProfileWindow(ASubMainWindow):
def __init__(self, profile=None, title="Profile", parent=None):
self._title = title
self.parent = parent
super(ProfileWindow, self).__init__(self.parent)
super(ProfileWindow, self).__init__(
name=self._title,
parent=self.parent
)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
@@ -66,12 +86,14 @@ class ProfileWindow(QMainWindow, WindowToolKit):
if (name is None) or (name == ""):
name = _translate("MainWindowProfile", "(no name)")
self.setWindowTitle(
self._title = (
header + " - " +
f"{self._profile.reach.name}" + " - " +
f"{name} ({self._profile.kp})"
)
self.setWindowTitle(self._title)
def setup_sc(self):
self._undo_stack = QUndoStack()
@@ -1,3 +1,19 @@
# mainwindow_ui_profile.py -- Pamhyr
# Copyright (C) 2023 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 os.path
+36 -13
View File
@@ -1,6 +1,24 @@
# Table.py -- Pamhyr
# Copyright (C) 2023 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 time
import logging
import traceback
from tools import timer, trace
@@ -21,6 +39,7 @@ from Model.Geometry import Reach
from Model.Geometry.ProfileXYZ import ProfileXYZ
from View.Geometry.UndoCommand import *
logger = logging.getLogger()
_translate = QCoreApplication.translate
@@ -98,23 +117,27 @@ class TableEditableModel(QAbstractTableModel):
column = index.column()
if role == Qt.EditRole and index.column() != 2:
if index.column() == 0:
self._undo_stack.push(
SetNameCommand(
self._reach, index.row(),
self._reach.profile(index.row()).name,
value
try:
if index.column() == 0:
self._undo_stack.push(
SetNameCommand(
self._reach, index.row(),
self._reach.profile(index.row()).name,
value
)
)
)
if index.column() == 1:
self._undo_stack.push(
SetKPCommand(
self._reach, index.row(),
self._reach.profile(index.row()).kp,
if index.column() == 1:
self._undo_stack.push(
SetKPCommand(
self._reach, index.row(),
self._reach.profile(index.row()).kp,
value
)
)
)
except Exception as e:
logger.info(e)
logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
self.layoutChanged.emit()
+25 -1
View File
@@ -1,3 +1,19 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2023 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
@@ -17,9 +33,13 @@ class SetDataCommand(QUndoCommand):
self._reach = reach
self._index = index
self._old = old_value
self._new = new_value
self._new = self.type(new_value)
class SetNameCommand(SetDataCommand):
def __init__(self, reach, index, old_value, new_value):
self.type = str
super(SetNameCommand, self).__init__(reach, index, old_value, new_value)
def undo(self):
self._reach.profile(self._index).name = self._old
@@ -27,6 +47,10 @@ class SetNameCommand(SetDataCommand):
self._reach.profile(self._index).name = self._new
class SetKPCommand(SetDataCommand):
def __init__(self, reach, index, old_value, new_value):
self.type = float
super(SetKPCommand, self).__init__(reach, index, old_value, new_value)
def undo(self):
self._reach.profile(self._index).kp = self._old
+39 -10
View File
@@ -1,3 +1,19 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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 os
@@ -25,7 +41,8 @@ from View.Geometry.PlotXY import PlotXY
from View.Geometry.PlotKPZ import PlotKPZ
from View.Geometry.PlotAC import PlotAC
from View.ASubWindow import WindowToolKit
from View.ASubWindow import ASubMainWindow, WindowToolKit
from View.ListedSubWindow import ListedSubWindow
from View.Geometry.mainwindow_ui_reach import Ui_MainWindow
from View.Geometry.Table import *
from View.Geometry.Profile.Window import ProfileWindow
@@ -33,10 +50,14 @@ from View.Geometry.Profile.Window import ProfileWindow
_translate = QCoreApplication.translate
class GeometryWindow(QMainWindow, WindowToolKit):
def __init__(self, model=None, parent=None):
class GeometryWindow(ASubMainWindow, ListedSubWindow):
def __init__(self, model=None, title="Geometry", parent=None):
self._title = title
self.parent = parent
super(GeometryWindow, self).__init__(parent=parent)
super(GeometryWindow, self).__init__(
name=self._title,
parent=parent
)
self._model = model
self._reach = model.river.current_reach().reach
@@ -59,7 +80,8 @@ class GeometryWindow(QMainWindow, WindowToolKit):
self.changed_slider_value()
def setup_window(self):
self.setWindowTitle(f"{self.ui.mainwindow_title} - {self._reach.name}")
self._title = f"{self.ui.mainwindow_title} - {self._reach.name}"
self.setWindowTitle(self._title)
def setup_sc(self):
self._undo_stack = QUndoStack()
@@ -162,13 +184,20 @@ class GeometryWindow(QMainWindow, WindowToolKit):
for row in rows:
profile = self._reach.profile(row)
win = ProfileWindow(
profile = profile,
parent = self,
win = self.sub_win_filter_first(
"Profile",
contain = [self._reach.name, str(profile.kp)]
)
self._profile_window.append(win)
win.show()
if win is None:
win = ProfileWindow(
profile = profile,
parent = self,
)
self._profile_window.append(win)
win.show()
else:
win.activateWindow()
self.tableView.model().blockSignals(False)
+16
View File
@@ -1,3 +1,19 @@
# mainwindow_ui_reach.py -- Pamhyr
# Copyright (C) 2023 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 sys
@@ -1,3 +1,19 @@
# DialogDischarge.py -- Pamhyr
# Copyright (C) 2023 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 View.ASubWindow import ASubWindow
@@ -1,3 +1,19 @@
# DialogHeight.py -- Pamhyr
# Copyright (C) 2023 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 View.ASubWindow import ASubWindow
+17 -1
View File
@@ -1,3 +1,19 @@
# PlotDKP.py -- Pamhyr
# Copyright (C) 2023 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
@@ -26,7 +42,7 @@ class PlotDKP(APlot):
return
self.canvas.axes.set_ylabel(
_translate("MainWindow_reach", "Draft (m)"),
_translate("MainWindow_reach", "Elevation (m)"),
color='green', fontsize=11
)
self.canvas.axes.set_xlabel(
@@ -1,3 +1,19 @@
# PlotDischarge.py -- Pamhyr
# Copyright (C) 2023 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
+29 -5
View File
@@ -1,5 +1,23 @@
# Table.py -- Pamhyr
# Copyright (C) 2023 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 (
@@ -23,6 +41,8 @@ from View.InitialConditions.UndoCommand import (
from View.InitialConditions.translate import *
logger = logging.getLogger()
_translate = QCoreApplication.translate
class ComboBoxDelegate(QItemDelegate):
@@ -119,12 +139,16 @@ class TableModel(QAbstractTableModel):
row = index.row()
column = index.column()
if self._headers[column] is not None:
self._undo.push(
SetCommand(
self._ics, row, self._headers[column], value
try:
if self._headers[column] is not None:
self._undo.push(
SetCommand(
self._ics, row, self._headers[column], value
)
)
)
except Exception as e:
logger.info(e)
logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
+22 -1
View File
@@ -1,3 +1,19 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2023 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
@@ -18,7 +34,12 @@ class SetCommand(QUndoCommand):
self._row = row
self._column = column
self._old = self._ics.get(self._row)[column]
self._new = new_value
_type = float
if column == "name" or column == "comment":
_type = str
self._new = _type(new_value)
def undo(self):
self._ics.get(self._row)[self._column] = self._old
+16
View File
@@ -1,3 +1,19 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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
+16
View File
@@ -1,3 +1,19 @@
# translate.py -- Pamhyr
# Copyright (C) 2023 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
+19
View File
@@ -1,3 +1,19 @@
# Plot.py -- Pamhyr
# Copyright (C) 2023 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 datetime import datetime
@@ -25,6 +41,9 @@ class Plot(APlot):
self._mode = mode
def custom_ticks(self):
if self.data.header[0] != "time":
return
t0 = datetime.fromtimestamp(0)
nb = len(self.data.data)
mod = int(nb / 5)
+25 -4
View File
@@ -1,6 +1,23 @@
# Table.py -- Pamhyr
# Copyright (C) 2023 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 datetime import date, time, datetime, timedelta
from tools import trace, timer
@@ -194,11 +211,15 @@ class TableModel(QAbstractTableModel):
row = index.row()
column = index.column()
self._undo.push(
SetDataCommand(
self._data, row, column, value
try:
self._undo.push(
SetDataCommand(
self._data, row, column, value
)
)
)
except Exception as e:
logger.info(e)
logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
@@ -1,3 +1,19 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2023 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
@@ -17,7 +33,8 @@ class SetDataCommand(QUndoCommand):
self._index = index
self._column = column
self._old = self._data.get_i(self._index)[self._column]
self._new = new_value
_type = self._data.get_type_column(self._column)
self._new = _type(new_value)
def undo(self):
self._data._set_i_c_v(self._index, self._column, self._old)
+20 -4
View File
@@ -1,3 +1,19 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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, trace
@@ -29,7 +45,7 @@ from View.LateralContribution.Edit.Plot import Plot
_translate = QCoreApplication.translate
class EditLateralContributionWindow(ASubMainWindow, ListedSubWindow):
def __init__(self, title="Edit lateral conditribution",
def __init__(self, title="Edit lateral contribution",
data=None, study=None, parent=None):
self._data = data
self._study = study
@@ -38,7 +54,7 @@ class EditLateralContributionWindow(ASubMainWindow, ListedSubWindow):
self.compute_title()
super(EditLateralContributionWindow, self).__init__(
name=self._title, ui="EditLateralContribution", parent=parent
name=title, ui="EditLateralContribution", parent=parent
)
self.ui.setWindowTitle(self._title)
@@ -53,9 +69,9 @@ class EditLateralContributionWindow(ASubMainWindow, ListedSubWindow):
edge_name = (self._data.edge.name if self._data.edge is not None
else _translate("LateralContribution", "Not associate"))
self._title = (
_translate("Edit Lateral contribution", self._title) +
_translate("Edit lateral contribution", self._title) +
f" - {self._study.name} " +
f" - {self._data.name} " +
f" - {self._data.name} ({self._data.id}) " +
f"({long_types[self._data.lctype]} - {edge_name})"
)
@@ -1,3 +1,19 @@
# translate.py -- Pamhyr
# Copyright (C) 2023 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
+51 -26
View File
@@ -1,5 +1,24 @@
# Table.py -- Pamhyr
# Copyright (C) 2023 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 (
@@ -27,6 +46,8 @@ from Model.LateralContribution.LateralContributionTypes import (
)
from View.LateralContribution.translate import *
logger = logging.getLogger()
_translate = QCoreApplication.translate
class ComboBoxDelegate(QItemDelegate):
@@ -140,37 +161,41 @@ class TableModel(QAbstractTableModel):
row = index.row()
column = index.column()
if self._headers[column] == "name":
self._undo.push(
SetNameCommand(
self._lcs, self._tab, row, value
try:
if self._headers[column] == "name":
self._undo.push(
SetNameCommand(
self._lcs, self._tab, row, value
)
)
)
elif self._headers[column] == "type":
key = next(k for k, v in long_types.items() if v == value)
self._undo.push(
SetTypeCommand(
self._lcs, self._tab, row, LC_types[key]
elif self._headers[column] == "type":
key = next(k for k, v in long_types.items() if v == value)
self._undo.push(
SetTypeCommand(
self._lcs, self._tab, row, LC_types[key]
)
)
)
elif self._headers[column] == "edge":
self._undo.push(
SetEdgeCommand(
self._lcs, self._tab, row, self._data.edge(value)
elif self._headers[column] == "edge":
self._undo.push(
SetEdgeCommand(
self._lcs, self._tab, row, self._data.edge(value)
)
)
)
elif self._headers[column] == "begin_kp":
self._undo.push(
SetBeginCommand(
self._lcs, self._tab, row, value
elif self._headers[column] == "begin_kp":
self._undo.push(
SetBeginCommand(
self._lcs, self._tab, row, value
)
)
)
elif self._headers[column] == "end_kp":
self._undo.push(
SetEndCommand(
self._lcs, self._tab, row, value
elif self._headers[column] == "end_kp":
self._undo.push(
SetEndCommand(
self._lcs, self._tab, row, value
)
)
)
except Exception as e:
logger.info(e)
logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
+19 -3
View File
@@ -1,3 +1,19 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2023 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
@@ -18,7 +34,7 @@ class SetNameCommand(QUndoCommand):
self._tab = tab
self._index = index
self._old = self._lcs.get(self._tab, self._index).name
self._new = new_value
self._new = str(new_value)
def undo(self):
self._lcs.get(self._tab, self._index).name = self._old
@@ -34,7 +50,7 @@ class SetBeginCommand(QUndoCommand):
self._tab = tab
self._index = index
self._old = self._lcs.get(self._tab, self._index).begin_kp
self._new = new_value
self._new = float(new_value)
def undo(self):
self._lcs.get(self._tab, self._index).begin_kp = float(self._old)
@@ -50,7 +66,7 @@ class SetEndCommand(QUndoCommand):
self._tab = tab
self._index = index
self._old = self._lcs.get(self._tab, self._index).end_kp
self._new = new_value
self._new = float(new_value)
def undo(self):
self._lcs.get(self._tab, self._index).end_kp = float(self._old)
+31 -7
View File
@@ -1,3 +1,19 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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
@@ -49,7 +65,7 @@ logger = logging.getLogger()
class LateralContributionWindow(ASubMainWindow, ListedSubWindow):
def __init__(self, title="Lateral contribution", study=None, parent=None):
title = title + " - " + study.name
self._title = title + " - " + study.name
super(LateralContributionWindow, self).__init__(
name=title, ui="LateralContributions", parent=parent
@@ -63,7 +79,7 @@ class LateralContributionWindow(ASubMainWindow, ListedSubWindow):
self.setup_graph()
self.setup_connections()
self.ui.setWindowTitle(title)
self.ui.setWindowTitle(self._title)
def setup_sc(self):
self._undo_stack = QUndoStack()
@@ -250,9 +266,17 @@ class LateralContributionWindow(ASubMainWindow, ListedSubWindow):
tab = self.current_tab()
rows = self.index_selected_rows()
for row in rows:
win = EditLateralContributionWindow(
data=self._lcs.get(tab, row),
study=self._study,
parent=self
win = self.sub_win_filter_first(
"Edit lateral contribution",
contain = [f"({self._lcs.get(tab, row).id})"]
)
win.show()
if win is None:
win = EditLateralContributionWindow(
data=self._lcs.get(tab, row),
study=self._study,
parent=self
)
win.show()
else:
win.activateWindow()
+16
View File
@@ -1,3 +1,19 @@
# translate.py -- Pamhyr
# Copyright (C) 2023 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
+58 -1
View File
@@ -1,3 +1,19 @@
# ListedSubWindow.py -- Pamhyr
# Copyright (C) 2023 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
@@ -32,9 +48,50 @@ class ListedSubWindow(object):
self.sub_win_cnt = len(self.sub_win_list)
logger.info(f"Close window: {name} ({self.sub_win_cnt})")
def sub_win_exists(self, name):
def _sub_win_exists(self, name):
return reduce(
lambda acc, n: (acc or (n[0] == name)),
self.sub_win_list,
False
)
def _sub_win_exists_with_contain(self, name, contain):
return reduce(
lambda acc, n: (
acc or
(
(n[0] == name) and
reduce(
lambda acc, c: acc and (c in n[1]._title),
contain,
True
)
)
),
self.sub_win_list,
False
)
def sub_win_exists(self, name, contain = []):
if contain == []:
return self._sub_win_exists(name)
else:
return self._sub_win_exists_with_contain(name, contain)
def sub_win_filter_first(self, name, contain):
try:
return next(
filter(
lambda n: (
(name in n[0]) and
reduce(
lambda acc, c: acc and (c in n[1]._title),
contain,
True
)
),
self.sub_win_list,
)
)[1]
except:
return None
+185 -32
View File
@@ -1,3 +1,19 @@
# MainWindow.py -- Pamhyr
# Copyright (C) 2023 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 os
@@ -39,6 +55,7 @@ from View.SedimentLayers.Reach.Window import ReachSedimentLayersWindow
from View.SolverParameters.Window import SolverParametersWindow
from View.RunSolver.Window import SelectSolverWindow, SolverLogWindow
from View.CheckList.Window import CheckListWindow
from View.Results.Window import ResultsWindow
from View.Debug.Window import ReplWindow
from Model.Study import Study
@@ -93,6 +110,9 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
# Model
self.model = None
# Results
self._last_results = None
# UI
self.ui = loadUi(
os.path.join(os.path.dirname(__file__), "ui", "MainWindow.ui"),
@@ -107,6 +127,9 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
self.trans = QTranslator(self)
#self.ui.retranslateUi()
if self.conf.last_study != "" and not self.conf.close_correctly:
self.dialog_reopen_study()
def set_title(self):
if self.model is not None:
self.setWindowTitle(f"PAMHYR - {self.model.name}")
@@ -192,16 +215,24 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
if self.model is not None and not self.model.is_saved:
self._close_question = True
if self.dialog_close():
# PAMHYR is close correctly (no crash)
self.conf.set_close_correctly()
super(ApplicationWindow, self).close()
else:
self._close_question = False
else:
# PAMHYR is close correctly (no crash)
self.conf.set_close_correctly()
super(ApplicationWindow, self).close()
def closeEvent(self, event):
if not self._close_question:
if self.model is not None and not self.model.is_saved:
if self.dialog_close(cancel = False):
# PAMHYR is close correctly (no crash)
self.conf.set_close_correctly()
super(ApplicationWindow, self).closeEvent(event)
else:
super(ApplicationWindow, self).closeEvent(event)
@@ -261,11 +292,13 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
def set_model(self, model):
self.model = model
self.update_enable_action()
self.conf.set_last_study(self.model.filename)
self.set_title()
def close_model(self):
self.model = None
self.update_enable_action()
self.conf.set_close_correctly()
self.set_title()
def update_enable_action(self):
@@ -288,10 +321,26 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
for action in model_action:
self.enable_actions(action, not no_model)
def set_results(self, results):
self._last_results = results
############
# FEATURES #
############
def open_study(self, filename):
"""Open a study
Args:
filename: The study path
Returns:
Nothing
"""
self.set_model(Study.open(filename))
logger.info(f"Open Study - {self.model.name}")
self.set_title()
def save_study(self):
"""Save current study
@@ -348,6 +397,27 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
"Geometry edition need a reach selected "
"into river network window to work on it")
def dialog_reopen_study(self):
dlg = QMessageBox(self)
dlg.setWindowTitle("Last open study")
dlg.setText("Do you want to open again the last open study?")
opt = QMessageBox.Cancel | QMessageBox.Ok #| QMessageBox.Open
dlg.setStandardButtons(opt)
dlg.setIcon(QMessageBox.Question)
res = dlg.exec()
if res == QMessageBox.Ok:
self.open_study(self.conf.last_study)
return True
elif res == QMessageBox.Open:
self.open_model()
return True
elif res == QMessageBox.Cancel:
return False
def dialog_close(self, cancel = True):
dlg = QMessageBox(self)
@@ -408,12 +478,11 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
dialog.setDefaultSuffix(".pamhyr")
#dialog.setFilter(dialog.filter() | QtCore.QDir.Hidden)
dialog.setNameFilters(['PamHyr (*.pamhyr)'])
dialog.setDirectory(os.path.dirname(self.conf.last_study))
if dialog.exec_():
file_name = dialog.selectedFiles()
self.set_model(Study.open(file_name[0]))
logger.info(f"Open Study - {self.model.name}")
self.set_title()
self.open_study(file_name[0])
def open_new_study(self):
"""Open dialog to set new study
@@ -441,10 +510,12 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
Returns:
Nothing
"""
if (self.model is not None and
not self.sub_win_exists("River network")):
self.network = NetworkWindow(model=self.model, parent=self)
self.network.show()
if self.model is not None:
if not self.sub_win_exists("River network"):
self.network = NetworkWindow(model=self.model, parent=self)
self.network.show()
else:
self.network.activateWindow()
def open_geometry(self):
"""Open geometry window
@@ -452,56 +523,112 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
Returns:
Nothing
"""
if (self.model is not None and
self.model.river.has_current_reach()):
geometry = GeometryWindow(model=self.model, parent=self)
geometry.show()
if (self.model is not None and self.model.river.has_current_reach()):
geometry = self.sub_win_filter_first(
"Geometry",
contain = [self.model.river.current_reach().name]
)
if geometry is None:
geometry = GeometryWindow(model=self.model, parent=self)
geometry.show()
else:
geometry.activateWindow()
else:
self.msg_select_reach()
def open_boundary_cond(self):
bound = BoundaryConditionWindow(study = self.model, parent = self)
bound.show()
bound = self.sub_win_filter_first(
"Boundary conditions",
contain = []
)
if bound is None:
bound = BoundaryConditionWindow(study = self.model, parent = self)
bound.show()
else:
bound.activateWindow()
def open_lateral_contrib(self):
lateral = LateralContributionWindow(study = self.model, parent = self)
lateral.show()
lateral = self.sub_win_filter_first(
"Lateral contribution",
contain = []
)
if lateral is None:
lateral = LateralContributionWindow(study = self.model, parent = self)
lateral.show()
else:
lateral.activateWindow()
def open_stricklers(self):
strick = StricklersWindow(
study = self.model,
config = self.conf,
parent = self
strick = self.sub_win_filter_first(
"Stricklers",
contain = []
)
strick.show()
if strick is None:
strick = StricklersWindow(
study = self.model,
config = self.conf,
parent = self
)
strick.show()
else:
strick.activateWindow()
def open_frictions(self):
if (self.model is not None and
self.model.river.has_current_reach()):
frictions = FrictionsWindow(
study = self.model,
parent = self
frictions = self.sub_win_filter_first(
"Frictions",
contain = [self.model.river.current_reach().name]
)
frictions.show()
if frictions is None:
frictions = FrictionsWindow(
study = self.model,
parent = self
)
frictions.show()
else:
frictions.activateWindow()
else:
self.msg_select_reach()
def open_initial_conditions(self):
if self.model.river.has_current_reach():
initial = InitialConditionsWindow(
study = self.model,
parent = self
initial = self.sub_win_filter_first(
"Initial condition",
contain = [self.model.river.current_reach().name]
)
initial.show()
if initial is None:
initial = InitialConditionsWindow(
study = self.model,
parent = self
)
initial.show()
else:
initial.activateWindow()
else:
self.msg_select_reach()
def open_solver_parameters(self):
params = SolverParametersWindow(
study = self.model,
parent = self
params = self.sub_win_filter_first(
"Solver parameters",
contain = []
)
params.show()
if params is None:
params = SolverParametersWindow(
study = self.model,
parent = self
)
params.show()
else:
params.activateWindow()
def open_sediment_layers(self):
sl = SedimentLayersWindow(
@@ -545,6 +672,32 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
)
sol.show()
def open_solver_results(self, solver, results = None):
# If no specific results, get last results
if results is None:
results = self._last_results
# No results available
if results is None:
return
# Windows already opened
res = self.sub_win_filter_first(
"Results",
contain = [solver.name, results.date]
)
if res is None:
res = ResultsWindow(
study = self.model,
solver = solver,
results = results,
parent = self
)
res.show()
else:
res.activateWindow()
#########
# DEBUG #
#########
+35 -7
View File
@@ -1,6 +1,23 @@
# GraphWidget.py -- Pamhyr
# Copyright (C) 2023 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 math
import logging
from tools import timer
@@ -23,6 +40,8 @@ from Model.Network.Graph import Graph
from View.Network.UndoCommand import *
logger = logging.getLogger()
_translate = QCoreApplication.translate
@@ -158,7 +177,7 @@ class EdgeItem(QGraphicsItem):
if self.graph.selected_item() == self:
color = Qt.red
elif self.graph.current_edge() == self:
color = Qt.blue
color = Qt.black
elif not self.graph.graph.is_enable_edge(self.edge):
color = Qt.darkGray
@@ -555,14 +574,17 @@ class GraphWidget(QGraphicsView):
Returns:
Nothing
"""
previous_item = self._selected_item
self._selected_item = item
try:
previous_item = self._selected_item
self._selected_item = item
if previous_item:
previous_item.update()
if previous_item:
previous_item.update()
if item:
item.update()
if item:
item.update()
except Exception as e:
logger.debug(str(e))
def selected_new_edge_src_node(self):
"""The current node item selected to add new edge
@@ -714,6 +736,9 @@ class GraphWidget(QGraphicsView):
def mouseReleaseEvent(self, event):
self.clicked = False
if self._only_display:
return
if self._state == "move":
if self._current_moved_node is not None:
pos = self.mapToScene(event.pos())
@@ -819,6 +844,9 @@ class GraphWidget(QGraphicsView):
self.reverse_edge(items[0])
def contextMenuEvent(self, event):
if self._only_display:
return
pos = self.mapToScene(event.pos())
items = self.items(event.pos())
+46 -23
View File
@@ -1,5 +1,24 @@
# Table.py -- Pamhyr
# Copyright (C) 2023 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 Model.Network.Node import Node
from Model.Network.Edge import Edge
from Model.Network.Graph import Graph
@@ -137,31 +156,35 @@ class GraphTableModel(QAbstractTableModel):
def setData(self, index, value, role=Qt.EditRole):
if index.isValid():
if role == Qt.EditRole:
if (self.headers[index.column()] == "node1" or
self.headers[index.column()] == "node2"):
node = self.graph.node(value)
self._undo.push(
SetNodeCommand(
self.graph,
self.rows[index.row()],
self.headers[index.column()],
node
try:
if (self.headers[index.column()] == "node1" or
self.headers[index.column()] == "node2"):
node = self.graph.node(value)
self._undo.push(
SetNodeCommand(
self.graph,
self.rows[index.row()],
self.headers[index.column()],
node
)
)
)
elif self.headers[index.column()] == "enable":
self._undo.push(
EnableEdgeCommand(
self.rows[index.row()], value
# elif self.headers[index.column()] == "enable":
# self._undo.push(
# EnableEdgeCommand(
# self.rows[index.row()], value
# )
# )
else:
self._undo.push(
SetCommand(
self.rows[index.row()],
self.headers[index.column()],
value
)
)
)
else:
self._undo.push(
SetCommand(
self.rows[index.row()],
self.headers[index.column()],
value
)
)
except Exception as e:
logger.info(e)
logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index, [Qt.DisplayRole])
self.layoutChanged.emit()
+16
View File
@@ -1,3 +1,19 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2023 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
+21 -4
View File
@@ -1,3 +1,19 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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.QtGui import (
@@ -34,7 +50,7 @@ class NetworkWindow(ASubMainWindow):
self.setup_title()
super(NetworkWindow, self).__init__(
name=self._title, ui="Network", parent=parent
name=title, ui="Network", parent=parent
)
self.ui.setWindowTitle(self._title)
@@ -71,7 +87,8 @@ class NetworkWindow(ASubMainWindow):
# Edges table
self._reachs_model = GraphTableModel(
headers = ["name", "enable", "node1", "node2"],
headers = ["name", # "enable",
"node1", "node2"],
graph = self._graph,
rows_type = "edges",
undo = self._undo_stack,
@@ -86,9 +103,9 @@ class NetworkWindow(ASubMainWindow):
table = self.find(QTableView, "tableView_reachs")
table.setModel(self._reachs_model)
table.setItemDelegateForColumn(1, self.delegate_true_false_combobox)
# table.setItemDelegateForColumn(1, self.delegate_true_false_combobox)
table.setItemDelegateForColumn(1, self.delegate_combobox)
table.setItemDelegateForColumn(2, self.delegate_combobox)
table.setItemDelegateForColumn(3, self.delegate_combobox)
table.setSelectionBehavior(QAbstractItemView.SelectRows)
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
#table.resizeColumnsToContents()
+16
View File
@@ -1,3 +1,19 @@
# APlot.py -- Pamhyr
# Copyright (C) 2023 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 -*-
class APlot(object):
+16
View File
@@ -1,3 +1,19 @@
# MplCanvas.py -- Pamhyr
# Copyright (C) 2023 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/>.
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.figure import Figure
+16
View File
@@ -1,3 +1,19 @@
# mpl_canvas_onpick_event.py -- Pamhyr
# Copyright (C) 2023 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/>.
import logging
from time import time
+16
View File
@@ -1,3 +1,19 @@
# navigation_toolbar_2qt.py -- Pamhyr
# Copyright (C) 2023 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 os
+115
View File
@@ -0,0 +1,115 @@
# PlotAC.py -- Pamhyr
# Copyright (C) 2023 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.Plot.APlot import APlot
from PyQt5.QtCore import (
QCoreApplication
)
_translate = QCoreApplication.translate
class PlotAC(APlot):
def __init__(self, canvas=None, results=None,
reach_id=0, profile_id=0,
toolbar=None):
super(PlotAC, self).__init__(
canvas=canvas,
data=results,
toolbar=toolbar
)
self._current_timestamp = max(results.get("timestamps"))
self._current_reach_id = reach_id
self._current_profile_id = profile_id
@property
def results(self):
return self.data
@timer
def draw(self, highlight=None):
self.canvas.axes.cla()
self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
if self.results is None:
return
self.canvas.axes.set_xlabel(
_translate("MainWindow_reach", "X (m)"),
color='green', fontsize=11
)
self.canvas.axes.set_ylabel(
_translate("MainWindow_reach", "Elevation (m)"),
color='green', fontsize=11
)
reach = self.results.river.reach(self._current_reach_id)
profile = reach.profile(self._current_profile_id)
x = profile.geometry.get_station()
z = profile.geometry.z()
self.canvas.axes.set_xlim(
left = min(x), right = max(x)
)
self.line_kp, = self.canvas.axes.plot(
x, z,
linestyle="solid",
lw=1.8,
color='grey',
)
kp = reach.geometry.get_kp()
# Water elevation
water_z = profile.get_ts_key(self._current_timestamp, "Z")
self.canvas.axes.plot(
[min(x), max(x)], [water_z, water_z],
lw=1., color='b',
)
x_z = list(map(lambda _: water_z, x))
self.canvas.axes.fill_between(
x, z, water_z,
where=z <= water_z,
color='blue', alpha=0.5, interpolate=True
)
self.canvas.figure.tight_layout()
self.canvas.figure.canvas.draw_idle()
if self.toolbar is not None:
self.toolbar.update()
def set_reach(self, reach_id):
self._current_reach_id = reach_id
self._current_profile_id = 0
self.draw()
def set_profile(self, profile_id):
self._current_profile_id = profile_id
self.draw()
def set_timestamp(self, timestamp):
self._current_timestamp = timestamp
self.draw()
def update(self):
self.draw()
+131
View File
@@ -0,0 +1,131 @@
# PlotH.py -- Pamhyr
# Copyright (C) 2023 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 functools import reduce
from tools import timer, trace
from View.Plot.APlot import APlot
from PyQt5.QtCore import (
QCoreApplication
)
_translate = QCoreApplication.translate
logger = logging.getLogger()
class PlotH(APlot):
def __init__(self, canvas=None, results=None,
reach_id=0, profile_id=0,
toolbar=None, display_current=True):
super(PlotH, self).__init__(
canvas=canvas,
data=results,
toolbar=toolbar
)
self.display_current = display_current
self._current_timestamp = max(results.get("timestamps"))
self._current_reach_id = reach_id
self._current_profile_id = profile_id
@property
def results(self):
return self.data
@timer
def draw(self, highlight=None):
self.canvas.axes.cla()
self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
if self.results is None:
return
reach = self.results.river.reach(self._current_reach_id)
profile = reach.profile(self._current_profile_id)
if reach.geometry.number_profiles == 0:
self._init = False
return
kp_min, kp_max = (-1, -1)
if highlight is not None:
kp_min, kp_max = highlight
# Axes
self.canvas.axes.set_xlabel(
_translate("Results", "Time (s)"),
color='green', fontsize=12
)
self.canvas.axes.set_ylabel(
_translate("Results", "Discharge (m³/s)"),
color='green', fontsize=12
)
ts = list(self.results.get("timestamps"))
ts.sort()
self.canvas.axes.set_xlim(
left = min(ts), right = max(ts)
)
# Draw discharge for each timestamp
x = ts
y = profile.get_key("Q")
if len(ts) != len(x):
logger.warning(
"Results as less Q data ({len(x)}) " +
"than timestamps ({len(ts)}) " +
"for profile {self._current_profile_id}"
)
return
self._line = [
self.canvas.axes.plot(
x, y, lw=1.,
color='r',
markersize=3, marker='+'
)
]
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:
self.toolbar.update()
def set_reach(self, reach_id):
self._current_reach_id = reach_id
self._current_profile_id = 0
self.draw()
def set_profile(self, profile_id):
self._current_profile_id = profile_id
self.draw()
def set_timestamp(self, timestamp):
self._current_timestamp = timestamp
self.draw()
def update(self):
self.draw()
+117
View File
@@ -0,0 +1,117 @@
# PlotKPC.py -- Pamhyr
# Copyright (C) 2023 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.Plot.APlot import APlot
from PyQt5.QtCore import (
QCoreApplication
)
_translate = QCoreApplication.translate
class PlotKPC(APlot):
def __init__(self, canvas=None, results=None,
reach_id=0, profile_id=0,
toolbar=None):
super(PlotKPC, self).__init__(
canvas=canvas,
data=results,
toolbar=toolbar
)
self._current_timestamp = max(results.get("timestamps"))
self._current_reach_id = reach_id
self._current_profile_id = profile_id
@property
def results(self):
return self.data
@timer
def draw(self, highlight=None):
self.canvas.axes.cla()
self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
if self.results is None:
return
reach = self.results.river.reach(self._current_reach_id)
self.canvas.axes.set_ylabel(
_translate("MainWindow_reach", "Elevation (m)"),
color='green', fontsize=11
)
self.canvas.axes.set_xlabel(
_translate("MainWindow_reach", "KP (m)"),
color='green', fontsize=11
)
kp = reach.geometry.get_kp()
z_min = reach.geometry.get_z_min()
self.canvas.axes.set_xlim(
left = min(kp), right = max(kp)
)
self.line_kp_zmin = self.canvas.axes.plot(
kp, z_min,
color='grey', lw=1.
)
if len(reach.geometry.profiles) != 0:
kp = reach.geometry.get_kp()
# Water elevation
water_z = list(
map(
lambda p: p.get_ts_key(self._current_timestamp, "Z"),
reach.profiles
)
)
self.canvas.axes.plot(
kp, water_z, lw=1.,
color='b',
)
self.canvas.axes.fill_between(
kp, z_min, water_z,
color='blue', alpha=0.5, interpolate=True
)
self.canvas.figure.tight_layout()
self.canvas.figure.canvas.draw_idle()
if self.toolbar is not None:
self.toolbar.update()
def set_reach(self, reach_id):
self._current_reach_id = reach_id
self._current_profile_id = 0
self.draw()
def set_profile(self, profile_id):
self._current_profile_id = profile_id
self.draw()
def set_timestamp(self, timestamp):
self._current_timestamp = timestamp
self.draw()
def update(self):
self.draw()
+186
View File
@@ -0,0 +1,186 @@
# PlotXY.py -- Pamhyr
# Copyright (C) 2023 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 functools import reduce
from tools import timer, trace
from View.Plot.APlot import APlot
from PyQt5.QtCore import (
QCoreApplication
)
_translate = QCoreApplication.translate
logger = logging.getLogger()
class PlotXY(APlot):
def __init__(self, canvas=None, results=None,
reach_id=0, profile_id=0,
toolbar=None, display_current=True):
super(PlotXY, self).__init__(
canvas=canvas,
data=results,
toolbar=toolbar
)
self.display_current = display_current
self.line_xy = []
self.line_gl = []
self._current_timestamp = max(results.get("timestamps"))
self._current_reach_id = reach_id
self._current_profile_id = profile_id
@property
def results(self):
return self.data
@timer
def draw(self, highlight=None):
self.canvas.axes.cla()
self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
if self.results is None:
return
reach = self.results.river.reach(self._current_reach_id)
if reach.geometry.number_profiles == 0:
self._init = False
return
kp_min, kp_max = (-1, -1)
if highlight is not None:
kp_min, kp_max = highlight
# Axes
self.canvas.axes.set_xlabel(
_translate("Results", "X (m)"),
color='green', fontsize=12
)
self.canvas.axes.set_ylabel(
_translate("Results", "Y (m)"),
color='green', fontsize=12
)
self.canvas.axes.axis("equal")
kp = reach.geometry.get_kp()
self.canvas.axes.set_xlim(
left = min(kp), right = max(kp)
)
# Draw line for each profile
self.line_xy = [
self.canvas.axes.plot(
x, y, lw=1.,
color='b' if kp_min <= kp <= kp_max else 'grey',
markersize=3, marker='+'
)
for x, y, kp in zip(
reach.geometry.get_x(),
reach.geometry.get_y(),
kp
)
]
# Guide lines
x_complete = reach.geometry.get_guidelines_x()
y_complete = reach.geometry.get_guidelines_y()
self.line_gl = [
self.canvas.axes.plot(
x, y,
)
for x, y in zip(x_complete, y_complete)
]
if self.display_current:
# Current profile
profile = reach.profile(self._current_profile_id).geometry
self.plot_selected, = self.canvas.axes.plot(
profile.x(),
profile.y(),
lw=1., markersize=3,
marker='+', color="b"
)
self.plot_selected.set_visible(False)
# Display point under water
poly_l_x = []
poly_l_y = []
poly_r_x = []
poly_r_y = []
for profile in reach.profiles:
water_z = profile.get_ts_key(
self._current_timestamp, "Z"
)
pgeo = profile.geometry
x, y = reduce(
lambda acc, pts: (acc[0] + [pts.x], acc[1] + [pts.y]),
filter(
lambda pts: pts.z < water_z,
pgeo.points
),
([], [])
)
poly_l_x.append(x[0])
poly_l_y.append(y[0])
poly_r_x.append(x[-1])
poly_r_y.append(y[-1])
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_l_x[0]]
poly_y = poly_l_y + list(reversed(poly_r_y)) + [poly_l_y[0]]
self.canvas.axes.fill(poly_x, poly_y, color='blue', alpha=1)
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:
self.toolbar.update()
def set_reach(self, reach_id):
self._current_reach_id = reach_id
self._current_profile_id = 0
self.draw()
def set_profile(self, profile_id):
self._current_profile_id = profile_id
self.draw()
def set_timestamp(self, timestamp):
self._current_timestamp = timestamp
self.draw()
def update(self):
self.draw()
+107
View File
@@ -0,0 +1,107 @@
# Table.py -- Pamhyr
# Copyright (C) 2023 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 timer, trace
from PyQt5.QtGui import (
QKeySequence, QColor
)
from PyQt5.QtCore import (
Qt, QAbstractTableModel, QModelIndex,
QVariant, pyqtSlot, QCoreApplication,
)
from PyQt5.QtWidgets import (
QMessageBox, QUndoCommand, QUndoStack,
QStyledItemDelegate, QLineEdit, QAbstractItemView,
QComboBox,
)
from View.Results.translate import *
logger = logging.getLogger()
_translate = QCoreApplication.translate
class TableModel(QAbstractTableModel):
def __init__(self, results = None, study = None, mode = None, undo=None):
super(QAbstractTableModel, self).__init__()
self._results = results
self._study = study
self._mode = mode
self._undo_stack = undo
self._table_headers = table_headers_reach
if mode != "reach":
self._table_headers = table_headers_profile
self._headers = list(self._table_headers.keys())
self._selected = 0
self._timestamp = 0
def rowCount(self, parent=QModelIndex()):
if self._mode == "reach":
return len(self._results.river.reachs)
current_reach = self._results.river.reach(self._selected)
return len(current_reach.profiles)
def columnCount(self, parent=QModelIndex()):
return len(self._headers)
def data(self, index, role=Qt.DisplayRole):
if role != Qt.ItemDataRole.DisplayRole:
return QVariant()
row = index.row()
column = index.column()
if self._mode == "reach":
if self._headers[column] == "name":
v = self._results.river.reach(row).name
return str(v)
else:
current_reach = self._results.river.reach(self._selected)
if self._headers[column] == "name":
v = current_reach.profile(row).name
return str(v)
elif self._headers[column] == "kp":
v = current_reach.profile(row).kp
return f"{v:.4f}"
return QVariant()
def headerData(self, section, orientation, role=Qt.DisplayRole):
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
return self._table_headers[self._headers[section]]
return QVariant()
def index(self, row, column, parent=QModelIndex()):
if not self.hasIndex(row, column, parent):
return QModelIndex()
return self.createIndex(row, column, QModelIndex())
def flags(self, index):
return Qt.ItemIsEnabled | Qt.ItemIsSelectable
+17
View File
@@ -0,0 +1,17 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2023 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 -*-
+268
View File
@@ -0,0 +1,268 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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 trace, timer
from View.ASubWindow import ASubMainWindow
from View.ListedSubWindow import ListedSubWindow
from PyQt5.QtGui import (
QKeySequence,
)
from PyQt5.QtCore import (
Qt, QVariant, QAbstractTableModel,
QCoreApplication, QModelIndex, pyqtSlot,
)
from PyQt5.QtWidgets import (
QDialogButtonBox, QPushButton, QLineEdit,
QFileDialog, QTableView, QAbstractItemView,
QUndoStack, QShortcut, QAction, QItemDelegate,
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
QSlider,
)
from View.Plot.MplCanvas import MplCanvas
from View.Results.PlotXY import PlotXY
from View.Results.PlotAC import PlotAC
from View.Results.PlotKPC import PlotKPC
from View.Results.PlotH import PlotH
from View.Results.Table import TableModel
from View.Results.translate import *
from View.Stricklers.Window import StricklersWindow
_translate = QCoreApplication.translate
logger = logging.getLogger()
class ResultsWindow(ASubMainWindow, ListedSubWindow):
def __init__(self, title="Results",
study=None, solver=None, results=None,
parent=None):
self._study = study
self._solver = solver
self._results = results
self._timestamps = sorted(list(self._results.get("timestamps")))
self.setup_title(title)
super(ResultsWindow, self).__init__(
name=title, ui="Results", parent=parent
)
self.setup_sc()
self.setup_table()
self.setup_graph()
self.setup_slider()
self.setup_connections()
self.ui.setWindowTitle(self._title)
def setup_title(self, title):
self._title = (
title + " - "
+ self._study.name + " - "
+ self._solver.name + " - "
+ self._results.date
)
def setup_sc(self):
self._undo_stack = QUndoStack()
self.undo_sc = QShortcut(QKeySequence.Undo, self)
self.redo_sc = QShortcut(QKeySequence.Redo, self)
self.copy_sc = QShortcut(QKeySequence.Copy, self)
self.paste_sc = QShortcut(QKeySequence.Paste, self)
def setup_table(self):
self._table = {}
for t in ["reach", "profile"]:
table = self.find(QTableView, f"tableView_{t}")
self._table[t] = TableModel(
results = self._results,
study = self._study,
mode = t,
undo = self._undo_stack,
)
table.setModel(self._table[t])
table.setSelectionBehavior(QAbstractItemView.SelectRows)
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
table.setAlternatingRowColors(True)
def setup_slider(self):
self._slider_profile = self.find(QSlider, f"verticalSlider_profile")
default_reach = self._results.river.reach(0)
self._slider_profile.setMaximum(len(default_reach.profiles) - 1)
self._slider_profile.setValue(0)
self._slider_time = self.find(QSlider, f"horizontalSlider_time")
self._slider_time.setMaximum(len(self._timestamps) - 1)
self._slider_time.setValue(len(self._timestamps) - 1)
def setup_graph(self):
self.canvas = MplCanvas(width=5, height=4, dpi=100)
self.canvas.setObjectName("canvas")
self.plot_layout = self.find(QVBoxLayout, "verticalLayout")
self.plot_layout.addWidget(self.canvas)
self.plot_xy = PlotXY(
canvas = self.canvas,
results = self._results,
reach_id = 0,
profile_id = 0,
toolbar = None,
display_current = False
)
self.plot_xy.draw()
self.canvas_2 = MplCanvas(width=5, height=4, dpi=100)
self.canvas_2.setObjectName("canvas_2")
self.plot_layout_2 = self.find(QVBoxLayout, "verticalLayout_2")
self.plot_layout_2.addWidget(self.canvas_2)
self.plot_kpc = PlotKPC(
canvas = self.canvas_2,
results = self._results,
reach_id = 0,
profile_id = 0,
toolbar = None
)
self.plot_kpc.draw()
self.canvas_3 = MplCanvas(width=5, height=4, dpi=100)
self.canvas_3.setObjectName("canvas_3")
self.plot_layout_3 = self.find(QVBoxLayout, "verticalLayout_3")
self.plot_layout_3.addWidget(self.canvas_3)
self.plot_ac = PlotAC(
canvas = self.canvas_3,
results = self._results,
reach_id = 0,
profile_id = 0,
toolbar = None
)
self.plot_ac.draw()
self.canvas_4 = MplCanvas(width=5, height=4, dpi=100)
self.canvas_4.setObjectName("canvas_4")
self.plot_layout_4 = self.find(QVBoxLayout, "verticalLayout_hydrograph")
self.plot_layout_4.addWidget(self.canvas_4)
self.plot_h = PlotH(
canvas = self.canvas_4,
results = self._results,
reach_id = 0,
profile_id = 0,
toolbar = None
)
self.plot_h.draw()
def setup_connections(self):
self.undo_sc.activated.connect(self.undo)
self.redo_sc.activated.connect(self.redo)
self.copy_sc.activated.connect(self.copy)
self.paste_sc.activated.connect(self.paste)
fun = {
"reach": self._set_current_reach,
"profile": self._set_current_profile,
}
for t in ["reach", "profile"]:
table = self.find(QTableView, f"tableView_{t}")
table.selectionModel()\
.selectionChanged\
.connect(fun[t])
self._table[t].dataChanged.connect(fun[t])
self._slider_profile.valueChanged.connect(self._set_current_profile_slider)
self._slider_time.valueChanged.connect(self._set_current_timestamp)
def update(self, reach_id = None, profile_id = None, timestamp = None):
if reach_id is not None:
self.plot_xy.set_reach(reach_id)
self.plot_ac.set_reach(reach_id)
self.plot_kpc.set_reach(reach_id)
self.plot_h.set_reach(reach_id)
if profile_id is not None:
self.plot_xy.set_profile(profile_id)
self.plot_ac.set_profile(profile_id)
self.plot_kpc.set_profile(profile_id)
self.plot_h.set_profile(profile_id)
if timestamp is not None:
self.plot_xy.set_timestamp(timestamp)
self.plot_ac.set_timestamp(timestamp)
self.plot_kpc.set_timestamp(timestamp)
self.plot_h.set_timestamp(timestamp)
self.plot_xy.draw()
self.plot_ac.draw()
self.plot_kpc.draw()
self.plot_h.draw()
def _set_current_reach(self):
table = self.find(QTableView, f"tableView_reach")
indexes = table.selectedIndexes()
if len(indexes) == 0:
return
self.update(reach_id = indexes[0].row())
def _set_current_profile(self):
table = self.find(QTableView, f"tableView_profile")
indexes = table.selectedIndexes()
if len(indexes) == 0:
return
ind = indexes[0].row()
self.update(profile_id = ind)
self._slider_profile.setValue(ind)
def _set_current_profile_slider(self):
pid = self._slider_profile.value()
self.update(profile_id = pid)
return
def _set_current_timestamp(self):
timestamp = self._timestamps[self._slider_time.value()]
self.update(timestamp = timestamp)
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()
+30
View File
@@ -0,0 +1,30 @@
# translate.py -- Pamhyr
# Copyright (C) 2023 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
_translate = QCoreApplication.translate
table_headers_reach = {
"name": _translate("Results", "Reach name"),
}
table_headers_profile = {
"name": _translate("Results", "Name"),
"kp": _translate("Results", "KP (m)"),
}
+16
View File
@@ -1,3 +1,19 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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 tempfile
+37 -2
View File
@@ -1,7 +1,24 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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 tempfile
import os
import logging
import tempfile
from queue import Queue
from tools import trace, timer
@@ -37,6 +54,8 @@ except:
_translate = QCoreApplication.translate
logger = logging.getLogger()
class SelectSolverWindow(ASubWindow, ListedSubWindow):
def __init__(self, title="Select solver",
study=None, config=None,
@@ -94,6 +113,8 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow):
self._config = config
self._solver = solver
self._results = None
super(SolverLogWindow, self).__init__(
name=self._title, ui="SolverLog", parent=parent
)
@@ -153,6 +174,7 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow):
self.find(QAction, "action_pause").triggered.connect(self.pause)
self.find(QAction, "action_stop").triggered.connect(self.stop)
self.find(QAction, "action_log_file").triggered.connect(self.log_file)
self.find(QAction, "action_results").triggered.connect(self.results)
self._alarm.timeout.connect(self.update)
@@ -177,12 +199,16 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow):
self.find(QAction, "action_start").setEnabled(True)
self.find(QAction, "action_pause").setEnabled(False)
self.find(QAction, "action_stop").setEnabled(False)
self.find(QAction, "action_results").setEnabled(True)
if self._solver.log_file() != "":
self.find(QAction, "action_log_file").setEnabled(True)
while self._output.qsize() != 0:
s = self._output.get()
self._log(s)
if type(s) is str and "[ERROR]" in s:
self._log(s, color="red")
else:
self._log(s)
def start(self):
if self._solver.is_stoped():
@@ -193,6 +219,7 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow):
self._process = self.new_process(self._parent)
self._log(" *** Start", color="blue")
self._results = None
self._solver.start(self._process)
self.find(QAction, "action_start").setEnabled(False)
@@ -202,6 +229,7 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow):
self.find(QAction, "action_pause").setEnabled(False)
self.find(QAction, "action_stop").setEnabled(True)
self.find(QAction, "action_log_file").setEnabled(False)
self.find(QAction, "action_results").setEnabled(False)
def pause(self):
self._log(" *** Pause", color="blue")
@@ -210,6 +238,7 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow):
self.find(QAction, "action_start").setEnabled(True)
self.find(QAction, "action_pause").setEnabled(False)
self.find(QAction, "action_stop").setEnabled(True)
self.find(QAction, "action_results").setEnabled(False)
def stop(self):
self._log(" *** Stop", color="blue")
@@ -218,9 +247,15 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow):
self.find(QAction, "action_start").setEnabled(True)
self.find(QAction, "action_pause").setEnabled(False)
self.find(QAction, "action_stop").setEnabled(False)
self.find(QAction, "action_results").setEnabled(True)
if self._solver.log_file() != "":
self.find(QAction, "action_log_file").setEnabled(True)
def results(self):
if self._results is None:
self._results = self._solver.results(self._study, self._workdir, qlog = self._output)
self._parent.open_solver_results(self._solver, self._results)
def log_file(self):
file_name = os.path.join(self._workdir, self._solver.log_file())
log = SolverLogFileWindow(
+31 -8
View File
@@ -1,5 +1,24 @@
# Table.py -- Pamhyr
# Copyright (C) 2023 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 (
@@ -81,16 +100,20 @@ class TableModel(QAbstractTableModel):
row = index.row()
column = index.column()
if self._headers[column] == "value":
if value in tr.r_yes_no:
value = tr.r_yes_no[value].lower()
try:
if self._headers[column] == "value":
if value in tr.r_yes_no:
value = tr.r_yes_no[value].lower()
self._undo.push(
SetCommand(
self._params, row,
"value", value
self._undo.push(
SetCommand(
self._params, row,
"value", value
)
)
)
except Exception as e:
logger.info(e)
logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
+17 -1
View File
@@ -1,3 +1,19 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2023 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
@@ -17,7 +33,7 @@ class SetCommand(QUndoCommand):
self._index = index
self._column = column
self._old = self._data.get(self._index)[column]
self._new = new_value
self._new = str(new_value)
def undo(self):
self._data.get(self._index)[self._column] = self._old
+18 -2
View File
@@ -1,3 +1,19 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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
@@ -40,7 +56,7 @@ class SolverParametersWindow(ASubMainWindow, ListedSubWindow):
# Init tanslate dictionary
tr.init()
title = title + " - " + study.name
self._title = title + " - " + study.name
super(SolverParametersWindow, self).__init__(
name=title, ui="SolverParameters", parent=parent
@@ -53,7 +69,7 @@ class SolverParametersWindow(ASubMainWindow, ListedSubWindow):
self.setup_table()
self.setup_connections()
self.ui.setWindowTitle(title)
self.ui.setWindowTitle(self._title)
def setup_sc(self):
self._undo_stack = {}
+16
View File
@@ -1,3 +1,19 @@
# translate.py -- Pamhyr
# Copyright (C) 2023 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
+45 -21
View File
@@ -1,5 +1,24 @@
# Table.py -- Pamhyr
# Copyright (C) 2023 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 (
@@ -23,8 +42,9 @@ from View.Stricklers.UndoCommand import (
from View.Stricklers.translate import *
_translate = QCoreApplication.translate
logger = logging.getLogger()
_translate = QCoreApplication.translate
class TableModel(QAbstractTableModel):
def __init__(self, data=None, undo=None, tab=""):
@@ -76,30 +96,34 @@ class TableModel(QAbstractTableModel):
row = index.row()
column = index.column()
if self._headers[column] == "name":
self._undo.push(
SetNameCommand(
self._data, row, value
try:
if self._headers[column] == "name":
self._undo.push(
SetNameCommand(
self._data, row, value
)
)
)
elif self._headers[column] == "comment":
self._undo.push(
SetCommentCommand(
self._data, row, value
elif self._headers[column] == "comment":
self._undo.push(
SetCommentCommand(
self._data, row, value
)
)
)
elif self._headers[column] == "minor":
self._undo.push(
SetMinorCommand(
self._data, row, value
elif self._headers[column] == "minor":
self._undo.push(
SetMinorCommand(
self._data, row, value
)
)
)
elif self._headers[column] == "medium":
self._undo.push(
SetMediumCommand(
self._data, row, value
elif self._headers[column] == "medium":
self._undo.push(
SetMediumCommand(
self._data, row, value
)
)
)
except Exception as e:
logger.info(e)
logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
+20 -4
View File
@@ -1,3 +1,19 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2023 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
@@ -17,7 +33,7 @@ class SetNameCommand(QUndoCommand):
self._data = data
self._index = index
self._old = self._data.get(self._index).name
self._new = new_value
self._new = str(new_value)
def undo(self):
self._data.get(self._index).name = self._old
@@ -32,7 +48,7 @@ class SetCommentCommand(QUndoCommand):
self._data = data
self._index = index
self._old = self._data.get(self._index).comment
self._new = new_value
self._new = str(new_value)
def undo(self):
self._data.get(self._index).comment = self._old
@@ -47,7 +63,7 @@ class SetMinorCommand(QUndoCommand):
self._data = data
self._index = index
self._old = self._data.get(self._index).minor
self._new = new_value
self._new = float(new_value)
def undo(self):
self._data.get(self._index).minor = self._old
@@ -62,7 +78,7 @@ class SetMediumCommand(QUndoCommand):
self._data = data
self._index = index
self._old = self._data.get(self._index).medium
self._new = new_value
self._new = float(new_value)
def undo(self):
self._data.get(self._index).medium = self._old
+18 -2
View File
@@ -1,3 +1,19 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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
@@ -35,7 +51,7 @@ logger = logging.getLogger()
class StricklersWindow(ASubMainWindow, ListedSubWindow):
def __init__(self, title="Stricklers", study=None, config=None, parent=None):
title = title + " - " + study.name
self._title = title + " - " + study.name
super(StricklersWindow, self).__init__(
name=title, ui="Stricklers", parent=parent
@@ -48,7 +64,7 @@ class StricklersWindow(ASubMainWindow, ListedSubWindow):
self.setup_table()
self.setup_connections()
self.ui.setWindowTitle(title)
self.ui.setWindowTitle(self._title)
def setup_sc(self):
self._undo_stack = QUndoStack()
+16
View File
@@ -1,3 +1,19 @@
# translate.py -- Pamhyr
# Copyright (C) 2023 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
+16
View File
@@ -1,3 +1,19 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 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 Model.Study import Study
+15 -46
View File
@@ -85,17 +85,12 @@
<addaction name="separator"/>
<addaction name="action_menu_open"/>
<addaction name="separator"/>
<addaction name="action_menu_import_mage"/>
<addaction name="action_menu_import_rubarbe"/>
<addaction name="separator"/>
<addaction name="separator"/>
<addaction name="action_menu_close"/>
<addaction name="separator"/>
<addaction name="action_menu_edit"/>
<addaction name="action_menu_save"/>
<addaction name="action_menu_save_as"/>
<addaction name="separator"/>
<addaction name="separator"/>
<addaction name="action_menu_config"/>
<addaction name="separator"/>
<addaction name="action_menu_quit"/>
@@ -117,32 +112,8 @@
<property name="title">
<string>&amp;Geometry</string>
</property>
<widget class="QMenu" name="menuCompare">
<property name="title">
<string>Comparer</string>
</property>
<widget class="QMenu" name="menu_cross_profile">
<property name="title">
<string>Profil en travers</string>
</property>
<addaction name="action_menu_abscisse_cote"/>
<addaction name="action_menu_XYZ"/>
</widget>
<addaction name="menu_cross_profile"/>
</widget>
<addaction name="action_menu_edit_geometry"/>
<addaction name="separator"/>
<addaction name="action_menu_import_geometry"/>
<addaction name="action_menu_export_geometry"/>
<addaction name="separator"/>
<addaction name="action_menu_run_meshing_tool"/>
<addaction name="action_menu_view_mesh"/>
<addaction name="action_menu_export_mesh"/>
<addaction name="action_menu_delete_mesh_for_current_reach"/>
<addaction name="action_menu_delete_mesh"/>
<addaction name="separator"/>
<addaction name="separator"/>
<addaction name="menuCompare"/>
</widget>
<widget class="QMenu" name="menu_run">
<property name="locale">
@@ -152,8 +123,8 @@
<string>&amp;Execute</string>
</property>
<addaction name="action_menu_numerical_parameter"/>
<addaction name="separator"/>
<addaction name="action_menu_run_solver"/>
<addaction name="action_simulation_directory_management"/>
<addaction name="separator"/>
</widget>
<widget class="QMenu" name="menu_Hydraulics">
@@ -166,14 +137,9 @@
<addaction name="action_menu_boundary_conditions"/>
<addaction name="separator"/>
<addaction name="action_menu_initial_conditions"/>
<addaction name="action_initia_conditions_export"/>
<addaction name="action_import_final_conditions_as_initial"/>
<addaction name="separator"/>
<addaction name="action_menu_edit_friction"/>
<addaction name="action_menu_edit_lateral_contribution"/>
<addaction name="action_edit_spills"/>
<addaction name="separator"/>
<addaction name="action_edi_cross_building"/>
</widget>
<widget class="QMenu" name="menu_plot">
<property name="title">
@@ -272,8 +238,6 @@
<addaction name="separator"/>
<addaction name="action_toolBar_network"/>
<addaction name="action_toolBar_geometry"/>
<addaction name="action_toolBar_mesh"/>
<addaction name="action_toolBar_run_meshing_tool"/>
</widget>
<widget class="QToolBar" name="toolBar_2">
<property name="font">
@@ -298,12 +262,8 @@
<addaction name="separator"/>
<addaction name="action_toolBar_lateral_contrib"/>
<addaction name="separator"/>
<addaction name="action_toolBar_spills"/>
<addaction name="separator"/>
<addaction name="action_toolBar_frictions"/>
<addaction name="separator"/>
<addaction name="action_toolBar_building"/>
<addaction name="separator"/>
<addaction name="action_toolBar_initial_cond"/>
</widget>
<action name="action_menu_new">
@@ -675,11 +635,17 @@
</property>
</action>
<action name="action_menu_help_pamhyr">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Help PAMHYR</string>
</property>
</action>
<action name="action_menu_help_mage">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Help MAGE</string>
</property>
@@ -737,10 +703,10 @@
<normaloff>ressources/exit_bis.png</normaloff>ressources/exit_bis.png</iconset>
</property>
<property name="text">
<string>Quit application</string>
<string>Quit</string>
</property>
<property name="toolTip">
<string>Quitter l'application (Ctrl+Q)</string>
<string>Quit the application (Ctrl+Q)</string>
</property>
<property name="shortcut">
<string>Ctrl+Q</string>
@@ -755,7 +721,7 @@
<string>Run solver</string>
</property>
<property name="toolTip">
<string>Run solver on current study</string>
<string>Run a solver</string>
</property>
</action>
<action name="action_toolBar_kill_solver">
@@ -836,7 +802,7 @@
<string>Mesh</string>
</property>
<property name="toolTip">
<string>Afficher le maillage</string>
<string>Display meshed reach</string>
</property>
</action>
<action name="action_toolBar_boundary_cond">
@@ -871,7 +837,7 @@
<string>Friction</string>
</property>
<property name="toolTip">
<string>Edit friction frictions and lateral contributions</string>
<string>Edit friction frictions</string>
</property>
</action>
<action name="action_toolBar_stricklers">
@@ -916,6 +882,9 @@
<property name="text">
<string>Initial conditions</string>
</property>
<property name="toolTip">
<string>Define initial conditions</string>
</property>
</action>
<action name="action_menu_sediment_layers">
<property name="text">
+120
View File
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>942</width>
<height>655</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="locale">
<locale language="English" country="Europe"/>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QSplitter" name="splitter_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QSplitter" name="splitter_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QTableView" name="tableView_reach"/>
<widget class="QTableView" name="tableView_profile"/>
</widget>
<widget class="QWidget" name="">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Geometry</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QSplitter" name="splitter_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="verticalLayoutWidget">
<layout class="QVBoxLayout" name="verticalLayout"/>
</widget>
<widget class="QWidget" name="verticalLayoutWidget_2">
<layout class="QVBoxLayout" name="verticalLayout_2"/>
</widget>
</widget>
<widget class="QWidget" name="verticalLayoutWidget_3">
<layout class="QVBoxLayout" name="verticalLayout_3"/>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Hydrograph</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_hydrograph"/>
</item>
</layout>
</widget>
</widget>
</item>
<item row="0" column="1">
<widget class="QSlider" name="verticalSlider_profile">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="invertedAppearance">
<bool>true</bool>
</property>
<property name="invertedControls">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QSlider" name="horizontalSlider_time">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>942</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
+6
View File
@@ -63,6 +63,7 @@
<addaction name="action_pause"/>
<addaction name="action_stop"/>
<addaction name="action_log_file"/>
<addaction name="action_results"/>
</widget>
<action name="action_stop">
<property name="icon">
@@ -100,6 +101,11 @@
<string>LogFile</string>
</property>
</action>
<action name="action_results">
<property name="text">
<string>results</string>
</property>
</action>
</widget>
<resources/>
<connections/>
+64 -31
View File
@@ -6,53 +6,86 @@
<rect>
<x>0</x>
<y>0</y>
<width>362</width>
<height>98</height>
<width>553</width>
<height>262</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="locale">
<locale language="English" country="Europe"/>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<widget class="QLabel" name="label_logo">
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap>ressources/logoCemagref.gif</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
<pixmap>ressources/Logo-INRAE.png</pixmap>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_2">
<property name="font">
<font>
<pointsize>16</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>PamHyr</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Version en developpement:</string>
</property>
</widget>
</item>
</layout>
<widget class="QLabel" name="label_title">
<property name="font">
<font>
<pointsize>16</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>About PAMHYR</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_copyright">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_version">
<property name="text">
<string>Version: @version</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_license">
<property name="text">
<string>License: GPLv3+</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;a href=&quot;https://gitlab.irstea.fr/theophile.terraz/pamhyr&quot;&gt;Source code&lt;/a&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

+16
View File
@@ -1,5 +1,21 @@
#! /bin/sh
# ui_to_py.sh -- Pamhyr
# Copyright (C) 2023 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/>.
for ui in $(ls *.ui)
do
python3 -m PyQt5.uic.pyuic -x $ui -o ${ui%.*}.py