mirror of
https://gitlab.com/pamhyr/pamhyr2.git
synced 2026-10-30 03:20:41 +01:00
Compare commits
No files matched your search
@@ -0,0 +1,12 @@
|
|||||||
|
# Pamhyr .editorconfig
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*.py]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
tab_width = 8
|
||||||
|
end_of_line = lf
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
+249
-115
@@ -15,96 +15,55 @@
|
|||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
|
- downloads
|
||||||
- build
|
- build
|
||||||
- test
|
- test
|
||||||
- package
|
- package
|
||||||
- release
|
- release
|
||||||
|
|
||||||
|
#############
|
||||||
|
# DOWNLOADS #
|
||||||
|
#############
|
||||||
|
|
||||||
|
dl-mage-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/Test6/downloads/packages/mage_linux.tgz
|
||||||
|
- mkdir -p mage-linux
|
||||||
|
- cd mage-linux
|
||||||
|
- tar xvf ../mage.tgz
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- mage-linux/mage
|
||||||
|
- mage-linux/mage_extraire
|
||||||
|
- mage-linux/mailleurPF
|
||||||
|
|
||||||
|
dl-mage-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/Test6/downloads/packages/mage_windows.tgz
|
||||||
|
- mkdir -p mage-windows
|
||||||
|
- cd mage-windows
|
||||||
|
- tar xvf ../mage.tgz
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- mage-windows/mage.exe
|
||||||
|
- mage-windows/mage_extraire.exe
|
||||||
|
- mage-windows/mailleurPF.exe
|
||||||
|
|
||||||
#########
|
#########
|
||||||
# BUILD #
|
# BUILD #
|
||||||
#########
|
#########
|
||||||
|
|
||||||
build-mage-linux:
|
set-version:
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- linux
|
|
||||||
rules:
|
|
||||||
- if: $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
|
||||||
script:
|
|
||||||
- curl -L -o mage.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/Test6/downloads/packages/mage_linux.tgz
|
|
||||||
- mkdir -p mage
|
|
||||||
- cd mage
|
|
||||||
- tar xvf ../mage.tgz
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- mage/mage
|
|
||||||
- mage/mage_extraire
|
|
||||||
- mage/mailleurPF
|
|
||||||
|
|
||||||
# build-mage-linux:
|
|
||||||
# stage: build
|
|
||||||
# tags:
|
|
||||||
# - linux
|
|
||||||
# rules:
|
|
||||||
# - if: $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
|
||||||
# variables:
|
|
||||||
# GIT_SUBMODULE_STRATEGY: recursive
|
|
||||||
# GIT_SUBMODULE_DEPTH: 20
|
|
||||||
# script:
|
|
||||||
# - cd mage/src/
|
|
||||||
# - mkdir -p build
|
|
||||||
# - cd build
|
|
||||||
# - cmake ..
|
|
||||||
# - make
|
|
||||||
# artifacts:
|
|
||||||
# paths:
|
|
||||||
# - mage/src/build/mage
|
|
||||||
# - mage/src/build/mage_extraire
|
|
||||||
# - mage/src/build/mailleurPF
|
|
||||||
|
|
||||||
build-mage-windows:
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- linux
|
|
||||||
rules:
|
|
||||||
- if: $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
|
||||||
script:
|
|
||||||
- curl -L -o mage.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/Test6/downloads/packages/mage_windows.tgz
|
|
||||||
- mkdir -p mage
|
|
||||||
- cd mage
|
|
||||||
- tar xvf ../mage.tgz
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- mage/mage.exe
|
|
||||||
- mage/mage_extraire.exe
|
|
||||||
- mage/mailleurPF.exe
|
|
||||||
|
|
||||||
# build-mage-windows:
|
|
||||||
# stage: build
|
|
||||||
# tags:
|
|
||||||
# - wine
|
|
||||||
# rules:
|
|
||||||
# - if: $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
|
||||||
# variables:
|
|
||||||
# GIT_SUBMODULE_STRATEGY: recursive
|
|
||||||
# GIT_SUBMODULE_DEPTH: 20
|
|
||||||
# script:
|
|
||||||
# - cd mage/src/
|
|
||||||
# - sed s/add_compile_definitions(win)/add_compile_definitions(windows)/ CMakeLists.txt > __tmp__
|
|
||||||
# - echo set(CMAKE_Fortran_COMPILER "C:/Program\ Files/gcc/bin/gfortran.exe") > CMakeLists.txt
|
|
||||||
# - echo set(CMAKE_MAKE_PROGRAM "C:/Program Files\ \(x86\)/GnuWin32/bin/make.exe") >> CMakeLists.txt
|
|
||||||
# - type __tmp__ >> CMakeLists.txt
|
|
||||||
# - mkdir build
|
|
||||||
# - cd build
|
|
||||||
# - cmake -G "MinGW Makefiles" ..
|
|
||||||
# - make
|
|
||||||
# artifacts:
|
|
||||||
# paths:
|
|
||||||
# - mage/src/build/mage.exe
|
|
||||||
# - mage/src/build/mage_extraire.exe
|
|
||||||
# - mage/src/build/mailleurPF.exe
|
|
||||||
|
|
||||||
build:
|
|
||||||
stage: build
|
stage: build
|
||||||
tags:
|
tags:
|
||||||
- linux
|
- linux
|
||||||
@@ -126,60 +85,214 @@ build-lang:
|
|||||||
paths:
|
paths:
|
||||||
- src/lang/*.qm
|
- src/lang/*.qm
|
||||||
|
|
||||||
|
build-users-doc:
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- linux
|
||||||
|
script:
|
||||||
|
- cd ./doc/users/
|
||||||
|
- ./build.sh
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- doc/users/documentation.pdf
|
||||||
|
|
||||||
|
build-developers-doc:
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- linux
|
||||||
|
script:
|
||||||
|
- cd ./doc/dev/
|
||||||
|
- ./build.sh
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- doc/dev/documentation.pdf
|
||||||
|
|
||||||
|
build-linux:
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- linux
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||||
|
needs:
|
||||||
|
- job: dl-mage-linux
|
||||||
|
artifacts: true
|
||||||
|
- job: set-version
|
||||||
|
artifacts: true
|
||||||
|
- job: build-lang
|
||||||
|
artifacts: true
|
||||||
|
- job: build-developers-doc
|
||||||
|
artifacts: true
|
||||||
|
- job: build-users-doc
|
||||||
|
artifacts: true
|
||||||
|
script:
|
||||||
|
- mkdir -p linux
|
||||||
|
- cd linux
|
||||||
|
# Setup virtual env
|
||||||
|
- python3 -m venv linux-venv
|
||||||
|
- . linux-venv/bin/activate
|
||||||
|
- pip3 install -r ../requirements.txt
|
||||||
|
# Run Pyinstaller
|
||||||
|
- pyinstaller -y --paths linux-venv/lib/python3.8/site-packages ../src/pamhyr.py
|
||||||
|
# Create directory
|
||||||
|
- mkdir -p pamhyr
|
||||||
|
- mkdir -p pamhyr/pamhyr
|
||||||
|
# Copy Pamhyr info
|
||||||
|
- cp -v ../VERSION pamhyr/pamhyr/
|
||||||
|
- cp -v ../AUTHORS pamhyr/pamhyr/
|
||||||
|
- cp -v ../LICENSE pamhyr/pamhyr/
|
||||||
|
# Copy mage
|
||||||
|
- mkdir -p pamhyr/mage
|
||||||
|
- cp -v ../mage-linux/* pamhyr/mage/
|
||||||
|
# Copy Pamhyr
|
||||||
|
- cp -r dist/pamhyr pamhyr/
|
||||||
|
# Copy Pamhyr resources
|
||||||
|
- mkdir -p pamhyr/pamhyr/View
|
||||||
|
- mkdir -p pamhyr/pamhyr/View/ui
|
||||||
|
- mkdir -p pamhyr/pamhyr/View/ui/Widgets
|
||||||
|
- cp -r ../src/View/ui/*.ui pamhyr/pamhyr/View/ui/
|
||||||
|
- cp -r ../src/View/ui/ressources/ pamhyr/pamhyr/View/ui
|
||||||
|
- cp -r ../src/View/ui/Widgets/*.ui pamhyr/pamhyr/View/ui/Widgets
|
||||||
|
# Copy lang
|
||||||
|
- mkdir -p pamhyr/pamhyr/lang
|
||||||
|
- cp -r ../src/lang/*.qm pamhyr/pamhyr/lang
|
||||||
|
# Copy tests cases
|
||||||
|
- mkdir -p pamhyr/tests_cases/
|
||||||
|
- mkdir -p pamhyr/tests_cases/Saar
|
||||||
|
- cp ../tests_cases/Saar/Saar.pamhyr pamhyr/tests_cases/Saar/
|
||||||
|
# Copy documentations
|
||||||
|
- mkdir -p pamhyr/doc/
|
||||||
|
- cp ../doc/users/documentation.pdf pamhyr/doc/Pamhyr2-users.pdf
|
||||||
|
- cp ../doc/dev/documentation.pdf pamhyr/doc/Pamhyr2-dev.pdf
|
||||||
|
# Create running script
|
||||||
|
- echo "#!/bin/sh" > pamhyr/Pamhyr2
|
||||||
|
- echo "./pamhyr/pamhyr $@" >> pamhyr/Pamhyr2
|
||||||
|
- chmod u+x pamhyr/Pamhyr2
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- linux/pamhyr
|
||||||
|
|
||||||
|
build-windows:
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- wine
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||||
|
needs:
|
||||||
|
- job: dl-mage-windows
|
||||||
|
artifacts: true
|
||||||
|
- job: set-version
|
||||||
|
artifacts: true
|
||||||
|
- job: build-lang
|
||||||
|
artifacts: true
|
||||||
|
- job: build-developers-doc
|
||||||
|
artifacts: true
|
||||||
|
- job: build-users-doc
|
||||||
|
artifacts: true
|
||||||
|
script:
|
||||||
|
- mkdir windows
|
||||||
|
- cd windows
|
||||||
|
# Setup env
|
||||||
|
- python -m pip install -r ..\requirements.txt
|
||||||
|
# Run Pyinstaller
|
||||||
|
- pyinstaller -y ..\src\pamhyr.py
|
||||||
|
# Create directory
|
||||||
|
- mkdir pamhyr
|
||||||
|
- dir
|
||||||
|
- copy ..\packages\make-windows-dir.bat .\make-windows-dir.bat
|
||||||
|
- .\make-windows-dir.bat
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- windows/pamhyr
|
||||||
|
|
||||||
#########
|
#########
|
||||||
# TESTS #
|
# TESTS #
|
||||||
#########
|
#########
|
||||||
|
|
||||||
test:
|
# test-windows:
|
||||||
stage: test
|
# stage: test
|
||||||
script:
|
# tags:
|
||||||
- echo "TODO PAMHYR tests"
|
# - wine
|
||||||
|
# needs:
|
||||||
|
# - job: set-version
|
||||||
|
# artifacts: true
|
||||||
|
# - job: build-windows
|
||||||
|
# artifacts: true
|
||||||
|
# script:
|
||||||
|
# - cd windows\pamhyr
|
||||||
|
# - pamhyr\pamhyr.exe hello
|
||||||
|
|
||||||
|
# test-linux:
|
||||||
|
# stage: test
|
||||||
|
# tags:
|
||||||
|
# - linux
|
||||||
|
# needs:
|
||||||
|
# - job: set-version
|
||||||
|
# artifacts: true
|
||||||
|
# - job: build-linux
|
||||||
|
# artifacts: true
|
||||||
|
# script:
|
||||||
|
# - cd linux/pamhyr
|
||||||
|
# - ./Pamhyr2 hello
|
||||||
|
|
||||||
############
|
############
|
||||||
# PACKAGES #
|
# PACKAGES #
|
||||||
############
|
############
|
||||||
|
|
||||||
linux-package:
|
linux-package-tar:
|
||||||
stage: package
|
stage: package
|
||||||
tags:
|
tags:
|
||||||
- release
|
- release
|
||||||
- linux
|
- linux
|
||||||
needs:
|
needs:
|
||||||
- job: build-lang
|
# - job: test-linux
|
||||||
artifacts: true
|
- job: build-linux
|
||||||
- job: build
|
|
||||||
artifacts: true
|
|
||||||
- job: build-mage-linux
|
|
||||||
artifacts: true
|
artifacts: true
|
||||||
rules:
|
rules:
|
||||||
- if: $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- packages/pamhyr-gnulinux-amd64.tar.xz
|
- linux/pamhyr-gnulinux.tar.xz
|
||||||
script:
|
script:
|
||||||
- cd packages
|
- cd linux
|
||||||
- ./linux.sh
|
- tar --xz -cf pamhyr-gnulinux.tar.xz ./pamhyr --checkpoint=.100
|
||||||
|
|
||||||
windows-package:
|
windows-package-zip:
|
||||||
|
stage: package
|
||||||
|
tags:
|
||||||
|
- release
|
||||||
|
- linux
|
||||||
|
needs:
|
||||||
|
# - job: test-windows
|
||||||
|
- job: build-windows
|
||||||
|
artifacts: true
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- windows/pamhyr-windows.zip
|
||||||
|
script:
|
||||||
|
- cd windows
|
||||||
|
- zip -r pamhyr-windows.zip pamhyr
|
||||||
|
|
||||||
|
windows-package-exe:
|
||||||
stage: package
|
stage: package
|
||||||
tags:
|
tags:
|
||||||
- release
|
- release
|
||||||
- wine
|
- wine
|
||||||
needs:
|
needs:
|
||||||
- job: build-lang
|
# - job: test-windows
|
||||||
artifacts: true
|
- job: build-windows
|
||||||
- job: build
|
|
||||||
artifacts: true
|
|
||||||
- job: build-mage-windows
|
|
||||||
artifacts: true
|
artifacts: true
|
||||||
rules:
|
rules:
|
||||||
- if: $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- packages/pamhyr-win-amd64.exe
|
- windows/pamhyr-windows.exe
|
||||||
script:
|
script:
|
||||||
- cd packages
|
- cd windows
|
||||||
- ./windows.bat
|
- copy ..\packages\make-windows-exe.bat make-windows-exe.bat
|
||||||
|
- copy ..\packages\pamhyr.nsi pamhyr.nsi
|
||||||
|
- .\make-windows-exe.bat
|
||||||
|
|
||||||
###########
|
###########
|
||||||
# RELEASE #
|
# RELEASE #
|
||||||
@@ -191,16 +304,25 @@ tag-release:
|
|||||||
- release
|
- release
|
||||||
- linux
|
- linux
|
||||||
needs:
|
needs:
|
||||||
- job: linux-package
|
- job: linux-package-tar
|
||||||
artifacts: true
|
artifacts: true
|
||||||
- job: windows-package
|
- job: windows-package-zip
|
||||||
|
artifacts: true
|
||||||
|
- job: windows-package-exe
|
||||||
|
artifacts: true
|
||||||
|
- job: build-users-doc
|
||||||
|
artifacts: true
|
||||||
|
- job: build-developers-doc
|
||||||
artifacts: true
|
artifacts: true
|
||||||
rules:
|
rules:
|
||||||
- if: $CI_COMMIT_TAG
|
- if: $CI_COMMIT_TAG
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- packages/pamhyr-gnulinux-amd64.tar.xz
|
- linux/pamhyr-gnulinux.tar.xz
|
||||||
- packages/pamhyr-win-amd64.exe
|
- windows/pamhyr-windows.zip
|
||||||
|
- windows/pamhyr-windows.exe
|
||||||
|
- doc/dev/documentation.pdf
|
||||||
|
- doc/users/documentation.pdf
|
||||||
script:
|
script:
|
||||||
- cd packages
|
- cd packages
|
||||||
release:
|
release:
|
||||||
@@ -210,11 +332,23 @@ tag-release:
|
|||||||
ref: '$CI_COMMIT_SHA'
|
ref: '$CI_COMMIT_SHA'
|
||||||
assets:
|
assets:
|
||||||
links:
|
links:
|
||||||
- name: 'GNU/Linux amd64 (tar.xz)'
|
- name: 'GNU/Linux (tar.xz)'
|
||||||
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/packages/pamhyr-gnulinux-amd64.tar.xz'
|
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/linux/pamhyr-gnulinux.tar.xz'
|
||||||
filepath: '/packages/pamhyr-gnulinux-amd64.tar.xz'
|
filepath: '/linux/pamhyr-gnulinux.tar.xz'
|
||||||
link_type: 'package'
|
link_type: 'package'
|
||||||
- name: 'Windows amd64 (exe)'
|
- name: 'Windows (exe)'
|
||||||
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/packages/pamhyr-win-amd64.exe'
|
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/windows/pamhyr-windows.exe'
|
||||||
filepath: '/packages/pamhyr-win-amd64.exe'
|
filepath: '/windows/pamhyr-windows.exe'
|
||||||
link_type: 'package'
|
link_type: 'package'
|
||||||
|
- name: 'Windows (zip)'
|
||||||
|
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/windows/pamhyr-windows.zip'
|
||||||
|
filepath: '/windows/pamhyr-windows.zip'
|
||||||
|
link_type: 'package'
|
||||||
|
- name: 'User documentations (pdf)'
|
||||||
|
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/doc/users/documentation.pdf'
|
||||||
|
filepath: '/doc/users/documentation.pdf'
|
||||||
|
link_type: 'other'
|
||||||
|
- name: 'Dev documentations (pdf)'
|
||||||
|
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/doc/dev/documentation.pdf'
|
||||||
|
filepath: '/doc/dev/documentation.pdf'
|
||||||
|
link_type: 'other'
|
||||||
@@ -47,5 +47,4 @@ pip3 install -r requirements.txt
|
|||||||
|
|
||||||
# Run pamhyr
|
# Run pamhyr
|
||||||
./src/pamhyr.py
|
./src/pamhyr.py
|
||||||
|
|
||||||
```
|
```
|
||||||
Executable
+10
@@ -0,0 +1,10 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
# Build the PDF
|
||||||
|
|
||||||
|
emacs -Q -q -nw --batch \
|
||||||
|
--eval "(require 'org)" \
|
||||||
|
--eval "(require 'ox-latex)" \
|
||||||
|
--eval "(load-file \"../tools/setup.el\")" \
|
||||||
|
--file ./documentation.org \
|
||||||
|
-f org-latex-export-to-pdf
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../tools/ref.bib
|
||||||
@@ -0,0 +1,551 @@
|
|||||||
|
# documentation.org -- Pamhyr developers documentation
|
||||||
|
# Copyright (C) 2023 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#+STARTUP: indent
|
||||||
|
|
||||||
|
#+INCLUDE: ../tools/macro.org
|
||||||
|
#+INCLUDE: ../tools/latex.org
|
||||||
|
|
||||||
|
#+TITLE: Developers documentation
|
||||||
|
#+SUBTITLE: Version: {{{version}}}
|
||||||
|
#+AUTHOR: {{{INRAE}}}
|
||||||
|
|
||||||
|
#+OPTIONS: toc:t
|
||||||
|
#+LANGUAGE: UKenglish
|
||||||
|
|
||||||
|
#+NAME: attr_wrap
|
||||||
|
#+HEADER: :var width="\\textwidth"
|
||||||
|
#+HEADER: :var caption=""
|
||||||
|
#+HEADER: :var smallcaption=""
|
||||||
|
#+HEADER: :var name=""
|
||||||
|
#+HEADER: :var data=""
|
||||||
|
#+HEADER: :var float="nil"
|
||||||
|
#+BEGIN_SRC sh :results output :exports none
|
||||||
|
echo "#+CAPTION[$smallcaption]: $caption"
|
||||||
|
echo "#+NAME: $name"
|
||||||
|
echo "#+ATTR_LATEX: :width $width :float $float"
|
||||||
|
echo "$data"
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
#+BEGIN_abstract
|
||||||
|
This document is for the use of developers. It describes the project
|
||||||
|
architecture, the tools available to assist development and
|
||||||
|
debugging. It also describes the procedures for creating packages and
|
||||||
|
the configurations required to set up the gitlab runners. Finally,
|
||||||
|
this document explains how documentation is written and modified, and
|
||||||
|
how to contribute to the project by modifying, improving or adding
|
||||||
|
documentation, translations or code.
|
||||||
|
#+END_abstract
|
||||||
|
|
||||||
|
* Introduction
|
||||||
|
|
||||||
|
Pamhyr2 is free and open source software (FOSS) graphical user
|
||||||
|
interface (GUI) for 1D hydro-sedimentary modelling of rivers developed
|
||||||
|
in Python (with version 3.8). It use PyQt at version 5 and matplotlib
|
||||||
|
in version 3.4.1 or later for the user insterface (see
|
||||||
|
{{{file(/requirements.txt)}}} for details). The architecture of
|
||||||
|
project code follow the Qt Model/View architecture [fn:qt-arch] (see
|
||||||
|
details in section [[Architecture]]). Pamhyr2 packages can be build
|
||||||
|
manually (see section [[Building packages]]), but there are automatically
|
||||||
|
build with the gitlab-ci (see the section [[Setup the CI
|
||||||
|
environment]]). Documentation files are written with org-mode[fn:org],
|
||||||
|
let see section [[Documentation files]]. Finally, to see the contribution
|
||||||
|
rules, see the section [[How to contribute?]].
|
||||||
|
|
||||||
|
[fn:qt-arch] Qt Model/View documentation:
|
||||||
|
https://doc.qt.io/qt-5/model-view-programming.html (last access
|
||||||
|
2023-09-15)
|
||||||
|
[fn:org] The org-mode website: https://orgmode.org/ (last access
|
||||||
|
2023-09-15)
|
||||||
|
|
||||||
|
* TODO Architecture
|
||||||
|
|
||||||
|
Pamhyr2 architecture is based on Qt Model/View programming[fn:qt-mv] architecture.
|
||||||
|
|
||||||
|
#+name: graph-pipeline
|
||||||
|
#+header: :results drawer
|
||||||
|
#+header: :exports results
|
||||||
|
#+header: :post attr_wrap(width="12cm", data=*this*, name="graph-pipeline", caption="Pamhyr2 solver execution pipeline architecture scheme", float="t")
|
||||||
|
#+begin_src dot :file "images/graph-pipeline.png" :cache no
|
||||||
|
digraph {
|
||||||
|
node[colorscheme=set19,shape=box,style="filled",fillcolor=9];
|
||||||
|
|
||||||
|
subgraph cluster0 {
|
||||||
|
label="Pamhyr2"
|
||||||
|
config[label="Config",fillcolor=5];
|
||||||
|
model[label="Model",fillcolor=2];
|
||||||
|
obj[label="Solver",fillcolor=6];
|
||||||
|
results[label="Results",fillcolor=2];
|
||||||
|
view[label="View",fillcolor=1];
|
||||||
|
|
||||||
|
results -> model[style="dotted"];
|
||||||
|
results -> obj[style="dotted"];
|
||||||
|
}
|
||||||
|
|
||||||
|
config -> obj[label=""];
|
||||||
|
obj -> model;
|
||||||
|
|
||||||
|
subgraph cluster1{
|
||||||
|
label="System";
|
||||||
|
in[label="Solver input files",shape=note];
|
||||||
|
out[label="Solver output files",shape=note];
|
||||||
|
bin[label="Solver binary",shape=note];
|
||||||
|
}
|
||||||
|
|
||||||
|
obj -> in[label="Write"];
|
||||||
|
bin -> in[label="Read"];
|
||||||
|
obj -> bin[label="Execute"];
|
||||||
|
bin -> out[label="Write"];
|
||||||
|
obj -> results[label="Create"];
|
||||||
|
results -> out[label="Read"];
|
||||||
|
view -> model;
|
||||||
|
view -> results;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+name: graph-architecture
|
||||||
|
#+header: :results drawer
|
||||||
|
#+header: :exports results
|
||||||
|
#+header: :post attr_wrap(width="7cm", data=*this*, name="graph-architecture", caption="Pamhyr2 Model/View architecture scheme (inspired by Qt Model/View architecture [[https://doc.qt.io/qt-5/model-view-programming.html]])", float="t")
|
||||||
|
#+begin_src dot :file "images/graph-architecture.png" :cache no
|
||||||
|
digraph {
|
||||||
|
node[colorscheme=set19,shape=box,style="filled",fillcolor=white];
|
||||||
|
|
||||||
|
save[label="Pamhyr save",fillcolor="9",shape=note];
|
||||||
|
model[label="Model",fillcolor="2"];
|
||||||
|
view[label="View",fillcolor="1"];
|
||||||
|
delegate[label="Delegate",fillcolor="3"];
|
||||||
|
undocommand[label="UndoCommand",fillcolor="4"];
|
||||||
|
user[label="User",shape=ellipse];
|
||||||
|
|
||||||
|
model -> save[label="Save"];
|
||||||
|
save -> model[label="Load"];
|
||||||
|
|
||||||
|
model -> view[label="Rendering"];
|
||||||
|
view -> delegate[label="Rendering"];
|
||||||
|
delegate -> undocommand[label="Create"];
|
||||||
|
undocommand -> model[label="Modify"]
|
||||||
|
|
||||||
|
view -> user[label="Vizualize"];
|
||||||
|
user -> delegate[label="Modify"];
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+name: graph-model
|
||||||
|
#+header: :results drawer
|
||||||
|
#+header: :exports results
|
||||||
|
#+header: :post attr_wrap(width="16cm", data=*this*, name="graph-model", caption="Pamhyr2 Model architecture scheme", float="t")
|
||||||
|
#+begin_src dot :file "images/graph-model.png" :cache no
|
||||||
|
digraph {
|
||||||
|
node[colorscheme=set19,shape=box,style="filled",fillcolor="2"];
|
||||||
|
|
||||||
|
study[label="Study"];
|
||||||
|
river[label="River"];
|
||||||
|
|
||||||
|
subgraph cluster00 {
|
||||||
|
label="Network"
|
||||||
|
rnode[label="RiverNode"];
|
||||||
|
redge[label="RiverReach"];
|
||||||
|
}
|
||||||
|
|
||||||
|
frictionlist[label="FrictionList"];
|
||||||
|
|
||||||
|
subgraph cluster01 {
|
||||||
|
label="Stricklers";
|
||||||
|
stricklers[label="Stricklers"];
|
||||||
|
stricklerslist[label="StricklersList"];
|
||||||
|
}
|
||||||
|
subgraph cluster02 {
|
||||||
|
label="BoundaryCondition";
|
||||||
|
boundaryconditionlist[label="BoundaryConditionList"];
|
||||||
|
boundarycondition[label="BoundaryCondition"];
|
||||||
|
}
|
||||||
|
subgraph cluster03 {
|
||||||
|
label="LateralContribution";
|
||||||
|
lateralcontributionlist[label="LateralContributionList"];
|
||||||
|
lateralcontribution[label="LateralContribution"];
|
||||||
|
}
|
||||||
|
subgraph cluster04 {
|
||||||
|
label="InitialConditions";
|
||||||
|
initialconditionsdict[label="InitialConditionsDict"];
|
||||||
|
initialconditions[label="InitialConditions"];
|
||||||
|
}
|
||||||
|
|
||||||
|
solverparameterslist[label="SolverParametersList"];
|
||||||
|
|
||||||
|
subgraph cluster05 {
|
||||||
|
label="Sediment";
|
||||||
|
sedimentlayerlist[label="SedimentLayerList"];
|
||||||
|
sedimentlayer[label="SedimentLayer"];
|
||||||
|
layer[label="Layer"];
|
||||||
|
}
|
||||||
|
|
||||||
|
subgraph cluster06 {
|
||||||
|
label="Greometry"
|
||||||
|
georeach[label="Reach"];
|
||||||
|
geocrosssection[label="Cross-section"];
|
||||||
|
geopoint[label="Point"];
|
||||||
|
}
|
||||||
|
|
||||||
|
study -> river;
|
||||||
|
river -> rnode;
|
||||||
|
river -> redge;
|
||||||
|
redge -> rnode;
|
||||||
|
river -> boundaryconditionlist -> boundarycondition -> rnode;
|
||||||
|
river -> lateralcontributionlist -> lateralcontribution -> redge;
|
||||||
|
river -> initialconditionsdict -> initialconditions;
|
||||||
|
initialconditions -> redge;
|
||||||
|
river -> stricklerslist -> stricklers;
|
||||||
|
river -> solverparameterslist;
|
||||||
|
river -> sedimentlayerlist -> sedimentlayer -> layer;
|
||||||
|
redge -> frictionlist -> stricklers;
|
||||||
|
redge -> georeach -> geocrosssection -> geopoint;
|
||||||
|
geocrosssection -> sedimentlayer;
|
||||||
|
geopoint -> sedimentlayer;
|
||||||
|
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
[fn:qt-mv] The Qt Model/View documentation web page:
|
||||||
|
https://doc.qt.io/qt-5/model-view-programming.html
|
||||||
|
|
||||||
|
** TODO Model
|
||||||
|
** TODO View
|
||||||
|
*** TODO UI file
|
||||||
|
*** TODO Window class
|
||||||
|
** TODO UndoCommand
|
||||||
|
** TODO Table
|
||||||
|
** TODO Plot
|
||||||
|
** TODO Solver
|
||||||
|
** TODO Unit tests
|
||||||
|
** TODO The debug mode
|
||||||
|
* TODO Build the project
|
||||||
|
|
||||||
|
The project uses gitlab-ci runners to build packages, but it is possible
|
||||||
|
to build packages manually.
|
||||||
|
|
||||||
|
** Building packages
|
||||||
|
|
||||||
|
If you need an hand made package, you can script available in
|
||||||
|
{{{file(packages)}}} directory.
|
||||||
|
|
||||||
|
*** GNU/Linux
|
||||||
|
|
||||||
|
On GNU/Linux building GNU/Linux packages is easy, you just need python
|
||||||
|
in version 3.8 must be installed with venv and pyinstaller packages
|
||||||
|
(see Listing [[linux-env-deb]] for Debian and derived system). Finally,
|
||||||
|
run the {{{file(linux.sh)}}} script (see Listing [[linux-pkg]]).
|
||||||
|
|
||||||
|
#+NAME: linux-env-deb
|
||||||
|
#+CAPTION: Install environment on GNU/Linux
|
||||||
|
#+begin_src shell
|
||||||
|
sudo apt install python3.8
|
||||||
|
python3 -m pip install venv
|
||||||
|
python3 -m pip install pyinstaller
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+NAME: linux-pkg
|
||||||
|
#+CAPTION: Build GNU/Linux package
|
||||||
|
#+begin_src shell
|
||||||
|
cd packages
|
||||||
|
./linux.sh
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** Windows
|
||||||
|
|
||||||
|
To make the Windows packages you have two choice: If you use Windows
|
||||||
|
you can use the script {{{file(packages/windows.bat)}}}, other else
|
||||||
|
you can use the script {{{file(packages/wine.sh)}}}. Each script need
|
||||||
|
a specific software environment.
|
||||||
|
|
||||||
|
On windows, you needs python on version 3.8, pyinstaller and
|
||||||
|
NSIS[fn:nsis] installed. On GNU/Linux you need wget, wine and
|
||||||
|
winetricks installed.
|
||||||
|
|
||||||
|
[fn:nsis] The NSIS web site: https://sourceforge.net/projects/nsis/
|
||||||
|
|
||||||
|
** TODO Setup the CI environment
|
||||||
|
* Documentation files
|
||||||
|
|
||||||
|
This document and the user documentation are org files. This text file
|
||||||
|
format is formatted so that it can be exported in different formats:
|
||||||
|
PDF (with latex), ODT, HTML, etc. It was originally designed for the
|
||||||
|
GNUEmacs[fn:emacs] text editor, but can be edited with any text editor. Here we
|
||||||
|
take a look at the different features used in these documents.
|
||||||
|
|
||||||
|
[fn:org] The org-mode website: https://orgmode.org/ (last access
|
||||||
|
2023-09-15)
|
||||||
|
[fn:emacs] The GNUEmacs project website: https://gnu.org/s/emacs/
|
||||||
|
(last access 2023-09-15)
|
||||||
|
|
||||||
|
** Org-mode
|
||||||
|
*** Document structure
|
||||||
|
|
||||||
|
Org uses the =*= character to define a new document section. To add a
|
||||||
|
sub-section, you can add an additional =*= to the current section[fn::
|
||||||
|
See document structure documentation:
|
||||||
|
https://orgmode.org/org.html#Headlines (last access 2023-09-15)].
|
||||||
|
|
||||||
|
#+BEGIN_EXAMPLE
|
||||||
|
* Top level headline
|
||||||
|
** Second level
|
||||||
|
*** Third level
|
||||||
|
some text
|
||||||
|
*** Third level
|
||||||
|
more text
|
||||||
|
* Another top level headline
|
||||||
|
#+END_EXAMPLE
|
||||||
|
|
||||||
|
*** Format
|
||||||
|
|
||||||
|
Org-mode is a markup file, using markup in the text to modify the
|
||||||
|
appearance of a portion of text[fn:: See markup documentation:
|
||||||
|
https://orgmode.org/org.html#Emphasis-and-Monospace (last access
|
||||||
|
2023-09-15)].
|
||||||
|
|
||||||
|
| Markup | Results |
|
||||||
|
|--------------------+------------------|
|
||||||
|
| =*Bolt*= | *Bolt* |
|
||||||
|
| =/Italic/= | /Italic/ |
|
||||||
|
| =_underline_= | _underline_ |
|
||||||
|
| ==verbatim== | =verbatim= |
|
||||||
|
| =~code~= | ~code~ |
|
||||||
|
| =+strike-through+= | +strike-through+ |
|
||||||
|
|
||||||
|
*** Source code blocks
|
||||||
|
|
||||||
|
You can add some code blocks[fn:: See org-mode documentation for
|
||||||
|
source code: https://orgmode.org/org.html#Working-with-Source-Code
|
||||||
|
(last access 2023-09-15)] in the document.
|
||||||
|
|
||||||
|
Here is an example for python source code:
|
||||||
|
#+BEGIN_EXAMPLE
|
||||||
|
#+CAPTION: Get os type name in Python code
|
||||||
|
#+begin_src python
|
||||||
|
import os
|
||||||
|
|
||||||
|
print(f"Document build on system: {os.name}")
|
||||||
|
#+end_src
|
||||||
|
#+END_EXAMPLE
|
||||||
|
|
||||||
|
If you use GNUEmacs, it is also possible to run the code inside a
|
||||||
|
block and export (or not) the reuslts in the document.
|
||||||
|
|
||||||
|
#+OPTIONS: float:nil
|
||||||
|
#+CAPTION: Get os type name in Python code
|
||||||
|
#+begin_src python :python python3 :results output :exports both :noweb yes
|
||||||
|
import os
|
||||||
|
|
||||||
|
print(f"Document build on system: {os.name}")
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
|
: Document build on system: posix
|
||||||
|
|
||||||
|
*** LaTeX
|
||||||
|
|
||||||
|
If we export the file to PDF, org-mode use {{{latex}}}. So we can add
|
||||||
|
some piece of {{{latex}}} into the document[fn:: See {{{latex}}} part
|
||||||
|
in documentation: https://orgmode.org/org.html#Embedded-LaTeX (last
|
||||||
|
access 2023-09-15)]. For exemple, we can add math formula like
|
||||||
|
=$E=mc^2$= ($E=mc^2$) or =\[E=mc^2\]=:
|
||||||
|
|
||||||
|
\[E=mc^2\]
|
||||||
|
|
||||||
|
But we can also add every type of {{{latex}}}:
|
||||||
|
|
||||||
|
#+BEGIN_EXAMPLE
|
||||||
|
# Add latex in line
|
||||||
|
#+LATEX: <my line of latex>
|
||||||
|
|
||||||
|
# Add multiple line of LaTeX
|
||||||
|
#+BEGIN_EXPORT latex
|
||||||
|
<my latex here>
|
||||||
|
#+END_EXPORT
|
||||||
|
#+END_EXAMPLE
|
||||||
|
|
||||||
|
It is also possible to add specific {{{latex}}} file header with
|
||||||
|
=#+LATEX_HEADER=. In this document we use the file
|
||||||
|
{{{file(doc/tools/latex.org)}}} for all {{{latex}}} headers.
|
||||||
|
|
||||||
|
*** Macro
|
||||||
|
|
||||||
|
In this document, we use a few macros[fn:: See marcos documentation
|
||||||
|
https://orgmode.org/org.html#Macro-Replacement (last access
|
||||||
|
2023-09-15)] to simplify writing. They allow you to define sequences
|
||||||
|
of text to be replaced, so that the macro name is replaced by its
|
||||||
|
value. They are defined in the {{{file(doc/tools/macro.org)}}}
|
||||||
|
file. Once defined, they can be used in the document as follows:
|
||||||
|
={{{<macro-name>}}}=. You can also have macros with arguments, in this
|
||||||
|
case: ={{{<macro-name>(arg1,...)}}}=. Les macros peuvent aussi
|
||||||
|
utiliser du code emacs-lisp.
|
||||||
|
|
||||||
|
#+BEGIN_EXAMPLE
|
||||||
|
# Exemple of macro définition
|
||||||
|
|
||||||
|
#+MACRO: toto tata
|
||||||
|
#+MACRO: add \(($1 + $2)\)
|
||||||
|
#+MACRO: emacs-version (eval (nth 2 (split-string (emacs-version))))
|
||||||
|
#+END_EXAMPLE
|
||||||
|
|
||||||
|
#+MACRO: toto tata
|
||||||
|
#+MACRO: add \(($1 + $2)\)
|
||||||
|
#+MACRO: emacs-version (eval (nth 2 (split-string (emacs-version))))
|
||||||
|
|
||||||
|
Macro apply:
|
||||||
|
- Marco ={{{toto}}}=: {{{toto}}}
|
||||||
|
- Marco ={{{add(x,y)}}}=: {{{add(x,y)}}}
|
||||||
|
- Marco ={{{emacs-version}}}=: {{{emacs-version}}}
|
||||||
|
|
||||||
|
*** Footnotes
|
||||||
|
|
||||||
|
Footnote in org-mode is define with marker =[fn:...]=[fn:: Create
|
||||||
|
footnotes in org-mode documentation
|
||||||
|
https://orgmode.org/org.html#Creating-Footnotes (last access
|
||||||
|
2023-09-15)]:
|
||||||
|
#+BEGIN_EXAMPLE
|
||||||
|
The Org website[fn:1] now looks a lot better than it used to.
|
||||||
|
...
|
||||||
|
[fn:1] The link is: https://orgmode.org
|
||||||
|
#+END_EXAMPLE
|
||||||
|
or:
|
||||||
|
#+BEGIN_EXAMPLE
|
||||||
|
The Org website[fn:: The link is: https://orgmode.org] now looks
|
||||||
|
a lot better than it used to.
|
||||||
|
...
|
||||||
|
#+END_EXAMPLE
|
||||||
|
|
||||||
|
*** References
|
||||||
|
|
||||||
|
The references use the {{{latex}}} bibtex tools. The bib file is in
|
||||||
|
{{{file(/doc/tools/ref.bib)}}} and use for developers and user
|
||||||
|
documentation. In document, use ={{{cite(<name>)}}}= to cite a paper.
|
||||||
|
|
||||||
|
** Export
|
||||||
|
|
||||||
|
To export the files, a {{{file(build.sh)}}} script is available in the org
|
||||||
|
files directories. On GNU/Linux system you can build the documentation
|
||||||
|
PDF file with the command =./build.sh=. Texlive package must be
|
||||||
|
installed, you can install only needed packages or all texlive
|
||||||
|
packages, for example on Debian (and some derived system) use command
|
||||||
|
Listing [[texlive-install]].
|
||||||
|
|
||||||
|
#+NAME: texlive-install
|
||||||
|
#+CAPTION: Installation command for texlive full on Debian system
|
||||||
|
#+begin_src shell
|
||||||
|
sudo apt install texlive-full
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Some org-mode configuration used in documentations files are define in
|
||||||
|
=/doc/tools/=:
|
||||||
|
- {{{file(PamhyrDoc.cls)}}}: The {{{latex}}} document class
|
||||||
|
- {{{file(macro.org)}}}: Available macro
|
||||||
|
- {{{file(latex.org)}}}: {{{latex}}} configutation for documentations
|
||||||
|
files
|
||||||
|
- {{{file(setup.el)}}}: GNUEmacs configuration to build documentations
|
||||||
|
- {{{file(ref.bib)}}}: Bibtex files for documentations files
|
||||||
|
|
||||||
|
* How to contribute?
|
||||||
|
|
||||||
|
Pamhyr2 is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License[fn:license], either
|
||||||
|
version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
[fn:license] The GPLv3 web page:
|
||||||
|
https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||||
|
|
||||||
|
** Guidelines
|
||||||
|
|
||||||
|
To contribute to Pamhyr2, we expect a minimum of respect between
|
||||||
|
contributors. We therefore ask you to respect the following rules
|
||||||
|
regarding communication and contribution content:
|
||||||
|
+ No gender, racial, religious or social discrimination
|
||||||
|
+ No insults, personal attacks or potentially offensive remarks
|
||||||
|
+ Pamhyr2 is free software, and intended to remain so, so take care
|
||||||
|
with the licensing of libraries and external content you want to add
|
||||||
|
to the project
|
||||||
|
+ Humour or hidden easter eggs are welcome if they respect the
|
||||||
|
previous rules
|
||||||
|
|
||||||
|
** Make a contribution
|
||||||
|
|
||||||
|
There are several ways to contribute: you can report a bug by creating
|
||||||
|
an issue on the project's gitlab page[fn:p2-gitlab], or you can create
|
||||||
|
a merge request on the same page with the changes you have made to the
|
||||||
|
code, translation or documentation.
|
||||||
|
|
||||||
|
The Pamhyr2 copyright is owned by INRAE[fn:inrae], but we keep a
|
||||||
|
record of each contributors. If you made a modification to pamhyr2
|
||||||
|
software, please add your name at the end of {{{file(AUTHORS)}}} file
|
||||||
|
and respect the Listing [[auth-format]] format. You can update this file
|
||||||
|
information for following contribution.
|
||||||
|
|
||||||
|
#+NAME: auth-format
|
||||||
|
#+CAPTION: =AUTHORS= file format
|
||||||
|
#+begin_src text
|
||||||
|
<first name> <last name> [(optional) email], <organisation>, <years>
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+CAPTION: Current =AUTHORS= file
|
||||||
|
#+INCLUDE: "../../AUTHORS" src text
|
||||||
|
|
||||||
|
[fn:p2-gitlab] The Pamhyr2 Gitlab project page:
|
||||||
|
https://gitlab.irstea.fr/theophile.terraz/pamhyr
|
||||||
|
[fn:inrae] The INRAE web site: https://www.inrae.fr/
|
||||||
|
|
||||||
|
** Translate
|
||||||
|
|
||||||
|
You can improve or add translation for the project. To contribute to
|
||||||
|
Pamhyr2 translate, you need to use Qt Linguist[fn:qt-linguist]. Open
|
||||||
|
Qt-linguist and edite the translation ({{{file(.ts)}}}) file, finally,
|
||||||
|
commit the new version of file and make a merge request.
|
||||||
|
|
||||||
|
If you want add a new language, edit the script
|
||||||
|
{{{file(src/lang/create_ts.sh)}}} like Listing [[ts-it]]. Run the script
|
||||||
|
and open the new file with Qt-linguist, setup target language (Figure
|
||||||
|
[[qt-linguist-setup]]) and complete translation. Finally, commit the new
|
||||||
|
file and make a merge request.
|
||||||
|
|
||||||
|
#+NAME: ts-it
|
||||||
|
#+CAPTION: Example of modified {{{file(src/lang/create_ts.sh)}}} to add italian (it) translate for Pamhyr2
|
||||||
|
#+begin_src shell
|
||||||
|
...
|
||||||
|
LANG="fr it"
|
||||||
|
...
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+NAME: qt-linguist-setup
|
||||||
|
#+ATTR_HTML: :width 8cm
|
||||||
|
#+ATTR_LATEX: :width 8cm
|
||||||
|
#+CAPTION: Qt linguist lang setup example with italian.
|
||||||
|
[[../images/Qt-linguist-setup-lang.png]]
|
||||||
|
|
||||||
|
[fn:qt-linguist] The Qt linguist documentation web page:
|
||||||
|
https://doc.qt.io/qt-5/qtlinguist-index.html (last access 2023-09-18)
|
||||||
|
|
||||||
|
** Code contribution
|
||||||
|
|
||||||
|
If you are developper you can improve and/or add features to
|
||||||
|
Pamhyr2. Please, follow the architecture described in section
|
||||||
|
[[Architecture]] as closely as possible. Keep the code simple, clear and
|
||||||
|
efficient as possible. The master branch is reserved for the project
|
||||||
|
maintainer; you can create a new branch or fork the project before the
|
||||||
|
request.
|
||||||
|
|
||||||
|
|
||||||
|
{{{biblio}}}
|
||||||
Whitespace-only changes.
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
@@ -0,0 +1,163 @@
|
|||||||
|
\ProvidesClass{Pamhyr}[Pamhyr class]
|
||||||
|
\NeedsTeXFormat{LaTeX2e}
|
||||||
|
\ProcessOptions\relax
|
||||||
|
\LoadClass[11pt,a4paper]{article}
|
||||||
|
|
||||||
|
\usepackage[hmargin=2cm, vmargin=3cm]{geometry}
|
||||||
|
\usepackage[british,UKenglish,USenglish,english,american]{babel}
|
||||||
|
\usepackage[T1]{fontenc}
|
||||||
|
\usepackage{times}
|
||||||
|
\usepackage[usenames,dvipsnames]{xcolor}
|
||||||
|
\usepackage[absolute]{textpos}
|
||||||
|
\usepackage{titlesec}
|
||||||
|
\usepackage{amssymb}
|
||||||
|
\usepackage{tcolorbox}
|
||||||
|
|
||||||
|
\usepackage{enumitem}
|
||||||
|
\setlist[enumerate]{itemsep=-0.5em}
|
||||||
|
\setlist[itemize]{itemsep=-0.5em}
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Bibtex
|
||||||
|
%%
|
||||||
|
|
||||||
|
\bibliographystyle{plain}
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Colors
|
||||||
|
%%
|
||||||
|
|
||||||
|
\definecolor{primary}{HTML}{212121}
|
||||||
|
\definecolor{lightheadings}{HTML}{5c5c5c}
|
||||||
|
\definecolor{headings}{HTML}{212121}
|
||||||
|
\definecolor{links}{HTML}{e12121}
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Title
|
||||||
|
%%
|
||||||
|
|
||||||
|
\setlength{\columnsep}{20pt}
|
||||||
|
\setlength{\parskip}{0pt} %% inter paragraph space
|
||||||
|
|
||||||
|
\renewcommand{\maketitle}{
|
||||||
|
{
|
||||||
|
\centering
|
||||||
|
{
|
||||||
|
\fontsize{35}{40}
|
||||||
|
\selectfont
|
||||||
|
\scshape
|
||||||
|
Pamhyr2 \\
|
||||||
|
\medskip
|
||||||
|
}
|
||||||
|
{
|
||||||
|
%\centering
|
||||||
|
\scshape
|
||||||
|
\fontsize{20pt}{24pt}
|
||||||
|
\selectfont
|
||||||
|
A graphical user interface for 1D hydro-sedimentary modelling
|
||||||
|
of rivers \\
|
||||||
|
\medskip
|
||||||
|
}
|
||||||
|
\rule{3cm}{0.4pt}\\
|
||||||
|
\vspace{0.3cm}
|
||||||
|
{
|
||||||
|
%\centering
|
||||||
|
\scshape
|
||||||
|
\fontsize{26pt}{24pt}
|
||||||
|
\selectfont
|
||||||
|
\@title \\
|
||||||
|
Document licence: GPLv3 \\
|
||||||
|
\medskip
|
||||||
|
\includegraphics[width=3cm]{../images/GPLv3_Logo.png} \\
|
||||||
|
\medskip
|
||||||
|
\fontsize{14pt}{16pt}
|
||||||
|
\selectfont
|
||||||
|
© \@author \\
|
||||||
|
\medskip
|
||||||
|
}
|
||||||
|
{
|
||||||
|
%\centering
|
||||||
|
%\scshape
|
||||||
|
\fontsize{12pt}{14pt}
|
||||||
|
\selectfont
|
||||||
|
\@date
|
||||||
|
%\medskip
|
||||||
|
}\\
|
||||||
|
\vspace{0.3cm}
|
||||||
|
\rule{3cm}{0.4pt}\\
|
||||||
|
\vspace{0.3cm}
|
||||||
|
{
|
||||||
|
\begin{minipage}[h]{0.24\textwidth}
|
||||||
|
\includegraphics[width=4cm]{../../src/View/ui/ressources/Logo-INRAE.png}
|
||||||
|
\end{minipage}
|
||||||
|
\begin{minipage}[h]{0.24\textwidth}
|
||||||
|
\includegraphics[width=4cm]{../images/riverly.png}
|
||||||
|
\end{minipage}
|
||||||
|
}\\
|
||||||
|
\vspace{0.3cm}
|
||||||
|
%%\rule{\textwidth}{0.4pt}
|
||||||
|
%%\newpage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Texttt
|
||||||
|
%%
|
||||||
|
|
||||||
|
\usepackage[htt]{hyphenat} % Make texttt split at end of line
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Verbatim
|
||||||
|
%%
|
||||||
|
|
||||||
|
\AtBeginEnvironment{verbatim}{\footnotesize}
|
||||||
|
|
||||||
|
%% Add box arrond of verbatim
|
||||||
|
\BeforeBeginEnvironment{verbatim}{\begin{tcolorbox}[boxsep=0pt, left=0.1cm, right=0.1cm, arc=0pt, boxrule=0.5pt, colback=white]}%
|
||||||
|
\AfterEndEnvironment{verbatim}{\end{tcolorbox}}%
|
||||||
|
|
||||||
|
\makeatletter
|
||||||
|
\AtBeginEnvironment{verbatim}{\dontdofcolorbox}
|
||||||
|
|
||||||
|
\def\dontdofcolorbox{\renewcommand\fcolorbox[4][]{##4}}
|
||||||
|
\makeatother
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Source code blocks
|
||||||
|
%%
|
||||||
|
|
||||||
|
%% Use minted
|
||||||
|
\usepackage{minted}
|
||||||
|
\usemintedstyle{tango}
|
||||||
|
\setminted[c]{fontsize=\footnotesize,encoding=utf8,linenos}
|
||||||
|
\setminted[c++]{breaklines,fontsize=\footnotesize,encoding=utf8,linenos}
|
||||||
|
\setminted[python]{breaklines,fontsize=\footnotesize,encoding=utf8,linenos}
|
||||||
|
\setminted[shell]{breaklines,fontsize=\footnotesize,encoding=utf8}
|
||||||
|
\setminted[scheme]{breaklines,fontsize=\footnotesize,encoding=utf8}
|
||||||
|
\setminted[commun-lisp]{breaklines,fontsize=\footnotesize,encoding=utf8}
|
||||||
|
\setminted[text]{breaklines,fontsize=\footnotesize,encoding=utf8}
|
||||||
|
\setminted[llvm]{breaklines,fontsize=\footnotesize,encoding=utf8}
|
||||||
|
|
||||||
|
%% Add box arrond of minted
|
||||||
|
\BeforeBeginEnvironment{minted}{\begin{tcolorbox}[boxsep=0pt, left=0.1cm, right=0.1cm, arc=0pt, boxrule=0.5pt, colback=white]}%
|
||||||
|
\AfterEndEnvironment{minted}{\end{tcolorbox}}%
|
||||||
|
|
||||||
|
\makeatletter
|
||||||
|
\AtBeginEnvironment{minted}{\dontdofcolorbox}
|
||||||
|
|
||||||
|
\def\dontdofcolorbox{\renewcommand\fcolorbox[4][]{##4}}
|
||||||
|
\makeatother
|
||||||
|
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Water mark
|
||||||
|
%%
|
||||||
|
|
||||||
|
%% FIXME: Delete me for the first realease
|
||||||
|
\usepackage{draftwatermark}
|
||||||
|
\SetWatermarkLightness{0.8}
|
||||||
|
\SetWatermarkAngle{25}
|
||||||
|
\SetWatermarkScale{3}
|
||||||
|
\SetWatermarkFontSize{1cm}
|
||||||
|
\SetWatermarkText{Work in progress}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# latex.org -- Pamhyr documentation latex config
|
||||||
|
# Copyright (C) 2023 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#+LaTeX_CLASS: PamhyrDoc
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# macro.org -- Pamhyr documentation macro
|
||||||
|
# Copyright (C) 2023 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Constant name
|
||||||
|
#+MACRO: oldPamhyr PAMHyR
|
||||||
|
#+MACRO: Pamhyr Pamhyr2
|
||||||
|
#+MACRO: Mage Mage
|
||||||
|
#+MACRO: Rubarbe RubarBE
|
||||||
|
#+MACRO: Inrae INRAE
|
||||||
|
#+MACRO: latex \LaTeX
|
||||||
|
|
||||||
|
# Information
|
||||||
|
#+MACRO: version (eval (pamhyr-version))
|
||||||
|
#+MACRO: current-file (eval (pamhyr-current-file))
|
||||||
|
|
||||||
|
# Special format
|
||||||
|
#+MACRO: file =$1=
|
||||||
|
|
||||||
|
# Biblio
|
||||||
|
#+MACRO: cite [cite:$1]
|
||||||
|
#+MACRO: biblio \bibliography{documentation}
|
||||||
|
|
||||||
|
# Wrapper
|
||||||
|
#+NAME: attr_wrap
|
||||||
|
#+HEADER: :var width="\\textwidth"
|
||||||
|
#+HEADER: :var caption=""
|
||||||
|
#+HEADER: :var smallcaption=""
|
||||||
|
#+HEADER: :var name=""
|
||||||
|
#+HEADER: :var data=""
|
||||||
|
#+HEADER: :var float="nil"
|
||||||
|
#+BEGIN_SRC sh :results output :exports none
|
||||||
|
echo "#+CAPTION[$smallcaption]: $caption"
|
||||||
|
echo "#+NAME: $name"
|
||||||
|
echo "#+ATTR_LATEX: :width $width :float $float"
|
||||||
|
echo "$data"
|
||||||
|
#+END_SRC
|
||||||
Whitespace-only changes.
@@ -0,0 +1,66 @@
|
|||||||
|
(require 'org)
|
||||||
|
(require 'subr-x)
|
||||||
|
|
||||||
|
;; LaTeX config
|
||||||
|
|
||||||
|
(add-to-list
|
||||||
|
'org-latex-classes
|
||||||
|
'("PamhyrDoc"
|
||||||
|
"\\documentclass{../tools/PamhyrDoc}"
|
||||||
|
("\\section{%s}" . "\\section*{%s}")
|
||||||
|
("\\subsection{%s}" . "\\subsection*{%s}")
|
||||||
|
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
|
||||||
|
("\\paragraph{%s}" . "\\paragraph*{%s}")
|
||||||
|
("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
|
||||||
|
|
||||||
|
(setq org-confirm-babel-evaluate nil)
|
||||||
|
(setq org-latex-caption-above nil)
|
||||||
|
|
||||||
|
(org-babel-do-load-languages
|
||||||
|
'org-babel-load-languages
|
||||||
|
(add-to-list 'org-babel-load-languages '(shell . t)))
|
||||||
|
|
||||||
|
(org-babel-do-load-languages
|
||||||
|
'org-babel-load-languages
|
||||||
|
(add-to-list 'org-babel-load-languages '(dot . t)))
|
||||||
|
|
||||||
|
(org-babel-do-load-languages
|
||||||
|
'org-babel-load-languages
|
||||||
|
(add-to-list 'org-babel-load-languages '(python . t)))
|
||||||
|
|
||||||
|
(add-to-list 'org-latex-packages-alist '("" "minted"))
|
||||||
|
(setq org-latex-listings 'minted)
|
||||||
|
(setq org-src-fontify-natively t)
|
||||||
|
|
||||||
|
(setq org-latex-pdf-process
|
||||||
|
'("pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"
|
||||||
|
"bibtex documentation"
|
||||||
|
"pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"
|
||||||
|
"pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"))
|
||||||
|
|
||||||
|
;; Citations
|
||||||
|
|
||||||
|
(org-add-link-type
|
||||||
|
"cite" 'ebib
|
||||||
|
(lambda (path desc format)
|
||||||
|
(cond
|
||||||
|
((eq format 'html)
|
||||||
|
(format "(<cite>%s</cite>)" path))
|
||||||
|
((eq format 'latex)
|
||||||
|
(if (or (not desc) (equal 0 (search "cite:" desc)))
|
||||||
|
(format "\\cite{%s}" path)
|
||||||
|
(format "\\cite[%s][%s]{%s}"
|
||||||
|
(cadr (split-string desc ";"))
|
||||||
|
(car (split-string desc ";")) path))))))
|
||||||
|
|
||||||
|
;; Functools
|
||||||
|
|
||||||
|
(defun pamhyr-version ()
|
||||||
|
"Return the contents of the pamhyr version file."
|
||||||
|
(with-temp-buffer
|
||||||
|
(insert-file-contents "../../VERSION")
|
||||||
|
(buffer-string)))
|
||||||
|
|
||||||
|
(defun pamhyr-current-file ()
|
||||||
|
(let ((lst (split-string (buffer-file-name) "/")))
|
||||||
|
(string-join (nthcdr (- (length lst) 3) lst) "/")))
|
||||||
Executable
+10
@@ -0,0 +1,10 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
# Build the PDF
|
||||||
|
|
||||||
|
emacs -Q -q -nw --batch \
|
||||||
|
--eval "(require 'org)" \
|
||||||
|
--eval "(require 'ox-latex)" \
|
||||||
|
--eval "(load-file \"../tools/setup.el\")" \
|
||||||
|
--file ./documentation.org \
|
||||||
|
-f org-latex-export-to-pdf
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../tools/ref.bib
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#+STARTUP: indent
|
||||||
|
|
||||||
|
#+INCLUDE: ../tools/macro.org
|
||||||
|
#+INCLUDE: ../tools/latex.org
|
||||||
|
|
||||||
|
#+TITLE: User documentation
|
||||||
|
#+SUBTITLE: Version: {{{version}}}
|
||||||
|
#+AUTHOR: {{{INRAE}}}
|
||||||
|
|
||||||
|
#+OPTIONS: toc:t
|
||||||
|
#+LANGUAGE: UKenglish
|
||||||
|
|
||||||
|
* TODO Over view
|
||||||
|
* TODO Get started
|
||||||
|
** Installation
|
||||||
|
*** Linux
|
||||||
|
*** Windows
|
||||||
|
* TODO Usage
|
||||||
|
|
||||||
|
{{{biblio}}}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
rem windows.bat -- Pamhyr Windows batch for windows version building
|
||||||
|
rem Copyright (C) 2023 INRAE
|
||||||
|
rem
|
||||||
|
rem This program is free software: you can redistribute it and/or modify
|
||||||
|
rem it under the terms of the GNU General Public License as published by
|
||||||
|
rem the Free Software Foundation, either version 3 of the License, or
|
||||||
|
rem (at your option) any later version.
|
||||||
|
rem
|
||||||
|
rem This program is distributed in the hope that it will be useful,
|
||||||
|
rem but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
rem MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
rem GNU General Public License for more details.
|
||||||
|
rem
|
||||||
|
rem You should have received a copy of the GNU General Public License
|
||||||
|
rem along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
@ECHO ON
|
||||||
|
|
||||||
|
mkdir pamhyr\pamhyr
|
||||||
|
xcopy /s /e /y dist\pamhyr pamhyr\pamhyr
|
||||||
|
|
||||||
|
rem Copy data
|
||||||
|
mkdir pamhyr\pamhyr\lang
|
||||||
|
mkdir pamhyr\pamhyr\View\ui\ressources
|
||||||
|
mkdir pamhyr\pamhyr\View\ui\Widgets
|
||||||
|
|
||||||
|
rem UI
|
||||||
|
copy /y ..\src\View\ui\ressources\ pamhyr\pamhyr\View\ui\ressources
|
||||||
|
copy /y ..\src\View\ui\Widgets\*.ui pamhyr\pamhyr\View\ui\Widgets
|
||||||
|
copy /y ..\src\View\ui\*.ui pamhyr\pamhyr\View\ui\
|
||||||
|
|
||||||
|
rem Lang
|
||||||
|
copy /y ..\src\lang\*.qm pamhyr\pamhyr\lang\
|
||||||
|
|
||||||
|
rem Information
|
||||||
|
copy /y ..\VERSION pamhyr\pamhyr
|
||||||
|
copy /y ..\AUTHORS pamhyr\pamhyr
|
||||||
|
copy /y ..\LICENSE pamhyr\pamhyr
|
||||||
|
|
||||||
|
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\mailleurPF.exe pamhyr\mage\
|
||||||
|
|
||||||
|
rem Copy tests_cases
|
||||||
|
mkdir pamhyr\tests_cases
|
||||||
|
mkdir pamhyr\tests_cases\Saar
|
||||||
|
copy /y ..\tests_cases\Saar\Saar.pamhyr pamhyr\tests_cases\Saar\
|
||||||
|
|
||||||
|
rem Documentations
|
||||||
|
mkdir pamhyr\doc
|
||||||
|
copy /y ..\doc\users\documentation.pdf pamhyr\doc\Pamhyr2-users.pdf
|
||||||
|
copy /y ..\doc\dev\documentation.pdf pamhyr\doc\Pamhyr2-dev.pdf
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
rem windows.bat -- Pamhyr Windows batch for windows version building
|
||||||
|
rem Copyright (C) 2023 INRAE
|
||||||
|
rem
|
||||||
|
rem This program is free software: you can redistribute it and/or modify
|
||||||
|
rem it under the terms of the GNU General Public License as published by
|
||||||
|
rem the Free Software Foundation, either version 3 of the License, or
|
||||||
|
rem (at your option) any later version.
|
||||||
|
rem
|
||||||
|
rem This program is distributed in the hope that it will be useful,
|
||||||
|
rem but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
rem MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
rem GNU General Public License for more details.
|
||||||
|
rem
|
||||||
|
rem You should have received a copy of the GNU General Public License
|
||||||
|
rem along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
@ECHO ON
|
||||||
|
|
||||||
|
rem Make installer
|
||||||
|
"C:\Program Files (x86)\NSIS\makensis.exe" pamhyr.nsi
|
||||||
+18
-18
@@ -3,17 +3,17 @@
|
|||||||
!define LIC_NAME "LICENSE"
|
!define LIC_NAME "LICENSE"
|
||||||
!define APP_NAME "PAMHYR"
|
!define APP_NAME "PAMHYR"
|
||||||
|
|
||||||
Name "PAMHYR"
|
Name "Pamhyr2"
|
||||||
OutFile "pamhyr-win-amd64.exe"
|
OutFile "pamhyr-windows.exe"
|
||||||
LicenseData "..\LICENSE"
|
LicenseData "pamhyr\pamhyr\LICENSE"
|
||||||
LicenseText "I Agree"
|
LicenseText "I Agree"
|
||||||
|
|
||||||
RequestExecutionLevel admin
|
RequestExecutionLevel admin
|
||||||
|
|
||||||
Unicode True
|
Unicode True
|
||||||
InstallDir $PROGRAMFILES\PAMHYR
|
InstallDir $PROGRAMFILES\Pamhyr2
|
||||||
|
|
||||||
InstallDirRegKey HKLM "Software\PAMHYR" "Install_Dir"
|
InstallDirRegKey HKLM "Software\Pamhyr2" "Install_Dir"
|
||||||
|
|
||||||
Page license
|
Page license
|
||||||
Page components
|
Page components
|
||||||
@@ -23,35 +23,35 @@ Page instfiles
|
|||||||
UninstPage uninstConfirm
|
UninstPage uninstConfirm
|
||||||
UninstPage instfiles
|
UninstPage instfiles
|
||||||
|
|
||||||
Section "PAMHYR"
|
Section "Pamhyr2"
|
||||||
SectionIn RO
|
SectionIn RO
|
||||||
|
|
||||||
SetOutPath $INSTDIR
|
SetOutPath $INSTDIR
|
||||||
|
|
||||||
File /r "dist\pamhyr\*"
|
File /r "pamhyr\*"
|
||||||
|
|
||||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\PAMHYR" "DisplayName" "NSIS PAMHYR"
|
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pamhyr2" "DisplayName" "NSIS Pamhyr2"
|
||||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\PAMHYR" "UninstallString" "$INSTDIR\uninstall.exe"
|
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pamhyr2" "UninstallString" "$INSTDIR\uninstall.exe"
|
||||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\PAMHYR" "NoModify" 1
|
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pamhyr2" "NoModify" 1
|
||||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\PAMHYR" "NoRepair" 1
|
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pamhyr2" "NoRepair" 1
|
||||||
WriteUninstaller "$INSTDIR\uninstall.exe"
|
WriteUninstaller "$INSTDIR\uninstall.exe"
|
||||||
|
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
Section "Start Menu Shortcuts"
|
Section "Start Menu Shortcuts"
|
||||||
|
|
||||||
CreateDirectory "$SMPROGRAMS\PAMHYR"
|
CreateDirectory "$SMPROGRAMS\Pamhyr2"
|
||||||
CreateShortcut "$SMPROGRAMS\PAMHYR\Uninstall.lnk" "$INSTDIR\uninstall.exe"
|
CreateShortcut "$SMPROGRAMS\Pamhyr2\Uninstall.lnk" "$INSTDIR\uninstall.exe"
|
||||||
CreateShortcut "$SMPROGRAMS\PAMHYR\PAMHYR.lnk" "$INSTDIR\pamhyr.exe"
|
CreateShortcut "$SMPROGRAMS\Pamhyr2\Pamhyr2.lnk" "$INSTDIR\pamhyr\pamhyr.exe"
|
||||||
|
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
Section "Uninstall"
|
Section "Uninstall"
|
||||||
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\PAMHYR"
|
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pamhyr2"
|
||||||
DeleteRegKey HKLM SOFTWARE\NSIS_PAMHYR
|
DeleteRegKey HKLM SOFTWARE\NSIS_Pamhyr2
|
||||||
|
|
||||||
Delete "$SMPROGRAMS\PAMHYR\*.lnk"
|
Delete "$SMPROGRAMS\Pamhyr2\*.lnk"
|
||||||
|
|
||||||
RMDir "$SMPROGRAMS\PAMHYR"
|
RMDir "$SMPROGRAMS\Pamhyr2"
|
||||||
RMDir /R "$INSTDIR"
|
RMDir /R "$INSTDIR"
|
||||||
SectionEnd
|
SectionEnd
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
class AbstractModelComponent(object):
|
|
||||||
def __init__(self):
|
|
||||||
super(AbstractModelComponent, self).__init__()
|
|
||||||
|
|
||||||
def new(self, filename):
|
|
||||||
|
|
||||||
|
|
||||||
def export(self, filename):
|
|
||||||
@@ -20,7 +20,7 @@ import logging
|
|||||||
|
|
||||||
from tools import trace, timer, old_pamhyr_date_to_timestamp
|
from tools import trace, timer, old_pamhyr_date_to_timestamp
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrList import PamhyrModelListWithTab
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
from Model.BoundaryCondition.BoundaryCondition import BoundaryCondition
|
from Model.BoundaryCondition.BoundaryCondition import BoundaryCondition
|
||||||
@@ -30,30 +30,12 @@ from Model.BoundaryCondition.BoundaryConditionTypes import (
|
|||||||
Solid,
|
Solid,
|
||||||
)
|
)
|
||||||
|
|
||||||
class BoundaryConditionList(SQLSubModel):
|
class BoundaryConditionList(PamhyrModelListWithTab):
|
||||||
|
_tabs_list = ["liquid", "solid", "suspenssion"]
|
||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
BoundaryCondition,
|
BoundaryCondition,
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, status = None):
|
|
||||||
super(BoundaryConditionList, self).__init__()
|
|
||||||
|
|
||||||
self._status = status
|
|
||||||
|
|
||||||
self._tabs = {
|
|
||||||
"liquid" : [],
|
|
||||||
"solid" : [],
|
|
||||||
"suspenssion" : []
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _sql_create(cls, execute):
|
|
||||||
return cls._create_submodel(execute)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _sql_update(cls, execute, version):
|
|
||||||
return True
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data = None):
|
||||||
new = cls(status = data['status'])
|
new = cls(status = data['status'])
|
||||||
@@ -82,66 +64,12 @@ class BoundaryConditionList(SQLSubModel):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def len(self, lst):
|
|
||||||
return len(self._tabs[lst])
|
|
||||||
|
|
||||||
def get_tab(self, lst):
|
|
||||||
return self._tabs[lst].copy()
|
|
||||||
|
|
||||||
def get(self, lst, row):
|
|
||||||
return self._tabs[lst][row]
|
|
||||||
|
|
||||||
def set(self, lst, row, new):
|
|
||||||
self._tabs[lst][row] = new
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def new(self, lst, index):
|
def new(self, lst, index):
|
||||||
n = NotDefined(status=self._status)
|
n = NotDefined(status=self._status)
|
||||||
self._tabs[lst].insert(index, n)
|
self._tabs[lst].insert(index, n)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
return n
|
return n
|
||||||
|
|
||||||
def insert(self, lst, index, new):
|
|
||||||
self._tabs[lst].insert(index, new)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete(self, lst, bcs):
|
|
||||||
for bc in bcs:
|
|
||||||
self._tabs[lst].remove(bc)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete_i(self, lst, indexes):
|
|
||||||
bcs = list(
|
|
||||||
map(
|
|
||||||
lambda x: x[1],
|
|
||||||
filter(
|
|
||||||
lambda x: x[0] in indexes,
|
|
||||||
enumerate(self._tabs[lst])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.delete(lst, bcs)
|
|
||||||
|
|
||||||
def sort(self, lst, reverse=False, key=None):
|
|
||||||
self._tabs[lst].sort(reverse=reverse, key=key)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def move_up(self, lst, index):
|
|
||||||
if index < len(self._tabs[lst]):
|
|
||||||
next = index - 1
|
|
||||||
|
|
||||||
l = self._tabs[lst]
|
|
||||||
l[index], l[next] = l[next], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def move_down(self, lst, index):
|
|
||||||
if index >= 0:
|
|
||||||
prev = index + 1
|
|
||||||
|
|
||||||
l = self._tabs[lst]
|
|
||||||
l[index], l[prev] = l[prev], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def __copy__(self):
|
def __copy__(self):
|
||||||
new = BoundaryConditionList()
|
new = BoundaryConditionList()
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
|
||||||
class Friction(SQLSubModel):
|
class Friction(SQLSubModel):
|
||||||
def __init__(self, name:str = "", status = None):
|
def __init__(self, name:str = "", status = None):
|
||||||
|
|||||||
@@ -21,26 +21,18 @@ import logging
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Tools.PamhyrList import PamhyrModelList
|
||||||
|
|
||||||
from Model.Friction.Friction import Friction
|
from Model.Friction.Friction import Friction
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
class FrictionList(SQLSubModel):
|
class FrictionList(PamhyrModelList):
|
||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
Friction
|
Friction
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, status = None):
|
|
||||||
super(FrictionList, self).__init__()
|
|
||||||
|
|
||||||
self._status = status
|
|
||||||
self._frictions = []
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _sql_create(cls, execute):
|
|
||||||
return cls._create_submodel(execute)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_update_0_0_1(cls, execute, version):
|
def _sql_update_0_0_1(cls, execute, version):
|
||||||
execute("ALTER TABLE `section` RENAME TO `friction`")
|
execute("ALTER TABLE `section` RENAME TO `friction`")
|
||||||
@@ -57,7 +49,7 @@ class FrictionList(SQLSubModel):
|
|||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data = None):
|
||||||
new = cls(status = data['status'])
|
new = cls(status = data['status'])
|
||||||
|
|
||||||
new._frictions = Friction._sql_load(
|
new._lst = Friction._sql_load(
|
||||||
execute, data
|
execute, data
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -69,70 +61,19 @@ class FrictionList(SQLSubModel):
|
|||||||
|
|
||||||
ok = True
|
ok = True
|
||||||
ind = 0
|
ind = 0
|
||||||
for friction in self._frictions:
|
for friction in self._lst:
|
||||||
data["ind"] = ind
|
data["ind"] = ind
|
||||||
ok &= friction._sql_save(execute, data = data)
|
ok &= friction._sql_save(execute, data = data)
|
||||||
ind += 1
|
ind += 1
|
||||||
|
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self._frictions)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def frictions(self):
|
def frictions(self):
|
||||||
return self._frictions.copy()
|
return self.lst
|
||||||
|
|
||||||
def get(self, row):
|
|
||||||
return self._frictions[row]
|
|
||||||
|
|
||||||
def set(self, row, new):
|
|
||||||
self._frictions[row] = new
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def new(self, index):
|
def new(self, index):
|
||||||
n = Friction(status = self._status)
|
n = Friction(status = self._status)
|
||||||
self._frictions.insert(index, n)
|
self._lst.insert(index, n)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
return n
|
return n
|
||||||
|
|
||||||
def insert(self, index, new):
|
|
||||||
self._frictions.insert(index, new)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete(self, frictions):
|
|
||||||
for friction in frictions:
|
|
||||||
self._frictions.remove(friction)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete_i(self, indexes):
|
|
||||||
frictions = list(
|
|
||||||
map(
|
|
||||||
lambda x: x[1],
|
|
||||||
filter(
|
|
||||||
lambda x: x[0] in indexes,
|
|
||||||
enumerate(self._frictions)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.delete(frictions)
|
|
||||||
|
|
||||||
def sort(self, reverse=False, key=None):
|
|
||||||
self._frictions.sort(reverse=reverse, key=key)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def move_up(self, index):
|
|
||||||
if index < len(self._frictions):
|
|
||||||
next = index - 1
|
|
||||||
|
|
||||||
l = self._frictions
|
|
||||||
l[index], l[next] = l[next], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def move_down(self, index):
|
|
||||||
if index >= 0:
|
|
||||||
prev = index + 1
|
|
||||||
|
|
||||||
l = self._frictions
|
|
||||||
l[index], l[prev] = l[prev], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
from math import dist
|
from math import dist
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Geometry.Point import Point
|
from Model.Geometry.Point import Point
|
||||||
|
|
||||||
class PointXYZ(Point, SQLSubModel):
|
class PointXYZ(Point, SQLSubModel):
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ from typing import List
|
|||||||
|
|
||||||
from tools import timer
|
from tools import timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import ClipboardFormatError
|
from Model.Except import ClipboardFormatError
|
||||||
from Model.Geometry.Profile import Profile
|
from Model.Geometry.Profile import Profile
|
||||||
from Model.Geometry.PointXYZ import PointXYZ
|
from Model.Geometry.PointXYZ import PointXYZ
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ from functools import reduce
|
|||||||
|
|
||||||
from tools import flatten, timer, trace
|
from tools import flatten, timer, trace
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
|
||||||
from Model.Geometry.Profile import Profile
|
from Model.Geometry.Profile import Profile
|
||||||
from Model.Geometry.ProfileXYZ import ProfileXYZ
|
from Model.Geometry.ProfileXYZ import ProfileXYZ
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ from copy import copy, deepcopy
|
|||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
|
||||||
class Data(SQLSubModel):
|
class Data(SQLSubModel):
|
||||||
def __init__(self, name:str = "",
|
def __init__(self, name:str = "",
|
||||||
|
|||||||
@@ -19,29 +19,14 @@
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDict import PamhyrModelDict
|
||||||
from Model.InitialConditions.InitialConditions import InitialConditions
|
from Model.InitialConditions.InitialConditions import InitialConditions
|
||||||
|
|
||||||
class InitialConditionsDict(SQLSubModel):
|
class InitialConditionsDict(PamhyrModelDict):
|
||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
InitialConditions,
|
InitialConditions,
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, status = None):
|
|
||||||
super(InitialConditionsDict, self).__init__()
|
|
||||||
|
|
||||||
self._status = status
|
|
||||||
|
|
||||||
self._reach = {}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _sql_create(cls, execute):
|
|
||||||
return cls._create_submodel(execute)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _sql_update(cls, execute, version):
|
|
||||||
return cls._update_submodel(execute, version)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data = None):
|
||||||
new = cls(status = data["status"])
|
new = cls(status = data["status"])
|
||||||
@@ -55,7 +40,7 @@ class InitialConditionsDict(SQLSubModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if ic is not None:
|
if ic is not None:
|
||||||
new._reach[reach] = ic
|
new._dict[reach] = ic
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
@@ -66,30 +51,12 @@ class InitialConditionsDict(SQLSubModel):
|
|||||||
|
|
||||||
execute("DELETE FROM initial_conditions")
|
execute("DELETE FROM initial_conditions")
|
||||||
|
|
||||||
for reach in self._reach:
|
for reach in self._dict:
|
||||||
data["reach"] = reach
|
data["reach"] = reach
|
||||||
ok &= self._reach[reach]._sql_save(execute, data)
|
ok &= self._dict[reach]._sql_save(execute, data)
|
||||||
|
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self._reach)
|
|
||||||
|
|
||||||
def is_defined(self, reach):
|
|
||||||
return reach in self._reach
|
|
||||||
|
|
||||||
def get(self, reach):
|
|
||||||
if reach in self._reach:
|
|
||||||
return self._reach[reach]
|
|
||||||
|
|
||||||
new = self.new(reach)
|
|
||||||
self.set(reach, new)
|
|
||||||
return new
|
|
||||||
|
|
||||||
def set(self, reach, new):
|
|
||||||
self._reach[reach] = new
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def new(self, reach):
|
def new(self, reach):
|
||||||
new = InitialConditions(reach = reach, status = self._status)
|
new = InitialConditions(reach = reach, status = self._status)
|
||||||
self.set(reach, new)
|
self.set(reach, new)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import logging
|
|||||||
|
|
||||||
from tools import trace, timer, old_pamhyr_date_to_timestamp
|
from tools import trace, timer, old_pamhyr_date_to_timestamp
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrList import PamhyrModelListWithTab
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
from Model.LateralContribution.LateralContribution import LateralContribution
|
from Model.LateralContribution.LateralContribution import LateralContribution
|
||||||
@@ -27,30 +27,12 @@ from Model.LateralContribution.LateralContributionTypes import (
|
|||||||
NotDefined, LateralContrib, Rain, Evaporation,
|
NotDefined, LateralContrib, Rain, Evaporation,
|
||||||
)
|
)
|
||||||
|
|
||||||
class LateralContributionList(SQLSubModel):
|
class LateralContributionList(PamhyrModelListWithTab):
|
||||||
|
_tabs_list = ["liquid", "solid", "suspenssion"]
|
||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
LateralContribution,
|
LateralContribution,
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, status = None):
|
|
||||||
super(LateralContributionList, self).__init__()
|
|
||||||
|
|
||||||
self._status = status
|
|
||||||
|
|
||||||
self._tabs = {
|
|
||||||
"liquid" : [],
|
|
||||||
"solid" : [],
|
|
||||||
"suspenssion" : []
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _sql_create(cls, execute):
|
|
||||||
return cls._create_submodel(execute)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _sql_update(cls, execute, version):
|
|
||||||
return True
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data = None):
|
||||||
new = cls(status = data['status'])
|
new = cls(status = data['status'])
|
||||||
@@ -79,66 +61,12 @@ class LateralContributionList(SQLSubModel):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def len(self, lst):
|
|
||||||
return len(self._tabs[lst])
|
|
||||||
|
|
||||||
def get_tab(self, lst):
|
|
||||||
return self._tabs[lst].copy()
|
|
||||||
|
|
||||||
def get(self, lst, row):
|
|
||||||
return self._tabs[lst][row]
|
|
||||||
|
|
||||||
def set(self, lst, row, new):
|
|
||||||
self._tabs[lst][row] = new
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def new(self, lst, index):
|
def new(self, lst, index):
|
||||||
n = NotDefined(status=self._status)
|
n = NotDefined(status=self._status)
|
||||||
self._tabs[lst].insert(index, n)
|
self._tabs[lst].insert(index, n)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
return n
|
return n
|
||||||
|
|
||||||
def insert(self, lst, index, new):
|
|
||||||
self._tabs[lst].insert(index, new)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete(self, lst, bcs):
|
|
||||||
for bc in bcs:
|
|
||||||
self._tabs[lst].remove(bc)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete_i(self, lst, indexes):
|
|
||||||
bcs = list(
|
|
||||||
map(
|
|
||||||
lambda x: x[1],
|
|
||||||
filter(
|
|
||||||
lambda x: x[0] in indexes,
|
|
||||||
enumerate(self._tabs[lst])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.delete(lst, bcs)
|
|
||||||
|
|
||||||
def sort(self, lst, reverse=False, key=None):
|
|
||||||
self._tabs[lst].sort(reverse=reverse, key=key)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def move_up(self, lst, index):
|
|
||||||
if index < len(self._tabs[lst]):
|
|
||||||
next = index - 1
|
|
||||||
|
|
||||||
l = self._tabs[lst]
|
|
||||||
l[index], l[next] = l[next], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def move_down(self, lst, index):
|
|
||||||
if index >= 0:
|
|
||||||
prev = index + 1
|
|
||||||
|
|
||||||
l = self._tabs[lst]
|
|
||||||
l[index], l[prev] = l[prev], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def __copy__(self):
|
def __copy__(self):
|
||||||
new = LateralContributionList()
|
new = LateralContributionList()
|
||||||
|
|
||||||
|
|||||||
+1
-5
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
from tools import flatten
|
from tools import flatten
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
|
||||||
from Model.Network.Node import Node
|
from Model.Network.Node import Node
|
||||||
from Model.Network.Edge import Edge
|
from Model.Network.Edge import Edge
|
||||||
@@ -311,10 +311,6 @@ class River(Graph, SQLSubModel):
|
|||||||
self._save_submodel(execute, objs, data)
|
self._save_submodel(execute, objs, data)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@property
|
|
||||||
def frictions(self):
|
|
||||||
return self._frictions
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def boundary_condition(self):
|
def boundary_condition(self):
|
||||||
return self._boundary_condition
|
return self._boundary_condition
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
class Layer(SQLSubModel):
|
class Layer(SQLSubModel):
|
||||||
|
|||||||
@@ -2,35 +2,18 @@
|
|||||||
|
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Tools.PamhyrList import PamhyrModelList
|
||||||
from Model.SedimentLayer.SedimentLayer import SedimentLayer
|
from Model.SedimentLayer.SedimentLayer import SedimentLayer
|
||||||
|
|
||||||
class SedimentLayerList(SQLSubModel):
|
class SedimentLayerList(PamhyrModelList):
|
||||||
_sub_classes = [SedimentLayer]
|
_sub_classes = [SedimentLayer]
|
||||||
|
|
||||||
def __init__(self, status = None):
|
|
||||||
super(SedimentLayerList, self).__init__()
|
|
||||||
|
|
||||||
self._status = status
|
|
||||||
self._sl = []
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self._sl)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _sql_create(cls, execute):
|
|
||||||
return cls._create_submodel(execute)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _sql_update(cls, execute, version):
|
|
||||||
return cls._update_submodel(execute, version)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data = None):
|
||||||
new = cls(status = data["status"])
|
new = cls(status = data["status"])
|
||||||
|
|
||||||
new._sl = SedimentLayer._sql_load(execute, data)
|
new._lst = SedimentLayer._sql_load(execute, data)
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
@@ -41,61 +24,17 @@ class SedimentLayerList(SQLSubModel):
|
|||||||
execute("DELETE FROM sedimentary_layer")
|
execute("DELETE FROM sedimentary_layer")
|
||||||
execute("DELETE FROM sedimentary_layer_layer")
|
execute("DELETE FROM sedimentary_layer_layer")
|
||||||
|
|
||||||
for sl in self._sl:
|
for sl in self._lst:
|
||||||
ok &= sl._sql_save(execute, data)
|
ok &= sl._sql_save(execute, data)
|
||||||
|
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sediment_layers(self):
|
def sediment_layers(self):
|
||||||
return self._sl.copy()
|
return self.lst
|
||||||
|
|
||||||
def get(self, index):
|
|
||||||
return self._sl[index]
|
|
||||||
|
|
||||||
def set(self, index, new):
|
|
||||||
self._sl[index] = new
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def insert(self, index, new):
|
|
||||||
self._sl.insert(index, new)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def new(self, index):
|
def new(self, index):
|
||||||
n = SedimentLayer(status = self._status)
|
n = SedimentLayer(status = self._status)
|
||||||
self.insert(index, n)
|
self.insert(index, n)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
return n
|
return n
|
||||||
|
|
||||||
def delete(self, els):
|
|
||||||
for el in els:
|
|
||||||
self._sl.remove(el)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete_i(self, indexes):
|
|
||||||
els = list(
|
|
||||||
map(
|
|
||||||
lambda x: x[1],
|
|
||||||
filter(
|
|
||||||
lambda x: x[0] in indexes,
|
|
||||||
enumerate(self._sl)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.delete(els)
|
|
||||||
|
|
||||||
def move_up(self, index):
|
|
||||||
if index < len(self._sl):
|
|
||||||
next = index - 1
|
|
||||||
|
|
||||||
l = self._sl
|
|
||||||
l[index], l[next] = l[next], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def move_down(self, index):
|
|
||||||
if index >= 0:
|
|
||||||
prev = index + 1
|
|
||||||
|
|
||||||
l = self._sl
|
|
||||||
l[index], l[prev] = l[prev], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
@@ -20,7 +20,7 @@ from copy import copy
|
|||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
from Solver.Solvers import solver_type_list
|
from Solver.Solvers import solver_type_list
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrList import PamhyrModelList
|
||||||
|
|
||||||
class Parameter():
|
class Parameter():
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
@@ -63,13 +63,13 @@ class Parameter():
|
|||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
class SolverParametersList(SQLSubModel):
|
class SolverParametersList(PamhyrModelList):
|
||||||
def __init__(self, solver_type = None, status = None):
|
def __init__(self, solver_type = None, status = None):
|
||||||
super(SolverParametersList, self).__init__()
|
super(SolverParametersList, self).__init__()
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
self._solver = solver_type
|
self._solver = solver_type
|
||||||
self._parameters = list(
|
self._lst = list(
|
||||||
map(
|
map(
|
||||||
lambda t: Parameter.from_tuple(t, self._status),
|
lambda t: Parameter.from_tuple(t, self._status),
|
||||||
solver_type.default_parameters()
|
solver_type.default_parameters()
|
||||||
@@ -194,7 +194,7 @@ class SolverParametersList(SQLSubModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
ind = 0
|
ind = 0
|
||||||
for param in self._parameters:
|
for param in self._lst:
|
||||||
sql = (
|
sql = (
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"solver_parameter(ind, name, value, solver) "+
|
"solver_parameter(ind, name, value, solver) "+
|
||||||
@@ -210,39 +210,36 @@ class SolverParametersList(SQLSubModel):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self._parameters)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def parameters(self):
|
def parameters(self):
|
||||||
return self._parameters.copy()
|
return self.lst
|
||||||
|
|
||||||
def get(self, index):
|
def get(self, index):
|
||||||
return self._parameters[index]
|
return self._lst[index]
|
||||||
|
|
||||||
def get_by_key(self, key):
|
def get_by_key(self, key):
|
||||||
try:
|
try:
|
||||||
return next(
|
return next(
|
||||||
filter(
|
filter(
|
||||||
lambda p: p["name"] == key,
|
lambda p: p["name"] == key,
|
||||||
self._parameters
|
self._lst
|
||||||
)
|
)
|
||||||
)["value"]
|
)["value"]
|
||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def set(self, index, new):
|
def set(self, index, new):
|
||||||
self._parameters[index] = new
|
self._lst[index] = new
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
def set_value(self, key, value):
|
def set_value(self, key, value):
|
||||||
for p in self._parameters:
|
for p in self._lst:
|
||||||
if p["name"] == key:
|
if p["name"] == key:
|
||||||
p["value"] = value
|
p["value"] = value
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
return
|
return
|
||||||
|
|
||||||
self._parameters.append(
|
self._lst.append(
|
||||||
Parameter(
|
Parameter(
|
||||||
name = key,
|
name = key,
|
||||||
value = value,
|
value = value,
|
||||||
@@ -253,47 +250,6 @@ class SolverParametersList(SQLSubModel):
|
|||||||
|
|
||||||
def new(self, index):
|
def new(self, index):
|
||||||
n = Parameter(status = self._status)
|
n = Parameter(status = self._status)
|
||||||
self._parameters.insert(index, n)
|
self._lst.insert(index, n)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
return n
|
return n
|
||||||
|
|
||||||
def insert(self, index, new):
|
|
||||||
self._parameters.insert(index, new)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete(self, parameters):
|
|
||||||
for parameter in parameters:
|
|
||||||
self._parameters.remove(parameter)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete_i(self, indexes):
|
|
||||||
parameters = list(
|
|
||||||
map(
|
|
||||||
lambda x: x[1],
|
|
||||||
filter(
|
|
||||||
lambda x: x[0] in indexes,
|
|
||||||
enumerate(self._parameters)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.delete(parameters)
|
|
||||||
|
|
||||||
def sort(self, reverse=False, key=None):
|
|
||||||
self._parameters.sort(reverse=reverse, key=key)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def move_up(self, index):
|
|
||||||
if index < len(self._parameters):
|
|
||||||
next = index - 1
|
|
||||||
|
|
||||||
l = self._parameters
|
|
||||||
l[index], l[next] = l[next], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def move_down(self, index):
|
|
||||||
if index >= 0:
|
|
||||||
prev = index + 1
|
|
||||||
|
|
||||||
l = self._parameters
|
|
||||||
l[index], l[prev] = l[prev], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
|
||||||
class Stricklers(SQLSubModel):
|
class Stricklers(SQLSubModel):
|
||||||
_id_cnt = 0
|
_id_cnt = 0
|
||||||
|
|||||||
@@ -18,22 +18,15 @@
|
|||||||
|
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
|
||||||
from Model.Saved import SavedStatus
|
from Model.Saved import SavedStatus
|
||||||
|
from Model.Tools.PamhyrList import PamhyrModelList
|
||||||
from Model.Stricklers.Stricklers import Stricklers
|
from Model.Stricklers.Stricklers import Stricklers
|
||||||
|
|
||||||
class StricklersList(SQLSubModel):
|
class StricklersList(PamhyrModelList):
|
||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
Stricklers,
|
Stricklers,
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, status = None):
|
|
||||||
if status is None:
|
|
||||||
status = SavedStatus()
|
|
||||||
self._status = status
|
|
||||||
|
|
||||||
self._stricks = []
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_create(cls, execute):
|
def _sql_create(cls, execute):
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
@@ -46,7 +39,7 @@ class StricklersList(SQLSubModel):
|
|||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data = None):
|
||||||
new = cls(status = data["status"])
|
new = cls(status = data["status"])
|
||||||
|
|
||||||
new._stricks = Stricklers._sql_load(
|
new._lst = Stricklers._sql_load(
|
||||||
execute,
|
execute,
|
||||||
data = data
|
data = data
|
||||||
)
|
)
|
||||||
@@ -56,60 +49,26 @@ class StricklersList(SQLSubModel):
|
|||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data = None):
|
||||||
execute("DELETE FROM stricklers")
|
execute("DELETE FROM stricklers")
|
||||||
|
|
||||||
objs = self._stricks
|
objs = self._lst
|
||||||
return self._save_submodel(execute, objs, data)
|
return self._save_submodel(execute, objs, data)
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self._stricks)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def stricklers(self):
|
def stricklers(self):
|
||||||
return self._stricks.copy()
|
return self.lst
|
||||||
|
|
||||||
def get(self, index):
|
def new(self, index):
|
||||||
if 0 <= index < len(self._stricks):
|
|
||||||
return self._stricks[index]
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def insert(self, index, strick):
|
|
||||||
self._stricks.insert(index, strick)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def add(self, index):
|
|
||||||
s = Stricklers(status = self._status)
|
s = Stricklers(status = self._status)
|
||||||
self.insert(index, s)
|
self.insert(index, s)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def delete(self, stricks):
|
|
||||||
self._stricks = list(
|
|
||||||
filter(
|
|
||||||
lambda s: s not in stricks,
|
|
||||||
self._stricks
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete_i(self, indexes):
|
|
||||||
stricks = set(
|
|
||||||
map(
|
|
||||||
lambda e: e[1],
|
|
||||||
filter(
|
|
||||||
lambda e: e[0] in indexes,
|
|
||||||
enumerate(self._stricks)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.delete(stricks)
|
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def sort(self, reverse:bool = False, key=None):
|
def sort(self, reverse:bool = False, key=None):
|
||||||
f = lambda st: st.name
|
f = lambda st: st.name
|
||||||
if key is not None:
|
if key is not None:
|
||||||
f = key
|
f = key
|
||||||
|
|
||||||
self._stricks = sorted(
|
self._lst = sorted(
|
||||||
self._stricks,
|
self._lst,
|
||||||
key = f,
|
key = f,
|
||||||
reverse = reverse,
|
reverse = reverse,
|
||||||
)
|
)
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ from datetime import datetime
|
|||||||
|
|
||||||
from tools import timer, timestamp
|
from tools import timer, timestamp
|
||||||
|
|
||||||
from Model.DB import SQLModel
|
from Model.Tools.PamhyrDB import SQLModel
|
||||||
from Model.Saved import SavedStatus
|
from Model.Saved import SavedStatus
|
||||||
from Model.Serializable import Serializable
|
from Model.Serializable import Serializable
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# DB.py -- Pamhyr abstract model database classes
|
# PamhyrDB.py -- Pamhyr abstract model database classes
|
||||||
# Copyright (C) 2023 INRAE
|
# Copyright (C) 2023 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
# PamhyrDict.py -- Pamhyr abstract dict for model classes
|
||||||
|
# Copyright (C) 2023 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from copy import copy
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class PamhyrModelDict(SQLSubModel):
|
||||||
|
_sub_classes = []
|
||||||
|
|
||||||
|
def __init__(self, status = None):
|
||||||
|
super(PamhyrModelDict, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
|
||||||
|
self._dict = {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_create(cls, execute):
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_update(cls, execute, version):
|
||||||
|
return cls._update_submodel(execute, version)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_load(cls, execute, data = None):
|
||||||
|
raise NotImplementedMethodeError(cls, cls._sql_load)
|
||||||
|
|
||||||
|
def _sql_save(self, execute, data = None):
|
||||||
|
raise NotImplementedMethodeError(self, self._sql_save)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._dict)
|
||||||
|
|
||||||
|
def is_defined(self, key):
|
||||||
|
return key in self._dict
|
||||||
|
|
||||||
|
def set(self, key, new):
|
||||||
|
self._dict[key] = new
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def get(self, key):
|
||||||
|
if key in self._dict:
|
||||||
|
return self._dict[key]
|
||||||
|
|
||||||
|
new = self.new(key)
|
||||||
|
self.set(key, new)
|
||||||
|
return new
|
||||||
|
|
||||||
|
def new(self, key):
|
||||||
|
raise NotImplementedMethodeError(self, self.new)
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
# PamhyrList.py -- Pamhyr Abstract List object for the Model
|
||||||
|
# Copyright (C) 2023 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from copy import copy
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class PamhyrModelList(SQLSubModel):
|
||||||
|
_sub_classes = [
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, status = None):
|
||||||
|
super(PamhyrModelList, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
self._lst = []
|
||||||
|
|
||||||
|
#######
|
||||||
|
# SQL #
|
||||||
|
#######
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_create(cls, execute):
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_update(cls, execute, version):
|
||||||
|
return cls._update_submodel(execute, version)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_load(cls, execute, data = None):
|
||||||
|
raise NotImplementedMethodeError(cls, cls._sql_load)
|
||||||
|
|
||||||
|
def _sql_save(self, execute, data = None):
|
||||||
|
raise NotImplementedMethodeError(self, self._sql_save)
|
||||||
|
|
||||||
|
################
|
||||||
|
# MODEL METHOD #
|
||||||
|
################
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._lst)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lst(self):
|
||||||
|
return self._lst.copy()
|
||||||
|
|
||||||
|
def get(self, row):
|
||||||
|
return self._lst[row]
|
||||||
|
|
||||||
|
def set(self, row, new):
|
||||||
|
self._lst[row] = new
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def new(self, index):
|
||||||
|
"""Create new elements and add it to list
|
||||||
|
|
||||||
|
Args:
|
||||||
|
index: The index of new elements
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The new elements
|
||||||
|
"""
|
||||||
|
raise NotImplementedMethodeError(self, self.new)
|
||||||
|
|
||||||
|
def insert(self, index, new):
|
||||||
|
self._lst.insert(index, new)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def delete(self, lst):
|
||||||
|
for el in lst:
|
||||||
|
self._lst.remove(el)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def delete_i(self, indexes):
|
||||||
|
lst = list(
|
||||||
|
map(
|
||||||
|
lambda x: x[1],
|
||||||
|
filter(
|
||||||
|
lambda x: x[0] in indexes,
|
||||||
|
enumerate(self._lst)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.delete(lst)
|
||||||
|
|
||||||
|
def sort(self, reverse=False, key=None):
|
||||||
|
self._lst.sort(reverse=reverse, key=key)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def move_up(self, index):
|
||||||
|
if index < len(self._lst):
|
||||||
|
next = index - 1
|
||||||
|
|
||||||
|
l = self._lst
|
||||||
|
l[index], l[next] = l[next], l[index]
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def move_down(self, index):
|
||||||
|
if index >= 0:
|
||||||
|
prev = index + 1
|
||||||
|
|
||||||
|
l = self._lst
|
||||||
|
l[index], l[prev] = l[prev], l[index]
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
|
||||||
|
class PamhyrModelListWithTab(SQLSubModel):
|
||||||
|
_tabs_list = []
|
||||||
|
_sub_classes = [
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, status = None):
|
||||||
|
super(PamhyrModelListWithTab, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
self._tabs = {}
|
||||||
|
for tab in self._tabs_list:
|
||||||
|
self._tabs[tab] = []
|
||||||
|
|
||||||
|
#######
|
||||||
|
# SQL #
|
||||||
|
#######
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_create(cls, execute):
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_update(cls, execute, version):
|
||||||
|
return cls._update_submodel(execute, version)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_load(cls, execute, data = None):
|
||||||
|
raise NotImplementedMethodeError(cls, cls._sql_load)
|
||||||
|
|
||||||
|
def _sql_save(self, execute, data = None):
|
||||||
|
raise NotImplementedMethodeError(self, self._sql_save)
|
||||||
|
|
||||||
|
################
|
||||||
|
# MODEL METHOD #
|
||||||
|
################
|
||||||
|
|
||||||
|
def len(self, lst):
|
||||||
|
return len(self._tabs[lst])
|
||||||
|
|
||||||
|
def get_tab(self, lst):
|
||||||
|
return self._tabs[lst].copy()
|
||||||
|
|
||||||
|
def get(self, lst, row):
|
||||||
|
return self._tabs[lst][row]
|
||||||
|
|
||||||
|
def set(self, lst, row, new):
|
||||||
|
self._tabs[lst][row] = new
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def new(self, lst, index):
|
||||||
|
"""Create new elements and add it to list
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lst: The tab name
|
||||||
|
index: The index of new elements
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The new elements
|
||||||
|
"""
|
||||||
|
raise NotImplementedMethodeError(self, self.new)
|
||||||
|
|
||||||
|
def insert(self, lst, index, new):
|
||||||
|
self._tabs[lst].insert(index, new)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def delete(self, lst, els):
|
||||||
|
for el in els:
|
||||||
|
self._tabs[lst].remove(el)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def delete_i(self, lst, indexes):
|
||||||
|
els = list(
|
||||||
|
map(
|
||||||
|
lambda x: x[1],
|
||||||
|
filter(
|
||||||
|
lambda x: x[0] in indexes,
|
||||||
|
enumerate(self._tabs[lst])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.delete(lst, els)
|
||||||
|
|
||||||
|
def sort(self, lst, reverse=False, key=None):
|
||||||
|
self._tabs[lst].sort(reverse=reverse, key=key)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def move_up(self, lst, index):
|
||||||
|
if index < len(self._tabs[lst]):
|
||||||
|
next = index - 1
|
||||||
|
|
||||||
|
l = self._tabs[lst]
|
||||||
|
l[index], l[next] = l[next], l[index]
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def move_down(self, lst, index):
|
||||||
|
if index >= 0:
|
||||||
|
prev = index + 1
|
||||||
|
|
||||||
|
l = self._tabs[lst]
|
||||||
|
l[index], l[prev] = l[prev], l[index]
|
||||||
|
self._status.modified()
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# AScript.py -- Pamhyr abstract script class
|
||||||
|
# Copyright (C) 2023 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
class AScript(object):
|
||||||
|
name = ""
|
||||||
|
description = ""
|
||||||
|
|
||||||
|
def __init__(self, app, conf, args):
|
||||||
|
super(AScript, self).__init__()
|
||||||
|
|
||||||
|
self._app = app
|
||||||
|
self._conf = conf
|
||||||
|
self._args = args.copy()
|
||||||
|
|
||||||
|
def usage(self):
|
||||||
|
raise NotImplementedMethodeError(self, self.usage)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
raise NotImplementedMethodeError(self, self.run)
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# help.py -- Pamhyr
|
||||||
|
# Copyright (C) 2023 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from Scripts.AScript import AScript
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class ScriptHello(AScript):
|
||||||
|
name = "Hello"
|
||||||
|
description = "Display hello"
|
||||||
|
|
||||||
|
def usage(self):
|
||||||
|
logger.info(f"Usage : {self._args[0]} hello")
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
logger.info("Hello from Pamhyr2 script !")
|
||||||
|
return 0
|
||||||
@@ -22,6 +22,7 @@ import logging
|
|||||||
from tools import timer
|
from tools import timer
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# Installation allow Unix-like signal
|
||||||
from signal import SIGTERM, SIGSTOP, SIGCONT
|
from signal import SIGTERM, SIGSTOP, SIGCONT
|
||||||
_signal = True
|
_signal = True
|
||||||
except:
|
except:
|
||||||
@@ -201,7 +202,7 @@ class AbstractSolver(object):
|
|||||||
return os.path.abspath(
|
return os.path.abspath(
|
||||||
os.path.join(
|
os.path.join(
|
||||||
os.path.dirname(__file__),
|
os.path.dirname(__file__),
|
||||||
".."
|
"..", ".."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -216,7 +217,6 @@ class AbstractSolver(object):
|
|||||||
The executable and list of arguments
|
The executable and list of arguments
|
||||||
"""
|
"""
|
||||||
# HACK: Works in most case... Trust me i'm an engineer
|
# HACK: Works in most case... Trust me i'm an engineer
|
||||||
|
|
||||||
cmd = cmd.replace("@install_dir", self._install_dir())
|
cmd = cmd.replace("@install_dir", self._install_dir())
|
||||||
cmd = cmd.replace("@path", path.replace(" ", "\ "))
|
cmd = cmd.replace("@path", path.replace(" ", "\ "))
|
||||||
cmd = cmd.replace("@input", self.input_param())
|
cmd = cmd.replace("@input", self.input_param())
|
||||||
@@ -358,6 +358,7 @@ class AbstractSolver(object):
|
|||||||
|
|
||||||
def start(self, study, process = None):
|
def start(self, study, process = None):
|
||||||
if _signal:
|
if _signal:
|
||||||
|
# Solver is PAUSED, so continue execution
|
||||||
if self._status == STATUS.PAUSED:
|
if self._status == STATUS.PAUSED:
|
||||||
os.kill(self._process.pid(), SIGCONT)
|
os.kill(self._process.pid(), SIGCONT)
|
||||||
self._status = STATUS.RUNNING
|
self._status = STATUS.RUNNING
|
||||||
@@ -371,6 +372,7 @@ class AbstractSolver(object):
|
|||||||
if self._process is None:
|
if self._process is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# Send SIGSTOP to PAUSED solver
|
||||||
os.kill(self._process.pid(), SIGSTOP)
|
os.kill(self._process.pid(), SIGSTOP)
|
||||||
self._status = STATUS.PAUSED
|
self._status = STATUS.PAUSED
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ from tools import trace, timer
|
|||||||
|
|
||||||
from View.ASubWindow import ASubMainWindow, AWidget
|
from View.ASubWindow import ASubMainWindow, AWidget
|
||||||
from View.ListedSubWindow import ListedSubWindow
|
from View.ListedSubWindow import ListedSubWindow
|
||||||
|
from View.Tools.PamhyrTable import PamhyrTableModel
|
||||||
|
|
||||||
from PyQt5.QtCore import (
|
from PyQt5.QtCore import (
|
||||||
Qt, QVariant, QAbstractTableModel,
|
Qt, QVariant, QAbstractTableModel,
|
||||||
@@ -53,125 +54,7 @@ _translate = QCoreApplication.translate
|
|||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
class ExtendedTimeEdit(AWidget):
|
class TableModel(PamhyrTableModel):
|
||||||
def __init__(self, parent=None):
|
|
||||||
super(ExtendedTimeEdit, self).__init__(
|
|
||||||
ui="extendedTimeEdit",
|
|
||||||
parent=parent
|
|
||||||
)
|
|
||||||
self.parent = parent
|
|
||||||
|
|
||||||
self.spinBox_days = self.find(QSpinBox, "spinBox_days")
|
|
||||||
self.timeEdit = self.find(QTimeEdit, "timeEdit")
|
|
||||||
|
|
||||||
def set_time(self, time):
|
|
||||||
days = 0
|
|
||||||
stime = time
|
|
||||||
|
|
||||||
# if ',' in time, time format is 'DD days, HH:MM:SS',
|
|
||||||
# otherelse is 'HH:MM:SS'
|
|
||||||
if "," in time:
|
|
||||||
s = time.strip().split(" ")
|
|
||||||
days = int(s[0])
|
|
||||||
stime = s[-1]
|
|
||||||
|
|
||||||
qtime = QTime.fromString(
|
|
||||||
stime,
|
|
||||||
"h:mm:ss"
|
|
||||||
)
|
|
||||||
self.spinBox_days.setValue(days)
|
|
||||||
self.timeEdit.setTime(qtime)
|
|
||||||
|
|
||||||
def get_time(self):
|
|
||||||
days = self.spinBox_days.value()
|
|
||||||
time = self.timeEdit.time().toPyTime()
|
|
||||||
secs = (
|
|
||||||
(time.hour * 3600) +
|
|
||||||
(time.minute * 60) +
|
|
||||||
time.second
|
|
||||||
)
|
|
||||||
|
|
||||||
return timedelta(days=days, seconds=secs)
|
|
||||||
|
|
||||||
class ExtendedDateTimeEdit(AWidget):
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
super(ExtendedDateTimeEdit, self).__init__(
|
|
||||||
ui="extendedDateTimeEdit",
|
|
||||||
parent=parent
|
|
||||||
)
|
|
||||||
self.parent = parent
|
|
||||||
|
|
||||||
self.dateTimeEdit = self.find(QDateTimeEdit, "dateTimeEdit")
|
|
||||||
|
|
||||||
def set_time(self, time):
|
|
||||||
qdatetime = QDateTime.fromString(
|
|
||||||
time,
|
|
||||||
"yyyy-MM-dd hh:mm:ss"
|
|
||||||
)
|
|
||||||
self.dateTimeEdit.setDateTime(qdatetime)
|
|
||||||
|
|
||||||
def get_time(self):
|
|
||||||
time = self.dateTimeEdit.dateTime().toPyDateTime()
|
|
||||||
return time
|
|
||||||
|
|
||||||
class ExTimeDelegate(QItemDelegate):
|
|
||||||
def __init__(self, data=None, mode="time", parent=None):
|
|
||||||
super(ExTimeDelegate, self).__init__(parent)
|
|
||||||
|
|
||||||
self._data = data
|
|
||||||
self._mode = mode
|
|
||||||
|
|
||||||
def createEditor(self, parent, option, index):
|
|
||||||
if self._mode == "time":
|
|
||||||
self.editor = ExtendedTimeEdit(parent=parent)
|
|
||||||
else:
|
|
||||||
self.editor = ExtendedDateTimeEdit(parent=parent)
|
|
||||||
value = index.data(Qt.DisplayRole)
|
|
||||||
self.editor.set_time(value)
|
|
||||||
logger.debug(str(value))
|
|
||||||
return self.editor
|
|
||||||
|
|
||||||
def setModelData(self, editor, model, index):
|
|
||||||
time = editor.get_time()
|
|
||||||
if self._mode == "time":
|
|
||||||
model.setData(index, int(time.total_seconds()))
|
|
||||||
else:
|
|
||||||
logger.debug(str(time.timestamp()))
|
|
||||||
model.setData(index, int(time.timestamp()))
|
|
||||||
editor.close()
|
|
||||||
editor.deleteLater()
|
|
||||||
|
|
||||||
def updateEditorGeometry(self, editor, option, index):
|
|
||||||
r = QRect(option.rect)
|
|
||||||
if self.editor.windowFlags() & Qt.Popup and editor.parent() is not None:
|
|
||||||
r.setTopLeft(self.editor.parent().mapToGlobal(r.topLeft()))
|
|
||||||
editor.setGeometry(r)
|
|
||||||
|
|
||||||
@pyqtSlot()
|
|
||||||
def currentItemChanged(self):
|
|
||||||
self.commitData.emit(self.sender())
|
|
||||||
|
|
||||||
|
|
||||||
class TableModel(QAbstractTableModel):
|
|
||||||
def __init__(self, data=None, mode="time", undo=None):
|
|
||||||
super(QAbstractTableModel, self).__init__()
|
|
||||||
self._headers = data.header
|
|
||||||
self._data = data
|
|
||||||
self._mode = mode
|
|
||||||
self._undo = undo
|
|
||||||
|
|
||||||
def flags(self, index):
|
|
||||||
options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
|
||||||
options |= Qt.ItemIsEditable
|
|
||||||
|
|
||||||
return options
|
|
||||||
|
|
||||||
def rowCount(self, parent):
|
|
||||||
return len(self._data)
|
|
||||||
|
|
||||||
def columnCount(self, parent):
|
|
||||||
return len(self._headers)
|
|
||||||
|
|
||||||
def data(self, index, role):
|
def data(self, index, role):
|
||||||
if role == Qt.TextAlignmentRole:
|
if role == Qt.TextAlignmentRole:
|
||||||
return Qt.AlignHCenter | Qt.AlignVCenter
|
return Qt.AlignHCenter | Qt.AlignVCenter
|
||||||
@@ -189,7 +72,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
if self._data.get_type_column(column) == float:
|
if self._data.get_type_column(column) == float:
|
||||||
value = f"{v:.4f}"
|
value = f"{v:.4f}"
|
||||||
elif self._data.header[column] == "time":
|
elif self._data.header[column] == "time":
|
||||||
if self._mode == "time":
|
if self._opt_data == "time":
|
||||||
t0 = datetime.fromtimestamp(0)
|
t0 = datetime.fromtimestamp(0)
|
||||||
t = datetime.fromtimestamp(v)
|
t = datetime.fromtimestamp(v)
|
||||||
value = str(t - t0)
|
value = str(t - t0)
|
||||||
@@ -200,12 +83,6 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def headerData(self, section, orientation, role):
|
|
||||||
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
|
|
||||||
return table_headers[self._headers[section]]
|
|
||||||
|
|
||||||
return QVariant()
|
|
||||||
|
|
||||||
def setData(self, index, value, role=Qt.EditRole):
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
if not index.isValid() or role != Qt.EditRole:
|
if not index.isValid() or role != Qt.EditRole:
|
||||||
return False
|
return False
|
||||||
@@ -315,12 +192,3 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self.layoutAboutToBeChanged.emit()
|
self.layoutAboutToBeChanged.emit()
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
|
||||||
def undo(self):
|
|
||||||
self._undo.undo()
|
|
||||||
self.layoutChanged.emit()
|
|
||||||
|
|
||||||
def redo(self):
|
|
||||||
self._undo.redo()
|
|
||||||
self.layoutChanged.emit()
|
|
||||||
@@ -16,10 +16,13 @@
|
|||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
from tools import timer, trace
|
from tools import timer, trace
|
||||||
|
|
||||||
from View.ASubWindow import ASubMainWindow, AWidget
|
from View.ASubWindow import ASubMainWindow, AWidget
|
||||||
from View.ListedSubWindow import ListedSubWindow
|
from View.ListedSubWindow import ListedSubWindow
|
||||||
|
from View.Tools.PamhyrDelegate import PamhyrExTimeDelegate
|
||||||
|
|
||||||
from PyQt5.QtGui import (
|
from PyQt5.QtGui import (
|
||||||
QKeySequence,
|
QKeySequence,
|
||||||
@@ -39,15 +42,18 @@ from PyQt5.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from View.Plot.MplCanvas import MplCanvas
|
from View.Plot.MplCanvas import MplCanvas
|
||||||
from View.Plot.navigation_toolbar_2qt import PamHyrNavigationToolbar2QT
|
from View.Plot.PamhyrToolbar import PamhyrPlotToolbar
|
||||||
|
|
||||||
from View.BoundaryCondition.translate import long_types
|
from View.BoundaryCondition.translate import long_types
|
||||||
|
from View.BoundaryCondition.Edit.translate import table_headers, retranslate
|
||||||
from View.BoundaryCondition.Edit.UndoCommand import SetMetaDataCommand
|
from View.BoundaryCondition.Edit.UndoCommand import SetMetaDataCommand
|
||||||
from View.BoundaryCondition.Edit.Table import TableModel, ExTimeDelegate
|
from View.BoundaryCondition.Edit.Table import TableModel
|
||||||
from View.BoundaryCondition.Edit.Plot import Plot
|
from View.BoundaryCondition.Edit.Plot import Plot
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
class WD50Sigma(AWidget):
|
class WD50Sigma(AWidget):
|
||||||
d50Changed = pyqtSignal(float)
|
d50Changed = pyqtSignal(float)
|
||||||
sigmaChanged = pyqtSignal(float)
|
sigmaChanged = pyqtSignal(float)
|
||||||
@@ -141,23 +147,29 @@ class EditBoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self._d50sigma.set_sigma(self._data.sigma)
|
self._d50sigma.set_sigma(self._data.sigma)
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
table = self.find(QTableView, "tableView")
|
retranslate()
|
||||||
self._table = TableModel(
|
headers = {}
|
||||||
|
for h in self._data.header:
|
||||||
|
headers[h] = table_headers[h]
|
||||||
|
|
||||||
|
self._delegate_time = PamhyrExTimeDelegate(
|
||||||
data = self._data,
|
data = self._data,
|
||||||
undo = self._undo_stack,
|
mode = self._study.time_system,
|
||||||
mode = self._study.time_system
|
parent = self
|
||||||
)
|
)
|
||||||
|
|
||||||
if self._data.header[0] == "time":
|
table = self.find(QTableView, "tableView")
|
||||||
self._delegate_time = ExTimeDelegate(
|
self._table = TableModel(
|
||||||
data = self._data,
|
table_view = table,
|
||||||
mode = self._study.time_system,
|
table_headers = headers,
|
||||||
parent = self
|
editable_headers = self._data.header,
|
||||||
)
|
delegates = {
|
||||||
|
"time": self._delegate_time,
|
||||||
table.setItemDelegateForColumn(
|
},
|
||||||
0, self._delegate_time
|
data = self._data,
|
||||||
)
|
undo = self._undo_stack,
|
||||||
|
opt_data = self._study.time_system
|
||||||
|
)
|
||||||
|
|
||||||
table.setModel(self._table)
|
table.setModel(self._table)
|
||||||
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
@@ -167,7 +179,7 @@ class EditBoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
def setup_plot(self):
|
def setup_plot(self):
|
||||||
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas.setObjectName("canvas")
|
self.canvas.setObjectName("canvas")
|
||||||
self.toolbar = PamHyrNavigationToolbar2QT(
|
self.toolbar = PamhyrPlotToolbar(
|
||||||
self.canvas, self
|
self.canvas, self
|
||||||
)
|
)
|
||||||
self.verticalLayout.addWidget(self.toolbar)
|
self.verticalLayout.addWidget(self.toolbar)
|
||||||
|
|||||||
@@ -29,3 +29,12 @@ table_headers = {
|
|||||||
"z": _translate("BoundaryCondition", "Z (m)"),
|
"z": _translate("BoundaryCondition", "Z (m)"),
|
||||||
"solid": _translate("BoundaryCondition", "Solid (kg/s)"),
|
"solid": _translate("BoundaryCondition", "Solid (kg/s)"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def retranslate():
|
||||||
|
table_headers["x"] = _translate("BoundaryCondition", "X")
|
||||||
|
table_headers["y"] = _translate("BoundaryCondition", "Y")
|
||||||
|
table_headers["time"] = _translate("BoundaryCondition", "Time")
|
||||||
|
table_headers["date"] = _translate("BoundaryCondition", "Date")
|
||||||
|
table_headers["discharge"] = _translate("BoundaryCondition", "Discharge (m³/s)")
|
||||||
|
table_headers["z"] = _translate("BoundaryCondition", "Z (m)")
|
||||||
|
table_headers["solid"] = _translate("BoundaryCondition", "Solid (kg/s)")
|
||||||
@@ -39,6 +39,8 @@ from Model.BoundaryCondition.BoundaryConditionTypes import (
|
|||||||
TimeOverZ, TimeOverDischarge, ZOverDischarge
|
TimeOverZ, TimeOverDischarge, ZOverDischarge
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from View.Tools.PamhyrTable import PamhyrTableModel
|
||||||
|
|
||||||
from View.BoundaryCondition.UndoCommand import (
|
from View.BoundaryCondition.UndoCommand import (
|
||||||
SetNameCommand, SetNodeCommand, SetTypeCommand,
|
SetNameCommand, SetNodeCommand, SetTypeCommand,
|
||||||
AddCommand, DelCommand, SortCommand,
|
AddCommand, DelCommand, SortCommand,
|
||||||
@@ -104,26 +106,13 @@ class ComboBoxDelegate(QItemDelegate):
|
|||||||
self.commitData.emit(self.sender())
|
self.commitData.emit(self.sender())
|
||||||
|
|
||||||
|
|
||||||
class TableModel(QAbstractTableModel):
|
class TableModel(PamhyrTableModel):
|
||||||
def __init__(self, data=None, undo=None, tab=""):
|
def _setup_lst(self):
|
||||||
super(QAbstractTableModel, self).__init__()
|
self._lst = self._data.boundary_condition
|
||||||
self._headers = list(table_headers.keys())
|
self._tab = self._opt_data
|
||||||
self._data = data
|
|
||||||
self._undo = undo
|
|
||||||
self._tab = tab
|
|
||||||
self._bcs = self._data.boundary_condition
|
|
||||||
|
|
||||||
def flags(self, index):
|
|
||||||
options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
|
||||||
options |= Qt.ItemIsEditable
|
|
||||||
|
|
||||||
return options
|
|
||||||
|
|
||||||
def rowCount(self, parent):
|
def rowCount(self, parent):
|
||||||
return self._bcs.len(self._tab)
|
return self._lst.len(self._tab)
|
||||||
|
|
||||||
def columnCount(self, parent):
|
|
||||||
return len(self._headers)
|
|
||||||
|
|
||||||
def data(self, index, role):
|
def data(self, index, role):
|
||||||
if role != Qt.ItemDataRole.DisplayRole:
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
@@ -133,24 +122,18 @@ class TableModel(QAbstractTableModel):
|
|||||||
column = index.column()
|
column = index.column()
|
||||||
|
|
||||||
if self._headers[column] == "name":
|
if self._headers[column] == "name":
|
||||||
return self._bcs.get(self._tab, row).name
|
return self._lst.get(self._tab, row).name
|
||||||
elif self._headers[column] == "type":
|
elif self._headers[column] == "type":
|
||||||
t = self._bcs.get(self._tab, row).bctype
|
t = self._lst.get(self._tab, row).bctype
|
||||||
return long_types[t]
|
return long_types[t]
|
||||||
elif self._headers[column] == "node":
|
elif self._headers[column] == "node":
|
||||||
n = self._bcs.get(self._tab, row).node
|
n = self._lst.get(self._tab, row).node
|
||||||
if n is None:
|
if n is None:
|
||||||
return _translate("BoundaryCondition", "Not associate")
|
return _translate("BoundaryCondition", "Not associate")
|
||||||
return n.name
|
return n.name
|
||||||
|
|
||||||
return QVariant()
|
return QVariant()
|
||||||
|
|
||||||
def headerData(self, section, orientation, role):
|
|
||||||
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
|
|
||||||
return table_headers[self._headers[section]]
|
|
||||||
|
|
||||||
return QVariant()
|
|
||||||
|
|
||||||
def setData(self, index, value, role=Qt.EditRole):
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
if not index.isValid() or role != Qt.EditRole:
|
if not index.isValid() or role != Qt.EditRole:
|
||||||
return False
|
return False
|
||||||
@@ -162,20 +145,20 @@ class TableModel(QAbstractTableModel):
|
|||||||
if self._headers[column] == "name":
|
if self._headers[column] == "name":
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
SetNameCommand(
|
SetNameCommand(
|
||||||
self._bcs, self._tab,row, value
|
self._lst, self._tab,row, value
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif self._headers[column] == "type":
|
elif self._headers[column] == "type":
|
||||||
key = next(k for k, v in long_types.items() if v == value)
|
key = next(k for k, v in long_types.items() if v == value)
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
SetTypeCommand(
|
SetTypeCommand(
|
||||||
self._bcs, self._tab,row, BC_types[key]
|
self._lst, self._tab,row, BC_types[key]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif self._headers[column] == "node":
|
elif self._headers[column] == "node":
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
SetNodeCommand(
|
SetNodeCommand(
|
||||||
self._bcs, self._tab,row, self._data.node(value)
|
self._lst, self._tab,row, self._data.node(value)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -190,7 +173,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
AddCommand(
|
AddCommand(
|
||||||
self._bcs, self._tab,row
|
self._lst, self._tab,row
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -202,7 +185,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
DelCommand(
|
DelCommand(
|
||||||
self._bcs, self._tab,rows
|
self._lst, self._tab, rows
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -214,7 +197,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
SortCommand(
|
SortCommand(
|
||||||
self._bcs, self._tab,False
|
self._lst, self._tab, False
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -231,7 +214,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self._undo_stack.push(
|
self._undo_stack.push(
|
||||||
MoveCommand(
|
MoveCommand(
|
||||||
self._bcs, self._tab,"up", row
|
self._lst, self._tab, "up", row
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -239,7 +222,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def move_down(self, index, parent=QModelIndex()):
|
def move_down(self, index, parent=QModelIndex()):
|
||||||
if row > len(self._bcs):
|
if row > len(self._lst):
|
||||||
return
|
return
|
||||||
|
|
||||||
target = row
|
target = row
|
||||||
@@ -248,7 +231,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self._undo_stack.push(
|
self._undo_stack.push(
|
||||||
MoveCommand(
|
MoveCommand(
|
||||||
self._bcs, self._tab,"down", row
|
self._lst, self._tab, "down", row
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ from View.BoundaryCondition.Table import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from View.Network.GraphWidget import GraphWidget
|
from View.Network.GraphWidget import GraphWidget
|
||||||
from View.BoundaryCondition.translate import *
|
from View.BoundaryCondition.translate import table_headers, retranslate
|
||||||
from View.BoundaryCondition.Edit.Window import EditBoundaryConditionWindow
|
from View.BoundaryCondition.Edit.Window import EditBoundaryConditionWindow
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
@@ -90,17 +90,10 @@ class BoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
|
retranslate()
|
||||||
self._table = {}
|
self._table = {}
|
||||||
|
|
||||||
for t in ["liquid", "solid", "suspenssion"]:
|
for t in ["liquid", "solid", "suspenssion"]:
|
||||||
table = self.find(QTableView, f"tableView_{t}")
|
|
||||||
self._table[t] = TableModel(
|
|
||||||
data = self._study.river,
|
|
||||||
undo = self._undo_stack,
|
|
||||||
tab = t,
|
|
||||||
)
|
|
||||||
table.setModel(self._table[t])
|
|
||||||
|
|
||||||
self._delegate_type = ComboBoxDelegate(
|
self._delegate_type = ComboBoxDelegate(
|
||||||
data = self._study.river,
|
data = self._study.river,
|
||||||
mode = "type",
|
mode = "type",
|
||||||
@@ -114,13 +107,20 @@ class BoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
parent=self
|
parent=self
|
||||||
)
|
)
|
||||||
|
|
||||||
table.setItemDelegateForColumn(
|
table = self.find(QTableView, f"tableView_{t}")
|
||||||
1, self._delegate_type
|
self._table[t] = TableModel(
|
||||||
|
table_view = table,
|
||||||
|
table_headers = table_headers,
|
||||||
|
editable_headers = ["name", "type", "node"],
|
||||||
|
delegates = {
|
||||||
|
"type": self._delegate_type,
|
||||||
|
"node": self._delegate_node,
|
||||||
|
},
|
||||||
|
data = self._study.river,
|
||||||
|
undo = self._undo_stack,
|
||||||
|
opt_data = t,
|
||||||
)
|
)
|
||||||
table.setItemDelegateForColumn(
|
table.setModel(self._table[t])
|
||||||
2, self._delegate_node
|
|
||||||
)
|
|
||||||
|
|
||||||
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
table.setAlternatingRowColors(True)
|
table.setAlternatingRowColors(True)
|
||||||
|
|||||||
@@ -49,3 +49,8 @@ BC_types = {
|
|||||||
"ZD": ZOverDischarge,
|
"ZD": ZOverDischarge,
|
||||||
"SL": Solid,
|
"SL": Solid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def retranslate():
|
||||||
|
table_headers["name"] = _translate("BoundaryCondition", "Name")
|
||||||
|
table_headers["type"] = _translate("BoundaryCondition", "Type")
|
||||||
|
table_headers["node"] = _translate("BoundaryCondition", "Node")
|
||||||
@@ -37,10 +37,11 @@ class Worker(QObject):
|
|||||||
self.signalStatus.emit('end')
|
self.signalStatus.emit('end')
|
||||||
|
|
||||||
def _compute(self):
|
def _compute(self):
|
||||||
|
# The computation loop
|
||||||
for checker in self._checker_list:
|
for checker in self._checker_list:
|
||||||
self.signalStatus.emit(checker.name)
|
self.signalStatus.emit(checker.name)
|
||||||
|
|
||||||
# time.sleep(1)
|
# Run checker
|
||||||
checker.run(self._study)
|
checker.run(self._study)
|
||||||
|
|
||||||
self.signalStatus.emit("progress")
|
self.signalStatus.emit("progress")
|
||||||
@@ -92,7 +92,9 @@ class ReplWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self.set_plaintext_edit_text("plainTextEdit", "")
|
self.set_plaintext_edit_text("plainTextEdit", "")
|
||||||
self._history_ind = 0
|
self._history_ind = 0
|
||||||
|
|
||||||
|
# Code to rich_code
|
||||||
rich_code = code.strip().split("\n")
|
rich_code = code.strip().split("\n")
|
||||||
|
# Add return variable for results display at last row
|
||||||
rich_code[-1] = "self.__debug_exec_result__ = " + rich_code[-1]
|
rich_code[-1] = "self.__debug_exec_result__ = " + rich_code[-1]
|
||||||
rich_code = "\n".join(rich_code)
|
rich_code = "\n".join(rich_code)
|
||||||
logger.debug(f"User debug command : {rich_code}")
|
logger.debug(f"User debug command : {rich_code}")
|
||||||
@@ -102,6 +104,8 @@ class ReplWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
value = f"<font color=\"red\">" + str(e) + "</font>"
|
value = f"<font color=\"red\">" + str(e) + "</font>"
|
||||||
|
|
||||||
|
# Display code
|
||||||
msg = f"<font color=\"grey\"> # " + code + " #</font>"
|
msg = f"<font color=\"grey\"> # " + code + " #</font>"
|
||||||
self.find(QTextEdit, "textEdit").append(msg)
|
self.find(QTextEdit, "textEdit").append(msg)
|
||||||
|
# Display results
|
||||||
self.find(QTextEdit, "textEdit").append(str(value))
|
self.find(QTextEdit, "textEdit").append(str(value))
|
||||||
@@ -51,7 +51,7 @@ from View.Frictions.Table import (
|
|||||||
from View.Plot.MplCanvas import MplCanvas
|
from View.Plot.MplCanvas import MplCanvas
|
||||||
from View.Geometry.PlotKPZ import PlotKPZ
|
from View.Geometry.PlotKPZ import PlotKPZ
|
||||||
from View.Frictions.PlotStricklers import PlotStricklers
|
from View.Frictions.PlotStricklers import PlotStricklers
|
||||||
from View.Frictions.translate import *
|
from View.Frictions.translate import table_headers, retranslate
|
||||||
|
|
||||||
from View.Stricklers.Window import StricklersWindow
|
from View.Stricklers.Window import StricklersWindow
|
||||||
|
|
||||||
@@ -94,6 +94,7 @@ class FrictionsWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
|
retranslate()
|
||||||
self._table = {}
|
self._table = {}
|
||||||
|
|
||||||
table = self.find(QTableView, f"tableView")
|
table = self.find(QTableView, f"tableView")
|
||||||
|
|||||||
@@ -28,3 +28,11 @@ table_headers = {
|
|||||||
"begin_strickler": _translate("Frictions", "Begin strickler"),
|
"begin_strickler": _translate("Frictions", "Begin strickler"),
|
||||||
"end_strickler": _translate("Frictions", "End strickler"),
|
"end_strickler": _translate("Frictions", "End strickler"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def retranslate():
|
||||||
|
table_headers["name"] = _translate("Frictions", "Name")
|
||||||
|
# table_headers["edge"] = _translate("Frictions", "Reach")
|
||||||
|
table_headers["begin_kp"] = _translate("Frictions", "Begin kp (m)")
|
||||||
|
table_headers["end_kp"] = _translate("Frictions", "End kp (m)")
|
||||||
|
table_headers["begin_strickler"] = _translate("Frictions", "Begin strickler")
|
||||||
|
table_headers["end_strickler"] = _translate("Frictions", "End strickler")
|
||||||
@@ -25,7 +25,8 @@ from PyQt5.QtWidgets import (
|
|||||||
QToolBar,
|
QToolBar,
|
||||||
)
|
)
|
||||||
|
|
||||||
from View.Plot import MplCanvas, navigation_toolbar_2qt
|
from View.Plot import MplCanvas
|
||||||
|
from View.Plot.PamhyrToolbar import PamhyrPlotToolbar
|
||||||
|
|
||||||
file_path = os.path.abspath(os.path.dirname(__file__))
|
file_path = os.path.abspath(os.path.dirname(__file__))
|
||||||
icon_path = f"{os.path.dirname(os.path.dirname(file_path))}/../View/ui/ressources/"
|
icon_path = f"{os.path.dirname(os.path.dirname(file_path))}/../View/ui/ressources/"
|
||||||
@@ -197,7 +198,7 @@ class Ui_MainWindow(object):
|
|||||||
self.canvas = MplCanvas.MplCanvas(width=5, height=4, dpi=100)
|
self.canvas = MplCanvas.MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas.setObjectName("canvas")
|
self.canvas.setObjectName("canvas")
|
||||||
|
|
||||||
self.my_toolbar = navigation_toolbar_2qt.PamHyrNavigationToolbar2QT(
|
self.my_toolbar = PamhyrPlotToolbar(
|
||||||
self.canvas, self.widget1
|
self.canvas, self.widget1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ from PyQt5.QtWidgets import (
|
|||||||
QAbstractItemView, QHeaderView, QToolBar,
|
QAbstractItemView, QHeaderView, QToolBar,
|
||||||
)
|
)
|
||||||
|
|
||||||
from View.Plot import (
|
from View.Plot import MplCanvas
|
||||||
MplCanvas, navigation_toolbar_2qt
|
from View.Plot.PamhyrToolbar import PamhyrPlotToolbar
|
||||||
)
|
|
||||||
|
|
||||||
file_path = os.path.abspath(os.path.dirname(__file__))
|
file_path = os.path.abspath(os.path.dirname(__file__))
|
||||||
icon_path = f"{os.path.dirname(os.path.dirname(file_path))}/View/ui/ressources/"
|
icon_path = f"{os.path.dirname(os.path.dirname(file_path))}/View/ui/ressources/"
|
||||||
@@ -190,7 +190,7 @@ class Ui_MainWindow(object):
|
|||||||
self.canvas_1 = MplCanvas.MplCanvas(width=5, height=4, dpi=100)
|
self.canvas_1 = MplCanvas.MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas_1.setObjectName("canvas_1")
|
self.canvas_1.setObjectName("canvas_1")
|
||||||
|
|
||||||
self.toolbar_1 = navigation_toolbar_2qt.PamHyrNavigationToolbar2QT(
|
self.toolbar_1 = PamhyrPlotToolbar(
|
||||||
self.canvas_1, self.centralwidget,
|
self.canvas_1, self.centralwidget,
|
||||||
items = ["home", "zoom", "save", "iso", "back/forward", "move"]
|
items = ["home", "zoom", "save", "iso", "back/forward", "move"]
|
||||||
)
|
)
|
||||||
@@ -207,7 +207,7 @@ class Ui_MainWindow(object):
|
|||||||
self.canvas_2 = MplCanvas.MplCanvas(width=5, height=4, dpi=100)
|
self.canvas_2 = MplCanvas.MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas_2.setObjectName("canvas_2")
|
self.canvas_2.setObjectName("canvas_2")
|
||||||
|
|
||||||
self.toolbar_2 = navigation_toolbar_2qt.PamHyrNavigationToolbar2QT(
|
self.toolbar_2 = PamhyrPlotToolbar(
|
||||||
self.canvas_2, self.centralwidget,
|
self.canvas_2, self.centralwidget,
|
||||||
items = ["home", "zoom", "save", "iso", "back/forward", "move"]
|
items = ["home", "zoom", "save", "iso", "back/forward", "move"]
|
||||||
)
|
)
|
||||||
@@ -223,7 +223,7 @@ class Ui_MainWindow(object):
|
|||||||
self.canvas_3 = MplCanvas.MplCanvas(width=5, height=4, dpi=100)
|
self.canvas_3 = MplCanvas.MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas_3.setObjectName("canvas_3")
|
self.canvas_3.setObjectName("canvas_3")
|
||||||
|
|
||||||
self.toolbar_3 = navigation_toolbar_2qt.PamHyrNavigationToolbar2QT(
|
self.toolbar_3 = PamhyrPlotToolbar(
|
||||||
self.canvas_3, self.centralwidget,
|
self.canvas_3, self.centralwidget,
|
||||||
items = ["home", "zoom", "save", "iso", "back/forward", "move"]
|
items = ["home", "zoom", "save", "iso", "back/forward", "move"]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -49,11 +49,11 @@ from View.InitialConditions.UndoCommand import (
|
|||||||
from View.InitialConditions.Table import TableModel, ComboBoxDelegate
|
from View.InitialConditions.Table import TableModel, ComboBoxDelegate
|
||||||
|
|
||||||
from View.Plot.MplCanvas import MplCanvas
|
from View.Plot.MplCanvas import MplCanvas
|
||||||
from View.Plot.navigation_toolbar_2qt import PamHyrNavigationToolbar2QT
|
from View.Plot.PamhyrToolbar import PamhyrPlotToolbar
|
||||||
|
|
||||||
from View.InitialConditions.PlotDKP import PlotDKP
|
from View.InitialConditions.PlotDKP import PlotDKP
|
||||||
from View.InitialConditions.PlotDischarge import PlotDischarge
|
from View.InitialConditions.PlotDischarge import PlotDischarge
|
||||||
from View.InitialConditions.translate import *
|
from View.InitialConditions.translate import table_headers, retranslate
|
||||||
from View.InitialConditions.DialogHeight import HeightDialog
|
from View.InitialConditions.DialogHeight import HeightDialog
|
||||||
from View.InitialConditions.DialogDischarge import DischargeDialog
|
from View.InitialConditions.DialogDischarge import DischargeDialog
|
||||||
|
|
||||||
@@ -97,6 +97,8 @@ class InitialConditionsWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
|
retranslate()
|
||||||
|
|
||||||
table = self.find(QTableView, f"tableView")
|
table = self.find(QTableView, f"tableView")
|
||||||
self._table = TableModel(
|
self._table = TableModel(
|
||||||
river = self._study.river,
|
river = self._study.river,
|
||||||
@@ -122,7 +124,7 @@ class InitialConditionsWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
def setup_graph(self):
|
def setup_graph(self):
|
||||||
self.canvas_1 = MplCanvas(width=5, height=4, dpi=100)
|
self.canvas_1 = MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas_1.setObjectName("canvas_1")
|
self.canvas_1.setObjectName("canvas_1")
|
||||||
self.toolbar_1 = PamHyrNavigationToolbar2QT(
|
self.toolbar_1 = PamhyrPlotToolbar(
|
||||||
self.canvas_1, self
|
self.canvas_1, self
|
||||||
)
|
)
|
||||||
self.plot_layout_1 = self.find(QVBoxLayout, "verticalLayout_1")
|
self.plot_layout_1 = self.find(QVBoxLayout, "verticalLayout_1")
|
||||||
@@ -138,7 +140,7 @@ class InitialConditionsWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
|
|
||||||
self.canvas_2 = MplCanvas(width=5, height=4, dpi=100)
|
self.canvas_2 = MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas_2.setObjectName("canvas_2")
|
self.canvas_2.setObjectName("canvas_2")
|
||||||
self.toolbar_2 = PamHyrNavigationToolbar2QT(
|
self.toolbar_2 = PamhyrPlotToolbar(
|
||||||
self.canvas_2, self
|
self.canvas_2, self
|
||||||
)
|
)
|
||||||
self.plot_layout_2 = self.find(QVBoxLayout, "verticalLayout_2")
|
self.plot_layout_2 = self.find(QVBoxLayout, "verticalLayout_2")
|
||||||
|
|||||||
@@ -29,3 +29,12 @@ table_headers = {
|
|||||||
"height": _translate("LateralContribution", "Height (m)"),
|
"height": _translate("LateralContribution", "Height (m)"),
|
||||||
# "comment": _translate("LateralContribution", "Comment"),
|
# "comment": _translate("LateralContribution", "Comment"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def retranslate():
|
||||||
|
# table_headers["name"] = _translate("LateralContribution", "Name")
|
||||||
|
table_headers["kp"] = _translate("LateralContribution", "KP (m)")
|
||||||
|
# table_headers["speed"] = _translate("LateralContribution", "Speed (m/s)")
|
||||||
|
table_headers["discharge"] = _translate("LateralContribution", "Discharge (m³/s)")
|
||||||
|
table_headers["elevation"] = _translate("LateralContribution", "Elevation (m)")
|
||||||
|
table_headers["height"] = _translate("LateralContribution", "Height (m)")
|
||||||
|
# table_headers["comment"] = _translate("LateralContribution", "Comment")
|
||||||
@@ -24,6 +24,7 @@ from tools import trace, timer
|
|||||||
|
|
||||||
from View.ASubWindow import ASubMainWindow, AWidget
|
from View.ASubWindow import ASubMainWindow, AWidget
|
||||||
from View.ListedSubWindow import ListedSubWindow
|
from View.ListedSubWindow import ListedSubWindow
|
||||||
|
from View.Tools.PamhyrTable import PamhyrTableModel
|
||||||
|
|
||||||
from PyQt5.QtCore import (
|
from PyQt5.QtCore import (
|
||||||
Qt, QVariant, QAbstractTableModel,
|
Qt, QVariant, QAbstractTableModel,
|
||||||
@@ -51,125 +52,8 @@ _translate = QCoreApplication.translate
|
|||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
class ExtendedTimeEdit(AWidget):
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
super(ExtendedTimeEdit, self).__init__(
|
|
||||||
ui="extendedTimeEdit",
|
|
||||||
parent=parent
|
|
||||||
)
|
|
||||||
self.parent = parent
|
|
||||||
|
|
||||||
self.spinBox_days = self.find(QSpinBox, "spinBox_days")
|
|
||||||
self.timeEdit = self.find(QTimeEdit, "timeEdit")
|
|
||||||
|
|
||||||
def set_time(self, time):
|
|
||||||
days = 0
|
|
||||||
stime = time
|
|
||||||
|
|
||||||
# if ',' in time, time format is 'DD days, HH:MM:SS',
|
|
||||||
# otherelse is 'HH:MM:SS'
|
|
||||||
if "," in time:
|
|
||||||
s = time.strip().split(" ")
|
|
||||||
days = int(s[0])
|
|
||||||
stime = s[-1]
|
|
||||||
|
|
||||||
qtime = QTime.fromString(
|
|
||||||
stime,
|
|
||||||
"h:mm:ss"
|
|
||||||
)
|
|
||||||
self.spinBox_days.setValue(days)
|
|
||||||
self.timeEdit.setTime(qtime)
|
|
||||||
|
|
||||||
def get_time(self):
|
|
||||||
days = self.spinBox_days.value()
|
|
||||||
time = self.timeEdit.time().toPyTime()
|
|
||||||
secs = (
|
|
||||||
(time.hour * 3600) +
|
|
||||||
(time.minute * 60) +
|
|
||||||
time.second
|
|
||||||
)
|
|
||||||
|
|
||||||
return timedelta(days=days, seconds=secs)
|
|
||||||
|
|
||||||
class ExtendedDateTimeEdit(AWidget):
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
super(ExtendedDateTimeEdit, self).__init__(
|
|
||||||
ui="extendedDateTimeEdit",
|
|
||||||
parent=parent
|
|
||||||
)
|
|
||||||
self.parent = parent
|
|
||||||
|
|
||||||
self.dateTimeEdit = self.find(QDateTimeEdit, "dateTimeEdit")
|
|
||||||
|
|
||||||
def set_time(self, time):
|
|
||||||
qdatetime = QDateTime.fromString(
|
|
||||||
time,
|
|
||||||
"yyyy-MM-dd hh:mm:ss"
|
|
||||||
)
|
|
||||||
self.dateTimeEdit.setDateTime(qdatetime)
|
|
||||||
|
|
||||||
def get_time(self):
|
|
||||||
time = self.dateTimeEdit.dateTime().toPyDateTime()
|
|
||||||
return time
|
|
||||||
|
|
||||||
class ExTimeDelegate(QItemDelegate):
|
|
||||||
def __init__(self, data=None, mode="time", parent=None):
|
|
||||||
super(ExTimeDelegate, self).__init__(parent)
|
|
||||||
|
|
||||||
self._data = data
|
|
||||||
self._mode = mode
|
|
||||||
|
|
||||||
def createEditor(self, parent, option, index):
|
|
||||||
if self._mode == "time":
|
|
||||||
self.editor = ExtendedTimeEdit(parent=parent)
|
|
||||||
else:
|
|
||||||
self.editor = ExtendedDateTimeEdit(parent=parent)
|
|
||||||
value = index.data(Qt.DisplayRole)
|
|
||||||
self.editor.set_time(value)
|
|
||||||
logger.debug(str(value))
|
|
||||||
return self.editor
|
|
||||||
|
|
||||||
def setModelData(self, editor, model, index):
|
|
||||||
time = editor.get_time()
|
|
||||||
if self._mode == "time":
|
|
||||||
model.setData(index, int(time.total_seconds()))
|
|
||||||
else:
|
|
||||||
logger.debug(str(time.timestamp()))
|
|
||||||
model.setData(index, int(time.timestamp()))
|
|
||||||
editor.close()
|
|
||||||
editor.deleteLater()
|
|
||||||
|
|
||||||
def updateEditorGeometry(self, editor, option, index):
|
|
||||||
r = QRect(option.rect)
|
|
||||||
if self.editor.windowFlags() & Qt.Popup and editor.parent() is not None:
|
|
||||||
r.setTopLeft(self.editor.parent().mapToGlobal(r.topLeft()))
|
|
||||||
editor.setGeometry(r)
|
|
||||||
|
|
||||||
@pyqtSlot()
|
|
||||||
def currentItemChanged(self):
|
|
||||||
self.commitData.emit(self.sender())
|
|
||||||
|
|
||||||
|
|
||||||
class TableModel(QAbstractTableModel):
|
|
||||||
def __init__(self, data=None, mode="time", undo=None):
|
|
||||||
super(QAbstractTableModel, self).__init__()
|
|
||||||
self._headers = data.header
|
|
||||||
self._data = data
|
|
||||||
self._mode = mode
|
|
||||||
self._undo = undo
|
|
||||||
|
|
||||||
def flags(self, index):
|
|
||||||
options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
|
||||||
options |= Qt.ItemIsEditable
|
|
||||||
|
|
||||||
return options
|
|
||||||
|
|
||||||
def rowCount(self, parent):
|
|
||||||
return len(self._data)
|
|
||||||
|
|
||||||
def columnCount(self, parent):
|
|
||||||
return len(self._headers)
|
|
||||||
|
|
||||||
|
class TableModel(PamhyrTableModel):
|
||||||
def data(self, index, role):
|
def data(self, index, role):
|
||||||
if role == Qt.TextAlignmentRole:
|
if role == Qt.TextAlignmentRole:
|
||||||
return Qt.AlignHCenter | Qt.AlignVCenter
|
return Qt.AlignHCenter | Qt.AlignVCenter
|
||||||
@@ -187,7 +71,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
if self._data.get_type_column(column) == float:
|
if self._data.get_type_column(column) == float:
|
||||||
value = f"{v:.4f}"
|
value = f"{v:.4f}"
|
||||||
elif self._data.header[column] == "time":
|
elif self._data.header[column] == "time":
|
||||||
if self._mode == "time":
|
if self._opt_data == "time":
|
||||||
t0 = datetime.fromtimestamp(0)
|
t0 = datetime.fromtimestamp(0)
|
||||||
t = datetime.fromtimestamp(v)
|
t = datetime.fromtimestamp(v)
|
||||||
value = str(t - t0)
|
value = str(t - t0)
|
||||||
@@ -198,12 +82,6 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def headerData(self, section, orientation, role):
|
|
||||||
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
|
|
||||||
return table_headers[self._headers[section]]
|
|
||||||
|
|
||||||
return QVariant()
|
|
||||||
|
|
||||||
def setData(self, index, value, role=Qt.EditRole):
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
if not index.isValid() or role != Qt.EditRole:
|
if not index.isValid() or role != Qt.EditRole:
|
||||||
return False
|
return False
|
||||||
@@ -313,12 +191,3 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self.layoutAboutToBeChanged.emit()
|
self.layoutAboutToBeChanged.emit()
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
|
||||||
def undo(self):
|
|
||||||
self._undo.undo()
|
|
||||||
self.layoutChanged.emit()
|
|
||||||
|
|
||||||
def redo(self):
|
|
||||||
self._undo.redo()
|
|
||||||
self.layoutChanged.emit()
|
|
||||||
@@ -20,6 +20,7 @@ from tools import timer, trace
|
|||||||
|
|
||||||
from View.ASubWindow import ASubMainWindow
|
from View.ASubWindow import ASubMainWindow
|
||||||
from View.ListedSubWindow import ListedSubWindow
|
from View.ListedSubWindow import ListedSubWindow
|
||||||
|
from View.Tools.PamhyrDelegate import PamhyrExTimeDelegate
|
||||||
|
|
||||||
from PyQt5.QtGui import (
|
from PyQt5.QtGui import (
|
||||||
QKeySequence,
|
QKeySequence,
|
||||||
@@ -37,10 +38,11 @@ from PyQt5.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from View.Plot.MplCanvas import MplCanvas
|
from View.Plot.MplCanvas import MplCanvas
|
||||||
from View.Plot.navigation_toolbar_2qt import PamHyrNavigationToolbar2QT
|
from View.Plot.PamhyrToolbar import PamhyrPlotToolbar
|
||||||
|
|
||||||
from View.LateralContribution.translate import long_types
|
from View.LateralContribution.translate import long_types
|
||||||
from View.LateralContribution.Edit.Table import TableModel, ExTimeDelegate
|
from View.LateralContribution.Edit.translate import table_headers, retranslate
|
||||||
|
from View.LateralContribution.Edit.Table import TableModel
|
||||||
from View.LateralContribution.Edit.Plot import Plot
|
from View.LateralContribution.Edit.Plot import Plot
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
@@ -85,23 +87,29 @@ class EditLateralContributionWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
table = self.find(QTableView, "tableView")
|
retranslate()
|
||||||
self._table = TableModel(
|
headers = {}
|
||||||
|
for h in self._data.header:
|
||||||
|
headers[h] = table_headers[h]
|
||||||
|
|
||||||
|
self._delegate_time = PamhyrExTimeDelegate(
|
||||||
data = self._data,
|
data = self._data,
|
||||||
undo = self._undo_stack,
|
mode = self._study.time_system,
|
||||||
mode = self._study.time_system
|
parent = self
|
||||||
)
|
)
|
||||||
|
|
||||||
if self._data.header[0] == "time":
|
table = self.find(QTableView, "tableView")
|
||||||
self._delegate_time = ExTimeDelegate(
|
self._table = TableModel(
|
||||||
data = self._data,
|
table_view = table,
|
||||||
mode = self._study.time_system,
|
table_headers = headers,
|
||||||
parent = self
|
editable_headers = self._data.header,
|
||||||
)
|
delegates = {
|
||||||
|
"time": self._delegate_time,
|
||||||
table.setItemDelegateForColumn(
|
},
|
||||||
0, self._delegate_time
|
data = self._data,
|
||||||
)
|
undo = self._undo_stack,
|
||||||
|
opt_data = self._study.time_system
|
||||||
|
)
|
||||||
|
|
||||||
table.setModel(self._table)
|
table.setModel(self._table)
|
||||||
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
@@ -111,7 +119,7 @@ class EditLateralContributionWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
def setup_plot(self):
|
def setup_plot(self):
|
||||||
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas.setObjectName("canvas")
|
self.canvas.setObjectName("canvas")
|
||||||
self.toolbar = PamHyrNavigationToolbar2QT(
|
self.toolbar = PamhyrPlotToolbar(
|
||||||
self.canvas, self
|
self.canvas, self
|
||||||
)
|
)
|
||||||
self.verticalLayout.addWidget(self.toolbar)
|
self.verticalLayout.addWidget(self.toolbar)
|
||||||
|
|||||||
@@ -28,3 +28,11 @@ table_headers = {
|
|||||||
"discharge": _translate("LateralContribution", "Discharge (m³/s)"),
|
"discharge": _translate("LateralContribution", "Discharge (m³/s)"),
|
||||||
"z": _translate("LateralContribution", "Z (m)")
|
"z": _translate("LateralContribution", "Z (m)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def retranslate():
|
||||||
|
table_headers["x"] = _translate("LateralContribution", "X")
|
||||||
|
table_headers["y"] = _translate("LateralContribution", "Y")
|
||||||
|
table_headers["time"] = _translate("LateralContribution", "Time")
|
||||||
|
table_headers["date"] = _translate("LateralContribution", "Date")
|
||||||
|
table_headers["discharge"] = _translate("LateralContribution", "Discharge (m³/s)")
|
||||||
|
table_headers["z"] = _translate("LateralContribution", "Z (m)")
|
||||||
@@ -44,6 +44,8 @@ from View.LateralContribution.UndoCommand import (
|
|||||||
from Model.LateralContribution.LateralContributionTypes import (
|
from Model.LateralContribution.LateralContributionTypes import (
|
||||||
NotDefined, LateralContrib, Rain, Evaporation,
|
NotDefined, LateralContrib, Rain, Evaporation,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from View.Tools.PamhyrTable import PamhyrTableModel
|
||||||
from View.LateralContribution.translate import *
|
from View.LateralContribution.translate import *
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
@@ -102,26 +104,13 @@ class ComboBoxDelegate(QItemDelegate):
|
|||||||
self.commitData.emit(self.sender())
|
self.commitData.emit(self.sender())
|
||||||
|
|
||||||
|
|
||||||
class TableModel(QAbstractTableModel):
|
class TableModel(PamhyrTableModel):
|
||||||
def __init__(self, data=None, undo=None, tab=""):
|
def _setup_lst(self):
|
||||||
super(QAbstractTableModel, self).__init__()
|
self._lst = self._data.lateral_contribution
|
||||||
self._headers = list(table_headers.keys())
|
self._tab = self._opt_data
|
||||||
self._data = data
|
|
||||||
self._undo = undo
|
|
||||||
self._tab = tab
|
|
||||||
self._lcs = self._data.lateral_contribution
|
|
||||||
|
|
||||||
def flags(self, index):
|
|
||||||
options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
|
||||||
options |= Qt.ItemIsEditable
|
|
||||||
|
|
||||||
return options
|
|
||||||
|
|
||||||
def rowCount(self, parent):
|
def rowCount(self, parent):
|
||||||
return self._lcs.len(self._tab)
|
return self._lst.len(self._tab)
|
||||||
|
|
||||||
def columnCount(self, parent):
|
|
||||||
return len(self._headers)
|
|
||||||
|
|
||||||
def data(self, index, role):
|
def data(self, index, role):
|
||||||
if role != Qt.ItemDataRole.DisplayRole:
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
@@ -131,26 +120,19 @@ class TableModel(QAbstractTableModel):
|
|||||||
column = index.column()
|
column = index.column()
|
||||||
|
|
||||||
if self._headers[column] == "name":
|
if self._headers[column] == "name":
|
||||||
return self._lcs.get(self._tab, row).name
|
return self._lst.get(self._tab, row).name
|
||||||
elif self._headers[column] == "type":
|
elif self._headers[column] == "type":
|
||||||
t = self._lcs.get(self._tab, row).lctype
|
t = self._lst.get(self._tab, row).lctype
|
||||||
return long_types[t]
|
return long_types[t]
|
||||||
elif self._headers[column] == "edge":
|
elif self._headers[column] == "edge":
|
||||||
n = self._lcs.get(self._tab, row).edge
|
n = self._lst.get(self._tab, row).edge
|
||||||
if n is None:
|
if n is None:
|
||||||
return _translate("LateralContribution", "Not associate")
|
return _translate("LateralContribution", "Not associate")
|
||||||
return n.name
|
return n.name
|
||||||
elif self._headers[column] == "begin_kp":
|
elif self._headers[column] == "begin_kp":
|
||||||
return self._lcs.get(self._tab, row).begin_kp
|
return self._lst.get(self._tab, row).begin_kp
|
||||||
elif self._headers[column] == "end_kp":
|
elif self._headers[column] == "end_kp":
|
||||||
return self._lcs.get(self._tab, row).end_kp
|
return self._lst.get(self._tab, row).end_kp
|
||||||
|
|
||||||
|
|
||||||
return QVariant()
|
|
||||||
|
|
||||||
def headerData(self, section, orientation, role):
|
|
||||||
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
|
|
||||||
return table_headers[self._headers[section]]
|
|
||||||
|
|
||||||
return QVariant()
|
return QVariant()
|
||||||
|
|
||||||
@@ -165,32 +147,32 @@ class TableModel(QAbstractTableModel):
|
|||||||
if self._headers[column] == "name":
|
if self._headers[column] == "name":
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
SetNameCommand(
|
SetNameCommand(
|
||||||
self._lcs, self._tab, row, value
|
self._lst, self._tab, row, value
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif self._headers[column] == "type":
|
elif self._headers[column] == "type":
|
||||||
key = next(k for k, v in long_types.items() if v == value)
|
key = next(k for k, v in long_types.items() if v == value)
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
SetTypeCommand(
|
SetTypeCommand(
|
||||||
self._lcs, self._tab, row, LC_types[key]
|
self._lst, self._tab, row, LC_types[key]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif self._headers[column] == "edge":
|
elif self._headers[column] == "edge":
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
SetEdgeCommand(
|
SetEdgeCommand(
|
||||||
self._lcs, self._tab, row, self._data.edge(value)
|
self._lst, self._tab, row, self._data.edge(value)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif self._headers[column] == "begin_kp":
|
elif self._headers[column] == "begin_kp":
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
SetBeginCommand(
|
SetBeginCommand(
|
||||||
self._lcs, self._tab, row, value
|
self._lst, self._tab, row, value
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif self._headers[column] == "end_kp":
|
elif self._headers[column] == "end_kp":
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
SetEndCommand(
|
SetEndCommand(
|
||||||
self._lcs, self._tab, row, value
|
self._lst, self._tab, row, value
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -205,7 +187,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
AddCommand(
|
AddCommand(
|
||||||
self._lcs, self._tab, row
|
self._lst, self._tab, row
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -217,7 +199,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
DelCommand(
|
DelCommand(
|
||||||
self._lcs, self._tab, rows
|
self._lst, self._tab, rows
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -229,7 +211,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
SortCommand(
|
SortCommand(
|
||||||
self._lcs, self._tab, False
|
self._lst, self._tab, False
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -246,7 +228,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self._undo_stack.push(
|
self._undo_stack.push(
|
||||||
MoveCommand(
|
MoveCommand(
|
||||||
self._lcs, self._tab,"up", row
|
self._lst, self._tab, "up", row
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -254,7 +236,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def move_down(self, index, parent=QModelIndex()):
|
def move_down(self, index, parent=QModelIndex()):
|
||||||
if row > len(self._lcs):
|
if row > len(self._lst):
|
||||||
return
|
return
|
||||||
|
|
||||||
target = row
|
target = row
|
||||||
@@ -263,17 +245,9 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self._undo_stack.push(
|
self._undo_stack.push(
|
||||||
MoveCommand(
|
MoveCommand(
|
||||||
self._lcs, self._tab,"down", row
|
self._lst, self._tab, "down", row
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.endMoveRows()
|
self.endMoveRows()
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def undo(self):
|
|
||||||
self._undo.undo()
|
|
||||||
self.layoutChanged.emit()
|
|
||||||
|
|
||||||
def redo(self):
|
|
||||||
self._undo.redo()
|
|
||||||
self.layoutChanged.emit()
|
|
||||||
@@ -56,7 +56,10 @@ from View.LateralContribution.Table import (
|
|||||||
|
|
||||||
from View.Plot.MplCanvas import MplCanvas
|
from View.Plot.MplCanvas import MplCanvas
|
||||||
from View.Geometry.PlotXY import PlotXY
|
from View.Geometry.PlotXY import PlotXY
|
||||||
from View.LateralContribution.translate import *
|
from View.LateralContribution.translate import (
|
||||||
|
long_types, table_headers, LC_types,
|
||||||
|
retranslate,
|
||||||
|
)
|
||||||
from View.LateralContribution.Edit.Window import EditLateralContributionWindow
|
from View.LateralContribution.Edit.Window import EditLateralContributionWindow
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
@@ -90,17 +93,10 @@ class LateralContributionWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
|
retranslate()
|
||||||
self._table = {}
|
self._table = {}
|
||||||
|
|
||||||
for t in ["liquid", "solid", "suspenssion"]:
|
for t in ["liquid", "solid", "suspenssion"]:
|
||||||
table = self.find(QTableView, f"tableView_{t}")
|
|
||||||
self._table[t] = TableModel(
|
|
||||||
data = self._study.river,
|
|
||||||
undo = self._undo_stack,
|
|
||||||
tab = t,
|
|
||||||
)
|
|
||||||
table.setModel(self._table[t])
|
|
||||||
|
|
||||||
self._delegate_type = ComboBoxDelegate(
|
self._delegate_type = ComboBoxDelegate(
|
||||||
data = self._study.river,
|
data = self._study.river,
|
||||||
mode = "type",
|
mode = "type",
|
||||||
@@ -114,13 +110,20 @@ class LateralContributionWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
parent=self
|
parent=self
|
||||||
)
|
)
|
||||||
|
|
||||||
table.setItemDelegateForColumn(
|
table = self.find(QTableView, f"tableView_{t}")
|
||||||
1, self._delegate_type
|
self._table[t] = TableModel(
|
||||||
|
table_view = table,
|
||||||
|
table_headers = table_headers,
|
||||||
|
editable_headers = True,
|
||||||
|
delegates = {
|
||||||
|
"type": self._delegate_type,
|
||||||
|
"edge": self._delegate_edge,
|
||||||
|
},
|
||||||
|
data = self._study.river,
|
||||||
|
undo = self._undo_stack,
|
||||||
|
opt_data = t,
|
||||||
)
|
)
|
||||||
table.setItemDelegateForColumn(
|
table.setModel(self._table[t])
|
||||||
2, self._delegate_edge
|
|
||||||
)
|
|
||||||
|
|
||||||
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
table.setAlternatingRowColors(True)
|
table.setAlternatingRowColors(True)
|
||||||
|
|||||||
@@ -45,3 +45,15 @@ LC_types = {
|
|||||||
"RA": Rain,
|
"RA": Rain,
|
||||||
"EV": Evaporation,
|
"EV": Evaporation,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def retranslate():
|
||||||
|
table_headers["name"] = _translate("LateralContribution", "Name")
|
||||||
|
table_headers["type"] = _translate("LateralContribution", "Type")
|
||||||
|
table_headers["edge"] = _translate("LateralContribution", "Reach")
|
||||||
|
table_headers["begin_kp"] = _translate("LateralContribution", "Begin kp (m)")
|
||||||
|
table_headers["end_kp"] = _translate("LateralContribution", "End kp (m)")
|
||||||
|
|
||||||
|
long_types["ND"] = _translate("LateralContribution", "Not defined")
|
||||||
|
long_types["LC"] = _translate("LateralContribution", "Lateral contribution")
|
||||||
|
long_types["RA"] = _translate("LateralContribution", "Rain")
|
||||||
|
long_types["EV"] = _translate("LateralContribution", "Evaporation")
|
||||||
@@ -131,10 +131,14 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
self.dialog_reopen_study()
|
self.dialog_reopen_study()
|
||||||
|
|
||||||
def set_title(self):
|
def set_title(self):
|
||||||
|
title = "(dbg) " if self.conf.debug else ""
|
||||||
|
|
||||||
if self.model is not None:
|
if self.model is not None:
|
||||||
self.setWindowTitle(f"PAMHYR - {self.model.name}")
|
title += f"Pamhyr2 - {self.model.name}"
|
||||||
|
self.setWindowTitle(title)
|
||||||
else:
|
else:
|
||||||
self.setWindowTitle("PAMHYR")
|
title += "Pamhyr2"
|
||||||
|
self.setWindowTitle(title)
|
||||||
|
|
||||||
def enable_actions(self, action:str, enable:bool):
|
def enable_actions(self, action:str, enable:bool):
|
||||||
"""Enable of disable an action componant
|
"""Enable of disable an action componant
|
||||||
@@ -255,9 +259,9 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
logger.setLevel(logging.INFO)
|
logger.setLevel(logging.INFO)
|
||||||
logger.info("Set logging level to INFO")
|
logger.info("Set logging level to INFO")
|
||||||
|
|
||||||
|
|
||||||
def setup_debug_mode(self, init = False):
|
def setup_debug_mode(self, init = False):
|
||||||
menu = self.findChild(QMenu, "menu_help")
|
menu = self.findChild(QMenu, "menu_help")
|
||||||
|
self.set_title()
|
||||||
|
|
||||||
if init:
|
if init:
|
||||||
self.debug_action = QAction("Debug", self)
|
self.debug_action = QAction("Debug", self)
|
||||||
|
|||||||
@@ -584,7 +584,7 @@ class GraphWidget(QGraphicsView):
|
|||||||
if item:
|
if item:
|
||||||
item.update()
|
item.update()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.debug(str(e))
|
logger.warning(str(e))
|
||||||
|
|
||||||
def selected_new_edge_src_node(self):
|
def selected_new_edge_src_node(self):
|
||||||
"""The current node item selected to add new edge
|
"""The current node item selected to add new edge
|
||||||
@@ -626,12 +626,15 @@ class GraphWidget(QGraphicsView):
|
|||||||
Returns:
|
Returns:
|
||||||
Nothing
|
Nothing
|
||||||
"""
|
"""
|
||||||
previous_edge = self._current_edge
|
try:
|
||||||
self._current_edge = edge
|
previous_edge = self._current_edge
|
||||||
self.graph.set_current_reach(edge.edge)
|
self._current_edge = edge
|
||||||
|
self.graph.set_current_reach(edge.edge)
|
||||||
|
|
||||||
if previous_edge:
|
if previous_edge:
|
||||||
previous_edge.update()
|
previous_edge.update()
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(str(e))
|
||||||
|
|
||||||
def reset_selection(self):
|
def reset_selection(self):
|
||||||
"""Reset all the selected items
|
"""Reset all the selected items
|
||||||
|
|||||||
+72
-117
@@ -25,6 +25,7 @@ from Model.Network.Graph import Graph
|
|||||||
from View.ASubWindow import ASubWindow
|
from View.ASubWindow import ASubWindow
|
||||||
from View.Network.GraphWidget import GraphWidget
|
from View.Network.GraphWidget import GraphWidget
|
||||||
from View.Network.UndoCommand import *
|
from View.Network.UndoCommand import *
|
||||||
|
from View.Tools.PamhyrTable import PamhyrTableModel
|
||||||
|
|
||||||
from PyQt5.QtCore import (
|
from PyQt5.QtCore import (
|
||||||
Qt, QRect, QVariant, QAbstractTableModel, pyqtSlot, pyqtSignal,
|
Qt, QRect, QVariant, QAbstractTableModel, pyqtSlot, pyqtSignal,
|
||||||
@@ -69,151 +70,105 @@ class ComboBoxDelegate(QItemDelegate):
|
|||||||
def currentItemChanged(self):
|
def currentItemChanged(self):
|
||||||
self.commitData.emit(self.sender())
|
self.commitData.emit(self.sender())
|
||||||
|
|
||||||
class TrueFalseComboBoxDelegate(QItemDelegate):
|
class NodeTableModel(PamhyrTableModel):
|
||||||
def __init__(self, parent=None):
|
def _setup_lst(self):
|
||||||
super(TrueFalseComboBoxDelegate, self).__init__(parent)
|
self._lst = self._data.nodes()
|
||||||
|
|
||||||
def createEditor(self, parent, option, index):
|
|
||||||
self.editor = QComboBox(parent)
|
|
||||||
self.editor.addItems(["true", "false"])
|
|
||||||
self.editor.setCurrentText("true" if index.data(Qt.DisplayRole) else "false")
|
|
||||||
return self.editor
|
|
||||||
|
|
||||||
def setEditorData(self, editor, index):
|
|
||||||
value = str(index.data(Qt.DisplayRole))
|
|
||||||
self.editor.currentTextChanged.connect(self.currentItemChanged)
|
|
||||||
|
|
||||||
def setModelData(self, editor, model, index):
|
|
||||||
value = str(editor.currentText()) == "true"
|
|
||||||
model.setData(index, value)
|
|
||||||
editor.close()
|
|
||||||
editor.deleteLater()
|
|
||||||
|
|
||||||
def updateEditorGeometry(self, editor, option, index):
|
|
||||||
r = QRect(option.rect)
|
|
||||||
if self.editor.windowFlags() & Qt.Popup and editor.parent() is not None:
|
|
||||||
r.setTopLeft(self.editor.parent().mapToGlobal(r.topLeft()))
|
|
||||||
editor.setGeometry(r)
|
|
||||||
|
|
||||||
@pyqtSlot()
|
|
||||||
def currentItemChanged(self):
|
|
||||||
self.commitData.emit(self.sender())
|
|
||||||
|
|
||||||
class GraphTableModel(QAbstractTableModel):
|
|
||||||
def __init__(self, headers=[], graph=None, undo = None, rows_type="nodes"):
|
|
||||||
super(QAbstractTableModel, self).__init__()
|
|
||||||
self.headers = headers
|
|
||||||
self.graph = graph
|
|
||||||
self._type = rows_type
|
|
||||||
self._undo = undo
|
|
||||||
|
|
||||||
if self._type == "nodes":
|
|
||||||
self.rows = graph.nodes()
|
|
||||||
elif self._type == "edges":
|
|
||||||
self.rows = graph.edges()
|
|
||||||
|
|
||||||
def flags(self, index):
|
|
||||||
options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
|
||||||
|
|
||||||
if self.headers[index.column()] != "type":
|
|
||||||
options |= Qt.ItemIsEditable
|
|
||||||
|
|
||||||
return options
|
|
||||||
|
|
||||||
def rowCount(self, parent):
|
|
||||||
return len(self.rows)
|
|
||||||
|
|
||||||
def columnCount(self, parent):
|
|
||||||
return len(self.headers)
|
|
||||||
|
|
||||||
def data(self, index, role):
|
def data(self, index, role):
|
||||||
if role != Qt.ItemDataRole.DisplayRole:
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
return QVariant()
|
return QVariant()
|
||||||
|
|
||||||
if self.headers[index.column()] == "type":
|
if self._headers[index.column()] == "type":
|
||||||
node = self.rows[index.row()]
|
node = self._lst[index.row()]
|
||||||
ret = "internal"
|
ret = "internal"
|
||||||
|
|
||||||
if not self.graph.is_enable_node(node):
|
if not self._data.is_enable_node(node):
|
||||||
ret = "disable"
|
ret = "disable"
|
||||||
elif self.graph.is_upstream_node(node):
|
elif self._data.is_upstream_node(node):
|
||||||
ret = "upstream"
|
ret = "upstream"
|
||||||
elif self.graph.is_downstream_node(node):
|
elif self._data.is_downstream_node(node):
|
||||||
ret = "downstream"
|
ret = "downstream"
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
return self.rows[index.row()][self.headers[index.column()]]
|
return self._lst[index.row()][self._headers[index.column()]]
|
||||||
|
|
||||||
def headerData(self, section, orientation, role):
|
|
||||||
if (role == Qt.ItemDataRole.DisplayRole and
|
|
||||||
orientation == Qt.Orientation.Horizontal):
|
|
||||||
return self.headers[section].capitalize()
|
|
||||||
|
|
||||||
return QVariant()
|
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def setData(self, index, value, role=Qt.EditRole):
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
if index.isValid():
|
if not index.isValid():
|
||||||
if role == Qt.EditRole:
|
return False
|
||||||
try:
|
|
||||||
if (self.headers[index.column()] == "node1" or
|
if role == Qt.EditRole:
|
||||||
self.headers[index.column()] == "node2"):
|
try:
|
||||||
node = self.graph.node(value)
|
self._undo.push(
|
||||||
self._undo.push(
|
SetCommand(
|
||||||
SetNodeCommand(
|
self._lst[index.row()],
|
||||||
self.graph,
|
self._headers[index.column()],
|
||||||
self.rows[index.row()],
|
value
|
||||||
self.headers[index.column()],
|
)
|
||||||
node
|
)
|
||||||
)
|
except Exception as e:
|
||||||
)
|
logger.info(e)
|
||||||
# elif self.headers[index.column()] == "enable":
|
logger.debug(traceback.format_exc())
|
||||||
# self._undo.push(
|
|
||||||
# EnableEdgeCommand(
|
|
||||||
# self.rows[index.row()], value
|
|
||||||
# )
|
|
||||||
# )
|
|
||||||
else:
|
|
||||||
self._undo.push(
|
|
||||||
SetCommand(
|
|
||||||
self.rows[index.row()],
|
|
||||||
self.headers[index.column()],
|
|
||||||
value
|
|
||||||
)
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
logger.info(e)
|
|
||||||
logger.debug(traceback.format_exc())
|
|
||||||
|
|
||||||
self.dataChanged.emit(index, index, [Qt.DisplayRole])
|
self.dataChanged.emit(index, index, [Qt.DisplayRole])
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
self.dataChanged.emit(index, index)
|
self.dataChanged.emit(index, index)
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
if self._type == "nodes":
|
self._lst = self._data.nodes()
|
||||||
self.rows = self.graph.nodes()
|
|
||||||
elif self._type == "edges":
|
|
||||||
self.rows = self.graph.edges()
|
|
||||||
|
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def reverse_edge(self, index):
|
class EdgeTableModel(PamhyrTableModel):
|
||||||
if self._type == "edges":
|
def _setup_lst(self):
|
||||||
tmp = self.rows[index.row()].node1
|
self._lst = self._data.edges()
|
||||||
self.rows[index.row()].node1 = self.rows[index.row()].node2
|
|
||||||
self.rows[index.row()].node2 = tmp
|
def data(self, index, role):
|
||||||
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
return self._lst[index.row()][self._headers[index.column()]]
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
|
if not index.isValid():
|
||||||
|
return False
|
||||||
|
|
||||||
|
if role != Qt.EditRole:
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if (self._headers[index.column()] == "node1" or
|
||||||
|
self._headers[index.column()] == "node2"):
|
||||||
|
node = self.graph.node(value)
|
||||||
|
self._undo.push(
|
||||||
|
SetNodeCommand(
|
||||||
|
self._data,
|
||||||
|
self._lst[index.row()],
|
||||||
|
self._headers[index.column()],
|
||||||
|
node
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self._undo.push(
|
||||||
|
SetCommand(
|
||||||
|
self._lst[index.row()],
|
||||||
|
self._headers[index.column()],
|
||||||
|
value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.info(e)
|
||||||
|
logger.debug(traceback.format_exc())
|
||||||
|
|
||||||
self.dataChanged.emit(index, index, [Qt.DisplayRole])
|
self.dataChanged.emit(index, index, [Qt.DisplayRole])
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
return True
|
||||||
|
|
||||||
def undo(self):
|
self.dataChanged.emit(index, index)
|
||||||
self._undo.undo()
|
|
||||||
self.layoutChanged.emit()
|
|
||||||
|
|
||||||
def redo(self):
|
def update(self):
|
||||||
self._undo.redo()
|
self._lst = self._data.edges()
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
+31
-24
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QCoreApplication
|
||||||
|
|
||||||
from PyQt5.QtGui import (
|
from PyQt5.QtGui import (
|
||||||
QKeySequence,
|
QKeySequence,
|
||||||
)
|
)
|
||||||
@@ -37,9 +39,16 @@ from Model.River import RiverNode, RiverReach, River
|
|||||||
from View.ASubWindow import ASubMainWindow
|
from View.ASubWindow import ASubMainWindow
|
||||||
from View.Network.GraphWidget import GraphWidget
|
from View.Network.GraphWidget import GraphWidget
|
||||||
from View.Network.UndoCommand import *
|
from View.Network.UndoCommand import *
|
||||||
from View.Network.Table import (
|
from View.Network.translate import (
|
||||||
GraphTableModel, ComboBoxDelegate, TrueFalseComboBoxDelegate,
|
table_headers_node, table_headers_edge,
|
||||||
|
retranslate,
|
||||||
)
|
)
|
||||||
|
from View.Network.Table import (
|
||||||
|
ComboBoxDelegate, NodeTableModel, EdgeTableModel,
|
||||||
|
)
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
class NetworkWindow(ASubMainWindow):
|
class NetworkWindow(ASubMainWindow):
|
||||||
def __init__(self, model=None, title="River network", parent=None):
|
def __init__(self, model=None, title="River network", parent=None):
|
||||||
@@ -69,43 +78,41 @@ class NetworkWindow(ASubMainWindow):
|
|||||||
self.redo_sc = QShortcut(QKeySequence.Redo, self)
|
self.redo_sc = QShortcut(QKeySequence.Redo, self)
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
# Nodes table
|
retranslate()
|
||||||
|
|
||||||
self._nodes_model = GraphTableModel(
|
# Nodes table
|
||||||
headers = ["name", "type"],
|
table = self.find(QTableView, "tableView_nodes")
|
||||||
graph = self._graph,
|
self._nodes_model = NodeTableModel(
|
||||||
rows_type = "nodes",
|
table_view = table,
|
||||||
|
table_headers = table_headers_node,
|
||||||
|
editable_headers = ["name"],
|
||||||
|
data = self._graph,
|
||||||
undo = self._undo_stack,
|
undo = self._undo_stack,
|
||||||
)
|
)
|
||||||
table = self.find(QTableView, "tableView_nodes")
|
|
||||||
table.setModel(self._nodes_model)
|
table.setModel(self._nodes_model)
|
||||||
#table.resizeColumnsToContents()
|
|
||||||
|
|
||||||
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
|
|
||||||
# Edges table
|
# Edges table
|
||||||
|
table = self.find(QTableView, "tableView_reachs")
|
||||||
self._reachs_model = GraphTableModel(
|
|
||||||
headers = ["name", # "enable",
|
|
||||||
"node1", "node2"],
|
|
||||||
graph = self._graph,
|
|
||||||
rows_type = "edges",
|
|
||||||
undo = self._undo_stack,
|
|
||||||
)
|
|
||||||
self.delegate_combobox = ComboBoxDelegate(
|
self.delegate_combobox = ComboBoxDelegate(
|
||||||
graph = self._graph,
|
graph = self._graph,
|
||||||
parent = self,
|
parent = self,
|
||||||
)
|
)
|
||||||
self.delegate_true_false_combobox = TrueFalseComboBoxDelegate(
|
|
||||||
parent = self,
|
|
||||||
)
|
|
||||||
|
|
||||||
table = self.find(QTableView, "tableView_reachs")
|
self._reachs_model = EdgeTableModel(
|
||||||
|
table_view = table,
|
||||||
|
table_headers = table_headers_edge,
|
||||||
|
editable_headers = ["name", "node1", "node2"],
|
||||||
|
delegates = {
|
||||||
|
"node1": self.delegate_combobox,
|
||||||
|
"node2": self.delegate_combobox,
|
||||||
|
},
|
||||||
|
data = self._graph,
|
||||||
|
undo = self._undo_stack,
|
||||||
|
)
|
||||||
table.setModel(self._reachs_model)
|
table.setModel(self._reachs_model)
|
||||||
# table.setItemDelegateForColumn(1, self.delegate_true_false_combobox)
|
|
||||||
table.setItemDelegateForColumn(1, self.delegate_combobox)
|
|
||||||
table.setItemDelegateForColumn(2, self.delegate_combobox)
|
|
||||||
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
#table.resizeColumnsToContents()
|
#table.resizeColumnsToContents()
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# translate.py -- Pamhyr
|
||||||
|
# Copyright (C) 2023 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QCoreApplication
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
table_headers_node = {
|
||||||
|
"name": _translate("Network", "Name"),
|
||||||
|
"type": _translate("Network", "Type"),
|
||||||
|
}
|
||||||
|
|
||||||
|
table_headers_edge = {
|
||||||
|
"name": _translate("Network", "Name"),
|
||||||
|
"node1": _translate("Network", "Source node"),
|
||||||
|
"node2": _translate("Network", "Destination node"),
|
||||||
|
}
|
||||||
|
|
||||||
|
def retranslate():
|
||||||
|
table_headers_node["name"] = _translate("Network", "Name")
|
||||||
|
table_headers_node["type"] = _translate("Network", "Type")
|
||||||
|
|
||||||
|
table_headers_edge["name"] = _translate("Network", "Name")
|
||||||
|
table_headers_edge["node1"] = _translate("Network", "Source node")
|
||||||
|
table_headers_edge["node2"] = _translate("Network", "Destination node")
|
||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
class APlot(object):
|
class APlot(object):
|
||||||
def __init__(self, canvas=None, data=None, toolbar=None):
|
def __init__(self, canvas=None, data=None, toolbar=None):
|
||||||
super(APlot, self).__init__()
|
super(APlot, self).__init__()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# navigation_toolbar_2qt.py -- Pamhyr
|
# PamhyrToolbar.py -- Pamhyr
|
||||||
# Copyright (C) 2023 INRAE
|
# Copyright (C) 2023 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
@@ -19,10 +19,12 @@
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
import matplotlib as mpl
|
import matplotlib as mpl
|
||||||
|
|
||||||
from matplotlib.backends import qt_compat
|
from matplotlib.backends import qt_compat
|
||||||
|
from matplotlib.backends.backend_qt5 import NavigationToolbar2QT
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
from PyQt5.QtWidgets import QAction
|
from PyQt5.QtWidgets import QAction
|
||||||
from matplotlib.backends.backend_qt5 import NavigationToolbar2QT
|
|
||||||
from PyQt5.QtCore import pyqtSignal, QSize
|
from PyQt5.QtCore import pyqtSignal, QSize
|
||||||
|
|
||||||
_translate = QtCore.QCoreApplication.translate
|
_translate = QtCore.QCoreApplication.translate
|
||||||
@@ -31,21 +33,21 @@ logger = logging.getLogger()
|
|||||||
file_path = os.path.abspath(os.path.dirname(__file__))
|
file_path = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|
||||||
class PamHyrNavigationToolbar2QT(NavigationToolbar2QT):
|
class PamhyrPlotToolbar(NavigationToolbar2QT):
|
||||||
"""
|
"""
|
||||||
Cette classe est une personnalisation de la toolbar (NavigationToolbar2QT). Elle permet l'internationnalisation et
|
MatPlotLib plot toolbar for Pamhyr
|
||||||
l'ajout d'autres boutons à la toolbar initiale
|
|
||||||
"""
|
"""
|
||||||
isometric_signal = pyqtSignal(str)
|
isometric_signal = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, canvas, parent, items = ["home", "move", "zoom", "save"]):
|
def __init__(self, canvas, parent, items = ["home", "move", "zoom", "save"]):
|
||||||
"""
|
"""PamhyrPlotToolbar
|
||||||
Args:
|
|
||||||
canvas: canvas de matplotlib
|
|
||||||
parent: parent du canvas
|
|
||||||
"""
|
|
||||||
self.my_canvas = canvas
|
|
||||||
|
|
||||||
|
Args:
|
||||||
|
canvas: MatPlotLib canvas
|
||||||
|
parent: parent Qt object
|
||||||
|
items: Enables items (default: "home", "move", "zoom", "save")
|
||||||
|
"""
|
||||||
|
self._canvas = canvas
|
||||||
self._items = items
|
self._items = items
|
||||||
self.toolitems = [
|
self.toolitems = [
|
||||||
(None, None, None, None),
|
(None, None, None, None),
|
||||||
@@ -118,7 +120,7 @@ class PamHyrNavigationToolbar2QT(NavigationToolbar2QT):
|
|||||||
self.toolitems.append((None, None, None, None))
|
self.toolitems.append((None, None, None, None))
|
||||||
|
|
||||||
NavigationToolbar2QT.__init__(self, canvas, parent)
|
NavigationToolbar2QT.__init__(self, canvas, parent)
|
||||||
btn_size = QSize(30, 30)
|
btn_size = QSize(40, 28)
|
||||||
actions = self.findChildren(QAction)
|
actions = self.findChildren(QAction)
|
||||||
|
|
||||||
for a, i in icons:
|
for a, i in icons:
|
||||||
@@ -161,18 +163,15 @@ class PamHyrNavigationToolbar2QT(NavigationToolbar2QT):
|
|||||||
QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.NoButton
|
QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.NoButton
|
||||||
)
|
)
|
||||||
|
|
||||||
def cursor1(self):
|
|
||||||
logger.info("TODO: cursor1")
|
|
||||||
|
|
||||||
def isometric_view(self):
|
def isometric_view(self):
|
||||||
self.my_canvas.axes.axis("equal")
|
self._canvas.axes.axis("equal")
|
||||||
self.my_canvas.figure.canvas.draw_idle()
|
self._canvas.figure.canvas.draw_idle()
|
||||||
self.isometric_signal[str].emit("vue iso")
|
self.isometric_signal[str].emit("vue iso")
|
||||||
|
|
||||||
def non_isometric_view(self):
|
def non_isometric_view(self):
|
||||||
self.my_canvas.axes.axis("tight")
|
self._canvas.axes.axis("tight")
|
||||||
self.my_canvas.toolbar.update()
|
self._canvas.toolbar.update()
|
||||||
self.my_canvas.figure.canvas.draw_idle()
|
self._canvas.figure.canvas.draw_idle()
|
||||||
|
|
||||||
def toolitems_translation(self):
|
def toolitems_translation(self):
|
||||||
self._actions['home'].setToolTip(_translate("Toolbar", "Default view"))
|
self._actions['home'].setToolTip(_translate("Toolbar", "Default view"))
|
||||||
@@ -43,7 +43,7 @@ from PyQt5.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from View.Plot.MplCanvas import MplCanvas
|
from View.Plot.MplCanvas import MplCanvas
|
||||||
from View.Plot.navigation_toolbar_2qt import PamHyrNavigationToolbar2QT
|
from View.Plot.PamhyrToolbar import PamhyrPlotToolbar
|
||||||
|
|
||||||
from View.Results.PlotXY import PlotXY
|
from View.Results.PlotXY import PlotXY
|
||||||
from View.Results.PlotAC import PlotAC
|
from View.Results.PlotAC import PlotAC
|
||||||
@@ -53,7 +53,10 @@ from View.Results.PlotSedReach import PlotSedReach
|
|||||||
from View.Results.PlotSedProfile import PlotSedProfile
|
from View.Results.PlotSedProfile import PlotSedProfile
|
||||||
|
|
||||||
from View.Results.Table import TableModel
|
from View.Results.Table import TableModel
|
||||||
from View.Results.translate import *
|
from View.Results.translate import (
|
||||||
|
table_headers_reach, table_headers_profile,
|
||||||
|
retranslate,
|
||||||
|
)
|
||||||
from View.Stricklers.Window import StricklersWindow
|
from View.Stricklers.Window import StricklersWindow
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
@@ -102,6 +105,7 @@ class ResultsWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
|
retranslate()
|
||||||
self._table = {}
|
self._table = {}
|
||||||
|
|
||||||
for t in ["reach", "profile"]:
|
for t in ["reach", "profile"]:
|
||||||
@@ -131,7 +135,7 @@ class ResultsWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
def setup_graph(self):
|
def setup_graph(self):
|
||||||
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas.setObjectName("canvas")
|
self.canvas.setObjectName("canvas")
|
||||||
self.toolbar = PamHyrNavigationToolbar2QT(
|
self.toolbar = PamhyrPlotToolbar(
|
||||||
self.canvas, self
|
self.canvas, self
|
||||||
)
|
)
|
||||||
self.plot_layout = self.find(QVBoxLayout, "verticalLayout")
|
self.plot_layout = self.find(QVBoxLayout, "verticalLayout")
|
||||||
@@ -150,7 +154,7 @@ class ResultsWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
|
|
||||||
self.canvas_2 = MplCanvas(width=5, height=4, dpi=100)
|
self.canvas_2 = MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas_2.setObjectName("canvas_2")
|
self.canvas_2.setObjectName("canvas_2")
|
||||||
self.toolbar_2 = PamHyrNavigationToolbar2QT(
|
self.toolbar_2 = PamhyrPlotToolbar(
|
||||||
self.canvas_2, self
|
self.canvas_2, self
|
||||||
)
|
)
|
||||||
self.plot_layout_2 = self.find(QVBoxLayout, "verticalLayout_2")
|
self.plot_layout_2 = self.find(QVBoxLayout, "verticalLayout_2")
|
||||||
@@ -168,7 +172,7 @@ class ResultsWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
|
|
||||||
self.canvas_3 = MplCanvas(width=5, height=4, dpi=100)
|
self.canvas_3 = MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas_3.setObjectName("canvas_3")
|
self.canvas_3.setObjectName("canvas_3")
|
||||||
self.toolbar_3 = PamHyrNavigationToolbar2QT(
|
self.toolbar_3 = PamhyrPlotToolbar(
|
||||||
self.canvas_3, self
|
self.canvas_3, self
|
||||||
)
|
)
|
||||||
self.plot_layout_3 = self.find(QVBoxLayout, "verticalLayout_3")
|
self.plot_layout_3 = self.find(QVBoxLayout, "verticalLayout_3")
|
||||||
@@ -186,7 +190,7 @@ class ResultsWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
|
|
||||||
self.canvas_4 = MplCanvas(width=5, height=4, dpi=100)
|
self.canvas_4 = MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas_4.setObjectName("canvas_4")
|
self.canvas_4.setObjectName("canvas_4")
|
||||||
self.toolbar_4 = PamHyrNavigationToolbar2QT(
|
self.toolbar_4 = PamhyrPlotToolbar(
|
||||||
self.canvas_4, self
|
self.canvas_4, self
|
||||||
)
|
)
|
||||||
self.plot_layout_4 = self.find(QVBoxLayout, "verticalLayout_hydrograph")
|
self.plot_layout_4 = self.find(QVBoxLayout, "verticalLayout_hydrograph")
|
||||||
@@ -204,7 +208,7 @@ class ResultsWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
|
|
||||||
self.canvas_5 = MplCanvas(width=5, height=4, dpi=100)
|
self.canvas_5 = MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas_5.setObjectName("canvas_5")
|
self.canvas_5.setObjectName("canvas_5")
|
||||||
self.toolbar_5 = PamHyrNavigationToolbar2QT(
|
self.toolbar_5 = PamhyrPlotToolbar(
|
||||||
self.canvas_5, self
|
self.canvas_5, self
|
||||||
)
|
)
|
||||||
self.plot_layout_5 = self.find(QVBoxLayout, "verticalLayout_sed_reach")
|
self.plot_layout_5 = self.find(QVBoxLayout, "verticalLayout_sed_reach")
|
||||||
@@ -224,7 +228,7 @@ class ResultsWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
|
|
||||||
self.canvas_6 = MplCanvas(width=5, height=4, dpi=100)
|
self.canvas_6 = MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas_6.setObjectName("canvas_6")
|
self.canvas_6.setObjectName("canvas_6")
|
||||||
self.toolbar_6 = PamHyrNavigationToolbar2QT(
|
self.toolbar_6 = PamhyrPlotToolbar(
|
||||||
self.canvas_6, self
|
self.canvas_6, self
|
||||||
)
|
)
|
||||||
self.plot_layout_6 = self.find(QVBoxLayout, "verticalLayout_sed_profile")
|
self.plot_layout_6 = self.find(QVBoxLayout, "verticalLayout_sed_profile")
|
||||||
|
|||||||
@@ -28,3 +28,9 @@ table_headers_profile = {
|
|||||||
"name": _translate("Results", "Name"),
|
"name": _translate("Results", "Name"),
|
||||||
"kp": _translate("Results", "KP (m)"),
|
"kp": _translate("Results", "KP (m)"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def retranslate():
|
||||||
|
table_headers_reach["name"] = _translate("Results", "Reach name")
|
||||||
|
|
||||||
|
table_headers_profile["name"] = _translate("Results", "Name")
|
||||||
|
table_headers_profile["kp"] = _translate("Results", "KP (m)")
|
||||||
@@ -41,12 +41,12 @@ from PyQt5.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from View.Plot.MplCanvas import MplCanvas
|
from View.Plot.MplCanvas import MplCanvas
|
||||||
from View.Plot.navigation_toolbar_2qt import PamHyrNavigationToolbar2QT
|
from View.Plot.PamhyrToolbar import PamhyrPlotToolbar
|
||||||
|
|
||||||
from View.SedimentLayers.Edit.UndoCommand import *
|
from View.SedimentLayers.Edit.UndoCommand import *
|
||||||
from View.SedimentLayers.Edit.Table import *
|
from View.SedimentLayers.Edit.Table import *
|
||||||
from View.SedimentLayers.Edit.Plot import Plot
|
from View.SedimentLayers.Edit.Plot import Plot
|
||||||
from View.SedimentLayers.Edit.translate import *
|
from View.SedimentLayers.Edit.translate import table_headers, retranslate
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
@@ -89,6 +89,7 @@ class EditSedimentLayersWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
|
retranslate()
|
||||||
self._table = {}
|
self._table = {}
|
||||||
|
|
||||||
table = self.find(QTableView, f"tableView")
|
table = self.find(QTableView, f"tableView")
|
||||||
@@ -106,7 +107,7 @@ class EditSedimentLayersWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
def setup_graph(self):
|
def setup_graph(self):
|
||||||
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas.setObjectName("canvas")
|
self.canvas.setObjectName("canvas")
|
||||||
self.toolbar = PamHyrNavigationToolbar2QT(
|
self.toolbar = PamhyrPlotToolbar(
|
||||||
self.canvas, self
|
self.canvas, self
|
||||||
)
|
)
|
||||||
self.plot_layout = self.find(QVBoxLayout, "verticalLayout")
|
self.plot_layout = self.find(QVBoxLayout, "verticalLayout")
|
||||||
|
|||||||
@@ -12,3 +12,11 @@ table_headers = {
|
|||||||
"sigma": _translate("SedimentLayers", "Sigma"),
|
"sigma": _translate("SedimentLayers", "Sigma"),
|
||||||
"critical_constraint": _translate("SedimentLayers", "Critical constraint"),
|
"critical_constraint": _translate("SedimentLayers", "Critical constraint"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def retranslate():
|
||||||
|
table_headers["name"] = _translate("SedimentLayers", "Name")
|
||||||
|
# table_headers["type"] = _translate("SedimentLayers", "Type")
|
||||||
|
table_headers["height"] = _translate("SedimentLayers", "Height")
|
||||||
|
table_headers["d50"] = _translate("SedimentLayers", "D50")
|
||||||
|
table_headers["sigma"] = _translate("SedimentLayers", "Sigma")
|
||||||
|
table_headers["critical_constraint"] = _translate("SedimentLayers", "Critical constraint")
|
||||||
@@ -29,9 +29,9 @@ from View.SedimentLayers.Reach.Profile.Table import *
|
|||||||
from View.SedimentLayers.Reach.Profile.Plot import Plot
|
from View.SedimentLayers.Reach.Profile.Plot import Plot
|
||||||
|
|
||||||
from View.Plot.MplCanvas import MplCanvas
|
from View.Plot.MplCanvas import MplCanvas
|
||||||
from View.Plot.navigation_toolbar_2qt import PamHyrNavigationToolbar2QT
|
from View.Plot.PamhyrToolbar import PamhyrPlotToolbar
|
||||||
|
|
||||||
from View.SedimentLayers.Reach.Profile.translate import *
|
from View.SedimentLayers.Reach.Profile.translate import table_headers, retranslate
|
||||||
from View.SedimentLayers.Window import SedimentLayersWindow
|
from View.SedimentLayers.Window import SedimentLayersWindow
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
@@ -85,6 +85,8 @@ class ProfileSedimentLayersWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
|
retranslate()
|
||||||
|
|
||||||
table = self.find(QTableView, f"tableView")
|
table = self.find(QTableView, f"tableView")
|
||||||
self._table = TableModel(
|
self._table = TableModel(
|
||||||
study = self._study,
|
study = self._study,
|
||||||
@@ -110,7 +112,7 @@ class ProfileSedimentLayersWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
def setup_graph(self):
|
def setup_graph(self):
|
||||||
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas.setObjectName("canvas")
|
self.canvas.setObjectName("canvas")
|
||||||
self.toolbar = PamHyrNavigationToolbar2QT(
|
self.toolbar = PamhyrPlotToolbar(
|
||||||
self.canvas, self
|
self.canvas, self
|
||||||
)
|
)
|
||||||
self.plot_layout = self.find(QVBoxLayout, "verticalLayout")
|
self.plot_layout = self.find(QVBoxLayout, "verticalLayout")
|
||||||
|
|||||||
@@ -11,3 +11,10 @@ table_headers = {
|
|||||||
"name": _translate("SedimentLayers", "Name"),
|
"name": _translate("SedimentLayers", "Name"),
|
||||||
"sl": _translate("SedimentLayers", "Sediment layers"),
|
"sl": _translate("SedimentLayers", "Sediment layers"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def retranslate():
|
||||||
|
table_headers["x"] = _translate("SedimentLayers", "X (m)")
|
||||||
|
table_headers["y"] = _translate("SedimentLayers", "Y (m)")
|
||||||
|
table_headers["z"] = _translate("SedimentLayers", "Z (m)")
|
||||||
|
table_headers["name"] = _translate("SedimentLayers", "Name")
|
||||||
|
table_headers["sl"] = _translate("SedimentLayers", "Sediment layers")
|
||||||
@@ -30,9 +30,9 @@ from View.SedimentLayers.Reach.Plot import Plot
|
|||||||
from View.SedimentLayers.Reach.SLDialog import SLDialog
|
from View.SedimentLayers.Reach.SLDialog import SLDialog
|
||||||
|
|
||||||
from View.Plot.MplCanvas import MplCanvas
|
from View.Plot.MplCanvas import MplCanvas
|
||||||
from View.Plot.navigation_toolbar_2qt import PamHyrNavigationToolbar2QT
|
from View.Plot.PamhyrToolbar import PamhyrPlotToolbar
|
||||||
|
|
||||||
from View.SedimentLayers.Reach.translate import *
|
from View.SedimentLayers.Reach.translate import table_headers, retranslate
|
||||||
from View.SedimentLayers.Window import SedimentLayersWindow
|
from View.SedimentLayers.Window import SedimentLayersWindow
|
||||||
from View.SedimentLayers.Reach.Profile.Window import ProfileSedimentLayersWindow
|
from View.SedimentLayers.Reach.Profile.Window import ProfileSedimentLayersWindow
|
||||||
|
|
||||||
@@ -73,6 +73,8 @@ class ReachSedimentLayersWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
|
retranslate()
|
||||||
|
|
||||||
table = self.find(QTableView, f"tableView")
|
table = self.find(QTableView, f"tableView")
|
||||||
self._table = TableModel(
|
self._table = TableModel(
|
||||||
study = self._study,
|
study = self._study,
|
||||||
@@ -98,7 +100,7 @@ class ReachSedimentLayersWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
def setup_graph(self):
|
def setup_graph(self):
|
||||||
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas.setObjectName("canvas")
|
self.canvas.setObjectName("canvas")
|
||||||
self.toolbar = PamHyrNavigationToolbar2QT(
|
self.toolbar = PamhyrPlotToolbar(
|
||||||
self.canvas, self
|
self.canvas, self
|
||||||
)
|
)
|
||||||
self.plot_layout = self.find(QVBoxLayout, "verticalLayout_2")
|
self.plot_layout = self.find(QVBoxLayout, "verticalLayout_2")
|
||||||
|
|||||||
@@ -9,3 +9,8 @@ table_headers = {
|
|||||||
"kp": _translate("SedimentLayers", "KP (m)"),
|
"kp": _translate("SedimentLayers", "KP (m)"),
|
||||||
"sl": _translate("SedimentLayers", "Sediment layers"),
|
"sl": _translate("SedimentLayers", "Sediment layers"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def retranslate():
|
||||||
|
table_headers["name"] = _translate("SedimentLayers", "Name")
|
||||||
|
table_headers["kp"] = _translate("SedimentLayers", "KP (m)")
|
||||||
|
table_headers["sl"] = _translate("SedimentLayers", "Sediment layers")
|
||||||
@@ -30,7 +30,7 @@ from View.SedimentLayers.Table import *
|
|||||||
from View.SedimentLayers.Edit.Plot import Plot
|
from View.SedimentLayers.Edit.Plot import Plot
|
||||||
|
|
||||||
from View.Plot.MplCanvas import MplCanvas
|
from View.Plot.MplCanvas import MplCanvas
|
||||||
from View.SedimentLayers.translate import *
|
from View.SedimentLayers.translate import table_headers, retranslate
|
||||||
|
|
||||||
from View.SedimentLayers.Edit.Window import EditSedimentLayersWindow
|
from View.SedimentLayers.Edit.Window import EditSedimentLayersWindow
|
||||||
|
|
||||||
@@ -70,6 +70,8 @@ class SedimentLayersWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
|
retranslate()
|
||||||
|
|
||||||
table = self.find(QTableView, f"tableView")
|
table = self.find(QTableView, f"tableView")
|
||||||
self._table = TableModel(
|
self._table = TableModel(
|
||||||
study = self._study,
|
study = self._study,
|
||||||
|
|||||||
@@ -8,3 +8,7 @@ table_headers = {
|
|||||||
"name": _translate("SedimentLayers", "Name"),
|
"name": _translate("SedimentLayers", "Name"),
|
||||||
"comment": _translate("SedimentLayers", "Comment"),
|
"comment": _translate("SedimentLayers", "Comment"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def retranslate():
|
||||||
|
table_headers["name"] = _translate("SedimentLayers", "Name")
|
||||||
|
table_headers["comment"] = _translate("SedimentLayers", "Comment")
|
||||||
@@ -34,37 +34,19 @@ from PyQt5.QtWidgets import (
|
|||||||
QComboBox,
|
QComboBox,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from View.Tools.PamhyrTable import PamhyrTableModel
|
||||||
|
|
||||||
from View.Stricklers.UndoCommand import (
|
from View.Stricklers.UndoCommand import (
|
||||||
SetNameCommand, SetCommentCommand,
|
SetNameCommand, SetCommentCommand,
|
||||||
SetMinorCommand, SetMediumCommand,
|
SetMinorCommand, SetMediumCommand,
|
||||||
AddCommand, DelCommand, SortCommand,
|
AddCommand, DelCommand, SortCommand,
|
||||||
)
|
)
|
||||||
|
|
||||||
from View.Stricklers.translate import *
|
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
class TableModel(QAbstractTableModel):
|
class TableModel(PamhyrTableModel):
|
||||||
def __init__(self, data=None, undo=None, tab=""):
|
|
||||||
super(QAbstractTableModel, self).__init__()
|
|
||||||
self._headers = list(table_headers.keys())
|
|
||||||
self._data = data
|
|
||||||
self._undo = undo
|
|
||||||
|
|
||||||
def flags(self, index):
|
|
||||||
options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
|
||||||
options |= Qt.ItemIsEditable
|
|
||||||
|
|
||||||
return options
|
|
||||||
|
|
||||||
def rowCount(self, parent):
|
|
||||||
return len(self._data)
|
|
||||||
|
|
||||||
def columnCount(self, parent):
|
|
||||||
return len(self._headers)
|
|
||||||
|
|
||||||
def data(self, index, role):
|
def data(self, index, role):
|
||||||
if role != Qt.ItemDataRole.DisplayRole:
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
return QVariant()
|
return QVariant()
|
||||||
@@ -83,12 +65,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
return QVariant()
|
return QVariant()
|
||||||
|
|
||||||
def headerData(self, section, orientation, role):
|
@pyqtSlot()
|
||||||
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
|
|
||||||
return table_headers[self._headers[section]]
|
|
||||||
|
|
||||||
return QVariant()
|
|
||||||
|
|
||||||
def setData(self, index, value, role=Qt.EditRole):
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
if not index.isValid() or role != Qt.EditRole:
|
if not index.isValid() or role != Qt.EditRole:
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ class AddCommand(QUndoCommand):
|
|||||||
|
|
||||||
def redo(self):
|
def redo(self):
|
||||||
if self._new is None:
|
if self._new is None:
|
||||||
self._new = self._data.add(self._index)
|
self._new = self._data.new(self._index)
|
||||||
else:
|
else:
|
||||||
self._data.insert(self._index, self._new)
|
self._data.insert(self._index, self._new)
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ from Model.Stricklers.Stricklers import Stricklers
|
|||||||
|
|
||||||
from View.Stricklers.UndoCommand import PasteCommand
|
from View.Stricklers.UndoCommand import PasteCommand
|
||||||
from View.Stricklers.Table import TableModel
|
from View.Stricklers.Table import TableModel
|
||||||
|
from View.Stricklers.translate import table_headers, retranslate
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
@@ -74,7 +75,9 @@ class StricklersWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self.copy_sc = QShortcut(QKeySequence.Copy, self)
|
self.copy_sc = QShortcut(QKeySequence.Copy, self)
|
||||||
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
||||||
|
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
|
retranslate()
|
||||||
self._table = {}
|
self._table = {}
|
||||||
|
|
||||||
for t in ["app", "study"]:
|
for t in ["app", "study"]:
|
||||||
@@ -85,6 +88,9 @@ class StricklersWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
data = self._config.stricklers
|
data = self._config.stricklers
|
||||||
|
|
||||||
self._table[t] = TableModel(
|
self._table[t] = TableModel(
|
||||||
|
table_view = table,
|
||||||
|
table_headers = table_headers,
|
||||||
|
editable_headers = ["name", "comment", "minor", "medium"],
|
||||||
data = data,
|
data = data,
|
||||||
undo = self._undo_stack,
|
undo = self._undo_stack,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -30,3 +30,9 @@ table_headers = {
|
|||||||
"medium": _translate("LateralContribution", "Medium bed"),
|
"medium": _translate("LateralContribution", "Medium bed"),
|
||||||
"comment": _translate("LateralContribution", "Comment"),
|
"comment": _translate("LateralContribution", "Comment"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def retranslate():
|
||||||
|
table_headers["name"] = _translate("LateralContribution", "Name")
|
||||||
|
table_headers["minor"] = _translate("LateralContribution", "Minor bed")
|
||||||
|
table_headers["medium"] = _translate("LateralContribution", "Medium bed")
|
||||||
|
table_headers["comment"] = _translate("LateralContribution", "Comment")
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
# PamhyrDelegate.py -- Pamhyr
|
||||||
|
# Copyright (C) 2023 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QRect, QTime, QDateTime, pyqtSlot,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QSpinBox, QTimeEdit, QDateTimeEdit, QItemDelegate,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.Tools.PamhyrWidget import (
|
||||||
|
PamhyrExtendedTimeEdit, PamhyrExtendedDateTimeEdit
|
||||||
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class PamhyrExTimeDelegate(QItemDelegate):
|
||||||
|
def __init__(self, data=None, mode="time", parent=None):
|
||||||
|
super(PamhyrExTimeDelegate, self).__init__(parent)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._mode = mode
|
||||||
|
|
||||||
|
def createEditor(self, parent, option, index):
|
||||||
|
if self._mode == "time":
|
||||||
|
self.editor = PamhyrExtendedTimeEdit(parent=parent)
|
||||||
|
else:
|
||||||
|
self.editor = PamhyrExtendedDateTimeEdit(parent=parent)
|
||||||
|
value = index.data(Qt.DisplayRole)
|
||||||
|
self.editor.set_time(value)
|
||||||
|
logger.debug(str(value))
|
||||||
|
return self.editor
|
||||||
|
|
||||||
|
def setModelData(self, editor, model, index):
|
||||||
|
time = editor.get_time()
|
||||||
|
if self._mode == "time":
|
||||||
|
model.setData(index, int(time.total_seconds()))
|
||||||
|
else:
|
||||||
|
logger.debug(str(time.timestamp()))
|
||||||
|
model.setData(index, int(time.timestamp()))
|
||||||
|
editor.close()
|
||||||
|
editor.deleteLater()
|
||||||
|
|
||||||
|
def updateEditorGeometry(self, editor, option, index):
|
||||||
|
r = QRect(option.rect)
|
||||||
|
if self.editor.windowFlags() & Qt.Popup and editor.parent() is not None:
|
||||||
|
r.setTopLeft(self.editor.parent().mapToGlobal(r.topLeft()))
|
||||||
|
editor.setGeometry(r)
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def currentItemChanged(self):
|
||||||
|
self.commitData.emit(self.sender())
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
# PamhyrTable.py -- Pamhyr abstract table model
|
||||||
|
# Copyright (C) 2023 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant, QAbstractTableModel,
|
||||||
|
QCoreApplication, QModelIndex, pyqtSlot,
|
||||||
|
QRect,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QDialogButtonBox, QPushButton, QLineEdit,
|
||||||
|
QFileDialog, QTableView, QAbstractItemView,
|
||||||
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||||
|
QComboBox, QStyledItemDelegate,
|
||||||
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class PamhyrTextDelegate(QStyledItemDelegate):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super(PamhyrTextDelegate, self).__init__(parent)
|
||||||
|
|
||||||
|
def createEditor(self, parent, option, index):
|
||||||
|
index.model().data(index, Qt.DisplayRole)
|
||||||
|
return QLineEdit(parent)
|
||||||
|
|
||||||
|
def setEditorData(self, editor, index):
|
||||||
|
value = index.model().data(index, Qt.DisplayRole)
|
||||||
|
editor.setText(str(value))
|
||||||
|
|
||||||
|
def setModelData(self, editor, model, index):
|
||||||
|
model.setData(index, editor.text())
|
||||||
|
|
||||||
|
def updateEditorGeometry(self, editor, option, index):
|
||||||
|
editor.setGeometry(option.rect)
|
||||||
|
|
||||||
|
class PamhyrTableModel(QAbstractTableModel):
|
||||||
|
def _setup_delegates(self):
|
||||||
|
if self._table_view is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
for h in self._headers:
|
||||||
|
if h in self._delegates:
|
||||||
|
self._table_view.setItemDelegateForColumn(
|
||||||
|
self._headers.index(h), self._delegates[h]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self._table_view.setItemDelegateForColumn(
|
||||||
|
self._headers.index(h), PamhyrTextDelegate(
|
||||||
|
parent=self
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
table_view=None,
|
||||||
|
table_headers={},
|
||||||
|
editable_headers=[],
|
||||||
|
delegates = {},
|
||||||
|
data=None,
|
||||||
|
undo=None,
|
||||||
|
opt_data=None):
|
||||||
|
super(PamhyrTableModel, self).__init__()
|
||||||
|
|
||||||
|
self._table_view = table_view
|
||||||
|
|
||||||
|
self._table_headers = table_headers
|
||||||
|
self._headers = list(table_headers.keys())
|
||||||
|
self._editable_headers = editable_headers
|
||||||
|
self._delegates = delegates
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._opt_data = opt_data
|
||||||
|
self._undo = undo
|
||||||
|
self._lst = []
|
||||||
|
|
||||||
|
self._setup_delegates()
|
||||||
|
self._setup_lst()
|
||||||
|
|
||||||
|
def _setup_lst(self):
|
||||||
|
self._lst = self._data
|
||||||
|
|
||||||
|
def flags(self, index):
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
||||||
|
|
||||||
|
if (self._editable_headers or
|
||||||
|
self._headers[column] in self._editable_headers):
|
||||||
|
options |= Qt.ItemIsEditable
|
||||||
|
|
||||||
|
return options
|
||||||
|
|
||||||
|
def rowCount(self, parent):
|
||||||
|
return len(self._lst)
|
||||||
|
|
||||||
|
def columnCount(self, parent):
|
||||||
|
return len(self._headers)
|
||||||
|
|
||||||
|
def headerData(self, section, orientation, role):
|
||||||
|
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
|
||||||
|
return self._table_headers[self._headers[section]]
|
||||||
|
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
raise NotImplementedMethodeError(self, self.data)
|
||||||
|
|
||||||
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
|
raise NotImplementedMethodeError(self, self.setData)
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._undo.undo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._undo.redo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
# PamhyrWidget.py -- Pamhyr
|
||||||
|
# Copyright (C) 2023 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
QModelIndex, QRect, QTime, QDateTime,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QSpinBox, QTimeEdit, QDateTimeEdit, QItemDelegate,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.ASubWindow import AWidget
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class PamhyrExtendedTimeEdit(AWidget):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super(PamhyrExtendedTimeEdit, self).__init__(
|
||||||
|
ui="extendedTimeEdit",
|
||||||
|
parent=parent
|
||||||
|
)
|
||||||
|
self.parent = parent
|
||||||
|
|
||||||
|
self.spinBox_days = self.find(QSpinBox, "spinBox_days")
|
||||||
|
self.timeEdit = self.find(QTimeEdit, "timeEdit")
|
||||||
|
|
||||||
|
def set_time(self, time):
|
||||||
|
days = 0
|
||||||
|
stime = time
|
||||||
|
|
||||||
|
# if ',' in time, time format is 'DD days, HH:MM:SS',
|
||||||
|
# otherelse is 'HH:MM:SS'
|
||||||
|
if "," in time:
|
||||||
|
s = time.strip().split(" ")
|
||||||
|
days = int(s[0])
|
||||||
|
stime = s[-1]
|
||||||
|
|
||||||
|
qtime = QTime.fromString(
|
||||||
|
stime,
|
||||||
|
"h:mm:ss"
|
||||||
|
)
|
||||||
|
self.spinBox_days.setValue(days)
|
||||||
|
self.timeEdit.setTime(qtime)
|
||||||
|
|
||||||
|
def get_time(self):
|
||||||
|
days = self.spinBox_days.value()
|
||||||
|
time = self.timeEdit.time().toPyTime()
|
||||||
|
secs = (
|
||||||
|
(time.hour * 3600) +
|
||||||
|
(time.minute * 60) +
|
||||||
|
time.second
|
||||||
|
)
|
||||||
|
|
||||||
|
return timedelta(days=days, seconds=secs)
|
||||||
|
|
||||||
|
class PamhyrExtendedDateTimeEdit(AWidget):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super(ExtendedDateTimeEdit, self).__init__(
|
||||||
|
ui="extendedDateTimeEdit",
|
||||||
|
parent=parent
|
||||||
|
)
|
||||||
|
self.parent = parent
|
||||||
|
|
||||||
|
self.dateTimeEdit = self.find(QDateTimeEdit, "dateTimeEdit")
|
||||||
|
|
||||||
|
def set_time(self, time):
|
||||||
|
qdatetime = QDateTime.fromString(
|
||||||
|
time,
|
||||||
|
"yyyy-MM-dd hh:mm:ss"
|
||||||
|
)
|
||||||
|
self.dateTimeEdit.setDateTime(qdatetime)
|
||||||
|
|
||||||
|
def get_time(self):
|
||||||
|
time = self.dateTimeEdit.dateTime().toPyDateTime()
|
||||||
|
return time
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>About PAMHYR</string>
|
<string>About Pamhyr2</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
+2
-2
@@ -96,7 +96,7 @@ class Config(SQL):
|
|||||||
INSERT INTO solver VALUES (
|
INSERT INTO solver VALUES (
|
||||||
'mage8',
|
'mage8',
|
||||||
'default-mage',
|
'default-mage',
|
||||||
'Default PAMHYR mage 8 version',
|
'Default Pamhyr2 mage 8 version',
|
||||||
|
|
||||||
'', '', '',
|
'', '', '',
|
||||||
|
|
||||||
@@ -265,7 +265,7 @@ class Config(SQL):
|
|||||||
posix = os.name == 'posix'
|
posix = os.name == 'posix'
|
||||||
ctor = solver_type_list["mage8"]
|
ctor = solver_type_list["mage8"]
|
||||||
new = ctor("default-mage")
|
new = ctor("default-mage")
|
||||||
new._description = "Default PAMHYR mage 8 version"
|
new._description = "Default Pamhyr2 mage 8 version"
|
||||||
new._cmd_solver = f""""@install_dir/mage/mage{"" if posix else ".exe"}" -fp=1 @input"""
|
new._cmd_solver = f""""@install_dir/mage/mage{"" if posix else ".exe"}" -fp=1 @input"""
|
||||||
self._solvers.append(new)
|
self._solvers.append(new)
|
||||||
|
|
||||||
|
|||||||
+109
@@ -0,0 +1,109 @@
|
|||||||
|
# init.py -- Pamhyr
|
||||||
|
# Copyright (C) 2023 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import sys, os
|
||||||
|
import locale
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QTranslator
|
||||||
|
|
||||||
|
from tools import (
|
||||||
|
reset_timers, display_timers, timer,
|
||||||
|
logger_color_blue, logger_color_red, logger_color_green, logger_color_reset
|
||||||
|
)
|
||||||
|
from config import Config
|
||||||
|
|
||||||
|
from View.MainWindow import ApplicationWindow
|
||||||
|
from Model.Study import Study
|
||||||
|
|
||||||
|
|
||||||
|
# Configure logger
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.DEBUG,
|
||||||
|
format=(f'[{logger_color_blue()}PAMHYR{logger_color_reset()}]' +
|
||||||
|
f'[{logger_color_green()}%(levelname)s{logger_color_reset()}]' +
|
||||||
|
' %(message)s')
|
||||||
|
)
|
||||||
|
logger = logging.getLogger()
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
try:
|
||||||
|
log = os.path.join(
|
||||||
|
os.path.dirname(Config.filename()), "log.txt"
|
||||||
|
)
|
||||||
|
logfile = open(log, "w+")
|
||||||
|
handler = logging.StreamHandler(logfile)
|
||||||
|
formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s')
|
||||||
|
handler.setFormatter(formatter)
|
||||||
|
handler.setLevel(logging.DEBUG)
|
||||||
|
logger.addHandler(handler)
|
||||||
|
except:
|
||||||
|
logger.error("Failed to create logfile...")
|
||||||
|
|
||||||
|
|
||||||
|
def license():
|
||||||
|
"Display in stdout Pamhyr infomation about licence and version"
|
||||||
|
blue = lambda s: logger.info(f"{logger_color_blue()}{s}{logger_color_reset()}")
|
||||||
|
|
||||||
|
blue("""`7MM\"""Mq. db `7MMM. ,MMF'`7MMF' `7MMF'`YMM' `MM'`7MM\"""Mq.""")
|
||||||
|
blue(""" MM `MM. ;MM: MMMb dPMM MM MM VMA ,V MM `MM.""")
|
||||||
|
blue(""" MM ,M9 ,V^MM. M YM ,M MM MM MM VMA ,V MM ,M9 pd*"*b.""")
|
||||||
|
blue(""" MMmmdM9 ,M `MM M Mb M' MM MMmmmmmmMM VMMP MMmmdM9 (O) j8""")
|
||||||
|
blue(""" MM AbmmmqMA M YM.P' MM MM MM MM MM YM. ,;j9""")
|
||||||
|
blue(""" MM A' VML M `YM' MM MM MM MM MM `Mb. ,-='""")
|
||||||
|
blue(""".JMML. .AMA. .AMMA..JML. `' .JMML..JMML. .JMML. .JMML. .JMML. .JMM. Ammmmmmm""")
|
||||||
|
|
||||||
|
with open(os.path.abspath(
|
||||||
|
os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
"VERSION"
|
||||||
|
)
|
||||||
|
), "r") as f:
|
||||||
|
version = f.readline().strip()
|
||||||
|
logger.info(f"version: {logger_color_green()}{version}{logger_color_reset()}")
|
||||||
|
|
||||||
|
logger.info("license: pamhyr Copyright (C) 2023 INRAE")
|
||||||
|
logger.info("license: This program comes with ABSOLUTELY NO WARRANTY.")
|
||||||
|
logger.info("license: This is free software, and you are welcome to redistribute it")
|
||||||
|
logger.info("license: under certain conditions.")
|
||||||
|
|
||||||
|
def setup_lang(app, conf:Config):
|
||||||
|
"Return QTranslator configured for current language"
|
||||||
|
lang_file = ""
|
||||||
|
translator = QTranslator()
|
||||||
|
|
||||||
|
if conf.lang == "":
|
||||||
|
# System language
|
||||||
|
sys_lang = locale.getdefaultlocale()
|
||||||
|
if "fr" in sys_lang[0]:
|
||||||
|
lang_file = os.path.dirname(__file__) + "/lang/fr.qm"
|
||||||
|
elif conf.lang == "fr":
|
||||||
|
# French
|
||||||
|
lang_file = os.path.dirname(__file__) + "/lang/fr.qm"
|
||||||
|
else:
|
||||||
|
# English default language
|
||||||
|
lang_file = ""
|
||||||
|
|
||||||
|
if lang_file != "":
|
||||||
|
logger.info(f"Load lang file: {lang_file}")
|
||||||
|
ok = translator.load(lang_file)
|
||||||
|
if not ok:
|
||||||
|
logger.error("Failed to load translate file")
|
||||||
|
|
||||||
|
return translator
|
||||||
+122
-83
@@ -1,6 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!DOCTYPE TS>
|
<!DOCTYPE TS><TS version="2.0" language="fr_FR" sourcelanguage="en_150">
|
||||||
<TS version="2.1" language="fr_FR" sourcelanguage="en_150">
|
|
||||||
<context>
|
<context>
|
||||||
<name>About</name>
|
<name>About</name>
|
||||||
<message>
|
<message>
|
||||||
@@ -12,7 +11,7 @@
|
|||||||
<context>
|
<context>
|
||||||
<name>BoundaryCondition</name>
|
<name>BoundaryCondition</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/BoundaryCondition/Table.py" line="143"/>
|
<location filename="../View/BoundaryCondition/Table.py" line="132"/>
|
||||||
<source>Not associate</source>
|
<source>Not associate</source>
|
||||||
<translation>Non associer</translation>
|
<translation>Non associer</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -78,7 +77,7 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/BoundaryCondition/Edit/translate.py" line="12"/>
|
<location filename="../View/BoundaryCondition/Edit/translate.py" line="12"/>
|
||||||
<source>Discharge (m³/s)</source>
|
<source>Discharge (m³/s)</source>
|
||||||
<translation type="obsolete">Débit (m³/s)</translation>
|
<translation type="obsolete">Débit (m³/s)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
@@ -106,6 +105,11 @@
|
|||||||
<source>ZDischarge</source>
|
<source>ZDischarge</source>
|
||||||
<translation>HauteurDébit</translation>
|
<translation>HauteurDébit</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message encoding="UTF-8">
|
||||||
|
<location filename="../View/BoundaryCondition/Edit/translate.py" line="28"/>
|
||||||
|
<source>Discharge (m³/s)</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>Checker</name>
|
<name>Checker</name>
|
||||||
@@ -486,12 +490,12 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../View/ui/about.ui" line="42"/>
|
<location filename="../View/ui/about.ui" line="42"/>
|
||||||
<source>About PAMHYR</source>
|
<source>About PAMHYR</source>
|
||||||
<translation>À propos de PAMHYR</translation>
|
<translation type="obsolete">À propos de PAMHYR</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/ui/about.ui" line="56"/>
|
<location filename="../View/ui/about.ui" line="56"/>
|
||||||
<source>Version: @version</source>
|
<source>Version: @version</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation>Version: @version</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/ui/about.ui" line="63"/>
|
<location filename="../View/ui/about.ui" line="63"/>
|
||||||
@@ -518,6 +522,11 @@
|
|||||||
<source>Sigma</source>
|
<source>Sigma</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../View/ui/about.ui" line="42"/>
|
||||||
|
<source>About Pamhyr2</source>
|
||||||
|
<translation>À propos de Pamhyr2</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>Frictions</name>
|
<name>Frictions</name>
|
||||||
@@ -603,7 +612,7 @@
|
|||||||
<translation>Commentaire</translation>
|
<translation>Commentaire</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/LateralContribution/Table.py" line="141"/>
|
<location filename="../View/LateralContribution/Table.py" line="130"/>
|
||||||
<source>Not associate</source>
|
<source>Not associate</source>
|
||||||
<translation>Non associer</translation>
|
<translation>Non associer</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -699,9 +708,14 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/InitialConditions/translate.py" line="11"/>
|
<location filename="../View/InitialConditions/translate.py" line="11"/>
|
||||||
<source>Discharge (m³/s)</source>
|
<source>Discharge (m³/s)</source>
|
||||||
<translation type="obsolete">Débit (m³/s)</translation>
|
<translation type="obsolete">Débit (m³/s)</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message encoding="UTF-8">
|
||||||
|
<location filename="../View/InitialConditions/translate.py" line="27"/>
|
||||||
|
<source>Discharge (m³/s)</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>MainWindow</name>
|
<name>MainWindow</name>
|
||||||
@@ -1408,7 +1422,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../View/ui/SolverLog.ui" line="106"/>
|
<location filename="../View/ui/SolverLog.ui" line="106"/>
|
||||||
<source>results</source>
|
<source>results</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation>Résultats</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/ui/EditSedimentLayers.ui" line="63"/>
|
<location filename="../View/ui/EditSedimentLayers.ui" line="63"/>
|
||||||
@@ -1510,28 +1524,28 @@
|
|||||||
<source>Edit sediment layers</source>
|
<source>Edit sediment layers</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/ui/MainWindow.ui" line="553"/>
|
<location filename="../View/ui/MainWindow.ui" line="553"/>
|
||||||
<source>Édition des Tronçons</source>
|
<source>Édition des Tronçons</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/ui/MainWindow.ui" line="667"/>
|
<location filename="../View/ui/MainWindow.ui" line="667"/>
|
||||||
<source>Ouvrir une étude</source>
|
<source>Ouvrir une étude</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/ui/MainWindow.ui" line="679"/>
|
<location filename="../View/ui/MainWindow.ui" line="679"/>
|
||||||
<source>Enrégistrer étude en cours (Ctrl+S)</source>
|
<source>Enrégistrer étude en cours (Ctrl+S)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/ui/MainWindow.ui" line="694"/>
|
<location filename="../View/ui/MainWindow.ui" line="694"/>
|
||||||
<source>Fermer étude en cours (Ctrl+F)</source>
|
<source>Fermer étude en cours (Ctrl+F)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context encoding="UTF-8">
|
||||||
<name>MainWindowProfile</name>
|
<name>MainWindowProfile</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Geometry/Profile/Window.py" line="83"/>
|
<location filename="../View/Geometry/Profile/Window.py" line="83"/>
|
||||||
@@ -1549,17 +1563,17 @@
|
|||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="223"/>
|
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="224"/>
|
||||||
<source>MainWindowProfile</source>
|
<source>MainWindowProfile</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="227"/>
|
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="228"/>
|
||||||
<source>Trier les points par ordre croissant de X</source>
|
<source>Trier les points par ordre croissant de X</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="231"/>
|
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="232"/>
|
||||||
<source>Trier les points par ordre croissant de Y</source>
|
<source>Trier les points par ordre croissant de Y</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -1605,108 +1619,108 @@
|
|||||||
<source>Cote (m)</source>
|
<source>Cote (m)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/Window.py" line="328"/>
|
<location filename="../View/Geometry/Profile/Window.py" line="328"/>
|
||||||
<source>Suppression les lignes incomplètes</source>
|
<source>Suppression les lignes incomplètes</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/Window.py" line="328"/>
|
<location filename="../View/Geometry/Profile/Window.py" line="328"/>
|
||||||
<source>Supprimer les lignes des cellules non renseignées ?</source>
|
<source>Supprimer les lignes des cellules non renseignées ?</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/Window.py" line="371"/>
|
<location filename="../View/Geometry/Profile/Window.py" line="371"/>
|
||||||
<source>Suppression des noms répétés</source>
|
<source>Suppression des noms répétés</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/Window.py" line="382"/>
|
<location filename="../View/Geometry/Profile/Window.py" line="382"/>
|
||||||
<source>Etes-vous sûr de vouloir quitter ?</source>
|
<source>Etes-vous sûr de vouloir quitter ?</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="224"/>
|
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="225"/>
|
||||||
<source>Insérer un point</source>
|
<source>Insérer un point</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="225"/>
|
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="226"/>
|
||||||
<source>Supprimer le/les point(s) sélectionnés</source>
|
<source>Supprimer le/les point(s) sélectionnés</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="229"/>
|
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="230"/>
|
||||||
<source>Trier les points par ordre décroissant de X</source>
|
<source>Trier les points par ordre décroissant de X</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="234"/>
|
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="235"/>
|
||||||
<source>Trier les points par ordre décroissant de Y</source>
|
<source>Trier les points par ordre décroissant de Y</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="236"/>
|
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="237"/>
|
||||||
<source>Décaler le point sélectionné vers le haut</source>
|
<source>Décaler le point sélectionné vers le haut</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="238"/>
|
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="239"/>
|
||||||
<source>Décaler le point sélectionné vers le bas</source>
|
<source>Décaler le point sélectionné vers le bas</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="240"/>
|
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="241"/>
|
||||||
<source>Exporter (dans un fichier) les points du profil au format tabulé</source>
|
<source>Exporter (dans un fichier) les points du profil au format tabulé</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="242"/>
|
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="243"/>
|
||||||
<source>Copier la sélection au format tabulé</source>
|
<source>Copier la sélection au format tabulé</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="244"/>
|
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="245"/>
|
||||||
<source>Coller la sélection depuis le presse-papier au format tabulé</source>
|
<source>Coller la sélection depuis le presse-papier au format tabulé</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="246"/>
|
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="247"/>
|
||||||
<source>Vérifier la validité de la saisie et garder ou pas les modifications apportées</source>
|
<source>Vérifier la validité de la saisie et garder ou pas les modifications apportées</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="249"/>
|
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="250"/>
|
||||||
<source>Annuler toutes les modifications depuis la dernière validation</source>
|
<source>Annuler toutes les modifications depuis la dernière validation</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="251"/>
|
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="252"/>
|
||||||
<source>Annuler toutes les modifications et revenir à l'état initial</source>
|
<source>Annuler toutes les modifications et revenir à l'état initial</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="253"/>
|
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="254"/>
|
||||||
<source>Ligne d'eau :
|
<source>Ligne d'eau :
|
||||||
Z : Cote (m)
|
<byte value="x9"/>Z : Cote (m)
|
||||||
A : Aire mouillée (mu00B2)
|
<byte value="x9"/>A : Aire mouillée (mu00B2)
|
||||||
p : Périmètre mouillé (m)
|
<byte value="x9"/>p : Périmètre mouillé (m)
|
||||||
L : Largeur au miroir (m)</source>
|
<byte value="x9"/>L : Largeur au miroir (m)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="257"/>
|
<location filename="../View/Geometry/Profile/mainwindow_ui_profile.py" line="258"/>
|
||||||
<source>'Maj + Clic' : Ligne d'eau & 'Ctrl + Clic' : Sélectionner des points</source>
|
<source>'Maj + Clic' : Ligne d'eau & 'Ctrl + Clic' : Sélectionner des points</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Profile/Table.py" line="142"/>
|
<location filename="../View/Geometry/Profile/Table.py" line="142"/>
|
||||||
<source>Abscisse en travers calculée en projétant les points
|
<source>Abscisse en travers calculée en projétant les points
|
||||||
sur le plan défini par les deux points nommés extrêmes </source>
|
sur le plan défini par les deux points nommés extrêmes </source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context encoding="UTF-8">
|
||||||
<name>MainWindow_reach</name>
|
<name>MainWindow_reach</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Frictions/PlotStricklers.py" line="76"/>
|
<location filename="../View/Frictions/PlotStricklers.py" line="76"/>
|
||||||
@@ -1844,7 +1858,7 @@ sur le plan défini par les deux points nommés extrêmes </source>
|
|||||||
<translation type="unfinished">Hauteur (m)</translation>
|
<translation type="unfinished">Hauteur (m)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Plot/navigation_toolbar_2qt.py" line="146"/>
|
<location filename="../View/Plot/PamhyrToolbar.py" line="148"/>
|
||||||
<source>Select destination file</source>
|
<source>Select destination file</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -1898,58 +1912,58 @@ sur le plan défini par les deux points nommés extrêmes </source>
|
|||||||
<source> Editer selected profile</source>
|
<source> Editer selected profile</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Window.py" line="164"/>
|
<location filename="../View/Geometry/Window.py" line="164"/>
|
||||||
<source>Édition des profils sélectionnés</source>
|
<source>Édition des profils sélectionnés</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Window.py" line="166"/>
|
<location filename="../View/Geometry/Window.py" line="166"/>
|
||||||
<source>Vous avez sélectionné plus de 5 profils.
|
<source>Vous avez sélectionné plus de 5 profils.
|
||||||
Seuls les 5 premiers seront édités.</source>
|
Seuls les 5 premiers seront édités.</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/Window.py" line="322"/>
|
<location filename="../View/Geometry/Window.py" line="322"/>
|
||||||
<source>Profil N° : </source>
|
<source>Profil N° : </source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/PlotAC.py" line="179"/>
|
<location filename="../View/Geometry/PlotAC.py" line="179"/>
|
||||||
<source>Profil précédent</source>
|
<source>Profil précédent</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/PlotAC.py" line="180"/>
|
<location filename="../View/Geometry/PlotAC.py" line="180"/>
|
||||||
<source>Profil sélectionné</source>
|
<source>Profil sélectionné</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/mainwindow_ui_reach.py" line="328"/>
|
<location filename="../View/Geometry/mainwindow_ui_reach.py" line="328"/>
|
||||||
<source> Trier les profils par ordre décroissant des Pk</source>
|
<source> Trier les profils par ordre décroissant des Pk</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/mainwindow_ui_reach.py" line="329"/>
|
<location filename="../View/Geometry/mainwindow_ui_reach.py" line="329"/>
|
||||||
<source> Changer l'ordre des profils (en décalant le profil sélectionné vers le haut)</source>
|
<source> Changer l'ordre des profils (en décalant le profil sélectionné vers le haut)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/mainwindow_ui_reach.py" line="331"/>
|
<location filename="../View/Geometry/mainwindow_ui_reach.py" line="331"/>
|
||||||
<source> Changer l'ordre des profils (en décalant le profil sélectionné vers le bas)</source>
|
<source> Changer l'ordre des profils (en décalant le profil sélectionné vers le bas)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/mainwindow_ui_reach.py" line="339"/>
|
<location filename="../View/Geometry/mainwindow_ui_reach.py" line="339"/>
|
||||||
<source>Vue isométrique (Alt+Z)</source>
|
<source>Vue isométrique (Alt+Z)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/mainwindow_ui_reach.py" line="342"/>
|
<location filename="../View/Geometry/mainwindow_ui_reach.py" line="342"/>
|
||||||
<source>Vue isométrique (Alt+E)</source>
|
<source>Vue isométrique (Alt+E)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message encoding="UTF-8">
|
||||||
<location filename="../View/Geometry/mainwindow_ui_reach.py" line="345"/>
|
<location filename="../View/Geometry/mainwindow_ui_reach.py" line="345"/>
|
||||||
<source>Vue isométrique (Alt+R)</source>
|
<source>Vue isométrique (Alt+R)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
@@ -1958,40 +1972,60 @@ Seuls les 5 premiers seront édités.</source>
|
|||||||
<context>
|
<context>
|
||||||
<name>Network</name>
|
<name>Network</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Network/GraphWidget.py" line="809"/>
|
<location filename="../View/Network/GraphWidget.py" line="812"/>
|
||||||
<source>Add node</source>
|
<source>Add node</source>
|
||||||
<translation>Ajouter un nœud</translation>
|
<translation>Ajouter un nœud</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Network/GraphWidget.py" line="817"/>
|
<location filename="../View/Network/GraphWidget.py" line="820"/>
|
||||||
<source>Delete the node</source>
|
<source>Delete the node</source>
|
||||||
<translation>Supprimer un nœud</translation>
|
<translation>Supprimer un nœud</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Network/GraphWidget.py" line="818"/>
|
<location filename="../View/Network/GraphWidget.py" line="821"/>
|
||||||
<source>Disable the node</source>
|
<source>Disable the node</source>
|
||||||
<translation>Déactiver un nœud</translation>
|
<translation>Déactiver un nœud</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Network/GraphWidget.py" line="826"/>
|
<location filename="../View/Network/GraphWidget.py" line="829"/>
|
||||||
<source>Delete the reach</source>
|
<source>Delete the reach</source>
|
||||||
<translation>Supprimer un bief</translation>
|
<translation>Supprimer un bief</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Network/GraphWidget.py" line="829"/>
|
<location filename="../View/Network/GraphWidget.py" line="832"/>
|
||||||
<source>Disable the reach</source>
|
<source>Disable the reach</source>
|
||||||
<translation>Déactiver un bief</translation>
|
<translation>Déactiver un bief</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Network/GraphWidget.py" line="832"/>
|
<location filename="../View/Network/GraphWidget.py" line="835"/>
|
||||||
<source>Enable the reach</source>
|
<source>Enable the reach</source>
|
||||||
<translation>Activer un bief</translation>
|
<translation>Activer un bief</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Network/GraphWidget.py" line="835"/>
|
<location filename="../View/Network/GraphWidget.py" line="838"/>
|
||||||
<source>Reverse the reach orientation</source>
|
<source>Reverse the reach orientation</source>
|
||||||
<translation>Inverser l'orientation du bief</translation>
|
<translation>Inverser l'orientation du bief</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../View/Network/translate.py" line="29"/>
|
||||||
|
<source>Name</source>
|
||||||
|
<translation>Nom</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../View/Network/translate.py" line="25"/>
|
||||||
|
<source>Type</source>
|
||||||
|
<translation>Type</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../View/Network/translate.py" line="30"/>
|
||||||
|
<source>Source node</source>
|
||||||
|
<translation>Nœud source</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../View/Network/translate.py" line="31"/>
|
||||||
|
<source>Destination node</source>
|
||||||
|
<translation>Nœud destination</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>Results</name>
|
<name>Results</name>
|
||||||
@@ -2037,9 +2071,14 @@ Seuls les 5 premiers seront édités.</source>
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Results/PlotH.py" line="79"/>
|
<location filename="../View/Results/PlotH.py" line="79"/>
|
||||||
<source>Discharge (m³/s)</source>
|
<source>Discharge (m³/s)</source>
|
||||||
<translation type="obsolete">Débit (m³/s)</translation>
|
<translation type="obsolete">Débit (m³/s)</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message encoding="UTF-8">
|
||||||
|
<location filename="../View/Results/PlotH.py" line="79"/>
|
||||||
|
<source>Discharge (m³/s)</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SedimentLayers</name>
|
<name>SedimentLayers</name>
|
||||||
@@ -2303,42 +2342,42 @@ Seuls les 5 premiers seront édités.</source>
|
|||||||
<context>
|
<context>
|
||||||
<name>Toolbar</name>
|
<name>Toolbar</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Plot/navigation_toolbar_2qt.py" line="182"/>
|
<location filename="../View/Plot/PamhyrToolbar.py" line="181"/>
|
||||||
<source>Zoom</source>
|
<source>Zoom</source>
|
||||||
<translation>Zoom</translation>
|
<translation>Zoom</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Plot/navigation_toolbar_2qt.py" line="178"/>
|
<location filename="../View/Plot/PamhyrToolbar.py" line="177"/>
|
||||||
<source>Default view</source>
|
<source>Default view</source>
|
||||||
<translation>Vue par défaut</translation>
|
<translation>Vue par défaut</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Plot/navigation_toolbar_2qt.py" line="179"/>
|
<location filename="../View/Plot/PamhyrToolbar.py" line="178"/>
|
||||||
<source>Back to previous view</source>
|
<source>Back to previous view</source>
|
||||||
<translation>Retour a la vue précédente</translation>
|
<translation>Retour a la vue précédente</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Plot/navigation_toolbar_2qt.py" line="180"/>
|
<location filename="../View/Plot/PamhyrToolbar.py" line="179"/>
|
||||||
<source>Return to next view</source>
|
<source>Return to next view</source>
|
||||||
<translation>Retour à la vue suivante</translation>
|
<translation>Retour à la vue suivante</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Plot/navigation_toolbar_2qt.py" line="181"/>
|
<location filename="../View/Plot/PamhyrToolbar.py" line="180"/>
|
||||||
<source>Axes panoramic</source>
|
<source>Axes panoramic</source>
|
||||||
<translation>Axes panoramique</translation>
|
<translation>Axes panoramique</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Plot/navigation_toolbar_2qt.py" line="184"/>
|
<location filename="../View/Plot/PamhyrToolbar.py" line="183"/>
|
||||||
<source>Isometric view (Shift+W)</source>
|
<source>Isometric view (Shift+W)</source>
|
||||||
<translation>Vue isométrique (Shift+W)</translation>
|
<translation>Vue isométrique (Shift+W)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Plot/navigation_toolbar_2qt.py" line="185"/>
|
<location filename="../View/Plot/PamhyrToolbar.py" line="184"/>
|
||||||
<source>Auto scale view (Shift+X)</source>
|
<source>Auto scale view (Shift+X)</source>
|
||||||
<translation>Vue automatique (Shift+X)</translation>
|
<translation>Vue automatique (Shift+X)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Plot/navigation_toolbar_2qt.py" line="183"/>
|
<location filename="../View/Plot/PamhyrToolbar.py" line="182"/>
|
||||||
<source>Save the figure</source>
|
<source>Save the figure</source>
|
||||||
<translation>Sauvegarder la figure</translation>
|
<translation>Sauvegarder la figure</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|||||||
+47
-64
@@ -34,85 +34,68 @@ from tools import (
|
|||||||
from View.MainWindow import ApplicationWindow
|
from View.MainWindow import ApplicationWindow
|
||||||
from Model.Study import Study
|
from Model.Study import Study
|
||||||
|
|
||||||
logging.basicConfig(
|
from Scripts.Hello import ScriptHello
|
||||||
level=logging.DEBUG,
|
|
||||||
format=(f'[{logger_color_blue()}PAMHYR{logger_color_reset()}]' +
|
from init import license, setup_lang
|
||||||
f'[{logger_color_green()}%(levelname)s{logger_color_reset()}]' +
|
|
||||||
' %(message)s')
|
|
||||||
)
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
logger.setLevel(logging.INFO)
|
|
||||||
|
|
||||||
try:
|
scripts = {
|
||||||
log = os.path.join(
|
"hello": ScriptHello,
|
||||||
os.path.dirname(Config.filename()), "log.txt"
|
}
|
||||||
)
|
|
||||||
logfile = open(log, "w+")
|
|
||||||
handler = logging.StreamHandler(logfile)
|
|
||||||
formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s')
|
|
||||||
handler.setFormatter(formatter)
|
|
||||||
handler.setLevel(logging.DEBUG)
|
|
||||||
logger.addHandler(handler)
|
|
||||||
except:
|
|
||||||
logger.error("Failed to create logfile...")
|
|
||||||
|
|
||||||
def license():
|
def usage(argv):
|
||||||
blue = lambda s: logger.info(f"{logger_color_blue()}{s}{logger_color_reset()}")
|
logger.info("")
|
||||||
|
logger.info(f"Usage: {argv[0]} <script> <args...>")
|
||||||
|
logger.info("")
|
||||||
|
logger.info(f"Available scripts:")
|
||||||
|
logger.info(f"\thelp\t\tDisplay this message")
|
||||||
|
logger.info(f"\tgui\t\tRun Pamhyr graphics user interface (by default)")
|
||||||
|
logger.info(f"\tdebug\t\tRun Pamhyr graphics user interface as debug mode (for developers)")
|
||||||
|
for s in scripts:
|
||||||
|
logger.info(f"\t{s}\t\t{scripts[s].description}")
|
||||||
|
logger.info("")
|
||||||
|
|
||||||
blue("""`7MM\"""Mq. db `7MMM. ,MMF'`7MMF' `7MMF'`YMM' `MM'`7MM\"""Mq.""")
|
def gui(app:QApplication, conf:Config):
|
||||||
blue(""" MM `MM. ;MM: MMMb dPMM MM MM VMA ,V MM `MM.""")
|
application = ApplicationWindow(conf=conf)
|
||||||
blue(""" MM ,M9 ,V^MM. M YM ,M MM MM MM VMA ,V MM ,M9 pd*"*b.""")
|
application.show()
|
||||||
blue(""" MMmmdM9 ,M `MM M Mb M' MM MMmmmmmmMM VMMP MMmmdM9 (O) j8""")
|
|
||||||
blue(""" MM AbmmmqMA M YM.P' MM MM MM MM MM YM. ,;j9""")
|
|
||||||
blue(""" MM A' VML M `YM' MM MM MM MM MM `Mb. ,-='""")
|
|
||||||
blue(""".JMML. .AMA. .AMMA..JML. `' .JMML..JMML. .JMML. .JMML. .JMML. .JMM. Ammmmmmm""")
|
|
||||||
|
|
||||||
with open(os.path.abspath(
|
return app.exec_()
|
||||||
os.path.join(
|
|
||||||
os.path.dirname(__file__),
|
|
||||||
"VERSION"
|
|
||||||
)
|
|
||||||
), "r") as f:
|
|
||||||
version = f.readline().strip()
|
|
||||||
logger.info(f"version: {logger_color_green()}{version}{logger_color_reset()}")
|
|
||||||
|
|
||||||
logger.info("license: pamhyr Copyright (C) 2023 INRAE")
|
|
||||||
logger.info("license: This program comes with ABSOLUTELY NO WARRANTY.")
|
|
||||||
logger.info("license: This is free software, and you are welcome to redistribute it")
|
|
||||||
logger.info("license: under certain conditions.")
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
conf = Config.load()
|
conf = Config.load()
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
|
|
||||||
translator = QTranslator()
|
tr = setup_lang(app, conf)
|
||||||
|
app.installTranslator(tr)
|
||||||
|
|
||||||
license()
|
license()
|
||||||
|
|
||||||
lang_file = ""
|
if len(sys.argv) > 1:
|
||||||
if conf.lang == "":
|
# Run a script
|
||||||
# System language
|
script = sys.argv[1]
|
||||||
sys_lang = locale.getdefaultlocale()
|
|
||||||
if "fr" in sys_lang[0]:
|
if script == "help":
|
||||||
lang_file = os.path.dirname(__file__) + "/lang/fr.qm"
|
ret = usage(sys.argv)
|
||||||
elif conf.lang == "fr":
|
elif script == "gui":
|
||||||
# French
|
ret = gui(app, conf)
|
||||||
lang_file = os.path.dirname(__file__) + "/lang/fr.qm"
|
elif script == "debug":
|
||||||
|
conf.debug = True
|
||||||
|
ret = gui(app, conf)
|
||||||
|
else:
|
||||||
|
if script not in scripts:
|
||||||
|
logger.error(f"{logger_color_red()}Invalid script name '{sys.argv[1]}'{logger_color_reset()}")
|
||||||
|
usage(sys.argv)
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
application = scripts[script](app, conf, sys.argv)
|
||||||
|
ret = application.run()
|
||||||
|
if ret != 0:
|
||||||
|
application.usage()
|
||||||
else:
|
else:
|
||||||
# English default language
|
# No args, run Pamhyr2 interface
|
||||||
lang_file = ""
|
ret = gui(app, conf)
|
||||||
|
|
||||||
if lang_file != "":
|
|
||||||
ok = translator.load(lang_file)
|
|
||||||
if not ok:
|
|
||||||
logger.error("Failed to load translate file")
|
|
||||||
|
|
||||||
app.installTranslator(translator)
|
|
||||||
|
|
||||||
application = ApplicationWindow(conf=conf)
|
|
||||||
application.show()
|
|
||||||
|
|
||||||
ret = app.exec_()
|
|
||||||
display_timers()
|
display_timers()
|
||||||
sys.exit(ret)
|
sys.exit(ret)
|
||||||
|
|
||||||
|
|||||||
@@ -247,6 +247,7 @@ class SQL(object):
|
|||||||
self._init_db_file(filename)
|
self._init_db_file(filename)
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
|
logger.debug("SQL - commit")
|
||||||
self._db.commit()
|
self._db.commit()
|
||||||
|
|
||||||
def _fetch_string(self, s):
|
def _fetch_string(self, s):
|
||||||
|
|||||||
Reference in new issue
Block a user