25 #include <QtCore/QStringList>
26 #include <QtCore/QTimer>
30 #define KDO(object) kDebug() << #object << object
32 #include "kbihash_p.h"
34 typedef KHash2Map<QPersistentModelIndex, int>
Mapping;
36 class KDescendantsProxyModelPrivate
41 m_ignoreNextLayoutAboutToBeChanged(
false),
42 m_ignoreNextLayoutChanged(
false),
44 m_displayAncestorData(
false ),
54 void scheduleProcessPendingParents()
const;
55 void processPendingParents();
57 void synchronousMappingRefresh();
59 void updateInternalIndexes(
int start,
int offset);
61 void resetInternalData();
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);
69 void sourceModelAboutToBeReset();
70 void sourceModelReset();
71 void sourceLayoutAboutToBeChanged();
72 void sourceLayoutChanged();
74 void sourceModelDestroyed();
81 bool m_ignoreNextLayoutAboutToBeChanged;
82 bool m_ignoreNextLayoutChanged;
85 bool m_displayAncestorData;
89 QModelIndexList m_proxyIndexes;
92 void KDescendantsProxyModelPrivate::resetInternalData()
96 m_layoutChangePersistentIndexes.clear();
97 m_proxyIndexes.clear();
100 void KDescendantsProxyModelPrivate::synchronousMappingRefresh()
104 m_pendingParents.clear();
108 m_relayouting =
true;
109 while (!m_pendingParents.isEmpty())
111 processPendingParents();
113 m_relayouting =
false;
116 void KDescendantsProxyModelPrivate::scheduleProcessPendingParents()
const
119 const_cast<KDescendantsProxyModelPrivate*
>(
this)->processPendingParents();
122 void KDescendantsProxyModelPrivate::processPendingParents()
129 static const int chunkSize = 30;
132 m_pendingParents.end();
136 while (it != end && it != m_pendingParents.
end()) {
138 if (!sourceParent.
isValid() && m_rowCount > 0)
141 it = m_pendingParents.
erase(it);
144 const int rowCount = q->sourceModel()->rowCount(sourceParent);
146 Q_ASSERT(rowCount > 0);
149 Q_ASSERT(sourceIndex.
isValid());
151 const QModelIndex proxyParent = q->mapFromSource(sourceParent);
153 Q_ASSERT(sourceParent.
isValid() == proxyParent.isValid());
154 const int proxyEndRow = proxyParent.
row() + rowCount;
155 const int proxyStartRow = proxyEndRow - rowCount + 1;
158 q->beginInsertRows(
QModelIndex(), proxyStartRow, proxyEndRow);
160 updateInternalIndexes(proxyStartRow, rowCount);
161 m_mapping.insert(sourceIndex, proxyEndRow);
162 it = m_pendingParents.
erase(it);
163 m_rowCount += rowCount;
168 for (
int sourceRow = 0; sourceRow < rowCount; ++sourceRow ) {
169 static const int column = 0;
170 const QModelIndex child = q->sourceModel()->index(sourceRow, column, sourceParent);
173 if (q->sourceModel()->hasChildren(child))
175 Q_ASSERT(q->sourceModel()->rowCount(child) > 0);
176 newPendingParents.
append(child);
180 m_pendingParents += newPendingParents;
181 if (!m_pendingParents.isEmpty())
182 processPendingParents();
186 void KDescendantsProxyModelPrivate::updateInternalIndexes(
int start,
int offset)
191 Mapping::right_iterator it = m_mapping.rightLowerBound(start);
192 const Mapping::right_iterator end = m_mapping.rightEnd();
196 updates.
insert(it.key() + offset, *it);
205 for ( ; it !=
end; ++it)
207 m_mapping.insert(it.value(), it.key());
236 d->m_displayAncestorData = display;
242 return d->m_displayAncestorData;
248 d->m_ancestorSeparator = separator;
254 return d->m_ancestorSeparator;
264 this, SLOT(sourceRowsAboutToBeInserted(
QModelIndex,
int,
int)));
266 this, SLOT(sourceRowsInserted(
QModelIndex,
int,
int)));
268 this, SLOT(sourceRowsAboutToBeRemoved(
QModelIndex,
int,
int)));
270 this, SLOT(sourceRowsRemoved(
QModelIndex,
int,
int)));
276 this, SLOT(sourceModelAboutToBeReset()));
278 this, SLOT(sourceModelReset()));
282 this, SLOT(sourceLayoutAboutToBeChanged()));
284 this, SLOT(sourceLayoutChanged()));
286 this, SLOT(sourceModelDestroyed()));
293 SLOT(sourceRowsAboutToBeInserted(
QModelIndex,
int,
int)));
297 SLOT(sourceRowsAboutToBeRemoved(
QModelIndex,
int,
int)));
305 SLOT(sourceModelAboutToBeReset()));
307 SLOT(sourceModelReset()));
311 SLOT(sourceLayoutAboutToBeChanged()));
313 SLOT(sourceLayoutChanged()));
315 SLOT(sourceModelDestroyed()));
330 return !(d->m_mapping.isEmpty() || parent.
isValid());
342 const_cast<KDescendantsProxyModelPrivate*
>(d)->synchronousMappingRefresh();
344 return d->m_rowCount;
364 const Mapping::right_const_iterator result = d->m_mapping.rightLowerBound(proxyIndex.
row());
365 Q_ASSERT(result != d->m_mapping.rightEnd());
367 const int proxyLastRow = result.key();
368 const QModelIndex sourceLastChild = result.value();
369 Q_ASSERT(sourceLastChild.
isValid());
400 int verticalDistance = proxyLastRow - proxyIndex.
row();
407 const int ancestorRow = ancestor.
row();
408 if (verticalDistance <= ancestorRow)
410 return ancestor.
sibling(ancestorRow - verticalDistance, proxyIndex.
column());
412 verticalDistance -= (ancestorRow + 1);
413 ancestor = ancestor.
parent();
415 Q_ASSERT(!
"Didn't find target row.");
426 if (d->m_mapping.isEmpty())
433 Mapping::right_const_iterator it = d->m_mapping.rightConstBegin();
434 const Mapping::right_const_iterator end = d->m_mapping.rightConstEnd();
436 Mapping::right_const_iterator result =
end;
438 for ( ; it !=
end; ++it )
441 bool found_block =
false;
445 if (ancestor == sourceParent && index.
row() >= sourceIndex.
row())
448 if (result == end || it.key() < result.key())
456 if (found_block && !index.
isValid())
461 Q_ASSERT(result != end);
462 const QModelIndex sourceLastChild = result.value();
463 int proxyRow = result.key();
468 if (ancestor == sourceParent)
472 proxyRow -= (index.
row() + 1);
475 Q_ASSERT(!
"Didn't find valid proxy mapping.");
501 if ((d->m_displayAncestorData) && ( role == Qt::DisplayRole ) )
508 sourceIndex = sourceIndex.
parent();
511 displayData.
prepend(d->m_ancestorSeparator);
513 sourceIndex = sourceIndex.
parent();
517 return sourceIndex.
data(role);
539 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeInserted(
const QModelIndex &parent,
int start,
int end)
543 if (!q->sourceModel()->hasChildren(parent))
545 Q_ASSERT(q->sourceModel()->rowCount(parent) == 0);
552 const int rowCount = q->sourceModel()->rowCount(parent);
554 if (rowCount > start)
556 const QModelIndex belowStart = q->sourceModel()->index(start, 0, parent);
557 proxyStart = q->mapFromSource(belowStart).
row();
558 }
else if (rowCount == 0)
560 proxyStart = q->mapFromSource(parent).row() + 1;
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))
567 Q_ASSERT(q->sourceModel()->rowCount(idx) > 0);
568 idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx);
571 proxyStart = q->mapFromSource(idx).
row() + 1;
573 const int proxyEnd = proxyStart + (end - start);
575 m_insertPair = qMakePair(proxyStart, proxyEnd);
576 q->beginInsertRows(
QModelIndex(), proxyStart, proxyEnd);
579 void KDescendantsProxyModelPrivate::sourceRowsInserted(
const QModelIndex &parent,
int start,
int end)
583 const QModelIndex sourceStart = q->sourceModel()->index(start, 0, parent);
584 Q_ASSERT(sourceStart.
isValid());
586 const int rowCount = q->sourceModel()->rowCount(parent);
587 Q_ASSERT(rowCount > 0);
589 const int difference = end - start + 1;
591 if (rowCount == difference)
594 m_pendingParents.append(parent);
595 scheduleProcessPendingParents();
599 const int proxyStart = m_insertPair.first;
601 Q_ASSERT(proxyStart >= 0);
603 updateInternalIndexes(proxyStart, difference);
605 if (rowCount - 1 == end)
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));
643 const QModelIndex newIndex = q->sourceModel()->index(rowCount - 1, column, parent);
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);
661 Q_ASSERT(q->sourceModel()->rowCount(indexAbove) == 0);
664 Q_ASSERT(m_mapping.leftContains(indexAbove));
666 const int newProxyRow = m_mapping.leftToRight(indexAbove) + difference;
669 m_mapping.removeLeft(oldIndex);
672 m_mapping.insert(newIndex, newProxyRow);
675 for (
int row = start; row <=
end; ++row)
677 static const int column = 0;
678 const QModelIndex idx = q->sourceModel()->index(row, column, parent);
680 if (q->sourceModel()->hasChildren(idx))
682 Q_ASSERT(q->sourceModel()->rowCount(idx) > 0);
683 m_pendingParents.append(idx);
687 m_rowCount += difference;
690 scheduleProcessPendingParents();
693 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeRemoved(
const QModelIndex &parent,
int start,
int end)
697 const int proxyStart = q->mapFromSource(q->sourceModel()->index(start, 0, parent)).row();
699 static const int column = 0;
700 QModelIndex idx = q->sourceModel()->index(end, column, parent);
701 while (q->sourceModel()->hasChildren(idx))
703 Q_ASSERT(q->sourceModel()->rowCount(idx) > 0);
704 idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx);
706 const int proxyEnd = q->mapFromSource(idx).
row();
708 m_removePair = qMakePair(proxyStart, proxyEnd);
710 q->beginRemoveRows(
QModelIndex(), proxyStart, proxyEnd);
714 static const int column = 0;
716 Q_ASSERT(model->
rowCount(parent) > 0);
717 for (
int row = 0; row < model->
rowCount(parent); ++row) {
724 return model->
index(model->
rowCount(parent) - 1, column, parent);
727 void KDescendantsProxyModelPrivate::sourceRowsRemoved(
const QModelIndex &parent,
int start,
int end)
732 const
int rowCount = q->sourceModel()->rowCount(parent);
735 const
int proxyStart = m_removePair.first;
736 const
int proxyEnd = m_removePair.second;
738 const
int difference = proxyEnd - proxyStart + 1;
740 Mapping::right_iterator it = m_mapping.rightLowerBound(proxyStart);
741 const Mapping::right_iterator endIt = m_mapping.rightUpperBound(proxyEnd);
743 if (endIt != m_mapping.rightEnd())
745 it = m_mapping.eraseRight(it);
747 while (it != m_mapping.rightUpperBound(proxyEnd))
748 it = m_mapping.eraseRight(it);
751 m_removePair = qMakePair(-1, -1);
752 m_rowCount -= difference;
753 Q_ASSERT(m_rowCount >= 0);
755 updateInternalIndexes(proxyStart, -1 * difference);
757 if (rowCount != start || rowCount == 0) {
762 static const int column = 0;
763 const QModelIndex newEnd = q->sourceModel()->index(rowCount - 1, column, parent);
766 if (m_mapping.isEmpty()) {
767 m_mapping.insert(newEnd, newEnd.
row());
771 if (q->sourceModel()->hasChildren(newEnd)) {
774 Q_ASSERT(firstDeepest.
isValid());
775 const int firstDeepestProxy = m_mapping.leftToRight(firstDeepest);
777 m_mapping.insert(newEnd, firstDeepestProxy - count);
781 Mapping::right_iterator lowerBound = m_mapping.rightLowerBound(proxyStart);
782 if (lowerBound == m_mapping.rightEnd()) {
783 int proxyRow = (lowerBound - 1).key();
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)) {
793 m_mapping.insert(newEnd, proxyRow);
796 }
else if (lowerBound == m_mapping.rightBegin()) {
797 int proxyRow = rowCount - 1;
799 while (trackedParent.
isValid()) {
800 proxyRow += (trackedParent.
row() + 1);
801 trackedParent = trackedParent.
parent();
803 m_mapping.insert(newEnd, proxyRow);
807 const Mapping::right_iterator boundAbove = lowerBound - 1;
815 if (target == boundAbove.value()) {
816 m_mapping.insert(newEnd, count + boundAbove.key() + newEnd.
row() + 1);
820 count += (target.
row() + 1);
829 Q_ASSERT(boundParent.
isValid());
830 while (boundParent.
isValid()) {
831 prevParent = boundParent;
832 boundParent = boundParent.
parent();
834 if (targetParents.
contains(prevParent))
837 if (!m_mapping.leftContains(prevParent))
840 if (m_mapping.leftToRight(prevParent) > boundAbove.key())
846 int proxyRow = boundAbove.key();
848 Q_ASSERT(prevParent.
isValid());
849 proxyRow -= prevParent.
row();
850 while (trackedParent != boundParent) {
851 proxyRow += (trackedParent.
row() + 1);
852 trackedParent = trackedParent.
parent();
854 m_mapping.insert(newEnd, proxyRow + newEnd.
row());
858 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeMoved(
const QModelIndex &srcParent,
int srcStart,
int srcEnd,
const QModelIndex &destParent,
int destStart)
866 q->beginResetModel();
869 void KDescendantsProxyModelPrivate::sourceRowsMoved(const
QModelIndex &srcParent,
int srcStart,
int srcEnd, const
QModelIndex &destParent,
int destStart)
876 Q_Q(KDescendantsProxyModel);
881 void KDescendantsProxyModelPrivate::sourceModelAboutToBeReset()
883 Q_Q(KDescendantsProxyModel);
884 q->beginResetModel();
887 void KDescendantsProxyModelPrivate::sourceModelReset()
889 Q_Q(KDescendantsProxyModel);
891 if (q->sourceModel()->hasChildren())
893 Q_ASSERT(q->sourceModel()->rowCount() > 0);
895 scheduleProcessPendingParents();
900 void KDescendantsProxyModelPrivate::sourceLayoutAboutToBeChanged()
902 Q_Q(KDescendantsProxyModel);
904 if (m_ignoreNextLayoutChanged) {
905 m_ignoreNextLayoutChanged =
false;
909 if (m_mapping.isEmpty())
914 m_proxyIndexes << proxyPersistentIndex;
915 Q_ASSERT(proxyPersistentIndex.isValid());
916 srcPersistentIndex = q->mapToSource(proxyPersistentIndex);
917 Q_ASSERT(srcPersistentIndex.isValid());
918 m_layoutChangePersistentIndexes << srcPersistentIndex;
921 q->layoutAboutToBeChanged();
924 void KDescendantsProxyModelPrivate::sourceLayoutChanged()
926 Q_Q(KDescendantsProxyModel);
928 if (m_ignoreNextLayoutAboutToBeChanged) {
929 m_ignoreNextLayoutAboutToBeChanged =
false;
933 if (m_mapping.isEmpty())
938 synchronousMappingRefresh();
940 for (
int i = 0; i < m_proxyIndexes.size(); ++i) {
941 q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i)));
944 m_layoutChangePersistentIndexes.clear();
945 m_proxyIndexes.clear();
950 void KDescendantsProxyModelPrivate::sourceDataChanged(
const QModelIndex &topLeft,
const QModelIndex &bottomRight)
952 Q_Q(KDescendantsProxyModel);
953 Q_ASSERT(topLeft.
model() == q->sourceModel());
954 Q_ASSERT(bottomRight.
model() == q->sourceModel());
956 const int topRow = topLeft.
row();
957 const int bottomRow = bottomRight.
row();
959 for(
int i = topRow; i <= bottomRow; ++i)
962 Q_ASSERT(sourceTopLeft.
isValid());
963 const QModelIndex proxyTopLeft = q->mapFromSource(sourceTopLeft);
967 const QModelIndex proxyBottomRight = q->mapFromSource(sourceBottomRight);
968 Q_ASSERT(proxyTopLeft.isValid());
969 Q_ASSERT(proxyBottomRight.
isValid());
970 emit q->dataChanged(proxyTopLeft, proxyBottomRight);
974 void KDescendantsProxyModelPrivate::sourceModelDestroyed()
976 Q_Q(KDescendantsProxyModel);
986 QModelIndexList sourceIndexes;
1007 #include "moc_kdescendantsproxymodel.cpp"
bool hasIndex(int row, int column, const QModelIndex &parent) const
void setRootIndex(const QModelIndex &index)
virtual int rowCount(const QModelIndex &parent) const =0
iterator insert(const Key &key, const T &value)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const =0
virtual QModelIndex index(int, int, const QModelIndex &parent=QModelIndex()) const
Proxy Model for restructuring a Tree into a list.
void append(const T &value)
virtual Qt::DropActions supportedDropActions() const
QString & prepend(QChar ch)
virtual QMimeData * mimeData(const QModelIndexList &indexes) const
iterator erase(iterator begin, iterator end)
void modelAboutToBeReset()
virtual QMimeData * mimeData(const QModelIndexList &indexes) const
void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
virtual QStringList mimeTypes() const
QModelIndex mapToSource(const QModelIndex &proxyIndex) const
virtual QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits, QFlags< Qt::MatchFlag > flags) const
void layoutAboutToBeChanged()
void setAncestorSeparator(const QString &separator)
Sets the ancestor separator used between data of ancestors.
bool contains(const T &value) const
void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
const_iterator constEnd() const
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
virtual bool hasChildren(const QModelIndex &parent=QModelIndex()) const
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const
QString ancestorSeparator() const
Separator used between data of ancestors.
virtual Qt::DropActions supportedDropActions() const
virtual void setSourceModel(QAbstractItemModel *sourceModel)
static QModelIndex getFirstDeepest(QAbstractItemModel *model, const QModelIndex &parent, int *count)
virtual QVariant data(const QModelIndex &index, int role) const =0
KDescendantsProxyModel(QObject *parent=0)
Creates a new descendant entities proxy model.
virtual QMimeData * mimeData(const QModelIndexList &indexes) const
QModelIndex parent() const
void rowsRemoved(const QModelIndex &parent, int start, int end)
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
QModelIndex createIndex(int row, int column, void *ptr) const
virtual Qt::DropActions supportedDropActions() const
virtual QStringList mimeTypes() const
const_iterator constBegin() const
QAbstractItemModel * sourceModel() const
const QAbstractItemModel * model() const
virtual int columnCount(const QModelIndex &index=QModelIndex()) const
QVariant data(int role) const
virtual void setSourceModel(QAbstractItemModel *model)
Sets the source model of the proxy.
virtual bool hasChildren(const QModelIndex &parent) const
QModelIndex sibling(int row, int column) const
virtual Qt::ItemFlags flags(const QModelIndex &index) const
virtual Qt::ItemFlags flags(const QModelIndex &index) const
KHash2Map< QPersistentModelIndex, int > Mapping
virtual int columnCount(const QModelIndex &parent) const =0
void setDisplayAncestorData(bool display)
Set whether to show ancestor data in the model.
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const
void push_back(const T &value)
virtual ~KDescendantsProxyModel()
Destroys the descendant entities proxy model.
virtual Qt::ItemFlags flags(const QModelIndex &index) const
void rowsInserted(const QModelIndex &parent, int start, int end)
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
const KShortcut & end()
Goto end of the document.
virtual QStringList mimeTypes() const
bool displayAncestorData() const
Whether ancestor data will be displayed.
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const
void destroyed(QObject *obj)
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.
const KShortcut & begin()
Goto beginning of the document.