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

akonadi_next

  • sources
  • kde-4.12
  • kdepim
  • akonadi_next
kreparentingproxymodel.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 2009 Stephen Kelly <steveire@gmail.com>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "kreparentingproxymodel.h"
21 #include <kdebug.h>
22 #include <QStack>
23 
24 #include <functional>
25 #include <algorithm>
26 
27 
28 class KReparentingProxyModelPrivate
29 {
30  KReparentingProxyModelPrivate(KReparentingProxyModel *proxyModel)
31  : q_ptr(proxyModel), m_nextId(0)
32  {
33 
34  }
35 
36  qint64 newId() const { return m_nextId++; }
37 
38  enum MapStrategy
39  {
40  MapDescendants,
41  MapChildrenOnly
42  };
43 
49  QHash<QModelIndex, QModelIndexList> recreateMappings(const QModelIndex &parent, int start, int end = -1, int strategy = MapChildrenOnly) const;
50 
57  QHash<QModelIndex, QModelIndexList> mergeDescendants(QHash<QModelIndex, QModelIndexList> mappings, const QModelIndex &parent, int start );
58 
63  void verifyStructure(const QModelIndex &parent, int start);
64 
70  QModelIndex getIndexBelow(const QModelIndex &index, QAbstractItemModel *model = 0) const;
71 
75  QModelIndex getLastDescendant(const QModelIndex &index) const;
76 
77  bool isDescendantInModel(const QModelIndex &ancestor, const QModelIndex &descendant) const;
78 
85  QVector<QModelIndex> getExistingAncestors(const QModelIndex &descendant) const;
86 
87  void sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end);
88  void sourceRowsInserted(const QModelIndex &parent, int start, int end);
89  void sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
90  void sourceRowsRemoved(const QModelIndex &parent, int start, int end);
91  void sourceRowsAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow);
92  void sourceRowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow);
93  void sourceModelAboutToBeReset();
94  void sourceModelReset();
95  void sourceLayoutAboutToBeChanged();
96  void sourceLayoutChanged();
97  void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
98 
99  mutable QHash<qint64, QPersistentModelIndex> m_parents;
100  mutable QHash<QPersistentModelIndex, QList<QPersistentModelIndex> > m_childIndexes;
101 
102  struct PendingInsertion
103  {
104  PendingInsertion()
105  : parentId(-1), start(-1), end(-1)
106  { }
107 
108  PendingInsertion(const QModelIndex &_index, int _start, int _end)
109  : index(_index), parentId(-1), start(_start), end(_end)
110  { }
111 
112  QPersistentModelIndex index;
113  QModelIndex sourceIndex;
114  qint64 parentId;
115  int start;
116  int end;
117  };
118 
119  struct PendingRemoval : PendingInsertion
120  {
121  int numTrailing;
122  };
123  // Needed between the beginRemoveRows and endRemoveRows signals.
124  mutable QHash<qint64, QPersistentModelIndex> m_pendingRemovalParents;
125  mutable QHash<QPersistentModelIndex, QList<QPersistentModelIndex> > m_pendingRemovalChildIndexes;
126 
127  QHash<QModelIndex, QModelIndexList> insertTree( QHash<QModelIndex, QModelIndexList> mappings, const QModelIndex &parent );
128 
129  void handleInsertion(const PendingInsertion &pendingInsertion);
130 
131  void handleRemoval(const PendingRemoval &pendingRemoval);
132 
133  mutable QHash<QModelIndex, PendingInsertion> m_pendingInsertions;
134  mutable QVector<PendingRemoval> m_pendingRemovals;
135 
136  mutable qint64 m_nextId;
137 
138  Q_DECLARE_PUBLIC( KReparentingProxyModel )
139  KReparentingProxyModel *q_ptr;
140 
141  QList<QPersistentModelIndex> m_layoutChangePersistentIndexes;
142  QModelIndexList m_proxyIndexes;
143 
144  void emitDataChangedSignals(const QModelIndex &parent, int maxChanged);
145 
150  QModelIndex findLastInParent(QModelIndex parent, int start, int end);
151 
155  void removeTree(const QPersistentModelIndex &idx, int start = 0, int end = -1);
156 
157  int pendingRemovalRowCount(const QModelIndex &sourceIndex) const;
158 
159 };
160 
161 class LessThan
162 {
163  const KReparentingProxyModel *m_model;
164 public:
165  LessThan(const KReparentingProxyModel *model) : m_model(model) {}
166  bool operator()(const QModelIndex &ancestor, const QModelIndex &descendant)
167  {
168  return m_model->isDescendantOf(ancestor, descendant);
169  }
170 };
171 
172 QModelIndex KReparentingProxyModelPrivate::getIndexBelow(const QModelIndex &index, QAbstractItemModel *model) const
173 {
174  Q_Q(const KReparentingProxyModel);
175 
176  if (!model)
177  model = q->sourceModel();
178 
179  if (model->hasChildren(index))
180  return model->index(0, 0, index);
181 
182  QModelIndex sibling = index.sibling(index.row() + 1, index.column());
183  if (sibling.isValid())
184  return sibling;
185 
186  QModelIndex parent = sibling.parent();
187 
188  if(!parent.isValid())
189  return QModelIndex();
190 
191  int affectedRow = index.row();
192  const int column = 0;
193 
194  while (parent.isValid())
195  {
196  if (model->rowCount(parent) >= affectedRow)
197  return model->index(affectedRow + 1, column, parent);
198 
199  affectedRow = parent.row();
200  parent = parent.parent();
201  }
202 
203  if (model->rowCount(parent) >= affectedRow)
204  return model->index(affectedRow + 1, column, parent);
205 
206  return QModelIndex();
207 }
208 
209 QModelIndex KReparentingProxyModelPrivate::getLastDescendant(const QModelIndex &index) const
210 {
211  Q_Q(const KReparentingProxyModel);
212 
213  QModelIndex proxyIndex = q->mapFromSource(index);
214 
215  while (q->hasChildren(proxyIndex))
216  {
217  proxyIndex = proxyIndex.child(q->rowCount(proxyIndex), proxyIndex.column());
218  if (!proxyIndex.isValid())
219  break;
220  }
221  return q->mapToSource(proxyIndex);
222 }
223 
224 QVector<QModelIndex> KReparentingProxyModelPrivate::getExistingAncestors(const QModelIndex &descendant) const
225 {
226  Q_Q(const KReparentingProxyModel);
227 
228  QVector<QModelIndex> vector;
229  if (!descendant.isValid())
230  return vector;
231 
232  QModelIndex parent = q->mapFromSource(descendant).parent();
233  vector.append(q->mapToSource(parent));
234  while (parent.isValid())
235  {
236  parent = parent.parent();
237  vector.prepend(q->mapToSource(parent));
238  }
239  return vector;
240 }
241 
242 QHash<QModelIndex, QModelIndexList> KReparentingProxyModelPrivate::recreateMappings(const QModelIndex &ancestor, int start, int end, int strategy) const
243 {
244  Q_Q(const KReparentingProxyModel);
245  const int column = 0;
246 
247  QHash<QModelIndex, QModelIndexList> mappings;
248  // Handle listing the root QModelIndex().
249  if (!ancestor.isValid() && !q->sourceModel()->hasChildren())
250  // Empty model. Nothing to do.
251  return mappings;
252 
253  // A
254  // - B
255  // - - C
256  // - D
257  // If start refers to D, existing ancestors will contain only A.
258  // We need to go 'up' to C and get its ancestors in case D is to be made a child of B or C (for example if B and C have just been inserted)
259  QModelIndex indexAbove;
260  if (start > 0)
261  indexAbove = getLastDescendant(q->sourceModel()->index(start - 1, column, ancestor));
262  else
263  indexAbove = ancestor;
264 
265  QVector<QModelIndex> ancestors = getExistingAncestors(indexAbove);
266 
267  ancestors.append(indexAbove);
268 
269  QModelIndex nextIndex = ancestor;
270 
271  for (int row = start; (row <= end || end == -1); ++row)
272  {
273  // TODO: Change this to get the next index by asking the proxy model, not the source model.
274  if (MapDescendants == strategy)
275  {
276  nextIndex = getIndexBelow(nextIndex);
277  } else {
278  nextIndex = q->sourceModel()->index(row, column, ancestor);
279  }
280  if (!nextIndex.isValid())
281  break;
282 
283  QModelIndex deepestAncestor = ancestors.last();
284  if (q->isDescendantOf(deepestAncestor, nextIndex))
285  {
286  mappings[deepestAncestor].append(nextIndex);
287  ancestors.append(nextIndex);
288  continue;
289  }
290  kDebug()<< "######\nNextIndex" << nextIndex.data();
291  foreach(const QModelIndex &idx, ancestors)
292  {
293  kDebug() << "#" << idx << idx.data();
294  }
295  QVector<QModelIndex>::iterator ancestorIt = qLowerBound(ancestors.begin(), ancestors.end(), nextIndex, LessThan(q));
296 
297  QModelIndex parent;
298  if (ancestorIt != ancestors.begin())
299  {
300  parent = *(ancestorIt - 1);
301  }
302  //kDebug() << parent << *ancestorIt; // this crashes if ancestorIt == ancestors.end()
303  ancestorIt = ancestors.insert(ancestorIt, nextIndex);
304 
305  if (ancestorIt != ancestors.end())
306  {
307  ++ancestorIt;
308  while (ancestorIt != ancestors.end())
309  {
310  ancestorIt = ancestors.erase(ancestorIt);
311  }
312  }
313  mappings[parent].append(nextIndex);
314  }
315 
316  return mappings;
317 }
318 
319 void KReparentingProxyModelPrivate::verifyStructure(const QModelIndex &sourceParent, int sourceStart)
320 {
321  Q_Q( KReparentingProxyModel );
322 
323  // If the start structure is:
324 
325  // C
326  // D
327  // E
328 
329  // and then A and B are inserted, we may need to move C D and E. Not all of the siblings will
330  // necessarily be moved to the same destination parent.
331  // Some example finished scenarios depending on the outcome of isDescendantOf:
332 
333  // A
334  // B
335  // C
336  // D
337  // E
338 
339  // A
340  // B
341  // - C
342  // - D
343  // - E
344 
345  // A
346  // - B
347  // - C
348  // - D
349  // - E
350 
351  // A
352  // - B
353  // - - C
354  // - D
355  // E
356 
357  // Local variable mappings now contains all the information about finished state
358  // When we locate the first child to be moved, we process it and its siblings
359 
360  QHash<QModelIndex, QModelIndexList> mappings = recreateMappings(sourceParent, sourceStart, -1);
361 
362  if (mappings.isEmpty())
363  return;
364 
365  QModelIndex sourceFirstIndex = q->sourceModel()->index(sourceStart, 0, sourceParent);
366 
367  QModelIndex destinationParent;
368  QModelIndexList movedIndexes;
369 
370  QHashIterator<QModelIndex, QModelIndexList> it(mappings);
371  while (it.hasNext())
372  {
373  it.next();
374  kDebug() << it.key() << it.key().data() << it.value();
375  if (it.value().at(0) == sourceFirstIndex)
376  {
377  destinationParent = it.key();
378  movedIndexes = it.value();
379  break;
380  }
381  }
382 
383  forever
384  {
385 
386  if (destinationParent == sourceParent)
387  // No indexes moved
388  return;
389 
390  Q_ASSERT(destinationParent.isValid());
391  Q_ASSERT(!movedIndexes.isEmpty());
392 
393  // It's only possible for things to move right, and even that's only an option
394  // for children of parent, but not their descendants. ie, children of C D and E will not need to be reparented.
395  // They are already in the correct positions.
396 
397  QList<QPersistentModelIndex> &existingSourceIndexes = m_childIndexes[sourceParent];
398  QList<QPersistentModelIndex> existingDestinationIndexes = m_childIndexes[destinationParent];
399 
400  QModelIndex proxySourceParent = q->mapFromSource(sourceParent);
401  QModelIndex proxyDestinationParent = q->mapFromSource(destinationParent);
402 
403  // That is, start position of indexes to be moved from the source parent.
404  int proxySourceStart = m_childIndexes.value(sourceParent).indexOf(movedIndexes.at(0));
405  int proxySourceEnd = proxySourceStart + movedIndexes.size() - 1;
406 
407  // The moved indexes are appended to the destinationParent. Nothing else is possible.
408  // If they were to be inserted in the middle somewhere, they would already be there.
409 
410  int destinationRow = existingDestinationIndexes.size();
411 
412  bool allowMove = q->beginMoveRows(proxySourceParent, proxySourceStart, proxySourceEnd, proxyDestinationParent, destinationRow);
413  Q_ASSERT(allowMove);
414 
415  for (int row = proxySourceEnd; row >= proxySourceStart; --row)
416  {
417  existingSourceIndexes.removeAt(row);
418  }
419 
420  QHash<QModelIndex, QModelIndexList> mapping;
421  mapping.insert(destinationParent, movedIndexes);
422  mergeDescendants(mapping, destinationParent, existingDestinationIndexes.size());
423 
424  q->endMoveRows();
425 
426  if (!mappings.contains(q->mapToSource(proxyDestinationParent.parent())))
427  break;
428 
429  destinationParent = q->mapToSource(proxyDestinationParent.parent());
430  movedIndexes = mappings.value(destinationParent);
431  }
432 }
433 
434 
435 KReparentingProxyModel::KReparentingProxyModel(QObject* parent)
436  : QAbstractProxyModel(parent), d_ptr(new KReparentingProxyModelPrivate(this))
437 {
438 
439 }
440 
441 KReparentingProxyModel::~KReparentingProxyModel()
442 {
443  delete d_ptr;
444 }
445 
446 bool KReparentingProxyModelPrivate::isDescendantInModel(const QModelIndex& ancestor, const QModelIndex& descendant) const
447 {
448  kDebug() << ancestor.data() << descendant.data();
449 
450 // if (!ancestor.isValid())
451 // return true;
452 
453  QModelIndex _ancestor = descendant.parent();
454  while (_ancestor.isValid())
455  {
456  if (_ancestor == ancestor)
457  return true;
458  _ancestor = _ancestor.parent();
459  }
460  return (!ancestor.isValid() && descendant.isValid());
461 }
462 
463 bool KReparentingProxyModel::isDescendantOf(const QModelIndex& ancestor, const QModelIndex& descendant) const
464 {
465  Q_D( const KReparentingProxyModel );
466  return d->isDescendantInModel(ancestor, descendant);
467 // return (!ancestor.isValid() && descendant.isValid());
468 }
469 
470 QModelIndex KReparentingProxyModel::mapFromSource(const QModelIndex& sourceIndex) const
471 {
472  Q_D( const KReparentingProxyModel );
473  if (!sourceIndex.isValid())
474  return QModelIndex();
475 
476  QModelIndex sourceIndexFirstColumn = sourceIndex.sibling(sourceIndex.row(), 0);
477 
478  QHash<QPersistentModelIndex, QList<QPersistentModelIndex> >::const_iterator it;
479  const QHash<QPersistentModelIndex, QList<QPersistentModelIndex> >::const_iterator begin = d->m_childIndexes.constBegin();
480  const QHash<QPersistentModelIndex, QList<QPersistentModelIndex> >::const_iterator end = d->m_childIndexes.constEnd();
481 
482  for(it = begin; it != end; ++it)
483  {
484  QList<QPersistentModelIndex> list = it.value();
485  if (list.contains(sourceIndexFirstColumn))
486  {
487  QModelIndex sourceParent = it.key();
488  QModelIndex proxyParent = mapFromSource(sourceParent);
489  int row = list.indexOf(sourceIndexFirstColumn);
490 
491  // There must have been a mapping made for it.
492  Q_ASSERT(d->m_parents.values().contains(sourceParent));
493 
494  qint64 id = d->m_parents.key(sourceParent);
495 
496  // id refers to the parent.
497  return createIndex(row, sourceIndex.column(), reinterpret_cast<void*>(id));
498  }
499  }
500  return QModelIndex();
501 }
502 
503 QModelIndex KReparentingProxyModel::mapToSource(const QModelIndex& proxyIndex) const
504 {
505  Q_D( const KReparentingProxyModel );
506 
507 // kDebug() << "MMMMMM" << proxyIndex;
508 
509  if (!proxyIndex.isValid())
510  return QModelIndex();
511 
512  qint64 id = reinterpret_cast<qint64>(proxyIndex.internalPointer());
513 
514 // if (!d->m_parents.contains(id))
515 // kDebug() << d->m_parents << id;
516 
517  QModelIndex sourceParent;
518  if (d->m_pendingRemovalParents.contains(id))
519  {
520 // kDebug() << "pending";
521  sourceParent = d->m_pendingRemovalParents.value(id);
522  } else {
523  Q_ASSERT(d->m_parents.contains(id));
524  sourceParent = d->m_parents.value(id);
525  }
526 
527 // kDebug() << sourceParent << sourceParent.data();
528 
529  QModelIndex sourceIndexFirstColumn;
530  if (d->m_pendingRemovalChildIndexes.contains(sourceParent)) {
531 // kDebug() << "#############";
532 
533  foreach( const KReparentingProxyModelPrivate::PendingRemoval &pendingRemoval, d->m_pendingRemovals)
534  {
535 // kDebug() << "In" << pendingRemoval.index << pendingRemoval.sourceIndex << sourceParent;
536  if (pendingRemoval.sourceIndex == sourceParent)
537  {
538 // kDebug() << "Out" << pendingRemoval.sourceIndex << sourceParent;
539  int proxyRow = proxyIndex.row();
540  int row = proxyRow - pendingRemoval.start;
541 
542 // kDebug() << d->m_pendingRemovalChildIndexes.value(sourceParent) << proxyRow << row << pendingRemoval.end;
543 
544  if (proxyRow > pendingRemoval.end)
545  {
546  Q_ASSERT(d->m_childIndexes.contains(sourceParent));
547  row = proxyRow - (pendingRemoval.end - pendingRemoval.start + 1);
548 // kDebug() << "new row" << row;
549  sourceIndexFirstColumn = d->m_childIndexes.value(sourceParent).at(row);
550  }
551  else
552  sourceIndexFirstColumn = d->m_pendingRemovalChildIndexes.value(sourceParent).at(row);
553  break;
554  }
555  }
556  } else {
557  Q_ASSERT(d->m_childIndexes.contains(sourceParent));
558  sourceIndexFirstColumn = d->m_childIndexes.value(sourceParent).at(proxyIndex.row());
559  }
560 
561  Q_ASSERT(sourceIndexFirstColumn.isValid());
562 
563  return sourceIndexFirstColumn.sibling(sourceIndexFirstColumn.row(), proxyIndex.column());
564 }
565 
566 int KReparentingProxyModel::columnCount(const QModelIndex& parent) const
567 {
568  Q_D( const KReparentingProxyModel );
569 
570  if (!parent.isValid())
571  return sourceModel()->columnCount();
572 
573  if ( parent.column() > 0 )
574  {
575  return 0;
576  }
577  QModelIndex sourceIndex = mapToSource(parent);
578 
579  return (d->m_childIndexes.value(sourceIndex).size() > 0)
580  ? sourceModel()->columnCount() : 0;
581 }
582 
583 QVariant KReparentingProxyModel::data(const QModelIndex& proxyIndex, int role) const
584 {
585  return QAbstractProxyModel::data(proxyIndex, role);
586 }
587 
588 QModelIndex KReparentingProxyModel::index(int row, int column, const QModelIndex& parent) const
589 {
590  Q_D( const KReparentingProxyModel );
591 
592  if (!hasIndex(row, column, parent))
593  return QModelIndex();
594 
595  QModelIndex sourceParent = mapToSource(parent);
596 
597 // if (!d->m_pendingRemovals.isEmpty())
598 // kDebug() << sourceParent << sourceParent.data();
599 
600  // ### This is where we need to have the children of removed indexes stored.
601 
602 // if (!d->m_parents.values().contains(sourceParent))
603 // {
604 // kDebug() << d->m_pendingRemovalParents.values() << sourceParent << d->m_pendingRemovalParents.values().contains(sourceParent);
605 // }
606 
607  qint64 id;
608  if(d->m_pendingRemovalParents.values().contains(sourceParent))
609  {
610  id = d->m_pendingRemovalParents.key(sourceParent);
611  } else {
612  // There must have been a mapping made for it.
613  Q_ASSERT(d->m_parents.values().contains(sourceParent));
614  id = d->m_parents.key(sourceParent);
615  }
616  return createIndex(row, column, reinterpret_cast<void*>(id));
617 }
618 
619 QModelIndex KReparentingProxyModel::parent(const QModelIndex& child) const
620 {
621  Q_D( const KReparentingProxyModel );
622 
623  if (!child.isValid())
624  return QModelIndex();
625 
626  QModelIndex sourceIndex = mapToSource(child);
627 
628  QModelIndex firstColumnChild = sourceIndex;
629  if (sourceIndex.column() > 0)
630  firstColumnChild = sourceIndex.sibling(sourceIndex.row(), 0);
631 
632  QHashIterator<QPersistentModelIndex, QList<QPersistentModelIndex> > itPending(d->m_pendingRemovalChildIndexes);
633 
634  while (itPending.hasNext())
635  {
636  itPending.next();
637 
638  if (itPending.value().contains(firstColumnChild))
639  {
640  return mapFromSource(itPending.key());
641  }
642  }
643 
644  QHashIterator<QPersistentModelIndex, QList<QPersistentModelIndex> > it(d->m_childIndexes);
645 
646  while (it.hasNext())
647  {
648  it.next();
649 
650  if (it.value().contains(firstColumnChild))
651  {
652  return mapFromSource(it.key());
653  }
654  }
655  return QModelIndex();
656 }
657 
658 int KReparentingProxyModelPrivate::pendingRemovalRowCount(const QModelIndex &sourceIndex) const
659 {
660 
661  foreach(const PendingRemoval &pendingRemoval, m_pendingRemovals)
662  {
663 // kDebug() << pendingRemoval.sourceIndex;
664  if (pendingRemoval.sourceIndex == sourceIndex)
665  return pendingRemoval.end - pendingRemoval.start + 1;
666  }
667  return 0;
668 }
669 
670 
671 int KReparentingProxyModel::rowCount(const QModelIndex& parent) const
672 {
673  Q_D( const KReparentingProxyModel );
674 
675  if ( parent.column() > 0 )
676  return 0;
677 
678  QModelIndex sourceIndex = mapToSource(parent);
679 
680  int size = d->m_childIndexes.value(sourceIndex).size() + d->m_pendingRemovalChildIndexes.value(sourceIndex).size();
681 
682 // kDebug() << d->m_pendingRemovalChildIndexes.value(sourceIndex).size();
683 
684 // if (!d->m_pendingRemovals.isEmpty())
685 // {
686 // kDebug() << "SIZE" << sourceIndex << sourceIndex.data() << size << d->m_pendingRemovals.size() << d->pendingRemovalRowCount(sourceIndex);
687 // }
688 
689  return size;
690 }
691 
692 bool KReparentingProxyModel::hasChildren(const QModelIndex& parent) const
693 {
694  return rowCount(parent) > 0;
695 }
696 
697 void KReparentingProxyModel::setSourceModel(QAbstractItemModel* sourceModel)
698 {
699  Q_D( KReparentingProxyModel );
700 
701  beginResetModel();
702 
703  disconnect(sourceModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
704  this, SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int)));
705  disconnect(sourceModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
706  this, SLOT(sourceRowsInserted(QModelIndex,int,int)));
707  disconnect(sourceModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
708  this, SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
709  disconnect(sourceModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
710  this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
711  disconnect(sourceModel, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
712  this, SLOT(sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
713  disconnect(sourceModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
714  this, SLOT(sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
715  disconnect(sourceModel, SIGNAL(modelAboutToBeReset()),
716  this, SLOT(sourceModelAboutToBeReset()));
717  disconnect(sourceModel, SIGNAL(modelReset()),
718  this, SLOT(sourceModelReset()));
719  disconnect(sourceModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
720  this, SLOT(sourceDataChanged(QModelIndex,QModelIndex)));
721  disconnect(sourceModel, SIGNAL(layoutAboutToBeChanged()),
722  this, SLOT(sourceLayoutAboutToBeChanged()));
723  disconnect(sourceModel, SIGNAL(layoutChanged()),
724  this, SLOT(sourceLayoutChanged()));
725 
726  QAbstractProxyModel::setSourceModel(sourceModel);
727 
728  QHash<QModelIndex, QModelIndexList> mappings = d->recreateMappings(QModelIndex(), 0, sourceModel->rowCount() - 1, KReparentingProxyModelPrivate::MapDescendants);
729  d->mergeDescendants(mappings, QModelIndex(), 0);
730 
731  connect(sourceModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
732  SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int)));
733  connect(sourceModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
734  SLOT(sourceRowsInserted(QModelIndex,int,int)));
735  connect(sourceModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
736  SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
737  connect(sourceModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
738  SLOT(sourceRowsRemoved(QModelIndex,int,int)));
739  connect(sourceModel, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
740  SLOT(sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
741  connect(sourceModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
742  SLOT(sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
743  connect(sourceModel, SIGNAL(modelAboutToBeReset()),
744  SLOT(sourceModelAboutToBeReset()));
745  connect(sourceModel, SIGNAL(modelReset()),
746  SLOT(sourceModelReset()));
747  connect(sourceModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
748  SLOT(sourceDataChanged(QModelIndex,QModelIndex)));
749  connect(sourceModel, SIGNAL(layoutAboutToBeChanged()),
750  SLOT(sourceLayoutAboutToBeChanged()));
751  connect(sourceModel, SIGNAL(layoutChanged()),
752  SLOT(sourceLayoutChanged()));
753 
754  endResetModel();
755 }
756 
757 void KReparentingProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
758 {
759  Q_Q(KReparentingProxyModel);
760 
761  // We can't figure out the structure until the indexes are in the model.
762  // Store the signal until the new rows are actually there in sourceRowsInserted.
763  PendingInsertion pendingInsertion(parent, start, end);
764  m_pendingInsertions.insert(parent, pendingInsertion);
765 }
766 
767 QHash<QModelIndex, QModelIndexList> KReparentingProxyModelPrivate::mergeDescendants(QHash<QModelIndex, QModelIndexList> mappings, const QModelIndex &parent, int start)
768 {
769  QModelIndexList childIndexes = mappings.take(parent);
770  kDebug() << childIndexes;
771  if (!childIndexes.isEmpty())
772  {
773  if (!m_parents.values().contains(parent))
774  {
775  m_parents.insert(newId(), QPersistentModelIndex(parent));
776  }
777  }
778  int row = start;
779  foreach (const QModelIndex &idx, childIndexes)
780  {
781  m_childIndexes[parent].insert(row++, QPersistentModelIndex(idx));
782  mappings = mergeDescendants(mappings, idx, 0);
783  }
784  return mappings;
785 }
786 
787 QHash<QModelIndex, QModelIndexList> KReparentingProxyModelPrivate::insertTree( QHash<QModelIndex, QModelIndexList> mappings, const QModelIndex &parent )
788 {
789  return QHash<QModelIndex, QModelIndexList>();
790 }
791 
792 void KReparentingProxyModelPrivate::handleInsertion(const PendingInsertion &pendingInsertion)
793 {
794  Q_Q(KReparentingProxyModel);
795  QModelIndex parent = pendingInsertion.index;
796  int start = pendingInsertion.start;
797  int end = pendingInsertion.end;
798 
799  kDebug() << parent << parent.data() << start << end;
800 
801 
802 // for (int i = start; i < end; ++i)
803 // {
804 // QModelIndex idx = q->sourceModel()->index(i, 0, parent);
805 // kDebug() << idx << idx.data();
806 // }
807 
808  QHash<QModelIndex, QModelIndexList> newItemMappings = recreateMappings(parent, start, end, KReparentingProxyModelPrivate::MapDescendants);
809 
810  // iterate over keys. if key in keys iterate up. This gives list of top level parents.
811  // Pick the one whoes parent is @p parent. Insert it. Look up until find the parent of another one and insert that.
812  // If one of the parents is invalid it is necessarily the last one to be processed (if there are more to process, they'll be children of it)
813  // That case should work too.
814 
815  kDebug() << "new item mappings" << newItemMappings;
816 
817  const int column = 0;
818 
819  kDebug() << m_childIndexes.contains(parent);
820 
821  if (newItemMappings.contains(parent))
822  {
823  QModelIndexList newItemList = newItemMappings.value(parent);
824  kDebug() << "newItemList" << newItemList;
825  int proxyStart = 0;
826 
827  // A single insertion in the source model might be multiple insertions in the proxy model.
828  forever
829  {
830  if (newItemList.isEmpty())
831  {
832  if (!newItemMappings.contains(parent.parent()))
833  break;
834 
835  newItemList = newItemMappings.value(parent.parent());
836  continue;
837  }
838 
839  proxyStart = 0;
840 
841  QModelIndex proxyParent = q->mapFromSource(parent);
842  if (start > 0)
843  {
844  QModelIndex lastDesc = q->mapFromSource(getLastDescendant(q->sourceModel()->index(start - 1, column, parent)));
845 
846  while (lastDesc.parent() != proxyParent)
847  {
848  lastDesc = lastDesc.parent();
849  }
850  proxyStart = lastDesc.row() + 1;
851  }
852 
853  q->beginInsertRows(proxyParent, proxyStart, proxyStart + newItemList.size() - 1);
854 
855  newItemMappings = mergeDescendants(newItemMappings, parent, proxyStart);
856 
857  q->endInsertRows();
858 
859  if (!newItemMappings.contains(parent.parent()))
860  break;
861 
862  newItemList = newItemMappings.value(parent.parent());
863  }
864  }
865 
866 // // The rest are not descendants of pendingInsertion.index in the proxy model, but are elsewhere.
867 // foreach(const QModelIndex &parent, newItemMappings.keys())
868 // {
869 //
870 // }
871 
872  return;
873 }
874 
875 void KReparentingProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent, int start, int end)
876 {
877  Q_Q(KReparentingProxyModel);
878  if (m_pendingInsertions.contains(parent))
879  {
880  PendingInsertion pendingInsertion = m_pendingInsertions.value(parent);
881  handleInsertion(pendingInsertion);
882 
883  if (q->sourceModel()->rowCount(parent) <= (end + 1))
884  return;
885 
886  // The presence of new rows might affect the structure of indexes below.
887  verifyStructure(parent, end + 1);
888  }
889 }
890 
891 void KReparentingProxyModelPrivate::removeTree(const QPersistentModelIndex &idxToRemove, int start, int end)
892 {
893  if (!m_childIndexes.contains(idxToRemove))
894  return;
895 
896 // kDebug() << "idxToRemove" << idxToRemove << start << end;
897 
898  QList<QPersistentModelIndex> &toRemove = m_childIndexes[ idxToRemove ];
899 // kDebug() << toRemove << toRemove.size();
900 
901 // QList<int> intList;
902 // intList << 1 << 2 << 3 << 4 << 5;
903 //
904 // QList<int>::iterator intit = intList.begin();
905 // QList<int>::iterator intendIt = intList.end();
906 //
907 // if (end == 0)
908 // intendIt = intit + 1;
909 //
910 // if (end > 0)
911 // {
912 // intendIt = intit + (end - start + 1) + 1;
913 // kDebug() << "intend" << *intendIt;
914 // }
915 // intit += start;
916 //
917 // while (intit != intendIt)
918 // {
919 // int i = *intit;
920 // kDebug() << i;
921 // intit = intList.erase(intit);
922 // }
923 
924  QList<QPersistentModelIndex>::iterator it = toRemove.begin();
925  QList<QPersistentModelIndex>::iterator endIt = toRemove.end();
926 
927  if (end == 0)
928  endIt = it + 1;
929 
930  if (end > 0)
931  {
932  endIt = it + (end - start + 1) + 1;
933  }
934  it += start;
935 
936  int i = start;
937  while(it != endIt)
938  {
939  QPersistentModelIndex idx = *it;
940 // kDebug() << "removing" << idx << idx.data();
941 
942  if (m_parents.values().contains(idx))
943  {
944  qint64 key = m_parents.key(idx);
945  QPersistentModelIndex value = m_parents.take(key);
946  m_pendingRemovalParents.insert(key, value);
947 // kDebug() << "take from parent" << value;
948  }
949  removeTree(idx);
950 
951  ++i;
952 
953  m_pendingRemovalChildIndexes[idxToRemove].append(idx);
954 // kDebug() << idxToRemove << idxToRemove.data() << idx << idx.data();
955 
956  it = toRemove.erase(it);
957 // kDebug() << (it == endIt);
958 // if (i > end)
959 // break;
960 
961 // if (it == toRemove.end())
962 // break;
963 
964  }
965 
966 // kDebug() << "toRemove" << toRemove;
967 
968 // for(int i = start; (i <= end || (end == -1 && toRemove.size() > i)); )
969 // {
970 // kDebug() << i;
971 // QPersistentModelIndex idx = toRemove.takeAt(i);
972 // --end;
973 //
974 // kDebug() << "removing" << idx.data();
975 //
976 // if (m_parents.values().contains(idx))
977 // {
978 // QPersistentModelIndex bah = m_parents.take(m_parents.key(idx));
979 // // kDebug() << "take from parent" << bah;
980 // }
981 // removeTree(idx);
982 // }
983 }
984 
985 void KReparentingProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
986 {
987  Q_Q(KReparentingProxyModel);
988  kDebug() << parent << start << end;
989 
990  // This is really tricky.
991  //
992  // We could have something like:
993  //
994  // A A
995  // B - B
996  // C -> - - C
997  // D D
998  // E - E
999  //
1000  // And have to remove something like B to D. That would mean a remove signal for B, move E to its grandparent, remove D.
1001 
1002 // QHashIterator<QPersistentModelIndex, QList< QPersistentModelIndex> > it(m_childIndexes);
1003 // while (it.hasNext())
1004 // {
1005 // it.next();
1006 // kDebug() << it.key() << it.key().data();
1007 // kDebug() << it.value();
1008 // }
1009 
1010  const int column = 0;
1011 
1012  QModelIndex firstAffectedIndex = q->mapFromSource(q->sourceModel()->index(start, column, parent));
1013  QModelIndex lastAffectedIndex = q->mapFromSource(q->sourceModel()->index(end, column, parent));
1014 
1015  kDebug() << "firstAffectedIndex" << firstAffectedIndex.data();
1016  kDebug() << "lastAffectedIndex" << lastAffectedIndex.data();
1017 
1018  QModelIndex proxyParent = firstAffectedIndex.parent();
1019 
1020  Q_ASSERT(firstAffectedIndex.isValid() && lastAffectedIndex.isValid());
1021 
1022  forever
1023  {
1024  if (isDescendantInModel(proxyParent, lastAffectedIndex))
1025  {
1026  // They share a common ancestor.
1027 
1028  QModelIndex _parent = lastAffectedIndex.parent();
1029  QModelIndex lastAffectedAncestor = lastAffectedIndex;
1030  kDebug() << "last affected ancestor" << lastAffectedAncestor.data();
1031  while (_parent != proxyParent)
1032  {
1033  lastAffectedAncestor = _parent;
1034  _parent = _parent.parent();
1035  }
1036 
1037  if (q->hasChildren(lastAffectedAncestor))
1038  {
1039  QModelIndex next = q->index(0, 0, lastAffectedAncestor);
1040 
1041  QModelIndex proxySourceParent = lastAffectedAncestor;
1042  int startRow = next.row();
1043  int lastRow = q->rowCount(lastAffectedAncestor) - 1;
1044 
1045  QList<QPersistentModelIndex> &existingSourceIndexes = m_childIndexes[q->mapToSource(proxySourceParent)];
1046  QList<QPersistentModelIndex> &existingDestinationIndexes = m_childIndexes[q->mapToSource(proxyParent)];
1047 
1048  int destRow = lastAffectedAncestor.row() + 1;
1049 
1050 
1051  kDebug() << "Move from" << lastAffectedAncestor.data() << startRow << lastRow << " To " << proxyParent.data() << destRow;
1052  bool allowMove = q->beginMoveRows(lastAffectedAncestor, startRow, lastRow, proxyParent, destRow);
1053  Q_ASSERT(allowMove);
1054 
1055  for (int i = startRow; i <= lastRow; ++i)
1056  {
1057  QPersistentModelIndex movingIdx = existingSourceIndexes.takeAt(startRow);
1058  existingDestinationIndexes.insert(destRow + (i - startRow), movingIdx);
1059  }
1060 
1061  // TODO: If source was a parent before, it might not be now.
1062  // dest was already a parent.
1063 
1064  q->endMoveRows();
1065  }
1066  PendingRemoval removal;
1067  removal.index = proxyParent;
1068  removal.start = firstAffectedIndex.row();
1069  removal.end = lastAffectedAncestor.row();
1070  removal.parentId = proxyParent.internalId();
1071  removal.sourceIndex = q->mapToSource(proxyParent);
1072  m_pendingRemovals.append(removal);
1073 
1074  removeTree(q->mapToSource(proxyParent), removal.start, removal.end);
1075 
1076  kDebug() << "beg rem 1";
1077  q->beginRemoveRows(proxyParent, removal.start, removal.end);
1078 
1079  return;
1080 
1081  } else {
1082  QModelIndex next = getIndexBelow(firstAffectedIndex);
1083 
1084  proxyParent = next.parent();
1085 
1086  while (isDescendantInModel(proxyParent, next))
1087  {
1088  next = getIndexBelow(next);
1089  }
1090  QModelIndex _parent = next.parent();
1091  QModelIndex lastAffectedAncestor = next;
1092 
1093  while (_parent != proxyParent)
1094  {
1095  lastAffectedAncestor = _parent;
1096  _parent = _parent.parent();
1097  }
1098 
1099  PendingRemoval removal;
1100  removal.index = proxyParent;
1101  removal.start = firstAffectedIndex.row();
1102  removal.end = lastAffectedAncestor.row();
1103  removal.parentId = proxyParent.internalId();
1104  removal.sourceIndex = q->mapToSource(proxyParent);
1105  m_pendingRemovals.append(removal);
1106 
1107  removeTree(q->mapToSource(proxyParent), removal.start, removal.end);
1108 
1109  kDebug() << "beg rem 1";
1110  q->beginRemoveRows(proxyParent, removal.start, removal.end);
1111 
1112  proxyParent = next.parent();
1113  }
1114  }
1115 
1116 
1117 // // kDebug() << proxyParent.data() << lastAffectedIndex.parent().data() << proxyParent << lastAffectedIndex.parent();
1118 // if (proxyParent == lastAffectedIndex.parent())
1119 // {
1120 // PendingRemoval removal;
1121 // removal.index = proxyParent;
1122 // removal.start = firstAffectedIndex.row();
1123 // removal.end = lastAffectedIndex.row();
1124 // removal.parentId = proxyParent.internalId();
1125 // removal.sourceIndex = q->mapToSource(proxyParent);
1126 // m_pendingRemovals.append(removal);
1127 //
1128 // // Also need to store a removal object for each of the descendants.
1129 //
1130 // removeTree(q->mapToSource(proxyParent), removal.start, removal.end);
1131 //
1132 // // kDebug() << "beg rem 1";
1133 // q->beginRemoveRows(proxyParent, removal.start, removal.end);
1134 // return;
1135 // }
1136 //
1137 // QModelIndex lastParent = lastAffectedIndex.parent();
1138 // while (lastParent.parent().isValid())
1139 // {
1140 // if (lastParent.parent() == proxyParent)
1141 // {
1142 // PendingRemoval removal;
1143 // removal.index = proxyParent;
1144 // removal.start = firstAffectedIndex.row();
1145 // removal.end = lastParent.row();
1146 // removal.parentId = proxyParent.internalId();
1147 // removal.sourceIndex = q->mapToSource(proxyParent);
1148 // m_pendingRemovals.append(removal);
1149 //
1150 // // kDebug() << "beg rem 2";
1151 // q->beginRemoveRows(proxyParent, removal.start, removal.end);
1152 // return;
1153 // }
1154 // lastParent = lastParent.parent();
1155 // }
1156 //
1157 // // Several blocks need to be removed from the proxy model.
1158 // // Divide and conquer to find them.
1159 //
1160 // int proxyStart = firstAffectedIndex.row();
1161 // int proxyEnd = proxyStart + (end - start);
1162 // int processedUntil = start;
1163 //
1164 // while (processedUntil <= end)
1165 // {
1166 // QModelIndex lastInParent = findLastInParent(proxyParent, proxyStart, proxyEnd);
1167 // qDebug() << "lastInParent" << lastInParent;
1168 //
1169 // QModelIndex sourceLast = q->mapToSource(lastInParent);
1170 // processedUntil = sourceLast.row();
1171 //
1172 // PendingRemoval removal;
1173 // removal.index = proxyParent;
1174 // removal.start = proxyStart;
1175 // removal.end = lastInParent.row();
1176 // removal.parentId = proxyParent.internalId();
1177 // removal.sourceIndex = q->mapToSource(proxyParent);
1178 // m_pendingRemovals.append(removal);
1179 //
1180 // kDebug() << "beg rem 3";
1181 // q->beginRemoveRows(proxyParent, removal.start, removal.end);
1182 //
1183 // QModelIndex proxyIndexBelow = getIndexBelow(lastInParent, q);
1184 //
1185 // if (!proxyIndexBelow.isValid())
1186 // return;
1187 //
1188 // proxyParent = proxyIndexBelow.parent();
1189 // proxyStart = proxyIndexBelow.row();
1190 // }
1191 }
1192 
1193 
1194 QModelIndex KReparentingProxyModelPrivate::findLastInParent(QModelIndex parent, int start, int end)
1195 {
1196  Q_Q(KReparentingProxyModel);
1197 
1198  const int column = 0;
1199 
1200  if (start == end)
1201  return q->index(start, column, parent);
1202 
1203  int middle = start + (end - start / 2);
1204 
1205  QModelIndex sourceParent = q->mapToSource(parent);
1206  QModelIndex middleIndex = q->mapFromSource(q->sourceModel()->index(middle, column, sourceParent));
1207 
1208  if (middleIndex.parent() == parent)
1209  {
1210  return findLastInParent(parent, middle, end);
1211  } else {
1212  return findLastInParent(parent, start + ((middle - start) / 2), middle);
1213  }
1214 }
1215 
1216 
1217 // qDebug() << affectedIndex << affectedIndex.data() << proxyParent;
1218 //
1219 // QHash<QModelIndex, PendingRemoval> pendingRemovals;
1220 //
1221 // int i = start;
1222 // while (i <= end)
1223 // {
1224 // affectedIndex = affectedIndex.sibling(i, column);
1225 //
1226 // // affectedIndex = getIndexBelow(affectedIndex, q);
1227 // if (!affectedIndex.isValid())
1228 // break;
1229 // // Q_ASSERT(affectedIndex.isValid());
1230 //
1231 // if (affectedIndex.parent() != proxyParent)
1232 // {
1233 // // affectedIndex.parent() must be left of proxyParent
1234 //
1235 // PendingRemoval removal;
1236 // removal.index = proxyParent;
1237 // removal.start = start;
1238 // removal.end = i;
1239 // pendingRemovals.insert(proxyParent, removal);
1240 //
1241 // emit q->rowsAboutToBeRemoved(proxyParent, start, i);
1242 // proxyParent = affectedIndex.parent();
1243 //
1244 // end -= (i - start + 1);
1245 // start = affectedIndex.row();
1246 // i = start;
1247 // }
1248 //
1249 // ++i;
1250 // }
1251 
1252  // Move younger siblings out of the way so that the rows can be removed easily
1253  // No. It's easier to use verifyStructure afterward.
1254 
1255 // // Removing rows in the source model could require sending the children to their grandparents.
1256 //
1257 // QHash<QModelIndex, QModelIndexList> mappings;
1258 // recreateMappings(parent, start, end);
1259 //
1260 // QHashIterator<QModelIndex, QModelIndexList> it(mappings);
1261 // while (it.hasNext())
1262 // {
1263 // it.next();
1264 // QModelIndexList removedList = it.value();
1265 // PendingRemoval pendingRemoval;
1266 // pendingRemoval.index = it.key();
1267 // pendingRemoval.start = q->mapFromSource(removedList.at(0)).row();
1268 // pendingRemoval.end = pendingRemoval.start + removedList.size() - 1;
1269 // m_pendingRemovals.insert(parent, pendingRemoval);
1270 // }
1271 // }
1272 
1273 void KReparentingProxyModelPrivate::handleRemoval(const PendingRemoval &pendingRemoval)
1274 {
1275 // Q_Q(KReparentingProxyModel);
1276 // q->beginRemoveRows(pendingRemoval.index, pendingRemoval.start, pendingRemoval.end);
1277 // m_childIndexes.remove(pendingRemoval.index);
1278 // // Remove stuff from m_parents.
1279 // q->endRemoveRows();
1280 }
1281 
1282 void KReparentingProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent, int start, int end)
1283 {
1284  kDebug() << parent << start << end;
1285 
1286  Q_Q(KReparentingProxyModel);
1287 
1288  // loop over pending removals and process each one. Then look after the last one
1289  // to move displaced rows to where they should be.
1290 
1291  int lastAffectedRow = m_pendingRemovals.last().end;
1292  QModelIndex lastAffectedIndex = m_pendingRemovals.last().index;
1293 
1294  QMutableVectorIterator<PendingRemoval> it(m_pendingRemovals);
1295 
1296  while (it.hasNext())
1297  {
1298  PendingRemoval removal = it.next();
1299  m_pendingRemovalChildIndexes.remove(removal.sourceIndex);
1300  m_pendingRemovalParents.remove(parent.internalId());
1301  it.remove();
1302 
1303  emit q->endRemoveRows();
1304  }
1305  kDebug() << "Remove done ##########";
1306 
1307  kDebug() << lastAffectedIndex << lastAffectedIndex.data() << lastAffectedRow;
1308 
1309  verifyStructure(lastAffectedIndex, lastAffectedRow - 1);
1310 }
1311 
1312 void KReparentingProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex& destParent, int destRow)
1313 {
1314  // This could be several individual moves in the proxy model, or it could be no moves at all.
1315  // We can get the top indexes of the moved list and move those.
1316  // because their children won't be moved anywhere different.
1317 
1318  Q_Q(KReparentingProxyModel);
1319 
1320  QModelIndex proxySourceParent = q->mapFromSource(parent);
1321  QModelIndex proxyDestinationParent = q->mapFromSource(destParent);
1322 
1323  // I could look at the indexes between start and end (proxied could be several blocks), and move them to dest.
1324  // Then verify structure.
1325  // This could lead to an illegal move.
1326  // If we have
1327  //
1328  // Source: Proxy:
1329  // A A
1330  // B B
1331  // C - C
1332  // D - D
1333  // E E
1334  //
1335  // then source can legally move B to between C and D, however, implemented naively the proxymodel would attempt an illegal move.
1336  // We must first reparent everything below destRow in the proxy to the parent of parent in this case, then perform the move, then
1337  // verifyStructure.
1338  //
1339  // Moving B C and D to below E would be a legal move in the proxy model.
1340  //
1341  // Children of moved indexes which are not themselves moved must be first sent to their grandparents.
1342  // So if B and C were moved in the source model above to below E, D would first be moved to its grandparent, then B would be moved below E,
1343  // then the structure would need to be verified.
1344  //
1345  // Proxy start state: Intermediate state: Intermediate or final state: Possible alternative final state:
1346  // A A A A
1347  // B B E E
1348  // - C - C D - D
1349  // - D D B B
1350  // E E - C - C
1351 
1352  // So, I could iterate from start to end in proxySourceParent and if the depth goes less than parent, emit a block move, then start again.
1353 
1354 
1355  QHash<QModelIndex, QModelIndexList> newMappings = recreateMappings(parent, start, end);
1356 
1357 }
1358 
1359 void KReparentingProxyModelPrivate::sourceRowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex& destParent, int destRow)
1360 {
1361 
1362 }
1363 
1364 void KReparentingProxyModelPrivate::sourceLayoutAboutToBeChanged()
1365 {
1366  Q_Q(KReparentingProxyModel);
1367 
1368  emit q->layoutAboutToBeChanged();
1369 
1370  foreach( const QPersistentModelIndex &proxyPersistentIndex, q->persistentIndexList()) {
1371  m_proxyIndexes << proxyPersistentIndex;
1372  m_layoutChangePersistentIndexes << QPersistentModelIndex(q->mapToSource(proxyPersistentIndex));
1373  }
1374 }
1375 
1376 void KReparentingProxyModelPrivate::sourceLayoutChanged()
1377 {
1378  Q_Q(KReparentingProxyModel);
1379 
1380  for(int i = 0; i < m_proxyIndexes.size(); ++i)
1381  {
1382  q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i)));
1383  }
1384 
1385  m_layoutChangePersistentIndexes.clear();
1386  m_proxyIndexes.clear();
1387 
1388  emit q->layoutChanged();
1389 }
1390 
1391 void KReparentingProxyModelPrivate::sourceModelAboutToBeReset()
1392 {
1393  Q_Q(KReparentingProxyModel);
1394  q->beginResetModel();
1395 }
1396 
1397 void KReparentingProxyModelPrivate::sourceModelReset()
1398 {
1399  Q_Q(KReparentingProxyModel);
1400 
1401  m_parents.clear();
1402  m_childIndexes.clear();
1403  m_nextId = 0;
1404  m_pendingInsertions.clear();
1405  m_pendingRemovals.clear();
1406  m_pendingRemovalChildIndexes.clear();
1407  m_pendingRemovalParents.clear();
1408  q->endResetModel();
1409 }
1410 
1411 void KReparentingProxyModelPrivate::emitDataChangedSignals(const QModelIndex &startIndex, int maxChanged)
1412 {
1413  Q_Q(KReparentingProxyModel);
1414 
1415  QModelIndex proxyParent = startIndex.parent();
1416 
1417  const int column = 0;
1418 
1419  int numChanged = 1;
1420 
1421  QModelIndex lastAffectedSibling = startIndex;
1422  QModelIndex proxySibling = getIndexBelow(startIndex, q);
1423 
1424  forever
1425  {
1426  if (proxySibling.parent() != proxyParent || numChanged >= maxChanged)
1427  break;
1428 
1429  numChanged++;
1430  lastAffectedSibling = proxySibling;
1431 
1432  proxySibling = getIndexBelow(proxySibling);
1433  }
1434 
1435  emit q->dataChanged(startIndex, lastAffectedSibling);
1436  if (numChanged < maxChanged)
1437  {
1438  emitDataChangedSignals(proxySibling, maxChanged - numChanged);
1439  }
1440 }
1441 
1442 void KReparentingProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
1443 {
1444  Q_Q(KReparentingProxyModel);
1445  QModelIndex parent = topLeft.parent();
1446  const int start = topLeft.row();
1447  const int end = bottomRight.row();
1448  const int column = 0;
1449  const int maxChanged = end - start + 1;
1450 
1451  // Create mappings to the end because changing data can affect structure of siblings.
1452  verifyStructure(parent, start);
1453 
1454  // mapFromSource and emit signals.
1455 
1456  QModelIndex proxyStartIndex = q->mapFromSource(q->sourceModel()->index(start, column, parent));
1457 
1458  emitDataChangedSignals(proxyStartIndex, maxChanged);
1459 
1460 }
1461 
1462 Qt::DropActions KReparentingProxyModel::supportedDropActions() const
1463 {
1464  Q_ASSERT(sourceModel());
1465  return sourceModel()->supportedDropActions();
1466 }
1467 
1468 
1469 #include "kreparentingproxymodel.moc"
KReparentingProxyModel::rowCount
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const
Definition: kreparentingproxymodel.cpp:671
KReparentingProxyModel::hasChildren
virtual bool hasChildren(const QModelIndex &parent=QModelIndex()) const
Definition: kreparentingproxymodel.cpp:692
QVector
Definition: kcolumnfilterproxymodel.h:30
QObject
KReparentingProxyModel::parent
virtual QModelIndex parent(const QModelIndex &child) const
Definition: kreparentingproxymodel.cpp:619
KReparentingProxyModel::~KReparentingProxyModel
~KReparentingProxyModel()
Definition: kreparentingproxymodel.cpp:441
KReparentingProxyModel
Restructures a source model, changing the parents of items.
Definition: kreparentingproxymodel.h:74
kreparentingproxymodel.h
KReparentingProxyModel::index
virtual QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const
Definition: kreparentingproxymodel.cpp:588
KReparentingProxyModel::isDescendantOf
virtual bool isDescendantOf(const QModelIndex &ancestor, const QModelIndex &descendant) const
Reimplement this to return whether descendant is a descendant of ancestor.
Definition: kreparentingproxymodel.cpp:463
KReparentingProxyModel::data
virtual QVariant data(const QModelIndex &proxyIndex, int role=Qt::DisplayRole) const
Definition: kreparentingproxymodel.cpp:583
KReparentingProxyModel::mapToSource
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const
Definition: kreparentingproxymodel.cpp:503
KReparentingProxyModel::mapFromSource
virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const
Definition: kreparentingproxymodel.cpp:470
QAbstractProxyModel
KReparentingProxyModel::supportedDropActions
virtual Qt::DropActions supportedDropActions() const
Definition: kreparentingproxymodel.cpp:1462
KReparentingProxyModel::columnCount
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const
Definition: kreparentingproxymodel.cpp:566
KReparentingProxyModel::setSourceModel
virtual void setSourceModel(QAbstractItemModel *sourceModel)
Definition: kreparentingproxymodel.cpp:697
KReparentingProxyModel::KReparentingProxyModel
KReparentingProxyModel(QObject *parent=0)
Definition: kreparentingproxymodel.cpp:435
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:54:56 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi_next

Skip menu "akonadi_next"
  • Main Page
  • Namespace List
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer

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