diff --git a/archive/DragAndDropReference.py b/archive/DragAndDropReference.py new file mode 100755 index 0000000..7f29c9c --- /dev/null +++ b/archive/DragAndDropReference.py @@ -0,0 +1,190 @@ +#!/usr/bin/python3 +# vim: set expandtab tabstop=4 shiftwidth=4: + +# PyQt Functionality Snippet by Apocalyptech +# "Licensed" in the Public Domain under CC0 1.0 Universal (CC0 1.0) +# Public Domain Dedication. Use it however you like! +# +# https://creativecommons.org/publicdomain/zero/1.0/ +# https://creativecommons.org/publicdomain/zero/1.0/legalcode + +from PyQt6 import QtWidgets, QtCore + + +# class MyModel(QtGui.QStandardItemModel): +class MyModel(QtCore.QAbstractTableModel): + def __init__(self, parent=None): + super().__init__(parent) + + def columnCount(self, parent=None): + return 5 + + def rowCount(self, parent=None): + return 20 + + # def headerData(self, column: int, orientation, role: QtCore.Qt.ItemDataRole): + # return (('Regex', 'Category')[column] + # if role == QtCore.Qt.DisplayRole and orientation == QtCore.Qt.Horizontal + # else None) + + def headerData(self, column, orientation, role): + if role == QtCore.Qt.ItemDataRole.DisplayRole and orientation == QtCore.Qt.Orientation.Horizontal: + return f"{column=}" + return None + + def data(self, index: QtCore.QModelIndex, role: QtCore.Qt.ItemDataRole): + if not index.isValid() or role not in { + QtCore.Qt.ItemDataRole.DisplayRole, + QtCore.Qt.ItemDataRole.EditRole, + }: + return None + # return (self._data[index.row()][index.column()] if index.row() < len(self._data) else + # "edit me" if role == QtCore.Qt.DisplayRole else "") + + # def data(self, index, role): + # if not index.isValid() or role not in [QtCore.Qt.DisplayRole, + # QtCore.Qt.EditRole]: + # return None + # return (self._data[index.row()][index.column()] if index.row() < len(self._data) else + # "edit me" if role == QtCore.Qt.DisplayRole else "") + + row = index.row() + column = index.column() + return f"Row {row}, Col {column}" + + def flags(self, index: QtCore.QModelIndex) -> QtCore.Qt.ItemFlag: + # https://doc.qt.io/qt-5/qt.html#ItemFlag-enum + if not index.isValid(): + return QtCore.Qt.ItemFlag.ItemIsEnabled + if index.row() < 20: + return ( + QtCore.Qt.ItemFlag.ItemIsEnabled + | QtCore.Qt.ItemFlag.ItemIsEditable + | QtCore.Qt.ItemFlag.ItemIsSelectable + | QtCore.Qt.ItemFlag.ItemIsDragEnabled + ) + return QtCore.Qt.ItemFlag.ItemIsEnabled | QtCore.Qt.ItemFlag.ItemIsEditable + + # def flags(self, index): + # if not index.isValid(): + # return QtCore.Qt.ItemIsDropEnabled + # if index.row() < 5: + # return ( + # QtCore.Qt.ItemIsEnabled + # | QtCore.Qt.ItemIsEditable + # | QtCore.Qt.ItemIsSelectable + # | QtCore.Qt.ItemIsDragEnabled + # ) + # return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable + + # def supportedDragOptions(self): + # return QtCore.Qt.MoveAction | QtCore.Qt.CopyAction + + # def supportedDropActions(self) -> bool: + # return QtCore.Qt.MoveAction | QtCore.Qt.CopyAction + + def relocateRow(self, row_source, row_target) -> None: + return + row_a, row_b = max(row_source, row_target), min(row_source, row_target) + self.beginMoveRows( + QtCore.QModelIndex(), row_a, row_a, QtCore.QModelIndex(), row_b + ) + self._data.insert(row_target, self._data.pop(row_source)) + self.endMoveRows() + + def supportedDropActions(self): + return QtCore.Qt.DropAction.MoveAction | QtCore.Qt.DropAction.CopyAction + + # def relocateRow(self, src, dst): + # print("relocateRow") + + # def dropMimeData(self, data, action, row, col, parent): + # """ + # Always move the entire row, and don't allow column "shifting" + # """ + # # return super().dropMimeData(data, action, row, 0, parent) + # print("dropMimeData") + # super().dropMimeData(data, action, row, col, parent) + + +class MyStyle(QtWidgets.QProxyStyle): + def drawPrimitive(self, element, option, painter, widget=None): + """ + Draw a line across the entire row rather than just the column + we're hovering over. This may not always work depending on global + style - for instance I think it won't work on OSX. + """ + if element == QtWidgets.QStyle.PrimitiveElement.PE_IndicatorItemViewItemDrop and not option.rect.isNull(): + option_new = QtWidgets.QStyleOption(option) + option_new.rect.setLeft(0) + if widget: + option_new.rect.setRight(widget.width()) + option = option_new + super().drawPrimitive(element, option, painter, widget) + + +class MyTableView(QtWidgets.QTableView): + def __init__(self, parent): + super().__init__(parent) + self.verticalHeader().hide() + self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.ExtendedSelection) + self.setDragDropMode(QtWidgets.QAbstractItemView.DragDropMode.InternalMove) + self.setDragDropOverwriteMode(False) + self.setAcceptDrops(True) + # self.horizontalHeader().hide() + # self.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch) + # self.setShowGrid(False) + + # Set our custom style - this draws the drop indicator across the whole row + self.setStyle(MyStyle()) + + # Set our custom model - this prevents row "shifting" + # self.model = MyModel() + # self.setModel(self.model) + self.setModel(MyModel()) + + # for (idx, data) in enumerate(['foo', 'bar', 'baz']): + # item_1 = QtGui.QStandardItem('Item {}'.format(idx)) + # item_1.setEditable(False) + # item_1.setDropEnabled(False) + + # item_2 = QtGui.QStandardItem(data) + # item_2.setEditable(False) + # item_2.setDropEnabled(False) + + # self.model.appendRow([item_1, item_2]) + + def dropEvent(self, event): + if event.source() is not self or ( + event.dropAction() != QtCore.Qt.DropAction.MoveAction + and self.dragDropMode() != QtWidgets.QAbstractItemView.InternalMove + ): + super().dropEvent(event) + + from_rows = list(set([a.row() for a in self.selectedIndexes()])) + to_row = self.indexAt(event.position().toPoint()).row() + if ( + 0 <= min(from_rows) <= self.model().rowCount() + and 0 <= max(from_rows) <= self.model().rowCount() + and 0 <= to_row <= self.model().rowCount() + ): + print(f"move_rows({from_rows=}, {to_row=})") + event.accept() + super().dropEvent(event) + + +class Testing(QtWidgets.QMainWindow): + def __init__(self): + super().__init__() + + view = MyTableView(self) + view.setModel(MyModel()) + self.setCentralWidget(view) + self.show() + + +if __name__ == "__main__": + app = QtWidgets.QApplication([]) + test = Testing() + raise SystemExit(app.exec())