REPLines: Add REP lines into model, view and minor change.

setup.py
Pierre-Antoine Rouby 2024-03-26 10:39:38 +01:00
parent 1ff895368e
commit aedb8c46fc
16 changed files with 735 additions and 5 deletions

View File

@ -0,0 +1,150 @@
# REPLine.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from functools import reduce
from tools import trace, timer
from Model.Tools.PamhyrDB import SQLSubModel
from Model.Except import NotImplementedMethodeError
class REPLine(SQLSubModel):
_sub_classes = []
_id_cnt = 0
def __init__(self, id: int = -1, enabled=True,
name="", line="", solvers=set(),
status=None):
super(REPLine, self).__init__()
if id == -1:
self.id = REPLine._id_cnt
else:
self.id = id
self._status = status
self._enabled = enabled
self._name = f"Line{self.id}" if name == "" else name
self._line = line
self._solvers = solvers
REPLine._id_cnt = max(id, REPLine._id_cnt+1)
@property
def enabled(self):
return self._enabled
@enabled.setter
def enabled(self, enabled):
self._enabled = enabled
def is_enabled(self):
return self._enabled
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
@property
def line(self):
return self._line
@line.setter
def line(self, line):
self._line = line
@property
def solvers(self):
return self._solvers
@solvers.setter
def solvers(self, solvers):
self._solvers = solvers
@classmethod
def _db_create(cls, execute):
execute("""
CREATE TABLE rep_lines(
id INTEGER NOT NULL PRIMARY KEY,
enabled BOOLEAN NOT NULL,
name TEXT NOT NULL,
line TEXT NOT NULL,
solvers TEXT NOT NULL
)
""")
return cls._create_submodel(execute)
@classmethod
def _db_update(cls, execute, version):
major, minor, release = version.strip().split(".")
if major == minor == "0":
if int(release) < 9:
cls._db_create(execute)
return True
@classmethod
def _db_load(cls, execute, data=None):
new = []
table = execute(
"SELECT id, enabled, name, line, solvers " +
"FROM rep_lines"
)
for row in table:
it = iter(row)
id = next(it)
enabled = (next(it) == 1)
name = next(it)
line = next(it)
solvers = set(next(it).split(";;"))
f = cls(
id=id, enabled=enabled, name=name, line=line,
solvers=solvers, status=data['status']
)
new.append(f)
return new
def _db_save(self, execute, data=None):
solvers = ";;".join(self._solvers)
sql = (
"INSERT INTO " +
"rep_lines(id, enabled, name, line, solvers) " +
"VALUES (" +
f"{self.id}, {self._enabled}, " +
f"'{self._db_format(self._name)}', " +
f"'{self._db_format(self._line)}', " +
f"'{self._db_format(solvers)}'" +
")"
)
execute(sql)
return True

View File

@ -0,0 +1,56 @@
# REPLineList.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from tools import trace, timer
from Model.Except import NotImplementedMethodeError
from Model.Tools.PamhyrList import PamhyrModelList
from Model.REPLine.REPLine import REPLine
class REPLineList(PamhyrModelList):
_sub_classes = [REPLine]
@classmethod
def _db_load(cls, execute, data=None):
new = cls(status=data["status"])
new._lst = REPLine._db_load(execute, data)
return new
def _db_save(self, execute, data=None):
ok = True
# Delete previous data
execute("DELETE FROM rep_lines")
for af in self._lst:
ok &= af._db_save(execute, data)
return ok
@property
def lines(self):
return self.lst
def new(self, index):
n = REPLine(status=self._status)
self.insert(index, n)
self._status.modified()
return n

View File

@ -41,6 +41,7 @@ from Model.HydraulicStructures.HydraulicStructuresList import (
HydraulicStructureList,
)
from Model.AdditionalFile.AddFileList import AddFileList
from Model.REPLine.REPLineList import REPLineList
from Solver.Solvers import solver_type_list
@ -226,6 +227,7 @@ class River(Graph, SQLSubModel):
ReservoirList,
HydraulicStructureList,
AddFileList,
REPLineList,
]
def __init__(self, status=None):
@ -248,6 +250,7 @@ class River(Graph, SQLSubModel):
status=self._status
)
self._additional_files = AddFileList(status=self._status)
self._rep_lines = REPLineList(status=self._status)
@classmethod
def _db_create(cls, execute):
@ -320,6 +323,7 @@ class River(Graph, SQLSubModel):
new._additional_files = AddFileList._db_load(
execute, data
)
new._rep_lines = REPLineList._db_load(execute, data)
return new
@ -335,6 +339,7 @@ class River(Graph, SQLSubModel):
objs.append(self._reservoir)
objs.append(self._hydraulic_structures)
objs.append(self._additional_files)
objs.append(self._rep_lines)
for solver in self._parameters:
objs.append(self._parameters[solver])
@ -438,6 +443,10 @@ Last export at: @date."""
def additional_files(self):
return self._additional_files
@property
def rep_lines(self):
return self._rep_lines
@property
def parameters(self):
return self._parameters

View File

@ -41,7 +41,7 @@ class Study(SQLModel):
def __init__(self, filename=None, init_new=True):
# Metadata
self._version = "0.0.8"
self._version = "0.0.9"
self.creation_date = datetime.now()
self.last_modification_date = datetime.now()
self.last_save_date = datetime.now()

View File

@ -128,6 +128,15 @@ class Mage(CommandLineSolver):
name = self._study.name
return f"{name}.TRA"
def _export_REP_additional_lines(self, study, rep_file):
lines = filter(
lambda line: line.is_enabled(),
study.river.rep_lines.lines
)
for line in lines:
rep_file.write(line.line)
@timer
def _export_ST(self, study, repertory, qlog, name="0"):
files = []
@ -661,6 +670,8 @@ class Mage(CommandLineSolver):
if EXT in ["GRA"]:
f.write(f"{EXT} {file}\n")
self._export_REP_additional_lines(study, f)
@timer
def export(self, study, repertory, qlog=None):
self._study = study

View File

@ -50,7 +50,7 @@ class TabListModel(PamhyrListModel):
if status is STATUS.OK:
color = Qt.green
elif status is STATUS.WARNING:
color = Qt.yellow
color = QColor("orange")
elif status is STATUS.ERROR:
color = Qt.red

View File

@ -57,7 +57,7 @@ class TableModel(PamhyrTableModel):
if self._data[row].is_ok():
color = Qt.green
elif self._data[row].is_warning():
color = Qt.yellow
color = QColor("orange")
elif self._data[row].is_error():
color = Qt.red
@ -136,7 +136,7 @@ class TabTableModel(PamhyrTableModel):
if status is STATUS.OK:
color = Qt.green
elif status is STATUS.WARNING:
color = Qt.yellow
color = QColor("orange")
elif status is STATUS.ERROR:
color = Qt.red

View File

@ -68,6 +68,7 @@ from View.Frictions.Window import FrictionsWindow
from View.SedimentLayers.Window import SedimentLayersWindow
from View.SedimentLayers.Reach.Window import ReachSedimentLayersWindow
from View.AdditionalFiles.Window import AddFileListWindow
from View.REPLines.Window import REPLineListWindow
from View.SolverParameters.Window import SolverParametersWindow
from View.RunSolver.Window import SelectSolverWindow, SolverLogWindow
from View.CheckList.Window import CheckListWindow
@ -121,6 +122,7 @@ define_model_action = [
"action_menu_edit_hydraulic_structures", "action_menu_additional_file",
"action_menu_results_last", "action_open_results_from_file",
"action_menu_boundary_conditions_sediment",
"action_menu_rep_additional_lines",
]
action = (
@ -254,6 +256,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
"action_menu_edit_reach_sediment_layers":
self.open_reach_sediment_layers,
"action_menu_additional_file": self.open_additional_files,
"action_menu_rep_additional_lines": self.open_rep_lines,
"action_menu_close": self.close_model,
"action_menu_results_last": self.open_last_results,
"action_open_results_from_file": self.open_results_from_file,
@ -1078,6 +1081,19 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
)
self.additonal_files.show()
def open_rep_lines(self):
if self._study is not None:
if self.sub_window_exists(
REPLineListWindow,
data=[self._study, None]
):
return
self.rep_lines = REPLineListWindow(
study=self._study, parent=self
)
self.rep_lines.show()
def open_solver_parameters(self):
if self.sub_window_exists(
SolverParametersWindow,

View File

@ -0,0 +1,71 @@
# Window.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
import logging
from Modules import Modules
from View.Tools.PamhyrWindow import PamhyrDialog
from PyQt5.QtWidgets import (
QLabel, QPlainTextEdit, QPushButton,
QCheckBox,
)
from View.REPLines.Translate import REPLineTranslate
logger = logging.getLogger()
class EditREPLineWindow(PamhyrDialog):
_pamhyr_ui = "REPLineDialog"
_pamhyr_name = "Edit Mage REP lines"
def __init__(self, study=None, config=None, rep_line=None,
trad=None, parent=None):
name = trad[self._pamhyr_name] + " - " + study.name
super(EditREPLineWindow, self).__init__(
title=name,
study=study,
config=config,
options=[],
parent=parent
)
self._rep_line = rep_line
self._hash_data.append(self._rep_line)
self.setup_values()
def setup_values(self):
self.set_check_box("checkBox_enabled", self._rep_line.enabled)
self.set_line_edit_text("lineEdit_name", self._rep_line.name)
self.set_line_edit_text("lineEdit_line", self._rep_line.line)
def accept(self):
is_enabled = self.get_check_box("checkBox_enabled")
name = self.get_line_edit_text("lineEdit_name")
line = self.get_line_edit_text("lineEdit_line")
self._rep_line.enabled = is_enabled
self._rep_line.name = name
self._rep_line.line = line
self._rep_line.solvers = set()
self._propagate_update(key=Modules.ADDITIONAL_FILES)
self.close()

71
src/View/REPLines/List.py Normal file
View File

@ -0,0 +1,71 @@
# List.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
import logging
from functools import reduce
from tools import trace, timer
from PyQt5.QtCore import (
Qt, QVariant,
)
from PyQt5.QtGui import (
QColor, QBrush,
)
from View.Tools.PamhyrList import PamhyrListModel
logger = logging.getLogger()
class ListModel(PamhyrListModel):
def data(self, index, role):
row = index.row()
column = index.column()
file = self._data.lines[row]
if role == Qt.ForegroundRole:
color = Qt.gray
if file.is_enabled():
color = QColor("black")
else:
color = QColor("grey")
return QBrush(color)
if role == Qt.ItemDataRole.DisplayRole:
text = f"{file.name}: '{file.line}'"
if not file.is_enabled():
text += " (disabled)"
return text
return QVariant()
def add(self, row):
self._data.new(row)
self.update()
def delete(self, rows):
logger.info(f"add_files: delete {rows}")
self._data.delete_i(rows)
self.update()

View File

@ -0,0 +1,35 @@
# Translate.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
from View.Translate import MainTranslate
_translate = QCoreApplication.translate
class REPLineTranslate(MainTranslate):
def __init__(self):
super(REPLineTranslate, self).__init__()
self._dict["Mage REP lines"] = _translate(
"REPLines", "Mage REP lines"
)
self._dict["Edit Mage REP lines"] = _translate(
"REPLines", "Edit Mage REP lines"
)

104
src/View/REPLines/Window.py Normal file
View File

@ -0,0 +1,104 @@
# Window.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from tools import trace, timer
from PyQt5.QtWidgets import (
QAction, QListView,
)
from View.Tools.PamhyrWindow import PamhyrWindow
from View.REPLines.List import ListModel
from View.REPLines.Translate import REPLineTranslate
from View.REPLines.Edit.Window import EditREPLineWindow
class REPLineListWindow(PamhyrWindow):
_pamhyr_ui = "REPLineList"
_pamhyr_name = "Mage REP lines"
def __init__(self, study=None, config=None,
parent=None):
trad = REPLineTranslate()
name = trad[self._pamhyr_name] + " - " + study.name
super(REPLineListWindow, self).__init__(
title=name,
study=study,
config=config,
trad=trad,
options=[],
parent=parent
)
self.setup_list()
self.setup_connections()
def setup_list(self):
lst = self.find(QListView, f"listView")
self._list = ListModel(
list_view=lst,
data=self._study.river.rep_lines,
)
def setup_connections(self):
self.find(QAction, "action_add").triggered.connect(self.add)
self.find(QAction, "action_delete").triggered.connect(self.delete)
self.find(QAction, "action_edit").triggered.connect(self.edit)
def update(self):
self._list.update()
def selected_rows(self):
lst = self.find(QListView, f"listView")
return list(map(lambda i: i.row(), lst.selectedIndexes()))
def add(self):
rows = self.selected_rows()
if len(rows) > 0:
row = rows[0]
else:
row = 0
self._list.add(row)
def delete(self):
rows = self.selected_rows()
self._list.delete(rows)
def edit(self):
rows = self.selected_rows()
for row in rows:
rep_line = self._study.river.rep_lines.lines[row]
if self.sub_window_exists(
EditREPLineWindow,
data=[self._study, self._config, rep_line]
):
continue
win = EditREPLineWindow(
study=self._study,
config=self._config,
rep_line=rep_line,
trad=self._trad,
parent=self,
)
win.show()

View File

@ -119,7 +119,7 @@ This is my new study description
## Copyright
(c) {get_user_name()} - {datetime.now().year}
© {get_user_name()} - {datetime.now().year}
All right reserved.
"""

View File

@ -208,7 +208,14 @@
<property name="title">
<string>&amp;Advansed</string>
</property>
<widget class="QMenu" name="menuMage">
<property name="title">
<string>Mage</string>
</property>
<addaction name="action_menu_rep_additional_lines"/>
</widget>
<addaction name="action_menu_additional_file"/>
<addaction name="menuMage"/>
</widget>
<addaction name="menu_File"/>
<addaction name="menu_network"/>
@ -1000,6 +1007,11 @@
<string>&amp;Additional file</string>
</property>
</action>
<action name="action_menu_rep_additional_lines">
<property name="text">
<string>REP additional lines</string>
</property>
</action>
</widget>
<resources/>
<connections>

View File

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>452</width>
<height>145</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QCheckBox" name="checkBox_enabled">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Line</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_name"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEdit_line">
<property name="toolTip">
<string>Comment lines start with '*' char (let see the mage documentation for more details)</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Dialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,85 @@
<?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>896</width>
<height>504</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QListView" name="listView"/>
</item>
</layout>
</widget>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="action_add"/>
<addaction name="action_delete"/>
<addaction name="action_edit"/>
</widget>
<action name="action_add">
<property name="icon">
<iconset>
<normaloff>ressources/gtk-add.png</normaloff>ressources/gtk-add.png</iconset>
</property>
<property name="text">
<string>Add</string>
</property>
<property name="toolTip">
<string>Add new additional line</string>
</property>
<property name="shortcut">
<string>Ctrl+N</string>
</property>
</action>
<action name="action_delete">
<property name="icon">
<iconset>
<normaloff>ressources/gtk-remove.png</normaloff>ressources/gtk-remove.png</iconset>
</property>
<property name="text">
<string>Delete</string>
</property>
<property name="toolTip">
<string>Delete additional line(s)</string>
</property>
<property name="shortcut">
<string>Del</string>
</property>
</action>
<action name="action_edit">
<property name="icon">
<iconset>
<normaloff>ressources/edit.png</normaloff>ressources/edit.png</iconset>
</property>
<property name="text">
<string>Edit</string>
</property>
<property name="toolTip">
<string>Edit selected line(s)</string>
</property>
<property name="shortcut">
<string>Ctrl+E</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>