Marble

kdescendantsproxymodel.cpp
1 /*
2  SPDX-FileCopyrightText: 2009 Stephen Kelly <[email protected]>
3  SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB a KDAB Group company <[email protected]>
4  SPDX-FileContributor: Stephen Kelly <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "kdescendantsproxymodel.h"
10 
11 #include <QStringList>
12 #include <QTimer>
13 
14 #include "kbihash_p.h"
15 
16 namespace Marble
17 {
18 
19 typedef KHash2Map<QPersistentModelIndex, int> Mapping;
20 
21 class KDescendantsProxyModelPrivate
22 {
23  KDescendantsProxyModelPrivate(KDescendantsProxyModel *qq)
24  : q_ptr(qq),
25  m_rowCount(0),
26  m_ignoreNextLayoutAboutToBeChanged(false),
27  m_ignoreNextLayoutChanged(false),
28  m_relayouting(false),
29  m_displayAncestorData(false),
30  m_ancestorSeparator(QStringLiteral(" / "))
31  {
32  }
33 
34  Q_DECLARE_PUBLIC(KDescendantsProxyModel)
35  KDescendantsProxyModel *const q_ptr;
36 
37  mutable QVector<QPersistentModelIndex> m_pendingParents;
38 
39  void scheduleProcessPendingParents() const;
40  void processPendingParents();
41 
42  void synchronousMappingRefresh();
43 
44  void updateInternalIndexes(int start, int offset);
45 
46  void resetInternalData();
47 
48  void sourceRowsAboutToBeInserted(const QModelIndex &, int, int);
49  void sourceRowsInserted(const QModelIndex &, int, int);
50  void sourceRowsAboutToBeRemoved(const QModelIndex &, int, int);
51  void sourceRowsRemoved(const QModelIndex &, int, int);
52  void sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int);
53  void sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
54  void sourceModelAboutToBeReset();
55  void sourceModelReset();
56  void sourceLayoutAboutToBeChanged();
57  void sourceLayoutChanged();
58  void sourceDataChanged(const QModelIndex &, const QModelIndex &);
59  void sourceModelDestroyed();
60 
61  Mapping m_mapping;
62  int m_rowCount;
63  QPair<int, int> m_removePair;
64  QPair<int, int> m_insertPair;
65 
66  bool m_ignoreNextLayoutAboutToBeChanged;
67  bool m_ignoreNextLayoutChanged;
68  bool m_relayouting;
69 
70  bool m_displayAncestorData;
71  QString m_ancestorSeparator;
72 
73  QList<QPersistentModelIndex> m_layoutChangePersistentIndexes;
74  QModelIndexList m_proxyIndexes;
75 };
76 
77 void KDescendantsProxyModelPrivate::resetInternalData()
78 {
79  m_rowCount = 0;
80  m_mapping.clear();
81  m_layoutChangePersistentIndexes.clear();
82  m_proxyIndexes.clear();
83 }
84 
85 void KDescendantsProxyModelPrivate::synchronousMappingRefresh()
86 {
87  m_rowCount = 0;
88  m_mapping.clear();
89  m_pendingParents.clear();
90 
91  m_pendingParents.append(QModelIndex());
92 
93  m_relayouting = true;
94  while (!m_pendingParents.isEmpty()) {
95  processPendingParents();
96  }
97  m_relayouting = false;
98 }
99 
100 void KDescendantsProxyModelPrivate::scheduleProcessPendingParents() const
101 {
102  const_cast<KDescendantsProxyModelPrivate *>(this)->processPendingParents();
103 }
104 
105 void KDescendantsProxyModelPrivate::processPendingParents()
106 {
108  const QVector<QPersistentModelIndex>::iterator begin = m_pendingParents.begin();
110 
111  const QVector<QPersistentModelIndex>::iterator end = m_pendingParents.end();
112 
113  QVector<QPersistentModelIndex> newPendingParents;
114 
115  while (it != end && it != m_pendingParents.end()) {
116  const QModelIndex sourceParent = *it;
117  if (!sourceParent.isValid() && m_rowCount > 0) {
118  // It was removed from the source model before it was inserted.
119  it = m_pendingParents.erase(it);
120  continue;
121  }
122  const int rowCount = q->sourceModel()->rowCount(sourceParent);
123 
124  Q_ASSERT(rowCount > 0);
125  const QPersistentModelIndex sourceIndex = q->sourceModel()->index(rowCount - 1, 0, sourceParent);
126 
127  Q_ASSERT(sourceIndex.isValid());
128 
129  const QModelIndex proxyParent = q->mapFromSource(sourceParent);
130 
131  Q_ASSERT(sourceParent.isValid() == proxyParent.isValid());
132  const int proxyEndRow = proxyParent.row() + rowCount;
133  const int proxyStartRow = proxyEndRow - rowCount + 1;
134 
135  if (!m_relayouting) {
136  q->beginInsertRows(QModelIndex(), proxyStartRow, proxyEndRow);
137  }
138 
139  updateInternalIndexes(proxyStartRow, rowCount);
140  m_mapping.insert(sourceIndex, proxyEndRow);
141  it = m_pendingParents.erase(it);
142  m_rowCount += rowCount;
143 
144  if (!m_relayouting) {
145  q->endInsertRows();
146  }
147 
148  for (int sourceRow = 0; sourceRow < rowCount; ++sourceRow) {
149  static const int column = 0;
150  const QModelIndex child = q->sourceModel()->index(sourceRow, column, sourceParent);
151  Q_ASSERT(child.isValid());
152 
153  if (q->sourceModel()->hasChildren(child)) {
154  Q_ASSERT(q->sourceModel()->rowCount(child) > 0);
155  newPendingParents.append(child);
156  }
157  }
158  }
159  m_pendingParents += newPendingParents;
160  if (!m_pendingParents.isEmpty()) {
161  processPendingParents();
162  }
163 // scheduleProcessPendingParents();
164 }
165 
166 void KDescendantsProxyModelPrivate::updateInternalIndexes(int start, int offset)
167 {
168  // TODO: Make KHash2Map support key updates and do this backwards.
170  {
171  Mapping::right_iterator it = m_mapping.rightLowerBound(start);
172  const Mapping::right_iterator end = m_mapping.rightEnd();
173 
174  while (it != end) {
175  updates.insert(it.key() + offset, *it);
176  ++it;
177  }
178  }
179 
180  {
183 
184  for (; it != end; ++it) {
185  m_mapping.insert(it.value(), it.key());
186  }
187  }
188 
189 }
190 
192  : QAbstractProxyModel(parent), d_ptr(new KDescendantsProxyModelPrivate(this))
193 {
194 }
195 
197 {
198  delete d_ptr;
199 }
200 
201 #if 0
203 {
204  Q_UNUSED(index)
205 }
206 #endif
207 
208 QModelIndexList KDescendantsProxyModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const
209 {
210  return QAbstractProxyModel::match(start, role, value, hits, flags);
211 }
212 
214 {
216  d->m_displayAncestorData = display;
217 }
218 
220 {
222  return d->m_displayAncestorData;
223 }
224 
226 {
228  d->m_ancestorSeparator = separator;
229 }
230 
232 {
234  return d->m_ancestorSeparator;
235 }
236 
238 {
240 
241  beginResetModel();
242 
243  static const char *const modelSignals[] = {
244  SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
245  SIGNAL(rowsInserted(QModelIndex,int,int)),
246  SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
247  SIGNAL(rowsRemoved(QModelIndex,int,int)),
248  SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
249  SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
250  SIGNAL(modelAboutToBeReset()),
251  SIGNAL(modelReset()),
253  SIGNAL(layoutAboutToBeChanged()),
254  SIGNAL(layoutChanged()),
255  SIGNAL(destroyed())
256  };
257  static const char *const proxySlots[] = {
258  SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int)),
259  SLOT(sourceRowsInserted(QModelIndex,int,int)),
260  SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int)),
261  SLOT(sourceRowsRemoved(QModelIndex,int,int)),
262  SLOT(sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
263  SLOT(sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)),
264  SLOT(sourceModelAboutToBeReset()),
265  SLOT(sourceModelReset()),
266  SLOT(sourceDataChanged(QModelIndex,QModelIndex)),
267  SLOT(sourceLayoutAboutToBeChanged()),
268  SLOT(sourceLayoutChanged()),
269  SLOT(sourceModelDestroyed())
270  };
271 
272  if (sourceModel()) {
273  for (int i = 0; i < int(sizeof modelSignals / sizeof * modelSignals); ++i) {
274  disconnect(sourceModel(), modelSignals[i], this, proxySlots[i]);
275  }
276  }
277 
279 
280  if (_sourceModel) {
281  for (int i = 0; i < int(sizeof modelSignals / sizeof * modelSignals); ++i) {
282  connect(_sourceModel, modelSignals[i], this, proxySlots[i]);
283  }
284  }
285 
287  if (_sourceModel && _sourceModel->hasChildren()) {
288  d->synchronousMappingRefresh();
289  }
290 
291  endResetModel();
292 }
293 
295 {
296  Q_UNUSED(index)
297  return QModelIndex();
298 }
299 
300 bool KDescendantsProxyModel::hasChildren(const QModelIndex &parent) const
301 {
303  return !(d->m_mapping.isEmpty() || parent.isValid());
304 }
305 
306 int KDescendantsProxyModel::rowCount(const QModelIndex &parent) const
307 {
309  if (d->m_pendingParents.contains(parent) || parent.isValid() || !sourceModel()) {
310  return 0;
311  }
312 
313  if (d->m_mapping.isEmpty() && sourceModel()->hasChildren()) {
314  Q_ASSERT(sourceModel()->rowCount() > 0);
315  const_cast<KDescendantsProxyModelPrivate *>(d)->synchronousMappingRefresh();
316  }
317  return d->m_rowCount;
318 }
319 
320 QModelIndex KDescendantsProxyModel::index(int row, int column, const QModelIndex &parent) const
321 {
322  if (parent.isValid()) {
323  return QModelIndex();
324  }
325 
326  if (!hasIndex(row, column, parent)) {
327  return QModelIndex();
328  }
329 
330  return createIndex(row, column);
331 }
332 
334 {
336  if (d->m_mapping.isEmpty() || !proxyIndex.isValid() || !sourceModel()) {
337  return QModelIndex();
338  }
339 
340  const Mapping::right_const_iterator result = d->m_mapping.rightLowerBound(proxyIndex.row());
341  Q_ASSERT(result != d->m_mapping.rightEnd());
342 
343  const int proxyLastRow = result.key();
344  const QModelIndex sourceLastChild = result.value();
345  Q_ASSERT(sourceLastChild.isValid());
346 
347  // proxyLastRow is greater than proxyIndex.row().
348  // sourceLastChild is vertically below the result we're looking for
349  // and not necessarily in the correct parent.
350  // We travel up through its parent hierarchy until we are in the
351  // right parent, then return the correct sibling.
352 
353  // Source: Proxy: Row
354  // - A - A - 0
355  // - B - B - 1
356  // - C - C - 2
357  // - D - D - 3
358  // - - E - E - 4
359  // - - F - F - 5
360  // - - G - G - 6
361  // - - H - H - 7
362  // - - I - I - 8
363  // - - - J - J - 9
364  // - - - K - K - 10
365  // - - - L - L - 11
366  // - - M - M - 12
367  // - - N - N - 13
368  // - O - O - 14
369 
370  // Note that L, N and O are lastChildIndexes, and therefore have a mapping. If we
371  // are trying to map G from the proxy to the source, We at this point have an iterator
372  // pointing to (L -> 11). The proxy row of G is 6. (proxyIndex.row() == 6). We seek the
373  // sourceIndex which is vertically above L by the distance proxyLastRow - proxyIndex.row().
374  // In this case the verticalDistance is 5.
375 
376  int verticalDistance = proxyLastRow - proxyIndex.row();
377 
378  // We traverse the ancestors of L, until we can index the desired row in the source.
379 
380  QModelIndex ancestor = sourceLastChild;
381  while (ancestor.isValid()) {
382  const int ancestorRow = ancestor.row();
383  if (verticalDistance <= ancestorRow) {
384  return ancestor.sibling(ancestorRow - verticalDistance, proxyIndex.column());
385  }
386  verticalDistance -= (ancestorRow + 1);
387  ancestor = ancestor.parent();
388  }
389  Q_ASSERT(!"Didn't find target row.");
390  return QModelIndex();
391 }
392 
394 {
396 
397  if (!sourceModel()) {
398  return QModelIndex();
399  }
400 
401  if (d->m_mapping.isEmpty()) {
402  return QModelIndex();
403  }
404 
405  {
406  // TODO: Consider a parent Mapping to speed this up.
407 
408  Mapping::right_const_iterator it = d->m_mapping.rightConstBegin();
409  const Mapping::right_const_iterator end = d->m_mapping.rightConstEnd();
410  const QModelIndex sourceParent = sourceIndex.parent();
411  Mapping::right_const_iterator result = end;
412 
413  for (; it != end; ++it) {
414  QModelIndex index = it.value();
415  bool found_block = false;
416  while (index.isValid()) {
417  const QModelIndex ancestor = index.parent();
418  if (ancestor == sourceParent && index.row() >= sourceIndex.row()) {
419  found_block = true;
420  if (result == end || it.key() < result.key()) {
421  result = it;
422  break; // Leave the while loop. index is still valid.
423  }
424  }
425  index = ancestor;
426  }
427  if (found_block && !index.isValid())
428  // Looked through the ascendants of it.key() without finding sourceParent.
429  // That means we've already got the result we need.
430  {
431  break;
432  }
433  }
434  Q_ASSERT(result != end);
435  const QModelIndex sourceLastChild = result.value();
436  int proxyRow = result.key();
437  QModelIndex index = sourceLastChild;
438  while (index.isValid()) {
439  const QModelIndex ancestor = index.parent();
440  if (ancestor == sourceParent) {
441  return createIndex(proxyRow - (index.row() - sourceIndex.row()), sourceIndex.column());
442  }
443  proxyRow -= (index.row() + 1);
444  index = ancestor;
445  }
446  Q_ASSERT(!"Didn't find valid proxy mapping.");
447  return QModelIndex();
448  }
449 
450 }
451 
452 int KDescendantsProxyModel::columnCount(const QModelIndex &parent) const
453 {
454  if (parent.isValid() /* || rowCount(parent) == 0 */ || !sourceModel()) {
455  return 0;
456  }
457 
458  return sourceModel()->columnCount();
459 }
460 
461 QVariant KDescendantsProxyModel::data(const QModelIndex &index, int role) const
462 {
464 
465  if (!sourceModel()) {
466  return QVariant();
467  }
468 
469  if (!index.isValid()) {
470  return sourceModel()->data(index, role);
471  }
472 
473  QModelIndex sourceIndex = mapToSource(index);
474 
475  if ((d->m_displayAncestorData) && (role == Qt::DisplayRole)) {
476  if (!sourceIndex.isValid()) {
477  return QVariant();
478  }
479  QString displayData = sourceIndex.data().toString();
480  sourceIndex = sourceIndex.parent();
481  while (sourceIndex.isValid()) {
482  displayData.prepend(d->m_ancestorSeparator);
483  displayData.prepend(sourceIndex.data().toString());
484  sourceIndex = sourceIndex.parent();
485  }
486  return displayData;
487  } else {
488  return sourceIndex.data(role);
489  }
490 }
491 
492 QVariant KDescendantsProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
493 {
494  if (!sourceModel() || columnCount() <= section) {
495  return QVariant();
496  }
497 
498  return QAbstractProxyModel::headerData(section, orientation, role);
499 }
500 
502 {
503  if (!index.isValid() || !sourceModel()) {
504  return QAbstractProxyModel::flags(index);
505  }
506 
507  const QModelIndex srcIndex = mapToSource(index);
508  Q_ASSERT(srcIndex.isValid());
509  return sourceModel()->flags(srcIndex);
510 }
511 
512 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
513 {
515 
516  if (!q->sourceModel()->hasChildren(parent)) {
517  Q_ASSERT(q->sourceModel()->rowCount(parent) == 0);
518  // parent was not a parent before.
519  return;
520  }
521 
522  int proxyStart = -1;
523 
524  const int rowCount = q->sourceModel()->rowCount(parent);
525 
526  if (rowCount > start) {
527  const QModelIndex belowStart = q->sourceModel()->index(start, 0, parent);
528  proxyStart = q->mapFromSource(belowStart).row();
529  } else if (rowCount == 0) {
530  proxyStart = q->mapFromSource(parent).row() + 1;
531  } else {
532  Q_ASSERT(rowCount == start);
533  static const int column = 0;
534  QModelIndex idx = q->sourceModel()->index(rowCount - 1, column, parent);
535  while (q->sourceModel()->hasChildren(idx)) {
536  Q_ASSERT(q->sourceModel()->rowCount(idx) > 0);
537  idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx);
538  }
539  // The last item in the list is getting a sibling below it.
540  proxyStart = q->mapFromSource(idx).row() + 1;
541  }
542  const int proxyEnd = proxyStart + (end - start);
543 
544  m_insertPair = qMakePair(proxyStart, proxyEnd);
545  q->beginInsertRows(QModelIndex(), proxyStart, proxyEnd);
546 }
547 
548 void KDescendantsProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent, int start, int end)
549 {
551 
552  Q_ASSERT(q->sourceModel()->index(start, 0, parent).isValid());
553 
554  const int rowCount = q->sourceModel()->rowCount(parent);
555  Q_ASSERT(rowCount > 0);
556 
557  const int difference = end - start + 1;
558 
559  if (rowCount == difference) {
560  // @p parent was not a parent before.
561  m_pendingParents.append(parent);
562  scheduleProcessPendingParents();
563  return;
564  }
565 
566  const int proxyStart = m_insertPair.first;
567 
568  Q_ASSERT(proxyStart >= 0);
569 
570  updateInternalIndexes(proxyStart, difference);
571 
572  if (rowCount - 1 == end) {
573  // The previously last row (the mapped one) is no longer the last.
574  // For example,
575 
576  // - A - A 0
577  // - - B - B 1
578  // - - C - C 2
579  // - - - D - D 3
580  // - - - E -> - E 4
581  // - - F - F 5
582  // - - G -> - G 6
583  // - H - H 7
584  // - I -> - I 8
585 
586  // As last children, E, F and G have mappings.
587  // Consider that 'J' is appended to the children of 'C', below 'E'.
588 
589  // - A - A 0
590  // - - B - B 1
591  // - - C - C 2
592  // - - - D - D 3
593  // - - - E -> - E 4
594  // - - - J - ??? 5
595  // - - F - F 6
596  // - - G -> - G 7
597  // - H - H 8
598  // - I -> - I 9
599 
600  // The updateInternalIndexes call above will have updated the F and G mappings correctly because proxyStart is 5.
601  // That means that E -> 4 was not affected by the updateInternalIndexes call.
602  // Now the mapping for E -> 4 needs to be updated so that it's a mapping for J -> 5.
603 
604  Q_ASSERT(!m_mapping.isEmpty());
605  static const int column = 0;
606  const QModelIndex oldIndex = q->sourceModel()->index(rowCount - 1 - difference, column, parent);
607  Q_ASSERT(m_mapping.leftContains(oldIndex));
608 
609  const QModelIndex newIndex = q->sourceModel()->index(rowCount - 1, column, parent);
610 
611  QModelIndex indexAbove = oldIndex;
612 
613  if (start > 0) {
614  // If we have something like this:
615  //
616  // - A
617  // - - B
618  // - - C
619  //
620  // and we then insert D as a sibling of A below it, we need to remove the mapping for A,
621  // and the row number used for D must take into account the descendants of A.
622 
623  while (q->sourceModel()->hasChildren(indexAbove)) {
624  Q_ASSERT(q->sourceModel()->rowCount(indexAbove) > 0);
625  indexAbove = q->sourceModel()->index(q->sourceModel()->rowCount(indexAbove) - 1, column, indexAbove);
626  }
627  Q_ASSERT(q->sourceModel()->rowCount(indexAbove) == 0);
628  }
629 
630  Q_ASSERT(m_mapping.leftContains(indexAbove));
631 
632  const int newProxyRow = m_mapping.leftToRight(indexAbove) + difference;
633 
634  // oldIndex is E in the source. proxyRow is 4.
635  m_mapping.removeLeft(oldIndex);
636 
637  // newIndex is J. (proxyRow + difference) is 5.
638  m_mapping.insert(newIndex, newProxyRow);
639  }
640 
641  for (int row = start; row <= end; ++row) {
642  static const int column = 0;
643  const QModelIndex idx = q->sourceModel()->index(row, column, parent);
644  Q_ASSERT(idx.isValid());
645  if (q->sourceModel()->hasChildren(idx)) {
646  Q_ASSERT(q->sourceModel()->rowCount(idx) > 0);
647  m_pendingParents.append(idx);
648  }
649  }
650 
651  m_rowCount += difference;
652 
653  q->endInsertRows();
654  scheduleProcessPendingParents();
655 }
656 
657 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
658 {
660 
661  const int proxyStart = q->mapFromSource(q->sourceModel()->index(start, 0, parent)).row();
662 
663  static const int column = 0;
664  QModelIndex idx = q->sourceModel()->index(end, column, parent);
665  while (q->sourceModel()->hasChildren(idx)) {
666  Q_ASSERT(q->sourceModel()->rowCount(idx) > 0);
667  idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx);
668  }
669  const int proxyEnd = q->mapFromSource(idx).row();
670 
671  m_removePair = qMakePair(proxyStart, proxyEnd);
672 
673  q->beginRemoveRows(QModelIndex(), proxyStart, proxyEnd);
674 }
675 
676 static QModelIndex getFirstDeepest(QAbstractItemModel *model, const QModelIndex &parent, int *count)
677 {
678  static const int column = 0;
679  Q_ASSERT(model->hasChildren(parent));
680  Q_ASSERT(model->rowCount(parent) > 0);
681  for (int row = 0; row < model->rowCount(parent); ++row) {
682  (*count)++;
683  const QModelIndex child = model->index(row, column, parent);
684  Q_ASSERT(child.isValid());
685  if (model->hasChildren(child)) {
686  return getFirstDeepest(model, child, count);
687  }
688  }
689  return model->index(model->rowCount(parent) - 1, column, parent);
690 }
691 
692 void KDescendantsProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent, int start, int end)
693 {
695  Q_UNUSED(end)
696 
697  const int rowCount = q->sourceModel()->rowCount(parent);
698 
699  const int proxyStart = m_removePair.first;
700  const int proxyEnd = m_removePair.second;
701 
702  const int difference = proxyEnd - proxyStart + 1;
703  {
704  Mapping::right_iterator it = m_mapping.rightLowerBound(proxyStart);
705  const Mapping::right_iterator endIt = m_mapping.rightUpperBound(proxyEnd);
706 
707  if (endIt != m_mapping.rightEnd())
708  while (it != endIt) {
709  it = m_mapping.eraseRight(it);
710  }
711  else
712  while (it != m_mapping.rightUpperBound(proxyEnd)) {
713  it = m_mapping.eraseRight(it);
714  }
715  }
716 
717  m_removePair = qMakePair(-1, -1);
718  m_rowCount -= difference;
719  Q_ASSERT(m_rowCount >= 0);
720 
721  updateInternalIndexes(proxyStart, -1 * difference);
722 
723  if (rowCount != start || rowCount == 0) {
724  q->endRemoveRows();
725  return;
726  }
727 
728  static const int column = 0;
729  const QModelIndex newEnd = q->sourceModel()->index(rowCount - 1, column, parent);
730  Q_ASSERT(newEnd.isValid());
731 
732  if (m_mapping.isEmpty()) {
733  m_mapping.insert(newEnd, newEnd.row());
734  q->endRemoveRows();
735  return;
736  }
737  if (q->sourceModel()->hasChildren(newEnd)) {
738  int count = 0;
739  const QModelIndex firstDeepest = getFirstDeepest(q->sourceModel(), newEnd, &count);
740  Q_ASSERT(firstDeepest.isValid());
741  const int firstDeepestProxy = m_mapping.leftToRight(firstDeepest);
742 
743  m_mapping.insert(newEnd, firstDeepestProxy - count);
744  q->endRemoveRows();
745  return;
746  }
747  Mapping::right_iterator lowerBound = m_mapping.rightLowerBound(proxyStart);
748  if (lowerBound == m_mapping.rightEnd()) {
749  int proxyRow = (lowerBound - 1).key();
750 
751  for (int row = newEnd.row(); row >= 0; --row) {
752  const QModelIndex newEndSibling = q->sourceModel()->index(row, column, parent);
753  if (!q->sourceModel()->hasChildren(newEndSibling)) {
754  ++proxyRow;
755  } else {
756  break;
757  }
758  }
759  m_mapping.insert(newEnd, proxyRow);
760  q->endRemoveRows();
761  return;
762  } else if (lowerBound == m_mapping.rightBegin()) {
763  int proxyRow = rowCount - 1;
764  QModelIndex trackedParent = parent;
765  while (trackedParent.isValid()) {
766  proxyRow += (trackedParent.row() + 1);
767  trackedParent = trackedParent.parent();
768  }
769  m_mapping.insert(newEnd, proxyRow);
770  q->endRemoveRows();
771  return;
772  }
773  const Mapping::right_iterator boundAbove = lowerBound - 1;
774 
775  QVector<QModelIndex> targetParents;
776  targetParents.push_back(parent);
777  {
778  QModelIndex target = parent;
779  int count = 0;
780  while (target.isValid()) {
781  if (target == boundAbove.value()) {
782  m_mapping.insert(newEnd, count + boundAbove.key() + newEnd.row() + 1);
783  q->endRemoveRows();
784  return;
785  }
786  count += (target.row() + 1);
787  target = target.parent();
788  if (target.isValid()) {
789  targetParents.push_back(target);
790  }
791  }
792  }
793 
794  QModelIndex boundParent = boundAbove.value().parent();
795  QModelIndex prevParent = boundParent;
796  Q_ASSERT(boundParent.isValid());
797  while (boundParent.isValid()) {
798  prevParent = boundParent;
799  boundParent = boundParent.parent();
800 
801  if (targetParents.contains(prevParent)) {
802  break;
803  }
804 
805  if (!m_mapping.leftContains(prevParent)) {
806  break;
807  }
808 
809  if (m_mapping.leftToRight(prevParent) > boundAbove.key()) {
810  break;
811  }
812  }
813 
814  QModelIndex trackedParent = parent;
815 
816  int proxyRow = boundAbove.key();
817 
818  Q_ASSERT(prevParent.isValid());
819  proxyRow -= prevParent.row();
820  while (trackedParent != boundParent) {
821  proxyRow += (trackedParent.row() + 1);
822  trackedParent = trackedParent.parent();
823  }
824  m_mapping.insert(newEnd, proxyRow + newEnd.row());
825  q->endRemoveRows();
826 }
827 
828 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart)
829 {
830  Q_UNUSED(srcParent)
831  Q_UNUSED(srcStart)
832  Q_UNUSED(srcEnd)
833  Q_UNUSED(destParent)
834  Q_UNUSED(destStart)
835  sourceLayoutAboutToBeChanged();
836 }
837 
838 void KDescendantsProxyModelPrivate::sourceRowsMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart)
839 {
840  Q_UNUSED(srcParent)
841  Q_UNUSED(srcStart)
842  Q_UNUSED(srcEnd)
843  Q_UNUSED(destParent)
844  Q_UNUSED(destStart)
845  sourceLayoutChanged();
846 }
847 
848 void KDescendantsProxyModelPrivate::sourceModelAboutToBeReset()
849 {
851  q->beginResetModel();
852 }
853 
854 void KDescendantsProxyModelPrivate::sourceModelReset()
855 {
857  resetInternalData();
858  if (q->sourceModel()->hasChildren()) {
859  Q_ASSERT(q->sourceModel()->rowCount() > 0);
860  m_pendingParents.append(QModelIndex());
861  scheduleProcessPendingParents();
862  }
863  q->endResetModel();
864 }
865 
866 void KDescendantsProxyModelPrivate::sourceLayoutAboutToBeChanged()
867 {
869 
870  if (m_ignoreNextLayoutChanged) {
871  m_ignoreNextLayoutChanged = false;
872  return;
873  }
874 
875  if (m_mapping.isEmpty()) {
876  return;
877  }
878 
879  QPersistentModelIndex srcPersistentIndex;
880  for (const QPersistentModelIndex &proxyPersistentIndex: q->persistentIndexList()) {
881  m_proxyIndexes << proxyPersistentIndex;
882  Q_ASSERT(proxyPersistentIndex.isValid());
883  srcPersistentIndex = q->mapToSource(proxyPersistentIndex);
884  Q_ASSERT(srcPersistentIndex.isValid());
885  m_layoutChangePersistentIndexes << srcPersistentIndex;
886  }
887 
888  q->layoutAboutToBeChanged();
889 }
890 
891 void KDescendantsProxyModelPrivate::sourceLayoutChanged()
892 {
894 
895  if (m_ignoreNextLayoutAboutToBeChanged) {
896  m_ignoreNextLayoutAboutToBeChanged = false;
897  return;
898  }
899 
900  if (m_mapping.isEmpty()) {
901  return;
902  }
903 
904  m_rowCount = 0;
905 
906  synchronousMappingRefresh();
907 
908  for (int i = 0; i < m_proxyIndexes.size(); ++i) {
909  q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i)));
910  }
911 
912  m_layoutChangePersistentIndexes.clear();
913  m_proxyIndexes.clear();
914 
915  q->layoutChanged();
916 }
917 
918 void KDescendantsProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
919 {
921  Q_ASSERT(topLeft.model() == q->sourceModel());
922  Q_ASSERT(bottomRight.model() == q->sourceModel());
923 
924  const int topRow = topLeft.row();
925  const int bottomRow = bottomRight.row();
926 
927  for (int i = topRow; i <= bottomRow; ++i) {
928  const QModelIndex sourceTopLeft = q->sourceModel()->index(i, topLeft.column(), topLeft.parent());
929  Q_ASSERT(sourceTopLeft.isValid());
930  const QModelIndex proxyTopLeft = q->mapFromSource(sourceTopLeft);
931  // TODO. If an index does not have any descendants, then we can emit in blocks of rows.
932  // As it is we emit once for each row.
933  const QModelIndex sourceBottomRight = q->sourceModel()->index(i, bottomRight.column(), bottomRight.parent());
934  const QModelIndex proxyBottomRight = q->mapFromSource(sourceBottomRight);
935  Q_ASSERT(proxyTopLeft.isValid());
936  Q_ASSERT(proxyBottomRight.isValid());
937  emit q->dataChanged(proxyTopLeft, proxyBottomRight);
938  }
939 }
940 
941 void KDescendantsProxyModelPrivate::sourceModelDestroyed()
942 {
943  resetInternalData();
944 }
945 
946 QMimeData *KDescendantsProxyModel::mimeData(const QModelIndexList &indexes) const
947 {
948  if (!sourceModel()) {
949  return QAbstractProxyModel::mimeData(indexes);
950  }
951  Q_ASSERT(sourceModel());
952  QModelIndexList sourceIndexes;
953  for (const QModelIndex &index: indexes) {
954  sourceIndexes << mapToSource(index);
955  }
956  return sourceModel()->mimeData(sourceIndexes);
957 }
958 
960 {
961  if (!sourceModel()) {
963  }
964  Q_ASSERT(sourceModel());
965  return sourceModel()->mimeTypes();
966 }
967 
969 {
970  if (!sourceModel()) {
972  }
973  return sourceModel()->supportedDropActions();
974 }
975 
976 }
977 
978 #include "moc_kdescendantsproxymodel.cpp"
virtual bool hasChildren(const QModelIndex &parent) const const
Proxy Model for restructuring a Tree into a list.
DisplayRole
virtual QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const const
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
virtual int rowCount(const QModelIndex &parent) const const=0
virtual QVariant data(const QModelIndex &proxyIndex, int role) const const override
QModelIndex sibling(int row, int column) const const
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const const=0
virtual Qt::ItemFlags flags(const QModelIndex &index) const const override
int column() const const
void layoutChanged(const QList< QPersistentModelIndex > &parents, QAbstractItemModel::LayoutChangeHint hint)
void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
void append(const T &value)
void push_back(const T &value)
QString & prepend(QChar ch)
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const const override
KDescendantsProxyModel(QObject *parent=nullptr)
Creates a new descendant entities proxy model.
bool isValid() const const
const QList< QKeySequence > & begin()
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
bool hasIndex(int row, int column, const QModelIndex &parent) const const
QHash::iterator insert(const Key &key, const T &value)
virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const const=0
void destroyed(QObject *obj)
virtual Qt::DropActions supportedDropActions() const const override
void rowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row)
QVariant data(int role) const const
QModelIndex createIndex(int row, int column, void *ptr) const const
Q_SCRIPTABLE Q_NOREPLY void start()
typedef ItemFlags
void setSourceModel(QAbstractItemModel *model) override
Sets the source model of the proxy.
QHash::const_iterator constBegin() const const
QHash::const_iterator constEnd() const const
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector< int > &roles)
Orientation
void setRootIndex(const QModelIndex &index)
bool contains(const T &value) const const
virtual int columnCount(const QModelIndex &parent) const const=0
Binds a QML item to a specific geodetic location in screen coordinates.
void rowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
bool isValid() const const
int row() const const
QString ancestorSeparator() const
Separator used between data of ancestors.
virtual QStringList mimeTypes() const const override
void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
typedef DropActions
void rowsInserted(const QModelIndex &parent, int first, int last)
virtual QMimeData * mimeData(const QModelIndexList &indexes) const const override
void rowsRemoved(const QModelIndex &parent, int first, int last)
bool displayAncestorData() const
Whether ancestor data will be displayed.
void clear()
QVector::iterator erase(QVector::iterator begin, QVector::iterator end)
QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits=1, Qt::MatchFlags flags=Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const override
Reimplemented to match all descendants.
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
void layoutAboutToBeChanged(const QList< QPersistentModelIndex > &parents, QAbstractItemModel::LayoutChangeHint hint)
QModelIndex parent() const const
void setDisplayAncestorData(bool display)
Set whether to show ancestor data in the model.
typedef MatchFlags
~KDescendantsProxyModel() override
Destroys the descendant entities proxy model.
QObject * parent() const const
const QAbstractItemModel * model() const const
const QList< QKeySequence > & end()
Q_D(Todo)
void setAncestorSeparator(const QString &separator)
Sets the ancestor separator used between data of ancestors.
void modelAboutToBeReset()
virtual void setSourceModel(QAbstractItemModel *sourceModel)
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Sep 21 2023 04:12:26 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.