summaryrefslogtreecommitdiff
path: root/src/main/python/utils/streamTable.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/python/utils/streamTable.py')
-rw-r--r--src/main/python/utils/streamTable.py183
1 files changed, 183 insertions, 0 deletions
diff --git a/src/main/python/utils/streamTable.py b/src/main/python/utils/streamTable.py
new file mode 100644
index 0000000..acccdee
--- /dev/null
+++ b/src/main/python/utils/streamTable.py
@@ -0,0 +1,183 @@
+from PyQt5.QtCore import Qt, QSize, QRect, QPoint, QAbstractTableModel, pyqtSignal, QModelIndex
+from PyQt5.QtGui import QBrush, QPen, QColor, QCursor
+from PyQt5.QtWidgets import QTableView, QMenu, QGraphicsRectItem, QInputDialog, QStyledItemDelegate, QHeaderView
+
+from collections import defaultdict
+
+class streamTableModel(QAbstractTableModel):
+ updateEvent = pyqtSignal()
+
+ def __init__(self, parent, list, header, *args):
+ super(streamTableModel, self).__init__(parent, *args)
+ self.list = list
+ self.header = header
+
+ def columnCount(self, parent=None):
+ return len(self.list)
+
+ def rowCount(self, parent=None):
+ return len(self.header)
+
+ def data(self, index, role):
+ if role == Qt.TextAlignmentRole:
+ return Qt.AlignHCenter
+ if role == Qt.BackgroundColorRole:
+ return Qt.white
+ if not index.isValid():
+ return None
+ elif role != Qt.DisplayRole:
+ return None
+ if index.row() == 0:
+ return self.list[index.column()].toPlainText()
+ else:
+ return self.list[index.column()].values[self.header[index.row()]]
+
+ def setData(self, index, value, role):
+ if not index.isValid():
+ return False
+ elif role != Qt.EditRole:
+ return False
+ if index.row() == 0:
+ self.list[index.column()].setPlainText(value)
+ else:
+ self.list[index.column()].values[self.header[index.row()]] = value
+ return True
+
+ def insertColumn(self, int=None, item=None):
+ int = int if int else self.rowCount()+1
+ self.beginInsertColumns(QModelIndex(), int, int)
+ self.list.insert(int, item)
+ self.endInsertColumns()
+ self.updateEvent.emit()
+
+ def insertRow(self, int=None, name="newVal"):
+ self.beginInsertRows(QModelIndex(), int, int)
+ self.header.insert(int, name)
+ self.endInsertRows()
+ self.updateEvent.emit()
+
+ def deleteRow(self, row):
+ self.beginRemoveRows(QModelIndex(), row, row)
+ valName = self.header.pop(row)
+ self.endRemoveRows()
+ for i in self.list:
+ i.values.pop(valName)
+ self.updateEvent.emit()
+
+ def headerData(self, col, orientation, role):
+ if orientation == Qt.Vertical and role == Qt.DisplayRole:
+ return self.header[col]
+ return None
+
+ def flags(self, index):
+ return (super(streamTableModel, self).flags(index) | Qt.ItemIsEditable)
+
+class streamTable(QTableView):
+
+ def __init__(self, itemLabels=[], canvas=None, parent=None):
+ super(streamTable, self).__init__(parent=parent)
+ self.canvas = canvas
+ for i in itemLabels:
+ i.nameChanged.connect(self.repaint)
+ header = ["name", "val1", "val2", "val3", "val4", "val5"]
+ self.model = streamTableModel(self, itemLabels, header)
+ self.setShowGrid(False)
+
+ self.horizontalHeader().hide()
+ header = verticalHeader(Qt.Vertical, self)
+ self.setVerticalHeader(header)
+ header.labelChangeRequested.connect(self.labelChange)
+
+ self.setModel(self.model)
+ self.borderThickness = defaultdict(lambda: False)
+ self.model.updateEvent.connect(self.resizeHandler)
+
+ self.setItemDelegateForRow(0, drawBorderDelegate(self))
+
+ def mousePressEvent(self, event):
+ if event.button() == Qt.RightButton:
+ point = event.pos()
+ # col = self.getCol(point.x())
+ index = self.indexAt(point)
+ menu = QMenu("Context Menu", self)
+ menu.addAction("Toggle bottom border thickness", lambda x=index.row(): self.changeRowBorder(x))
+ menu.addAction("Insert Row to bottom", lambda x=index.row(): self.insertRowBottom(x))
+ menu.addAction("Delete row", lambda x=index.row(): self.model.deleteRow(x))
+ menu.exec_(self.mapToGlobal(point)+ QPoint(20, 25))
+ event.accept()
+ return super(streamTable, self).mousePressEvent(event)
+
+ def changeRowBorder(self, row):
+ if self.borderThickness[row]:
+ self.borderThickness[row] = False
+ self.setItemDelegateForRow(row, QStyledItemDelegate(self))
+ else:
+ self.borderThickness[row] = True
+ self.setItemDelegateForRow(row, drawBorderDelegate(self))
+
+ def labelChange(self, index):
+ newName, bool = QInputDialog.getText(self, "Change Property Name", "Enter new name",
+ text = self.model.header[index])
+ if bool:
+ for i in self.model.list:
+ i.values[newName] = i.values.pop(self.model.header[index])
+ self.model.header[index] = newName
+ self.repaint()
+
+ def insertRowBottom(self, row):
+ name, bool = QInputDialog.getText(self, "New Property", "Enter name",
+ text = "newVal")
+ if bool:
+ self.model.insertRow(row + 1, name)
+ self.repaint()
+
+ def resizeHandler(self):
+ self.resize(self.sizeHint())
+
+ def sizeHint(self):
+ return self.rect().size()
+
+ def rect(self):
+ w = self.verticalHeader().width() + 4
+ for i in range(self.model.columnCount()):
+ w += self.columnWidth(i)
+ h = 0
+ for i in range(self.model.rowCount()):
+ h += self.rowHeight(i)
+ return QRect(0, 0, w, h)
+
+class drawBorderDelegate(QStyledItemDelegate):
+
+ # def __init__(self, parent):
+ # super(drawBorderDelegate, self).__init__(parent)
+
+ def paint(self, painter, option, index):
+ rect = option.rect
+ painter.drawLine(rect.bottomLeft(), rect.bottomRight())
+ painter.setPen(QPen(Qt.black, 1, Qt.SolidLine))
+ super(drawBorderDelegate, self).paint(painter, option, index)
+
+class moveRect(QGraphicsRectItem):
+
+ def __init__(self, sideLength = 15, *args):
+ super(moveRect, self).__init__(-sideLength, -sideLength, sideLength, sideLength)
+ self.setBrush(Qt.transparent)
+ self.setPen(QPen(Qt.transparent))
+ self.setCursor(QCursor(Qt.SizeAllCursor))
+ self.setAcceptHoverEvents(True)
+
+ def hoverEnterEvent(self, event):
+ self.setBrush(QBrush(QColor(0, 0, 0, 120)))
+ return super(moveRect, self).hoverEnterEvent(event)
+
+ def hoverLeaveEvent(self, event):
+ self.setBrush(QBrush(QColor(0, 0, 0, 0)))
+ return super(moveRect, self).hoverLeaveEvent(event)
+
+class verticalHeader(QHeaderView):
+ labelChangeRequested = pyqtSignal(int)
+
+ def mouseDoubleClickEvent(self, event):
+ index = self.logicalIndexAt(event.pos())
+ self.labelChangeRequested.emit(index)
+ return super().mouseDoubleClickEvent(event) \ No newline at end of file