Hi,

I have a QListView which shows data from a custom model which is based on QAbstractListModel.

Now I want that the user can reorder the items via drag & drop. To achive that I set movment to Snap, dragAndDropMode to InternalMove and defaultDropAction to Move.

I also reimplemented some methods of the model to enable drag and drop funcationality (see the code above).

There are two problems:
- When moving an item via drag & drop it gets inserted properly at the new position (and the data is properly set as well), but the old item at the old position gets not removed properly. removeRow() is called, but row is according to the debugger and the result I see always 2. Has anybody an idea why where this problem comes from?

- It is possible to drop an item over another item. This works. The old item gets removed and the data of the "target item" is set correctly. But I don't want that behaviour. I want to disable the possibility of droping an item over another item. I just want the possiblity to reorder the items.

Here is my code. I added some comments.

Qt Code:
  1. QVariant FieldModel::data(const QModelIndex &index, int role) const
  2. {
  3. if(index.isValid() && index.row() < m_fields.size()) {
  4. switch(role) {
  5. case Qt::DisplayRole:
  6. return fieldName(m_fields.at(index.row()).first);
  7. case Qt::CheckStateRole:
  8. return m_fields.at(index.row()).second ? Qt::Checked : Qt::Unchecked;
  9. case fieldRole:
  10. return m_fields.at(index.row()).first;
  11. default:
  12. ;
  13. }
  14. }
  15. return QVariant();
  16. }
  17.  
  18. bool FieldModel::setData(const QModelIndex &index, const QVariant &value, int role)
  19. {
  20. bool success = false;
  21. if(index.isValid() && index.row() < m_fields.size()) {
  22. switch(role) {
  23. case Qt::CheckStateRole:
  24. if(value.canConvert(QMetaType::Int)) {
  25. m_fields[index.row()].second = value.toInt() == Qt::Checked;
  26. success = true;
  27. }
  28. break;
  29. case fieldRole:
  30. if(value.canConvert(QMetaType::Int)) {
  31. m_fields[index.row()].first = value.toInt();
  32. success = true;
  33. }
  34. break;
  35. default:
  36. ;
  37. }
  38. }
  39. if(success) {
  40. dataChanged(index, index, QVector<int>() << role);
  41. }
  42. return success;
  43. }
  44.  
  45. // I'm using an user role. I reimplemented itemData to return data for that role as well.
  46. QMap<int, QVariant> FieldModel::itemData(const QModelIndex &index) const
  47. {
  48. QMap<int, QVariant> roles;
  49. for (int i = 0; i <= fieldRole; ++i) {
  50. QVariant variantData = data(index, i);
  51. if (variantData.isValid())
  52. roles.insert(i, variantData);
  53. }
  54. return roles;
  55. }
  56.  
  57. bool FieldModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles)
  58. {
  59. for (QMap<int, QVariant>::ConstIterator it = roles.constBegin(); it != roles.constEnd(); ++it)
  60. setData(index, it.value(), it.key());
  61. return true;
  62. // the default implementation (from qabstractitemmodel.cpp)
  63. // bool b = true;
  64. // for (QMap<int, QVariant>::ConstIterator it = roles.begin(); it != roles.end(); ++it)
  65. // b = b && setData(index, it.value(), it.key()); // does not call setData() after setData() returned once false -> thats why I reimplemented the method
  66. // return b;
  67. }
  68.  
  69. Qt::DropActions FieldModel::supportedDropActions() const
  70. {
  71. return Qt::MoveAction;
  72. }
  73.  
  74. Qt::DropActions FieldModel::supportedDragActions() const
  75. {
  76. return Qt::MoveAction;
  77. }
  78.  
  79. bool FieldModel::insertRows(int row, int count, const QModelIndex &parent)
  80. {
  81. if(parent.isValid())
  82. return false;
  83.  
  84. beginInsertRows(parent, row, 0);
  85. for(int index = row, end = row + count; index < end; ++index) {
  86. m_fields.insert(index, p(KnownField::Invalid, false));
  87. }
  88. endInsertRows();
  89. return true;
  90. }
  91.  
  92. // since the model has only one column is don't think I need to do here more
  93. bool FieldModel::insertColumns(int , int , const QModelIndex &)
  94. {
  95. return false;
  96. }
  97.  
  98. bool FieldModel::removeRows(int row, int count, const QModelIndex &parent)
  99. {
  100. // row is always 2 when this method is called
  101. if(parent.isValid())
  102. return false;
  103.  
  104. if(count) {
  105. beginRemoveRows(parent, row, row + count - 1);
  106. for(int index = row, end = row + count; index < end; ++index) {
  107. m_fields.removeAt(index);
  108. }
  109. endRemoveRows();
  110. }
  111. return true;
  112. }
  113.  
  114. // since the model has only one column is don't think I need to do here more
  115. bool FieldModel::removeColumns(int , int , const QModelIndex &)
  116. {
  117. return false;
  118. }
To copy to clipboard, switch view to plain text mode 

Thanks for helping.