Stricklers: Add base of code.

mesh
Pierre-Antoine Rouby 2023-05-16 16:24:49 +02:00
parent 1179dd0b92
commit 113fafac50
11 changed files with 669 additions and 12 deletions

View File

@ -202,10 +202,10 @@ class Reach:
return [profile.kp for profile in self.profiles] return [profile.kp for profile in self.profiles]
def get_kp_min(self): def get_kp_min(self):
return min([profile.kp for profile in self.profiles]) return min(self.get_kp())
def get_kp_max(self): def get_kp_max(self):
return max([profile.kp for profile in self.profiles]) return max(self.get_kp())
# Guidelines # Guidelines
@ -237,7 +237,7 @@ class Reach:
@timer @timer
def compute_guidelines(self): def compute_guidelines(self):
"""Compute reach guideline and check if is valid for all profiles """Compute reach guidelines
Returns: Returns:
Tuple of complete and incomplete guidelines name. Tuple of complete and incomplete guidelines name.

View File

@ -9,7 +9,7 @@ from Model.Geometry.Reach import Reach
from Model.BoundaryCondition.BoundaryConditionList import BoundaryConditionList from Model.BoundaryCondition.BoundaryConditionList import BoundaryConditionList
from Model.LateralContribution.LateralContributionList import LateralContributionList from Model.LateralContribution.LateralContributionList import LateralContributionList
from Model.Stricklers.StricklersList import StricklersList
class RiverNode(Node): class RiverNode(Node):
def __init__(self, id:str, name:str, def __init__(self, id:str, name:str,
@ -61,6 +61,7 @@ class River(Graph):
self._current_reach = None self._current_reach = None
self._boundary_condition = BoundaryConditionList(status=self._status) self._boundary_condition = BoundaryConditionList(status=self._status)
self._lateral_contribution = LateralContributionList(status=self._status) self._lateral_contribution = LateralContributionList(status=self._status)
self._stricklers = StricklersList(status=self._status)
@property @property
def boundary_condition(self): def boundary_condition(self):
@ -70,6 +71,10 @@ class River(Graph):
def lateral_contribution(self): def lateral_contribution(self):
return self._lateral_contribution return self._lateral_contribution
@property
def striklers(self):
return self._stricklers
def has_current_reach(self): def has_current_reach(self):
return self._current_reach is not None return self._current_reach is not None

View File

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
from tools import trace, timer
class Stricklers(object):
def __init__(self, status = None):
super(Stricklers, self).__init__()
self._status = status
self._name = ""
self._comment = ""
self._minor = 35
self._medium = 15
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
@property
def comment(self):
return self._comment
@comment.setter
def comment(self, comment):
self._comment = comment
@property
def minor(self):
return self._minor
@minor.setter
def minor(self, minor):
self._minor = int(minor)
@property
def medium(self):
return self._medium
@medium.setter
def medium(self, medium):
self._medium = int(medium)

View File

@ -0,0 +1,62 @@
# -*- coding: utf-8 -*-
from tools import trace, timer
from Model.Stricklers.Stricklers import Stricklers
class StricklersList(object):
def __init__(self, status = None):
self._status = status
self._stricks = []
def __len__(self):
return len(self._stricks)
@property
def stricks(self):
return self._stricks.copy()
def get(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)
self.insert(index, 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)
def sort(self, reverse:bool = False):
self._strick = sorted(
self._strick,
key = lambda st: st.name,
reverse = reverse,
)
self._status.modified()

View File

@ -50,9 +50,7 @@ class ComboBoxDelegate(QItemDelegate):
) )
) )
) )
self.editor.addItems( self.editor.addItems(lst)
lst
)
else: else:
self.editor.addItems( self.editor.addItems(
[_translate("LateralContribution", "Not associate")] + [_translate("LateralContribution", "Not associate")] +
@ -182,7 +180,7 @@ class TableModel(QAbstractTableModel):
self._undo.push( self._undo.push(
AddCommand( AddCommand(
self._lcs, self._tab,row self._lcs, self._tab, row
) )
) )
@ -194,7 +192,7 @@ class TableModel(QAbstractTableModel):
self._undo.push( self._undo.push(
DelCommand( DelCommand(
self._lcs, self._tab,rows self._lcs, self._tab, rows
) )
) )
@ -206,7 +204,7 @@ class TableModel(QAbstractTableModel):
self._undo.push( self._undo.push(
SortCommand( SortCommand(
self._lcs, self._tab,False self._lcs, self._tab, False
) )
) )

View File

@ -24,6 +24,7 @@ from View.Network.Window import NetworkWindow
from View.Geometry.Window import GeometryWindow from View.Geometry.Window import GeometryWindow
from View.BoundaryCondition.Window import BoundaryConditionWindow from View.BoundaryCondition.Window import BoundaryConditionWindow
from View.LateralContribution.Window import LateralContributionWindow from View.LateralContribution.Window import LateralContributionWindow
from View.Stricklers.Window import StricklersWindow
from Model.Study import Study from Model.Study import Study
@ -125,8 +126,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
"action_toolBar_boundary_cond": self.open_boundary_cond, "action_toolBar_boundary_cond": self.open_boundary_cond,
"action_toolBar_lateral_contrib": self.open_lateral_contrib, "action_toolBar_lateral_contrib": self.open_lateral_contrib,
"action_toolBar_spills": lambda: self.open_dummy("Deversement"), "action_toolBar_spills": lambda: self.open_dummy("Deversement"),
"action_toolBar_sections": lambda: self.open_dummy("Tronçons"), "action_toolBar_frictions": self.open_stricklers,
"action_toolBar_frictions": lambda: self.open_dummy("Frottements"),
"action_toolBar_building": lambda: self.open_dummy("Ouvrages"), "action_toolBar_building": lambda: self.open_dummy("Ouvrages"),
} }
@ -333,6 +333,10 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
self.lateral = LateralContributionWindow(study = self.model, parent=self) self.lateral = LateralContributionWindow(study = self.model, parent=self)
self.lateral.show() self.lateral.show()
def open_stricklers(self):
self.strick = StricklersWindow(study = self.model, parent=self)
self.strick.show()
# TODO: Delete me ! # TODO: Delete me !
############### ###############
# DUMMY STUFF # # DUMMY STUFF #

View File

@ -0,0 +1,149 @@
# -*- coding: utf-8 -*-
from tools import trace, timer
from PyQt5.QtCore import (
Qt, QVariant, QAbstractTableModel,
QCoreApplication, QModelIndex, pyqtSlot,
QRect,
)
from PyQt5.QtWidgets import (
QDialogButtonBox, QPushButton, QLineEdit,
QFileDialog, QTableView, QAbstractItemView,
QUndoStack, QShortcut, QAction, QItemDelegate,
QComboBox,
)
from View.Stricklers.UndoCommand import (
SetNameCommand, SetCommentCommand,
SetMinorCommand, SetMediumCommand,
AddCommand, DelCommand, SortCommand,
)
from View.Stricklers.translate import *
_translate = QCoreApplication.translate
class TableModel(QAbstractTableModel):
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):
if role != Qt.ItemDataRole.DisplayRole:
return QVariant()
row = index.row()
column = index.column()
if self._headers[column] == "name":
return self._data.get(row).name
elif self._headers[column] == "comment":
return self._data.get(row).comment
elif self._headers[column] == "minor":
return self._data.get(row).minor
elif self._headers[column] == "medium":
return self._data.get(row).medium
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):
if not index.isValid() or role != Qt.EditRole:
return False
row = index.row()
column = index.column()
if self._headers[column] == "name":
self._undo.push(
SetNameCommand(
self._data, row, value
)
)
elif self._headers[column] == "comment":
self._undo.push(
SetCommentCommand(
self._data, row, value
)
)
elif self._headers[column] == "minor":
self._undo.push(
SetMinorCommand(
self._data, row, value
)
)
elif self._headers[column] == "medium":
self._undo.push(
SetMediumCommand(
self._data, row, value
)
)
self.dataChanged.emit(index, index)
return True
def add(self, row, parent=QModelIndex()):
self.beginInsertRows(parent, row, row - 1)
self._undo.push(
AddCommand(
self._data, row
)
)
self.endInsertRows()
self.layoutChanged.emit()
def delete(self, rows, parent=QModelIndex()):
self.beginRemoveRows(parent, rows[0], rows[-1])
self._undo.push(
DelCommand(
self._data, rows
)
)
self.endRemoveRows()
self.layoutChanged.emit()
def sort(self, _reverse, parent=QModelIndex()):
self.layoutAboutToBeChanged.emit()
self._undo.push(
SortCommand(
self._data, False
)
)
self.layoutAboutToBeChanged.emit()
self.layoutChanged.emit()
def undo(self):
self._undo.undo()
self.layoutChanged.emit()
def redo(self):
self._undo.redo()
self.layoutChanged.emit()

View File

@ -0,0 +1,156 @@
# -*- coding: utf-8 -*-
from copy import deepcopy
from tools import trace, timer
from PyQt5.QtWidgets import (
QMessageBox, QUndoCommand, QUndoStack,
)
from Model.LateralContribution.LateralContribution import LateralContribution
from Model.LateralContribution.LateralContributionList import LateralContributionList
class SetNameCommand(QUndoCommand):
def __init__(self, data, index, new_value):
QUndoCommand.__init__(self)
self._data = data
self._index = index
self._old = self._data.get(self._index).name
self._new = new_value
def undo(self):
self._data.get(self._index).name = self._old
def redo(self):
self._data.get(self._index).name = self._new
class SetCommentCommand(QUndoCommand):
def __init__(self, data, index, new_value):
QUndoCommand.__init__(self)
self._data = data
self._index = index
self._old = self._data.get(self._index).comment
self._new = new_value
def undo(self):
self._data.get(self._index).comment = self._old
def redo(self):
self._data.get(self._index).comment = self._new
class SetMinorCommand(QUndoCommand):
def __init__(self, data, index, new_value):
QUndoCommand.__init__(self)
self._data = data
self._index = index
self._old = self._data.get(self._index).minor
self._new = new_value
def undo(self):
self._data.get(self._index).minor = self._old
def redo(self):
self._data.get(self._index).minor = self._new
class SetMediumCommand(QUndoCommand):
def __init__(self, data, index, new_value):
QUndoCommand.__init__(self)
self._data = data
self._index = index
self._old = self._data.get(self._index).medium
self._new = new_value
def undo(self):
self._data.get(self._index).medium = self._old
def redo(self):
self._data.get(self._index).medium = self._new
class AddCommand(QUndoCommand):
def __init__(self, data, index):
QUndoCommand.__init__(self)
self._data = data
self._index = index
self._new = None
def undo(self):
self._data.delete_i([self._index])
def redo(self):
if self._new is None:
self._new = self._data.add(self._index)
else:
self._data.insert(self._index, self._new)
class DelCommand(QUndoCommand):
def __init__(self, data, rows):
QUndoCommand.__init__(self)
self._data = data
self._rows = rows
self._el = []
for row in rows:
self._el.append((row, self._data.get(row)))
self._el.sort()
def undo(self):
for row, el in self._el:
self._data.insert(row, el)
def redo(self):
self._data.delete_i(self._rows)
class SortCommand(QUndoCommand):
def __init__(self, data, _reverse):
QUndoCommand.__init__(self)
self._data = data
self._reverse = _reverse
self._old = self._data.get_tab(self._tab)
self._indexes = None
def undo(self):
ll = self._data.get_tab(self._tab)
self._data.sort(
self._tab,
key=lambda x: self._indexes[ll.index(x)]
)
def redo(self):
self._data.sort(
self._tab,
reverse=self._reverse,
key=lambda x: x.name
)
if self._indexes is None:
self._indexes = list(
map(
lambda p: self._old.index(p),
self._data.get_tab(self._tab)
)
)
self._old = None
class PasteCommand(QUndoCommand):
def __init__(self, data, row, el):
QUndoCommand.__init__(self)
self._data = data
self._row = row
self._el = deepcopy(el)
self._el.reverse()
def undo(self):
self._data.delete(self._el)
def redo(self):
for el in self._el:
self._data.insert(self._row, el)

View File

@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
from tools import trace, timer
from View.ASubWindow import ASubMainWindow
from View.ListedSubWindow import ListedSubWindow
from PyQt5.QtGui import (
QKeySequence,
)
from PyQt5.QtCore import (
Qt, QVariant, QAbstractTableModel,
QCoreApplication, QModelIndex, pyqtSlot,
QRect,
)
from PyQt5.QtWidgets import (
QDialogButtonBox, QPushButton, QLineEdit,
QFileDialog, QTableView, QAbstractItemView,
QUndoStack, QShortcut, QAction, QItemDelegate,
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
)
from Model.Stricklers.Stricklers import Stricklers
from View.Stricklers.UndoCommand import PasteCommand
from View.Stricklers.Table import TableModel
_translate = QCoreApplication.translate
class StricklersWindow(ASubMainWindow, ListedSubWindow):
def __init__(self, title="Stricklers", study=None, parent=None):
title = title + " - " + study.name
super(StricklersWindow, self).__init__(
name=title, ui="Stricklers", parent=parent
)
self._study = study
self.setup_sc()
self.setup_table()
self.setup_connections()
self.ui.setWindowTitle(title)
def setup_sc(self):
self._undo_stack = QUndoStack()
self.undo_sc = QShortcut(QKeySequence.Undo, self)
self.redo_sc = QShortcut(QKeySequence.Redo, self)
self.copy_sc = QShortcut(QKeySequence.Copy, self)
self.paste_sc = QShortcut(QKeySequence.Paste, self)
def setup_table(self):
self._table = {}
for t in ["app", "study"]:
table = self.find(QTableView, f"tableView_{t}")
self._table[t] = TableModel(
data = self._study.river.striklers,
undo = self._undo_stack,
)
table.setModel(self._table[t])
table.setSelectionBehavior(QAbstractItemView.SelectRows)
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
table.setAlternatingRowColors(True)
def setup_connections(self):
self.find(QAction, "action_add").triggered.connect(self.add)
self.find(QAction, "action_del").triggered.connect(self.delete)
self.find(QAction, "action_sort").triggered.connect(self.sort)
self.undo_sc.activated.connect(self.undo)
self.redo_sc.activated.connect(self.redo)
self.copy_sc.activated.connect(self.copy)
self.paste_sc.activated.connect(self.paste)
def index_selected_rows(self):
table = self.find(QTableView, f"tableView_study")
return list(
set(
map(
lambda i: i.row(),
table.selectedIndexes()
)
)
)
def add(self):
rows = self.index_selected_rows()
if len(rows) == 0:
self._table['study'].add(0)
else:
self._table['study'].add(rows[0])
def delete(self):
rows = self.index_selected_rows()
if len(rows) == 0:
return
self._table['study'].delete(rows)
def sort(self):
self._table['study'].sort()
def copy(self):
print("TODO")
def paste(self):
print("TODO")
def undo(self):
self._table['study'].undo()
def redo(self):
self._table['study'].redo()

View File

@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
from Model.LateralContribution.LateralContributionTypes import (
NotDefined, LateralContrib, Rain, Evaporation,
)
_translate = QCoreApplication.translate
table_headers = {
"name": _translate("LateralContribution", "Name"),
"minor": _translate("LateralContribution", "Minor bed"),
"medium": _translate("LateralContribution", "Medium bed"),
"comment": _translate("LateralContribution", "Comment"),
}

100
src/View/ui/Stricklers.ui Normal file
View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>820</width>
<height>480</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Study stricklers</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTableView" name="tableView_study"/>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Application stricklers</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QTableView" name="tableView_app"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="action_add"/>
<addaction name="action_del"/>
<addaction name="action_sort"/>
</widget>
<action name="action_add">
<property name="icon">
<iconset>
<normaloff>ressources/gtk-add.png</normaloff>ressources/gtk-add.png</iconset>
</property>
<property name="text">
<string>Add</string>
</property>
<property name="toolTip">
<string>Add new stricklers</string>
</property>
</action>
<action name="action_del">
<property name="icon">
<iconset>
<normaloff>ressources/gtk-remove.png</normaloff>ressources/gtk-remove.png</iconset>
</property>
<property name="text">
<string>Delete</string>
</property>
<property name="toolTip">
<string>Delete selected stricklers</string>
</property>
</action>
<action name="action_sort">
<property name="icon">
<iconset>
<normaloff>ressources/gtk-sort-ascending.png</normaloff>ressources/gtk-sort-ascending.png</iconset>
</property>
<property name="text">
<string>Sort</string>
</property>
<property name="toolTip">
<string>Sort stricklers</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>