Pamhyr2/src/View/OutputKpAdisTS/BasicHydraulicStructures/Table.py

278 lines
7.8 KiB
Python

# Table.py -- Pamhyr
# Copyright (C) 2023-2024 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 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, QMessageBox,
)
from View.Tools.PamhyrTable import PamhyrTableModel
from View.HydraulicStructures.BasicHydraulicStructures.UndoCommand import (
SetNameCommand, SetTypeCommand,
SetEnabledCommand, AddCommand, DelCommand,
SetValueCommand,
)
from Model.HydraulicStructures.Basic.Types import BHS_types
logger = logging.getLogger()
_translate = QCoreApplication.translate
class ComboBoxDelegate(QItemDelegate):
def __init__(self, data=None, trad=None, parent=None):
super(ComboBoxDelegate, self).__init__(parent)
self._data = data
self._trad = trad
self._long_types = {}
if self._trad is not None:
self._long_types = self._trad.get_dict("long_types")
def createEditor(self, parent, option, index):
self.editor = QComboBox(parent)
lst = list(
map(
lambda k: self._long_types[k],
BHS_types.keys()
)
)
self.editor.addItems(lst)
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:
if 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(PamhyrTableModel):
def __init__(self, trad=None, **kwargs):
self._trad = trad
self._long_types = {}
if self._trad is not None:
self._long_types = self._trad.get_dict("long_types")
super(TableModel, self).__init__(trad=trad, **kwargs)
def rowCount(self, parent):
return len(self._lst)
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.basic_structure(row).name
elif self._headers[column] == "type":
return self._long_types[self._data.basic_structure(row).type]
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()
try:
if self._headers[column] == "name":
self._undo.push(
SetNameCommand(
self._data, row, value
)
)
elif self._headers[column] == "type":
old_type = self._data.basic_structure(row).type
if old_type == "ND" or self._question_set_type():
key = next(
k for k, v in self._long_types.items()
if v == value
)
self._undo.push(
SetTypeCommand(
self._data, row, BHS_types[key]
)
)
except Exception as e:
logger.error(e)
logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
def _question_set_type(self):
question = QMessageBox(self._parent)
question.setWindowTitle(self._trad['msg_type_change_title'])
question.setText(self._trad['msg_type_change_text'])
question.setStandardButtons(QMessageBox.Cancel | QMessageBox.Ok)
question.setIcon(QMessageBox.Question)
res = question.exec()
return res == QMessageBox.Ok
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 enabled(self, row, enabled, parent=QModelIndex()):
self._undo.push(
SetEnabledCommand(
self._lst, row, enabled
)
)
self.layoutChanged.emit()
def undo(self):
self._undo.undo()
self.layoutChanged.emit()
def redo(self):
self._undo.redo()
self.layoutChanged.emit()
class ParametersTableModel(PamhyrTableModel):
def __init__(self, trad=None, **kwargs):
self._trad = trad
self._long_types = {}
if self._trad is not None:
self._long_types = self._trad.get_dict("long_types")
self._hs_index = None
super(ParametersTableModel, self).__init__(trad=trad, **kwargs)
def rowCount(self, parent):
if self._hs_index is None:
return 0
return len(
self._data.basic_structure(self._hs_index)
)
def data(self, index, role):
if role != Qt.ItemDataRole.DisplayRole:
return QVariant()
if self._hs_index is None:
return QVariant()
row = index.row()
column = index.column()
hs = self._data.basic_structure(self._hs_index)
if self._headers[column] == "name":
return self._trad[hs.parameters[row].name]
elif self._headers[column] == "value":
return str(hs.parameters[row].value)
return QVariant()
def setData(self, index, value, role=Qt.EditRole):
if not index.isValid() or role != Qt.EditRole:
return False
if self._hs_index is None:
return QVariant()
row = index.row()
column = index.column()
try:
if self._headers[column] == "value":
self._undo.push(
SetValueCommand(
self._data.basic_structure(self._hs_index),
row, value
)
)
except Exception as e:
logger.error(e)
logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
def update_hs_index(self, index):
self._hs_index = index
self.layoutChanged.emit()