diff --git a/src/Model/Geometry/Point.py b/src/Model/Geometry/Point.py index 2108d962120014fa8e12dc4bc49a1fbd6410a5a5..041603df38d3cb337c5206e2cd93476766d57158 100644 --- a/src/Model/Geometry/Point.py +++ b/src/Model/Geometry/Point.py @@ -9,6 +9,16 @@ class Point(object): self._status = status self._name = name + self._sl = None + + + @property + def sl(self): + return self._sl + + @sl.setter + def sl(self, sl): + self._sl = sl @property def name(self): diff --git a/src/Model/Geometry/Profile.py b/src/Model/Geometry/Profile.py index 7836c47f0da581d6148cd4c1f11652e607734fdc..483082b0aa94e8c462b77a797443c0f746a5b68a 100644 --- a/src/Model/Geometry/Profile.py +++ b/src/Model/Geometry/Profile.py @@ -48,6 +48,9 @@ class Profile(object): def points(self): return self._points.copy() + def point(self, index): + return self._points[index] + @property def reach(self): return self._reach diff --git a/src/View/SedimentLayers/Reach/Profile/Table.py b/src/View/SedimentLayers/Reach/Profile/Table.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2675e8ee2957de8f7061b6f86f09bb842e08f8e4 100644 --- a/src/View/SedimentLayers/Reach/Profile/Table.py +++ b/src/View/SedimentLayers/Reach/Profile/Table.py @@ -0,0 +1,155 @@ +# -*- 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.Profile.UndoCommand import * +from View.SedimentLayers.Reach.Profile.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, profile=None, undo=None): + super(QAbstractTableModel, self).__init__() + self._headers = list(table_headers.keys()) + self._study = study + self._undo = undo + self._profile = profile + + 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._profile.number_points + + 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._profile.point(row).name + elif self._headers[column] == "sl": + value = self._profile.point(row).sl + if value == None: + text = _translate("SedimentLayers", "Not defined") + return text + return str(value) + elif self._headers[column] == "x": + return self._profile.point(row).x + elif self._headers[column] == "y": + return self._profile.point(row).y + elif self._headers[column] == "z": + return self._profile.point(row).z + + 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._profile, 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/Profile/UndoCommand.py b/src/View/SedimentLayers/Reach/Profile/UndoCommand.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fe3497aede40ac048aa6ea1999e6da1566bce976 100644 --- a/src/View/SedimentLayers/Reach/Profile/UndoCommand.py +++ b/src/View/SedimentLayers/Reach/Profile/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, profile, index, new_value): + QUndoCommand.__init__(self) + + self._profile = profile + self._index = index + self._old = self._profile.point(self._index).sl + self._new = new_value + + def undo(self): + self._profile.point(self._index).sl = self._old + + def redo(self): + self._profile.point(self._index).sl = self._new diff --git a/src/View/SedimentLayers/Reach/Profile/Window.py b/src/View/SedimentLayers/Reach/Profile/Window.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8f15a27e8ca14b6281d7cc42671085662a459497 100644 --- a/src/View/SedimentLayers/Reach/Profile/Window.py +++ b/src/View/SedimentLayers/Reach/Profile/Window.py @@ -0,0 +1,148 @@ +# -*- 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.Profile.UndoCommand import * +from View.SedimentLayers.Reach.Profile.Table import * + +from View.Plot.MplCanvas import MplCanvas +from View.SedimentLayers.Reach.Profile.translate import * + +from View.SedimentLayers.Window import SedimentLayersWindow + +_translate = QCoreApplication.translate + +logger = logging.getLogger() + +class ProfileSedimentLayersWindow(ASubMainWindow, ListedSubWindow): + def __init__(self, title="Profile sediment layers", study=None, profile=None, parent=None): + self._study = study + self._sediment_layers = self._study.river.sediment_layers + self._profile = profile + self._reach = self._study.river.current_reach().reach + + self.setup_title(title) + + super(ProfileSedimentLayersWindow, self).__init__( + name=self._title, ui="ProfileSedimentLayers", parent=parent + ) + + self.setup_sc() + self.setup_table() + self.setup_graph() + self.setup_connections() + + self.ui.setWindowTitle(self._title) + + def setup_title(self, title): + rname = self._reach.name + if rname == "": + rname = _translate("SedimentLayers", "(no name)") + + pname = self._profile.name + if pname == "": + pname = _translate("SedimentLayers", "(no name)") + + self._title = ( + title + " - " + + self._study.name + " - " + + rname + " - " + pname + ) + + 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, + profile = self._profile, + 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") + 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.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() diff --git a/src/View/SedimentLayers/Reach/Profile/translate.py b/src/View/SedimentLayers/Reach/Profile/translate.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..33e204b33552e41cece53621407ab7f0fbe3774c 100644 --- a/src/View/SedimentLayers/Reach/Profile/translate.py +++ b/src/View/SedimentLayers/Reach/Profile/translate.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- + +from PyQt5.QtCore import QCoreApplication + +_translate = QCoreApplication.translate + +table_headers = { + "x": _translate("SedimentLayers", "X (m)"), + "y": _translate("SedimentLayers", "Y (m)"), + "z": _translate("SedimentLazers", "Z (m)"), + "name": _translate("SedimentLayers", "Name"), + "sl": _translate("SedimentLayers", "Sediment layers"), +} diff --git a/src/View/SedimentLayers/Reach/Window.py b/src/View/SedimentLayers/Reach/Window.py index b292db5d490745cc07f48ac86761eb3be4566ec3..711a04fc49639a637e21a6d9dfd6a9652cf1a194 100644 --- a/src/View/SedimentLayers/Reach/Window.py +++ b/src/View/SedimentLayers/Reach/Window.py @@ -31,6 +31,7 @@ from View.Plot.MplCanvas import MplCanvas from View.SedimentLayers.Reach.translate import * from View.SedimentLayers.Window import SedimentLayersWindow +from View.SedimentLayers.Reach.Profile.Window import ProfileSedimentLayersWindow _translate = QCoreApplication.translate @@ -144,7 +145,7 @@ class ReachSedimentLayersWindow(ASubMainWindow, ListedSubWindow): for row in rows: slw = ProfileSedimentLayersWindow( study = self._study, - sl = self._sediment_layers.get(row), + profile = self._reach.profile(row), parent = self ) slw.show()