Pamhyr2/src/View/Geometry/qtableview_reach.py

306 lines
8.3 KiB
Python

# -*- coding: utf-8 -*-
import time
from tools import timer, trace
from PyQt5.QtGui import (
QKeySequence, QColor
)
from PyQt5.QtCore import (
Qt, QAbstractTableModel, QModelIndex,
QVariant, pyqtSlot, QCoreApplication,
)
from PyQt5.QtWidgets import (
QMessageBox, QUndoCommand, QUndoStack,
QStyledItemDelegate, QLineEdit, QAbstractItemView,
QComboBox,
)
from Model.Geometry import Reach
from Model.Geometry.ProfileXYZ import ProfileXYZ
from View.Geometry.ReachUndoCommand import *
_translate = QCoreApplication.translate
class TableEditableModel(QAbstractTableModel):
def __init__(self, reach, headers=None, undo=None):
QAbstractTableModel.__init__(self)
data_list = []
self._undo_stack = undo
self._reach = reach
# Hack for qtlinguist
_ = _translate("Geometry", "Name")
_ = _translate("Geometry", "Kp (m)")
_ = _translate("Geometry", "Type")
if headers is None:
self.headers = [
"Name",
"Kp (m)",
"Type"
]
else:
self.headers = headers
def rowCount(self, parent=QModelIndex()):
return self._reach.number_profiles
def columnCount(self, parent=QModelIndex()):
return len(self.headers)
def data(self, index, role=Qt.DisplayRole):
if not index.isValid():
return QVariant()
if role == Qt.DisplayRole and index.column() == 0:
return self._reach.profile(index.row()).name
if role == Qt.DisplayRole and index.column() == 1:
kp = self._reach.profile(index.row()).kp
return f"{kp:.4f}"
if role == Qt.DisplayRole and index.column() == 2:
return self._reach.profile(index.row()).profile_type
if role == Qt.TextAlignmentRole:
return Qt.AlignHCenter | Qt.AlignVCenter
if role == Qt.ForegroundRole and index.column() == 0:
name = self._reach.profile(index.row()).name\
.strip()\
.lower()
if (name == "upstream" or name == "up" or
name == _translate("Geometry", "upstream")):
return QColor("Green")
elif (name == "downstream" or name == "down" or
name == _translate("Geometry", "downstream")):
return QColor("Red")
return QVariant()
def headerData(self, section, orientation, role=Qt.DisplayRole):
if role == Qt.DisplayRole:
if orientation == Qt.Horizontal:
if section < len(self.headers):
return _translate("Geometry", self.headers[section])
else:
return str(section + 1)
return QVariant()
def setData(self, index, value, role=Qt.EditRole):
row = index.row()
column = index.column()
if role == Qt.EditRole and index.column() != 2:
if index.column() == 0:
self._undo_stack.push(
SetNameCommand(
self._reach, index.row(),
self._reach.profile(index.row()).name,
value
)
)
if index.column() == 1:
self._undo_stack.push(
SetKPCommand(
self._reach, index.row(),
self._reach.profile(index.row()).kp,
value
)
)
self.dataChanged.emit(index, index)
self.layoutChanged.emit()
return True
self.dataChanged.emit(index, index)
self.layoutChanged.emit()
return False
def index(self, row, column, parent=QModelIndex()):
if not self.hasIndex(row, column, parent):
return QModelIndex()
return self.createIndex(row, column, QModelIndex())
def flags(self, index):
flg = Qt.ItemIsEnabled | Qt.ItemIsSelectable
if index.column() == 2:
return flg
else:
return Qt.ItemIsEditable | flg
# @QtCore.pyqtSlot()
def insert_row(self, row, parent=QModelIndex()):
self.beginInsertRows(parent, row, row - 1)
self._undo_stack.push(
AddCommand(
self._reach, row
)
)
self.endInsertRows()
self.layoutChanged.emit()
def remove_rows(self, rows, parent=QModelIndex()):
self.beginRemoveRows(parent, rows[0], rows[-1])
self._undo_stack.push(
DelCommand(
self._reach, rows
)
)
self.endRemoveRows()
self.layoutChanged.emit()
def sort_profiles(self, _reverse):
self.layoutAboutToBeChanged.emit()
self._undo_stack.push(
SortCommand(
self._reach, _reverse
)
)
self.layoutAboutToBeChanged.emit()
self.layoutChanged.emit()
def move_row_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._reach, "up", row
)
)
self.endMoveRows()
self.layoutChanged.emit()
def move_row_down(self, row, parent=QModelIndex()):
if row > self._reach.number_profiles:
return
target = row
self.beginMoveRows(parent, row + 1, row + 1, parent, target)
self._undo_stack.push(
MoveCommand(
self._reach, "down", row
)
)
self.endMoveRows()
self.layoutChanged.emit()
def paste(self, row, header, data):
if row > self._reach.number_profiles:
return
if len(data) == 0:
return
self.layoutAboutToBeChanged.emit()
self._undo_stack.push(
PasteCommand(
self._reach, row,
list(
map(
lambda d: ProfileXYZ.from_data(header, d),
data
)
)
)
)
self.layoutAboutToBeChanged.emit()
self.layoutChanged.emit()
def undo(self):
self._undo_stack.undo()
self.layoutChanged.emit()
def redo(self):
self._undo_stack.redo()
self.layoutChanged.emit()
class Delegate(QStyledItemDelegate):
def __init__(self, parent=None, setModelDataEvent=None):
super(Delegate, self).__init__(parent)
self.setModelDataEvent = setModelDataEvent
def createEditor(self, parent, option, index):
index.model().data(index, Qt.DisplayRole)
return QLineEdit(parent)
def setEditorData(self, editor, index):
value = index.model().data(index, Qt.DisplayRole)
editor.setText(str(value))
def setModelData(self, editor, model, index):
model.setData(index, editor.text())
if not self.setModelDataEvent is None:
self.setModelDataEvent()
def updateEditorGeometry(self, editor, option, index):
editor.setGeometry(option.rect)
class Delegate1(QStyledItemDelegate):
def __init__(self, owner, choices):
super().__init__(owner)
self.items = choices
def paint(self, painter, option, index):
if isinstance(self.parent(), QAbstractItemView):
self.parent().openPersistentEditor(index)
super(Delegate1, self).paint(painter, option, index)
def createEditor(self, parent, option, index):
editor = QComboBox(parent)
# editor.currentIndexChanged.connect(self.commit_editor)
editor.addItems(self.items)
return editor
def setEditorData(self, editor, index):
editor.blockSignals(True)
text = index.model().data(index, Qt.DisplayRole)
try:
i = self.items.index(text)
except ValueError:
i = 0
editor.setCurrentIndex(i)
editor.blockSignals(False)
def setModelData(self, editor, model, index):
model.setData(index, editor.currentText(), Qt.DisplayRole)
def updateEditorGeometry(self, editor, option, index):
editor.setGeometry(option.rect)
@pyqtSlot()
def currentIndexChanged(self):
self.commitData.emit(self.sender())