mirror of
https://gitlab.com/pamhyr/pamhyr2.git
synced 2026-10-30 03:20:41 +01:00
Compare commits
No files matched your search
+50
-52
@@ -1,5 +1,5 @@
|
||||
# .gitlab-ci.yml -- Pamhyr gitlab-ci
|
||||
# Copyright (C) 2023 INRAE
|
||||
# Copyright (C) 2023-2024 INRAE
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -29,9 +29,9 @@ stages:
|
||||
#############
|
||||
|
||||
variables:
|
||||
MAGE_VERSION: "v8.3.4"
|
||||
MAGE_8_VERSION: "v8.3.5"
|
||||
|
||||
dl-mage-doc:
|
||||
dl-mage8-doc:
|
||||
stage: downloads
|
||||
tags:
|
||||
- linux
|
||||
@@ -40,46 +40,48 @@ dl-mage-doc:
|
||||
script:
|
||||
- mkdir -p doc
|
||||
- cd doc
|
||||
- curl -L -o mage8.pdf https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/$MAGE_VERSION/downloads/documents/Mage-8_Documentation.pdf
|
||||
- curl -L -o mage8.pdf https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/$MAGE_8_VERSION/downloads/documents/Mage-8_Documentation.pdf
|
||||
artifacts:
|
||||
paths:
|
||||
- doc/mage8.pdf
|
||||
|
||||
dl-mage-linux:
|
||||
dl-mage8-linux:
|
||||
stage: downloads
|
||||
tags:
|
||||
- linux
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||
script:
|
||||
- curl -L -o mage.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/$MAGE_VERSION/downloads/packages/mage_linux.tgz
|
||||
- mkdir -p mage-linux
|
||||
- cd mage-linux
|
||||
- tar xvf ../mage.tgz
|
||||
- curl -L -o mage8.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/$MAGE_8_VERSION/downloads/packages/mage_linux.tgz
|
||||
- mkdir -p mage8-linux
|
||||
- cd mage8-linux
|
||||
- tar xvf ../mage8.tgz
|
||||
artifacts:
|
||||
paths:
|
||||
- mage-linux/mage
|
||||
- mage-linux/mage_extraire
|
||||
- mage-linux/mailleurTT
|
||||
- mage-linux/libbief.so
|
||||
- mage8-linux/mage
|
||||
- mage8-linux/mage_as7
|
||||
- mage8-linux/mage_extraire
|
||||
- mage8-linux/mailleurTT
|
||||
- mage8-linux/libbief.so
|
||||
|
||||
dl-mage-windows:
|
||||
dl-mage8-windows:
|
||||
stage: downloads
|
||||
tags:
|
||||
- linux
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||
script:
|
||||
- curl -L -o mage.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/$MAGE_VERSION/downloads/packages/mage_windows.tgz
|
||||
- mkdir -p mage-windows
|
||||
- cd mage-windows
|
||||
- tar xvf ../mage.tgz
|
||||
- curl -L -o mage8.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/$MAGE_8_VERSION/downloads/packages/mage_windows.tgz
|
||||
- mkdir -p mage8-windows
|
||||
- cd mage8-windows
|
||||
- tar xvf ../mage8.tgz
|
||||
artifacts:
|
||||
paths:
|
||||
- mage-windows/mage.exe
|
||||
- mage-windows/mage_extraire.exe
|
||||
- mage-windows/mailleurTT.exe
|
||||
- mage-windows/libbief.dll
|
||||
- mage8-windows/mage.exe
|
||||
- mage8-windows/mage_as7.exe
|
||||
- mage8-windows/mage_extraire.exe
|
||||
- mage8-windows/mailleurTT.exe
|
||||
- mage8-windows/libbief.dll
|
||||
|
||||
#############
|
||||
# CONFIGURE #
|
||||
@@ -222,9 +224,9 @@ build-linux:
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||
needs:
|
||||
- job: dl-mage-linux
|
||||
- job: dl-mage8-linux
|
||||
artifacts: true
|
||||
- job: dl-mage-doc
|
||||
- job: dl-mage8-doc
|
||||
artifacts: true
|
||||
- job: set-version
|
||||
artifacts: true
|
||||
@@ -249,28 +251,27 @@ build-linux:
|
||||
- pyinstaller -y --paths linux-venv/lib/python3.8/site-packages ../src/pamhyr.py
|
||||
# Create directory
|
||||
- mkdir -p pamhyr
|
||||
- mkdir -p pamhyr/pamhyr
|
||||
- mkdir -p pamhyr/pamhyr/_internal
|
||||
- mkdir -p pamhyr/_internal
|
||||
# Copy Pamhyr info
|
||||
- cp -v ../VERSION pamhyr/pamhyr/_internal/
|
||||
- cp -v ../AUTHORS pamhyr/pamhyr/_internal/
|
||||
- cp -v ../LICENSE pamhyr/pamhyr/_internal/
|
||||
- cp -v ../src/motd.txt pamhyr/pamhyr/_internal/
|
||||
- cp -v ../VERSION pamhyr/_internal/
|
||||
- cp -v ../AUTHORS pamhyr/_internal/
|
||||
- cp -v ../LICENSE pamhyr/_internal/
|
||||
- cp -v ../src/motd.txt pamhyr/_internal/
|
||||
# Copy mage
|
||||
- mkdir -p pamhyr/mage
|
||||
- cp -v ../mage-linux/* pamhyr/mage/
|
||||
- mkdir -p pamhyr/mage8
|
||||
- cp -v ../mage8-linux/* pamhyr/mage8/
|
||||
# Copy Pamhyr
|
||||
- cp -r dist/pamhyr pamhyr/
|
||||
- cp -r dist/pamhyr/* pamhyr/
|
||||
# Copy Pamhyr resources
|
||||
- mkdir -p pamhyr/pamhyr/_internal/View
|
||||
- mkdir -p pamhyr/pamhyr/_internal/View/ui
|
||||
- mkdir -p pamhyr/pamhyr/_internal/View/ui/Widgets
|
||||
- cp -r ../src/View/ui/*.ui pamhyr/pamhyr/_internal/View/ui/
|
||||
- cp -r ../src/View/ui/ressources/ pamhyr/pamhyr/_internal/View/ui
|
||||
- cp -r ../src/View/ui/Widgets/*.ui pamhyr/pamhyr/_internal/View/ui/Widgets
|
||||
- mkdir -p pamhyr/_internal/View
|
||||
- mkdir -p pamhyr/_internal/View/ui
|
||||
- mkdir -p pamhyr/_internal/View/ui/Widgets
|
||||
- cp -r ../src/View/ui/*.ui pamhyr/_internal/View/ui/
|
||||
- cp -r ../src/View/ui/ressources/ pamhyr/_internal/View/ui
|
||||
- cp -r ../src/View/ui/Widgets/*.ui pamhyr/_internal/View/ui/Widgets
|
||||
# Copy lang
|
||||
- mkdir -p pamhyr/pamhyr/_internal/lang
|
||||
- cp -r ../src/lang/*.qm pamhyr/pamhyr/_internal/lang
|
||||
- mkdir -p pamhyr/_internal/lang
|
||||
- cp -r ../src/lang/*.qm pamhyr/_internal/lang
|
||||
# Copy tests cases
|
||||
- mkdir -p pamhyr/tests_cases/
|
||||
- mkdir -p pamhyr/tests_cases/Saar
|
||||
@@ -298,10 +299,6 @@ build-linux:
|
||||
# Copy TP charriage
|
||||
- mkdir -p pamhyr/doc/TP_charriage/
|
||||
- cp ../doc/users/TP_charriage/* pamhyr/doc/TP_charriage
|
||||
# Create running script
|
||||
- echo "#!/bin/sh" > pamhyr/Pamhyr2
|
||||
- echo "./pamhyr/pamhyr $@" >> pamhyr/Pamhyr2
|
||||
- chmod u+x pamhyr/Pamhyr2
|
||||
artifacts:
|
||||
paths:
|
||||
- linux/pamhyr
|
||||
@@ -313,9 +310,9 @@ build-windows:
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||
needs:
|
||||
- job: dl-mage-windows
|
||||
- job: dl-mage8-windows
|
||||
artifacts: true
|
||||
- job: dl-mage-doc
|
||||
- job: dl-mage8-doc
|
||||
artifacts: true
|
||||
- job: set-version
|
||||
artifacts: true
|
||||
@@ -335,7 +332,8 @@ build-windows:
|
||||
- python -m pip install -r ..\requirements.txt
|
||||
- python -m pip install -U -r ..\requirements.txt
|
||||
# Run Pyinstaller
|
||||
- pyinstaller -y ..\src\pamhyr.py
|
||||
# - pyinstaller --noconsole -y ..\src\pamhyr.py
|
||||
- pyinstaller --hide-console hide-early -y ..\src\pamhyr.py
|
||||
# Create directory
|
||||
- mkdir pamhyr
|
||||
- dir
|
||||
@@ -421,10 +419,10 @@ linux-build-hash:
|
||||
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||
script:
|
||||
- cd linux
|
||||
- sha256sum -b pamhyr/pamhyr/pamhyr > pamhyr/pamhyr/pamhyr.sha256
|
||||
- sha256sum -b pamhyr/pamhyr > pamhyr/pamhyr.sha256
|
||||
artifacts:
|
||||
paths:
|
||||
- linux/pamhyr/pamhyr/pamhyr.sha256
|
||||
- linux/pamhyr/pamhyr.sha256
|
||||
|
||||
windows-build-hash:
|
||||
stage: hash
|
||||
@@ -438,10 +436,10 @@ windows-build-hash:
|
||||
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||
script:
|
||||
- cd windows
|
||||
- sha256sum -b pamhyr/pamhyr/pamhyr.exe > pamhyr/pamhyr/pamhyr.exe.sha256
|
||||
- sha256sum -b pamhyr/pamhyr.exe > pamhyr/pamhyr.exe.sha256
|
||||
artifacts:
|
||||
paths:
|
||||
- windows/pamhyr/pamhyr/pamhyr.exe.sha256
|
||||
- windows/pamhyr/pamhyr.exe.sha256
|
||||
|
||||
pkg-hash:
|
||||
stage: hash
|
||||
|
||||
+82
-45
@@ -1,5 +1,5 @@
|
||||
# documentation.org -- Pamhyr developers documentation
|
||||
# Copyright (C) 2023 INRAE
|
||||
# Copyright (C) 2023-2024 INRAE
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -369,6 +369,7 @@ of Bar (Listing [[sql-bar]] and [[sql-foo]]).
|
||||
CREATE TABLE bar (
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
x INTEGER NOT NULL,
|
||||
y INTEGER NOT NULL,
|
||||
foo_id INTEGER NOT NULL,
|
||||
FOREIGN KEY(foo_id) REFERENCES foo(id),
|
||||
)""")
|
||||
@@ -455,6 +456,15 @@ of Bar (Listing [[sql-bar]] and [[sql-foo]]).
|
||||
bar._sql_save(execute, data=data)
|
||||
#+end_src
|
||||
|
||||
Let see the results database scheme for Pamhyr2 at version v0.0.7 in
|
||||
Figure [[sql_schema]].
|
||||
|
||||
#+NAME: sql_schema
|
||||
#+ATTR_LATEX: :width 16cm
|
||||
#+CAPTION: SQLite database scheme at Pamhyr2 version v0.0.7 (generate with [[https://gitlab.com/Screwtapello/sqlite-schema-diagram]])
|
||||
[[./images/schema_v0.0.7.png]]
|
||||
|
||||
|
||||
[fn:sqlite] The SQLite web site: https://www.sqlite.org/index.html
|
||||
(last access 2023-09-20)
|
||||
|
||||
@@ -538,44 +548,44 @@ generic value from optional parameters, for examples:
|
||||
#+NAME: window
|
||||
#+CAPTION: Example of Pamhyr2 window
|
||||
#+begin_src python :python python3 :results output :noweb yes
|
||||
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||
from View.My.Translate import MyTranslate
|
||||
from View.My.Table import MyTableModel
|
||||
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||
from View.My.Translate import MyTranslate
|
||||
from View.My.Table import MyTableModel
|
||||
|
||||
class MyWindow(PamhyrWindow):
|
||||
_pamhyr_ui = "MyUI"
|
||||
_pamhyr_name = "My window"
|
||||
class MyWindow(PamhyrWindow):
|
||||
_pamhyr_ui = "MyUI"
|
||||
_pamhyr_name = "My window"
|
||||
|
||||
def __init__(self, my_data=None,
|
||||
study=None, config=None,
|
||||
parent=None):
|
||||
self._my_data = my_data
|
||||
def __init__(self, study=None, config=None,
|
||||
my_data=None,
|
||||
parent=None):
|
||||
self._my_data = my_data
|
||||
|
||||
super(MyWindow, self).__init__(
|
||||
# Window title
|
||||
title = self._pamhyr_name + " - " + study.name,
|
||||
# Window standard data
|
||||
study = study, config = config,
|
||||
trad = MyTranslate(),
|
||||
parent = parent,
|
||||
# Activate undo/redo and copy/paste shortcut
|
||||
options = ["undo", "copy"]
|
||||
)
|
||||
super(MyWindow, self).__init__(
|
||||
# Window title
|
||||
title = self._pamhyr_name + " - " + study.name,
|
||||
# Window standard data
|
||||
study = study, config = config,
|
||||
trad = MyTranslate(),
|
||||
parent = parent,
|
||||
# Activate undo/redo and copy/paste shortcut
|
||||
options = ["undo", "copy"]
|
||||
)
|
||||
|
||||
# Add custom data to hash window computation
|
||||
self._hash_data.append(self._my_data)
|
||||
# Add custom data to hash window computation
|
||||
self._hash_data.append(self._my_data)
|
||||
|
||||
# Setup custom window components
|
||||
self.setup_table()
|
||||
self.setup_connections()
|
||||
# Setup custom window components
|
||||
self.setup_table()
|
||||
self.setup_connections()
|
||||
|
||||
def setup_table(self):
|
||||
# Init table(s)...
|
||||
def setup_table(self):
|
||||
# Init table(s)...
|
||||
|
||||
def setup_connections(self):
|
||||
# Init action connection(s)...
|
||||
def setup_connections(self):
|
||||
# Init action connection(s)...
|
||||
|
||||
# ...
|
||||
# ...
|
||||
#+end_src
|
||||
|
||||
Typically we called method =setup_*=, the method to initialize some
|
||||
@@ -661,11 +671,13 @@ creation, this stack is accessible at =self._undo_stack=.
|
||||
|
||||
*** Plot
|
||||
|
||||
To define a new plot you can create a class who inherit to APlot. The
|
||||
creator need threee argument:
|
||||
To define a new plot you can create a class who inherit to
|
||||
PamhyrPlot. The creator need at leaste five argument:
|
||||
- A =canvas= of type =MplCanvas=
|
||||
- A (optional) =trad= of type =PamhyrTranslate=
|
||||
- A =data= used in =draw= and =update= to create and update the plot
|
||||
- A optional =toolbar= of type =PamhyrToolbar=
|
||||
- A =parent= window
|
||||
This class must implement two method =draw= and =update=, the first
|
||||
method to draw the plot from scratch, the second to update the plot if
|
||||
data has changed.
|
||||
@@ -673,19 +685,36 @@ data has changed.
|
||||
#+begin_src python :python python3 :results output :noweb yes
|
||||
from View.Tools.PamhyrPlot import PamhyrPlot
|
||||
|
||||
class MyPlot(APlot):
|
||||
def __init__(self, canvas=None, data=None, toolbar=None):
|
||||
class MyPlot(PamhyrPlot):
|
||||
def __init__(self, canvas=None, trad=None, toolbar=None
|
||||
data=None, parent=None):
|
||||
super(MyPlot, self).__init__(
|
||||
canvas=canvas,
|
||||
trad=trad,
|
||||
data=data,
|
||||
toolbar=toolbar
|
||||
toolbar=toolbar,
|
||||
parent=parent
|
||||
)
|
||||
|
||||
self.label_x = self._trad["x"]
|
||||
self.label_y = self._trad["y"]
|
||||
|
||||
# Optional configuration
|
||||
self._isometric_axis = False
|
||||
|
||||
self._auto_relim_update = True
|
||||
self._autoscale_update = True
|
||||
|
||||
def draw(self):
|
||||
# Draw function code...
|
||||
|
||||
def update(self, ind = None):
|
||||
def update(self):
|
||||
# Update function code...
|
||||
|
||||
def clear(self):
|
||||
# Clear plot values...
|
||||
|
||||
# ...
|
||||
#+end_src
|
||||
|
||||
** Solver
|
||||
@@ -745,7 +774,7 @@ execute a code on distant computer, for example, over ssh.
|
||||
style=dashed;
|
||||
subgraph cluster021 {
|
||||
label="Solver Classes";
|
||||
classSolverM7[label="Mage7", fillcolor=6];
|
||||
//classSolverM7[label="Mage7", fillcolor=6];
|
||||
classSolverM8[label="Mage8", fillcolor=6];
|
||||
classSolverR[label="RubarBE", fillcolor=6];
|
||||
}
|
||||
@@ -828,7 +857,7 @@ solver and get results:
|
||||
- (2.1) The solver read the input file(s)
|
||||
- (2.2) The solver compute results and write it to solver output
|
||||
file(s)
|
||||
- (3) Pamhyr2 create a Reuslts
|
||||
- (3) Pamhyr2 create a =Results= object
|
||||
- (3.1) The Pamhyr2 solver class read solver output file(s) and
|
||||
complete Results with readed data
|
||||
|
||||
@@ -958,8 +987,16 @@ different methods:
|
||||
|
||||
** Unit tests
|
||||
|
||||
The unit tests is actually not implemented in Pamhyr2, it is a *work
|
||||
in progress*.
|
||||
A very small part of Pamhyr2 has unit test. This part is limited to the Model.
|
||||
|
||||
#+begin_src shell
|
||||
python3 -m venv test
|
||||
. test test/bin/activate
|
||||
pip3 install -U -r ./full-requirements.txt
|
||||
|
||||
cd src/
|
||||
python3 -Walways -m unittest discovert -v -t .
|
||||
#+end_src
|
||||
|
||||
** The debug mode
|
||||
|
||||
@@ -970,14 +1007,14 @@ line:
|
||||
./Pamhyr2 debug
|
||||
#+end_src
|
||||
|
||||
This mode add some log and add two action in main window menu:
|
||||
"About/Debug" open a window with Python Repl in current Python
|
||||
environement, and "About/Debug SQLite" who open the application
|
||||
This mode add some log and add two action in main window menu: "About
|
||||
> Debug" open a window with Python Repl in current Python
|
||||
environement, and "About > Debug SQLite" who open the application
|
||||
SQLiteBrowser (if installed) on current Study to explore the study
|
||||
data base file.
|
||||
|
||||
#+NAME: debug-repl
|
||||
#+ATTR_LATEX: :width 12cm
|
||||
#+ATTR_LATEX: :width 14cm
|
||||
#+CAPTION: Pamhyr2 debug Python REPL
|
||||
[[./images/python-debug-repl.png]]
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 51 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 224 KiB |
@@ -10,3 +10,4 @@ colorama>=0.4.3
|
||||
pyinstaller>=5.11.0
|
||||
shapely>=2.0.1
|
||||
lxml>=4.9.3
|
||||
platformdirs>=4.2.0
|
||||
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
|
||||
start cmd /c pamhyr.exe debug
|
||||
@@ -0,0 +1,3 @@
|
||||
#! /bin/sh
|
||||
|
||||
./pamhyr debug
|
||||
@@ -16,34 +16,35 @@ rem along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
@ECHO ON
|
||||
|
||||
mkdir pamhyr\pamhyr\_internal
|
||||
xcopy /s /e /y dist\pamhyr pamhyr\pamhyr
|
||||
mkdir pamhyr\_internal
|
||||
xcopy /s /e /y dist\pamhyr pamhyr
|
||||
|
||||
rem Copy data
|
||||
mkdir pamhyr\pamhyr\_internal\lang
|
||||
mkdir pamhyr\pamhyr\_internal\View\ui\ressources
|
||||
mkdir pamhyr\pamhyr\_internal\View\ui\Widgets
|
||||
mkdir pamhyr\_internal\lang
|
||||
mkdir pamhyr\_internal\View\ui\ressources
|
||||
mkdir pamhyr\_internal\View\ui\Widgets
|
||||
|
||||
rem UI
|
||||
copy /y ..\src\View\ui\ressources\ pamhyr\pamhyr\_internal\View\ui\ressources
|
||||
copy /y ..\src\View\ui\Widgets\*.ui pamhyr\pamhyr\_internal\View\ui\Widgets
|
||||
copy /y ..\src\View\ui\*.ui pamhyr\pamhyr\_internal\View\ui\
|
||||
copy /y ..\src\View\ui\ressources\ pamhyr\_internal\View\ui\ressources
|
||||
copy /y ..\src\View\ui\Widgets\*.ui pamhyr\_internal\View\ui\Widgets
|
||||
copy /y ..\src\View\ui\*.ui pamhyr\_internal\View\ui\
|
||||
|
||||
rem Lang
|
||||
copy /y ..\src\lang\*.qm pamhyr\pamhyr\_internal\lang\
|
||||
copy /y ..\src\lang\*.qm pamhyr\_internal\lang\
|
||||
|
||||
rem Information
|
||||
copy /y ..\VERSION pamhyr\pamhyr\_internal
|
||||
copy /y ..\AUTHORS pamhyr\pamhyr\_internal
|
||||
copy /y ..\LICENSE pamhyr\pamhyr\_internal
|
||||
copy /y ..\src\motd.txt pamhyr\pamhyr\_internal
|
||||
copy /y ..\VERSION pamhyr\_internal
|
||||
copy /y ..\AUTHORS pamhyr\_internal
|
||||
copy /y ..\LICENSE pamhyr\_internal
|
||||
copy /y ..\src\motd.txt pamhyr\_internal
|
||||
|
||||
rem MAGE
|
||||
mkdir pamhyr\mage
|
||||
copy /y ..\mage-windows\mage.exe pamhyr\mage\
|
||||
copy /y ..\mage-windows\mage_extraire.exe pamhyr\mage\
|
||||
copy /y ..\mage-windows\mailleurTT.exe pamhyr\mage\
|
||||
copy /y ..\mage-windows\libbief.dll pamhyr\mage\
|
||||
mkdir pamhyr\mage8
|
||||
copy /y ..\mage8-windows\mage.exe pamhyr\mage8\
|
||||
copy /y ..\mage8-windows\mage_as7.exe pamhyr\mage8\
|
||||
copy /y ..\mage8-windows\mage_extraire.exe pamhyr\mage8\
|
||||
copy /y ..\mage8-windows\mailleurTT.exe pamhyr\mage8\
|
||||
copy /y ..\mage8-windows\libbief.dll pamhyr\mage8\
|
||||
|
||||
rem Copy tests_cases
|
||||
mkdir pamhyr\tests_cases
|
||||
|
||||
+3
-3
@@ -5,7 +5,7 @@
|
||||
|
||||
Name "Pamhyr2"
|
||||
OutFile "pamhyr-windows.exe"
|
||||
LicenseData "pamhyr\pamhyr\_internal\LICENSE"
|
||||
LicenseData "pamhyr\_internal\LICENSE"
|
||||
LicenseText "I Agree"
|
||||
|
||||
RequestExecutionLevel admin
|
||||
@@ -41,12 +41,12 @@ SectionEnd
|
||||
Section "Start Menu Shortcuts"
|
||||
CreateDirectory "$SMPROGRAMS\Pamhyr2"
|
||||
CreateShortcut "$SMPROGRAMS\Pamhyr2\Uninstall.lnk" "$INSTDIR\uninstall.exe"
|
||||
CreateShortcut "$SMPROGRAMS\Pamhyr2\Pamhyr2.lnk" "$INSTDIR\pamhyr\pamhyr.exe"
|
||||
CreateShortcut "$SMPROGRAMS\Pamhyr2\Pamhyr2.lnk" "$INSTDIR\pamhyr.exe"
|
||||
SectionEnd
|
||||
|
||||
Section "Desktop Shortcuts"
|
||||
SetShellVarContext all
|
||||
CreateShortcut "$desktop\Pamhyr2.lnk" "$instdir\pamhyr\pamhyr.exe"
|
||||
CreateShortcut "$desktop\Pamhyr2.lnk" "$instdir\pamhyr.exe"
|
||||
SectionEnd
|
||||
|
||||
Section "Uninstall"
|
||||
|
||||
@@ -10,3 +10,4 @@ colorama>=0.4.3
|
||||
pyinstaller>=5.11.0
|
||||
shapely>=2.0.1
|
||||
lxml>=4.9.3
|
||||
platformdirs>=4.2.0
|
||||
+31
-1
@@ -16,23 +16,53 @@
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
|
||||
from enum import Enum
|
||||
|
||||
from Modules import Modules
|
||||
from Model.Except import NotImplementedMethodeError
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
class STATUS(Enum):
|
||||
UNKNOWN = -1
|
||||
OK = 0
|
||||
WARNING = 1
|
||||
ERROR = 2
|
||||
UNKNOWN = 999
|
||||
|
||||
def __eq__(self, y):
|
||||
return self.value == y.value
|
||||
|
||||
def __gt__(self, y):
|
||||
return self.value > y.value
|
||||
|
||||
def __or__(self, y):
|
||||
v = [self, y]
|
||||
r = self.OK
|
||||
|
||||
if self.UNKNOWN in v:
|
||||
r = self.UNKNOWN
|
||||
if self.ERROR in v:
|
||||
r = self.ERROR
|
||||
if self.WARNING in v:
|
||||
r = self.WARNING
|
||||
|
||||
logger.debug(f"CHECKER: STATUS: {self} | {y} = {r}")
|
||||
return r
|
||||
|
||||
|
||||
class AbstractModelChecker(object):
|
||||
def __init__(self):
|
||||
self._name = ""
|
||||
self._description = ""
|
||||
self._solver = "study"
|
||||
self._modules = Modules.NONE
|
||||
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
self._status = STATUS.UNKNOWN
|
||||
self._summary = "Unknown"
|
||||
|
||||
|
||||
+9
-2
@@ -23,6 +23,8 @@ from tools import flatten, timer
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from Modules import Modules
|
||||
|
||||
from Checker.Checker import AbstractModelChecker, STATUS
|
||||
from Checker.Study import StudyGeometryChecker
|
||||
|
||||
@@ -30,7 +32,7 @@ _translate = QCoreApplication.translate
|
||||
|
||||
|
||||
class MageNetworkGraphChecker(AbstractModelChecker):
|
||||
def __init__(self, connectivity=True):
|
||||
def __init__(self, connectivity=True, version="mage8"):
|
||||
super(MageNetworkGraphChecker, self).__init__()
|
||||
|
||||
self._mode_conn = connectivity
|
||||
@@ -44,6 +46,8 @@ class MageNetworkGraphChecker(AbstractModelChecker):
|
||||
"Checker", f"Mage network graph {mode} checker")
|
||||
self._description = _translate(
|
||||
"Checker", "Check if the network graph is valid")
|
||||
self._solver = version
|
||||
self._modules = Modules.NETWORK
|
||||
|
||||
@timer
|
||||
def _connectivity(self, summary, status, graph):
|
||||
@@ -199,7 +203,7 @@ class MageNetworkGraphChecker(AbstractModelChecker):
|
||||
|
||||
|
||||
class MageGeometryGuideLineChecker(StudyGeometryChecker):
|
||||
def __init__(self):
|
||||
def __init__(self, version="mage8"):
|
||||
super(MageGeometryGuideLineChecker, self).__init__()
|
||||
|
||||
self._name = _translate("Checker", "Mage geometry guide line checker")
|
||||
@@ -208,6 +212,9 @@ class MageGeometryGuideLineChecker(StudyGeometryChecker):
|
||||
"Check if exists geometry guide line is correctly defined \
|
||||
for each reaches of the study"
|
||||
)
|
||||
self._solver = version
|
||||
self._modules = Modules.GEOMETRY
|
||||
|
||||
self._reachs = []
|
||||
|
||||
def run(self, study):
|
||||
|
||||
@@ -20,6 +20,7 @@ import time
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from Modules import Modules
|
||||
from Checker.Checker import AbstractModelChecker, STATUS
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
@@ -31,7 +32,9 @@ class StudyNetworkReachChecker(AbstractModelChecker):
|
||||
|
||||
self._name = _translate("Checker", "Study network reach checker")
|
||||
self._description = _translate(
|
||||
"Checker", "Check if exists at least one reach for study")
|
||||
"Checker", "Check if exists at least one reach for study"
|
||||
)
|
||||
self._modules = Modules.NETWORK
|
||||
|
||||
def run(self, study):
|
||||
if study is None:
|
||||
@@ -62,7 +65,10 @@ class StudyGeometryChecker(AbstractModelChecker):
|
||||
|
||||
self._name = _translate("Checker", "Study geometry checker")
|
||||
self._description = _translate(
|
||||
"Checker", "Check if exists geometry for each reach of study")
|
||||
"Checker", "Check if exists geometry for each reach of study"
|
||||
)
|
||||
self._modules = Modules.GEOMETRY
|
||||
|
||||
self._reachs = []
|
||||
|
||||
def run(self, study):
|
||||
|
||||
+22
-9
@@ -30,7 +30,7 @@ from ctypes import (
|
||||
)
|
||||
from PyQt5.QtCore import QProcess
|
||||
|
||||
from tools import logger_color_red, logger_color_reset
|
||||
from tools import logger_color_red, logger_color_reset, logger_exception
|
||||
from Meshing.AMeshingTool import AMeshingTool
|
||||
|
||||
logger = logging.getLogger()
|
||||
@@ -278,7 +278,7 @@ class MeshingWithMageMailleurTT(AMeshingTool):
|
||||
return os.path.abspath(
|
||||
os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"..", "..", "..", "mage", f"mailleurTT{ext}"
|
||||
"..", "..", "mage8", f"mailleurTT{ext}"
|
||||
)
|
||||
)
|
||||
|
||||
@@ -305,6 +305,8 @@ class MeshingWithMageMailleurTT(AMeshingTool):
|
||||
st_file = self.export_reach_to_st(reach, tmp)
|
||||
m_file = st_file.rsplit(".ST", 1)[0] + ".M"
|
||||
|
||||
os.sync()
|
||||
|
||||
proc = QProcess()
|
||||
proc.setWorkingDirectory(tmp)
|
||||
|
||||
@@ -312,7 +314,7 @@ class MeshingWithMageMailleurTT(AMeshingTool):
|
||||
linear = 1 if linear else 0
|
||||
|
||||
logger.info(
|
||||
f"! mailleurTT {st_file} {m_file} " +
|
||||
f"! {self._exe_path()} {st_file} {m_file} " +
|
||||
f"{str(step)} " +
|
||||
f"{limites[0]} {limites[1]} " +
|
||||
f"{directrices[0]} {directrices[1]} " +
|
||||
@@ -332,13 +334,22 @@ class MeshingWithMageMailleurTT(AMeshingTool):
|
||||
)
|
||||
proc.waitForFinished()
|
||||
|
||||
errors = proc.readAllStandardError()
|
||||
if len(errors) != 0:
|
||||
if proc.exitCode() != 0:
|
||||
logger.error(
|
||||
f"{logger_color_red()}" +
|
||||
f"MailleurTT error: {proc.exitCode()}" +
|
||||
f"{logger_color_reset()}"
|
||||
)
|
||||
outputs = proc.readAllStandardOutput()
|
||||
logger.debug(outputs)
|
||||
|
||||
errors = proc.readAllStandardError()
|
||||
logger.error(
|
||||
f"{logger_color_red()}{errors}{logger_color_reset()}"
|
||||
)
|
||||
else:
|
||||
self.import_m_file(reach, m_file)
|
||||
|
||||
return reach
|
||||
|
||||
def export_reach_to_st(self, reach, tmp):
|
||||
@@ -350,7 +361,9 @@ class MeshingWithMageMailleurTT(AMeshingTool):
|
||||
return tmp_st
|
||||
|
||||
def import_m_file(self, reach, m):
|
||||
reach.purge()
|
||||
|
||||
logger.debug(f"meshing: Import geometry from {m}")
|
||||
reach.import_geometry(m)
|
||||
if os.path.exists(m):
|
||||
reach.purge()
|
||||
logger.debug(f"meshing: Import geometry from {m}")
|
||||
reach.import_geometry(m)
|
||||
else:
|
||||
logger.error(f"meshing: Meshed geometry file {m} do not exists")
|
||||
@@ -25,9 +25,10 @@ from Model.Saved import SavedStatus
|
||||
from Model.Study import Study
|
||||
from Model.River import River
|
||||
|
||||
from Meshing.Mage import MeshingWithMage
|
||||
from Meshing.Mage import MeshingWithMage, MeshingWithMageMailleurTT
|
||||
|
||||
mage_mesher = os.path.exists(MeshingWithMage._lib_path())
|
||||
mage_mesher_TT = os.path.exists(MeshingWithMageMailleurTT._exe_path())
|
||||
|
||||
|
||||
class MeshingTestCase(unittest.TestCase):
|
||||
@@ -35,3 +36,8 @@ class MeshingTestCase(unittest.TestCase):
|
||||
def test_create_meshingtool_mage(self):
|
||||
mesher = MeshingWithMage()
|
||||
self.assertNotEqual(mesher, None)
|
||||
|
||||
@unittest.skipIf(not mage_mesher_TT, "mailleurTT is not available")
|
||||
def test_create_meshingtool_mageTT(self):
|
||||
mesher = MeshingWithMageMailleurTT()
|
||||
self.assertNotEqual(mesher, None)
|
||||
@@ -0,0 +1,178 @@
|
||||
# AddFile.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 AddFile(SQLSubModel):
|
||||
_sub_classes = []
|
||||
_id_cnt = 0
|
||||
|
||||
def __init__(self, id: int = -1, enabled=True,
|
||||
name="", path="", text="",
|
||||
status=None):
|
||||
super(AddFile, self).__init__()
|
||||
|
||||
if id == -1:
|
||||
self.id = AddFile._id_cnt
|
||||
else:
|
||||
self.id = id
|
||||
|
||||
self._status = status
|
||||
|
||||
self._enabled = enabled
|
||||
self._name = f"File {self.id}" if name == "" else name
|
||||
self._path = path
|
||||
self._text = text
|
||||
|
||||
AddFile._id_cnt = max(id, AddFile._id_cnt+1)
|
||||
|
||||
def __getitem__(self, key):
|
||||
value = None
|
||||
|
||||
if key == "enabled":
|
||||
value = self._enabled
|
||||
elif key == "name":
|
||||
value = self._name
|
||||
elif key == "path":
|
||||
value = self._path
|
||||
elif key == "text":
|
||||
value = self._text
|
||||
|
||||
return value
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
if key == "enabled":
|
||||
self._enabled = value
|
||||
elif key == "name":
|
||||
self._name = value
|
||||
elif key == "path":
|
||||
self._path = value
|
||||
elif key == "text":
|
||||
self._text = value
|
||||
|
||||
self._status.modified()
|
||||
|
||||
@property
|
||||
def enabled(self):
|
||||
return self._enabled
|
||||
|
||||
@enabled.setter
|
||||
def enabled(self, enabled):
|
||||
self._enabled = enabled
|
||||
self._status.modified()
|
||||
|
||||
def is_enabled(self):
|
||||
return self._enabled
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
self._name = name
|
||||
self._status.modified()
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
return self._path
|
||||
|
||||
@path.setter
|
||||
def path(self, path):
|
||||
self._path = path
|
||||
self._status.modified()
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
return self._text
|
||||
|
||||
@text.setter
|
||||
def text(self, text):
|
||||
self._text = text
|
||||
self._status.modified()
|
||||
|
||||
@classmethod
|
||||
def _db_create(cls, execute):
|
||||
execute("""
|
||||
CREATE TABLE additional_files(
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
enabled BOOLEAN NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
path TEXT NOT NULL,
|
||||
text 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) < 8:
|
||||
cls._db_create(execute)
|
||||
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _db_load(cls, execute, data=None):
|
||||
new = []
|
||||
|
||||
table = execute(
|
||||
"SELECT id, enabled, name, path, text " +
|
||||
"FROM additional_files"
|
||||
)
|
||||
|
||||
for row in table:
|
||||
it = iter(row)
|
||||
|
||||
id = next(it)
|
||||
enabled = (next(it) == 1)
|
||||
name = next(it)
|
||||
path = next(it)
|
||||
text = next(it)
|
||||
|
||||
f = cls(
|
||||
id=id, enabled=enabled, name=name, path=path, text=text,
|
||||
status=data['status']
|
||||
)
|
||||
|
||||
new.append(f)
|
||||
|
||||
return new
|
||||
|
||||
def _db_save(self, execute, data=None):
|
||||
sql = (
|
||||
"INSERT INTO " +
|
||||
"additional_files(id, enabled, name, path, text) " +
|
||||
"VALUES (" +
|
||||
f"{self.id}, {self._enabled}, " +
|
||||
f"'{self._db_format(self._name)}', " +
|
||||
f"'{self._db_format(self._path)}', " +
|
||||
f"'{self._db_format(self._text)}'" +
|
||||
")"
|
||||
)
|
||||
execute(sql)
|
||||
|
||||
return True
|
||||
@@ -0,0 +1,56 @@
|
||||
# AddFileList.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.AdditionalFile.AddFile import AddFile
|
||||
|
||||
|
||||
class AddFileList(PamhyrModelList):
|
||||
_sub_classes = [AddFile]
|
||||
|
||||
@classmethod
|
||||
def _db_load(cls, execute, data=None):
|
||||
new = cls(status=data["status"])
|
||||
|
||||
new._lst = AddFile._db_load(execute, data)
|
||||
|
||||
return new
|
||||
|
||||
def _db_save(self, execute, data=None):
|
||||
ok = True
|
||||
|
||||
# Delete previous data
|
||||
execute("DELETE FROM additional_files")
|
||||
|
||||
for af in self._lst:
|
||||
ok &= af._db_save(execute, data)
|
||||
|
||||
return ok
|
||||
|
||||
@property
|
||||
def files(self):
|
||||
return self.lst
|
||||
|
||||
def new(self, index):
|
||||
n = AddFile(status=self._status)
|
||||
self.insert(index, n)
|
||||
self._status.modified()
|
||||
return n
|
||||
@@ -18,7 +18,12 @@
|
||||
|
||||
import logging
|
||||
|
||||
from tools import trace, timer, old_pamhyr_date_to_timestamp
|
||||
from tools import (
|
||||
trace, timer,
|
||||
old_pamhyr_date_to_timestamp,
|
||||
date_iso_to_timestamp,
|
||||
date_dmy_to_timestamp,
|
||||
)
|
||||
|
||||
from Model.Tools.PamhyrDB import SQLSubModel
|
||||
from Model.Except import NotImplementedMethodeError
|
||||
@@ -189,6 +194,10 @@ class BoundaryCondition(SQLSubModel):
|
||||
@classmethod
|
||||
def time_convert(cls, data):
|
||||
if type(data) is str:
|
||||
if data.count("-") == 2:
|
||||
return date_iso_to_timestamp(data)
|
||||
if data.count("/") == 2:
|
||||
return date_dmy_to_timestamp(data)
|
||||
if data.count(":") == 3:
|
||||
return old_pamhyr_date_to_timestamp(data)
|
||||
if data.count(":") == 2:
|
||||
|
||||
@@ -47,7 +47,7 @@ class PointXYZ(Point, SQLSubModel):
|
||||
z INTEGER NOT NULL,
|
||||
profile INTEGER NOT NULL,
|
||||
sl INTEGER,
|
||||
FOREIGN KEY(profile) REFERENCES profileXYZ(id),
|
||||
FOREIGN KEY(profile) REFERENCES geometry_profileXYZ(id),
|
||||
FOREIGN KEY(sl) REFERENCES sedimentary_layer(id)
|
||||
)
|
||||
""")
|
||||
|
||||
@@ -65,7 +65,7 @@ class Reach(SQLSubModel):
|
||||
|
||||
new._profiles = ProfileXYZ._db_load(
|
||||
execute,
|
||||
data=data
|
||||
data=data.copy()
|
||||
)
|
||||
|
||||
return new
|
||||
@@ -111,7 +111,7 @@ class Reach(SQLSubModel):
|
||||
def _get_profiles_list(self):
|
||||
# Profiles list generator is type (int, Point) with the first
|
||||
# element the index of the Point in list
|
||||
logger.info(f"Load profiles from reach {self.name}")
|
||||
logger.debug(f"Load profiles from reach {self.name}")
|
||||
return list(
|
||||
map(
|
||||
lambda p: p[1],
|
||||
@@ -743,7 +743,10 @@ class Reach(SQLSubModel):
|
||||
incline_acc.sort()
|
||||
|
||||
marge = round(len(incline_acc) * 0.1)
|
||||
incline_set = incline_acc[marge:-marge]
|
||||
if marge > 0:
|
||||
incline_set = incline_acc[marge:-marge]
|
||||
else:
|
||||
incline_set = incline_acc
|
||||
|
||||
logger.debug(f"+{incline_acc}")
|
||||
logger.debug(f"-{incline_set}")
|
||||
|
||||
@@ -430,7 +430,7 @@ class InitialConditions(SQLSubModel):
|
||||
logger.debug(f"({profile.kp}):")
|
||||
logger.debug(f" width = {width}")
|
||||
logger.debug(f" strickler = {strickler}")
|
||||
logger.debug(f" hieght = {height}")
|
||||
logger.debug(f" height = {height}")
|
||||
|
||||
new = Data(reach=self._reach, status=self._status)
|
||||
new["kp"] = profile.kp
|
||||
|
||||
@@ -18,7 +18,12 @@
|
||||
|
||||
import logging
|
||||
|
||||
from tools import trace, timer, old_pamhyr_date_to_timestamp
|
||||
from tools import (
|
||||
trace, timer,
|
||||
old_pamhyr_date_to_timestamp,
|
||||
date_iso_to_timestamp,
|
||||
date_dmy_to_timestamp,
|
||||
)
|
||||
|
||||
from Model.Tools.PamhyrDB import SQLSubModel
|
||||
from Model.Except import NotImplementedMethodeError
|
||||
@@ -189,6 +194,10 @@ class LateralContribution(SQLSubModel):
|
||||
@classmethod
|
||||
def time_convert(cls, data):
|
||||
if type(data) is str:
|
||||
if data.count("-") == 2:
|
||||
return date_iso_to_timestamp(data)
|
||||
if data.count("/") == 2:
|
||||
return date_dmy_to_timestamp(data)
|
||||
if data.count(":") == 3:
|
||||
return old_pamhyr_date_to_timestamp(data)
|
||||
if data.count(":") == 2:
|
||||
|
||||
@@ -67,6 +67,13 @@ class Graph(object):
|
||||
def edges_counts(self):
|
||||
return len(self._edges)
|
||||
|
||||
def enable_nodes_counts(self):
|
||||
return reduce(
|
||||
lambda acc, n: acc + 1 if self.is_enable_node(n) else acc,
|
||||
self._nodes,
|
||||
0
|
||||
)
|
||||
|
||||
def enable_edges_counts(self):
|
||||
return reduce(
|
||||
lambda acc, e: acc + 1 if e.is_enable() else acc,
|
||||
@@ -213,6 +220,12 @@ class Graph(object):
|
||||
True
|
||||
)
|
||||
|
||||
def is_internal_node(self, node):
|
||||
return not (
|
||||
self.is_upstream_node(node) or
|
||||
self.is_downstream_node(node)
|
||||
)
|
||||
|
||||
def is_enable_node(self, node):
|
||||
return reduce(
|
||||
lambda acc, e: (
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
# 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)
|
||||
|
||||
def __getitem__(self, key):
|
||||
value = None
|
||||
|
||||
if key == "enabled":
|
||||
value = self._enabled
|
||||
elif key == "name":
|
||||
value = self._name
|
||||
elif key == "line":
|
||||
value = self._line
|
||||
elif key == "solvers":
|
||||
value = self._solvers
|
||||
|
||||
return value
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
if key == "enabled":
|
||||
self._enabled = value
|
||||
elif key == "name":
|
||||
self._name = value
|
||||
elif key == "line":
|
||||
self._line = value
|
||||
elif key == "solvers":
|
||||
self._solvers = value
|
||||
|
||||
self._status.modified()
|
||||
|
||||
@property
|
||||
def enabled(self):
|
||||
return self._enabled
|
||||
|
||||
@enabled.setter
|
||||
def enabled(self, enabled):
|
||||
self._enabled = enabled
|
||||
self._status.modified()
|
||||
|
||||
def is_enabled(self):
|
||||
return self._enabled
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
self._name = name
|
||||
self._status.modified()
|
||||
|
||||
@property
|
||||
def line(self):
|
||||
return self._line
|
||||
|
||||
@line.setter
|
||||
def line(self, line):
|
||||
self._line = line
|
||||
self._status.modified()
|
||||
|
||||
@property
|
||||
def solvers(self):
|
||||
return self._solvers
|
||||
|
||||
@solvers.setter
|
||||
def solvers(self, solvers):
|
||||
self._solvers = solvers
|
||||
self._status.modified()
|
||||
|
||||
@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
|
||||
@@ -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
|
||||
+48
-20
@@ -40,6 +40,8 @@ from Model.Reservoir.ReservoirList import ReservoirList
|
||||
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
|
||||
|
||||
@@ -224,6 +226,8 @@ class River(Graph, SQLSubModel):
|
||||
SedimentLayerList,
|
||||
ReservoirList,
|
||||
HydraulicStructureList,
|
||||
AddFileList,
|
||||
REPLineList,
|
||||
]
|
||||
|
||||
def __init__(self, status=None):
|
||||
@@ -245,6 +249,8 @@ class River(Graph, SQLSubModel):
|
||||
self._hydraulic_structures = HydraulicStructureList(
|
||||
status=self._status
|
||||
)
|
||||
self._additional_files = AddFileList(status=self._status)
|
||||
self._rep_lines = REPLineList(status=self._status)
|
||||
|
||||
@classmethod
|
||||
def _db_create(cls, execute):
|
||||
@@ -263,66 +269,62 @@ class River(Graph, SQLSubModel):
|
||||
# Stricklers (Stricklers is load in first because it's needed
|
||||
# for reachs)
|
||||
new._stricklers = StricklersList._db_load(
|
||||
execute,
|
||||
data
|
||||
execute, data
|
||||
)
|
||||
data["stricklers"] = new._stricklers
|
||||
|
||||
# Initial conditions
|
||||
new._sediment_layers = SedimentLayerList._db_load(
|
||||
execute,
|
||||
data
|
||||
execute, data
|
||||
)
|
||||
data["sediment_layers_list"] = new._sediment_layers
|
||||
|
||||
# Network
|
||||
new._nodes = RiverNode._db_load(
|
||||
execute,
|
||||
data
|
||||
execute, data
|
||||
)
|
||||
data["nodes"] = new.nodes()
|
||||
|
||||
new._edges = RiverReach._db_load(
|
||||
execute,
|
||||
data
|
||||
execute, data
|
||||
)
|
||||
data["edges"] = new.edges()
|
||||
|
||||
# Boundary Condition
|
||||
new._boundary_condition = BoundaryConditionList._db_load(
|
||||
execute,
|
||||
data
|
||||
execute, data
|
||||
)
|
||||
# Lateral Contribution
|
||||
new._lateral_contribution = LateralContributionList._db_load(
|
||||
execute,
|
||||
data
|
||||
execute, data
|
||||
)
|
||||
|
||||
# Initial conditions
|
||||
new._initial_conditions = InitialConditionsDict._db_load(
|
||||
execute,
|
||||
data
|
||||
execute, data
|
||||
)
|
||||
|
||||
# Reservoir
|
||||
new._reservoir = ReservoirList._db_load(
|
||||
execute,
|
||||
data
|
||||
execute, data
|
||||
)
|
||||
|
||||
# Hydraulic Structures
|
||||
new._hydraulic_structures = HydraulicStructureList._db_load(
|
||||
execute,
|
||||
data
|
||||
execute, data
|
||||
)
|
||||
|
||||
# Parameters
|
||||
new._parameters = SolverParametersList._db_load(
|
||||
execute,
|
||||
data
|
||||
execute, data
|
||||
)
|
||||
|
||||
# Additional Files
|
||||
new._additional_files = AddFileList._db_load(
|
||||
execute, data
|
||||
)
|
||||
new._rep_lines = REPLineList._db_load(execute, data)
|
||||
|
||||
return new
|
||||
|
||||
def _db_save(self, execute, data=None):
|
||||
@@ -336,6 +338,8 @@ class River(Graph, SQLSubModel):
|
||||
objs.append(self._stricklers)
|
||||
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])
|
||||
@@ -373,11 +377,27 @@ class River(Graph, SQLSubModel):
|
||||
logger_exception(e)
|
||||
|
||||
def init_default(self):
|
||||
self.init_default_network()
|
||||
self.init_default_additional_files()
|
||||
|
||||
def init_default_network(self):
|
||||
n1 = self.add_node(880.0, 950.0)
|
||||
n2 = self.add_node(1120.0, 1020.0)
|
||||
|
||||
e = self.add_edge(n1, n2)
|
||||
|
||||
def init_default_additional_files(self):
|
||||
add_file = self._additional_files.new(0)
|
||||
add_file.name = "Pamhyr2 stamp file"
|
||||
add_file.path = "Pamhyr2.txt"
|
||||
add_file.text = """This repository has been generated by Pamhyr2 \
|
||||
version "@version" !
|
||||
|
||||
All hand made file modification could be erased by the next solver
|
||||
execution...
|
||||
|
||||
Last export at: @date."""
|
||||
|
||||
@property
|
||||
def boundary_condition(self):
|
||||
return self._boundary_condition
|
||||
@@ -419,6 +439,14 @@ class River(Graph, SQLSubModel):
|
||||
def hydraulic_structures(self):
|
||||
return self._hydraulic_structures
|
||||
|
||||
@property
|
||||
def additional_files(self):
|
||||
return self._additional_files
|
||||
|
||||
@property
|
||||
def rep_lines(self):
|
||||
return self._rep_lines
|
||||
|
||||
@property
|
||||
def parameters(self):
|
||||
return self._parameters
|
||||
|
||||
+25
-5
@@ -41,7 +41,7 @@ class Study(SQLModel):
|
||||
|
||||
def __init__(self, filename=None, init_new=True):
|
||||
# Metadata
|
||||
self._version = "0.0.7"
|
||||
self._version = "0.0.9"
|
||||
self.creation_date = datetime.now()
|
||||
self.last_modification_date = datetime.now()
|
||||
self.last_save_date = datetime.now()
|
||||
@@ -103,10 +103,20 @@ class Study(SQLModel):
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
is_new = False
|
||||
fname = fname + "." + str(self._old_save_id)
|
||||
filename = os.path.join(fdir, "_PAMHYR_", "__old__", fname)
|
||||
shutil.copy(self.filename, filename)
|
||||
self._old_save_id += 1
|
||||
if os.path.exists(self.filename) and ".backup" not in self.filename:
|
||||
filename = os.path.join(fdir, "_PAMHYR_", "__old__", fname)
|
||||
logger.debug(f"Backup previous version copy: {filename}")
|
||||
shutil.copy(self.filename, filename)
|
||||
self._old_save_id += 1
|
||||
is_new = True
|
||||
|
||||
if ".backup" in self.filename:
|
||||
is_new = True
|
||||
|
||||
self._init_db_file(self.filename, is_new=is_new)
|
||||
self.commit()
|
||||
|
||||
# Save
|
||||
self.last_save_date = datetime.now()
|
||||
@@ -128,6 +138,16 @@ class Study(SQLModel):
|
||||
|
||||
@filename.setter
|
||||
def filename(self, filename):
|
||||
if filename is None:
|
||||
self._filename = None
|
||||
self.status.modified()
|
||||
return
|
||||
|
||||
if self._filename is not None and self._filename != "":
|
||||
self._filename = str(filename)
|
||||
self.status.modified()
|
||||
return
|
||||
|
||||
self._filename = str(filename)
|
||||
self._init_db_file(filename, is_new=True)
|
||||
self.status.modified()
|
||||
@@ -221,7 +241,7 @@ class Study(SQLModel):
|
||||
if version[0] == self._version:
|
||||
return True
|
||||
|
||||
logger.info("Update database")
|
||||
logger.debug("Update database")
|
||||
|
||||
if self._update_submodel(version[0]):
|
||||
self.execute(
|
||||
|
||||
@@ -35,8 +35,10 @@ class SQLModel(SQL):
|
||||
_sub_classes = []
|
||||
|
||||
def _init_db_file(self, db, is_new=True):
|
||||
exists = Path(db).exists()
|
||||
if self._db is not None:
|
||||
self._db.close()
|
||||
|
||||
exists = Path(db).exists()
|
||||
if exists and is_new:
|
||||
os.remove(db)
|
||||
|
||||
@@ -68,6 +70,7 @@ class SQLModel(SQL):
|
||||
return True
|
||||
|
||||
def _create(self):
|
||||
|
||||
raise NotImplementedMethodeError(self, self._create)
|
||||
|
||||
def _update_submodel(self, version):
|
||||
|
||||
@@ -56,7 +56,7 @@ class PamhyrModelDict(SQLSubModel):
|
||||
def __len__(self):
|
||||
return len(self._dict)
|
||||
|
||||
def is_defined(self, key):
|
||||
def __contains__(self, key):
|
||||
return key in self._dict
|
||||
|
||||
def set(self, key, new):
|
||||
|
||||
@@ -62,16 +62,27 @@ class PamhyrModelList(SQLSubModel):
|
||||
|
||||
@property
|
||||
def lst(self):
|
||||
"""Return the PamhyrList as a Python list
|
||||
|
||||
Return the PamhyrList as a Python list. This list is the
|
||||
current list used in the PamhyrList object. **If you need to
|
||||
modify it, please make a copy.**
|
||||
|
||||
Returns: The Python list
|
||||
"""
|
||||
return self._lst
|
||||
|
||||
def __len__(self):
|
||||
return len(self.lst)
|
||||
|
||||
def get(self, row):
|
||||
return self._lst[row]
|
||||
def index(self, el):
|
||||
return self._lst.index(el)
|
||||
|
||||
def set(self, row, new):
|
||||
self._lst[row] = new
|
||||
def get(self, index):
|
||||
return self._lst[index]
|
||||
|
||||
def set(self, index, new):
|
||||
self._lst[index] = new
|
||||
if self._status is not None:
|
||||
self._status.modified()
|
||||
|
||||
@@ -93,6 +104,14 @@ class PamhyrModelList(SQLSubModel):
|
||||
self._status.modified()
|
||||
|
||||
def delete(self, lst):
|
||||
"""Delete a list of elements
|
||||
|
||||
Args:
|
||||
lst: The list of elements
|
||||
|
||||
Returns:
|
||||
Nothing
|
||||
"""
|
||||
for el in lst:
|
||||
self._lst.remove(el)
|
||||
|
||||
@@ -100,6 +119,14 @@ class PamhyrModelList(SQLSubModel):
|
||||
self._status.modified()
|
||||
|
||||
def delete_i(self, indexes):
|
||||
"""Delete elements from list of indexes
|
||||
|
||||
Args:
|
||||
indexes: The elements indexes
|
||||
|
||||
Returns:
|
||||
Nothing
|
||||
"""
|
||||
lst = list(
|
||||
map(
|
||||
lambda x: x[1],
|
||||
@@ -175,16 +202,32 @@ class PamhyrModelListWithTab(SQLSubModel):
|
||||
################
|
||||
|
||||
def len(self, lst):
|
||||
"""Size of tab list
|
||||
|
||||
Args:
|
||||
lst: The tab name
|
||||
|
||||
Returns:
|
||||
The size of the tab list
|
||||
"""
|
||||
return len(self._tabs[lst])
|
||||
|
||||
def get_tab(self, lst):
|
||||
"""Get tab list (copy) from name
|
||||
|
||||
Args:
|
||||
lst: The tab name
|
||||
|
||||
Returns:
|
||||
Nothing
|
||||
"""
|
||||
return self._tabs[lst].copy()
|
||||
|
||||
def get(self, lst, row):
|
||||
return self._tabs[lst][row]
|
||||
def get(self, lst, index):
|
||||
return self._tabs[lst][index]
|
||||
|
||||
def set(self, lst, row, new):
|
||||
self._tabs[lst][row] = new
|
||||
def set(self, lst, index, new):
|
||||
self._tabs[lst][index] = new
|
||||
self._status.modified()
|
||||
|
||||
def new(self, lst, index):
|
||||
@@ -200,15 +243,43 @@ class PamhyrModelListWithTab(SQLSubModel):
|
||||
raise NotImplementedMethodeError(self, self.new)
|
||||
|
||||
def insert(self, lst, index, new):
|
||||
"""Insert element in tab
|
||||
|
||||
Args:
|
||||
lst: The tab name
|
||||
index: The index of new element
|
||||
new: The new elements
|
||||
|
||||
Returns:
|
||||
Nothing
|
||||
"""
|
||||
self._tabs[lst].insert(index, new)
|
||||
self._status.modified()
|
||||
|
||||
def delete(self, lst, els):
|
||||
"""Delete elements from specific tab
|
||||
|
||||
Args:
|
||||
lst: The tab name
|
||||
els: The elements list
|
||||
|
||||
Returns:
|
||||
Nothing
|
||||
"""
|
||||
for el in els:
|
||||
self._tabs[lst].remove(el)
|
||||
self._status.modified()
|
||||
|
||||
def delete_i(self, lst, indexes):
|
||||
"""Delete elements from specific tab
|
||||
|
||||
Args:
|
||||
lst: The tab name
|
||||
indexes: The elements indexes
|
||||
|
||||
Returns:
|
||||
Nothing
|
||||
"""
|
||||
els = list(
|
||||
map(
|
||||
lambda x: x[1],
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
# Modules.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 enum import Flag, auto
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
class Modules(Flag):
|
||||
NONE = 0
|
||||
|
||||
# General
|
||||
STUDY = auto()
|
||||
CONFIG = auto()
|
||||
|
||||
# Modelling
|
||||
NETWORK = auto()
|
||||
GEOMETRY = auto()
|
||||
BOUNDARY_CONDITION = auto()
|
||||
LATERAL_CONTRIBUTION = auto()
|
||||
FRICTION = auto()
|
||||
INITIAL_CONDITION = auto()
|
||||
HYDRAULIC_STRUCTURES = auto()
|
||||
RESERVOIR = auto()
|
||||
SEDIMENT_LAYER = auto()
|
||||
ADDITIONAL_FILES = auto()
|
||||
|
||||
# Results
|
||||
RESULTS = auto()
|
||||
|
||||
# Display
|
||||
WINDOW_LIST = auto()
|
||||
|
||||
@classmethod
|
||||
def all(cls):
|
||||
return ~cls.NONE
|
||||
|
||||
@classmethod
|
||||
def modelling(cls):
|
||||
return (
|
||||
cls.NETWORK
|
||||
| cls.GEOMETRY
|
||||
| cls.BOUNDARY_CONDITION
|
||||
| cls.LATERAL_CONTRIBUTION
|
||||
| cls.FRICTION
|
||||
| cls.INITIAL_CONDITION
|
||||
| cls.HYDRAULIC_STRUCTURES
|
||||
| cls.RESERVOIR
|
||||
| cls.SEDIMENT_LAYER
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def modelling_list(cls):
|
||||
return [
|
||||
cls.NETWORK,
|
||||
cls.GEOMETRY,
|
||||
cls.BOUNDARY_CONDITION,
|
||||
cls.LATERAL_CONTRIBUTION,
|
||||
cls.FRICTION,
|
||||
cls.INITIAL_CONDITION,
|
||||
cls.HYDRAULIC_STRUCTURES,
|
||||
cls.RESERVOIR,
|
||||
cls.SEDIMENT_LAYER,
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def modelling_display_name(cls):
|
||||
return {
|
||||
cls.NETWORK: "Network",
|
||||
cls.GEOMETRY: "Geometry",
|
||||
cls.BOUNDARY_CONDITION: "Boundary condition",
|
||||
cls.LATERAL_CONTRIBUTION: "Lateral contribution",
|
||||
cls.FRICTION: "Friction",
|
||||
cls.INITIAL_CONDITION: "Initial condition",
|
||||
cls.HYDRAULIC_STRUCTURES: "Hydraulic structures",
|
||||
cls.RESERVOIR: "Reservoir",
|
||||
cls.SEDIMENT_LAYER: "Sediment layer",
|
||||
}
|
||||
@@ -19,7 +19,8 @@
|
||||
import os
|
||||
import logging
|
||||
|
||||
from tools import timer, parse_command_line
|
||||
from datetime import datetime
|
||||
from tools import timer, parse_command_line, get_version, logger_exception
|
||||
|
||||
try:
|
||||
# Installation allow Unix-like signal
|
||||
@@ -124,6 +125,54 @@ class CommandLineSolver(AbstractSolver):
|
||||
"""
|
||||
raise NotImplementedMethodeError(self, self.log_file)
|
||||
|
||||
def export_additional_files(self, study, repertory, qlog, name="0"):
|
||||
files = []
|
||||
|
||||
if qlog is not None:
|
||||
qlog.put("Export additional files")
|
||||
|
||||
add_files = study.river.additional_files.files
|
||||
for add_file in add_files:
|
||||
self.export_additional_file(
|
||||
study, add_file, repertory, files
|
||||
)
|
||||
|
||||
return files
|
||||
|
||||
def export_additional_file(self, study, add_file, repertory, files):
|
||||
if add_file.path == "" or not add_file.is_enabled():
|
||||
return files
|
||||
|
||||
path = os.path.join(repertory, add_file.path)
|
||||
os.makedirs(
|
||||
os.path.dirname(path),
|
||||
exist_ok=True
|
||||
)
|
||||
|
||||
with open(path, "w+") as f:
|
||||
files.append(add_file.path)
|
||||
|
||||
txt = add_file.text
|
||||
txt = txt.replace("@version", get_version())
|
||||
txt = txt.replace("@date", datetime.now().isoformat(sep=" "))
|
||||
|
||||
f.write(txt)
|
||||
|
||||
return files
|
||||
|
||||
def export_study_description(self, study, repertory, qlog, name="0"):
|
||||
files = []
|
||||
|
||||
path = os.path.join(
|
||||
repertory, "pamhyr-study-description.txt"
|
||||
)
|
||||
|
||||
with open(path, "w+", encoding='utf-8') as f:
|
||||
txt = study.description\
|
||||
.encode()\
|
||||
.decode('utf-8', 'replace')
|
||||
f.write(txt)
|
||||
|
||||
#######
|
||||
# Run #
|
||||
#######
|
||||
@@ -132,7 +181,7 @@ class CommandLineSolver(AbstractSolver):
|
||||
return os.path.abspath(
|
||||
os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"..", "..", ".."
|
||||
"..", ".."
|
||||
)
|
||||
)
|
||||
|
||||
@@ -224,12 +273,15 @@ class CommandLineSolver(AbstractSolver):
|
||||
return True
|
||||
|
||||
def _data_ready(self):
|
||||
# Read process output and put lines in queue
|
||||
s = self._process.readAll().data().decode()
|
||||
try:
|
||||
# Read process output and put lines in queue
|
||||
s = self._process.readAll().data().decode('utf-8', "replace")
|
||||
|
||||
if self._output is not None:
|
||||
for x in s.split('\n'):
|
||||
self._output.put(x)
|
||||
if self._output is not None:
|
||||
for x in s.split(os.linesep):
|
||||
self._output.put(x)
|
||||
except Exception as e:
|
||||
logger_exception(e)
|
||||
|
||||
def _finished(self, study, exit_code, exit_status):
|
||||
if self._output is not None:
|
||||
|
||||
+136
-101
@@ -20,7 +20,7 @@ import os
|
||||
import logging
|
||||
import numpy as np
|
||||
|
||||
from tools import timer, trace
|
||||
from tools import timer, trace, logger_exception
|
||||
|
||||
from Solver.CommandLine import CommandLineSolver
|
||||
from Checker.Mage import (
|
||||
@@ -98,10 +98,9 @@ class Mage(CommandLineSolver):
|
||||
@classmethod
|
||||
def checkers(cls):
|
||||
lst = [
|
||||
MageNetworkGraphChecker(connectivity=True),
|
||||
MageNetworkGraphChecker(connectivity=False),
|
||||
MageGeometryGuideLineChecker(),
|
||||
|
||||
MageNetworkGraphChecker(connectivity=True, version=cls._type),
|
||||
MageNetworkGraphChecker(connectivity=False, version=cls._type),
|
||||
MageGeometryGuideLineChecker(version=cls._type),
|
||||
]
|
||||
|
||||
return lst
|
||||
@@ -129,7 +128,15 @@ class Mage(CommandLineSolver):
|
||||
name = self._study.name
|
||||
return f"{name}.TRA"
|
||||
|
||||
@timer
|
||||
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)
|
||||
|
||||
def _export_ST(self, study, repertory, qlog, name="0"):
|
||||
files = []
|
||||
|
||||
@@ -139,14 +146,7 @@ class Mage(CommandLineSolver):
|
||||
os.makedirs(os.path.join(repertory, "net"), exist_ok=True)
|
||||
|
||||
# Write header
|
||||
edges = study.river.edges()
|
||||
edges = list(
|
||||
filter(
|
||||
lambda e: e.is_enable(),
|
||||
edges
|
||||
)
|
||||
)
|
||||
|
||||
edges = study.river.enable_edges()
|
||||
for edge in edges:
|
||||
name = f"Reach_{edge.id + 1:>3}".replace(" ", "0")
|
||||
|
||||
@@ -235,7 +235,6 @@ class Mage(CommandLineSolver):
|
||||
# Point line
|
||||
wfile.write(f"{x} {y} {z} {n} {sediment}\n")
|
||||
|
||||
@timer
|
||||
def _export_BC(self, t, bounds, repertory, qlog, name="0"):
|
||||
files = []
|
||||
|
||||
@@ -269,7 +268,6 @@ class Mage(CommandLineSolver):
|
||||
|
||||
return files
|
||||
|
||||
@timer
|
||||
def _export_bound_cond(self, study, repertory, qlog, name="0"):
|
||||
files = []
|
||||
lst = study.river.boundary_condition
|
||||
@@ -284,6 +282,9 @@ class Mage(CommandLineSolver):
|
||||
if bound.node is None:
|
||||
continue
|
||||
|
||||
if not study.river.is_enable_node(bound.node):
|
||||
continue
|
||||
|
||||
if bound.bctype == "ZD":
|
||||
AVA.append(bound)
|
||||
elif bound.bctype == "TD" or bound.bctype == "PC":
|
||||
@@ -300,42 +301,55 @@ class Mage(CommandLineSolver):
|
||||
|
||||
return files
|
||||
|
||||
# @timer
|
||||
# def _export_LC(self, lateral, repertory, qlog, name="0"):
|
||||
# files = []
|
||||
def _export_lateral_contrib(self, study, repertory, qlog, name="0"):
|
||||
files = []
|
||||
lst = study.river.lateral_contribution
|
||||
|
||||
# if qlog is not None:
|
||||
# qlog.put(f"Export LAT file")
|
||||
with mage_file_open(
|
||||
os.path.join(repertory, f"{name}.LAT"),
|
||||
"w+"
|
||||
) as f:
|
||||
if qlog is not None:
|
||||
qlog.put(f"Export LAT file")
|
||||
files.append(f"{name}.LAT")
|
||||
|
||||
# with mage_file_open(
|
||||
# os.path.join(repertory, f"{name}.LAT"),
|
||||
# "w+"
|
||||
# ) as f:
|
||||
# files.append(f"{name}.LAT")
|
||||
for tab in ["liquid", "solid", "suspenssion"]:
|
||||
for lateral in lst.get_tab(tab):
|
||||
self._export_LC(study, lateral, f, qlog)
|
||||
|
||||
# name = f"{lateral.node.id:3}".replace(" ", "x")
|
||||
# f.write(f"* {lateral.node.name} ({name}) {lateral.bctype}\n")
|
||||
# f.write(f"${name}\n")
|
||||
# header = lateral.header
|
||||
# f.write(f"*{header[0]:>9}|{header[1]:>10}\n")
|
||||
return files
|
||||
|
||||
# for d in lateral.data:
|
||||
# f.write(f"{d[0]:1{name}.3f}{d[1]:10.3f}\n")
|
||||
def _export_LC(self, study, lateral, f, qlog, name="0"):
|
||||
if lateral.edge is None:
|
||||
return
|
||||
|
||||
# return files
|
||||
edges = study.river.enable_edges()
|
||||
if lateral.edge not in edges:
|
||||
return
|
||||
|
||||
# @timer
|
||||
# def _export_lateral_contrib(self, study, repertory, qlog, name="0"):
|
||||
# files = []
|
||||
# lst = study.river.lateral_contribution
|
||||
eid, _ = next(
|
||||
filter(
|
||||
lambda e: e[1] == lateral.edge,
|
||||
enumerate(edges)
|
||||
)
|
||||
)
|
||||
|
||||
# for tab in ["liquid", "solid", "suspenssion"]:
|
||||
# for lateral in lst.get_tab(tab):
|
||||
# files = files + self._export_LC(lateral, repertory, qlog)
|
||||
name = f"{eid+1:>3}"
|
||||
# name = f"Reach_{lateral.edge.id + 1:>3}".replace(" ", "0")
|
||||
f.write(f"* {lateral.edge.name} ({name}) {lateral.lctype}\n")
|
||||
f.write(
|
||||
f"${name} " +
|
||||
f"{lateral.begin_kp:>10.4f} {lateral.end_kp:>10.4f}\n"
|
||||
)
|
||||
header = lateral.header
|
||||
f.write(f"*{header[0]:>9}|{header[1]:>10}\n")
|
||||
|
||||
# return files
|
||||
for d in lateral.data:
|
||||
if lateral.lctype in ["EV"]:
|
||||
f.write(f"{d[0]:10.3f}{-d[1]:10.3f}\n")
|
||||
else:
|
||||
f.write(f"{d[0]:10.3f}{d[1]:10.3f}\n")
|
||||
|
||||
@timer
|
||||
def _export_RUG(self, study, repertory, qlog, name="0"):
|
||||
files = []
|
||||
|
||||
@@ -346,13 +360,7 @@ class Mage(CommandLineSolver):
|
||||
with mage_file_open(os.path.join(repertory, f"{name}.RUG"), "w+") as f:
|
||||
files.append(f"{name}.RUG")
|
||||
|
||||
edges = study.river.edges()
|
||||
edges = list(
|
||||
filter(
|
||||
lambda e: e.is_enable(),
|
||||
edges
|
||||
)
|
||||
)
|
||||
edges = study.river.enable_edges()
|
||||
|
||||
id = 1
|
||||
for edge in edges:
|
||||
@@ -379,7 +387,6 @@ class Mage(CommandLineSolver):
|
||||
|
||||
return files
|
||||
|
||||
@timer
|
||||
def _export_INI(self, study, repertory, qlog, name="0"):
|
||||
files = []
|
||||
|
||||
@@ -422,7 +429,6 @@ class Mage(CommandLineSolver):
|
||||
files.append(f"{name}.INI")
|
||||
return files
|
||||
|
||||
@timer
|
||||
def _export_CAS(self, study, repertory, qlog, name="0"):
|
||||
files = []
|
||||
|
||||
@@ -455,7 +461,6 @@ class Mage(CommandLineSolver):
|
||||
|
||||
return files
|
||||
|
||||
@timer
|
||||
def _export_SIN(self, study, repertory, qlog, name="0"):
|
||||
files = []
|
||||
|
||||
@@ -487,35 +492,41 @@ class Mage(CommandLineSolver):
|
||||
if not hs.input_reach.is_enable():
|
||||
continue
|
||||
|
||||
if hs.input_kp is None:
|
||||
continue
|
||||
|
||||
f.write(
|
||||
'* ouvrage au pk ' +
|
||||
f"{float(hs.input_kp):>12.1f}" + ' ' +
|
||||
hs.name + '\n'
|
||||
)
|
||||
|
||||
for bhs in hs.basic_structures:
|
||||
reach_id = study.river.get_edge_id(hs.input_reach) + 1
|
||||
param_str = ' '.join(
|
||||
[
|
||||
f'{p:>10.3f}'
|
||||
for p in self._export_SIN_parameters(bhs)
|
||||
]
|
||||
)
|
||||
|
||||
name = bhs.name
|
||||
if name == "":
|
||||
name = f"HS_{bhs.id:>3}".replace(" ", "0")
|
||||
else:
|
||||
name = name.replace(" ", "_")
|
||||
|
||||
f.write(
|
||||
f"{sin_dict[bhs._type]} " +
|
||||
f"{reach_id} {float(hs.input_kp):>12.3f} " +
|
||||
f"{param_str} {name}\n"
|
||||
)
|
||||
self._export_SIN_bhs(study, sin_dict, hs, f)
|
||||
|
||||
return files
|
||||
|
||||
def _export_SIN_bhs(self, study, sin_dict, hs, f):
|
||||
for bhs in hs.basic_structures:
|
||||
reach_id = study.river.get_edge_id(hs.input_reach) + 1
|
||||
param_str = ' '.join(
|
||||
[
|
||||
f'{p:>10.3f}'
|
||||
for p in self._export_SIN_parameters(bhs)
|
||||
]
|
||||
)
|
||||
|
||||
name = bhs.name
|
||||
if name == "":
|
||||
name = f"HS_{bhs.id:>3}".replace(" ", "0")
|
||||
else:
|
||||
name = name.replace(" ", "_")
|
||||
|
||||
f.write(
|
||||
f"{sin_dict[bhs._type]} " +
|
||||
f"{reach_id} {float(hs.input_kp):>12.3f} " +
|
||||
f"{param_str} {name}\n"
|
||||
)
|
||||
|
||||
def _export_SIN_parameters(self, bhs):
|
||||
res = [9999.999] * 5
|
||||
|
||||
@@ -574,7 +585,6 @@ class Mage(CommandLineSolver):
|
||||
|
||||
return res
|
||||
|
||||
@timer
|
||||
def _export_VAR(self, study, repertory, qlog, name="0"):
|
||||
files = []
|
||||
|
||||
@@ -610,7 +620,6 @@ class Mage(CommandLineSolver):
|
||||
|
||||
return files
|
||||
|
||||
@timer
|
||||
def _export_DEV(self, study, repertory, qlog, name="0"):
|
||||
files = []
|
||||
|
||||
@@ -633,7 +642,6 @@ class Mage(CommandLineSolver):
|
||||
|
||||
return files
|
||||
|
||||
@timer
|
||||
def _export_REP(self, study, repertory, files, qlog, name="0"):
|
||||
if qlog is not None:
|
||||
qlog.put("Export REP file")
|
||||
@@ -655,6 +663,7 @@ class Mage(CommandLineSolver):
|
||||
f.write("* OUTPUT\n")
|
||||
f.write(f"TRA {name}.TRA\n")
|
||||
f.write(f"BIN {name}.BIN\n")
|
||||
f.write(f"ERR {name}.ERR\n")
|
||||
|
||||
for file in files:
|
||||
EXT = file.split('.')[1]
|
||||
@@ -662,6 +671,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
|
||||
@@ -672,6 +683,8 @@ class Mage(CommandLineSolver):
|
||||
self._bin_file = f"{name}.BIN"
|
||||
|
||||
self._export_ST(study, repertory, qlog, name=name)
|
||||
self.export_additional_files(study, repertory, qlog, name=name)
|
||||
self.export_study_description(study, repertory, qlog, name=name)
|
||||
|
||||
return True
|
||||
|
||||
@@ -763,7 +776,6 @@ class Mage8(Mage):
|
||||
|
||||
return lst
|
||||
|
||||
@timer
|
||||
def _export_PAR(self, study, repertory, qlog=None, name="0"):
|
||||
files = []
|
||||
|
||||
@@ -798,7 +810,6 @@ class Mage8(Mage):
|
||||
|
||||
return files
|
||||
|
||||
@timer
|
||||
def _export_NET(self, study, repertory, qlog=None, name="0"):
|
||||
files = []
|
||||
|
||||
@@ -808,13 +819,7 @@ class Mage8(Mage):
|
||||
with mage_file_open(os.path.join(repertory, f"{name}.NET"), "w+") as f:
|
||||
files.append(f"{name}.NET")
|
||||
|
||||
edges = study.river.edges()
|
||||
edges = list(
|
||||
filter(
|
||||
lambda e: e.is_enable(),
|
||||
edges
|
||||
)
|
||||
)
|
||||
edges = study.river.enable_edges()
|
||||
|
||||
for e in edges:
|
||||
name = f"Reach_{e.id + 1:>3}".replace(" ", "0")
|
||||
@@ -828,7 +833,6 @@ class Mage8(Mage):
|
||||
|
||||
return files
|
||||
|
||||
@timer
|
||||
def _export_QSO(self, bounds, repertory, qlog, name="0"):
|
||||
files = []
|
||||
|
||||
@@ -864,6 +868,16 @@ class Mage8(Mage):
|
||||
|
||||
return files
|
||||
|
||||
def export_func_dict(self):
|
||||
return [
|
||||
self._export_ST, self._export_PAR,
|
||||
self._export_NET, self._export_bound_cond,
|
||||
self._export_RUG, self._export_INI,
|
||||
self._export_SIN, self._export_VAR,
|
||||
self._export_CAS, self._export_DEV,
|
||||
self._export_lateral_contrib,
|
||||
]
|
||||
|
||||
@timer
|
||||
def export(self, study, repertory, qlog=None, name="0"):
|
||||
self._study = study
|
||||
@@ -876,20 +890,19 @@ class Mage8(Mage):
|
||||
# Generate files
|
||||
files = []
|
||||
|
||||
files = self._export_ST(study, repertory, qlog, name=name)
|
||||
files = files + self._export_PAR(study, repertory, qlog, name=name)
|
||||
files = files + self._export_NET(study, repertory, qlog, name=name)
|
||||
files = files + \
|
||||
self._export_bound_cond(study, repertory, qlog, name=name)
|
||||
files = files + self._export_RUG(study, repertory, qlog, name=name)
|
||||
files = files + self._export_INI(study, repertory, qlog, name=name)
|
||||
files = files + self._export_SIN(study, repertory, qlog, name=name)
|
||||
files = files + self._export_VAR(study, repertory, qlog, name=name)
|
||||
files = files + self._export_CAS(study, repertory, qlog, name=name)
|
||||
files = files + self._export_DEV(study, repertory, qlog, name=name)
|
||||
self._export_REP(study, repertory, files, qlog, name=name)
|
||||
try:
|
||||
for func in self.export_func_dict():
|
||||
files = files + func(study, repertory, qlog, name=name)
|
||||
|
||||
return True
|
||||
self.export_additional_files(study, repertory, qlog, name=name)
|
||||
self.export_study_description(study, repertory, qlog, name=name)
|
||||
self._export_REP(study, repertory, files, qlog, name=name)
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to export study to {self._type}")
|
||||
logger_exception(e)
|
||||
return False
|
||||
|
||||
###########
|
||||
# RESULTS #
|
||||
@@ -1202,12 +1215,34 @@ class Mage8(Mage):
|
||||
logger.info(f"read_gra: ... end with {len(ts)} timestamp read")
|
||||
|
||||
@timer
|
||||
def results(self, study, repertory, qlog=None, name=None):
|
||||
def results(self, study, repertory,
|
||||
qlog=None, name=None,
|
||||
with_gra=True):
|
||||
self._study = study
|
||||
if name is None:
|
||||
name = study.name.replace(" ", "_")
|
||||
|
||||
results = super(Mage8, self).results(study, repertory, qlog, name=name)
|
||||
self.read_gra(study, repertory, results, qlog, name=name)
|
||||
if with_gra:
|
||||
self.read_gra(study, repertory, results, qlog, name=name)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
class MageFake7(Mage8):
|
||||
_type = "mage_fake7"
|
||||
|
||||
def __init__(self, name):
|
||||
super(MageFake7, self).__init__(name)
|
||||
|
||||
self._type = "mage_fake7"
|
||||
|
||||
@timer
|
||||
def results(self, study, repertory,
|
||||
qlog=None, name=None,
|
||||
with_gra=False):
|
||||
results = super(MageFake7, self).results(
|
||||
study, repertory,
|
||||
qlog, name=name, with_gra=with_gra
|
||||
)
|
||||
return results
|
||||
@@ -19,7 +19,9 @@
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from Solver.GenericSolver import GenericSolver
|
||||
from Solver.Mage import Mage7, Mage8
|
||||
from Solver.Mage import (
|
||||
Mage7, Mage8, MageFake7,
|
||||
)
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
|
||||
@@ -27,10 +29,12 @@ solver_long_name = {
|
||||
# "generic": "Generic",
|
||||
# "mage7": "Mage v7",
|
||||
"mage8": "Mage v8",
|
||||
# "mage_fake7": "Mage fake v7",
|
||||
}
|
||||
|
||||
solver_type_list = {
|
||||
# "generic": GenericSolver,
|
||||
# "mage7": Mage7,
|
||||
"mage8": Mage8,
|
||||
# "mage_fake7": MageFake7,
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
# 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 PamhyrWindow
|
||||
|
||||
from PyQt5.QtWidgets import (
|
||||
QLabel, QPlainTextEdit, QPushButton,
|
||||
QCheckBox,
|
||||
)
|
||||
|
||||
from View.AdditionalFiles.Translate import AddFileTranslate
|
||||
from View.AdditionalFiles.UndoCommand import (
|
||||
SetCommand
|
||||
)
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
class EditAddFileWindow(PamhyrWindow):
|
||||
_pamhyr_ui = "AdditionalFile"
|
||||
_pamhyr_name = "Edit additional file"
|
||||
|
||||
def __init__(self, study=None, config=None, add_file=None,
|
||||
trad=None, undo=None, parent=None):
|
||||
|
||||
name = trad[self._pamhyr_name] + " - " + study.name
|
||||
super(EditAddFileWindow, self).__init__(
|
||||
title=name,
|
||||
study=study,
|
||||
config=config,
|
||||
options=[],
|
||||
parent=parent
|
||||
)
|
||||
|
||||
self._add_file = add_file
|
||||
self._hash_data.append(self._add_file)
|
||||
|
||||
self._undo = undo
|
||||
|
||||
self.setup_values()
|
||||
self.setup_connection()
|
||||
|
||||
def setup_values(self):
|
||||
self.set_check_box("checkBox", self._add_file.enabled)
|
||||
self.set_line_edit_text("lineEdit_name", self._add_file.name)
|
||||
self.set_line_edit_text("lineEdit_path", self._add_file.path)
|
||||
self.set_plaintext_edit_text("plainTextEdit", self._add_file.text)
|
||||
|
||||
def setup_connection(self):
|
||||
self.find(QPushButton, "pushButton_cancel")\
|
||||
.clicked.connect(self.close)
|
||||
self.find(QPushButton, "pushButton_ok")\
|
||||
.clicked.connect(self.accept)
|
||||
|
||||
def accept(self):
|
||||
is_enabled = self.get_check_box("checkBox")
|
||||
name = self.get_line_edit_text("lineEdit_name")
|
||||
path = self.get_line_edit_text("lineEdit_path")
|
||||
text = self.get_plaintext_edit_text("plainTextEdit")
|
||||
|
||||
self._undo.push(
|
||||
SetCommand(
|
||||
self._add_file,
|
||||
enabled=is_enabled,
|
||||
name=name,
|
||||
path=path,
|
||||
text=text,
|
||||
)
|
||||
)
|
||||
|
||||
self._propagate_update(key=Modules.ADDITIONAL_FILES)
|
||||
self.close()
|
||||
@@ -0,0 +1,81 @@
|
||||
# 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
|
||||
from View.AdditionalFiles.UndoCommand import (
|
||||
AddCommand, DelCommand
|
||||
)
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
class ListModel(PamhyrListModel):
|
||||
def data(self, index, role):
|
||||
row = index.row()
|
||||
column = index.column()
|
||||
|
||||
file = self._data.files[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.path}'"
|
||||
|
||||
if not file.is_enabled():
|
||||
text += " (disabled)"
|
||||
|
||||
return text
|
||||
|
||||
return QVariant()
|
||||
|
||||
def add(self, row):
|
||||
self._undo.push(
|
||||
AddCommand(
|
||||
self._data, row
|
||||
)
|
||||
)
|
||||
self.update()
|
||||
|
||||
def delete(self, row):
|
||||
self._undo.push(
|
||||
DelCommand(
|
||||
self._data, row
|
||||
)
|
||||
)
|
||||
self.update()
|
||||
@@ -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 AddFileTranslate(MainTranslate):
|
||||
def __init__(self):
|
||||
super(AddFileTranslate, self).__init__()
|
||||
|
||||
self._dict["Additional files"] = _translate(
|
||||
"AdditionalFiles", "Additional files"
|
||||
)
|
||||
|
||||
self._dict["Edit additional file"] = _translate(
|
||||
"AdditionalFiles", "Edit additional file"
|
||||
)
|
||||
@@ -0,0 +1,82 @@
|
||||
# UndoCommand.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 (
|
||||
QMessageBox, QUndoCommand, QUndoStack,
|
||||
)
|
||||
|
||||
|
||||
class SetCommand(QUndoCommand):
|
||||
def __init__(self, add_file, **kwargs):
|
||||
QUndoCommand.__init__(self)
|
||||
|
||||
self._add_file = add_file
|
||||
self._new = kwargs
|
||||
self._old = None
|
||||
|
||||
def undo(self):
|
||||
f = self._add_file
|
||||
|
||||
for key in self._old:
|
||||
f[key] = self._old[key]
|
||||
|
||||
def redo(self):
|
||||
f = self._add_file
|
||||
|
||||
if self._old is None:
|
||||
self._old = {}
|
||||
for key in self._new:
|
||||
self._old[key] = f[key]
|
||||
|
||||
for key in self._new:
|
||||
f[key] = self._new[key]
|
||||
|
||||
|
||||
class AddCommand(QUndoCommand):
|
||||
def __init__(self, files, row):
|
||||
QUndoCommand.__init__(self)
|
||||
|
||||
self._files = files
|
||||
self._row = row
|
||||
self._new = None
|
||||
|
||||
def undo(self):
|
||||
self._files.delete([self._new])
|
||||
|
||||
def redo(self):
|
||||
if self._new is None:
|
||||
self._new = self._files.new(self._row)
|
||||
else:
|
||||
self._files.insert(self._row, self._new)
|
||||
|
||||
|
||||
class DelCommand(QUndoCommand):
|
||||
def __init__(self, files, row):
|
||||
QUndoCommand.__init__(self)
|
||||
|
||||
self._files = files
|
||||
self._row = row
|
||||
self._old = self._files.get(row)
|
||||
|
||||
def undo(self):
|
||||
self._files.insert(self._row, self._old)
|
||||
|
||||
def redo(self):
|
||||
self._files.delete_i([self._row])
|
||||
@@ -0,0 +1,118 @@
|
||||
# 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.AdditionalFiles.List import ListModel
|
||||
from View.AdditionalFiles.Translate import AddFileTranslate
|
||||
from View.AdditionalFiles.Edit.Window import EditAddFileWindow
|
||||
|
||||
|
||||
class AddFileListWindow(PamhyrWindow):
|
||||
_pamhyr_ui = "AdditionalFileList"
|
||||
_pamhyr_name = "Additional files"
|
||||
|
||||
def __init__(self, study=None, config=None,
|
||||
parent=None):
|
||||
trad = AddFileTranslate()
|
||||
name = trad[self._pamhyr_name] + " - " + study.name
|
||||
|
||||
super(AddFileListWindow, 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.additional_files,
|
||||
undo=self._undo_stack,
|
||||
trad=self._trad,
|
||||
)
|
||||
|
||||
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()
|
||||
if len(rows) == 0:
|
||||
return
|
||||
|
||||
self._list.delete(rows[0])
|
||||
|
||||
def edit(self):
|
||||
rows = self.selected_rows()
|
||||
|
||||
for row in rows:
|
||||
add_file = self._study.river.additional_files.files[row]
|
||||
|
||||
if self.sub_window_exists(
|
||||
EditAddFileWindow,
|
||||
data=[self._study, self._config, add_file]
|
||||
):
|
||||
continue
|
||||
|
||||
win = EditAddFileWindow(
|
||||
study=self._study,
|
||||
config=self._config,
|
||||
add_file=add_file,
|
||||
trad=self._trad,
|
||||
undo=self._undo_stack,
|
||||
parent=self,
|
||||
)
|
||||
win.show()
|
||||
|
||||
def _undo(self):
|
||||
self._undo_stack.undo()
|
||||
self.update()
|
||||
|
||||
def _redo(self):
|
||||
self._undo_stack.redo()
|
||||
self.update()
|
||||
@@ -108,7 +108,7 @@ class EditBoundaryConditionWindow(PamhyrWindow):
|
||||
name = trad[self._pamhyr_name]
|
||||
if self._data is not None:
|
||||
node_name = (self._data.node.name if self._data.node is not None
|
||||
else _translate("BoundaryCondition", "Not associate"))
|
||||
else trad['not_associated'])
|
||||
name += (
|
||||
f" - {study.name} " +
|
||||
f" - {self._data.name} ({self._data.id}) " +
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||
from View.Translate import MainTranslate
|
||||
|
||||
from View.BoundaryCondition.translate import BCTranslate
|
||||
|
||||
@@ -36,9 +36,9 @@ class BCETranslate(BCTranslate):
|
||||
self._sub_dict["table_headers"] = {
|
||||
"x": _translate("BoundaryCondition", "X"),
|
||||
"y": _translate("BoundaryCondition", "Y"),
|
||||
"time": _translate("BoundaryCondition", "Time"),
|
||||
"date": _translate("BoundaryCondition", "Date"),
|
||||
"discharge": _translate("BoundaryCondition", "Discharge (m³/s)"),
|
||||
"z": _translate("BoundaryCondition", "Z (m)"),
|
||||
"time": self._dict["time"],
|
||||
"date": self._dict["date"],
|
||||
"discharge": self._dict["unit_discharge"],
|
||||
"z": self._dict["unit_elevation"],
|
||||
"solid": _translate("BoundaryCondition", "Solid (kg/s)"),
|
||||
}
|
||||
@@ -85,7 +85,7 @@ class ComboBoxDelegate(QItemDelegate):
|
||||
)
|
||||
else:
|
||||
self.editor.addItems(
|
||||
[_translate("BoundaryCondition", "Not associate")] +
|
||||
[self._trad["not_associated"]] +
|
||||
self._data.nodes_names()
|
||||
)
|
||||
|
||||
@@ -145,7 +145,7 @@ class TableModel(PamhyrTableModel):
|
||||
elif self._headers[column] == "node":
|
||||
n = self._lst.get(self._tab, row).node
|
||||
if n is None:
|
||||
return _translate("BoundaryCondition", "Not associate")
|
||||
return self._trad["not_associated"]
|
||||
return n.name
|
||||
|
||||
return QVariant()
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
import logging
|
||||
|
||||
from tools import trace, timer
|
||||
from tools import trace, timer, logger_exception
|
||||
|
||||
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||
|
||||
@@ -37,6 +37,7 @@ from PyQt5.QtWidgets import (
|
||||
QFileDialog, QTableView, QAbstractItemView,
|
||||
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from Model.BoundaryCondition.BoundaryConditionTypes import (
|
||||
@@ -170,6 +171,13 @@ class BoundaryConditionWindow(PamhyrWindow):
|
||||
)
|
||||
)
|
||||
|
||||
def set_active_tab(self, tab_id=0):
|
||||
try:
|
||||
tab_widget = self.find(QTabWidget, "tabWidget")
|
||||
tab_widget.setCurrentIndex(tab_id)
|
||||
except Exception as e:
|
||||
logger_exception(e)
|
||||
|
||||
def add(self):
|
||||
tab = self.current_tab()
|
||||
rows = self.index_selected_rows()
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||
from View.Translate import MainTranslate
|
||||
|
||||
from Model.BoundaryCondition.BoundaryConditionTypes import (
|
||||
NotDefined, PonctualContribution,
|
||||
@@ -38,7 +38,7 @@ BC_types = {
|
||||
}
|
||||
|
||||
|
||||
class BCTranslate(PamhyrTranslate):
|
||||
class BCTranslate(MainTranslate):
|
||||
def __init__(self):
|
||||
super(BCTranslate, self).__init__()
|
||||
|
||||
@@ -47,7 +47,7 @@ class BCTranslate(PamhyrTranslate):
|
||||
)
|
||||
|
||||
self._sub_dict["long_types"] = {
|
||||
"ND": _translate("BoundaryCondition", "Not defined"),
|
||||
"ND": self._dict["not_defined"],
|
||||
"PC": _translate("BoundaryCondition", "Ponctual contribution"),
|
||||
"TZ": _translate("BoundaryCondition", "Z(t)"),
|
||||
"TD": _translate("BoundaryCondition", "Q(t)"),
|
||||
@@ -56,7 +56,7 @@ class BCTranslate(PamhyrTranslate):
|
||||
}
|
||||
|
||||
self._sub_dict["table_headers"] = {
|
||||
"name": _translate("BoundaryCondition", "Name"),
|
||||
"type": _translate("BoundaryCondition", "Type"),
|
||||
"name": self._dict["name"],
|
||||
"type": self._dict["type"],
|
||||
"node": _translate("BoundaryCondition", "Node")
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
# 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 Modules import Modules
|
||||
from Checker.Checker import STATUS
|
||||
from View.Tools.PamhyrList import PamhyrListModel
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
class TabListModel(PamhyrListModel):
|
||||
def data(self, index, role):
|
||||
row = index.row()
|
||||
column = index.column()
|
||||
|
||||
checker = self._data[row]
|
||||
|
||||
if role == Qt.ForegroundRole:
|
||||
color = Qt.gray
|
||||
status = checker._status
|
||||
|
||||
if status is STATUS.OK:
|
||||
color = Qt.green
|
||||
elif status is STATUS.WARNING:
|
||||
color = QColor("orange")
|
||||
elif status is STATUS.ERROR:
|
||||
color = Qt.red
|
||||
|
||||
return QBrush(color)
|
||||
|
||||
if role == Qt.ItemDataRole.DisplayRole:
|
||||
msg = checker.name
|
||||
|
||||
if checker.is_error() or checker.is_warning():
|
||||
msg += f": {checker.summary}"
|
||||
|
||||
return msg
|
||||
|
||||
return QVariant()
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
|
||||
from functools import reduce
|
||||
from tools import trace, timer
|
||||
|
||||
from PyQt5.QtCore import (
|
||||
@@ -35,9 +38,11 @@ from PyQt5.QtWidgets import (
|
||||
QComboBox,
|
||||
)
|
||||
|
||||
from Modules import Modules
|
||||
from Checker.Checker import STATUS
|
||||
from View.Tools.PamhyrTable import PamhyrTableModel
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
class TableModel(PamhyrTableModel):
|
||||
@@ -52,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
|
||||
|
||||
@@ -68,3 +73,92 @@ class TableModel(PamhyrTableModel):
|
||||
return self._data[row].summary
|
||||
|
||||
return QVariant()
|
||||
|
||||
|
||||
class TabTableModel(PamhyrTableModel):
|
||||
def _setup_lst(self):
|
||||
self._lst = self._opt_data
|
||||
|
||||
def data(self, index, role):
|
||||
row = index.row()
|
||||
column = index.column()
|
||||
|
||||
if role == Qt.ForegroundRole:
|
||||
if self._headers[column] == "type":
|
||||
return QVariant()
|
||||
|
||||
color = Qt.gray
|
||||
status, _ = self.compute_status(row, column)
|
||||
|
||||
if status is STATUS.OK:
|
||||
color = Qt.green
|
||||
elif status is STATUS.WARNING:
|
||||
color = QColor("orange")
|
||||
elif status is STATUS.ERROR:
|
||||
color = Qt.red
|
||||
|
||||
return QBrush(color)
|
||||
|
||||
if role == Qt.ItemDataRole.DisplayRole:
|
||||
if self._headers[column] == "type":
|
||||
return self.module_display_name(self._opt_data[row])
|
||||
|
||||
value = "UNKNOWN"
|
||||
status, _ = self.compute_status(row, column)
|
||||
|
||||
if status is STATUS.OK:
|
||||
value = "OK"
|
||||
elif status is STATUS.WARNING:
|
||||
value = "WARNING"
|
||||
elif status is STATUS.ERROR:
|
||||
value = "ERROR"
|
||||
|
||||
return value
|
||||
|
||||
return QVariant()
|
||||
|
||||
def module_display_name(self, module):
|
||||
return Modules.modelling_display_name()[module]
|
||||
|
||||
def get_checkers(self, row, column):
|
||||
module = self._opt_data[row]
|
||||
solver = self._headers[column]
|
||||
|
||||
checkers = filter(
|
||||
lambda checker: checker._modules is module,
|
||||
filter(
|
||||
lambda checker: checker._solver is solver,
|
||||
self._data
|
||||
)
|
||||
)
|
||||
|
||||
return checkers
|
||||
|
||||
def get_checkers_from_indexes(self, indexes):
|
||||
lst = []
|
||||
|
||||
for index in indexes:
|
||||
row = index.row()
|
||||
column = index.column()
|
||||
|
||||
lst += list(self.get_checkers(row, column))
|
||||
|
||||
return lst
|
||||
|
||||
def compute_status(self, row, column):
|
||||
checkers = self.get_checkers(row, column)
|
||||
|
||||
checkers_status = list(
|
||||
map(
|
||||
lambda c: c._status,
|
||||
checkers
|
||||
)
|
||||
)
|
||||
|
||||
status = STATUS.UNKNOWN
|
||||
if len(checkers_status) > 0:
|
||||
status = reduce(lambda acc, c: acc | c, checkers_status)
|
||||
|
||||
logger.debug(f"Checkers: {row}, {column}: {checkers_status} {status}")
|
||||
|
||||
return status, checkers_status
|
||||
@@ -18,12 +18,12 @@
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||
from View.Translate import MainTranslate
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
|
||||
|
||||
class CheckListTranslate(PamhyrTranslate):
|
||||
class CheckListTranslate(MainTranslate):
|
||||
def __init__(self):
|
||||
super(CheckListTranslate, self).__init__()
|
||||
|
||||
@@ -32,6 +32,6 @@ class CheckListTranslate(PamhyrTranslate):
|
||||
)
|
||||
|
||||
self._sub_dict["table_headers"] = {
|
||||
"name": _translate("CheckList", "Name"),
|
||||
"name": self._dict["name"],
|
||||
"status": _translate("CheckList", "Status"),
|
||||
}
|
||||
@@ -17,11 +17,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import time
|
||||
import logging
|
||||
|
||||
from PyQt5.QtCore import (
|
||||
Qt, QObject, pyqtSlot, pyqtSignal
|
||||
)
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
class Worker(QObject):
|
||||
signalStatus = pyqtSignal(str)
|
||||
@@ -46,3 +49,35 @@ class Worker(QObject):
|
||||
checker._run(self._study)
|
||||
|
||||
self.signalStatus.emit("progress")
|
||||
|
||||
|
||||
class TabWorker(QObject):
|
||||
signalStatus = pyqtSignal(str)
|
||||
|
||||
def __init__(self, study, checker_q, parent=None):
|
||||
super(self.__class__, self).__init__(parent)
|
||||
|
||||
self._study = study
|
||||
self._checker_q = checker_q
|
||||
|
||||
@property
|
||||
def study(self):
|
||||
return self._study
|
||||
|
||||
@study.setter
|
||||
def study(self, study):
|
||||
self._study = study
|
||||
|
||||
def process(self):
|
||||
self._compute()
|
||||
|
||||
def _compute(self):
|
||||
while True:
|
||||
checker = self._checker_q.get()
|
||||
|
||||
if self._study is None:
|
||||
self._checker_q.put(checker)
|
||||
time.sleep(5)
|
||||
else:
|
||||
checker.run(self._study)
|
||||
self.signalStatus.emit("progress")
|
||||
@@ -18,12 +18,12 @@
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||
from View.Translate import MainTranslate
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
|
||||
|
||||
class ConfigureTranslate(PamhyrTranslate):
|
||||
class ConfigureTranslate(MainTranslate):
|
||||
def __init__(self):
|
||||
super(ConfigureTranslate, self).__init__()
|
||||
|
||||
@@ -32,9 +32,9 @@ class ConfigureTranslate(PamhyrTranslate):
|
||||
)
|
||||
|
||||
self._sub_dict["table_headers"] = {
|
||||
"name": _translate("Configure", "Name"),
|
||||
"type": _translate("Configure", "Type"),
|
||||
"description": _translate("Configure", "Description"),
|
||||
"name": self._dict["name"],
|
||||
"type": self._dict["type"],
|
||||
"description": self._dict["description"],
|
||||
}
|
||||
|
||||
# Solvers
|
||||
|
||||
@@ -45,6 +45,7 @@ from PyQt5.QtWidgets import (
|
||||
QComboBox, QUndoStack, QShortcut, QHeaderView,
|
||||
)
|
||||
|
||||
from Modules import Modules
|
||||
from Solver.Solvers import solver_long_name
|
||||
|
||||
logger = logging.getLogger()
|
||||
@@ -123,11 +124,11 @@ class ConfigureWindow(PamhyrDialog):
|
||||
def setup_data(self):
|
||||
# Backup
|
||||
self.set_check_box("checkBox_backup", self._config.backup_enable)
|
||||
self.set_line_edit_text("lineEdit_backup_path",
|
||||
self._config.backup_path)
|
||||
# self.set_line_edit_text("lineEdit_backup_path",
|
||||
# self._config.backup_path)
|
||||
self.set_time_edit("timeEdit_backup_frequence",
|
||||
self._config.backup_frequence)
|
||||
self.set_spin_box("spinBox_backup_max", self._config.backup_max)
|
||||
# self.set_spin_box("spinBox_backup_max", self._config.backup_max)
|
||||
|
||||
# Editor
|
||||
self.set_line_edit_text("lineEdit_editor_cmd",
|
||||
@@ -155,12 +156,12 @@ class ConfigureWindow(PamhyrDialog):
|
||||
"pushButton_stricklers_del": self.del_stricklers,
|
||||
"pushButton_stricklers_sort": self.sort_stricklers,
|
||||
# Others
|
||||
"pushButton_backup_path": lambda: self.file_dialog(
|
||||
select_file=False,
|
||||
callback=lambda f: self.set_line_edit_text(
|
||||
"lineEdit_backup_path", f[0]
|
||||
)
|
||||
),
|
||||
# "pushButton_backup_path": lambda: self.file_dialog(
|
||||
# select_file=False,
|
||||
# callback=lambda f: self.set_line_edit_text(
|
||||
# "lineEdit_backup_path", f[0]
|
||||
# )
|
||||
# ),
|
||||
}
|
||||
|
||||
for button in buttons:
|
||||
@@ -172,11 +173,12 @@ class ConfigureWindow(PamhyrDialog):
|
||||
|
||||
# Backup
|
||||
self._config.backup_enable = self.get_check_box("checkBox_backup")
|
||||
self._config.backup_path = self.get_line_edit_text(
|
||||
"lineEdit_backup_path")
|
||||
# self._config.backup_path = self.get_line_edit_text(
|
||||
# "lineEdit_backup_path")
|
||||
self._config.backup_frequence = self.get_time_edit(
|
||||
"timeEdit_backup_frequence")
|
||||
self._config.backup_max = self.get_spin_box("spinBox_backup_max")
|
||||
"timeEdit_backup_frequence"
|
||||
)
|
||||
# self._config.backup_max = self.get_spin_box("spinBox_backup_max")
|
||||
|
||||
# Stricklers
|
||||
self._config.stricklers = deepcopy(self._stricklers)
|
||||
@@ -188,6 +190,9 @@ class ConfigureWindow(PamhyrDialog):
|
||||
self._config.lang = Config.languages(
|
||||
)[self.get_combobox_text("comboBox_language")]
|
||||
|
||||
self._propagate_update(key=Modules.CONFIG)
|
||||
|
||||
self._config.save()
|
||||
self.end()
|
||||
|
||||
def reject(self):
|
||||
@@ -195,7 +200,6 @@ class ConfigureWindow(PamhyrDialog):
|
||||
self.end()
|
||||
|
||||
def end(self):
|
||||
self._config.save()
|
||||
self.close()
|
||||
|
||||
# Debug
|
||||
|
||||
@@ -77,30 +77,10 @@ class ReplWindow(PamhyrWindow):
|
||||
layout.insertWidget(0, self._editor)
|
||||
|
||||
def setup_connections(self):
|
||||
self._hup_sc = QShortcut(QKeySequence("ctrl+Up"), self)
|
||||
self._hdown_sc = QShortcut(QKeySequence("ctrl+Down"), self)
|
||||
self._hup_sc.activated.connect(self.history_up)
|
||||
self._hdown_sc.activated.connect(self.history_down)
|
||||
|
||||
self.find(QPushButton, "pushButton").clicked.connect(self.eval_python)
|
||||
|
||||
def history_up(self):
|
||||
if self._history_ind < len(self._history):
|
||||
self._history_ind += 1
|
||||
self._editor.setText(self._history[-self._history_ind])
|
||||
|
||||
def history_down(self):
|
||||
if self._history_ind > 0:
|
||||
self._history_ind -= 1
|
||||
self._editor.setText(self._history[-self._history_ind])
|
||||
else:
|
||||
self._editor.setText("")
|
||||
|
||||
def eval_python(self):
|
||||
code = self._editor.text()
|
||||
self._history.append(code)
|
||||
self._editor.setText("")
|
||||
self._history_ind = 0
|
||||
|
||||
# Code to rich_code
|
||||
rich_code = code.strip().split("\n")
|
||||
|
||||
@@ -50,7 +50,7 @@ class DocWindow(PamhyrWindow):
|
||||
return os.path.abspath(
|
||||
os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"..", "..", "..", "..", "doc", filename
|
||||
"..", "..", "..", "doc", filename
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -52,11 +52,12 @@ _translate = QCoreApplication.translate
|
||||
|
||||
class ComboBoxDelegate(QItemDelegate):
|
||||
def __init__(self, data=None, study=None,
|
||||
mode="stricklers", parent=None):
|
||||
mode="stricklers", trad=None, parent=None):
|
||||
super(ComboBoxDelegate, self).__init__(parent)
|
||||
|
||||
self._data = data
|
||||
self._study = study
|
||||
self._trad = trad
|
||||
self._mode = mode
|
||||
|
||||
def createEditor(self, parent, option, index):
|
||||
@@ -64,7 +65,7 @@ class ComboBoxDelegate(QItemDelegate):
|
||||
|
||||
if self._mode == "stricklers":
|
||||
self.editor.addItems(
|
||||
[_translate("Frictions", "Not defined")] +
|
||||
[self._trad["not_defined"]] +
|
||||
list(
|
||||
map(
|
||||
lambda s: str(s),
|
||||
@@ -119,12 +120,12 @@ class TableModel(PamhyrTableModel):
|
||||
elif self._headers[column] == "begin_strickler":
|
||||
value = self._lst.get(row).begin_strickler
|
||||
if value is None:
|
||||
return _translate("Frictions", "Not defined")
|
||||
return self._trad["not_defined"]
|
||||
return str(value)
|
||||
elif self._headers[column] == "end_strickler":
|
||||
value = self._lst.get(row).end_strickler
|
||||
if value is None:
|
||||
return _translate("Frictions", "Not defined")
|
||||
return self._trad["not_defined"]
|
||||
return str(value)
|
||||
|
||||
return QVariant()
|
||||
|
||||
@@ -39,6 +39,8 @@ from PyQt5.QtWidgets import (
|
||||
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
||||
)
|
||||
|
||||
from Modules import Modules
|
||||
|
||||
from View.Frictions.UndoCommand import (
|
||||
PasteCommand, DuplicateCommand,
|
||||
)
|
||||
@@ -99,6 +101,7 @@ class FrictionsWindow(PamhyrWindow):
|
||||
data=self._reach,
|
||||
study=self._study,
|
||||
mode="stricklers",
|
||||
trad=self._trad,
|
||||
parent=self
|
||||
)
|
||||
|
||||
@@ -115,6 +118,7 @@ class FrictionsWindow(PamhyrWindow):
|
||||
"end_strickler": self._delegate_stricklers,
|
||||
},
|
||||
data=self._reach,
|
||||
trad=self._trad,
|
||||
undo=self._undo_stack,
|
||||
opt_data=self._study
|
||||
)
|
||||
@@ -179,10 +183,10 @@ class FrictionsWindow(PamhyrWindow):
|
||||
|
||||
def update(self):
|
||||
self._set_current_reach()
|
||||
# self._propagate_update(key="friction")
|
||||
# self._propagate_update(key=Modules.FRICTION)
|
||||
|
||||
def _propagated_update(self, key=None):
|
||||
if key != "geometry":
|
||||
def _propagated_update(self, key=Modules(0)):
|
||||
if Modules.GEOMETRY not in key:
|
||||
return
|
||||
|
||||
self.update_plot()
|
||||
|
||||
@@ -18,18 +18,16 @@
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||
from View.Translate import MainTranslate
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
|
||||
|
||||
class FrictionsTranslate(PamhyrTranslate):
|
||||
class FrictionsTranslate(MainTranslate):
|
||||
def __init__(self):
|
||||
super(FrictionsTranslate, self).__init__()
|
||||
|
||||
self._dict["kp"] = _translate(
|
||||
"Frictions", "Kp (m)"
|
||||
)
|
||||
self._dict["kp"] = self._dict["unit_kp"]
|
||||
self._dict["stricklers"] = _translate(
|
||||
"Frictions", "Stricklers"
|
||||
)
|
||||
@@ -39,8 +37,8 @@ class FrictionsTranslate(PamhyrTranslate):
|
||||
)
|
||||
|
||||
self._sub_dict["table_headers"] = {
|
||||
# "name": _translate("Frictions", "Name"),
|
||||
# "edge": _translate("Frictions", "Reach"),
|
||||
# "name": self._dict["name"],
|
||||
# "edge": self._dict["reach"],
|
||||
"begin_kp": _translate("Frictions", "Begin kp (m)"),
|
||||
"end_kp": _translate("Frictions", "End kp (m)"),
|
||||
"begin_strickler": _translate("Frictions", "Begin strickler"),
|
||||
|
||||
@@ -21,12 +21,6 @@ import logging
|
||||
from tools import timer
|
||||
from View.Tools.PamhyrPlot import PamhyrPlot
|
||||
|
||||
from PyQt5.QtCore import (
|
||||
QCoreApplication
|
||||
)
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
@@ -46,20 +40,12 @@ class PlotAC(PamhyrPlot):
|
||||
self._auto_relim_update = True
|
||||
self._autoscale_update = True
|
||||
|
||||
self.label_x = _translate(
|
||||
"Geometry", "Transverse abscissa (m)"
|
||||
)
|
||||
self.label_y = _translate("Geometry", "Height (m)")
|
||||
self.label_x = self._trad["transverse_abscissa"]
|
||||
self.label_y = self._trad["unit_height"]
|
||||
|
||||
self.label_previous_plot_selected = _translate(
|
||||
"Geometry", "Previous cross-section"
|
||||
)
|
||||
self.label_plot_selected = _translate(
|
||||
"Geometry", "Cross-section"
|
||||
)
|
||||
self.label_next_plot_selected = _translate(
|
||||
"Geometry", "Next cross-section"
|
||||
)
|
||||
self.label_previous_plot_selected = self._trad["prev_cs"]
|
||||
self.label_plot_selected = self._trad["cs"]
|
||||
self.label_next_plot_selected = self._trad["next_cs"]
|
||||
|
||||
self.previous_plot_selected = None
|
||||
self.plot_selected = None
|
||||
|
||||
@@ -21,12 +21,6 @@ import logging
|
||||
from tools import timer
|
||||
from View.Tools.PamhyrPlot import PamhyrPlot
|
||||
|
||||
from PyQt5.QtCore import (
|
||||
QCoreApplication
|
||||
)
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
@@ -48,8 +42,8 @@ class PlotKPZ(PamhyrPlot):
|
||||
self.line_kp_zmin_zmax = None
|
||||
self.line_kp_zmin_zmax_highlight = None
|
||||
|
||||
self.label_x = _translate("MainWindow_reach", "Kp (m)")
|
||||
self.label_y = _translate("MainWindow_reach", "Height (m)")
|
||||
self.label_x = self._trad["unit_kp"]
|
||||
self.label_y = self._trad["unit_height"]
|
||||
|
||||
self.before_plot_selected = None
|
||||
self.plot_selected = None
|
||||
|
||||
@@ -40,8 +40,8 @@ class PlotXY(PamhyrPlot):
|
||||
self.line_xy = []
|
||||
self.line_gl = []
|
||||
|
||||
self.label_x = _translate("Geometry", "X (m)")
|
||||
self.label_y = _translate("Geometry", "Y (m)")
|
||||
self.label_x = self._trad["x"]
|
||||
self.label_y = self._trad["y"]
|
||||
|
||||
self.before_plot_selected = None
|
||||
self.plot_selected = None
|
||||
@@ -52,10 +52,12 @@ class PlotXY(PamhyrPlot):
|
||||
self.init_axes()
|
||||
|
||||
if self.data is None:
|
||||
self.idle()
|
||||
return
|
||||
|
||||
if self.data.number_profiles == 0:
|
||||
self._init = False
|
||||
self.idle()
|
||||
return
|
||||
|
||||
self.draw_xy()
|
||||
|
||||
@@ -47,16 +47,18 @@ class Plot(PamhyrPlot):
|
||||
self.line_xy = []
|
||||
self.line_gl = []
|
||||
|
||||
self.label_x = self._trad["unit_kp"]
|
||||
self.label_y = self._trad["unit_height"]
|
||||
|
||||
self.before_plot_selected = None
|
||||
self.plot_selected = None
|
||||
self.after_plot_selected = None
|
||||
|
||||
self._isometric_axis = False
|
||||
|
||||
@timer
|
||||
def draw(self):
|
||||
self.canvas.axes.cla()
|
||||
self.canvas.axes.grid(
|
||||
color='grey', linestyle='--', linewidth=0.5
|
||||
)
|
||||
self.init_axes()
|
||||
|
||||
x = self.data.get_station()
|
||||
y = self.data.z()
|
||||
@@ -71,19 +73,10 @@ class Plot(PamhyrPlot):
|
||||
gl = map(lambda p: p.name, self.data.points)
|
||||
|
||||
self.profile_line2D, = self.canvas.axes.plot(
|
||||
x, y, color='r', lw=1.5,
|
||||
markersize=7, marker='+',
|
||||
x, y, color=self.color_plot,
|
||||
lw=1.5, markersize=7, marker='+',
|
||||
picker=30
|
||||
)
|
||||
self.canvas.axes.set_xlabel(
|
||||
_translate("MainWindowProfile",
|
||||
"Transverse abscissa (m)"),
|
||||
color='black', fontsize=10
|
||||
)
|
||||
self.canvas.axes.set_ylabel(
|
||||
_translate("MainWindowProfile", "Height (m)"),
|
||||
color='black', fontsize=10
|
||||
)
|
||||
|
||||
# Add label on graph
|
||||
self.annotation = []
|
||||
@@ -142,10 +135,8 @@ class Plot(PamhyrPlot):
|
||||
self.onclick_event.onclick
|
||||
)
|
||||
|
||||
self.canvas.figure.tight_layout()
|
||||
self.canvas.figure.canvas.draw_idle()
|
||||
self.idle()
|
||||
|
||||
@timer
|
||||
def update(self, ind=None):
|
||||
logger.info("TODO: implemente update")
|
||||
def update(self):
|
||||
self.draw()
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||
from View.Translate import MainTranslate
|
||||
from View.Geometry.Translate import GeometryTranslate
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
@@ -33,9 +33,9 @@ class GeometryProfileTranslate(GeometryTranslate):
|
||||
)
|
||||
|
||||
self._sub_dict["table_headers"] = {
|
||||
"x": _translate("Geometry", "X (m)"),
|
||||
"y": _translate("Geometry", "Y (m)"),
|
||||
"z": _translate("Geometry", "Z (m)"),
|
||||
"name": _translate("Geometry", "Name"),
|
||||
"x": self._dict["x"],
|
||||
"y": self._dict["y"],
|
||||
"z": self._dict["z"],
|
||||
"name": self._dict["name"],
|
||||
"abs": _translate("Geometry", "Traversal abs (m)"),
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import csv
|
||||
from time import time
|
||||
|
||||
from tools import trace, timer
|
||||
from Modules import Modules
|
||||
|
||||
from PyQt5.QtGui import (
|
||||
QKeySequence,
|
||||
@@ -108,6 +109,7 @@ class ProfileWindow(PamhyrWindow):
|
||||
self._plot = Plot(
|
||||
canvas=self._canvas,
|
||||
data=self._profile,
|
||||
trad=self._trad,
|
||||
toolbar=self._toolbar,
|
||||
table=self.find(QTableView, "tableView")
|
||||
)
|
||||
@@ -133,7 +135,7 @@ class ProfileWindow(PamhyrWindow):
|
||||
|
||||
def update(self):
|
||||
self.update_plot()
|
||||
self._propagate_update(key="geometry")
|
||||
self._propagate_update(key=Modules.GEOMETRY)
|
||||
|
||||
def update_plot(self):
|
||||
self._tablemodel.blockSignals(True)
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||
from View.Translate import MainTranslate
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
|
||||
|
||||
class GeometryTranslate(PamhyrTranslate):
|
||||
class GeometryTranslate(MainTranslate):
|
||||
def __init__(self):
|
||||
super(GeometryTranslate, self).__init__()
|
||||
|
||||
@@ -38,17 +38,28 @@ class GeometryTranslate(PamhyrTranslate):
|
||||
"Geometry", "File mage meshed geometry (*.M *.m)")
|
||||
self._dict["file_all"] = _translate("Geometry", "All file (*)")
|
||||
|
||||
self._dict["reach"] = _translate("Geometry", "reach")
|
||||
self._dict["reachs"] = _translate("Geometry", "reachs")
|
||||
|
||||
self._dict["cross_section"] = _translate("Geometry", "cross-section")
|
||||
self._dict["cross_sections"] = _translate("Geometry", "cross-sections")
|
||||
self._dict["profile"] = _translate("Geometry", "cross-section")
|
||||
self._dict["profiles"] = _translate("Geometry", "cross-sections")
|
||||
|
||||
self._dict["transverse_abscissa"] = _translate(
|
||||
"Geometry", "Transverse abscissa (m)"
|
||||
)
|
||||
|
||||
self._dict["prev_cs"] = _translate(
|
||||
"Geometry", "Previous cross-section"
|
||||
)
|
||||
self._dict["cs"] = _translate("Geometry", "Cross-section")
|
||||
self._dict["next_cs"] = _translate("Geometry", "Next cross-section")
|
||||
|
||||
self._dict["x"] = _translate("Geometry", "X (m)")
|
||||
self._dict["y"] = _translate("Geometry", "Y (m)")
|
||||
self._dict["z"] = _translate("Geometry", "Z (m)")
|
||||
|
||||
self._sub_dict["table_headers"] = {
|
||||
"name": _translate("Geometry", "Name"),
|
||||
"kp": _translate("Geometry", "KP (m)"),
|
||||
"name": self._dict["name"],
|
||||
"kp": self._dict["unit_kp"],
|
||||
"poins": _translate("Geometry", "Points"),
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ from PyQt5.QtWidgets import (
|
||||
QLabel, QAbstractItemView,
|
||||
)
|
||||
|
||||
from Modules import Modules
|
||||
from Model.Except import ExternFileMissingError
|
||||
|
||||
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||
@@ -223,10 +224,10 @@ class GeometryWindow(PamhyrWindow):
|
||||
self.changed_slider_value()
|
||||
|
||||
if propagate:
|
||||
self._propagate_update(key="geometry")
|
||||
self._propagate_update(key=Modules.GEOMETRY)
|
||||
|
||||
def _propagated_update(self, key=None):
|
||||
if key != "network":
|
||||
def _propagated_update(self, key=Modules(0)):
|
||||
if Modules.NETWORK not in key:
|
||||
return
|
||||
|
||||
self._update(propagate=False)
|
||||
@@ -327,6 +328,7 @@ class GeometryWindow(PamhyrWindow):
|
||||
self._plot_xy = PlotXY(
|
||||
canvas=self._canvas_xy,
|
||||
data=self._reach,
|
||||
trad=self._trad,
|
||||
toolbar=self._toolbar_xy
|
||||
)
|
||||
self._plot_xy.draw()
|
||||
@@ -344,6 +346,7 @@ class GeometryWindow(PamhyrWindow):
|
||||
self._plot_kpc = PlotKPZ(
|
||||
canvas=self._canvas_kpc,
|
||||
data=self._reach,
|
||||
trad=self._trad,
|
||||
toolbar=self._toolbar_kpc
|
||||
)
|
||||
self._plot_kpc.draw()
|
||||
@@ -361,6 +364,7 @@ class GeometryWindow(PamhyrWindow):
|
||||
self._plot_ac = PlotAC(
|
||||
canvas=self._canvas_ac,
|
||||
data=self._reach,
|
||||
trad=self._trad,
|
||||
toolbar=self._toolbar_ac,
|
||||
)
|
||||
self._plot_ac.draw()
|
||||
@@ -609,7 +613,7 @@ class GeometryWindow(PamhyrWindow):
|
||||
options=options
|
||||
)
|
||||
|
||||
if filename != '':
|
||||
if filename != '' and filename is not None:
|
||||
self._export_to_file_st(filename)
|
||||
|
||||
def _export_to_file_st(self, filename):
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||
from View.Translate import MainTranslate
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
|
||||
|
||||
class BasicHydraulicStructuresTranslate(PamhyrTranslate):
|
||||
class BasicHydraulicStructuresTranslate(MainTranslate):
|
||||
def __init__(self):
|
||||
super(BasicHydraulicStructuresTranslate, self).__init__()
|
||||
|
||||
@@ -44,18 +44,10 @@ hydraulic structure values?"
|
||||
|
||||
# BHSValues translation
|
||||
|
||||
self._dict['width'] = _translate(
|
||||
"BasicHydraulicStructures", "Width (m)"
|
||||
)
|
||||
self._dict['height'] = _translate(
|
||||
"BasicHydraulicStructures", "Thickness (m)"
|
||||
)
|
||||
self._dict['elevation'] = _translate(
|
||||
"BasicHydraulicStructures", "Elevation (m)"
|
||||
)
|
||||
self._dict['diameter'] = _translate(
|
||||
"BasicHydraulicStructures", "Diameter (m)"
|
||||
)
|
||||
self._dict['width'] = self._dict["unit_width"]
|
||||
self._dict['height'] = self._dict["unit_thickness"]
|
||||
self._dict['elevation'] = self._dict["unit_elevation"]
|
||||
self._dict['diameter'] = self._dict["unit_diameter"]
|
||||
self._dict['discharge_coefficient'] = _translate(
|
||||
"BasicHydraulicStructures", "Discharge coefficient"
|
||||
)
|
||||
@@ -114,9 +106,7 @@ hydraulic structure values?"
|
||||
# BHS types long names
|
||||
|
||||
self._sub_dict["long_types"] = {
|
||||
"ND": _translate(
|
||||
"BasicHydraulicStructures", "Not defined"
|
||||
),
|
||||
"ND": self._dict["not_defined"],
|
||||
"S1": _translate(
|
||||
"BasicHydraulicStructures", "Discharge weir"
|
||||
),
|
||||
@@ -155,11 +145,11 @@ hydraulic structure values?"
|
||||
# Tables
|
||||
|
||||
self._sub_dict["table_headers"] = {
|
||||
"name": _translate("BasicHydraulicStructures", "Name"),
|
||||
"type": _translate("BasicHydraulicStructures", "Type"),
|
||||
"name": self._dict["name"],
|
||||
"type": self._dict["type"],
|
||||
}
|
||||
|
||||
self._sub_dict["table_headers_parameters"] = {
|
||||
"name": _translate("BasicHydraulicStructures", "Name"),
|
||||
"value": _translate("BasicHydraulicStructures", "Value"),
|
||||
"name": self._dict["name"],
|
||||
"value": self._dict["value"],
|
||||
}
|
||||
@@ -165,6 +165,7 @@ class BasicHydraulicStructuresWindow(PamhyrWindow):
|
||||
river=self._study.river,
|
||||
reach=self._hs.input_reach,
|
||||
profile=profile,
|
||||
trad=self._trad,
|
||||
toolbar=self.toolbar
|
||||
)
|
||||
self.plot_ac.draw()
|
||||
|
||||
@@ -20,12 +20,6 @@ from tools import timer
|
||||
from View.Tools.PamhyrPlot import PamhyrPlot
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
from PyQt5.QtCore import (
|
||||
QCoreApplication
|
||||
)
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
|
||||
|
||||
class PlotAC(PamhyrPlot):
|
||||
def __init__(self, canvas=None, trad=None, toolbar=None,
|
||||
@@ -42,8 +36,8 @@ class PlotAC(PamhyrPlot):
|
||||
self._current_reach = reach
|
||||
self._current_profile = profile
|
||||
|
||||
self.label_x = _translate("MainWindow_reach", "X (m)")
|
||||
self.label_y = _translate("MainWindow_reach", "Elevation (m)")
|
||||
self.label_x = self._trad["x"]
|
||||
self.label_y = self._trad["unit_elevation"]
|
||||
|
||||
self._isometric_axis = False
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@ class PlotKPC(PamhyrPlot):
|
||||
self._current_reach = reach
|
||||
self._current_profile = profile
|
||||
|
||||
self.label_x = _translate("MainWindow_reach", "KP (m)")
|
||||
self.label_y = _translate("MainWindow_reach", "Elevation (m)")
|
||||
self.label_x = self._trad["unit_kp"]
|
||||
self.label_y = self._trad["unit_elevation"]
|
||||
|
||||
self._isometric_axis = False
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ class ComboBoxDelegate(QItemDelegate):
|
||||
)
|
||||
|
||||
self.editor.addItems(
|
||||
[_translate("Hydraulic structure", "Not associated")] +
|
||||
[self._trad['not_associated']] +
|
||||
val
|
||||
)
|
||||
|
||||
@@ -124,12 +124,12 @@ class TableModel(PamhyrTableModel):
|
||||
elif self._headers[column] == "reach":
|
||||
n = self._lst.get(row).input_reach
|
||||
if n is None:
|
||||
return _translate("Hydraulic structure", "Not associated")
|
||||
return self._trad['not_associated']
|
||||
return n.name
|
||||
elif self._headers[column] == "kp":
|
||||
n = self._lst.get(row).input_kp
|
||||
if n is None:
|
||||
return _translate("Hydraulic structure", "Not associated")
|
||||
return self._trad['not_associated']
|
||||
return n
|
||||
|
||||
return QVariant()
|
||||
@@ -140,7 +140,7 @@ class TableModel(PamhyrTableModel):
|
||||
|
||||
row = index.row()
|
||||
column = index.column()
|
||||
na = _translate("Hydraulic structure", "Not associated")
|
||||
na = self._trad['not_associated']
|
||||
|
||||
try:
|
||||
if self._headers[column] == "name":
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||
from View.Translate import MainTranslate
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
|
||||
|
||||
class HydraulicStructuresTranslate(PamhyrTranslate):
|
||||
class HydraulicStructuresTranslate(MainTranslate):
|
||||
def __init__(self):
|
||||
super(HydraulicStructuresTranslate, self).__init__()
|
||||
|
||||
@@ -31,8 +31,10 @@ class HydraulicStructuresTranslate(PamhyrTranslate):
|
||||
"HydraulicStructures", "Hydraulic Structures"
|
||||
)
|
||||
|
||||
self._dict["x"] = _translate("HydraulicStructures", "X (m)")
|
||||
|
||||
self._sub_dict["table_headers"] = {
|
||||
"name": _translate("HydraulicStructures", "Name"),
|
||||
"reach": _translate("HydraulicStructures", "Reach"),
|
||||
"kp": _translate("HydraulicStructures", "Kp (m)"),
|
||||
"name": self._dict["name"],
|
||||
"reach": self._dict["reach"],
|
||||
"kp": self._dict["unit_kp"],
|
||||
}
|
||||
@@ -52,8 +52,6 @@ from View.HydraulicStructures.BasicHydraulicStructures.Window import (
|
||||
BasicHydraulicStructuresWindow
|
||||
)
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
@@ -142,6 +140,7 @@ class HydraulicStructuresWindow(PamhyrWindow):
|
||||
river=self._study.river,
|
||||
reach=None,
|
||||
profile=None,
|
||||
trad=self._trad,
|
||||
toolbar=self.toolbar
|
||||
)
|
||||
self.plot_kpc.draw()
|
||||
@@ -160,6 +159,7 @@ class HydraulicStructuresWindow(PamhyrWindow):
|
||||
river=self._study.river,
|
||||
reach=None,
|
||||
profile=None,
|
||||
trad=self._trad,
|
||||
toolbar=self.toolbar_2
|
||||
)
|
||||
self.plot_ac.draw()
|
||||
|
||||
@@ -39,6 +39,8 @@ from PyQt5.QtWidgets import (
|
||||
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
||||
)
|
||||
|
||||
from Modules import Modules
|
||||
|
||||
from View.InitialConditions.UndoCommand import (
|
||||
SetCommand, AddCommand, DelCommand,
|
||||
SortCommand, MoveCommand, PasteCommand,
|
||||
@@ -183,14 +185,14 @@ class InitialConditionsWindow(PamhyrWindow):
|
||||
|
||||
def update(self):
|
||||
self._update_plot()
|
||||
self._propagate_update(key="initial_condition")
|
||||
self._propagate_update(key=Modules.INITIAL_CONDITION)
|
||||
|
||||
def _update_plot(self):
|
||||
self.plot_1.draw()
|
||||
self.plot_2.draw()
|
||||
|
||||
def _propagated_update(self, key=None):
|
||||
if key != "geometry":
|
||||
def _propagated_update(self, key=Modules(0)):
|
||||
if Modules.GEOMETRY not in key:
|
||||
return
|
||||
|
||||
self.update()
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||
from View.Translate import MainTranslate
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
|
||||
|
||||
class ICTranslate(PamhyrTranslate):
|
||||
class ICTranslate(MainTranslate):
|
||||
def __init__(self):
|
||||
super(ICTranslate, self).__init__()
|
||||
|
||||
@@ -34,18 +34,16 @@ class ICTranslate(PamhyrTranslate):
|
||||
self._dict["Height"] = _translate(
|
||||
"InitialCondition", "Height")
|
||||
|
||||
self._dict["elevation"] = _translate(
|
||||
"InitialCondition", "Elevation (m)")
|
||||
self._dict["discharge"] = _translate(
|
||||
"InitialCondition", "Discharge (m³/s)")
|
||||
self._dict["kp"] = _translate("InitialCondition", "KP (m)")
|
||||
self._dict["elevation"] = self._dict["unit_elevation"]
|
||||
self._dict["discharge"] = self._dict["unit_discharge"]
|
||||
self._dict["kp"] = self._dict["unit_kp"]
|
||||
|
||||
self._sub_dict["table_headers"] = {
|
||||
# "name": _translate("InitialCondition", "Name"),
|
||||
"kp": _translate("InitialCondition", "KP (m)"),
|
||||
"kp": self._dict["unit_kp"],
|
||||
# "speed": _translate("InitialCondition", "Speed (m/s)"),
|
||||
"discharge": _translate("InitialCondition", "Discharge (m³/s)"),
|
||||
"elevation": _translate("InitialCondition", "Elevation (m)"),
|
||||
"height": _translate("InitialCondition", "Height (m)"),
|
||||
"discharge": self._dict["unit_discharge"],
|
||||
"elevation": self._dict["unit_elevation"],
|
||||
"height": self._dict["unit_height"],
|
||||
# "comment": _translate("InitialCondition", "Comment"),
|
||||
}
|
||||
@@ -59,8 +59,7 @@ class EditLateralContributionWindow(PamhyrWindow):
|
||||
name = trad[self._pamhyr_name]
|
||||
if self._data is not None:
|
||||
edge_name = (self._data.edge.name if self._data.edge is not None
|
||||
else _translate("LateralContribution",
|
||||
"Not associate"))
|
||||
else trad['not_associated'])
|
||||
name += (
|
||||
f" - {study.name} " +
|
||||
f" - {self._data.name} ({self._data.id}) " +
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||
from View.Translate import MainTranslate
|
||||
from View.LateralContribution.translate import LCTranslate
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
@@ -34,8 +34,8 @@ class LCETranslate(LCTranslate):
|
||||
self._sub_dict["table_headers"] = {
|
||||
"x": _translate("LateralContribution", "X"),
|
||||
"y": _translate("LateralContribution", "Y"),
|
||||
"time": _translate("LateralContribution", "Time"),
|
||||
"date": _translate("LateralContribution", "Date"),
|
||||
"discharge": _translate("LateralContribution", "Discharge (m³/s)"),
|
||||
"z": _translate("LateralContribution", "Z (m)")
|
||||
"time": self._dict["time"],
|
||||
"date": self._dict["date"],
|
||||
"discharge": self._dict["unit_discharge"],
|
||||
"z": self._dict["unit_elevation"],
|
||||
}
|
||||
@@ -80,7 +80,7 @@ class ComboBoxDelegate(QItemDelegate):
|
||||
self.editor.addItems(lst)
|
||||
else:
|
||||
self.editor.addItems(
|
||||
[_translate("LateralContribution", "Not associate")] +
|
||||
[self._trad['not_associated']] +
|
||||
self._data.edges_names()
|
||||
)
|
||||
|
||||
@@ -133,7 +133,7 @@ class TableModel(PamhyrTableModel):
|
||||
elif self._headers[column] == "edge":
|
||||
n = self._lst.get(self._tab, row).edge
|
||||
if n is None:
|
||||
return _translate("LateralContribution", "Not associate")
|
||||
return self._trad['not_associated']
|
||||
return n.name
|
||||
elif self._headers[column] == "begin_kp":
|
||||
return self._lst.get(self._tab, row).begin_kp
|
||||
|
||||
@@ -132,6 +132,7 @@ class LateralContributionWindow(PamhyrWindow):
|
||||
self.plot = PlotXY(
|
||||
canvas=self.canvas,
|
||||
data=None,
|
||||
trad=self._trad,
|
||||
toolbar=None,
|
||||
)
|
||||
|
||||
@@ -197,10 +198,11 @@ class LateralContributionWindow(PamhyrWindow):
|
||||
self.plot = PlotXY(
|
||||
canvas=self.canvas,
|
||||
data=data,
|
||||
trad=self._trad,
|
||||
toolbar=None,
|
||||
)
|
||||
self.plot.highlight = highlight
|
||||
self.plot.draw()
|
||||
self.plot.update()
|
||||
|
||||
def add(self):
|
||||
tab = self.current_tab()
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||
from View.Translate import MainTranslate
|
||||
|
||||
from Model.LateralContribution.LateralContributionTypes import (
|
||||
NotDefined, LateralContrib, Rain, Evaporation,
|
||||
@@ -34,7 +34,7 @@ LC_types = {
|
||||
}
|
||||
|
||||
|
||||
class LCTranslate(PamhyrTranslate):
|
||||
class LCTranslate(MainTranslate):
|
||||
def __init__(self):
|
||||
super(LCTranslate, self).__init__()
|
||||
|
||||
@@ -43,16 +43,20 @@ class LCTranslate(PamhyrTranslate):
|
||||
)
|
||||
|
||||
self._sub_dict["long_types"] = {
|
||||
"ND": _translate("LateralContribution", "Not defined"),
|
||||
"ND": self._dict["not_defined"],
|
||||
"LC": _translate("LateralContribution", "Lateral contribution"),
|
||||
"RA": _translate("LateralContribution", "Rain"),
|
||||
"EV": _translate("LateralContribution", "Evaporation"),
|
||||
}
|
||||
|
||||
self._dict["x"] = _translate("Geometry", "X (m)")
|
||||
self._dict["y"] = _translate("Geometry", "Y (m)")
|
||||
self._dict["z"] = _translate("Geometry", "Z (m)")
|
||||
|
||||
self._sub_dict["table_headers"] = {
|
||||
"name": _translate("LateralContribution", "Name"),
|
||||
"type": _translate("LateralContribution", "Type"),
|
||||
"edge": _translate("LateralContribution", "Reach"),
|
||||
"name": self._dict["name"],
|
||||
"type": self._dict["type"],
|
||||
"edge": self._dict["reach"],
|
||||
"begin_kp": _translate("LateralContribution", "Begin kp (m)"),
|
||||
"end_kp": _translate("LateralContribution", "End kp (m)")
|
||||
}
|
||||
+319
-74
@@ -18,9 +18,13 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import logging
|
||||
import subprocess
|
||||
from queue import Queue
|
||||
from functools import reduce
|
||||
from platformdirs import user_cache_dir
|
||||
from tools import logger_exception
|
||||
|
||||
from PyQt5 import QtGui
|
||||
from PyQt5.QtGui import (
|
||||
@@ -29,19 +33,26 @@ from PyQt5.QtGui import (
|
||||
|
||||
from PyQt5.QtCore import (
|
||||
Qt, QTranslator, QEvent, QUrl, QTimer,
|
||||
QCoreApplication,
|
||||
QCoreApplication, QMutex,
|
||||
)
|
||||
from PyQt5.QtWidgets import (
|
||||
QMainWindow, QApplication, QAction,
|
||||
QFileDialog, QShortcut, QMenu, QToolBar,
|
||||
QMessageBox, QProgressDialog,
|
||||
QMessageBox, QProgressDialog, QTabWidget,
|
||||
)
|
||||
from PyQt5.uic import loadUi
|
||||
|
||||
from Modules import Modules
|
||||
|
||||
from View.Tools.ASubWindow import WindowToolKit
|
||||
from View.Tools.ListedSubWindow import ListedSubWindow
|
||||
from View.DummyWindow import DummyWindow
|
||||
|
||||
from View.Translate import MainTranslate
|
||||
|
||||
from View.MainWindowTabInfo import WidgetInfo
|
||||
from View.MainWindowTabChecker import WidgetChecker
|
||||
|
||||
from View.Configure.Window import ConfigureWindow
|
||||
from View.Study.Window import NewStudyWindow
|
||||
from View.About.Window import AboutWindow
|
||||
@@ -56,10 +67,13 @@ from View.Stricklers.Window import StricklersWindow
|
||||
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
|
||||
from View.Results.Window import ResultsWindow
|
||||
from View.Results.ReadingResultsDialog import ReadingResultsDialog
|
||||
from View.Debug.Window import ReplWindow
|
||||
|
||||
# Optional internal display of documentation for make the application
|
||||
@@ -73,13 +87,10 @@ except Exception as e:
|
||||
|
||||
from Model.Study import Study
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
no_model_action = [
|
||||
"action_menu_new", "action_menu_open", "action_menu_import_mage",
|
||||
"action_menu_import_rubarbe", "action_toolBar_open",
|
||||
"action_menu_new", "action_menu_open", "action_toolBar_open",
|
||||
]
|
||||
|
||||
model_action = [
|
||||
@@ -89,17 +100,14 @@ model_action = [
|
||||
]
|
||||
|
||||
other_model_action = [
|
||||
"action_toolBar_run_solver", "action_toolBar_kill_solver"
|
||||
"action_toolBar_run_solver",
|
||||
]
|
||||
|
||||
define_model_action = [
|
||||
# Toolbar
|
||||
"action_toolBar_network", "action_toolBar_geometry",
|
||||
"action_toolBar_mesh", "action_toolBar_run_meshing_tool",
|
||||
"action_toolBar_boundary_cond", "action_toolBar_lateral_contrib",
|
||||
"action_toolBar_spills", "action_toolBar_frictions",
|
||||
"action_toolBar_stricklers", "action_toolBar_building",
|
||||
"action_toolBar_initial_cond",
|
||||
"action_toolBar_frictions", "action_toolBar_initial_cond",
|
||||
# Menu
|
||||
"action_menu_run_solver", "action_menu_numerical_parameter",
|
||||
"action_menu_edit_network", "action_menu_edit_geometry",
|
||||
@@ -107,8 +115,10 @@ define_model_action = [
|
||||
"action_menu_edit_friction", "action_menu_edit_lateral_contribution",
|
||||
"action_menu_run_solver", "action_menu_sediment_layers",
|
||||
"action_menu_edit_reach_sediment_layers", "action_menu_edit_reservoirs",
|
||||
"action_menu_edit_hydraulic_structures",
|
||||
"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 = (
|
||||
@@ -128,6 +138,9 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
# Model
|
||||
self._study = None
|
||||
|
||||
# Translate
|
||||
self._trad = MainTranslate()
|
||||
|
||||
# Results
|
||||
self._last_solver = None
|
||||
self._last_results = None
|
||||
@@ -138,16 +151,14 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
self
|
||||
)
|
||||
|
||||
self.setup_debug_mode(init=True)
|
||||
self.setup_tab()
|
||||
self.setup_sc()
|
||||
self.setup_connection()
|
||||
self.default_style()
|
||||
self.setup_debug_mode(init=True)
|
||||
self.setup_results()
|
||||
self.setup_timer()
|
||||
|
||||
self.trans = QTranslator(self)
|
||||
# self.ui.retranslateUi()
|
||||
|
||||
if not self.conf.close_correctly:
|
||||
if self.conf.last_study != "":
|
||||
self.dialog_reopen_study()
|
||||
@@ -165,6 +176,34 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
title += "Pamhyr2"
|
||||
self.setWindowTitle(title)
|
||||
|
||||
def setup_tab(self):
|
||||
self.setup_tab_info()
|
||||
self.setup_tab_checker()
|
||||
|
||||
def setup_tab_info(self):
|
||||
tab_widget = self.findChild(QTabWidget, "tabWidget")
|
||||
|
||||
self._tab_widget_info = WidgetInfo(
|
||||
study=self._study, parent=self
|
||||
)
|
||||
|
||||
tab_widget.addTab(
|
||||
self._tab_widget_info,
|
||||
self._trad["tab_info_name"]
|
||||
)
|
||||
|
||||
def setup_tab_checker(self):
|
||||
tab_widget = self.findChild(QTabWidget, "tabWidget")
|
||||
|
||||
self._tab_widget_checker = WidgetChecker(
|
||||
study=self._study, config=self.conf, parent=self
|
||||
)
|
||||
|
||||
tab_widget.addTab(
|
||||
self._tab_widget_checker,
|
||||
self._trad["tab_checker_name"]
|
||||
)
|
||||
|
||||
def enable_actions(self, action: str, enable: bool):
|
||||
"""Enable of disable an action componant
|
||||
|
||||
@@ -175,8 +214,11 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
Returns:
|
||||
Nothing
|
||||
"""
|
||||
logger.debug(f"Set {action} to {enable}")
|
||||
self.findChild(QAction, action).setEnabled(enable)
|
||||
qaction = self.findChild(QAction, action)
|
||||
if qaction is not None:
|
||||
qaction.setEnabled(enable)
|
||||
else:
|
||||
logger.warning(f"Set {action} to {enable}")
|
||||
|
||||
def setup_sc(self):
|
||||
self._run_sc = QShortcut(QKeySequence("F6"), self)
|
||||
@@ -200,6 +242,8 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
"action_menu_edit_network": self.open_network,
|
||||
"action_menu_edit_geometry": self.open_geometry,
|
||||
"action_menu_boundary_conditions": self.open_boundary_cond,
|
||||
"action_menu_boundary_conditions_sediment":
|
||||
self.open_boundary_cond_sed,
|
||||
"action_menu_edit_reservoirs": self.open_reservoir,
|
||||
"action_menu_edit_hydraulic_structures":
|
||||
self.open_hydraulic_structures,
|
||||
@@ -210,6 +254,8 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
"action_menu_sediment_layers": self.open_sediment_layers,
|
||||
"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,
|
||||
@@ -222,7 +268,6 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
"action_menu_mage": self.open_doc_mage,
|
||||
"action_menu_about": self.open_about,
|
||||
# ToolBar action
|
||||
"action_toolBar_quit": self.close,
|
||||
"action_toolBar_open": self.open_model,
|
||||
"action_toolBar_save": self.save_study,
|
||||
"action_toolBar_close": self.close_model,
|
||||
@@ -230,22 +275,21 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
# Current actions
|
||||
"action_toolBar_network": self.open_network,
|
||||
"action_toolBar_geometry": self.open_geometry,
|
||||
"action_toolBar_mesh": lambda: self.open_dummy("Mesh"),
|
||||
"action_toolBar_run_meshing_tool": self.open_solver_parameters,
|
||||
"action_toolBar_boundary_cond": self.open_boundary_cond,
|
||||
"action_toolBar_lateral_contrib": self.open_lateral_contrib,
|
||||
"action_toolBar_spills": lambda: self.open_dummy("Deversement"),
|
||||
"action_toolBar_stricklers": self.open_stricklers,
|
||||
"action_toolBar_frictions": self.open_frictions,
|
||||
"action_toolBar_building": lambda: self.open_dummy("Ouvrages"),
|
||||
"action_toolBar_initial_cond": self.open_initial_conditions,
|
||||
}
|
||||
|
||||
for action in actions:
|
||||
logger.debug("Setup connection : " + action)
|
||||
self.findChild(QAction, action)\
|
||||
.triggered.connect(actions[action])
|
||||
# action.triggered.connect(actions[action])
|
||||
qaction = self.findChild(QAction, action)
|
||||
if qaction is not None:
|
||||
qaction.triggered.connect(actions[action])
|
||||
else:
|
||||
logger.warning(
|
||||
"Setup connection : " +
|
||||
f"'{action}' to {actions[action]}"
|
||||
)
|
||||
|
||||
self._run_sc.activated.connect(self.run_lasest_solver)
|
||||
|
||||
@@ -305,18 +349,11 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
|
||||
if init:
|
||||
self.debug_action = QAction("Debug", self)
|
||||
self.debug_action.setToolTip(
|
||||
_translate("MainWindow", "Open debug window")
|
||||
)
|
||||
self.debug_action.setToolTip(self._trad["open_debug"])
|
||||
self.debug_action.triggered.connect(self.open_debug)
|
||||
|
||||
self.debug_sqlite_action = QAction("Debug SQLite", self)
|
||||
self.debug_sqlite_action.setToolTip(
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"Open SQLite debuging tool ('sqlitebrowser')"
|
||||
)
|
||||
)
|
||||
self.debug_sqlite_action.setToolTip(self._trad["open_debug_sql"])
|
||||
self.debug_sqlite_action.triggered.connect(self.open_sqlite)
|
||||
|
||||
if self.conf.debug:
|
||||
@@ -334,6 +371,10 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
self.set_debug_lvl(debug=False)
|
||||
|
||||
def setup_timer(self):
|
||||
self.setup_timer_propagation()
|
||||
self.setup_timer_backup()
|
||||
|
||||
def setup_timer_propagation(self):
|
||||
self._init_propagation_keys()
|
||||
|
||||
self._propagation_timer = QTimer(self)
|
||||
@@ -343,26 +384,80 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
self._do_propagate_update
|
||||
)
|
||||
|
||||
def _init_propagation_keys(self):
|
||||
self._propagation_keys = set()
|
||||
def get_config_backup_freq_to_sec(self):
|
||||
v = self.conf.backup_frequence.split(":")
|
||||
m = [
|
||||
(60 * 60), # Hour to sec
|
||||
60, # Minute to sec
|
||||
1 # Sec
|
||||
]
|
||||
|
||||
def _propagate_update(self, key=None):
|
||||
self._propagation_keys.add(key)
|
||||
ts = reduce(
|
||||
lambda acc, x: acc + x,
|
||||
map(
|
||||
lambda v, m: int(v) * int(m),
|
||||
v, m
|
||||
)
|
||||
)
|
||||
|
||||
return ts
|
||||
|
||||
def setup_timer_backup(self):
|
||||
self._save_mutex = QMutex()
|
||||
self._backup_timer = QTimer(self)
|
||||
|
||||
ts = self.get_config_backup_freq_to_sec()
|
||||
self._backup_timer.start(ts * 1000)
|
||||
|
||||
self._backup_timer.timeout.connect(self._backup)
|
||||
|
||||
def _do_update_config(self):
|
||||
ts = self.get_config_backup_freq_to_sec()
|
||||
logger.debug(f"Reset backup timer to {ts} second")
|
||||
|
||||
self._backup_timer.start(ts * 1000)
|
||||
|
||||
def _init_propagation_keys(self):
|
||||
self._propagation_keys = Modules(0)
|
||||
|
||||
def _propagate_update(self, key=Modules(0)):
|
||||
self._propagation_keys |= key
|
||||
logger.debug(f"Propagation keys: {self._propagation_keys}")
|
||||
|
||||
def _do_propagate_update(self):
|
||||
keys = self._propagation_keys.copy()
|
||||
self.update()
|
||||
|
||||
keys = self._propagation_keys
|
||||
if keys is Modules.NONE:
|
||||
return
|
||||
|
||||
self._init_propagation_keys()
|
||||
|
||||
for key in keys:
|
||||
if key == "window_list":
|
||||
logger.debug(f"Update window list")
|
||||
self._do_update_window_list()
|
||||
continue
|
||||
if Modules.WINDOW_LIST in keys:
|
||||
self._do_update_window_list()
|
||||
|
||||
logger.debug(f"Propagation of {key}")
|
||||
for _, window in self.sub_win_list:
|
||||
window._propagated_update(key=key)
|
||||
if Modules.CONFIG in keys:
|
||||
self._do_update_config()
|
||||
|
||||
if Modules.STUDY in keys:
|
||||
self._tab_widget_info.update()
|
||||
|
||||
logger.debug(f"Propagation of {keys}")
|
||||
for _, window in self.sub_win_list:
|
||||
window._propagated_update(key=keys)
|
||||
|
||||
self._tab_widget_checker.update(modules=keys)
|
||||
|
||||
def update(self):
|
||||
self.set_title()
|
||||
|
||||
if self._tab_widget_info.study != self._study:
|
||||
self._tab_widget_info.study = self._study
|
||||
self._tab_widget_info.update()
|
||||
|
||||
if self._tab_widget_checker.study != self._study:
|
||||
self._tab_widget_checker.study = self._study
|
||||
self._tab_widget_checker.update(modules=Modules.STUDY)
|
||||
|
||||
#########
|
||||
# MODEL #
|
||||
@@ -375,14 +470,15 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
self._study = model
|
||||
self.update_enable_action()
|
||||
self.conf.set_last_study(self._study.filename)
|
||||
self.set_title()
|
||||
|
||||
self.update()
|
||||
|
||||
def close_model(self):
|
||||
self._study = None
|
||||
self.update_enable_action()
|
||||
self.conf.set_close_correctly()
|
||||
self.set_title()
|
||||
|
||||
self.update()
|
||||
self._close_sub_window()
|
||||
|
||||
def update_enable_action(self):
|
||||
@@ -470,6 +566,9 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
if self._study.is_saved:
|
||||
return
|
||||
|
||||
self._backup_timer.blockSignals(True)
|
||||
self._save_mutex.lock()
|
||||
|
||||
sql_request_count = self._study.sql_save_request_count()
|
||||
progress = QProgressDialog(
|
||||
"Saving...", None,
|
||||
@@ -479,11 +578,22 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
progress.setWindowModality(Qt.WindowModal)
|
||||
progress.setValue(0)
|
||||
|
||||
logger.info("Save...")
|
||||
status = f"Save ({self._study.filename})..."
|
||||
self.statusbar.showMessage(status, 3000)
|
||||
logger.info(status)
|
||||
|
||||
self._study.save(
|
||||
progress=lambda: progress.setValue(progress.value() + 1)
|
||||
)
|
||||
logger.info("Done")
|
||||
|
||||
status += " Done"
|
||||
logger.info(status)
|
||||
self.statusbar.showMessage(status, 3000)
|
||||
|
||||
self.conf.set_last_study(self._study.filename)
|
||||
|
||||
self._save_mutex.unlock()
|
||||
self._backup_timer.blockSignals(False)
|
||||
|
||||
def save_as_study(self):
|
||||
"""Save current study as new file
|
||||
@@ -503,6 +613,9 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
if file_name == "":
|
||||
return
|
||||
|
||||
self._backup_timer.blockSignals(True)
|
||||
self._save_mutex.lock()
|
||||
|
||||
if file_name.rsplit(".", 1)[-1] == "pamhyr":
|
||||
logger.debug(
|
||||
"Pamhyr extention is present : " +
|
||||
@@ -525,11 +638,77 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
progress.setWindowModality(Qt.WindowModal)
|
||||
progress.setValue(0)
|
||||
|
||||
logger.info("Save...")
|
||||
status = f"Save ({self._study.filename})..."
|
||||
self.statusbar.showMessage(status, 3000)
|
||||
logger.info(status)
|
||||
|
||||
self._study.save(
|
||||
progress=lambda: progress.setValue(progress.value() + 1)
|
||||
)
|
||||
logger.info("Done")
|
||||
|
||||
status += " Done"
|
||||
logger.info(status)
|
||||
self.statusbar.showMessage(status, 3000)
|
||||
|
||||
self.conf.set_last_study(self._study.filename)
|
||||
|
||||
self._save_mutex.unlock()
|
||||
self._backup_timer.blockSignals(False)
|
||||
|
||||
def _backup(self):
|
||||
logger.debug("Backup signal...")
|
||||
if not self.conf.backup_enable:
|
||||
return
|
||||
|
||||
if self._study is None:
|
||||
return
|
||||
|
||||
if self._study.is_saved:
|
||||
return
|
||||
|
||||
self._save_mutex.lock()
|
||||
|
||||
old = self._study.filename
|
||||
file_name = ""
|
||||
if old == "" or old is None:
|
||||
file_name = os.path.join(
|
||||
user_cache_dir("pamhyr"),
|
||||
"unsaved.pamhyr.backup"
|
||||
)
|
||||
# Set backup at last study open
|
||||
self.conf.set_last_study(file_name)
|
||||
else:
|
||||
file_name = self._study.filename + ".backup"
|
||||
|
||||
self._study.filename = file_name
|
||||
|
||||
try:
|
||||
# sql_request_count = self._study.sql_save_request_count()
|
||||
# progress = QProgressDialog(
|
||||
# "Backup...", None,
|
||||
# 0, sql_request_count,
|
||||
# parent=self
|
||||
# )
|
||||
# progress.setWindowModality(Qt.WindowModal)
|
||||
# progress.setValue(0)
|
||||
|
||||
status = f"Backup ({file_name})..."
|
||||
logger.info(status)
|
||||
self.statusbar.showMessage(status, 3000)
|
||||
|
||||
self._study.save(
|
||||
# progress=lambda: progress.setValue(progress.value() + 1)
|
||||
)
|
||||
|
||||
status += " Done"
|
||||
logger.info(status)
|
||||
self.statusbar.showMessage(status, 3000)
|
||||
|
||||
except Exception as e:
|
||||
logger_exception(e)
|
||||
|
||||
self._study.filename = old
|
||||
self._save_mutex.unlock()
|
||||
|
||||
##################
|
||||
# MSG AND DIALOG #
|
||||
@@ -553,7 +732,14 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
res = dlg.exec()
|
||||
|
||||
if res == QMessageBox.Ok:
|
||||
self.open_study(self.conf.last_study)
|
||||
old = self.conf.last_study
|
||||
file = self.dialog_reopen_study_select_backup(
|
||||
self.conf.last_study
|
||||
)
|
||||
|
||||
self.open_study(file)
|
||||
self._study.filename = old
|
||||
self.conf.set_last_study(old)
|
||||
return True
|
||||
elif res == QMessageBox.Open:
|
||||
self.open_model()
|
||||
@@ -561,6 +747,19 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
elif res == QMessageBox.Cancel:
|
||||
return False
|
||||
|
||||
def dialog_reopen_study_select_backup(self, filename):
|
||||
file = self.conf.last_study
|
||||
backup = self.conf.last_study + ".backup"
|
||||
|
||||
if os.path.exists(backup):
|
||||
file_modified_date = time.ctime(os.path.getmtime(file))
|
||||
backup_modified_date = time.ctime(os.path.getmtime(backup))
|
||||
if backup_modified_date > file_modified_date:
|
||||
logger.info(f"Select backup ({backup})")
|
||||
file = backup
|
||||
|
||||
return file
|
||||
|
||||
def dialog_close(self, cancel=True):
|
||||
dlg = QMessageBox(self)
|
||||
|
||||
@@ -607,7 +806,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
return
|
||||
|
||||
def _update_window_list(self):
|
||||
self._propagation_keys.add("window_list")
|
||||
self._propagation_keys |= Modules.WINDOW_LIST
|
||||
|
||||
def _do_update_window_list(self):
|
||||
menu = self.findChild(QMenu, "menu_windows")
|
||||
@@ -635,9 +834,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
return lambda: self._activate_window(h)
|
||||
|
||||
action = QAction(window._title, self)
|
||||
action.setToolTip(
|
||||
_translate("MainWindow", "Activate this window")
|
||||
)
|
||||
action.setToolTip(self._trad["active_window"])
|
||||
h = window.hash()
|
||||
fn = lambda_generator(h)
|
||||
action.triggered.connect(fn)
|
||||
@@ -693,7 +890,10 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
dialog.setFileMode(QFileDialog.FileMode.ExistingFile)
|
||||
dialog.setDefaultSuffix(".pamhyr")
|
||||
# dialog.setFilter(dialog.filter() | QtCore.QDir.Hidden)
|
||||
dialog.setNameFilters(['PamHyr (*.pamhyr)'])
|
||||
dialog.setNameFilters([
|
||||
'Pamhyr2 (*.pamhyr)',
|
||||
'Pamhyr2 backup (*.pamhyr.backup)'
|
||||
])
|
||||
dialog.setDirectory(os.path.dirname(self.conf.last_study))
|
||||
|
||||
if dialog.exec_():
|
||||
@@ -773,15 +973,24 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
else:
|
||||
self.msg_select_reach()
|
||||
|
||||
def open_boundary_cond(self):
|
||||
def open_boundary_cond_sed(self):
|
||||
self.open_boundary_cond(tab=1)
|
||||
|
||||
def open_boundary_cond(self, tab=0):
|
||||
if self.sub_window_exists(
|
||||
BoundaryConditionWindow,
|
||||
data=[self._study, None]
|
||||
):
|
||||
bound = self.get_sub_window(
|
||||
BoundaryConditionWindow,
|
||||
data=[self._study, None]
|
||||
)
|
||||
bound.set_active_tab(tab)
|
||||
return
|
||||
|
||||
bound = BoundaryConditionWindow(study=self._study, parent=self)
|
||||
bound.show()
|
||||
bound.set_active_tab(tab)
|
||||
|
||||
def open_reservoir(self):
|
||||
if self.sub_window_exists(
|
||||
@@ -872,6 +1081,32 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
else:
|
||||
self.msg_select_reach()
|
||||
|
||||
def open_additional_files(self):
|
||||
if self._study is not None:
|
||||
if self.sub_window_exists(
|
||||
AddFileListWindow,
|
||||
data=[self._study, None]
|
||||
):
|
||||
return
|
||||
|
||||
self.additonal_files = AddFileListWindow(
|
||||
study=self._study, parent=self
|
||||
)
|
||||
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,
|
||||
@@ -964,15 +1199,20 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
sol.show()
|
||||
|
||||
def open_solver_results(self, solver, results=None):
|
||||
def reading_fn():
|
||||
self._tmp_results = results
|
||||
|
||||
# If no specific results, get last results
|
||||
if results is None:
|
||||
results = self._last_results
|
||||
def reading_fn():
|
||||
self._tmp_results = self._last_results
|
||||
|
||||
if self._last_results is None:
|
||||
results = solver.results(
|
||||
self._study,
|
||||
self._solver_workdir(solver),
|
||||
)
|
||||
def reading_fn():
|
||||
self._tmp_results = solver.results(
|
||||
self._study,
|
||||
self._solver_workdir(solver),
|
||||
)
|
||||
|
||||
# Open from file
|
||||
if type(results) is str:
|
||||
@@ -980,11 +1220,16 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
|
||||
name = os.path.basename(results).replace(".BIN", "")
|
||||
|
||||
results = solver.results(
|
||||
self._study,
|
||||
os.path.dirname(results),
|
||||
name=name
|
||||
)
|
||||
def reading_fn():
|
||||
self._tmp_results = solver.results(
|
||||
self._study,
|
||||
os.path.dirname(results),
|
||||
name=name
|
||||
)
|
||||
|
||||
dlg = ReadingResultsDialog(reading_fn=reading_fn, parent=self)
|
||||
dlg.exec_()
|
||||
results = self._tmp_results
|
||||
|
||||
# No results available
|
||||
if results is None:
|
||||
@@ -1072,7 +1317,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
return os.path.abspath(
|
||||
os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"..", "..", "..", "doc", filename
|
||||
"..", "..", "doc", filename
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
# MainWindowTabChecker.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 queue import Queue
|
||||
from tools import timer, trace, flatten
|
||||
|
||||
from PyQt5.QtCore import (
|
||||
QThread,
|
||||
)
|
||||
|
||||
from PyQt5.QtWidgets import (
|
||||
QTableView, QListView,
|
||||
)
|
||||
|
||||
from Modules import Modules
|
||||
from Model.Study import Study
|
||||
from Solver.Solvers import solver_type_list, solver_long_name
|
||||
|
||||
from View.Tools.PamhyrWidget import PamhyrWidget
|
||||
from View.CheckList.Table import TabTableModel
|
||||
from View.CheckList.List import TabListModel
|
||||
from View.CheckList.Worker import TabWorker
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
class WidgetChecker(PamhyrWidget):
|
||||
_pamhyr_ui = "MainWindowTabCheckers"
|
||||
|
||||
def __init__(self, study=None, config=None, parent=None):
|
||||
self._study = study
|
||||
self._config = config
|
||||
|
||||
super(WidgetChecker, self).__init__(
|
||||
parent=parent
|
||||
)
|
||||
|
||||
self.setup_worker()
|
||||
self.setup_solver_list()
|
||||
self.setup_checker_list()
|
||||
self.setup_table()
|
||||
self.setup_list()
|
||||
self.setup_connections()
|
||||
|
||||
def setup_worker(self):
|
||||
self._worker_q = Queue()
|
||||
|
||||
self._worker = TabWorker(self._study, self._worker_q)
|
||||
self._worker_thread = QThread()
|
||||
self._worker.moveToThread(self._worker_thread)
|
||||
|
||||
self._worker.signalStatus.connect(self.update_thread)
|
||||
self._worker_thread.started.connect(self._worker.process)
|
||||
|
||||
self._worker_thread.start()
|
||||
|
||||
def setup_solver_list(self):
|
||||
self._solvers = list(
|
||||
map(
|
||||
lambda solver: solver_type_list[solver],
|
||||
solver_type_list
|
||||
)
|
||||
)
|
||||
|
||||
def setup_checker_list(self):
|
||||
self._checkers = flatten(
|
||||
map(
|
||||
lambda solver: solver.checkers(),
|
||||
[Study] + self._solvers
|
||||
)
|
||||
)
|
||||
|
||||
def setup_table(self):
|
||||
header = {
|
||||
'type': "Type", "study": "Study",
|
||||
**solver_long_name
|
||||
}
|
||||
|
||||
table = self.find(QTableView, f"tableView_checker")
|
||||
self._table = TabTableModel(
|
||||
table_view=table,
|
||||
table_headers=header,
|
||||
data=self._checkers,
|
||||
opt_data=Modules.modelling_list(),
|
||||
options=[],
|
||||
)
|
||||
|
||||
def setup_list(self):
|
||||
lst = self.find(QListView, f"listView_current")
|
||||
self._list = TabListModel(
|
||||
list_view=lst,
|
||||
data=[],
|
||||
)
|
||||
|
||||
lst = self.find(QListView, f"listView_errors")
|
||||
self._list_error = TabListModel(
|
||||
list_view=lst,
|
||||
data=[],
|
||||
)
|
||||
|
||||
def setup_connections(self):
|
||||
table = self.find(QTableView, f"tableView_checker")
|
||||
table.selectionModel()\
|
||||
.selectionChanged\
|
||||
.connect(self.update_selection)
|
||||
|
||||
@property
|
||||
def study(self):
|
||||
return self._study
|
||||
|
||||
@study.setter
|
||||
def study(self, study):
|
||||
self._study = study
|
||||
|
||||
def _checkers_filtered(self, modules):
|
||||
return filter(
|
||||
lambda c: c._modules in modules,
|
||||
self._checkers
|
||||
)
|
||||
|
||||
def update_selection(self):
|
||||
table = self.find(QTableView, f"tableView_checker")
|
||||
indexes = table.selectedIndexes()
|
||||
|
||||
checkers = self._table.get_checkers_from_indexes(indexes)
|
||||
self._list._data = checkers
|
||||
self._list.update()
|
||||
|
||||
def update_thread(self, key):
|
||||
if key == "progress":
|
||||
self._table.update()
|
||||
self.update_errors()
|
||||
|
||||
def update_errors(self):
|
||||
checkers = list(
|
||||
filter(
|
||||
lambda c: c.is_error() or c.is_warning(),
|
||||
self._checkers
|
||||
)
|
||||
)
|
||||
|
||||
self._list_error._data = checkers
|
||||
self._list_error.update()
|
||||
|
||||
def update(self, modules=Modules.NONE):
|
||||
if modules is Modules.NONE:
|
||||
return
|
||||
|
||||
if Modules.STUDY in modules:
|
||||
self._worker.study = self._study
|
||||
|
||||
for checker in self._checkers:
|
||||
if self._study is None:
|
||||
checker.reset()
|
||||
|
||||
self._worker_q.put(checker)
|
||||
|
||||
self._table.update()
|
||||
return
|
||||
|
||||
for checker in self._checkers_filtered(modules):
|
||||
checker.reset()
|
||||
self._worker_q.put(checker)
|
||||
@@ -0,0 +1,202 @@
|
||||
# MainWindowTabInfo.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 tools import timer, trace
|
||||
|
||||
from View.Tools.PamhyrWidget import PamhyrWidget
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
class WidgetInfo(PamhyrWidget):
|
||||
_pamhyr_ui = "MainWindowTabInfo"
|
||||
|
||||
color_grey = "<font color='grey'>"
|
||||
color_end = "</font>"
|
||||
|
||||
def __init__(self, study=None, parent=None):
|
||||
self._study = study
|
||||
|
||||
super(WidgetInfo, self).__init__(
|
||||
parent=parent
|
||||
)
|
||||
|
||||
self.set_initial_values()
|
||||
|
||||
@property
|
||||
def study(self):
|
||||
return self._study
|
||||
|
||||
@study.setter
|
||||
def study(self, study):
|
||||
self._study = study
|
||||
|
||||
def set_initial_values(self):
|
||||
self.set_label_text("label_study_name", "")
|
||||
self.set_text_edit_text("textBrowser_study", "")
|
||||
|
||||
self.set_label_text("label_current_reach", "None")
|
||||
self.set_label_text("label_nodes", "-")
|
||||
self.set_label_text("label_edges", "-")
|
||||
|
||||
self.set_label_text("label_cs", "-")
|
||||
self.set_label_text("label_points", "-")
|
||||
|
||||
self.set_label_text("label_res", "-")
|
||||
self.set_label_text("label_bc", "-")
|
||||
self.set_label_text("label_lc", "-")
|
||||
self.set_label_text("label_hs", "-")
|
||||
|
||||
def update(self):
|
||||
if self._study is None:
|
||||
self.set_initial_values()
|
||||
return
|
||||
|
||||
self.set_label_text("label_study_name", self._study.name)
|
||||
self.set_text_edit_text("textBrowser_study", self._study.description)
|
||||
|
||||
self.set_network_values()
|
||||
self.set_geometry_values()
|
||||
|
||||
def set_network_values(self):
|
||||
river = self._study.river
|
||||
|
||||
n_nodes = river.enable_nodes_counts()
|
||||
n_d_nodes = river.nodes_counts() - n_nodes
|
||||
n_edges = river.enable_edges_counts()
|
||||
n_d_edges = river.edges_counts() - n_edges
|
||||
|
||||
self.set_label_text(
|
||||
"label_nodes",
|
||||
f"{n_nodes} {self.color_grey}({n_d_nodes}){self.color_end}"
|
||||
)
|
||||
self.set_label_text(
|
||||
"label_edges",
|
||||
f"{n_edges} {self.color_grey}({n_d_edges}){self.color_end}"
|
||||
)
|
||||
|
||||
current = river.current_reach()
|
||||
if current is not None:
|
||||
name = current.reach.name
|
||||
else:
|
||||
name = "None"
|
||||
self.set_label_text("label_current_reach", name)
|
||||
|
||||
self.set_network_values_ext(river)
|
||||
|
||||
def set_network_values_ext(self, river):
|
||||
self.set_network_values_ext_reservoir(river)
|
||||
self.set_network_values_ext_bc(river)
|
||||
self.set_network_values_ext_lc(river)
|
||||
|
||||
def set_network_values_ext_reservoir(self, river):
|
||||
n_res = 0
|
||||
n_na_res = 0
|
||||
for res in river.reservoir.lst:
|
||||
if res.node is not None:
|
||||
n_res += 1
|
||||
else:
|
||||
n_na_res += 1
|
||||
|
||||
self.set_label_text(
|
||||
"label_res",
|
||||
f"{n_res} {self.color_grey}({n_na_res}){self.color_end}"
|
||||
)
|
||||
|
||||
def set_network_values_ext_bc(self, river):
|
||||
bc = river.boundary_condition
|
||||
n_bc = 0
|
||||
n_na_bc = 0
|
||||
|
||||
for tab in bc._tabs_list:
|
||||
for c in bc.get_tab(tab):
|
||||
if c.node is not None:
|
||||
n_bc += 1
|
||||
else:
|
||||
n_na_bc += 1
|
||||
|
||||
self.set_label_text(
|
||||
"label_bc",
|
||||
f"{n_bc} {self.color_grey}({n_na_bc}){self.color_end}"
|
||||
)
|
||||
|
||||
def set_network_values_ext_lc(self, river):
|
||||
lc = river.lateral_contribution
|
||||
n_lc = 0
|
||||
n_na_lc = 0
|
||||
|
||||
for tab in lc._tabs_list:
|
||||
for c in lc.get_tab(tab):
|
||||
if c.edge is not None:
|
||||
n_lc += 1
|
||||
else:
|
||||
n_na_lc += 1
|
||||
|
||||
self.set_label_text(
|
||||
"label_lc",
|
||||
f"{n_lc} {self.color_grey}({n_na_lc}){self.color_end}"
|
||||
)
|
||||
|
||||
def set_geometry_values(self):
|
||||
river = self._study.river
|
||||
|
||||
n_cs = 0
|
||||
n_d_cs = 0
|
||||
n_points = 0
|
||||
n_d_points = 0
|
||||
|
||||
for edge in river.edges():
|
||||
for profile in edge.reach.profiles:
|
||||
if edge.is_enable():
|
||||
n_points += len(profile)
|
||||
n_cs += 1
|
||||
else:
|
||||
n_d_points += len(profile)
|
||||
n_d_cs += 1
|
||||
|
||||
self.set_label_text(
|
||||
"label_cs",
|
||||
f"{n_cs} {self.color_grey}({n_d_cs}){self.color_end}"
|
||||
)
|
||||
self.set_label_text(
|
||||
"label_points",
|
||||
f"{n_points} {self.color_grey}({n_d_points}){self.color_end}"
|
||||
)
|
||||
|
||||
self.set_geometry_values_ext(river)
|
||||
|
||||
def set_geometry_values_ext(self, river):
|
||||
self.set_geometry_values_ext_hs(river)
|
||||
|
||||
def set_geometry_values_ext_hs(self, river):
|
||||
hs = river.hydraulic_structures
|
||||
n_hs = 0
|
||||
n_na_hs = 0
|
||||
|
||||
for h in hs.lst:
|
||||
if h.input_reach is not None and h.input_kp is not None:
|
||||
n_hs += 1
|
||||
else:
|
||||
n_na_hs += 1
|
||||
|
||||
self.set_label_text(
|
||||
"label_hs",
|
||||
f"{n_hs} {self.color_grey}({n_na_hs}){self.color_end}"
|
||||
)
|
||||
@@ -0,0 +1,112 @@
|
||||
# ContextMenu.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.QtWidgets import (
|
||||
QMenu,
|
||||
)
|
||||
|
||||
|
||||
class AbstractMenu(object):
|
||||
def __init__(self, event=None, pos=None, items=[],
|
||||
graph=None, trad=None, parent=None):
|
||||
super(AbstractMenu, self).__init__()
|
||||
|
||||
self._menu = QMenu(parent)
|
||||
self._event = event
|
||||
self._pos = pos
|
||||
self._items = items
|
||||
|
||||
self._graph = graph
|
||||
self._trad = trad
|
||||
self._parent = parent
|
||||
|
||||
def map_to_global(self):
|
||||
return self._parent.mapToGlobal(self._event.pos())
|
||||
|
||||
def _exec(self):
|
||||
return self._menu.exec_(self.map_to_global())
|
||||
|
||||
def run(self):
|
||||
return
|
||||
|
||||
|
||||
class DefaultMenu(AbstractMenu):
|
||||
def run(self):
|
||||
add_node = self._menu.addAction(self._trad["menu_add_node"])
|
||||
|
||||
action = self._exec()
|
||||
if action == add_node:
|
||||
self._parent.add_node(self._pos)
|
||||
|
||||
|
||||
class NodeMenu(AbstractMenu):
|
||||
def run(self):
|
||||
item = self._items[0]
|
||||
node = item.node
|
||||
|
||||
delete = self._menu.addAction(self._trad["menu_del_node"])
|
||||
|
||||
is_internal = self._graph.is_internal_node(node)
|
||||
if is_internal:
|
||||
res = self._graph.reservoir.get_assoc_to_node(node)
|
||||
if res is not None:
|
||||
edt_res = self._menu.addAction(
|
||||
self._trad["menu_edit_res_node"]
|
||||
)
|
||||
del_res = self._menu.addAction(
|
||||
self._trad["menu_del_res_node"]
|
||||
)
|
||||
res_edit = True
|
||||
else:
|
||||
add_res = self._menu.addAction(self._trad["menu_add_res_node"])
|
||||
res_edit = False
|
||||
|
||||
action = self._exec()
|
||||
if action == delete:
|
||||
self._parent.del_node(item)
|
||||
elif is_internal:
|
||||
if res_edit:
|
||||
if action == edt_res:
|
||||
self._parent.edit_node_reservoir(node)
|
||||
elif action == del_res:
|
||||
self._parent.del_node_reservoir(node)
|
||||
else:
|
||||
if action == add_res:
|
||||
self._parent.add_node_reservoir(node)
|
||||
|
||||
|
||||
class EdgeMenu(AbstractMenu):
|
||||
def run(self):
|
||||
it = self._items[0]
|
||||
|
||||
reverse = self._menu.addAction(self._trad["menu_rev_edge"])
|
||||
delete = self._menu.addAction(self._trad["menu_del_edge"])
|
||||
if self._parent.graph.is_enable_edge(it.edge):
|
||||
enable = self._menu.addAction(self._trad["menu_dis_edge"])
|
||||
is_enable = True
|
||||
else:
|
||||
enable = self._menu.addAction(self._trad["menu_ena_edge"])
|
||||
is_enable = False
|
||||
|
||||
action = self._exec()
|
||||
if action == delete:
|
||||
self._parent.del_edge(it)
|
||||
elif action == enable:
|
||||
self._parent.enable_edge(it, is_enable)
|
||||
elif action == reverse:
|
||||
self._parent.reverse_edge(it)
|
||||
@@ -39,6 +39,9 @@ from Model.Network.Edge import Edge
|
||||
from Model.Network.Graph import Graph
|
||||
|
||||
from View.Network.UndoCommand import *
|
||||
from View.Network.ContextMenu import (
|
||||
DefaultMenu, NodeMenu, EdgeMenu,
|
||||
)
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
@@ -292,14 +295,15 @@ class GraphWidget(QGraphicsView):
|
||||
|
||||
def __init__(self, graph, parent=None,
|
||||
min_size=(400, 400), max_size=None,
|
||||
size=None, only_display=False, undo=None):
|
||||
size=None, only_display=False, undo=None,
|
||||
trad=None):
|
||||
super(GraphWidget, self).__init__(parent=parent)
|
||||
|
||||
self.timerId = 0
|
||||
self.parent = parent
|
||||
self._state = "move"
|
||||
self._only_display = only_display
|
||||
self._undo = undo
|
||||
self._trad = trad
|
||||
|
||||
self.graph = graph
|
||||
|
||||
@@ -449,6 +453,15 @@ class GraphWidget(QGraphicsView):
|
||||
if type(i) is NodeItem:
|
||||
self.texts[i].rename()
|
||||
|
||||
def add_node_reservoir(self, node):
|
||||
self.parent.add_node_reservoir(node)
|
||||
|
||||
def del_node_reservoir(self, node):
|
||||
self.parent.del_node_reservoir(node)
|
||||
|
||||
def edit_node_reservoir(self, node):
|
||||
self.parent.edit_node_reservoir(node)
|
||||
|
||||
def enable_edge(self, edge, prev):
|
||||
self._undo.push(
|
||||
EnableEdgeCommand(
|
||||
@@ -482,7 +495,7 @@ class GraphWidget(QGraphicsView):
|
||||
|
||||
Args:
|
||||
node1: The source node
|
||||
node2: The destination node
|
||||
node2: The desitnation node
|
||||
|
||||
Returns:
|
||||
Nothing
|
||||
@@ -610,11 +623,18 @@ class GraphWidget(QGraphicsView):
|
||||
Returns:
|
||||
Nothing
|
||||
"""
|
||||
previous_node = self._selected_new_edge_src_node
|
||||
self._selected_new_edge_src_node = node
|
||||
try:
|
||||
previous_node = self._selected_new_edge_src_node
|
||||
self._selected_new_edge_src_node = node
|
||||
|
||||
if previous_node:
|
||||
previous_node.update()
|
||||
if node is None:
|
||||
if self.tmp_line is not None:
|
||||
self.tmp_line = None
|
||||
|
||||
if previous_node is not None:
|
||||
previous_node.update()
|
||||
except Exception as e:
|
||||
logger.warning(str(e))
|
||||
|
||||
def current_edge(self):
|
||||
"""The current selected edge
|
||||
@@ -718,6 +738,7 @@ class GraphWidget(QGraphicsView):
|
||||
nodes = list(filter(lambda i: type(i) is NodeItem, items))
|
||||
if not nodes:
|
||||
self.add_node(pos)
|
||||
self.set_selected_new_edge_src_node(None)
|
||||
else:
|
||||
if self.selected_new_edge_src_node() is None:
|
||||
self.set_selected_new_edge_src_node(nodes[0])
|
||||
@@ -796,16 +817,18 @@ class GraphWidget(QGraphicsView):
|
||||
# If state is "move"
|
||||
if self._state == "move":
|
||||
# Move on scene
|
||||
if (not self.selected_item() and
|
||||
event.buttons() & Qt.LeftButton):
|
||||
old_p = self.mapToScene(self.m_origin_x, self.m_origin_y)
|
||||
new_p = self.mapToScene(event.pos())
|
||||
translation = new_p - old_p
|
||||
if not self.selected_item():
|
||||
if event.buttons() & Qt.LeftButton:
|
||||
old_p = self.mapToScene(
|
||||
int(self.m_origin_x), int(self.m_origin_y)
|
||||
)
|
||||
new_p = self.mapToScene(event.pos())
|
||||
translation = new_p - old_p
|
||||
|
||||
self.translate(translation.x(), translation.y())
|
||||
self.translate(translation.x(), translation.y())
|
||||
|
||||
self.m_origin_x = event.x()
|
||||
self.m_origin_y = event.y()
|
||||
self.m_origin_x = event.x()
|
||||
self.m_origin_y = event.y()
|
||||
|
||||
# Propagate event
|
||||
self.update()
|
||||
@@ -813,45 +836,6 @@ class GraphWidget(QGraphicsView):
|
||||
|
||||
# Contextual menu
|
||||
|
||||
def _menu_default(self, event, pos, items, menu):
|
||||
add_node = menu.addAction(_translate("Network", "Add node"))
|
||||
|
||||
action = menu.exec_(self.mapToGlobal(event.pos()))
|
||||
|
||||
if action == add_node:
|
||||
self.add_node(pos)
|
||||
|
||||
def _menu_node(self, event, pos, items, menu):
|
||||
delete = menu.addAction(_translate("Network", "Delete the node"))
|
||||
disable = menu.addAction(_translate("Network", "Disable the node"))
|
||||
|
||||
action = menu.exec_(self.mapToGlobal(event.pos()))
|
||||
|
||||
if action == delete:
|
||||
self.del_node(items[0])
|
||||
|
||||
def _menu_edge(self, event, pos, items, menu):
|
||||
delete = menu.addAction(_translate("Network", "Delete the reach"))
|
||||
|
||||
if self.graph.is_enable_edge(items[0].edge):
|
||||
enable = menu.addAction(_translate("Network", "Disable the reach"))
|
||||
is_enable = True
|
||||
else:
|
||||
enable = menu.addAction(_translate("Network", "Enable the reach"))
|
||||
is_enable = False
|
||||
|
||||
reverse = menu.addAction(_translate(
|
||||
"Network", "Reverse the reach orientation"))
|
||||
|
||||
action = menu.exec_(self.mapToGlobal(event.pos()))
|
||||
|
||||
if action == delete:
|
||||
self.del_edge(items[0])
|
||||
elif action == enable:
|
||||
self.enable_edge(items[0], is_enable)
|
||||
elif action == reverse:
|
||||
self.reverse_edge(items[0])
|
||||
|
||||
def contextMenuEvent(self, event):
|
||||
if self._only_display:
|
||||
return
|
||||
@@ -859,10 +843,17 @@ class GraphWidget(QGraphicsView):
|
||||
pos = self.mapToScene(event.pos())
|
||||
items = self.items(event.pos())
|
||||
|
||||
menu = QMenu(self)
|
||||
# Select current menu
|
||||
if len(items) == 0:
|
||||
self._menu_default(event, pos, items, menu)
|
||||
m_type = DefaultMenu
|
||||
elif type(items[0]) is NodeItem:
|
||||
self._menu_node(event, pos, items, menu)
|
||||
m_type = NodeMenu
|
||||
elif type(items[0]) is EdgeItem:
|
||||
self._menu_edge(event, pos, items, menu)
|
||||
m_type = EdgeMenu
|
||||
|
||||
# Create and exec menu
|
||||
m = m_type(
|
||||
event=event, pos=pos, items=items,
|
||||
graph=self.graph, trad=self._trad, parent=self
|
||||
)
|
||||
m.run()
|
||||
+54
-11
@@ -36,6 +36,7 @@ from PyQt5.QtWidgets import (
|
||||
QUndoStack, QShortcut,
|
||||
)
|
||||
|
||||
from Modules import Modules
|
||||
from Model.River import RiverNode, RiverReach, River
|
||||
|
||||
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||
@@ -46,6 +47,11 @@ from View.Network.Table import (
|
||||
ComboBoxDelegate, NodeTableModel, EdgeTableModel,
|
||||
)
|
||||
|
||||
# Reservoir short cut
|
||||
from View.Reservoir.Edit.Window import EditReservoirWindow
|
||||
import View.Reservoir.UndoCommand as ResUndoCommand
|
||||
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
@@ -69,6 +75,7 @@ class NetworkWindow(PamhyrWindow):
|
||||
)
|
||||
|
||||
self._graph = study.river
|
||||
self._reservoir = study.river.reservoir
|
||||
self._table_headers_node = self._trad.get_dict("table_headers_node")
|
||||
self._table_headers_edge = self._trad.get_dict("table_headers_edge")
|
||||
|
||||
@@ -117,19 +124,20 @@ class NetworkWindow(PamhyrWindow):
|
||||
def setup_graph(self):
|
||||
self._graph_widget = GraphWidget(
|
||||
self._graph, parent=self,
|
||||
undo=self._undo_stack
|
||||
undo=self._undo_stack,
|
||||
trad=self._trad,
|
||||
)
|
||||
self._graph_layout = self.find(QHBoxLayout, "horizontalLayout_graph")
|
||||
self._graph_layout.addWidget(self._graph_widget)
|
||||
|
||||
def setup_connections(self):
|
||||
self._nodes_model.dataChanged.connect(self._reachs_model.update)
|
||||
self._nodes_model.dataChanged.connect(self.update)
|
||||
self._nodes_model.dataChanged.connect(self._graph_widget.rename_nodes)
|
||||
self._reachs_model.dataChanged.connect(
|
||||
self._graph_widget.display_update)
|
||||
self._reachs_model.dataChanged.connect(self._nodes_model.update)
|
||||
self._graph_widget.changeEdge.connect(self._reachs_model.update)
|
||||
self._graph_widget.changeNode.connect(self._nodes_model.update)
|
||||
self._reachs_model.dataChanged.connect(self.update)
|
||||
self._graph_widget.changeEdge.connect(self.update)
|
||||
self._graph_widget.changeNode.connect(self.update)
|
||||
|
||||
self.find(QAction, "action_toolBar_add").setCheckable(True)
|
||||
self.find(QAction, "action_toolBar_add").triggered.connect(
|
||||
@@ -161,16 +169,51 @@ class NetworkWindow(PamhyrWindow):
|
||||
if key == Qt.Key_Escape:
|
||||
self._graph_widget.reset_selection
|
||||
|
||||
# Redefine undo/redo method
|
||||
def add_node_reservoir(self, node):
|
||||
if self._reservoir.get_assoc_to_node(node) is None:
|
||||
self._undo_stack.push(
|
||||
ResUndoCommand.AddAndAssociateCommand(
|
||||
self._reservoir, 0, node
|
||||
)
|
||||
)
|
||||
|
||||
def del_node_reservoir(self, node):
|
||||
res = self._reservoir.get_assoc_to_node(node)
|
||||
ind = self._reservoir.index(res)
|
||||
|
||||
self._undo_stack.push(
|
||||
ResUndoCommand.DelCommand(
|
||||
self._reservoir, [ind]
|
||||
)
|
||||
)
|
||||
|
||||
def edit_node_reservoir(self, node):
|
||||
data = self._reservoir.get_assoc_to_node(node)
|
||||
|
||||
if self.sub_window_exists(
|
||||
EditReservoirWindow,
|
||||
data=[self._study, None, data]
|
||||
):
|
||||
return
|
||||
|
||||
win = EditReservoirWindow(
|
||||
data=data,
|
||||
study=self._study,
|
||||
parent=self
|
||||
)
|
||||
win.show()
|
||||
|
||||
def _undo(self):
|
||||
self._undo_stack.undo()
|
||||
self.update()
|
||||
|
||||
def _redo(self):
|
||||
self._undo_stack.redo()
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
self._reachs_model.update()
|
||||
self._nodes_model.update()
|
||||
self._graph_widget.display_update()
|
||||
|
||||
def _redo(self):
|
||||
self._undo_stack.redo()
|
||||
self._reachs_model.update()
|
||||
self._nodes_model.update()
|
||||
self._graph_widget.display_update()
|
||||
self._propagate_update(key=Modules.NETWORK)
|
||||
@@ -18,12 +18,12 @@
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||
from View.Translate import MainTranslate
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
|
||||
|
||||
class NetworkTranslate(PamhyrTranslate):
|
||||
class NetworkTranslate(MainTranslate):
|
||||
def __init__(self):
|
||||
super(NetworkTranslate, self).__init__()
|
||||
|
||||
@@ -31,13 +31,33 @@ class NetworkTranslate(PamhyrTranslate):
|
||||
"Network", "River network"
|
||||
)
|
||||
|
||||
self._dict["menu_add_node"] = _translate("Network", "Add node")
|
||||
self._dict["menu_del_node"] = _translate("Network", "Delete the node")
|
||||
self._dict["menu_edit_res_node"] = _translate(
|
||||
"Network", "Edit node reservoir"
|
||||
)
|
||||
self._dict["menu_add_res_node"] = _translate(
|
||||
"Network", "Add node reservoir"
|
||||
)
|
||||
self._dict["menu_del_res_node"] = _translate(
|
||||
"Network", "Delete node reservoir"
|
||||
)
|
||||
|
||||
self._dict["menu_del_edge"] = _translate("Network", "Delete the reach")
|
||||
self._dict["menu_ena_edge"] = _translate("Network", "Enable the reach")
|
||||
self._dict["menu_dis_edge"] = _translate("Network",
|
||||
"Disable the reach")
|
||||
self._dict["menu_rev_edge"] = _translate(
|
||||
"Network", "Reverse the reach orientation"
|
||||
)
|
||||
|
||||
self._sub_dict["table_headers_node"] = {
|
||||
"name": _translate("Network", "Name"),
|
||||
"type": _translate("Network", "Type"),
|
||||
"name": self._dict['name'],
|
||||
"type": self._dict['type'],
|
||||
}
|
||||
|
||||
self._sub_dict["table_headers_edge"] = {
|
||||
"name": _translate("Network", "Name"),
|
||||
"name": self._dict['name'],
|
||||
"node1": _translate("Network", "Source node"),
|
||||
"node2": _translate("Network", "Destination node"),
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
# 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
|
||||
from View.REPLines.UndoCommand import (
|
||||
SetCommand
|
||||
)
|
||||
|
||||
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, undo=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._undo = undo
|
||||
|
||||
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")
|
||||
solvers = set()
|
||||
|
||||
self._undo.push(
|
||||
SetCommand(
|
||||
self._rep_line,
|
||||
enabled=is_enabled,
|
||||
name=name,
|
||||
line=line,
|
||||
solvers=solvers,
|
||||
)
|
||||
)
|
||||
|
||||
self._propagate_update(key=Modules.ADDITIONAL_FILES)
|
||||
self.close()
|
||||
@@ -0,0 +1,81 @@
|
||||
# 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
|
||||
from View.REPLines.UndoCommand import (
|
||||
AddCommand, DelCommand
|
||||
)
|
||||
|
||||
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._undo.push(
|
||||
AddCommand(
|
||||
self._data, row
|
||||
)
|
||||
)
|
||||
self.update()
|
||||
|
||||
def delete(self, row):
|
||||
self._undo.push(
|
||||
DelCommand(
|
||||
self._data, row
|
||||
)
|
||||
)
|
||||
self.update()
|
||||
@@ -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"
|
||||
)
|
||||
@@ -0,0 +1,82 @@
|
||||
# UndoCommand.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 (
|
||||
QMessageBox, QUndoCommand, QUndoStack,
|
||||
)
|
||||
|
||||
|
||||
class SetCommand(QUndoCommand):
|
||||
def __init__(self, rep_line, **kwargs):
|
||||
QUndoCommand.__init__(self)
|
||||
|
||||
self._rep_line = rep_line
|
||||
self._new = kwargs
|
||||
self._old = None
|
||||
|
||||
def undo(self):
|
||||
f = self._rep_line
|
||||
|
||||
for key in self._old:
|
||||
f[key] = self._old[key]
|
||||
|
||||
def redo(self):
|
||||
f = self._rep_line
|
||||
|
||||
if self._old is None:
|
||||
self._old = {}
|
||||
for key in self._new:
|
||||
self._old[key] = f[key]
|
||||
|
||||
for key in self._new:
|
||||
f[key] = self._new[key]
|
||||
|
||||
|
||||
class AddCommand(QUndoCommand):
|
||||
def __init__(self, lines, row):
|
||||
QUndoCommand.__init__(self)
|
||||
|
||||
self._lines = lines
|
||||
self._row = row
|
||||
self._new = None
|
||||
|
||||
def undo(self):
|
||||
self._lines.delete([self._new])
|
||||
|
||||
def redo(self):
|
||||
if self._new is None:
|
||||
self._new = self._lines.new(self._row)
|
||||
else:
|
||||
self._lines.insert(self._row, self._new)
|
||||
|
||||
|
||||
class DelCommand(QUndoCommand):
|
||||
def __init__(self, lines, row):
|
||||
QUndoCommand.__init__(self)
|
||||
|
||||
self._lines = lines
|
||||
self._row = row
|
||||
self._old = self._lines.get(row)
|
||||
|
||||
def undo(self):
|
||||
self._lines.insert(self._row, self._old)
|
||||
|
||||
def redo(self):
|
||||
self._lines.delete_i([self._row])
|
||||
@@ -0,0 +1,117 @@
|
||||
# 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,
|
||||
undo=self._undo_stack,
|
||||
)
|
||||
|
||||
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()
|
||||
if len(rows) < 0:
|
||||
return
|
||||
|
||||
self._list.delete(rows[0])
|
||||
|
||||
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,
|
||||
undo=self._undo_stack,
|
||||
parent=self,
|
||||
)
|
||||
win.show()
|
||||
|
||||
def _undo(self):
|
||||
self._undo_stack.undo()
|
||||
self.update()
|
||||
|
||||
def _redo(self):
|
||||
self._undo_stack.redo()
|
||||
self.update()
|
||||
@@ -50,7 +50,7 @@ class Plot(PamhyrPlot):
|
||||
self._table_headers = self._trad.get_dict("table_headers")
|
||||
|
||||
self.label_x = self._table_headers["z"]
|
||||
self.label_y = self._table_headers["Area"]
|
||||
self.label_y = self._table_headers["area"]
|
||||
|
||||
self._isometric_axis = False
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||
from View.Translate import MainTranslate
|
||||
|
||||
from View.Reservoir.Translate import ReservoirTranslate
|
||||
|
||||
@@ -34,6 +34,6 @@ class EditReservoirTranslate(ReservoirTranslate):
|
||||
)
|
||||
|
||||
self._sub_dict["table_headers"] = {
|
||||
"z": _translate("Reservoir", "Elevation (m)"),
|
||||
"Area": _translate("Reservoir", "Area (hectare)"),
|
||||
"z": self._dict["unit_elevation"],
|
||||
"area": self._dict["unit_area"],
|
||||
}
|
||||
@@ -63,7 +63,7 @@ class EditReservoirWindow(PamhyrWindow):
|
||||
name = trad[self._pamhyr_name]
|
||||
if self._data is not None:
|
||||
node_name = (self._data.node.name if self._data.node is not None
|
||||
else _translate("Reservoir", "Not associated"))
|
||||
else trad['not_associated'])
|
||||
name += (
|
||||
f" - {study.name} " +
|
||||
f" - {self._data.name} ({self._data.id}) " +
|
||||
@@ -202,10 +202,8 @@ class EditReservoirWindow(PamhyrWindow):
|
||||
|
||||
def _undo(self):
|
||||
self._table.undo()
|
||||
self.plot.update()
|
||||
self.widget_update()
|
||||
self.update()
|
||||
|
||||
def _redo(self):
|
||||
self._table.redo()
|
||||
self.plot.update()
|
||||
self.widget_update()
|
||||
self.update()
|
||||
@@ -70,7 +70,7 @@ class ComboBoxDelegate(QItemDelegate):
|
||||
)
|
||||
|
||||
self.editor.addItems(
|
||||
[_translate("Reservoir", "Not associated")] +
|
||||
[self._trad['not_associated']] +
|
||||
nodes
|
||||
)
|
||||
|
||||
@@ -118,7 +118,7 @@ class TableModel(PamhyrTableModel):
|
||||
elif self._headers[column] == "node":
|
||||
n = self._lst.get(row).node
|
||||
if n is None:
|
||||
return _translate("Reservoir", "Not associated")
|
||||
return self._trad['not_associated']
|
||||
return n.name
|
||||
|
||||
return QVariant()
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||
from View.Translate import MainTranslate
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
|
||||
|
||||
class ReservoirTranslate(PamhyrTranslate):
|
||||
class ReservoirTranslate(MainTranslate):
|
||||
def __init__(self):
|
||||
super(ReservoirTranslate, self).__init__()
|
||||
|
||||
@@ -32,6 +32,6 @@ class ReservoirTranslate(PamhyrTranslate):
|
||||
)
|
||||
|
||||
self._sub_dict["table_headers"] = {
|
||||
"name": _translate("Reservoir", "Name"),
|
||||
"node": _translate("Reservoir", "Node")
|
||||
"name": self._dict["name"],
|
||||
"node": _translate("Reservoir", "Node"),
|
||||
}
|
||||
@@ -85,6 +85,28 @@ class AddCommand(QUndoCommand):
|
||||
self._reservoir_lst.insert(self._index, self._new)
|
||||
|
||||
|
||||
class AddAndAssociateCommand(QUndoCommand):
|
||||
def __init__(self, reservoir_lst, index, node):
|
||||
QUndoCommand.__init__(self)
|
||||
|
||||
self._reservoir_lst = reservoir_lst
|
||||
|
||||
self._new = None
|
||||
self._index = index
|
||||
self._node = node
|
||||
|
||||
def undo(self):
|
||||
self._reservoir_lst.delete_i([self._index])
|
||||
|
||||
def redo(self):
|
||||
if self._new is None:
|
||||
self._new = self._reservoir_lst.new(self._index)
|
||||
else:
|
||||
self._reservoir_lst.insert(self._index, self._new)
|
||||
|
||||
self._reservoir_lst.get(self._index).node = self._node
|
||||
|
||||
|
||||
class DelCommand(QUndoCommand):
|
||||
def __init__(self, reservoir_lst, rows):
|
||||
QUndoCommand.__init__(self)
|
||||
|
||||
@@ -33,30 +33,20 @@ class CustomPlotTranslate(ResultsTranslate):
|
||||
|
||||
# Value type
|
||||
|
||||
self._dict['time'] = _translate(
|
||||
"CustomPlot", "Time (sec)"
|
||||
)
|
||||
self._dict['kp'] = _translate(
|
||||
"CustomPlot", "Kp (m)"
|
||||
)
|
||||
self._dict['time'] = self._dict["unit_time_s"]
|
||||
self._dict['kp'] = self._dict["unit_kp"]
|
||||
self._dict['water_elevation'] = self._dict["unit_water_elevation"]
|
||||
self._dict['discharge'] = self._dict["unit_discharge"]
|
||||
self._dict['elevation'] = _translate(
|
||||
"CustomPlot", "Bed load elevation (m)"
|
||||
)
|
||||
self._dict['water_elevation'] = _translate(
|
||||
"CustomPlot", "Water elevation (m)"
|
||||
)
|
||||
self._dict['discharge'] = _translate(
|
||||
"CustomPlot", "Discharge (m³/s)"
|
||||
)
|
||||
|
||||
# Unit corresponding long name (plot axes display)
|
||||
|
||||
self._dict['0-meter'] = _translate(
|
||||
"CustomPlot", "Bed load elevation (m)"
|
||||
)
|
||||
self._dict['1-m3s'] = _translate(
|
||||
"CustomPlot", "Discharge (m³/s)"
|
||||
)
|
||||
self._dict['1-m3s'] = self._dict["unit_discharge"]
|
||||
|
||||
# SubDict
|
||||
|
||||
|
||||
@@ -43,12 +43,12 @@ class PlotAC(PamhyrPlot):
|
||||
self._current_reach_id = reach_id
|
||||
self._current_profile_id = profile_id
|
||||
|
||||
self.label_x = _translate("Results", "X (m)")
|
||||
self.label_y = _translate("MainWindow_reach", "Elevation (m)")
|
||||
self.label_x = self._trad['x']
|
||||
self.label_y = self._trad["unit_elevation"]
|
||||
|
||||
self.label_bottom = _translate("Results", "River bottom")
|
||||
self.label_water = _translate("Results", "Water elevation")
|
||||
self.label_water_max = _translate("Results", "Max water elevation")
|
||||
self.label_bottom = self._trad['label_bottom']
|
||||
self.label_water = self._trad['label_water']
|
||||
self.label_water_max = self._trad['label_water_max']
|
||||
|
||||
self._isometric_axis = False
|
||||
|
||||
|
||||
@@ -29,8 +29,6 @@ from PyQt5.QtCore import (
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
|
||||
|
||||
class PlotKPC(PamhyrPlot):
|
||||
def __init__(self, canvas=None, trad=None, toolbar=None,
|
||||
@@ -49,12 +47,12 @@ class PlotKPC(PamhyrPlot):
|
||||
self._current_reach_id = reach_id
|
||||
self._current_profile_id = profile_id
|
||||
|
||||
self.label_x = _translate("Results", "KP (m)")
|
||||
self.label_y = _translate("Results", "Elevation (m)")
|
||||
self.label_x = self._trad["unit_kp"]
|
||||
self.label_y = self._trad["unit_elevation"]
|
||||
|
||||
self.label_bottom = _translate("Results", "River bottom")
|
||||
self.label_water = _translate("Results", "Water elevation")
|
||||
self.label_water_max = _translate("Results", "Max water elevation")
|
||||
self.label_bottom = self._trad["label_bottom"]
|
||||
self.label_water = self._trad["label_water"]
|
||||
self.label_water_max = self._trad["label_water_max"]
|
||||
|
||||
self._isometric_axis = False
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
# ReadingResultsDialog.py -- Pamhyr
|
||||
# Copyright (C) 2023-2024 INRAE
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
|
||||
from tools import logger_exception
|
||||
|
||||
from View.Tools.PamhyrWindow import PamhyrDialog
|
||||
from View.Results.translate import ResultsTranslate
|
||||
|
||||
from PyQt5.QtGui import (
|
||||
QKeySequence,
|
||||
)
|
||||
|
||||
from PyQt5.QtCore import (
|
||||
Qt, QVariant, QAbstractTableModel, QTimer,
|
||||
QObject, pyqtSlot, pyqtSignal, QThread,
|
||||
)
|
||||
|
||||
from PyQt5.QtWidgets import (
|
||||
QLabel,
|
||||
)
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
class Worker(QObject):
|
||||
signalStatus = pyqtSignal(str)
|
||||
|
||||
def __init__(self, reading_fn, parent=None):
|
||||
super(self.__class__, self).__init__(parent)
|
||||
|
||||
self._reading_fn = reading_fn
|
||||
|
||||
def process(self):
|
||||
self._reading_fn()
|
||||
self.signalStatus.emit('end')
|
||||
|
||||
|
||||
class ReadingResultsDialog(PamhyrDialog):
|
||||
_pamhyr_ui = "DialogReadingResults"
|
||||
_pamhyr_name = "Reading results"
|
||||
|
||||
_spin = ["-", "\\", "|", "/"]
|
||||
|
||||
def __init__(self, reading_fn, parent=None):
|
||||
trad = ResultsTranslate()
|
||||
super(ReadingResultsDialog, self).__init__(
|
||||
title=trad[self._pamhyr_name],
|
||||
trad=trad,
|
||||
options=[],
|
||||
parent=parent
|
||||
)
|
||||
|
||||
self._reading_fn = reading_fn
|
||||
|
||||
self._init_default_values()
|
||||
|
||||
self.setup_timer()
|
||||
self.setup_worker()
|
||||
|
||||
self._timer.start(150)
|
||||
self._worker_thread.start()
|
||||
|
||||
def _init_default_values(self):
|
||||
self._spinner_step = 0
|
||||
|
||||
self.set_label_text("label_spinner", self._spin[0])
|
||||
|
||||
def setup_worker(self):
|
||||
self._worker = Worker(self._reading_fn)
|
||||
self._worker_thread = QThread(parent=self)
|
||||
self._worker.moveToThread(self._worker_thread)
|
||||
|
||||
self._worker.signalStatus.connect(self.close)
|
||||
self._worker_thread.started.connect(self._worker.process)
|
||||
|
||||
def setup_timer(self):
|
||||
self._timer = QTimer(self)
|
||||
self._timer.timeout.connect(self.update_spinner)
|
||||
|
||||
def update_spinner(self):
|
||||
self._spinner_step += 1
|
||||
self._spinner_step %= len(self._spin)
|
||||
|
||||
self.set_label_text(
|
||||
"label_spinner",
|
||||
self._spin[self._spinner_step]
|
||||
)
|
||||
|
||||
def end_worker(self):
|
||||
self._worker_thread.terminate()
|
||||
self._worker_thread.wait()
|
||||
|
||||
def close(self):
|
||||
try:
|
||||
self._timer.stop()
|
||||
self.end_worker()
|
||||
except Exception as e:
|
||||
logger_exception(e)
|
||||
|
||||
super().close()
|
||||
+27
-12
@@ -160,7 +160,10 @@ class ResultsWindow(PamhyrWindow):
|
||||
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
||||
self.canvas.setObjectName("canvas")
|
||||
self.toolbar = PamhyrPlotToolbar(
|
||||
self.canvas, self
|
||||
self.canvas, self, items=[
|
||||
"home", "move", "zoom", "save",
|
||||
"iso", "back/forward"
|
||||
]
|
||||
)
|
||||
self.plot_layout = self.find(QVBoxLayout, "verticalLayout")
|
||||
self.plot_layout.addWidget(self.toolbar)
|
||||
@@ -171,6 +174,7 @@ class ResultsWindow(PamhyrWindow):
|
||||
results=self._results,
|
||||
reach_id=0,
|
||||
profile_id=0,
|
||||
trad=self._trad,
|
||||
toolbar=self.toolbar,
|
||||
display_current=True
|
||||
)
|
||||
@@ -179,7 +183,10 @@ class ResultsWindow(PamhyrWindow):
|
||||
self.canvas_2 = MplCanvas(width=5, height=4, dpi=100)
|
||||
self.canvas_2.setObjectName("canvas_2")
|
||||
self.toolbar_2 = PamhyrPlotToolbar(
|
||||
self.canvas_2, self
|
||||
self.canvas_2, self, items=[
|
||||
"home", "move", "zoom", "save",
|
||||
"iso", "back/forward"
|
||||
]
|
||||
)
|
||||
self.plot_layout_2 = self.find(QVBoxLayout, "verticalLayout_2")
|
||||
self.plot_layout_2.addWidget(self.toolbar_2)
|
||||
@@ -190,6 +197,7 @@ class ResultsWindow(PamhyrWindow):
|
||||
results=self._results,
|
||||
reach_id=0,
|
||||
profile_id=0,
|
||||
trad=self._trad,
|
||||
toolbar=self.toolbar_2
|
||||
)
|
||||
self.plot_kpc.draw()
|
||||
@@ -197,7 +205,10 @@ class ResultsWindow(PamhyrWindow):
|
||||
self.canvas_3 = MplCanvas(width=5, height=4, dpi=100)
|
||||
self.canvas_3.setObjectName("canvas_3")
|
||||
self.toolbar_3 = PamhyrPlotToolbar(
|
||||
self.canvas_3, self
|
||||
self.canvas_3, self, items=[
|
||||
"home", "move", "zoom", "save",
|
||||
"iso", "back/forward"
|
||||
]
|
||||
)
|
||||
self.plot_layout_3 = self.find(QVBoxLayout, "verticalLayout_3")
|
||||
self.plot_layout_3.addWidget(self.toolbar_3)
|
||||
@@ -208,6 +219,7 @@ class ResultsWindow(PamhyrWindow):
|
||||
results=self._results,
|
||||
reach_id=0,
|
||||
profile_id=0,
|
||||
trad=self._trad,
|
||||
toolbar=self.toolbar_3
|
||||
)
|
||||
self.plot_ac.draw()
|
||||
@@ -215,7 +227,10 @@ class ResultsWindow(PamhyrWindow):
|
||||
self.canvas_4 = MplCanvas(width=5, height=4, dpi=100)
|
||||
self.canvas_4.setObjectName("canvas_4")
|
||||
self.toolbar_4 = PamhyrPlotToolbar(
|
||||
self.canvas_4, self
|
||||
self.canvas_4, self, items=[
|
||||
"home", "move", "zoom", "save",
|
||||
"iso", "back/forward"
|
||||
]
|
||||
)
|
||||
self.plot_layout_4 = self.find(
|
||||
QVBoxLayout, "verticalLayout_hydrograph")
|
||||
@@ -227,6 +242,7 @@ class ResultsWindow(PamhyrWindow):
|
||||
results=self._results,
|
||||
reach_id=0,
|
||||
profile_id=0,
|
||||
trad=self._trad,
|
||||
toolbar=self.toolbar_4
|
||||
)
|
||||
self.plot_h.draw()
|
||||
@@ -610,12 +626,11 @@ class ResultsWindow(PamhyrWindow):
|
||||
quotechar='|', quoting=csv.QUOTE_MINIMAL)
|
||||
|
||||
writer.writerow(["timestamp", "z", "q"])
|
||||
for profile in reach.profiles:
|
||||
timestamps = self._results.get("timestamps")
|
||||
timestamps = sorted(self._results.get("timestamps"))
|
||||
|
||||
for ts in timestamps:
|
||||
writer.writerow([
|
||||
ts,
|
||||
profile.get_ts_key(ts, "Z"),
|
||||
profile.get_ts_key(ts, "Q"),
|
||||
])
|
||||
for ts in timestamps:
|
||||
writer.writerow([
|
||||
ts,
|
||||
profile.get_ts_key(ts, "Z"),
|
||||
profile.get_ts_key(ts, "Q"),
|
||||
])
|
||||
Loaded 100 of 139 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user