Hello!

I'm trying to implement a ProxyModel that combines up to 3 existing models (based on QAbstractTableModel). It works mostly, but I have some small problems.

If I use my proxy model directly in a QTableView anything works perfectly. I can add, change and delete entries to any of the models and the QableView updates correctly.

But if I try to use my ProxyModel indirectly through a QSortFilterProxyModel then only adding and changing works correctly. If I delete an entry, the QTableView is not updated correctly.

I'm not sure, if the signals for row removal are passed correctly?

Maybe somebody could take a look at my current implementation?!
What did I wrong?

Any help is appreciated...

Qt Code:
  1. #include <QAbstractProxyModel>
  2. class MergeProxyModel : public QAbstractProxyModel
  3. {
  4. Q_OBJECT
  5. public:
  6. MergeProxyModel(QAbstractTableModel* first_model=0, QAbstractTableModel* second_model=0, QAbstractTableModel* third_model=0, QObject* parent=0);
  7. ~MergeProxyModel();
  8.  
  9. void setColumnCount(int count) { column_count=count; };
  10.  
  11. Qt::ItemFlags flags(const QModelIndex &index) const;
  12. QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const;
  13.  
  14. int rowCount(const QModelIndex &index=QModelIndex()) const;
  15. int columnCount(const QModelIndex &index=QModelIndex()) const;
  16.  
  17. QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
  18. QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
  19.  
  20. QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
  21. QModelIndex parent(const QModelIndex &proxyChild) const;
  22.  
  23. bool indexCheck(const QModelIndex &index) const;
  24.  
  25. int getListNo(const QModelIndex &index) const;
  26. int getListPos(int n) const;
  27. int getListPos(const QModelIndex &index) const;
  28.  
  29. QAbstractTableModel* sourceModel(const QModelIndex &index) const;
  30.  
  31. protected:
  32. int column_count;
  33. int listsCount() const;
  34. int getOffset(const QAbstractItemModel* smodel) const;
  35.  
  36. QAbstractTableModel* first_model;
  37. QAbstractTableModel* second_model;
  38. QAbstractTableModel* third_model;
  39.  
  40. private:
  41. void connectModels(QAbstractTableModel* model);
  42.  
  43. private slots:
  44.  
  45. void dataChangedSlot(const QModelIndex &topLeft, const QModelIndex &bottomRight);
  46.  
  47. void rowsAboutToBeInsertedSlot(const QModelIndex &parent, int first, int last);
  48. void rowsInsertedSlot(const QModelIndex &parent, int first, int last);
  49.  
  50. void rowsAboutToBeRemovedSlot(const QModelIndex &parent, int first, int last);
  51. void rowsRemovedSlot(const QModelIndex &parent, int first, int last);
  52.  
  53. void modelAboutToBeResetSlot();
  54. void modelResetSlot();
  55. };
  56.  
  57. MergeProxyModel::MergeProxyModel(QAbstractTableModel* _first_model,
  58. QAbstractTableModel* _second_model,
  59. QAbstractTableModel* _third_model,
  60. QObject *_parent)
  61. : QAbstractProxyModel(_parent),
  62. column_count(1),
  63. first_model(_first_model),
  64. second_model(_second_model),
  65. third_model(_third_model)
  66. {
  67. if (first_model) connectModels(first_model);
  68. if (second_model) connectModels(second_model);
  69. if (third_model) connectModels(third_model);
  70. }
  71.  
  72. MergeProxyModel::~MergeProxyModel()
  73. {
  74. }
  75.  
  76. void MergeProxyModel::connectModels(QAbstractTableModel* model)
  77. {
  78. Q_ASSERT(model);
  79.  
  80. connect(model, SIGNAL(layoutAboutToBeChanged()), this, SIGNAL(layoutAboutToBeChanged()), Qt::DirectConnection);
  81. connect(model, SIGNAL(layoutChanged()), this, SIGNAL(layoutChanged()), Qt::DirectConnection);
  82.  
  83. connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(dataChangedSlot(QModelIndex,QModelIndex)), Qt::DirectConnection);
  84.  
  85. connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(rowsAboutToBeInsertedSlot(QModelIndex,int,int)), Qt::DirectConnection);
  86. connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInsertedSlot(QModelIndex,int,int)), Qt::DirectConnection);
  87.  
  88. connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(rowsAboutToBeRemovedSlot(QModelIndex,int,int)), Qt::DirectConnection);
  89. connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(rowsRemovedSlot(QModelIndex,int,int)), Qt::DirectConnection);
  90.  
  91. connect(model, SIGNAL(modelAboutToBeReset()), this, SLOT(modelAboutToBeResetSlot()), Qt::DirectConnection);
  92. connect(model, SIGNAL(modelReset()), this, SLOT(modelResetSlot()), Qt::DirectConnection);
  93. }
  94.  
  95. int MergeProxyModel::listsCount() const
  96. {
  97. int totalCount = 0;
  98. if (first_model) totalCount += first_model->rowCount();
  99. if (second_model) totalCount += second_model->rowCount();
  100. if (third_model) totalCount += third_model->rowCount();
  101. return totalCount;
  102. }
  103.  
  104. bool MergeProxyModel::indexCheck(const QModelIndex &index) const
  105. {
  106. return (index.isValid() && index.row() >= 0 && index.row() < rowCount() && index.column() >= 0 && index.column() < columnCount());
  107. }
  108.  
  109. Qt::ItemFlags MergeProxyModel::flags(const QModelIndex &index) const
  110. {
  111. Qt::ItemFlags theFlags = Qt::NoItemFlags;
  112. if (index.isValid()) return QAbstractProxyModel::flags(index);
  113. return theFlags;
  114. }
  115.  
  116. QVariant MergeProxyModel::data(const QModelIndex &index, int role) const
  117. {
  118. if (!indexCheck(index)) return QVariant();
  119.  
  120. switch (getListNo(index))
  121. {
  122. case 0: return first_model->data(mapToSource(index), role);
  123. case 1: return second_model->data(mapToSource(index), role);
  124. case 2: return third_model->data(mapToSource(index), role);
  125. default: return QVariant();
  126. }
  127. return QVariant();
  128. }
  129.  
  130. int MergeProxyModel::rowCount(const QModelIndex &index) const
  131. {
  132. return index.isValid() ? 0 : listsCount();
  133. }
  134.  
  135. int MergeProxyModel::columnCount(const QModelIndex &index) const
  136. {
  137. return index.isValid() ? 0 : column_count;
  138. }
  139.  
  140. int MergeProxyModel::getOffset(const QAbstractItemModel* smodel) const
  141. {
  142. int offset = 0;
  143.  
  144. if (smodel != first_model) {
  145. if (first_model) offset += first_model->rowCount();
  146. if (smodel != second_model) {
  147. if (second_model) offset += second_model->rowCount();
  148. }
  149. }
  150. return offset;
  151. }
  152.  
  153. QModelIndex MergeProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
  154. {
  155. if (!sourceIndex.isValid()) return QModelIndex();
  156. else if (sourceIndex.parent().isValid()) return QModelIndex();
  157.  
  158. int offset = getOffset(sourceIndex.model());
  159. return createIndex(sourceIndex.row() + offset, sourceIndex.column());
  160. }
  161.  
  162. QModelIndex MergeProxyModel::mapToSource(const QModelIndex &proxyIndex) const
  163. {
  164. if (!proxyIndex.isValid()) return QModelIndex();
  165.  
  166. int pos = getListPos(proxyIndex);
  167. QAbstractTableModel* smodel = sourceModel(proxyIndex);
  168. if (!smodel) return QModelIndex();
  169.  
  170. return smodel->index(pos, proxyIndex.column());
  171. }
  172.  
  173. QModelIndex MergeProxyModel::index(int row, int column, const QModelIndex &parent) const
  174. {
  175. if (row >= rowCount()) return QModelIndex();
  176. return createIndex(row, column, getListPos(row));
  177. }
  178.  
  179. QModelIndex MergeProxyModel::parent(const QModelIndex &proxyChild) const
  180. {
  181. return QModelIndex();
  182. }
  183.  
  184. int MergeProxyModel::getListNo(const QModelIndex &index) const
  185. {
  186. if (index.isValid())
  187. {
  188. int n = index.row();
  189. int offset = 0;
  190.  
  191. if (first_model) {
  192. if (n < first_model->rowCount()) return 0;
  193. offset += first_model->rowCount();
  194. }
  195.  
  196. if (second_model) {
  197. if (n-offset < second_model->rowCount()) return 1;
  198. offset += second_model->rowCount();
  199. }
  200.  
  201. if (third_model) {
  202. if (n-offset < third_model->rowCount()) return 2;
  203. }
  204. }
  205. return -1;
  206. }
  207.  
  208. int MergeProxyModel::getListPos(int n) const
  209. {
  210. if (first_model) {
  211. if (n < first_model->rowCount()) return n;
  212. n -= first_model->rowCount();
  213. }
  214.  
  215. if (second_model) {
  216. if (n < second_model->rowCount()) return n;
  217. n -= second_model->rowCount();
  218. }
  219.  
  220. if (third_model) {
  221. if (n < third_model->rowCount()) return n;
  222. }
  223. return -1;
  224. }
  225.  
  226. int MergeProxyModel::getListPos(const QModelIndex &index) const
  227. {
  228. if (index.isValid())
  229. {
  230. int n = index.row();
  231.  
  232. if (first_model) {
  233. if (n < first_model->rowCount()) return n;
  234. n -= first_model->rowCount();
  235. }
  236.  
  237. if (second_model) {
  238. if (n < second_model->rowCount()) return n;
  239. n -= second_model->rowCount();
  240. }
  241.  
  242. if (third_model) {
  243. if (n < third_model->rowCount()) return n;
  244. }
  245. }
  246. return -1;
  247. }
  248.  
  249. QAbstractTableModel* MergeProxyModel::sourceModel(const QModelIndex &index) const
  250. {
  251. switch (getListNo(index))
  252. {
  253. case 0: return first_model;
  254. case 1: return second_model;
  255. case 2: return third_model;
  256. default: return 0;
  257. }
  258. }
  259.  
  260. void MergeProxyModel::dataChangedSlot(const QModelIndex &topLeft, const QModelIndex &bottomRight)
  261. {
  262. const QModelIndex &proxyTopLeft = mapFromSource(topLeft);
  263. const QModelIndex &proxyBottomRight = mapFromSource(bottomRight);
  264. emit dataChanged(proxyTopLeft, proxyBottomRight);
  265. }
  266.  
  267. void MergeProxyModel::rowsAboutToBeInsertedSlot(const QModelIndex &parent, int first, int last)
  268. {
  269. beginInsertRows(parent, first, last);
  270. }
  271.  
  272. void MergeProxyModel::rowsInsertedSlot(const QModelIndex &parent, int first, int last)
  273. {
  274. endInsertRows();
  275. }
  276.  
  277. void MergeProxyModel::rowsAboutToBeRemovedSlot(const QModelIndex &parent, int first, int last)
  278. {
  279. QAbstractTableModel *smodel = qobject_cast<QAbstractTableModel *>(sender());
  280. const int offset = getOffset(smodel);
  281. beginRemoveRows(parent, first + offset, last + offset);
  282. }
  283.  
  284. void MergeProxyModel::rowsRemovedSlot(const QModelIndex &parent, int first, int last)
  285. {
  286. endRemoveRows();
  287. }
  288.  
  289. void MergeProxyModel::modelAboutToBeResetSlot()
  290. {
  291. beginResetModel();
  292. }
  293.  
  294. void MergeProxyModel::modelResetSlot()
  295. {
  296. endResetModel();
  297. }
To copy to clipboard, switch view to plain text mode 

Regards
Sven