Results 1 to 1 of 1

Thread: QAbstractItemModel::dropMimeData always passes -1,-1 for row and column for DnD

  1. #1
    Join Date
    Apr 2014
    Posts
    1
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: QAbstractItemModel::dropMimeData always passes -1,-1 for row and column for DnD

    I am trying to build a TreeView where you can reparent and move items around by dragging and dropping rows within the same TreeView. My model is included below. Data is just a struct with parent, children, and a string.

    I've set the properties of the TreeView correctly in mainwindow.cpp.

    But no matter what, when I drag an item to reparent it, dropMimeData is always passes (-1, -1) for it's row and column arguments. If I don't reimplement dropMimeData, the insertRows and removeRows are called in that order, but insertRows is always passed the number of rows that that parent has children. No matter which item I drag and drop, that number always stays the same.

    What I would like is to just know what index is being moved and to where it's being moved (parent/row) when I drag and drop an item internally. It looks like moveRows would be the function that would allow me to do this, but it never seems to be called by anyone.

    My code is supplied below. Thanks in advance.


    mainwindow.cpp
    Qt Code:
    1. ui->treeView->setSelectionMode(QAbstractItemView::SingleSelection);
    2. ui->treeView->setDragEnabled(true);
    3. ui->treeView->setAcceptDrops(true);
    4. ui->treeView->setDropIndicatorShown(true);
    5. ui->treeView->setDragDropMode(QAbstractItemView::InternalMove);
    6. ui->treeView->setModel(new model());
    To copy to clipboard, switch view to plain text mode 

    model.h
    Qt Code:
    1. class model : public QAbstractItemModel
    2. {
    3. public:
    4. model(QObject *parent = 0);
    5. QVariant data(const QModelIndex &index, int role) const;
    6. bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole);
    7. Qt::ItemFlags flags(const QModelIndex &index) const;
    8. QVariant headerData(int selection, Qt::Orientation orientation, int role) const;
    9. int rowCount(const QModelIndex &parent = QModelIndex()) const;
    10. int columnCount(const QModelIndex &parent = QModelIndex()) const;
    11. QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
    12. QModelIndex parent(const QModelIndex &index) const;
    13. bool hasChildren(const QModelIndex &parent = QModelIndex()) const;
    14. Qt::DropActions supportedDropActions() const;
    15. bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
    16. bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex());
    17. bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild);
    18. bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
    19. private:
    20. Data* item;
    21. };
    To copy to clipboard, switch view to plain text mode 

    model.cpp
    Qt Code:
    1. #include "model.h"
    2.  
    3. model::model(QObject *parent) :
    4. {
    5. item = new Data("parent");
    6. for(int i = 0; i < 100; i++) {
    7. QString s = QString("Row %1").arg(i);
    8. Data* child = new Data(s);
    9. child->parent = item;
    10. item->children.append(child);
    11. }
    12. }
    13.  
    14. bool model::setData(const QModelIndex &index, const QVariant &value, int role) {
    15. qDebug() << "setData" << value;
    16. return false;
    17. }
    18.  
    19. bool model::hasChildren(const QModelIndex &parent) const {
    20. Data* d = static_cast<Data*>(parent.internalPointer());
    21. if(!parent.isValid()) {
    22. return true;
    23. }
    24. return d->children.size() > 0;
    25. }
    26.  
    27. QVariant model::data(const QModelIndex &index, int role) const {
    28. if (!index.isValid()) {
    29. return QVariant();
    30. }
    31. if (role != Qt::DisplayRole) {
    32. return QVariant();
    33. }
    34. if(index.column() == 0) {
    35. return QVariant("Hello");
    36. }
    37. if(index.column() == 1) {
    38. Data* d = static_cast<Data*>(index.internalPointer());
    39. return d->data;
    40. }
    41. return QVariant();
    42. }
    43.  
    44. QVariant model::headerData(int selection, Qt::Orientation orientation, int role) const {
    45. if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
    46. if(selection == 0) {
    47. return "";
    48. }
    49. else {
    50. return "Decorator Type";
    51. }
    52. }
    53. return QVariant();
    54. }
    55.  
    56. int model::rowCount(const QModelIndex &parent) const {
    57. if (!parent.isValid()) {
    58. return 1;
    59. }
    60. Data* d = static_cast<Data*>(parent.internalPointer());
    61. return d->children.size();
    62. }
    63.  
    64. int model::columnCount(const QModelIndex& parent) const {
    65. return 2;
    66. }
    67.  
    68. Qt::DropActions model::supportedDropActions() const
    69. {
    70. return Qt::MoveAction;
    71. }
    72.  
    73. Qt::ItemFlags model::flags(const QModelIndex &index) const {
    74. Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index);
    75.  
    76. if (index.isValid()) {
    77. return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
    78. }
    79. else {
    80. return Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled | defaultFlags;
    81. }
    82. }
    83.  
    84. QModelIndex model::index(int row, int column, const QModelIndex &parent) const {
    85. if (!hasIndex(row, column, parent)) {
    86. return QModelIndex();
    87. }
    88. if (!parent.isValid()) {
    89. return createIndex(row, column, item);
    90. }
    91. Data* d = static_cast<Data*>(parent.internalPointer());
    92. return createIndex(row, column, d->children[row]);
    93. }
    94.  
    95. QModelIndex model::parent(const QModelIndex &index) const {
    96. if (!index.isValid()) {
    97. return QModelIndex();
    98. }
    99.  
    100. Data* childItem = static_cast<Data*>(index.internalPointer());
    101.  
    102. if (childItem->parent == NULL) {
    103. return QModelIndex();
    104. }
    105. int row = childItem->parent->children.indexOf(childItem);
    106.  
    107. return createIndex(row, 0, childItem->parent);
    108. }
    109.  
    110. bool model::dropMimeData(const QMimeData *d, Qt::DropAction action, int row, int column, const QModelIndex &parent) {
    111. qDebug() << "dropMimeData: " << row << " " << column;
    112. }
    113.  
    114. bool model::removeRows(int row, int count, const QModelIndex &parent) {
    115. qDebug() << "Remove Rows " << row;
    116. return false;
    117. }
    118.  
    119. bool model::insertRows(int row, int count, const QModelIndex &parent) {
    120. qDebug() << "Insert Rows " << row;
    121. return true;
    122. }
    123.  
    124. bool model::moveRows(const QModelIndex& sourceParent, int sourceRow, int count, const QModelIndex& destinationParent, int destinationChild) {
    125. qDebug() << "sourceRow: " << sourceRow << ", count: " << count << " destinationChild: " << destinationChild;
    126. return true;
    127. }
    To copy to clipboard, switch view to plain text mode 


    Added after 58 minutes:


    Ok I figured out what is going on.

    When I drop I have to be careful that I drop between items, and not on an item.

    Now i have a new problem. insertRows gets called first, so I don't know what rows are being moved, so I have to insert some kind of placeholder Data*. Then removeRows gets called and I'm trying to swap the row that gets removed with the fake one that was inserted and then remove the actual row.

    This seems completely convoluted.

    The second issue is that, for some reason, insertRows gets called twice for every one drag and drop:

    Insert Rows 15
    Insert Rows 16
    Remove Rows 10

    I'm not sure what to do with this.

    I just want to be able to reparent items by dragging them around, but this framework is making that very difficult. Thanks.
    Last edited by golgobot; 2nd April 2014 at 17:00.

Similar Threads

  1. When should QTreeWidget::dropMimeData be called?
    By rainbowgoblin in forum Qt Programming
    Replies: 1
    Last Post: 28th March 2014, 04:33
  2. Derived dropMimeData never called
    By davsa in forum Qt Programming
    Replies: 1
    Last Post: 18th August 2012, 03:49
  3. Replies: 3
    Last Post: 5th May 2011, 14:03
  4. Strange compiler behaviour (compiler passes wrong argument)
    By SasaVilic in forum General Programming
    Replies: 2
    Last Post: 2nd November 2010, 11:36
  5. Signal with pointer passes only the first value
    By Basti300 in forum Qt Programming
    Replies: 2
    Last Post: 14th September 2010, 13:37

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.