I am using a QStandardItemModel with a QTreeView to display custom Items. The items come in three different types FILTER_TYPE, MODIFIER_TYPE and GROUP_TYPE.
I would like to be able to reorder items within the model using drag and drop in the view (InternalMove). If I understood it correctly, I have to use setItemPrototype(MyItem()) on my model in order for it to use the custom MyItem and not the general QStandardItem when moving items.
My understanding was that a new instance of the custom MyItem gets created and then all data and flags from the old item are copied over to the new item. However, it seems the model only initialises a new MyItem and never copies the data.
Therefore: How do I reimplement QStandardItem.clone() in the MyItem subclass to copy all data and flags into the new item? Do I have to manually go through all the custom data roles and assign their value to the new item?
The Item class looks like this:
class MyItem(QtGui.QStandardItem):
FILTER_TYPE = QtGui.QStandardItem.UserType + 1
MODIFIER_TYPE = QtGui.QStandardItem.UserType + 2
GROUP_TYPE = QtGui.QStandardItem.UserType + 3
TYPE = QtCore.Qt.UserRole + 0
NAME = QtCore.Qt.UserRole + 1
IS_PROCESSED = QtCore.Qt.UserRole + 5
OUTPUT = QtCore.Qt.UserRole + 6
FN = QtCore.Qt.UserRole + 7
DEFAULT_PARAMS = QtCore.Qt.UserRole + 8
PARAMETER_SET = QtCore.Qt.UserRole + 9
def __init__(self):
super().__init__()
self.name = ""
self.full_name = ""
self.description = ""
self.fn = None
self.default_params = None
self.parameter_set = None
self.is_active = True
self.is_processed = False
self.output = None
self.icon = QtGui.QIcon()
def clone(self):
item = Item()
??? WHAT GOES HERE TO COPY ALL DATA AND FLAGS ???
return item
def __setattr__(self, name, value):
if name == 'name':
self.setData(value, self.NAME)
elif name == 'full_name':
self.setData(value, QtCore.Qt.DisplayRole)
self.setData(value, QtCore.Qt.EditRole)
elif name == 'description':
self.setData(value, QtCore.Qt.ToolTipRole)
...
else:
super().__setattr__(name, value)
def __getattribute__(self, name):
if name == 'name':
return self.data(self.NAME)
elif name == 'full_name':
return self.data(QtCore.Qt.DisplayRole)
elif name == 'description':
return self.data(QtCore.Qt.ToolTipRole)
...
else:
return super().__getattribute__(name)
def initializeItem(self, type_, name, full_name, description="", fn=None, default_params=None):
self.name = name
self.full_name = full_name
self.description = description
self.fn = fn
self.default_params = default_params
self.parameter_set = ParameterSet(params_list=default_params)
self.setData(type_, self.TYPE)
flags = QtCore.Qt.ItemIsSelectable|QtCore.Qt.ItemIsDragEnabled|QtCore.Qt.ItemIsUserCheckable|QtCore.Qt.ItemIsEnabled
if type_ == self.FILTER_TYPE:
self.icon = QtGui.QIcon('resources/filter.png')
flags = flags|QtCore.Qt.ItemNeverHasChildren
elif type_ == self.MODIFIER_TYPE:
self.icon = QtGui.QIcon('resources/modifier.png')
flags = flags|QtCore.Qt.ItemIsDropEnabled
elif type_ == self.GROUP_TYPE:
self.icon = QtGui.QIcon('resources/folder.png')
flags = flags|QtCore.Qt.ItemIsDropEnabled|QtCore.Qt.ItemIsEditable
self.setFlags(flags)
def type(self):
return self.data(self.TYPE)
The Model implementation looks like this:
from tree.items import MyItem
class TreeModel(QtGui.QStandardItemModel):
def __init__(self):
super().__init__()
self.setItemPrototype(MyItem())
The logic of "clone" is to create an object with the same information of the item, so in this case you are using the roles to store that information so you must copy all that information in the new item, in this case you can use QDataStream:
def clone(self):
item = MyItem()
ba = QtCore.QByteArray()
ds = QtCore.QDataStream(ba, QtCore.QIODevice.WriteOnly)
ds << self
ds = QtCore.QDataStream(ba)
ds >> item
return item