maxLibQt
GroupedItemsProxyModel.cpp
Go to the documentation of this file.
1 /*
2  GroupedItemsProxyModel
3 
4  COPYRIGHT: (c)2017 Maxim Paperno; All Right Reserved.
5  Contact: http://www.WorldDesign.com/contact
6 
7  LICENSE:
8 
9  Commercial License Usage
10  Licensees holding valid commercial licenses may use this file in
11  accordance with the terms contained in a written agreement between
12  you and Maxim Paperno/World Design Group.
13 
14  GNU General Public License Usage
15  Alternatively, this file may be used under the terms of the GNU
16  General Public License as published by the Free Software Foundation,
17  either version 3 of the License, or (at your option) any later version.
18 
19  This program is distributed in the hope that it will be useful,
20  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  GNU General Public License for more details.
23 
24  A copy of the GNU General Public License is available at <http://www.gnu.org/licenses/>.
25 */
26 
27 #include "GroupedItemsProxyModel.h"
28 
29 #include <QDebug>
30 #include <QQueue>
31 
37  m_parentItem(parent),
38  m_sourceIndex(srcIndex),
39  m_isSourceItem(isSrcItem)
40 {
41 }
42 
45 {
46 }
47 
49 {
50  clear();
51 }
52 
54 {
55  qDeleteAll(m_childItems);
56  m_childItems.clear();
57 }
58 
60 {
61  if (parent())
62  return parent()->childRow(const_cast<GroupedProxyItem *>(this));
63 
64  return -1;
65 }
66 
68 {
69  GroupedProxyItem * item = new GroupedProxyItem(srcIndex, isSrcItem, const_cast<GroupedProxyItem *>(this));
70  m_childItems.append(item);
71  return item;
72 }
73 
75 {
76  if (item) {
77  m_childItems.removeAll(item);
78  delete item;
79  }
80 }
81 
83 {
84  m_itemData.insert(role, data);
85  return true;
86 }
87 
89 {
90  bool b = true;
91  for (QMap<int, QVariant>::ConstIterator it = roles.begin(); it != roles.end(); ++it)
92  b = b && setData(it.value(), it.key());
93  return b;
94 }
95 
96 
103  m_root(new GroupedProxyItem()),
105  m_rowsAreMoving(false)
106 {
108 
110  setGroupColumnVisible(true);
111  setGroupColumnIsProxy(false);
113  setGroupRowSelectable(false);
114  setGroupHeaderTitle(tr("Grouping"), tr("This column shows item group information."));
115 
116  if (sourceModel) {
117  setReloadSuspended(!groupColumns.isEmpty());
119  setReloadSuspended(false);
120  if (!groupColumns.isEmpty())
121  setGroups(groupColumns);
122  else
124  }
125 }
126 
128 {
129  delete m_root;
130 }
131 
133 {
134  if (sourceModel()) {
135  disconnect(sourceModel(), 0, this, 0);
136  }
137 
138  QIdentityProxyModel::setSourceModel(newSourceModel);
140 
141  if (sourceModel()) {
147  }
148 }
149 
150 QModelIndex GroupedItemsProxyModel::index(int row, int column, const QModelIndex &parent) const
151 {
152  if (GroupedProxyItem * childItem = itemForIndex(parent, true)->child(row))
153  return indexForItem(childItem, column);
154 
155  return QModelIndex();
156 }
157 
159 {
160  GroupedProxyItem * childItem = itemForIndex(child);
161  if (!childItem)
162  return QModelIndex();
163 
164  GroupedProxyItem * parentItem = childItem->parent();
165  if (!parentItem || parentItem == m_root)
166  return QModelIndex();
167 
168  return indexForItem(parentItem);
169 }
170 
172 {
173  return itemForIndex(parent, true)->rowCount();
174 }
175 
177 {
179 }
180 
182 {
183  return (rowCount(parent) > 0);
184 }
185 
186 QVariant GroupedItemsProxyModel::data(const QModelIndex &index, int role) const
187 {
189  if (!item)
190  return QVariant();
191 
192  if (role == SourceRowNumberRole)
194 
195  if (item->isGroupItem() && index.column() == 0)
196  return sourceModel()->data(item->sourceIndex(), role);
197 
198  if (isProxyColumn(index))
199  return sourceModel()->data(sourceIndexForProxy(item), role);
200 
201  return sourceModel()->data(mapToSource(index), role);
202 }
203 
205 {
207  if (!item)
208  return QMap<int, QVariant>();
209 
210  if (item->isGroupItem() && index.column() == 0)
211  return sourceModel()->itemData(item->sourceIndex());
212 
213  if (isProxyColumn(index))
214  return sourceModel()->itemData(sourceIndexForProxy(item));
215 
217 }
218 
219 QVariant GroupedItemsProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
220 {
221  if (orientation == Qt::Horizontal) {
222  if (extraColumns() && section == 0 && (role == Qt::DisplayRole || role == Qt::ToolTipRole))
223  return m_root->data(role);
224 
225  return sourceModel()->headerData(section - extraColumns(), orientation, role);
226  }
227  if (orientation == Qt::Vertical) {
228  GroupedProxyItem * item = itemForRow(section);
229  if (item && item->isSourceItem())
230  return sourceModel()->headerData(section, orientation, role);
231  }
232  return QVariant();
233 }
234 
236 {
238  if (!item)
239  return Qt::NoItemFlags;
240 
241  if (item->isGroupItem()) {
242  if (groupRowSelectable())
244  else
245  return Qt::ItemIsEnabled;
246  }
247 
248  if (isProxyColumn(index))
249  return (sourceModel()->flags(sourceIndexForProxy(item)) & ~Qt::ItemIsEditable);
250 
251  return sourceModel()->flags(mapToSource(index));
252 }
253 
255 {
257  if (!item)
258  return QSize();
259 
260  if (item->isSourceItem())
261  return sourceModel()->span(mapToSource(index));
262 
263  return QSize(columnCount(), 1);
264 }
265 
267 {
268  return sourceModel()->roleNames();
269 }
270 
272 {
273  GroupedProxyItem * item = itemForIndex(proxyIndex, false);
274  if (item && item->isSourceItem()) {
275  //qDebug() << proxyIndex << item->sourceIndex << sourceModel()->index(item->sourceRow(), proxyIndex.column() - extraColumns());
276  return sourceModel()->index(item->sourceIndex().row(), proxyIndex.column() - extraColumns());
277  }
278 
279  return QModelIndex();
280 }
281 
283 {
284  GroupedProxyItem * item = NULL;
285  if (m_sourceMap.contains(sourceIndex.row()) && (item = m_sourceMap.value(sourceIndex.row()))) {
286  //qDebug() << sourceIndex << indexForItem(item, sourceIndex.column() + extraColumns());
287  return indexForItem(item, sourceIndex.column() + extraColumns());
288  }
289 
290  return QModelIndex();
291 }
292 
294 {
295  if (columns.isEmpty())
296  return;
297  bool prev = setReloadSuspended(true);
298  for (int i : columns)
299  insertGroup(m_groups.size(), i);
300  setReloadSuspended(prev);
302 }
303 
305 {
306  if (columns.isEmpty()) {
307  clearGroups();
308  return;
309  }
310  bool prev = setReloadSuspended(true);
311  clearGroups();
312  addGroups(columns);
313  setReloadSuspended(prev);
315 }
316 
317 void GroupedItemsProxyModel::insertGroup(int index, int column)
318 {
319  index = qBound(0, index, m_groups.size());
320  if (m_groups.indexOf(column) == -1) {
321  m_groups.insert(index, column);
323  }
324 }
325 
327 {
328  if (m_groups.removeAll(column))
330 }
331 
333 {
334  if (m_groups.isEmpty())
335  return;
336  bool prev = setReloadSuspended(true);
337  for (int i : m_groups)
338  removeGroup(i);
339  setReloadSuspended(prev);
341 }
342 
343 void GroupedItemsProxyModel::move(int idx, int pos, int parent)
344 {
345  if (idx != pos && idx >=0 && pos >= 0) {
347  if (!parentItem)
348  return;
349  const QModelIndex pIdx = indexForItem(parentItem);
350  if (!QAbstractItemModel::beginMoveRows(pIdx, idx, idx, pIdx, (idx < pos ? pos + 1 : pos))) {
351  qWarning() << "Invalid move detected:" << "idx" << idx<< "pos" << pos << "pIdx" << pIdx ;
352  return;
353  }
354  parentItem->m_childItems.move(idx, pos);
355  endMoveRows();
356  }
357  qDebug() << "move: idx" << idx << "pos" << pos;
358 
359 // const static int getIdx = sourceModel()->metaObject()->indexOfMethod(QMetaObject::normalizedSignature("move(int,int)"));
360 // // for (int i=0; i < sourceModel()->metaObject()->methodCount(); ++i)
361 // // qDebug() << sourceModel()->metaObject()->method(i).methodSignature() << sourceModel()->metaObject()->method(i).methodIndex();
362 // if (getIdx > -1) {
363 // const int fromIdx = mapToSourceRow(idx);
364 // const int toIdx = mapToSourceRow(pos);
365 // qDebug() << "Move attempt from" << fromIdx << "to" << toIdx << "orig:" << idx << pos << indexForItem(m_defaultParent) << index(idx, 0, indexForItem(m_defaultParent));
366 // if (fromIdx > -1 && toIdx > -1)
367 // sourceModel()->metaObject()->invokeMethod(sourceModel(), "move", Qt::DirectConnection, Q_ARG(int, fromIdx), Q_ARG(int, toIdx));
368 // }
369 // else
370 // qWarning() << "Can't MOVE, source model not compatible" << getIdx;
371 }
372 
373 void GroupedItemsProxyModel::setRootGroup(int column, const QVariant &value)
374 {
375 // if (m_defaultParentGroup = column)
376 // return;
377 
378  GroupedProxyItem *newRoot = nullptr;
379  if (column >= 0 && value.isValid() && m_groups.contains(column)) {
380  newRoot = findGroupItem(column, value, m_root);
381  }
382  if (!newRoot)
383  newRoot = m_root;
384 
385  m_defaultParent = newRoot;
386  m_defaultParentGroup = column;
387 }
388 
390 {
391  if (m_groupMatchRole != role) {
392  m_groupMatchRole = role;
393  if (sourceModel() && !m_groups.isEmpty())
395  }
396 }
397 
398 void GroupedItemsProxyModel::setGroupHeaderTitle(const QString &title, const QString &tooltip) {
399  m_root->setData(title, Qt::DisplayRole);
400  if (!tooltip.isEmpty())
401  m_root->setData(tooltip, Qt::ToolTipRole);
402  else
403  m_root->setData(title, Qt::ToolTipRole);
404  if (extraColumns())
405  emit headerDataChanged(Qt::Horizontal, 0, 0);
406 }
407 
408 
409 //
410 // protected methods
411 //
412 
414 {
415  if (!item || item->row() < 0 || col < 0)
416  return QModelIndex();
417 
418  return createIndex(item->row(), col, item);
419 }
420 
422 {
423  GroupedProxyItem * item;
424  if (index.isValid() && (item = static_cast<GroupedProxyItem *>(index.internalPointer())))
425  return item;
426 // if (m_defaultParentGroup > -1)
427 // return m_defaultParent;
428  if (rootDefault)
429  return m_defaultParent;
430  else
431  return NULL;
432 }
433 
435 {
436  if (!parent)
438  foreach (GroupedProxyItem * item, parent->children()) {
439  if (!item)
440  continue;
441  if (!item->isSourceItem() && item->data(Qt::UserRole).toInt() == group && (!value.isValid() || item->data(Qt::EditRole) == value))
442  return item;
443  else if (item->rowCount() && (item = findGroupItem(group, value, item)))
444  return item;
445  }
446  return NULL;
447 }
448 
450 {
451  QModelIndex srcIdx = item->sourceIndex();
452  if (groupColumnProxySrc() > -1)
453  srcIdx = sourceModel()->index(srcIdx.row(), groupColumnProxySrc(), srcIdx.parent());
454  return srcIdx;
455 }
456 
458 {
459  if (!parent)
461  int count = 0;
462  foreach (GroupedProxyItem * item, parent->children()) {
463  ++count;
464  if (item->isGroupItem())
465  count += totalRowCount(item);
466  }
467  return count;
468 }
469 
471 {
472  GroupedProxyItem * ret = NULL;
473  if (!parent)
476  q.enqueue(parent);
477  int count = 0;
478  while (!q.isEmpty()) {
479  GroupedProxyItem * p = q.dequeue();
480  foreach (GroupedProxyItem * item, p->children()) {
481  if (count++ == row)
482  return item;
483  if (item->rowCount())
484  q.enqueue(item);
485  }
486  }
487  return ret;
488 }
489 
491 {
492  GroupedProxyItem * grpParent = m_root;
493  QModelIndex sourceIndex = sourceModel()->index(row, 0);;
494  for (int col : m_groups) {
495  sourceIndex = sourceModel()->index(row, col);
496  QVariant val = sourceIndex.data(groupMatchRole());
497  GroupedProxyItem * grpItem;
498  if (!(grpItem = findGroupItem(col, val, grpParent))) {
499  if (!m_rowsAreMoving)
500  QAbstractItemModel::beginInsertRows(indexForItem(grpParent), grpParent->rowCount(), grpParent->rowCount());
501  grpItem = grpParent->addChild(sourceIndex, false);
502  grpItem->setData(col, Qt::UserRole);
503  grpItem->setData(val, Qt::EditRole);
504  if (!m_rowsAreMoving)
506  }
507  grpParent = grpItem;
508  }
509  if (!m_rowsAreMoving)
510  QAbstractItemModel::beginInsertRows(indexForItem(grpParent), grpParent->rowCount(), grpParent->rowCount());
511  GroupedProxyItem * newItem = grpParent->addChild(sourceIndex);
512  m_sourceMap.insert(row, newItem);
513  if (!m_rowsAreMoving)
515 
516  return newItem;
517 }
518 
520 {
521  if (!item || !item->parent())
522  return;
523 
524  GroupedProxyItem * parent = item->parent();
525  if (!m_rowsAreMoving)
527  if (item->isSourceItem())
528  m_sourceMap.remove(item->sourceIndex().row());
529  parent->removeChild(item);
530  if (!m_rowsAreMoving)
532 }
533 
535 {
536  if (!parent)
538  foreach (GroupedProxyItem * item, parent->children()) {
539  if (item->isSourceItem())
540  continue;
541  if (item->rowCount())
542  removeUnusedGroups(item);
543  if (!item->rowCount())
544  removeItem(item);
545  }
546 }
547 
549 {
550  if (reloadSuspended())
551  return;
552  beginResetModel();
553  m_root->clear();
554  m_sourceMap.clear();
556  for (int row = 0, e = sourceModel()->rowCount(); row < e; ++row)
557  placeSourceRow(row);
559  endResetModel();
560 }
561 
563 {
565 }
566 
567 void GroupedItemsProxyModel::dataChangedHandler(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
568 {
569  //qDebug() << topLeft << bottomRight << roles;
570  if (!topLeft.isValid() || !bottomRight.isValid() || m_groups.isEmpty() || (!roles.isEmpty() && !roles.contains(groupMatchRole())))
571  return;
572 
573  const QModelIndex & srcParent = topLeft.parent();
574  int endRow = qMin(bottomRight.row(), sourceModel()->rowCount());
575  int startCol = qMax(topLeft.column(), 0);
576  int endCol = qMin(bottomRight.column(), sourceModel()->columnCount() - 1);
577  bool modified = false;
578  for (int row = topLeft.row(); row <= endRow; ++row) {
579  for (int col : m_groups) {
580  if (startCol < col || endCol > col)
581  continue; // not a column we care about
582 
583  const QModelIndex & srcIdx = sourceModel()->index(row, col, srcParent);
584  GroupedProxyItem * currItem = itemForIndex(mapFromSource(srcIdx), false);
585  if (!currItem) {
586  // source model is out of sync (shouldn't happen)
588  return;
589  }
590  GroupedProxyItem * currParent = currItem->parent();
591  GroupedProxyItem * newParent = findGroupItem(col, srcIdx.data(groupMatchRole()));
592  if (newParent && currParent == newParent)
593  continue; // parent group hasn't changed
594 
595  // grouping value has changed
596  removeItem(currItem);
597  placeSourceRow(row);
598  modified = true;
599  break;
600  }
601  }
602  if (modified)
604 }
605 
606 void GroupedItemsProxyModel::rowsInsertedHandler(const QModelIndex &parent, int first, int last)
607 {
608  Q_UNUSED(parent)
609  for (int row = first; row <= last; ++row)
610  placeSourceRow(row);
611 
612  emit countChanged();
613 }
614 
615 void GroupedItemsProxyModel::rowsRemovedHandler(const QModelIndex &parent, int first, int last)
616 {
617  Q_UNUSED(parent)
618  for (int row = first; row <= last; ++row) {
619  GroupedProxyItem * currItem = m_sourceMap.value(row, NULL);
620  if (!currItem || !currItem->parent()) {
621  // source model is out of sync (shouldn't happen)
623  return;
624  }
625  removeItem(currItem);
626  }
628  emit countChanged();
629 }
630 
631 void GroupedItemsProxyModel::rowsMovedHandler(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row)
632 {
633 // m_rowsAreMoving = true;
634 // GroupedProxyItem * firstItem = m_sourceMap.value(start, NULL);
637 // if (!firstItem)
638 // return;
639 // //dataChangedHandler(sourceModel()->index(start, 0, parent), sourceModel()->index(end, 0, parent));
640 // GroupedProxyItem * currParent = firstItem->parent();
641 // const QModelIndex &pIndex = indexForItem(currParent);
642 // const int oldRow = firstItem->row();
643 // const int srcFirst = oldRow;
644 // const int srcLast = oldRow + (end - start);
645 // const int destChild = qMax(srcFirst + (row - start), 0);
646 // qDebug() << "start" << start << "end" << end << "row" << row << "srcFirst" << srcFirst << "srcLast" << srcLast << "destChild" << destChild << "pIndex" << pIndex;
647 // if (!QAbstractItemModel::beginMoveRows(pIndex, srcFirst, srcLast, pIndex, destChild)) {
648 // qWarning() << "Invalid move detected:" << "srcFirst" << srcFirst << "srcLast" << srcLast << "destChild" << destChild << "pIndex" << pIndex;;
649 // return;
650 // }
651  rowsRemovedHandler(parent, start, end);
652  rowsInsertedHandler(destination.parent(), row, row + (end - start));
653 // QAbstractItemModel::endMoveRows();
654 // m_rowsAreMoving = false;
655 }
virtual int rowCount(const QModelIndex &parent) const const=0
GroupedProxyItem(const QModelIndex &srcIndex, const bool isSrcItem=false, GroupedProxyItem *parent=NULL)
GroupedProxyItem.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
virtual GroupedProxyItem * findGroupItem(const int group, const QVariant &value=QVariant(), GroupedProxyItem *parent=NULL) const
QVariant data(const QModelIndex &index, int role=Qt::EditRole) const override
int removeAll(const T &t)
virtual void setSourceModel(QAbstractItemModel *newSourceModel) override
virtual void dataChangedHandler(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector< int > &roles=QVector< int >())
QModelIndex index(int row, int column, const QModelIndex &parent) const override
bool beginMoveRows(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destinationParent, int destinationChild)
void enqueue(const T &t)
virtual QSize span(const QModelIndex &index) const const
int indexOf(const T &value, int from) const const
virtual QMap< int, QVariant > itemData(const QModelIndex &index) const const
virtual void setGroupMatchRole(int role)
virtual QHash< int, QByteArray > roleNames() const const
T dequeue()
const QObjectList & children() const const
void insert(int i, T &&value)
virtual QModelIndex sourceIndexForProxy(GroupedProxyItem *item) const
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
virtual void clearGroups()
Remove the previously-added groupings.
bool setData(const QVariant &data, int role=Qt::EditRole)
bool isValid() const const
void setSourceModel(QAbstractItemModel *newSourceModel) override
virtual void removeUnusedGroups(GroupedProxyItem *parent=NULL)
void rowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row)
bool contains(const T &value) const const
virtual GroupedProxyItem * itemForIndex(const QModelIndex &index, const bool rootDefault=false) const
GroupedItemsProxyModel(QObject *parent=Q_NULLPTR, QAbstractItemModel *sourceModel=Q_NULLPTR, const QVector< int > &groupColumns=QVector< int >())
GroupedItemProxyModel.
int toInt(bool *ok) const const
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector< int > &roles)
void move(int idx, int pos, int parent=-1)
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
bool isEmpty() const const
EditRole
bool isEmpty() const const
void beginRemoveRows(const QModelIndex &parent, int first, int last)
int row() const const
Qt::ItemFlags flags(const QModelIndex &index) const override
void * internalPointer() const const
virtual void setGroupColumnIsProxy(bool enable)
virtual QVariant data(const QModelIndex &index, int role) const const=0
QMap::iterator end()
QModelIndex parent() const const
void rowsRemoved(const QModelIndex &parent, int first, int last)
QMap::iterator begin()
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const const
QModelIndex createIndex(int row, int column, void *ptr) const const
virtual uint extraColumns() const
virtual void removeGroup(int column)
Remove the previously-added column grouping.
QVariant data(int role=Qt::EditRole) const
void beginInsertRows(const QModelIndex &parent, int first, int last)
QAbstractItemModel * sourceModel() const const
virtual void removeItem(GroupedProxyItem *item)
QVariant data(int role) const const
QVector< GroupedProxyItem * > children() const
virtual void addGroups(const QVector< int > &columns)
Add multiple groupings based on columns.
bool isEmpty() const const
virtual void setGroupRowSelectable(bool selectable)
void headerDataChanged(Qt::Orientation orientation, int first, int last)
virtual int columnCount(const QModelIndex &parent) const const=0
virtual void setGroupHeaderTitle(const QString &title, const QString &tooltip=QString())
virtual QModelIndex indexForItem(GroupedProxyItem *item, const int col=0) const
virtual void setGroups(const QVector< int > &columns)
Add multiple groupings based on columns.
QHash< int, GroupedProxyItem * > m_sourceMap
int column() const const
virtual void setGroupColumnVisible(bool visible)
virtual void rowsRemovedHandler(const QModelIndex &parent, int first, int last)
int totalRowCount(GroupedProxyItem *parent=NULL) const
QString tr(const char *s, const char *c, int n)
GroupedProxyItem * m_defaultParent
bool isValid() const const
virtual Qt::ItemFlags flags(const QModelIndex &index) const const
virtual void insertGroup(int index, int column)
Insert a new grouping at index based on column.
GroupedProxyItem * addChild(const QModelIndex &srcIndex, const bool isSrcItem=true)
Vertical
virtual void setRootGroup(int column=-1, const QVariant &value=QVariant())
Sets parent group.
virtual void rowsMovedHandler(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row)
void rowsInserted(const QModelIndex &parent, int first, int last)
virtual bool isProxyColumn(const QModelIndex &index) const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
int size() const const
virtual void rowsInsertedHandler(const QModelIndex &parent, int first, int last)
int columnCount(const QModelIndex &parent=QModelIndex()) const override
bool hasChildren(const QModelIndex &parent=QModelIndex()) const override
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override
bool setItemData(const QMap< int, QVariant > &roles)
virtual GroupedProxyItem * placeSourceRow(const int row)
virtual bool setData(const QModelIndex &index, const QVariant &value, int role) override
QMap< int, QVariant > itemData(const QModelIndex &index) const override
virtual void setGroupColumnProxySrc(int column)
QHash< int, QByteArray > roleNames() const
GroupedProxyItem * itemForRow(int row, GroupedProxyItem *parent=NULL) const
typedef ItemFlags
QSize span(const QModelIndex &index) const override