network: New file for custom table model.

mesh
Pierre-Antoine Rouby 2023-03-24 13:28:01 +01:00
parent 4e1b3b94c0
commit 3d82b7be93
2 changed files with 176 additions and 156 deletions

View File

@ -5,6 +5,9 @@ from model.network.Edge import Edge
from model.network.Graph import Graph from model.network.Graph import Graph
from view.ASubWindow import ASubWindow from view.ASubWindow import ASubWindow
from view.network.GraphWidget import GraphWidget from view.network.GraphWidget import GraphWidget
from view.network.TableModel import (
GraphTableModel, ComboBoxDelegate, TrueFalseComboBoxDelegate,
)
from PyQt5.QtCore import ( from PyQt5.QtCore import (
Qt, QRect, QVariant, QAbstractTableModel, pyqtSlot, pyqtSignal, Qt, QRect, QVariant, QAbstractTableModel, pyqtSlot, pyqtSignal,
@ -17,154 +20,6 @@ from PyQt5.QtWidgets import (
QApplication, 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): class NetworkWindow(ASubWindow):
def __init__(self, title="Network", parent=None): def __init__(self, title="Network", parent=None):
super(NetworkWindow, self).__init__(name=title, ui="Network", parent=parent) 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_widget = GraphWidget(self.graph, parent=self)
self.graph_layout = self.find(QHBoxLayout, "horizontalLayout_graph") self.graph_layout = self.find(QHBoxLayout, "horizontalLayout_graph")
self.graph_layout.addWidget(self.graph_widget) 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 # Nodes table
self.nodes_model = TableModel( self.nodes_model = GraphTableModel(
headers = ["name", "type"], headers = ["name", "type"],
graph = self.graph, graph = self.graph,
rows_type="nodes", rows_type="nodes",
@ -197,7 +46,7 @@ class NetworkWindow(ASubWindow):
# Edges table # Edges table
self.reachs_model = TableModel( self.reachs_model = GraphTableModel(
headers = ["name", "enable", "node1", "node2"], headers = ["name", "enable", "node1", "node2"],
graph = self.graph, graph = self.graph,
rows_type="edges" rows_type="edges"
@ -257,6 +106,11 @@ class NetworkWindow(ASubWindow):
self.graph_widget.reset_selection self.graph_widget.reset_selection
def reverse_edge(self): def reverse_edge(self):
"""Reverse edge direction of selected table rows
Returns:
Nothing
"""
indices = self.find(QTableView, "tableView_reachs").selectionModel().selectedIndexes() indices = self.find(QTableView, "tableView_reachs").selectionModel().selectedIndexes()
indexes = {} indexes = {}

View File

@ -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()