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

marble

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

KDE's Doxygen guidelines are available online.

marble

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

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

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