DragDropTableWidget.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. from PyQt5.QtCore import Qt, QModelIndex
  2. from PyQt5.QtWidgets import QTableWidget, QAbstractItemView, QTableWidgetItem, QTableView
  3. from ui.qt.widgets.sqt.SQTableWidget import SQTableWidget
  4. class DragDropTableWidget(SQTableWidget):
  5. def __init__(self, *args, **kwargs):
  6. QTableWidget.__init__(self, *args, **kwargs)
  7. self.setDragEnabled(True)
  8. self.setAcceptDrops(True)
  9. self.viewport().setAcceptDrops(True)
  10. self.setDragDropOverwriteMode(False)
  11. self.setDropIndicatorShown(True)
  12. self.setSelectionMode(QAbstractItemView.SingleSelection)
  13. self.setSelectionBehavior(QAbstractItemView.SelectRows)
  14. self.setDragDropMode(QAbstractItemView.InternalMove)
  15. def dropEvent(self, event):
  16. if event.source() == self and (event.dropAction() == Qt.MoveAction or self.dragDropMode() == QAbstractItemView.InternalMove):
  17. success, row, col, topIndex = self.dropOn(event)
  18. if success:
  19. selRows = self.getSelectedRowsFast()
  20. top = selRows[0]
  21. # print 'top is %d'%top
  22. dropRow = row
  23. if dropRow == -1:
  24. dropRow = self.rowCount()
  25. # print 'dropRow is %d'%dropRow
  26. offset = dropRow - top
  27. # print 'offset is %d'%offset
  28. for i, row in enumerate(selRows):
  29. r = row + offset
  30. if r > self.rowCount() or r < 0:
  31. r = 0
  32. self.insertRow(r)
  33. # print 'inserting row at %d'%r
  34. selRows = self.getSelectedRowsFast()
  35. # print 'selected rows: %s'%selRows
  36. top = selRows[0]
  37. # print 'top is %d'%top
  38. offset = dropRow - top
  39. # print 'offset is %d'%offset
  40. for i, row in enumerate(selRows):
  41. r = row + offset
  42. if r > self.rowCount() or r < 0:
  43. r = 0
  44. for j in range(self.columnCount()):
  45. # print 'source is (%d, %d)'%(row, j)
  46. # print 'item text: %s'%self.item(row,j).text()
  47. source = QTableWidgetItem(self.item(row, j))
  48. # print 'dest is (%d, %d)'%(r,j)
  49. self.setItem(r, j, source)
  50. # Why does this NOT need to be here?
  51. # for row in reversed(selRows):
  52. # self.removeRow(row)
  53. event.accept()
  54. else:
  55. QTableView.dropEvent(event)
  56. def getSelectedRowsFast(self):
  57. selRows = []
  58. for item in self.selectedItems():
  59. if item.row() not in selRows:
  60. selRows.append(item.row())
  61. return selRows
  62. def droppingOnItself(self, event, index):
  63. dropAction = event.dropAction()
  64. if self.dragDropMode() == QAbstractItemView.InternalMove:
  65. dropAction = Qt.MoveAction
  66. if event.source() == self and event.possibleActions() & Qt.MoveAction and dropAction == Qt.MoveAction:
  67. selectedIndexes = self.selectedIndexes()
  68. child = index
  69. while child.isValid() and child != self.rootIndex():
  70. if child in selectedIndexes:
  71. return True
  72. child = child.parent()
  73. return False
  74. def dropOn(self, event):
  75. if event.isAccepted():
  76. return False, None, None, None
  77. index = QModelIndex()
  78. row = -1
  79. col = -1
  80. if self.viewport().rect().contains(event.pos()):
  81. index = self.indexAt(event.pos())
  82. if not index.isValid() or not self.visualRect(index).contains(event.pos()):
  83. index = self.rootIndex()
  84. if self.model().supportedDropActions() & event.dropAction():
  85. if index != self.rootIndex():
  86. dropIndicatorPosition = self.position(event.pos(), self.visualRect(index), index)
  87. if dropIndicatorPosition == QAbstractItemView.AboveItem:
  88. row = index.row()
  89. col = index.column()
  90. # index = index.parent()
  91. elif dropIndicatorPosition == QAbstractItemView.BelowItem:
  92. row = index.row() + 1
  93. col = index.column()
  94. # index = index.parent()
  95. else:
  96. row = index.row()
  97. col = index.column()
  98. if not self.droppingOnItself(event, index):
  99. # print 'row is %d'%row
  100. # print 'col is %d'%col
  101. return True, row, col, index
  102. return False, None, None, None
  103. def position(self, pos, rect, index):
  104. r = QAbstractItemView.OnViewport
  105. margin = 2
  106. if pos.y() - rect.top() < margin:
  107. r = QAbstractItemView.AboveItem
  108. elif rect.bottom() - pos.y() < margin:
  109. r = QAbstractItemView.BelowItem
  110. elif rect.contains(pos, True):
  111. r = QAbstractItemView.OnItem
  112. if r == QAbstractItemView.OnItem and not (self.model().flags(index) & Qt.ItemIsDropEnabled):
  113. r = QAbstractItemView.AboveItem if pos.y() < rect.center().y() else QAbstractItemView.BelowItem
  114. return r