Merge lp:~uriboni/unity-2d/unity-2d-exclude-filter-proxy-model into lp:unity-2d

Proposed by Ugo Riboni
Status: Merged
Approved by: Alberto Mardegan
Approved revision: 689
Merged at revision: 702
Proposed branch: lp:~uriboni/unity-2d/unity-2d-exclude-filter-proxy-model
Merge into: lp:unity-2d
Diff against target: 160 lines (+87/-2)
3 files modified
libunity-2d-private/src/qsortfilterproxymodelqml.cpp (+32/-2)
libunity-2d-private/src/qsortfilterproxymodelqml.h (+6/-0)
libunity-2d-private/tests/qsortfilterproxymodeltest.cpp (+49/-0)
To merge this branch: bzr merge lp:~uriboni/unity-2d/unity-2d-exclude-filter-proxy-model
Reviewer Review Type Date Requested Status
Alberto Mardegan (community) Approve
Review via email: mp+73836@code.launchpad.net

Commit message

Add a new proxy model class that excludes items matching the regexp instead of including them.

Description of the change

Add a new proxy model class that has all the features of QSortFilterProxyModelQML but excludes items matching the regexp instead of including them.

This is useful because generally speaking it's pretty hard to use a regular expression to exclude something. That's for example why tools like grep have the -v option to reverse the normal matching behavior.

This class is currently used only by another project but I thought having it in unity-2d would make things easier for everyone when they face a similar task.

To post a comment you must log in.
Alberto Mardegan (mardy) wrote :

The code looks fine, but I'd rather add a boolean property (invertMatch) to the existing model than add a subclass.
Hopefully most of the code you wrote for the tests can be reused.

review: Needs Fixing
688. By Ugo Riboni on 2011-09-07

Simplify the code by replacing ExcludeSortFilterProxyModel with QSortFilterProxyModel::invertMatch()

Ugo Riboni (uriboni) wrote :

I updated the MR following your suggestion.

Alberto Mardegan (mardy) wrote :

Great Ugo! Only one nitpick on the format of the comment in line 40: it starts with "//", and finishes with "*/".

689. By Ugo Riboni on 2011-09-07

FIx typo in a comment

Alberto Mardegan (mardy) wrote :

Thanks a lot! :-)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'libunity-2d-private/src/qsortfilterproxymodelqml.cpp'
2--- libunity-2d-private/src/qsortfilterproxymodelqml.cpp 2011-07-29 13:49:34 +0000
3+++ libunity-2d-private/src/qsortfilterproxymodelqml.cpp 2011-09-07 13:37:35 +0000
4@@ -17,8 +17,10 @@
5 #include "qsortfilterproxymodelqml.h"
6 #include <debug_p.h>
7
8-QSortFilterProxyModelQML::QSortFilterProxyModelQML(QObject *parent) :
9- QSortFilterProxyModel(parent), m_limit(-1)
10+QSortFilterProxyModelQML::QSortFilterProxyModelQML(QObject *parent)
11+ : QSortFilterProxyModel(parent)
12+ , m_limit(-1)
13+ , m_invertMatch(false)
14 {
15 connect(this, SIGNAL(modelReset()), SIGNAL(countChanged()));
16 connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(countChanged()));
17@@ -189,4 +191,32 @@
18 }
19 }
20
21+bool
22+QSortFilterProxyModelQML::invertMatch() const
23+{
24+ return m_invertMatch;
25+}
26+
27+void
28+QSortFilterProxyModelQML::setInvertMatch(bool invertMatch)
29+{
30+ if (invertMatch != m_invertMatch) {
31+ m_invertMatch = invertMatch;
32+ Q_EMIT invertMatchChanged(invertMatch);
33+ }
34+}
35+
36+bool
37+QSortFilterProxyModelQML::filterAcceptsRow(int sourceRow,
38+ const QModelIndex &sourceParent) const
39+{
40+ // If there's no regexp set, always accept all rows indepenently of the invertMatch setting
41+ if (filterRegExp().isEmpty()) {
42+ return true;
43+ }
44+
45+ bool result = QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
46+ return (m_invertMatch) ? !result : result;
47+}
48+
49 #include "qsortfilterproxymodelqml.moc"
50
51=== modified file 'libunity-2d-private/src/qsortfilterproxymodelqml.h'
52--- libunity-2d-private/src/qsortfilterproxymodelqml.h 2011-07-29 13:49:34 +0000
53+++ libunity-2d-private/src/qsortfilterproxymodelqml.h 2011-09-07 13:37:35 +0000
54@@ -27,6 +27,7 @@
55 Q_PROPERTY(int limit READ limit WRITE setLimit NOTIFY limitChanged)
56 Q_PROPERTY(int totalCount READ totalCount NOTIFY totalCountChanged)
57 Q_PROPERTY(int count READ count NOTIFY countChanged)
58+ Q_PROPERTY(bool invertMatch READ invertMatch WRITE setInvertMatch NOTIFY invertMatchChanged)
59
60 public:
61 explicit QSortFilterProxyModelQML(QObject *parent = 0);
62@@ -34,15 +35,18 @@
63 Q_INVOKABLE QVariantMap get(int row);
64 Q_INVOKABLE int count();
65 int rowCount(const QModelIndex &parent = QModelIndex()) const;
66+ virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
67
68 /* getters */
69 QObject* sourceModelQObject() const;
70 int limit() const;
71 int totalCount() const;
72+ bool invertMatch() const;
73
74 /* setters */
75 void setSourceModelQObject(QObject *model);
76 void setLimit(int limit);
77+ void setInvertMatch(bool invertMatch);
78
79 Q_SLOT void setRoleNames(const QHash<int,QByteArray> &roleNames);
80
81@@ -50,10 +54,12 @@
82 void limitChanged();
83 void totalCountChanged();
84 void countChanged();
85+ void invertMatchChanged(bool);
86 void roleNamesChanged(const QHash<int,QByteArray> &);
87
88 private:
89 int m_limit;
90+ bool m_invertMatch;
91 };
92
93 #endif // QSORTFILTERPROXYMODELQML_H
94
95=== modified file 'libunity-2d-private/tests/qsortfilterproxymodeltest.cpp'
96--- libunity-2d-private/tests/qsortfilterproxymodeltest.cpp 2011-07-26 16:50:34 +0000
97+++ libunity-2d-private/tests/qsortfilterproxymodeltest.cpp 2011-09-07 13:37:35 +0000
98@@ -67,6 +67,13 @@
99 return true;
100 }
101
102+ bool appendRows(QStringList &rows, const QModelIndex &parent=QModelIndex()) {
103+ beginInsertRows(parent, rowCount(), rowCount() + rows.count() - 1);
104+ m_list.append(rows);
105+ endInsertRows();
106+ return true;
107+ }
108+
109 bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) {
110 beginRemoveRows(parent, row, row+count-1);
111 for (int i=0; i<count; i++) {
112@@ -376,6 +383,48 @@
113 //QCOMPARE(spyOnRowsInserted.count(), 0);
114 //QCOMPARE(spyOnCountChanged.count(), 0);
115 }
116+
117+ void testInvertMatch() {
118+ QSortFilterProxyModelQML proxy;
119+ MockListModel model;
120+
121+ proxy.setSourceModelQObject(&model);
122+ proxy.setDynamicSortFilter(true);
123+
124+ QStringList rows;
125+ rows << "a/foobar/b" << "foobar" << "foobarbaz" << "hello";
126+ model.appendRows(rows);
127+
128+ // Check that without a filterRegExp all rows are accepted regardless of invertMatch
129+ QCOMPARE(model.rowCount(), rows.count());
130+ QCOMPARE(proxy.rowCount(), rows.count());
131+ for (int i=0; i<rows.count(); i++) {
132+ QCOMPARE(proxy.index(i, 0).data().toString(), model.index(i, 0).data().toString());
133+ }
134+ proxy.setInvertMatch(true);
135+ QCOMPARE(model.rowCount(), rows.count());
136+ QCOMPARE(proxy.rowCount(), rows.count());
137+ for (int i=0; i<rows.count(); i++) {
138+ QCOMPARE(proxy.index(i, 0).data().toString(), model.index(i, 0).data().toString());
139+ }
140+
141+
142+ // Test non-anchored regexp with invertMatch active
143+ proxy.setFilterRegExp("foobar");
144+ QCOMPARE(proxy.rowCount(), 1);
145+ QCOMPARE(proxy.index(0, 0).data().toString(), rows.last());
146+
147+ // Test anchored regexp with invertMatch active
148+ proxy.setFilterRegExp("^foobar$");
149+ QCOMPARE(proxy.rowCount(), 3);
150+ QCOMPARE(proxy.index(0, 0).data().toString(), rows.at(0));
151+ QCOMPARE(proxy.index(1, 0).data().toString(), rows.at(2));
152+ QCOMPARE(proxy.index(2, 0).data().toString(), rows.at(3));
153+
154+ // Test regexp with OR and invertMatch active
155+ proxy.setFilterRegExp("foobar|hello");
156+ QCOMPARE(proxy.count(), 0);
157+ }
158 };
159
160 QTEST_MAIN(QSortFilterProxyModelTest)

Subscribers

People subscribed via source and target branches