Problem with special drag'n'drop with QTreeView and custom model



  • I have a custom model derived from QAbstractItemModel. This model implements dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) method.

    Model assigned to the custom view widget, inheritted from QTreeView. Now I want to implement drag'n'drop of the view's items but in special way. First, when items is dragged inside same view, they should be just moved (e.g. to reorder items within tree). But when item dragged outside the view both copy and move actions should be proposed, so the host widget can choose what to do with dropped item (copy or move it).

    First I defined supported drop actions for a model

     Qt::DropActions MyTreeModel::supportedDropActions() const
     {
      return Qt::CopyAction | Qt::MoveAction;
     }
    

    And then reimplement dropEvent() handler in my view

    void MyTreeView::dropEvent(QDropEvent *event)
    {
      // if we dragging in the same view than actually we want to move
      if ( event->source() == this && event->proposedAction() == Qt::CopyAction)
      {
         event->setDropAction(Qt::MoveAction);
      }
      event->accept();
      QTreeView::dropEvent(event);
    

    But it does not works this way. When I drop item inside same view it completely disappeared. What I missed or doing wrong?

    P.S. sorry for my English, it is not my native language.


  • Moderators

    the model implementation is the interesting part here.
    Maybe you also want to read this thread for some clarification.



  • @raven-worx thanks for the reply.
    In my model I already have implemented mimeData(), mimeTypes(), dropMimeData() and supportedDropActions(). Until I tried to implement this special drag'n'drop case all worked fine: in supportedDropActions() i have only Qt::MoveAction and there is no need in the overloaded dropEvent(). Items moved inside view as expected.

    Now I can not figure out how to enable move only inside same view widget and allow both move and copy when dragging items outside view to another view.


  • Moderators

    @voltron
    ok now i think i got you.

    You almost had it. You should rather call event->setDropAction(Qt::MoveAction); in the dragEnter() event handler than in the dropEvent() handler.
    And return copy and move actions in your model.



  • @raven-worx

    thanks a lot for your help and time. I tried to follow your suggestion. In my model both actions are supported, as defined by supportedDropActions() method

    Qt::DropActions MyTreeModel::supportedDropActions() const
    {
      return Qt::CopyAction | Qt::MoveAction;
    }
    

    Also I removed dropEvent() handler from my view and added instead dragEnterEvent() handler with following implementation

    void MyTreeView::dragEnterEvent( QDragEnterEvent * event )
    {
      event->setDropAction( Qt::MoveAction );
      event->accept();
    }
    

    Unfortunatelly this does not works as I want. I can drag items inside my view, but they are copied not moved. Maybe I missed something or misunderstood you?

    The good thing is that I can also copy items to other views. Still need to restrict drag operations to move only when this drag'n'drop happens inside same view.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    It should rather be Qt::InternalMove when you want to move a row inside a view. Since you have a custom model, are you implementing the move related methods ?



  • @SGaist thanks for our reply!
    As I understand Qt::InternalMove forbid moving/copying view items from/to other views. Am I right?

    My model is custom, but it is based on the QAbstractItemModel and all important methods are implemented (e.g. data(), dropMimeData()). Also initially it has support only for moving items because in supportedDropActions() I have only Qt::MoveAction enabled and move operation worked fine. So I think all methods required for moving works.


  • Lifetime Qt Champion

    You can return more than one action in supportedDropActions()



  • @SGaist
    yes, I know. Let me explain again.
    Initially I have custom model where supportedDropActions() returns only Qt::MoveAction, so it is possible only move items when dragging them outside view. This works fine, item dragged and moved nicely to other views and inside same view (reordering).
    But now I want to implement following behavior. When item is dragged and dropped inside view — just move it (reorder). When item moved outside view — allow both operations copy and move. In same time I want to be able to copy/move items in both directions from my custom view to other views and from other views to my custom view.

    It is very easy to allow copy and move operations, just to return corresponding flags in supportedDropActions(). And I have it in my code

    Qt::DropActions MyTreeModel::supportedDropActions() const
    {
      return Qt::CopyAction | Qt::MoveAction;
    }
    

    But if I only change supportedDropActions() I can not move items inside my custom view, they copied. But when dragging items to other views I can choose what to do copy or move.

    There is a Qt::InternalMove flag which looks like a solution. But as I understand Qt::InternalMove forbids moving/copying view items from/to other views. Please correct me if I'm wrong.

    So now i'm looking for solution which will allow me to only move items inside my custom view and in same time move and copy items from/to other views.



  • Well, I found solution. It is very simple, all I need is to set default drop action for my view class as Qt::MoveAction and return copy and move in the suporrtedDropActions().


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.