on xenial help sign in
Fix insertions/removals on the qlimitproxymodel
commitd5f8aefdebbf0c0773be7c3249aee8607677039a authorAlbert Astals <albert.astals@canonical.com> dateTue 20 Aug 2013, 17:13 (13 years ago) parent2563253
3 files changed+185−12
plugins/Utils/qlimitproxymodelqml.cpp+50−4 plugins/Utils/qlimitproxymodelqml.h+2 tests/plugins/Utils/qlimitproxymodeltest.cpp+133−8
plugins/Utils/qlimitproxymodelqml.cpp+50−4
@@ -25,6 +25,8 @@ QLimitProxyModelQML::QLimitProxyModelQML(QObject *parent)
2525 , m_limit(-1)
2626 , m_sourceInserting(false)
2727 , m_sourceRemoving(false)
28+ , m_dataChangedBegin(-1)
29+ , m_dataChangedEnd(-1)
2830{
2931 connect(this, SIGNAL(modelReset()), SIGNAL(countChanged()));
3032 connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(countChanged()));
@@ -130,8 +132,25 @@ QLimitProxyModelQML::sourceRowsAboutToBeInserted(const QModelIndex &parent, int
130132 beginInsertRows(mapFromSource(parent), start, end);
131133 m_sourceInserting = true;
132134 } else if (start < m_limit) {
133− beginInsertRows(mapFromSource(parent), start, qMin(m_limit - 1, end));
134− m_sourceInserting = true;
135+ const int nSourceAddedItems = end - start + 1;
136+ const int currentCount = QIdentityProxyModel::rowCount();
137+ if (currentCount + nSourceAddedItems <= m_limit) {
138+ beginInsertRows(mapFromSource(parent), start, end);
139+ m_sourceInserting = true;
140+ } else if (currentCount < m_limit) {
141+ const int nItemsToInsert = m_limit - currentCount;
142+ beginInsertRows(mapFromSource(parent), start, start + nItemsToInsert - 1);
143+ m_sourceInserting = true;
144+ m_dataChangedBegin = start + nItemsToInsert;
145+ m_dataChangedEnd = m_limit - 1;
146+ if (m_dataChangedBegin > m_dataChangedEnd) {
147+ m_dataChangedBegin = -1;
148+ m_dataChangedEnd = -1;
149+ }
150+ } else {
151+ m_dataChangedBegin = start;
152+ m_dataChangedEnd = m_limit - 1;
153+ }
135154 }
136155}
137156
@@ -142,8 +161,25 @@ QLimitProxyModelQML::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int s
142161 beginRemoveRows(mapFromSource(parent), start, end);
143162 m_sourceRemoving = true;
144163 } else if (start < m_limit) {
145− beginRemoveRows(mapFromSource(parent), start, qMin(m_limit - 1, end));
146− m_sourceRemoving = true;
164+ const int nSourceRemovedItems = end - start + 1;
165+ const int currentCount = QIdentityProxyModel::rowCount();
166+ if (currentCount <= m_limit) {
167+ beginRemoveRows(mapFromSource(parent), start, end);
168+ m_sourceRemoving = true;
169+ } else if (currentCount - nSourceRemovedItems < m_limit) {
170+ const int nItemsToRemove = m_limit - (currentCount - nSourceRemovedItems);
171+ beginRemoveRows(mapFromSource(parent), m_limit - nItemsToRemove, m_limit - 1);
172+ m_sourceRemoving = true;
173+ m_dataChangedBegin = start;
174+ m_dataChangedEnd = m_limit - nItemsToRemove - 1;
175+ if (m_dataChangedBegin > m_dataChangedEnd) {
176+ m_dataChangedBegin = -1;
177+ m_dataChangedEnd = -1;
178+ }
179+ } else {
180+ m_dataChangedBegin = start;
181+ m_dataChangedEnd = m_limit - 1;
182+ }
147183 }
148184}
149185
@@ -154,6 +190,11 @@ QLimitProxyModelQML::sourceRowsInserted(const QModelIndex & /*parent*/, int /*st
154190 endInsertRows();
155191 m_sourceInserting = false;
156192 }
193+ if (m_dataChangedBegin != -1 && m_dataChangedEnd != -1) {
194+ dataChanged(index(m_dataChangedBegin, 0), index(m_dataChangedEnd, 0));
195+ m_dataChangedBegin = -1;
196+ m_dataChangedEnd = -1;
197+ }
157198}
158199
159200void
@@ -163,4 +204,9 @@ QLimitProxyModelQML::sourceRowsRemoved(const QModelIndex & /*parent*/, int /*sta
163204 endRemoveRows();
164205 m_sourceRemoving = false;
165206 }
207+ if (m_dataChangedBegin != -1 && m_dataChangedEnd != -1) {
208+ dataChanged(index(m_dataChangedBegin, 0), index(m_dataChangedEnd, 0));
209+ m_dataChangedBegin = -1;
210+ m_dataChangedEnd = -1;
211+ }
166212}
plugins/Utils/qlimitproxymodelqml.h+2
@@ -55,6 +55,8 @@ private:
5555 int m_limit;
5656 bool m_sourceInserting;
5757 bool m_sourceRemoving;
58+ int m_dataChangedBegin;
59+ int m_dataChangedEnd;
5860};
5961
6062#endif // QLIMITPROXYMODELQML_H
tests/plugins/Utils/qlimitproxymodeltest.cpp+133−8
@@ -58,10 +58,17 @@ public:
5858 m_roles = roles;
5959 }
6060
61+ void clear()
62+ {
63+ beginRemoveRows(QModelIndex(), 0, m_list.count() - 1);
64+ m_list.clear();
65+ endRemoveRows();
66+ }
67+
6168 bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) {
6269 beginInsertRows(parent, row, row+count-1);
6370 for (int i=0; i<count; i++) {
64− m_list.insert(i+row, "test"+i);
71+ m_list.insert(i+row, QString::number(i));
6572 }
6673 endInsertRows();
6774 return true;
@@ -88,6 +95,60 @@ private:
8895 QHash<int, QByteArray> m_roles;
8996};
9097
98+class MirrorModel : public QObject
99+{
100+ Q_OBJECT
101+
102+public:
103+ MirrorModel(QAbstractItemModel *model) : m_mirror(model)
104+ {
105+ connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInserted(QModelIndex,int,int)));
106+ connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(rowsRemoved(QModelIndex,int,int)));
107+ connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(dataChanged(QModelIndex,QModelIndex)));
108+ }
109+
110+ void check()
111+ {
112+ QCOMPARE(m_list.count(), m_mirror->rowCount());
113+ for (int i = 0; i < m_list.count(); ++i) {
114+ QCOMPARE(m_list[i], m_mirror->data(m_mirror->index(i, 0)).toString());
115+ }
116+ }
117+
118+private Q_SLOTS:
119+ void rowsInserted(const QModelIndex &parent, int start, int end)
120+ {
121+ QVERIFY(!parent.isValid());
122+ for (int i = start; i <= end; ++i) {
123+ m_list.insert(i, m_mirror->data(m_mirror->index(i, 0)).toString());
124+ }
125+ }
126+
127+ void rowsRemoved(const QModelIndex &parent, int start, int end)
128+ {
129+ QVERIFY(!parent.isValid());
130+ for (int i = end; i >= start; --i) {
131+ m_list.removeAt(i);
132+ }
133+ }
134+
135+ void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
136+ {
137+ QVERIFY(topLeft.isValid());
138+ QVERIFY(bottomRight.isValid());
139+ QVERIFY(!topLeft.parent().isValid());
140+ QVERIFY(!bottomRight.parent().isValid());
141+ for (int i = topLeft.row(); i <= bottomRight.row(); ++i) {
142+ m_list[i] = m_mirror->data(m_mirror->index(i, 0)).toString();
143+ }
144+ }
145+
146+
147+private:
148+ QStringList m_list;
149+ QAbstractItemModel *m_mirror;
150+};
151+
91152class QLimitProxyModelTest : public QObject
92153{
93154 Q_OBJECT
@@ -401,15 +462,10 @@ private Q_SLOTS:
401462 QCOMPARE(spyOnCountChanged.count(), 0);
402463
403464 model.removeRows(2, 2);
404− QCOMPARE(spyOnRowsRemoved.count(), 1);
465+ QCOMPARE(spyOnRowsRemoved.count(), 0);
405466 QCOMPARE(spyOnRowsInserted.count(), 0);
406− QCOMPARE(spyOnCountChanged.count(), 1);
407− arguments = spyOnRowsRemoved.takeFirst();
408− QCOMPARE(arguments.at(1).toInt(), 2);
409− QCOMPARE(arguments.at(2).toInt(), 3);
467+ QCOMPARE(spyOnCountChanged.count(), 0);
410468 QCOMPARE(proxy.rowCount(), 7);
411− spyOnRowsInserted.clear();
412− spyOnCountChanged.clear();
413469
414470 model.removeRows(0, 7);
415471 QCOMPARE(spyOnRowsRemoved.count(), 1);
@@ -479,6 +535,75 @@ private Q_SLOTS:
479535 QCOMPARE(proxy.rowCount(), 5);
480536 QCOMPARE(spyOnCountChanged.count(), 1);
481537 }
538+
539+ void testMirrorModel() {
540+ QLimitProxyModelQML proxy;
541+ MockListModel model;
542+ MirrorModel mirror(&proxy);
543+
544+ proxy.setModel(&model);
545+ proxy.setLimit(5);
546+
547+ // Checks what happens when the model already has
548+ // more items than the limit and we add stuff to
549+ // the front
550+ model.insertRows(0, 7);
551+ mirror.check();
552+ model.insertRows(1, 3);
553+ mirror.check();
554+ model.clear();
555+ mirror.check();
556+
557+ // Checks what happens when the model does
558+ // not has more items than limit but adding
559+ // stuff to its front makes it go past the limit
560+ model.insertRows(0, 3);
561+ mirror.check();
562+ model.insertRows(1, 3);
563+ mirror.check();
564+ model.clear();
565+ mirror.check();
566+
567+ // Checks what happens when the model does
568+ // not has more items than limit and adding
569+ // stuff to its front makes it not go past the limit
570+ model.insertRows(0, 1);
571+ mirror.check();
572+ model.insertRows(1, 3);
573+ mirror.check();
574+ model.clear();
575+ mirror.check();
576+
577+ // Checks what happens when the model already has
578+ // more items than the limit and we remove stuff from
579+ // the front but it still has more than the limit
580+ model.insertRows(0, 10);
581+ mirror.check();
582+ model.removeRows(1, 3);
583+ mirror.check();
584+ model.clear();
585+ mirror.check();
586+
587+ // Checks what happens when the model already has
588+ // more items than the limit and we remove stuff from
589+ // the front but it has less than the limit
590+ model.insertRows(0, 6);
591+ mirror.check();
592+ model.removeRows(1, 3);
593+ mirror.check();
594+ model.clear();
595+ mirror.check();
596+
597+ // Checks what happens when the model has
598+ // less items than the limit and we remove stuff from
599+ // the front
600+ model.insertRows(0, 4);
601+ mirror.check();
602+ model.removeRows(1, 3);
603+ mirror.check();
604+ model.clear();
605+ mirror.check();
606+ }
482607};
483608
484609QTEST_GUILESS_MAIN(QLimitProxyModelTest)