mike
mike

Reputation: 1322

Qt Drag and Drop Treeview : what am I missing

I have a standard treeview which is viewing a subclass of QStandardItemModel.

The items in the model are also subclassed form QStandardItem. The items have an additional object pointer which I use to store a pointer to an instance of my data class, a "stage" (itself a QObject). All items have either a pointer to a stage or subclass of it, or a NULL pointer in the _object.

class MyStandardItem : public QStandardItem
{  
  public:
  MyStandardItem();
  MyStandardItem(const QString &text);
  MyStandardItem(const QIcon &icon, const QString &text);

  ~MyStandardItem();        
  void object(QObject *object) {_object = object;}
  QObject *object(){return _object;}
private:
  QObject *_object;
};

I want to move items around in the treeview, subject to some restrictions. I have given the treeview the correct policies:

view->setAcceptDrops(true);
view->setDragEnabled(true);
view->setDropIndicatorShown(true);
view->setDragDropMode(QAbstractItemView::InternalMove);

And in my model I provide the following:

Qt::DropActions MyStandardItemModel::supportedDropActions() const
{
 return Qt::MoveAction;
}

Qt::ItemFlags MyStandardItemModel::flags(const QModelIndex &index) const
{
 Qt::ItemFlags defaultFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;

 MyStandardItem *item = dynamic_cast<MyStandardItem*>(itemFromIndex(index));

 if(!item || !item->object())
 {
   return defaultFlags;
 }
 Stage *stage = dynamic_cast<Stage*>(item->object());  
 switch (stage->type())
 {
     case Stage::STAGEA:
     return Qt::ItemIsDropEnabled | defaultFlags;
     break;
     case Stage::STAGEB:
     case Stage::STAGEC:       

     return Qt::ItemIsDragEnabled | defaultFlags;            
     break;
   }
   return defaultFlags;
 }

The dragging behaviour looks ok. But when I then click on a dragged item in the treeview, the object pointer of the selected item is junk:

void Project::model_clicked(const QModelIndex& index)
{
    MyStandardItem *item = static_cast<MyStandardItem*>(_tree_model->itemFromIndex(index));
    if(!item || !item->isValid())
      return;
    QObject *object = item->object();
    if(!object)
      return;
    // object is junk
    Stage *stage = static_cast<Stage*>(object);  
    // and of course stage is junk
}

do I need to implement dropMimeData or something similarly special for the drop for my subclassed MyStandardItem? Since I'm only moving I expected the object pointers to be intact. If I do need to implement dropMimeData, what is the mimetype of the dragged data? I know I can see it using the model selection, but logically I should be able to get the data from the mimedata. Your help most appreciated!

Upvotes: 1

Views: 1691

Answers (1)

mike
mike

Reputation: 1322

Well I found the answer to my own question.

the data is "moved" by Qt inserting into the required position in the model and then deleting it.

This means it is necessary to implement a clone() member to be used by dropMimeData (which must be reimplemented too as far as I can see)

This means widgets must be stored as pointers within objects to allow easy movement within the tree (otherwise the data has to be manually copied between widgets as there's no default copy for QObjects (by design)

Upvotes: 2

Related Questions