# -*- coding: utf-8 -*- import time from functools import reduce from itertools import groupby from operator import itemgetter import numpy as np import pandas as pd from PyQt5 import ( QtGui, QtWidgets ) from PyQt5.QtCore import ( Qt, QAbstractTableModel, QModelIndex, QVariant, pyqtSlot, QCoreApplication, ) from PyQt5.QtWidgets import ( QMessageBox, QUndoCommand, QUndoStack, ) from Model.Geometry import Reach from View.Geometry.ReachUndoCommand import * _translate = QCoreApplication.translate class PandasModelEditable(QAbstractTableModel): def __init__(self, reach, headers=None): QAbstractTableModel.__init__(self) data_list = [] self._undo_stack = QUndoStack() self._reach = reach if headers is None: self.headers = [ _translate("Geometry", "Name"), _translate("Geometry", "Kp (m)"), _translate("Geometry", "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 QtGui.QColor("Green") elif (name == "downstream" or name == "down" or name == _translate("Geometry", "downstream")): return QtGui.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 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, list_row_selected, parent=QModelIndex()): self.beginRemoveRows(parent, list_row_selected[0], list_row_selected[-1]) if len(list_row_selected) >= 1: if len(list_row_selected) == 1: self._reach.delete_profile(list_row_selected[0]) elif len(list_row_selected) > 1: self._reach.delete_profile_rows(list_row_selected) 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 moveRowDown(self, row_to_move, parent=QModelIndex()): target = row_to_move + 2 self.beginMoveRows(parent, row_to_move, row_to_move, parent, target) self._reach.move_down_profile(row_to_move) self.endMoveRows() self.layoutChanged.emit() def moveRowUp(self, row_to_move, parent=QModelIndex()): target = row_to_move + 1 self.beginMoveRows(parent, row_to_move - 1, row_to_move - 1, parent, target) self._reach.move_up_profile(row_to_move) self.endMoveRows() 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(QtWidgets.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 QtWidgets.QLineEdit(parent) def setEditorData(self, editor, index): value = index.model().data(index, Qt.DisplayRole) # DisplayRole editor.setText(str(value)) # récupère la valeur de la cellule applique la méthode définie dans setData 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(QtWidgets.QStyledItemDelegate): def __init__(self, owner, choices): super().__init__(owner) self.items = choices def paint(self, painter, option, index): if isinstance(self.parent(), QtWidgets.QAbstractItemView): self.parent().openPersistentEditor(index) super(Delegate1, self).paint(painter, option, index) def createEditor(self, parent, option, index): editor = QtWidgets.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())