• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KDEUI

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

KDE's Doxygen guidelines are available online.

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal