I need to be able to copy an item from one listWidget to another. This is easy enough to do but I can't seem to figure out a way to differentiate drop actions based on whether the item being dragged originated in the list it is being dropped to without perhaps having to override almost every drag and drop function with my own. When I drag an item from one list to the other I want to copy it but when I drag the item in the same list I want to move it.
I've been looking into setting the mimetypes but then I have to write my own mouseMoveEvent as a way to perhaps tell where the dragged item is coming from but so far trying this breaks everything. Is it not possible to set a mime type for an item without overriding mouseMoveEvent ?
Since the items I am dragging are customized I have to write my own definition to rebuilt it when it gets moved or copied to the second list. With the default drag functions this all works fine with internal moves. But so far I have not been able to figure out how to use the default drag drop functions when the drag is an internal move and then switch to my custom function to copy the item when the drop is coming from a different list.
import sys
from PyQt4 import QtGui , QtCore
def main():
app = QtGui.QApplication(sys.argv)
w = QtGui.QWidget()
w.resize(250, 150)
w.move(300, 300)
w.setWindowTitle('Simple')
layout=QtGui.QHBoxLayout(w)
dragList=DragDropListWidget()
layout.addWidget(dragList)
dragList.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
dragList.name='dragList'
dragList.populate(['one','two','three'])
dragList2=DragDropListWidget()
dragList2.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
dragList2.name='dragList'
layout.addWidget(dragList2)
w.show()
sys.exit(app.exec_())
class scriptsWidget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self)
self.name=''
self.widget_QHBoxLayout = QtGui.QHBoxLayout(self)
self.widget_QHBoxLayout.setSpacing(0)
self.widget_QHBoxLayout.setContentsMargins(0, 0, 0, 0)
self.name_QLabel = QtGui.QLabel(self)
self.widget_QHBoxLayout.addWidget(self.name_QLabel)
self.user_QLabel = QtGui.QLabel(self)
self.widget_QHBoxLayout.addWidget(self.user_QLabel)
self.widget_QHBoxLayout.setSpacing(0)
self.widget_QHBoxLayout.setContentsMargins(0, 0, 0, 0)
def setName(self,name):
self.name_QLabel.setText(name)
self.name=name
def setUser(self,user):
self.user_QLabel.setText(user)
class customQListWidgetItem(QtGui.QListWidgetItem):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self)
self.name=''
def setName(self,name):
self.name=name
class DragDropListWidget(QtGui.QListWidget):
_drag_info = []
def __init__(self, parent = None):
super(DragDropListWidget, self).__init__(parent)
self.name=''
def dragMoveEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
else:
super(DragDropListWidget, self).dragMoveEvent(event)
def dropEvent(self, event):
if event.mimeData().hasText():
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
links = []
for url in event.mimeData().urls():
links.append(str(url.toLocalFile()))
self.emit(QtCore.SIGNAL("dropped"), links)
else:
event.setDropAction(QtCore.Qt.CopyAction)
items = []
for index in xrange(self.count()):
items.append(self.item(index))
super(DragDropListWidget, self).dropEvent(event)
for index in xrange(self.count()):
if self.item(index) not in items:
self.populateDrop(self.item(index), index, [self.item(index).data(QtCore.Qt.UserRole).toPyObject()])
def populateDrop(self,item,row,items=[]):
for i in items:
widget = scriptsWidget()
widget.setName(i)
widget.setUser('x')
self.takeItem(row)
item = customQListWidgetItem()
item.setName(i)
item.setWhatsThis(i)
data = (i)
item.setData(QtCore.Qt.UserRole, data)
self.insertItem (row, item)
self.setItemWidget(item,widget)
def populate(self,items=[]):
self.clear()
for i in items:
print(i)
widget = scriptsWidget()
widget.setName(i)
widget.setUser('x')
item = customQListWidgetItem()
item.setName(i)
data = (i)
item.setData(QtCore.Qt.UserRole, data)
self.addItem(item)
self.setItemWidget(item,widget)
if __name__ == '__main__':
main()
Well this is what I came up with. I'm setting a class data variable when the item is clicked so I can tell where it came from when the the item is dropped. I tried using a class variable inside DragDropListWidget but for some reason it would only store the local name of the current list.. weird. A global variable also worked but is not desirable.
import sys
from PyQt4 import QtGui , QtCore
def main():
app = QtGui.QApplication(sys.argv)
w = QtGui.QWidget()
w.resize(250, 150)
w.move(300, 300)
w.setWindowTitle('Simple')
layout=QtGui.QHBoxLayout(w)
dragList=DragDropListWidget()
layout.addWidget(dragList)
d=data()
dragList.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
dragList.name='dragList'
dragList.populate(['one','two','three'])
dragList.data=d
dragList2=DragDropListWidget()
dragList2.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
dragList2.name='dragList2'
dragList2.external='dragList2'
dragList2.data=d
layout.addWidget(dragList2)
w.show()
sys.exit(app.exec_())
class data(object):
def __init__(self, parent=None):
self.origin='new'
class scriptsWidget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self)
self.name=''
self.widget_QHBoxLayout = QtGui.QHBoxLayout(self)
self.widget_QHBoxLayout.setSpacing(0)
self.widget_QHBoxLayout.setContentsMargins(0, 0, 0, 0)
self.name_QLabel = QtGui.QLabel(self)
self.widget_QHBoxLayout.addWidget(self.name_QLabel)
self.user_QLabel = QtGui.QLabel(self)
self.widget_QHBoxLayout.addWidget(self.user_QLabel)
self.widget_QHBoxLayout.setSpacing(0)
self.widget_QHBoxLayout.setContentsMargins(0, 0, 0, 0)
def setName(self,name):
self.name_QLabel.setText(name)
self.name=name
def setUser(self,user):
self.user_QLabel.setText(user)
class customQListWidgetItem(QtGui.QListWidgetItem):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self)
self.name=''
self.list=''
def setName(self,name):
self.name=name
class DragDropListWidget(QtGui.QListWidget):
def __init__(self, parent = None):
super(DragDropListWidget, self).__init__(parent)
self._dropping = False
self.itemPressed.connect(self.clicked)
self.data=''
self.name=''
self.external=''
self.internal=False
def clicked(self):
global origin
self.data.origin=self.name
def dragMoveEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
else:
super(DragDropListWidget, self).dragMoveEvent(event)
def dropEvent(self, event):
if event.mimeData().hasText():
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
links = []
for url in event.mimeData().urls():
links.append(str(url.toLocalFile()))
self.emit(QtCore.SIGNAL("dropped"), links)
else:
if self.external is self.name and self.data.origin is not self.name:
print('external')
event.setDropAction(QtCore.Qt.CopyAction)
items = []
for index in xrange(self.count()):
items.append(self.item(index))
print items
super(DragDropListWidget, self).dropEvent(event)
for index in xrange(self.count()):
if self.item(index) not in items:
print(index)
self.populateDrop(self.item(index), index, [self.item(index).data(QtCore.Qt.UserRole).toPyObject()])
else:
print('internal')
event.setDropAction(QtCore.Qt.MoveAction)
super(DragDropListWidget, self).dropEvent(event)
self.data.origin = None
def populateDrop(self,item,row,items=[]):
for i in items:
widget = scriptsWidget()
widget.setName(i)
widget.setUser('x')
self.takeItem(row)
item = customQListWidgetItem()
item.setName(i)
item.setWhatsThis(i)
item.list=self.name
data = (i)
item.setData(QtCore.Qt.UserRole, data)
self.insertItem (row, item)
self.setItemWidget(item,widget)
def populate(self,items=[]):
self.clear()
for i in items:
print(i)
widget = scriptsWidget()
widget.setName(i)
widget.setUser('x')
item = customQListWidgetItem()
item.setName(i)
item.list=self.name
data = (i)
item.setData(QtCore.Qt.UserRole, data)
self.addItem(item)
self.setItemWidget(item,widget)
if __name__ == '__main__':
main()