115 lines
3.7 KiB
Python
115 lines
3.7 KiB
Python
from PyQt5.QtCore import Qt
|
|
from PyQt5.QtGui import QDropEvent
|
|
from PyQt5.QtWidgets import (
|
|
QTableWidget,
|
|
QAbstractItemView,
|
|
QTableWidgetItem,
|
|
QWidget,
|
|
QHBoxLayout,
|
|
QApplication
|
|
)
|
|
|
|
from log import DEBUG
|
|
|
|
|
|
class Playlist(QTableWidget):
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
|
|
self.setDragEnabled(True)
|
|
self.setAcceptDrops(True)
|
|
self.viewport().setAcceptDrops(True)
|
|
self.setDragDropOverwriteMode(False)
|
|
self.setDropIndicatorShown(True)
|
|
|
|
self.setSelectionMode(QAbstractItemView.ExtendedSelection)
|
|
self.setSelectionBehavior(QAbstractItemView.SelectRows)
|
|
self.setDragDropMode(QAbstractItemView.InternalMove)
|
|
|
|
def dropEvent(self, event: QDropEvent):
|
|
if not event.isAccepted() and event.source() == self:
|
|
drop_row = self.drop_on(event)
|
|
|
|
rows = sorted(set(item.row() for item in self.selectedItems()))
|
|
rows_to_move = [
|
|
[QTableWidgetItem(self.item(row_index, column_index)) for
|
|
column_index in range(self.columnCount())]
|
|
for row_index in rows
|
|
]
|
|
for row_index in reversed(rows):
|
|
self.removeRow(row_index)
|
|
if row_index < drop_row:
|
|
drop_row -= 1
|
|
|
|
for row_index, data in enumerate(rows_to_move):
|
|
row_index += drop_row
|
|
self.insertRow(row_index)
|
|
for column_index, column_data in enumerate(data):
|
|
self.setItem(row_index, column_index, column_data)
|
|
event.accept()
|
|
for row_index in range(len(rows_to_move)):
|
|
for column_index in range(self.columnCount()):
|
|
self.item(drop_row + row_index,
|
|
column_index).setSelected(True)
|
|
super().dropEvent(event)
|
|
DEBUG(f"Moved row(s) {rows} to become row {drop_row}")
|
|
|
|
def drop_on(self, event):
|
|
index = self.indexAt(event.pos())
|
|
if not index.isValid():
|
|
return self.rowCount()
|
|
|
|
return (index.row() + 1 if self.is_below(event.pos(), index)
|
|
else index.row())
|
|
|
|
def is_below(self, pos, index):
|
|
rect = self.visualRect(index)
|
|
margin = 2
|
|
if pos.y() - rect.top() < margin:
|
|
return False
|
|
elif rect.bottom() - pos.y() < margin:
|
|
return True
|
|
# noinspection PyTypeChecker
|
|
return (
|
|
rect.contains(pos, True) and not
|
|
(int(self.model().flags(index)) & Qt.ItemIsDropEnabled)
|
|
and pos.y() >= rect.center().y() # noqa W503
|
|
)
|
|
|
|
def set_row_colour(self, row, colour):
|
|
for j in range(self.columnCount()):
|
|
if self.item(row, j):
|
|
self.item(row, j).setBackground(colour)
|
|
|
|
|
|
class Window(QWidget):
|
|
def __init__(self):
|
|
super(Window, self).__init__()
|
|
|
|
layout = QHBoxLayout()
|
|
self.setLayout(layout)
|
|
|
|
self.table_widget = Playlist()
|
|
layout.addWidget(self.table_widget)
|
|
|
|
# setup table widget
|
|
self.table_widget.setColumnCount(2)
|
|
self.table_widget.setHorizontalHeaderLabels(['Type', 'Name'])
|
|
|
|
items = [('Red', 'Toyota'), ('Blue', 'RV'), ('Green', 'Beetle'),
|
|
('Silver', 'Chevy'), ('Black', 'BMW')]
|
|
self.table_widget.setRowCount(len(items))
|
|
for i, (color, model) in enumerate(items):
|
|
self.table_widget.setItem(i, 0, QTableWidgetItem(color))
|
|
self.table_widget.setItem(i, 1, QTableWidgetItem(model))
|
|
|
|
self.resize(400, 400)
|
|
self.show()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
import sys
|
|
app = QApplication(sys.argv)
|
|
window = Window()
|
|
sys.exit(app.exec_())
|