From 92712dd172f779b8dc25e11dbe82d75c4dea7c97 Mon Sep 17 00:00:00 2001
From: Pierre-Antoine Rouby <pierre-antoine.rouby@inrae.fr>
Date: Wed, 19 Jul 2023 15:11:53 +0200
Subject: [PATCH] SL: Add sediment layer Model and UI files schemes.

---
 src/Model/River.py                            |   7 +
 src/View/MainWindow.py                        |  12 +-
 src/View/SedimentLayers/Edit/Table.py         |   0
 src/View/SedimentLayers/Edit/UndoCommand.py   |   0
 src/View/SedimentLayers/Edit/Window.py        |   0
 src/View/SedimentLayers/Edit/translate.py     |   0
 .../SedimentLayers/Reach/Profile/Table.py     |   0
 .../Reach/Profile/UndoCommand.py              |   0
 .../SedimentLayers/Reach/Profile/Window.py    |   0
 .../SedimentLayers/Reach/Profile/translate.py |   0
 src/View/SedimentLayers/Reach/Table.py        |   0
 src/View/SedimentLayers/Reach/UndoCommand.py  |   0
 src/View/SedimentLayers/Reach/Window.py       |   0
 src/View/SedimentLayers/Reach/translate.py    |   0
 src/View/SedimentLayers/Table.py              | 151 +++++++++++++++++
 src/View/SedimentLayers/UndoCommand.py        |  97 +++++++++++
 src/View/SedimentLayers/Window.py             | 156 ++++++++++++++++++
 src/View/SedimentLayers/translate.py          |  10 ++
 src/View/ui/EditSedimentLayers.ui             | 114 +++++++++++++
 src/View/ui/MainWindow.ui                     |  18 ++
 src/View/ui/ProfileSedimentLayers.ui          |  95 +++++++++++
 src/View/ui/ReachSedimentLayers.ui            |  98 +++++++++++
 src/View/ui/SedimentLayersList.ui             |  95 +++++++++++
 23 files changed, 852 insertions(+), 1 deletion(-)
 create mode 100644 src/View/SedimentLayers/Edit/Table.py
 create mode 100644 src/View/SedimentLayers/Edit/UndoCommand.py
 create mode 100644 src/View/SedimentLayers/Edit/Window.py
 create mode 100644 src/View/SedimentLayers/Edit/translate.py
 create mode 100644 src/View/SedimentLayers/Reach/Profile/Table.py
 create mode 100644 src/View/SedimentLayers/Reach/Profile/UndoCommand.py
 create mode 100644 src/View/SedimentLayers/Reach/Profile/Window.py
 create mode 100644 src/View/SedimentLayers/Reach/Profile/translate.py
 create mode 100644 src/View/SedimentLayers/Reach/Table.py
 create mode 100644 src/View/SedimentLayers/Reach/UndoCommand.py
 create mode 100644 src/View/SedimentLayers/Reach/Window.py
 create mode 100644 src/View/SedimentLayers/Reach/translate.py
 create mode 100644 src/View/SedimentLayers/Table.py
 create mode 100644 src/View/SedimentLayers/UndoCommand.py
 create mode 100644 src/View/SedimentLayers/Window.py
 create mode 100644 src/View/SedimentLayers/translate.py
 create mode 100644 src/View/ui/EditSedimentLayers.ui
 create mode 100644 src/View/ui/ProfileSedimentLayers.ui
 create mode 100644 src/View/ui/ReachSedimentLayers.ui
 create mode 100644 src/View/ui/SedimentLayersList.ui

diff --git a/src/Model/River.py b/src/Model/River.py
index a19e6cc3..a46661f4 100644
--- a/src/Model/River.py
+++ b/src/Model/River.py
@@ -15,6 +15,7 @@ from Model.InitialConditions.InitialConditionsDict import InitialConditionsDict
 from Model.Stricklers.StricklersList import StricklersList
 from Model.Friction.FrictionList import FrictionList
 from Model.SolverParameters.SolverParametersList import SolverParametersList
+from Model.SedimentLayer.SedimentLayerList import SedimentLayerList
 
 from Solver.Solvers import solver_type_list
 
@@ -192,6 +193,7 @@ class River(Graph, SQLSubModel):
         InitialConditionsDict,
         StricklersList,
         SolverParametersList,
+        SedimentLayerList,
     ]
 
     def __init__(self, status=None):
@@ -207,6 +209,7 @@ class River(Graph, SQLSubModel):
         self._initial_conditions = InitialConditionsDict(status=self._status)
         self._stricklers = StricklersList(status=self._status)
         self._parameters = {}
+        self._sediment_layers = SedimentLayerList()
 
     @classmethod
     def _sql_create(cls, execute):
@@ -301,6 +304,10 @@ class River(Graph, SQLSubModel):
     def initial_conditions(self):
         return self._initial_conditions
 
+    @property
+    def sediment_layers(self):
+        return self._sediment_layers
+
     @property
     def stricklers(self):
         return self._stricklers
diff --git a/src/View/MainWindow.py b/src/View/MainWindow.py
index 10a35a6e..79c7ef67 100644
--- a/src/View/MainWindow.py
+++ b/src/View/MainWindow.py
@@ -33,6 +33,7 @@ from View.LateralContribution.Window import LateralContributionWindow
 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.SolverParameters.Window import SolverParametersWindow
 from View.RunSolver.Window import SelectSolverWindow, SolverLogWindow
 from View.CheckList.Window import CheckListWindow
@@ -70,7 +71,8 @@ define_model_action = [
     "action_menu_edit_network", "action_menu_edit_geometry",
     "action_menu_boundary_conditions", "action_menu_initial_conditions",
     "action_menu_edit_friction", "action_menu_edit_lateral_contribution",
-    "action_menu_run_solver",
+    "action_menu_run_solver", "action_menu_sediment_layers",
+    "action_menu_edit_reach_sediment_layers"
 ]
 
 action = (
@@ -147,6 +149,7 @@ 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,
             ## Help
             "action_menu_about": self.open_about,
             # ToolBar action
@@ -490,6 +493,13 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
         )
         params.show()
 
+    def open_sediment_layer(self):
+        sl = SedimentLayersWindow(
+            study = self.model,
+            parent = self
+        )
+        sl.show()
+
     def run_solver(self):
         if self.model is None:
             return
diff --git a/src/View/SedimentLayers/Edit/Table.py b/src/View/SedimentLayers/Edit/Table.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/View/SedimentLayers/Edit/UndoCommand.py b/src/View/SedimentLayers/Edit/UndoCommand.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/View/SedimentLayers/Edit/Window.py b/src/View/SedimentLayers/Edit/Window.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/View/SedimentLayers/Edit/translate.py b/src/View/SedimentLayers/Edit/translate.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/View/SedimentLayers/Reach/Profile/Table.py b/src/View/SedimentLayers/Reach/Profile/Table.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/View/SedimentLayers/Reach/Profile/UndoCommand.py b/src/View/SedimentLayers/Reach/Profile/UndoCommand.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/View/SedimentLayers/Reach/Profile/Window.py b/src/View/SedimentLayers/Reach/Profile/Window.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/View/SedimentLayers/Reach/Profile/translate.py b/src/View/SedimentLayers/Reach/Profile/translate.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/View/SedimentLayers/Reach/Table.py b/src/View/SedimentLayers/Reach/Table.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/View/SedimentLayers/Reach/UndoCommand.py b/src/View/SedimentLayers/Reach/UndoCommand.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/View/SedimentLayers/Reach/Window.py b/src/View/SedimentLayers/Reach/Window.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/View/SedimentLayers/Reach/translate.py b/src/View/SedimentLayers/Reach/translate.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/View/SedimentLayers/Table.py b/src/View/SedimentLayers/Table.py
new file mode 100644
index 00000000..7abbd869
--- /dev/null
+++ b/src/View/SedimentLayers/Table.py
@@ -0,0 +1,151 @@
+# -*- 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.SedimentLayers.UndoCommand import *
+from View.SedimentLayers.translate import *
+
+_translate = QCoreApplication.translate
+
+
+class TableModel(QAbstractTableModel):
+    def __init__(self, study=None, undo=None):
+        super(QAbstractTableModel, self).__init__()
+        self._headers = list(table_headers.keys())
+        self._study = study
+        self._undo = undo
+        self._sl = self._study.river.sediment_layers
+
+    def flags(self, index):
+        options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
+        options |= Qt.ItemIsEditable
+
+        return options
+
+    def rowCount(self, parent):
+        return len(self._sl)
+
+    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._sl.get(row).name
+        elif self._headers[column] == "comment":
+            return self._sl.get(row).name
+
+        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] == "name":
+            self._undo.push(
+                SetNameCommand(
+                    self._sl, row, value
+                )
+            )
+        if self._headers[column] == "comment":
+            self._undo.push(
+                SetCommentCommand(
+                    self._sl, 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._sl, row, self._data
+            )
+        )
+
+        self.endInsertRows()
+        self.layoutChanged.emit()
+
+    def delete(self, rows, parent=QModelIndex()):
+        self.beginRemoveRows(parent, rows[0], rows[-1])
+
+        self._undo.push(
+            DelCommand(
+                self._sl, rows
+            )
+        )
+
+        self.endRemoveRows()
+        self.layoutChanged.emit()
+
+    def move_up(self, row, parent=QModelIndex()):
+        if row <= 0:
+            return
+
+        target = row + 2
+
+        self.beginMoveRows(parent, row - 1, row - 1, parent, target)
+
+        self._undo_stack.push(
+            MoveCommand(
+                self._sl, "up", row
+            )
+        )
+
+        self.endMoveRows()
+        self.layoutChanged.emit()
+
+    def move_down(self, index, parent=QModelIndex()):
+        if row > len(self._sl):
+            return
+
+        target = row
+
+        self.beginMoveRows(parent, row + 1, row + 1, parent, target)
+
+        self._undo_stack.push(
+            MoveCommand(
+                self._sl, "down", row
+            )
+        )
+
+        self.endMoveRows()
+        self.layoutChanged.emit()
+
+    def undo(self):
+        self._undo.undo()
+        self.layoutChanged.emit()
+
+    def redo(self):
+        self._undo.redo()
+        self.layoutChanged.emit()
diff --git a/src/View/SedimentLayers/UndoCommand.py b/src/View/SedimentLayers/UndoCommand.py
new file mode 100644
index 00000000..84c4027b
--- /dev/null
+++ b/src/View/SedimentLayers/UndoCommand.py
@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+
+from copy import deepcopy
+from tools import trace, timer
+
+from PyQt5.QtWidgets import (
+    QMessageBox, QUndoCommand, QUndoStack,
+)
+
+from Model.SedimentLayer.SedimentLayer import SedimentLayer
+from Model.SedimentLayer.SedimentLayerList import SedimentLayerList
+
+class SetNameCommand(QUndoCommand):
+    def __init__(self, sediment_layers_list, index, new_value):
+        QUndoCommand.__init__(self)
+
+        self._sediment_layers_list = sediment_layers_list
+        self._index = index
+        self._old = self._sediment_layers_list.get(self._index).name
+        self._new = new_value
+
+    def undo(self):
+        self._sediment_layers_list.get(self._index).name = self._old
+
+    def redo(self):
+        self._sediment_layers_list.get(self._index).name = self._new
+
+class SetCommentCommand(QUndoCommand):
+    def __init__(self, sediment_layers_list, index, new_value):
+        QUndoCommand.__init__(self)
+
+        self._sediment_layers_list = sediment_layers_list
+        self._index = index
+        self._old = self._sediment_layers_list.get(self._index).comment
+        self._new = new_value
+
+    def undo(self):
+        self._sediment_layers_list.get(self._index).comment = self._old
+
+    def redo(self):
+        self._sediment_layers_list.get(self._index).comment = self._new
+
+class AddCommand(QUndoCommand):
+    def __init__(self, sediment_layers_list, index, reach):
+        QUndoCommand.__init__(self)
+
+        self._sediment_layers_list = sediment_layers_list
+        self._index = index
+        self._new = None
+
+    def undo(self):
+        self._sediment_layers_list.delete_i([self._index])
+
+    def redo(self):
+        if self._new is None:
+            self._new = self._sediment_layers_list.new(self._index)
+        else:
+            self._sediment_layers_list.insert(self._index, self._new)
+
+class DelCommand(QUndoCommand):
+    def __init__(self, sediment_layers_list, rows):
+        QUndoCommand.__init__(self)
+
+        self._sediment_layers_list = sediment_layers_list
+        self._rows = rows
+
+        self._sl_pos = []
+        for row in rows:
+            self._sl_pos.append((row, self._sediment_layers_list.get(row)))
+        self._sl_pos.sort()
+
+    def undo(self):
+        for row, el in self._sl_pos:
+            self._sediment_layers_list.insert(row, el)
+
+    def redo(self):
+        self._sediment_layers_list.delete_i(self._rows)
+
+class MoveCommand(QUndoCommand):
+    def __init__(self, sediment_layers_list, up, i):
+        QUndoCommand.__init__(self)
+
+        self._sediment_layers_list = sediment_layers_list
+        self._up = up == "up"
+        self._i = i
+
+    def undo(self):
+        if self._up:
+            self._sediment_layers_list.move_up(self._i)
+        else:
+            self._sediment_layers_list.move_down(self._i)
+
+    def redo(self):
+        if self._up:
+            self._sediment_layers_list.move_up(self._i)
+        else:
+            self._sediment_layers_list.move_down(self._i)
diff --git a/src/View/SedimentLayers/Window.py b/src/View/SedimentLayers/Window.py
new file mode 100644
index 00000000..22b61318
--- /dev/null
+++ b/src/View/SedimentLayers/Window.py
@@ -0,0 +1,156 @@
+# -*- 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.UndoCommand import *
+from View.SedimentLayers.Table import *
+
+from View.Plot.MplCanvas import MplCanvas
+from View.SedimentLayers.translate import *
+
+# from View.SedimentLayers.Edit.Window import EditSedimentLayersWindow
+
+_translate = QCoreApplication.translate
+
+logger = logging.getLogger()
+
+class SedimentLayersWindow(ASubMainWindow, ListedSubWindow):
+    def __init__(self, title="SedimentLayersList", study=None, parent=None):
+        self._study = study
+        self._sediment_layers = self._study.river.sediment_layers
+
+        self.setup_title(title)
+
+        super(SedimentLayersWindow, self).__init__(
+            name=self._title, ui="SedimentLayersList", 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
+        )
+
+    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 = {}
+
+        table = self.find(QTableView, f"tableView")
+        self._table = TableModel(
+            study = self._study,
+            undo = self._undo_stack,
+        )
+        table.setModel(self._table)
+
+        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")
+        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_add").triggered.connect(self.add)
+        self.find(QAction, "action_del").triggered.connect(self.delete)
+        self.find(QAction, "action_edit").triggered.connect(self.edit_sediment_layers)
+
+        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 add(self):
+        rows = self.index_selected_rows()
+        if len(self._sediment_layers) == 0 or len(rows) == 0:
+            self._table.add(0)
+        else:
+            self._table.add(rows[0])
+
+    def delete(self):
+        rows = self.index_selected_rows()
+        if len(rows) == 0:
+            return
+
+        self._table.delete(rows)
+
+    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_sediment_layers(self):
+        rows = self.index_selected_rows()
+
+        for row in rows:
+            slw = EditSedimentLayersWindow(
+                study = self._study,
+                sl = self.__sediment_layers[row],
+                parent = self
+            )
+            slw.show()
diff --git a/src/View/SedimentLayers/translate.py b/src/View/SedimentLayers/translate.py
new file mode 100644
index 00000000..6eafe079
--- /dev/null
+++ b/src/View/SedimentLayers/translate.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+
+from PyQt5.QtCore import QCoreApplication
+
+_translate = QCoreApplication.translate
+
+table_headers = {
+    "name": _translate("SedimentLayers", "Name"),
+    "comment": _translate("SedimentLayers", "Comment"),
+}
diff --git a/src/View/ui/EditSedimentLayers.ui b/src/View/ui/EditSedimentLayers.ui
new file mode 100644
index 00000000..7e236641
--- /dev/null
+++ b/src/View/ui/EditSedimentLayers.ui
@@ -0,0 +1,114 @@
+<?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>960</width>
+    <height>480</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>MainWindow</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QGridLayout" name="gridLayout">
+    <item row="0" column="0">
+     <widget class="QSplitter" name="splitter">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+      <widget class="QTableView" name="tableView"/>
+      <widget class="QWidget" name="verticalLayoutWidget">
+       <layout class="QVBoxLayout" name="verticalLayout"/>
+      </widget>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>960</width>
+     <height>22</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+  <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_sediment_layer"/>
+   <addaction name="action_delete_sediment_layer"/>
+   <addaction name="action_move_up"/>
+   <addaction name="action_move_down"/>
+  </widget>
+  <action name="action_add_sediment_layer">
+   <property name="icon">
+    <iconset>
+     <normaloff>ressources/gtk-add.png</normaloff>ressources/gtk-add.png</iconset>
+   </property>
+   <property name="text">
+    <string>Add sediment layer</string>
+   </property>
+   <property name="toolTip">
+    <string>Add a new sediment layer</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+N</string>
+   </property>
+  </action>
+  <action name="action_delete_sediment_layer">
+   <property name="icon">
+    <iconset>
+     <normaloff>ressources/gtk-remove.png</normaloff>ressources/gtk-remove.png</iconset>
+   </property>
+   <property name="text">
+    <string>Delete sediment layer</string>
+   </property>
+   <property name="toolTip">
+    <string>Delete selected sediment layer(s)</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+D</string>
+   </property>
+  </action>
+  <action name="action_move_up">
+   <property name="icon">
+    <iconset>
+     <normaloff>ressources/up.png</normaloff>ressources/up.png</iconset>
+   </property>
+   <property name="text">
+    <string>Move up</string>
+   </property>
+   <property name="toolTip">
+    <string>Move up</string>
+   </property>
+  </action>
+  <action name="action_move_down">
+   <property name="icon">
+    <iconset>
+     <normaloff>ressources/down.png</normaloff>ressources/down.png</iconset>
+   </property>
+   <property name="text">
+    <string>Move down</string>
+   </property>
+   <property name="toolTip">
+    <string>Move down</string>
+   </property>
+  </action>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/View/ui/MainWindow.ui b/src/View/ui/MainWindow.ui
index b63f032c..e91bd14d 100644
--- a/src/View/ui/MainWindow.ui
+++ b/src/View/ui/MainWindow.ui
@@ -199,10 +199,18 @@
     <addaction name="action_menu_help_mage"/>
     <addaction name="action_menu_about"/>
    </widget>
+   <widget class="QMenu" name="menuSediment">
+    <property name="title">
+     <string>&amp;Sediment</string>
+    </property>
+    <addaction name="action_menu_sediment_layers"/>
+    <addaction name="action_menu_edit_reach_sediment_layers"/>
+   </widget>
    <addaction name="menu_File"/>
    <addaction name="menu_network"/>
    <addaction name="menu_geometry"/>
    <addaction name="menu_Hydraulics"/>
+   <addaction name="menuSediment"/>
    <addaction name="menu_run"/>
    <addaction name="menu_plot"/>
    <addaction name="menu_cartography"/>
@@ -909,6 +917,16 @@
     <string>Initial conditions</string>
    </property>
   </action>
+  <action name="action_menu_sediment_layers">
+   <property name="text">
+    <string>Sediment layers</string>
+   </property>
+  </action>
+  <action name="action_menu_edit_reach_sediment_layers">
+   <property name="text">
+    <string>Edit reach sediment layers</string>
+   </property>
+  </action>
  </widget>
  <resources/>
  <connections>
diff --git a/src/View/ui/ProfileSedimentLayers.ui b/src/View/ui/ProfileSedimentLayers.ui
new file mode 100644
index 00000000..b9f5106d
--- /dev/null
+++ b/src/View/ui/ProfileSedimentLayers.ui
@@ -0,0 +1,95 @@
+<?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>960</width>
+    <height>480</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>MainWindow</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QGridLayout" name="gridLayout">
+    <item row="0" column="0">
+     <widget class="QSplitter" name="splitter">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+      <widget class="QTableView" name="tableView"/>
+      <widget class="QWidget" name="verticalLayoutWidget">
+       <layout class="QVBoxLayout" name="verticalLayout"/>
+      </widget>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>960</width>
+     <height>22</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+  <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_sediment_layers"/>
+   <addaction name="action_delete_sediment_layers"/>
+   <addaction name="action_edit_sediment_layers"/>
+  </widget>
+  <action name="action_add_sediment_layers">
+   <property name="icon">
+    <iconset>
+     <normaloff>ressources/gtk-add.png</normaloff>ressources/gtk-add.png</iconset>
+   </property>
+   <property name="text">
+    <string>Add sediment layers</string>
+   </property>
+   <property name="toolTip">
+    <string>Add specific sediment layers on selected point(s)</string>
+   </property>
+  </action>
+  <action name="action_delete_sediment_layers">
+   <property name="icon">
+    <iconset>
+     <normaloff>ressources/gtk-remove.png</normaloff>ressources/gtk-remove.png</iconset>
+   </property>
+   <property name="text">
+    <string>Delete sediment layers</string>
+   </property>
+   <property name="toolTip">
+    <string>Delete specific sediment layers of selected point(s)</string>
+   </property>
+  </action>
+  <action name="action_edit_sediment_layers">
+   <property name="icon">
+    <iconset>
+     <normaloff>ressources/edit.png</normaloff>ressources/edit.png</iconset>
+   </property>
+   <property name="text">
+    <string>Edit sediment layers</string>
+   </property>
+   <property name="toolTip">
+    <string>Edit sediment layers list</string>
+   </property>
+  </action>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/View/ui/ReachSedimentLayers.ui b/src/View/ui/ReachSedimentLayers.ui
new file mode 100644
index 00000000..b37db0c4
--- /dev/null
+++ b/src/View/ui/ReachSedimentLayers.ui
@@ -0,0 +1,98 @@
+<?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>960</width>
+    <height>480</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>MainWindow</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QGridLayout" name="gridLayout">
+    <item row="0" column="0">
+     <widget class="QSplitter" name="splitter">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+      <widget class="QWidget" name="verticalLayoutWidget">
+       <layout class="QVBoxLayout" name="verticalLayout">
+        <item>
+         <widget class="QTableView" name="tableView"/>
+        </item>
+        <item>
+         <widget class="QPushButton" name="pushButton">
+          <property name="text">
+           <string>Edit sediment layers list</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QPushButton" name="pushButton_2">
+          <property name="text">
+           <string>Apply sediment layers on all reach</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="verticalLayoutWidget_2">
+       <layout class="QVBoxLayout" name="verticalLayout_2"/>
+      </widget>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>960</width>
+     <height>22</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+  <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_edit_profile"/>
+  </widget>
+  <action name="action_edit_profile">
+   <property name="icon">
+    <iconset>
+     <normaloff>ressources/edit.png</normaloff>ressources/edit.png</iconset>
+   </property>
+   <property name="text">
+    <string>Edit profile</string>
+   </property>
+   <property name="toolTip">
+    <string>Edit profile sediment layer</string>
+   </property>
+  </action>
+  <action name="action_add_sediment_layer">
+   <property name="icon">
+    <iconset>
+     <normaloff>ressources/gtk-add.png</normaloff>ressources/gtk-add.png</iconset>
+   </property>
+   <property name="text">
+    <string>Add sediment layer</string>
+   </property>
+  </action>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/View/ui/SedimentLayersList.ui b/src/View/ui/SedimentLayersList.ui
new file mode 100644
index 00000000..399b0995
--- /dev/null
+++ b/src/View/ui/SedimentLayersList.ui
@@ -0,0 +1,95 @@
+<?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>960</width>
+    <height>480</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>MainWindow</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QGridLayout" name="gridLayout">
+    <item row="0" column="0">
+     <widget class="QSplitter" name="splitter">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+      <widget class="QTableView" name="tableView"/>
+      <widget class="QWidget" name="verticalLayoutWidget">
+       <layout class="QVBoxLayout" name="verticalLayout"/>
+      </widget>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>960</width>
+     <height>22</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+  <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_edit"/>
+  </widget>
+  <action name="action_add">
+   <property name="icon">
+    <iconset>
+     <normaloff>ressources/gtk-add.png</normaloff>ressources/gtk-add.png</iconset>
+   </property>
+   <property name="text">
+    <string>Add sediment layer</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 sediment layer</string>
+   </property>
+   <property name="toolTip">
+    <string>Delete sediment layer</string>
+   </property>
+  </action>
+  <action name="action_edit">
+   <property name="icon">
+    <iconset>
+     <normaloff>ressources/edit.png</normaloff>ressources/edit.png</iconset>
+   </property>
+   <property name="text">
+    <string>Edit sediment layer</string>
+   </property>
+   <property name="toolTip">
+    <string>Edit sediment layer</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+E</string>
+   </property>
+  </action>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
-- 
GitLab