qtableview_reach.py 7.75 KiB
# -*- 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
)

from Model.Geometry import Reach

_translate = QCoreApplication.translate

class PandasModelEditable(QAbstractTableModel):
    def __init__(self, reach, headers=None):
        QAbstractTableModel.__init__(self)
        data_list = []

        self._data = 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._data.number_profiles

    def columnCount(self, parent=QModelIndex()):
        return len(self.headers)

    def data(self, index, role=Qt.DisplayRole):
        if index.isValid():
            if role == Qt.DisplayRole and index.column() == 0:
                return self._data.profile(index.row()).name

            if role == Qt.DisplayRole and index.column() == 1:
                kp = self._data.profile(index.row()).kp
                return f"{kp:.4f}"

            if role == Qt.DisplayRole and index.column() == 2:
                return self._data.profile(index.row()).profile_type

            for column in range(0, self.columnCount()):
                if index.column() == column and role == Qt.TextAlignmentRole:
                    return Qt.AlignHCenter | Qt.AlignVCenter

            if role == Qt.ForegroundRole and index.column() == 0:
                name = self._data.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 role == Qt.EditRole and index.column() == 0:
                self._data.profile(index.row()).name = value

            if role == Qt.EditRole and index.column() == 1:
                self._data.profile(index.row()).pk = float(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 insertRows(self, row, count, parent=QModelIndex()):
        self.beginInsertRows(parent, row, row + count - 1)

        self._data.add_profile(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._data.delete_profile(list_row_selected[0])
            elif len(list_row_selected) > 1:
                self._data.delete_profile_rows(list_row_selected)

        self.endRemoveRows()
        self.layoutChanged.emit()

    def sort_data(self, _reverse):
        self.layoutAboutToBeChanged.emit()

        self._data.sort(_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._data.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._data.move_up_profile(row_to_move)

        self.endMoveRows()
        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):
        """retourne le widget (éditeur) pour éditer l'item se trouvant à l'index index."""
        index.model().data(index, Qt.DisplayRole)
        return QtWidgets.QLineEdit(parent)

    def setEditorData(self, editor, index):
        """permet de transmettre à l'éditeur editor les données à afficher à partir du modèle se trouvant à l'index
        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
        print('Donnée éditée dans la case [{},{}] :'.format(index.row(), index.column()), value)

    def setModelData(self, editor, model, index):
        """permet de récupérer les données de l'éditeur et de les stocker à l'intérieur du modèle, à l'index identifié
        par le paramètre index """
        model.setData(index, editor.currentItem().text())

        if not self.setModelDataEvent is None:
            self.setModelDataEvent()

    def updateEditorGeometry(self, editor, option, index):
        """permet de redimensionner l'éditeur à la bonne taille lorsque la taille de la vue change"""
        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())