I have tried to implement moving rows with by drag and drop in tableview with my custom model. I have read everything I have found regarding this, and I just don't get it to work with tableview. It's working perfectly with listview.

In tableview row is copied correctly, but removerows is not called. What I am missing? If I have to call removerows directly where should I do it. I would like to be able to use the same model with listview and tableview. I feel that I am missing something trivial, but I just don't get what.

Here is simplified example:

Qt Code:
  1. #include <QtGui>
  2. #include "stringlistmodel.h"
  3. #include <QAbstractItemModel>
  4.  
  5. int main(int argc, char *argv[])
  6. {
  7. QApplication app(argc, argv);
  8.  
  9. QStringList numbers;
  10. numbers << "One" << "Two" << "Three" << "Four" << "Five";
  11.  
  12. QAbstractItemModel *model = new StringListModel(numbers);
  13. QTableView *tableView = new QTableView;
  14. QListView *listView = new QListView;
  15. tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);
  16. tableView->setDragEnabled(true);
  17. tableView->setAcceptDrops(true);
  18. tableView->setDropIndicatorShown(true);
  19. tableView->setModel(model);
  20. tableView->setDefaultDropAction(Qt::MoveAction);
  21. tableView->show();
  22. listView->setDragEnabled(true);
  23. listView->setAcceptDrops(true);
  24. listView->setModel(model);
  25. listView->setDefaultDropAction(Qt::MoveAction);
  26. listView->show();
  27. return app.exec();
  28. }
To copy to clipboard, switch view to plain text mode 

This is my model header:

Qt Code:
  1. #ifndef STRINGLISTMODEL_H
  2. #define STRINGLISTMODEL_H
  3.  
  4. #include <QAbstractListModel>
  5. #include <QStringList>
  6. #include <QMimeData>
  7.  
  8. class StringListModel : public QAbstractListModel
  9. {
  10. Q_OBJECT
  11. public:
  12. StringListModel(const QStringList &strings, QObject *parent = 0);
  13. int rowCount(const QModelIndex &parent = QModelIndex()) const;
  14. QVariant data(const QModelIndex &index, int role) const;
  15. QVariant headerData(int section, Qt::Orientation orientation,
  16. int role = Qt::DisplayRole) const;
  17. Qt::ItemFlags flags(const QModelIndex &index) const;
  18. bool setData(const QModelIndex &index, const QVariant &value,
  19. int role = Qt::EditRole);
  20. bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex());
  21. bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex());
  22.  
  23. Qt::DropActions supportedDropActions() const;
  24. QStringList mimeTypes() const;
  25. QMimeData *mimeData(const QModelIndexList &indexes) const;
  26. bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
  27. private:
  28. QStringList stringList;
  29.  
  30. signals:
  31.  
  32. public slots:
  33.  
  34. };
  35.  
  36. #endif // STRINGLISTMODEL_H
To copy to clipboard, switch view to plain text mode 

and this is my model source:
Qt Code:
  1. #include "stringlistmodel.h"
  2. #include <QStringListModel>
  3. #include <QDebug>
  4.  
  5. StringListModel::StringListModel(const QStringList &strings, QObject *parent)
  6. : QAbstractListModel(parent), stringList(strings)
  7. {
  8. }
  9.  
  10. int StringListModel::rowCount(const QModelIndex &parent) const
  11. {
  12. return stringList.count();
  13. }
  14.  
  15. QVariant StringListModel::data(const QModelIndex &index, int role) const
  16. {
  17. if (!index.isValid())
  18. return QVariant();
  19.  
  20. if (index.row() >= stringList.size())
  21. return QVariant();
  22.  
  23. if (role == Qt::DisplayRole || role == Qt::EditRole)
  24. return stringList.at(index.row());
  25. else
  26. return QVariant();
  27. }
  28.  
  29. QVariant StringListModel::headerData(int section, Qt::Orientation orientation,
  30. int role) const
  31. {
  32. if (role != Qt::DisplayRole)
  33. return QVariant();
  34.  
  35. if (orientation == Qt::Horizontal)
  36. return QString("Column %1").arg(section);
  37. else
  38. return QString("Row %1").arg(section);
  39. }
  40.  
  41. Qt::ItemFlags StringListModel::flags(const QModelIndex &index) const
  42. {
  43. Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index);
  44.  
  45. if (index.isValid())
  46. return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
  47. else
  48. return Qt::ItemIsDropEnabled | defaultFlags;
  49. }
  50.  
  51. bool StringListModel::setData(const QModelIndex &index,
  52. const QVariant &value, int role)
  53. {
  54. if (index.isValid() && role == Qt::EditRole) {
  55.  
  56. stringList.replace(index.row(), value.toString());
  57. emit dataChanged(index, index);
  58. return true;
  59. }
  60. return false;
  61. }
  62.  
  63. bool StringListModel::insertRows(int position, int rows, const QModelIndex &parent)
  64. {
  65. beginInsertRows(QModelIndex(), position, position+rows-1);
  66.  
  67. for (int row = 0; row < rows; ++row) {
  68. stringList.insert(position, "");
  69. }
  70.  
  71. endInsertRows();
  72. return true;
  73. }
  74.  
  75. bool StringListModel::removeRows(int position, int rows, const QModelIndex &parent)
  76. {
  77. beginRemoveRows(QModelIndex(), position, position+rows-1);
  78.  
  79. for (int row = 0; row < rows; ++row) {
  80. stringList.removeAt(position);
  81. }
  82.  
  83. endRemoveRows();
  84. return true;
  85. }
  86.  
  87. Qt::DropActions StringListModel::supportedDropActions() const
  88. {
  89. return Qt::CopyAction | Qt::MoveAction;
  90. }
  91.  
  92. QStringList StringListModel::mimeTypes() const
  93. {
  94. QStringList types;
  95. types << "application/vnd.text.list";
  96. return types;
  97. }
  98.  
  99. QMimeData *StringListModel::mimeData(const QModelIndexList &indexes) const
  100. {
  101. QMimeData *mimeData = new QMimeData();
  102. QByteArray encodedData;
  103.  
  104. QDataStream stream(&encodedData, QIODevice::WriteOnly);
  105.  
  106. foreach (const QModelIndex &index, indexes) {
  107. if (index.isValid()) {
  108. QString text = data(index, Qt::DisplayRole).toString();
  109. stream << text;
  110. }
  111. }
  112.  
  113. mimeData->setData("application/vnd.text.list", encodedData);
  114. return mimeData;
  115. }
  116.  
  117. bool StringListModel::dropMimeData(const QMimeData *data,
  118. Qt::DropAction action, int row, int column, const QModelIndex &parent)
  119. {
  120. qDebug() << action;
  121. if (action == Qt::IgnoreAction)
  122. return true;
  123.  
  124. if (!data->hasFormat("application/vnd.text.list"))
  125. return false;
  126.  
  127. if (column > 0)
  128. return false;
  129. int beginRow;
  130.  
  131. if (row != -1)
  132. beginRow = row;
  133. else if (parent.isValid())
  134. beginRow = parent.row();
  135. else
  136. beginRow = rowCount(QModelIndex());
  137. QByteArray encodedData = data->data("application/vnd.text.list");
  138. QDataStream stream(&encodedData, QIODevice::ReadOnly);
  139. QStringList newItems;
  140. int rows = 0;
  141.  
  142. while (!stream.atEnd()) {
  143. QString text;
  144. stream >> text;
  145. newItems << text;
  146. ++rows;
  147. }
  148. insertRows(beginRow, rows, QModelIndex());
  149. foreach (const QString &text, newItems) {
  150. QModelIndex idx = index(beginRow, 0, QModelIndex());
  151. setData(idx, text);
  152. beginRow++;
  153. }
  154.  
  155. return true;
  156. }
To copy to clipboard, switch view to plain text mode