diff --git a/src/Model/Geometry/Profile.py b/src/Model/Geometry/Profile.py
index b0328f80..7836c47f 100644
--- a/src/Model/Geometry/Profile.py
+++ b/src/Model/Geometry/Profile.py
@@ -34,6 +34,7 @@ class Profile(object):
self._kp = float(kp)
self._name = str(name)
self._reach = reach
+ self._sl = None
self._points: List[Point] = []
@@ -120,6 +121,19 @@ class Profile(object):
self._name = value.strip()
self._status.modified()
+ @property
+ def sl(self):
+ """
+ Returns:
+ Profile sediment layers.
+ """
+ return self._sl
+
+ @sl.setter
+ def sl(self, value: str):
+ self._sl = value
+ self._status.modified()
+
@property
def profile_type(self):
"""
diff --git a/src/Model/SedimentLayer/SedimentLayer.py b/src/Model/SedimentLayer/SedimentLayer.py
index 7f8f1fa4..8099aab0 100644
--- a/src/Model/SedimentLayer/SedimentLayer.py
+++ b/src/Model/SedimentLayer/SedimentLayer.py
@@ -108,7 +108,7 @@ class Layer(SQLSubModel):
"sedimentary_layer_layer(id, ind, name, type, height, sl) "+
"VALUES (" +
f"{self.id}, {ind}, '{self._sql_format(self._name)}', " +
- f"'{self._sql_format(self._type)}', '{self._height}', {sl}" +
+ f"'{self._sql_format(self._type)}', '{self._height}', {sl.id}" +
")"
)
execute(sql)
@@ -135,6 +135,9 @@ class SedimentLayer(SQLSubModel):
else:
self.id = id
+ def __str__(self):
+ return f"{self.name} ({len(self)}) - {self.comment}"
+
def __len__(self):
return len(self._layers)
diff --git a/src/Model/SedimentLayer/SedimentLayerList.py b/src/Model/SedimentLayer/SedimentLayerList.py
index 32317c0b..d2b66226 100644
--- a/src/Model/SedimentLayer/SedimentLayerList.py
+++ b/src/Model/SedimentLayer/SedimentLayerList.py
@@ -46,6 +46,10 @@ class SedimentLayerList(SQLSubModel):
return ok
+ @property
+ def sediment_layers(self):
+ return self._sl.copy()
+
def get(self, index):
return self._sl[index]
diff --git a/src/View/MainWindow.py b/src/View/MainWindow.py
index 79c7ef67..2c9b1b65 100644
--- a/src/View/MainWindow.py
+++ b/src/View/MainWindow.py
@@ -34,6 +34,7 @@ from View.InitialConditions.Window import InitialConditionsWindow
from View.Stricklers.Window import StricklersWindow
from View.Frictions.Window import FrictionsWindow
from View.SedimentLayers.Window import SedimentLayersWindow
+from View.SedimentLayers.Reach.Window import ReachSedimentLayersWindow
from View.SolverParameters.Window import SolverParametersWindow
from View.RunSolver.Window import SelectSolverWindow, SolverLogWindow
from View.CheckList.Window import CheckListWindow
@@ -149,7 +150,8 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
"action_menu_edit_friction": self.open_frictions,
"action_menu_edit_lateral_contribution": self.open_lateral_contrib,
"action_menu_run_solver": self.run_solver,
- "action_menu_sediment_layers": self.open_sediment_layer,
+ "action_menu_sediment_layers": self.open_sediment_layers,
+ "action_menu_edit_reach_sediment_layers": self.open_reach_sediment_layers,
## Help
"action_menu_about": self.open_about,
# ToolBar action
@@ -493,13 +495,20 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
)
params.show()
- def open_sediment_layer(self):
+ def open_sediment_layers(self):
sl = SedimentLayersWindow(
study = self.model,
parent = self
)
sl.show()
+ def open_reach_sediment_layers(self):
+ sl = ReachSedimentLayersWindow(
+ study = self.model,
+ parent = self
+ )
+ sl.show()
+
def run_solver(self):
if self.model is None:
return
diff --git a/src/View/SedimentLayers/Reach/Table.py b/src/View/SedimentLayers/Reach/Table.py
index e69de29b..d9cac095 100644
--- a/src/View/SedimentLayers/Reach/Table.py
+++ b/src/View/SedimentLayers/Reach/Table.py
@@ -0,0 +1,151 @@
+# -*- coding: utf-8 -*-
+
+import logging
+
+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.SedimentLayers.Reach.UndoCommand import *
+from View.SedimentLayers.Reach.translate import *
+
+_translate = QCoreApplication.translate
+
+logger = logging.getLogger()
+
+class ComboBoxDelegate(QItemDelegate):
+ def __init__(self, study=None, parent=None):
+ super(ComboBoxDelegate, self).__init__(parent)
+
+ self._study = study
+
+ def createEditor(self, parent, option, index):
+ self.editor = QComboBox(parent)
+
+ self.editor.addItems(
+ [_translate("SedimentLayers", "Not defined")] +
+ list(
+ map(
+ lambda sl: str(sl),
+ self._study.river.sediment_layers.sediment_layers
+ )
+ )
+ )
+
+ self.editor.setCurrentText(index.data(Qt.DisplayRole))
+ return self.editor
+
+ def setEditorData(self, editor, index):
+ value = index.data(Qt.DisplayRole)
+ self.editor.currentTextChanged.connect(self.currentItemChanged)
+
+ def setModelData(self, editor, model, index):
+ text = str(editor.currentText())
+ model.setData(index, text)
+ 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, study=None, reach=None, undo=None):
+ super(QAbstractTableModel, self).__init__()
+ self._headers = list(table_headers.keys())
+ self._study = study
+ self._undo = undo
+ self._reach = reach
+
+ def flags(self, index):
+ column = index.column()
+
+ options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
+ if self._headers[column] == "sl":
+ options |= Qt.ItemIsEditable
+
+ return options
+
+ def rowCount(self, parent):
+ return self._reach.number_profiles
+
+ 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._reach.profile(row).name
+ if self._headers[column] == "kp":
+ return self._reach.profile(row).kp
+ if self._headers[column] == "sl":
+ value = self._reach.profile(row).sl
+ if value == None:
+ text = _translate("SedimentLayers", "Not defined")
+ return text
+ return str(value)
+
+ return QVariant()
+
+ def headerData(self, friction, orientation, role):
+ if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
+ return table_headers[self._headers[friction]]
+
+ 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] == "sl":
+ new = None
+ if value != _translate("SedimentLayers", "Not defined"):
+ new = next(
+ filter(
+ lambda sl: str(sl) == value,
+ self._study.river.sediment_layers.sediment_layers
+ )
+ )
+
+ self._undo.push(
+ SetSLCommand(
+ self._reach, row, new
+ )
+ )
+
+ self.dataChanged.emit(index, index)
+ return True
+
+ def undo(self):
+ self._undo.undo()
+ self.layoutChanged.emit()
+
+ def redo(self):
+ self._undo.redo()
+ self.layoutChanged.emit()
diff --git a/src/View/SedimentLayers/Reach/UndoCommand.py b/src/View/SedimentLayers/Reach/UndoCommand.py
index e69de29b..82ba3764 100644
--- a/src/View/SedimentLayers/Reach/UndoCommand.py
+++ b/src/View/SedimentLayers/Reach/UndoCommand.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+
+import logging
+
+from copy import deepcopy
+from tools import trace, timer
+
+from PyQt5.QtWidgets import (
+ QMessageBox, QUndoCommand, QUndoStack,
+)
+
+from Model.Geometry.Reach import Reach
+from Model.Geometry.Profile import Profile
+from Model.SedimentLayer.SedimentLayer import SedimentLayer
+from Model.SedimentLayer.SedimentLayerList import SedimentLayerList
+
+logger = logging.getLogger()
+
+class SetSLCommand(QUndoCommand):
+ def __init__(self, reach, index, new_value):
+ QUndoCommand.__init__(self)
+
+ self._reach = reach
+ self._index = index
+ self._old = self._reach.profile(self._index).sl
+ self._new = new_value
+
+ def undo(self):
+ self._reach.profile(self._index).sl = self._old
+
+ def redo(self):
+ self._reach.profile(self._index).sl = self._new
diff --git a/src/View/SedimentLayers/Reach/Window.py b/src/View/SedimentLayers/Reach/Window.py
index e69de29b..b292db5d 100644
--- a/src/View/SedimentLayers/Reach/Window.py
+++ b/src/View/SedimentLayers/Reach/Window.py
@@ -0,0 +1,150 @@
+# -*- coding: utf-8 -*-
+
+import logging
+
+from tools import trace, timer
+
+from View.ASubWindow import ASubMainWindow
+from View.ListedSubWindow import ListedSubWindow
+
+from PyQt5.QtGui import (
+ QKeySequence,
+)
+
+from PyQt5.QtCore import (
+ Qt, QVariant, QAbstractTableModel,
+ QCoreApplication, QModelIndex, pyqtSlot,
+ QRect,
+)
+
+from PyQt5.QtWidgets import (
+ QDialogButtonBox, QPushButton, QLineEdit,
+ QFileDialog, QTableView, QAbstractItemView,
+ QUndoStack, QShortcut, QAction, QItemDelegate,
+ QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
+)
+
+from View.SedimentLayers.Reach.UndoCommand import *
+from View.SedimentLayers.Reach.Table import *
+
+from View.Plot.MplCanvas import MplCanvas
+from View.SedimentLayers.Reach.translate import *
+
+from View.SedimentLayers.Window import SedimentLayersWindow
+
+_translate = QCoreApplication.translate
+
+logger = logging.getLogger()
+
+class ReachSedimentLayersWindow(ASubMainWindow, ListedSubWindow):
+ def __init__(self, title="Reach sediment layers", study=None, parent=None):
+ self._study = study
+ self._sediment_layers = self._study.river.sediment_layers
+ self._reach = self._study.river.current_reach().reach
+
+ self.setup_title(title)
+
+ super(ReachSedimentLayersWindow, self).__init__(
+ name=self._title, ui="ReachSedimentLayers", parent=parent
+ )
+
+ self.setup_sc()
+ self.setup_table()
+ self.setup_graph()
+ self.setup_connections()
+
+ self.ui.setWindowTitle(self._title)
+
+ def setup_title(self, title):
+ self._title = (
+ title + " - " + self._study.name + " - " + self._reach.name
+ )
+
+ 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):
+ table = self.find(QTableView, f"tableView")
+ self._table = TableModel(
+ study = self._study,
+ reach = self._reach,
+ undo = self._undo_stack,
+ )
+ table.setModel(self._table)
+
+ self._delegate_stricklers = ComboBoxDelegate(
+ study = self._study,
+ parent=self
+ )
+
+ table.setItemDelegateForColumn(
+ list(table_headers).index("sl"),
+ self._delegate_stricklers
+ )
+
+ table.setSelectionBehavior(QAbstractItemView.SelectRows)
+ table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
+ table.setAlternatingRowColors(True)
+
+ def setup_graph(self):
+ self.canvas = MplCanvas(width=5, height=4, dpi=100)
+ self.canvas.setObjectName("canvas")
+ self.plot_layout = self.find(QVBoxLayout, "verticalLayout_2")
+ self.plot_layout.addWidget(self.canvas)
+
+ # self.plot = PlotKPC(
+ # canvas = self.canvas,
+ # data = self._reach.reach,
+ # toolbar = None,
+ # display_current = False
+ # )
+ # self.plot.draw()
+
+
+ def setup_connections(self):
+ self.find(QAction, "action_edit").triggered.connect(self.edit_profile)
+
+ 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")
+ return list(
+ # Delete duplicate
+ set(
+ map(
+ lambda i: i.row(),
+ table.selectedIndexes()
+ )
+ )
+ )
+
+ def copy(self):
+ logger.info("TODO: copy")
+
+ def paste(self):
+ logger.info("TODO: paste")
+
+ def undo(self):
+ self._table.undo()
+
+ def redo(self):
+ self._table.redo()
+
+ def edit_profile(self):
+ rows = self.index_selected_rows()
+
+ for row in rows:
+ slw = ProfileSedimentLayersWindow(
+ study = self._study,
+ sl = self._sediment_layers.get(row),
+ parent = self
+ )
+ slw.show()
diff --git a/src/View/SedimentLayers/Reach/translate.py b/src/View/SedimentLayers/Reach/translate.py
index e69de29b..f6b17cf8 100644
--- a/src/View/SedimentLayers/Reach/translate.py
+++ b/src/View/SedimentLayers/Reach/translate.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+
+from PyQt5.QtCore import QCoreApplication
+
+_translate = QCoreApplication.translate
+
+table_headers = {
+ "name": _translate("SedimentLayers", "Name"),
+ "kp": _translate("SedimentLayers", "KP (m)"),
+ "sl": _translate("SedimentLayers", "Sediment layers"),
+}
diff --git a/src/View/SedimentLayers/Window.py b/src/View/SedimentLayers/Window.py
index b2e8f1fa..b04c073d 100644
--- a/src/View/SedimentLayers/Window.py
+++ b/src/View/SedimentLayers/Window.py
@@ -68,8 +68,6 @@ class SedimentLayersWindow(ASubMainWindow, ListedSubWindow):
self.paste_sc = QShortcut(QKeySequence.Paste, self)
def setup_table(self):
- self._table = {}
-
table = self.find(QTableView, f"tableView")
self._table = TableModel(
study = self._study,
diff --git a/src/View/ui/ReachSedimentLayers.ui b/src/View/ui/ReachSedimentLayers.ui
index b37db0c4..a1beb8ca 100644
--- a/src/View/ui/ReachSedimentLayers.ui
+++ b/src/View/ui/ReachSedimentLayers.ui
@@ -69,9 +69,9 @@
false
-
+
-
+
ressources/edit.pngressources/edit.png
@@ -83,15 +83,6 @@
Edit profile sediment layer
-
-
-
- ressources/gtk-add.pngressources/gtk-add.png
-
-
- Add sediment layer
-
-