From 3d82b7be93ec513c3095efb210bf556df9757618 Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Rouby <pierre-antoine.rouby@inrae.fr> Date: Fri, 24 Mar 2023 13:28:01 +0100 Subject: [PATCH] network: New file for custom table model. --- src/view/NetworkWindow.py | 166 ++------------------------------- src/view/network/TableModel.py | 166 +++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+), 156 deletions(-) create mode 100644 src/view/network/TableModel.py diff --git a/src/view/NetworkWindow.py b/src/view/NetworkWindow.py index d165e6ef..4cf74d00 100644 --- a/src/view/NetworkWindow.py +++ b/src/view/NetworkWindow.py @@ -5,6 +5,9 @@ from model.network.Edge import Edge from model.network.Graph import Graph from view.ASubWindow import ASubWindow from view.network.GraphWidget import GraphWidget +from view.network.TableModel import ( + GraphTableModel, ComboBoxDelegate, TrueFalseComboBoxDelegate, +) from PyQt5.QtCore import ( Qt, QRect, QVariant, QAbstractTableModel, pyqtSlot, pyqtSignal, @@ -17,154 +20,6 @@ from PyQt5.QtWidgets import ( QApplication, ) -class ComboBoxDelegate(QItemDelegate): - def __init__(self, graph=None, parent=None): - super(ComboBoxDelegate, self).__init__(parent) - self.graph = graph - - def createEditor(self, parent, option, index): - self.editor = QComboBox(parent) - self.editor.addItems(self.graph.nodes_names()) - 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 TrueFalseComboBoxDelegate(QItemDelegate): - def __init__(self, parent=None): - super(TrueFalseComboBoxDelegate, self).__init__(parent) - - def createEditor(self, parent, option, index): - self.editor = QComboBox(parent) - self.editor.addItems(["true", "false"]) - return self.editor - - def setEditorData(self, editor, index): - value = str(index.data(Qt.DisplayRole)) - self.editor.currentTextChanged.connect(self.currentItemChanged) - - def setModelData(self, editor, model, index): - value = str(editor.currentText()) == "true" - model.setData(index, value) - 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, headers=[], graph=None, rows_type="nodes"): - super(QAbstractTableModel, self).__init__() - self.headers = headers - self.graph = graph - self._type = rows_type - - if self._type == "nodes": - self.rows = graph.nodes() - elif self._type == "edges": - self.rows = graph.edges() - - def flags(self, index): - options = Qt.ItemIsEnabled | Qt.ItemIsSelectable - - if self.headers[index.column()] != "type": - options |= Qt.ItemIsEditable - - return options - - def rowCount(self, parent): - return len(self.rows) - - def columnCount(self, parent): - return len(self.headers) - - def data(self, index, role): - if role != Qt.ItemDataRole.DisplayRole: - return QVariant() - - if self.headers[index.column()] == "type": - node = self.rows[index.row()] - ret = "internal" - - if not self.graph.is_enable_node(node): - ret = "disable" - elif self.graph.is_upstream_node(node): - ret = "upstream" - elif self.graph.is_downstream_node(node): - ret = "downstream" - - return ret - - return self.rows[index.row()][self.headers[index.column()]] - - def headerData(self, section, orientation, role): - if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal: - return self.headers[section].capitalize() - - # if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Vertical: - # return section - - return QVariant() - - @pyqtSlot() - def setData(self, index, value, role=Qt.EditRole): - if index.isValid(): - if role == Qt.EditRole: - if (self.headers[index.column()] == "node1" or - self.headers[index.column()] == "node2"): - node = self.graph.node(value) - self.rows[index.row()][self.headers[index.column()]] = node - else: - self.rows[index.row()][self.headers[index.column()]] = value - - self.dataChanged.emit(index, index, [Qt.DisplayRole]) - self.layoutChanged.emit() - return True - - self.dataChanged.emit(index, index) - else: - return False - - def update(self): - if self._type == "nodes": - self.rows = self.graph.nodes() - elif self._type == "edges": - self.rows = self.graph.edges() - - self.layoutChanged.emit() - - def reverse_edge(self, index): - if self._type == "edges": - tmp = self.rows[index.row()].node1 - self.rows[index.row()].node1 = self.rows[index.row()].node2 - self.rows[index.row()].node2 = tmp - self.dataChanged.emit(index, index, [Qt.DisplayRole]) - self.layoutChanged.emit() - class NetworkWindow(ASubWindow): def __init__(self, title="Network", parent=None): super(NetworkWindow, self).__init__(name=title, ui="Network", parent=parent) @@ -177,16 +32,10 @@ class NetworkWindow(ASubWindow): self.graph_widget = GraphWidget(self.graph, parent=self) self.graph_layout = self.find(QHBoxLayout, "horizontalLayout_graph") self.graph_layout.addWidget(self.graph_widget) - # self.zoom_slider = QSlider(Qt.Orientation.Vertical, parent=self) - # self.zoom_slider.setMinimum(0) - # self.zoom_slider.setMaximum(99) - # self.zoom_slider.setValue(50) - # self.graph_layout.addWidget(self.zoom_slider) - # self.zoom_slider.valueChanged.connect(self.graph_widget.scaleViewSlider) # Nodes table - self.nodes_model = TableModel( + self.nodes_model = GraphTableModel( headers = ["name", "type"], graph = self.graph, rows_type="nodes", @@ -197,7 +46,7 @@ class NetworkWindow(ASubWindow): # Edges table - self.reachs_model = TableModel( + self.reachs_model = GraphTableModel( headers = ["name", "enable", "node1", "node2"], graph = self.graph, rows_type="edges" @@ -257,6 +106,11 @@ class NetworkWindow(ASubWindow): self.graph_widget.reset_selection def reverse_edge(self): + """Reverse edge direction of selected table rows + + Returns: + Nothing + """ indices = self.find(QTableView, "tableView_reachs").selectionModel().selectedIndexes() indexes = {} diff --git a/src/view/network/TableModel.py b/src/view/network/TableModel.py new file mode 100644 index 00000000..0b8534c2 --- /dev/null +++ b/src/view/network/TableModel.py @@ -0,0 +1,166 @@ +# -*- coding: utf-8 -*- + +from model.network.Node import Node +from model.network.Edge import Edge +from model.network.Graph import Graph +from view.ASubWindow import ASubWindow +from view.network.GraphWidget import GraphWidget + +from PyQt5.QtCore import ( + Qt, QRect, QVariant, QAbstractTableModel, pyqtSlot, pyqtSignal, + QEvent, +) + +from PyQt5.QtWidgets import ( + QTableView, QItemDelegate, QComboBox, QLineEdit, QHBoxLayout, QSlider, + QPushButton, QCheckBox, QStyledItemDelegate, QStyleOptionButton, QStyle, + QApplication, +) + +class ComboBoxDelegate(QItemDelegate): + def __init__(self, graph=None, parent=None): + super(ComboBoxDelegate, self).__init__(parent) + self.graph = graph + + def createEditor(self, parent, option, index): + self.editor = QComboBox(parent) + self.editor.addItems(self.graph.nodes_names()) + 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 TrueFalseComboBoxDelegate(QItemDelegate): + def __init__(self, parent=None): + super(TrueFalseComboBoxDelegate, self).__init__(parent) + + def createEditor(self, parent, option, index): + self.editor = QComboBox(parent) + self.editor.addItems(["true", "false"]) + return self.editor + + def setEditorData(self, editor, index): + value = str(index.data(Qt.DisplayRole)) + self.editor.currentTextChanged.connect(self.currentItemChanged) + + def setModelData(self, editor, model, index): + value = str(editor.currentText()) == "true" + model.setData(index, value) + 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 GraphTableModel(QAbstractTableModel): + def __init__(self, headers=[], graph=None, rows_type="nodes"): + super(QAbstractTableModel, self).__init__() + self.headers = headers + self.graph = graph + self._type = rows_type + + if self._type == "nodes": + self.rows = graph.nodes() + elif self._type == "edges": + self.rows = graph.edges() + + def flags(self, index): + options = Qt.ItemIsEnabled | Qt.ItemIsSelectable + + if self.headers[index.column()] != "type": + options |= Qt.ItemIsEditable + + return options + + def rowCount(self, parent): + return len(self.rows) + + def columnCount(self, parent): + return len(self.headers) + + def data(self, index, role): + if role != Qt.ItemDataRole.DisplayRole: + return QVariant() + + if self.headers[index.column()] == "type": + node = self.rows[index.row()] + ret = "internal" + + if not self.graph.is_enable_node(node): + ret = "disable" + elif self.graph.is_upstream_node(node): + ret = "upstream" + elif self.graph.is_downstream_node(node): + ret = "downstream" + + return ret + + return self.rows[index.row()][self.headers[index.column()]] + + def headerData(self, section, orientation, role): + if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal: + return self.headers[section].capitalize() + + # if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Vertical: + # return section + + return QVariant() + + @pyqtSlot() + def setData(self, index, value, role=Qt.EditRole): + if index.isValid(): + if role == Qt.EditRole: + if (self.headers[index.column()] == "node1" or + self.headers[index.column()] == "node2"): + node = self.graph.node(value) + self.rows[index.row()][self.headers[index.column()]] = node + else: + self.rows[index.row()][self.headers[index.column()]] = value + + self.dataChanged.emit(index, index, [Qt.DisplayRole]) + self.layoutChanged.emit() + return True + + self.dataChanged.emit(index, index) + else: + return False + + def update(self): + if self._type == "nodes": + self.rows = self.graph.nodes() + elif self._type == "edges": + self.rows = self.graph.edges() + + self.layoutChanged.emit() + + def reverse_edge(self, index): + if self._type == "edges": + tmp = self.rows[index.row()].node1 + self.rows[index.row()].node1 = self.rows[index.row()].node2 + self.rows[index.row()].node2 = tmp + self.dataChanged.emit(index, index, [Qt.DisplayRole]) + self.layoutChanged.emit() -- GitLab