Merge lp:~kalikiana/ubuntu-ui-toolkit/sortFilterModel into lp:ubuntu-ui-toolkit/staging
- sortFilterModel
- Merge into staging
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Tim Peeters | ||||
Approved revision: | 996 | ||||
Merged at revision: | 1056 | ||||
Proposed branch: | lp:~kalikiana/ubuntu-ui-toolkit/sortFilterModel | ||||
Merge into: | lp:ubuntu-ui-toolkit/staging | ||||
Diff against target: |
811 lines (+686/-3) 11 files modified
components.api (+49/-0) examples/ubuntu-ui-toolkit-gallery/ListItems.qml (+11/-2) modules/Ubuntu/Components/plugin/filterbehavior.cpp (+47/-0) modules/Ubuntu/Components/plugin/filterbehavior.h (+46/-0) modules/Ubuntu/Components/plugin/plugin.cpp (+10/-1) modules/Ubuntu/Components/plugin/plugin.pro (+6/-0) modules/Ubuntu/Components/plugin/sortbehavior.cpp (+47/-0) modules/Ubuntu/Components/plugin/sortbehavior.h (+46/-0) modules/Ubuntu/Components/plugin/sortfiltermodel.cpp (+250/-0) modules/Ubuntu/Components/plugin/sortfiltermodel.h (+66/-0) tests/unit/tst_components/tst_sortfiltermodel.qml (+108/-0) |
||||
To merge this branch: | bzr merge lp:~kalikiana/ubuntu-ui-toolkit/sortFilterModel | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Tim Peeters | Approve | ||
Review via email: mp+217736@code.launchpad.net |
This proposal supersedes a proposal from 2014-03-20.
Commit message
Introduce QML bindings for SortFilterModel
Description of the change
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
fix quotes
122 + * filter.property: "producer
123 + * filter.pattern: /blender/
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
141 + * Label {
142 + * text: {
143 + * var firstRow = sortedMovies.
isn't /Elephant/ supposed to be a string?
144 + * var sourceRow = sortedMovies.
145 + * var foundTitle = movies.
146 + * i18n.tr("First matching movie: %1").arg(
I would guess you want to keep foundTitle outside of the translateion.
i18n.tr() needs to be return i18n.tr();
add semicolons at the end of the lines
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
TODO: documentation of properties
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:984
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Cris Dywan (kalikiana) wrote : Posted in a previous version of this proposal | # |
modules/
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:985
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:987
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Cris Dywan (kalikiana) wrote : Posted in a previous version of this proposal | # |
FTR failures in ubuntuuitoolkit
- 989. By Cris Dywan
-
Revert uncommenting of gallery sections
- 990. By Cris Dywan
-
SortFilterModel should be Ubuntu.Components 1.1
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:990
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 991. By Cris Dywan
-
Also register *Behavior and AbstractItemModel with version 1.1
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:991
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Cris Dywan (kalikiana) wrote : | # |
Looks like J has unrelated problems:
The following packages have unmet dependencies:
libmirserver18 : Depends: libmirplatform (= 0.1.8+14.
ubuntu-
E: Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution).
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:992
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Cris Dywan (kalikiana) wrote : | # |
FTR random failure in test_optionsele
Tim Peeters (tpeeters) wrote : | # |
Copyright in plugin.cpp may be updated
Tim Peeters (tpeeters) wrote : | # |
Why do you need to register the QAbstractItemModel?
Tim Peeters (tpeeters) wrote : | # |
I prefer to define each public class in its own .h and .cpp files. Is there a reason not to do this for FilterBehavior and SortBehavior?
Tim Peeters (tpeeters) wrote : | # |
Q_INVOKABLE QVariantMap get(int row); // Use with caution, it can be slow to query all the roles
perhaps you should document that function in the cpp file and add the warning there?
Tim Peeters (tpeeters) wrote : | # |
181 + * \qmltype SortFilterModel
182 + * \instantiates QSortFilterProx
183 + * \inqmlmodule Ubuntu.Components 0.1
184 + * \ingroup ubuntu
192 + *
193 + * Example usage:
194 + * \qml
195 + * import QtQuick 2.0
196 + * import Ubuntu.Components 0.1
197 + * import Ubuntu.
Ubuntu.Components 1.1
Tim Peeters (tpeeters) wrote : | # |
228 + * ListView {
229 + * model: sortedMovies
230 + *
231 + * delegate: Subtitled {
232 + * text: title
233 + * subText: producer
234 + * }
235 + *
236 + * section.delegate: sectionDelegate
237 + * section.property: "title"
238 + * section.criteria: ViewSection.
239 + * }
file://
file://
Tim Peeters (tpeeters) wrote : | # |
the ListView in your example needs anchors.fill: parent to show anything
Tim Peeters (tpeeters) wrote : | # |
your example is not working, output of the SortFilterModel is empty.
Tim Peeters (tpeeters) wrote : | # |
> your example is not working, output of the SortFilterModel is empty.
Ignore that comment, I had a typo in the id of the SortFilterModel.
Tim Peeters (tpeeters) wrote : | # |
> your example is not working, output of the SortFilterModel is empty.
Ignore that comment, I had a typo in the id of the SortFilterModel.
Tim Peeters (tpeeters) wrote : | # |
qmlRegister
qmlRegister
Those should also not be creatable from QML right? They come with the SoftFilterModel
- 993. By Cris Dywan
-
Take comments on inline example into account
- 994. By Cris Dywan
-
Make *Behavior uncreatable and document QAbstractItemModel type
- 995. By Cris Dywan
-
Split *Behavior into separate files
- 996. By Cris Dywan
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:996
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Tim Peeters (tpeeters) wrote : | # |
good stuff, I like the changes!
PS Jenkins bot (ps-jenkins) : | # |
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
1 | === modified file 'components.api' |
2 | --- components.api 2014-05-13 09:13:32 +0000 |
3 | +++ components.api 2014-05-15 09:54:24 +0000 |
4 | @@ -613,6 +613,11 @@ |
5 | function mouseLongPress(item, x, y, button, modifiers, delay) |
6 | function tryCompareFunction(func, expectedResult, timeout) |
7 | plugins.qmltypes |
8 | + name: "FilterBehavior" |
9 | + prototype: "QObject" |
10 | + exports: ["FilterBehavior 1.1"] |
11 | + Property { name: "property"; type: "string" } |
12 | + Property { name: "pattern"; type: "QRegExp" } |
13 | name: "InverseMouseAreaType" |
14 | prototype: "QQuickMouseArea" |
15 | exports: ["InverseMouseArea 0.1", "InverseMouseArea 1.0"] |
16 | @@ -621,6 +626,45 @@ |
17 | Method { |
18 | name: "contains" |
19 | Parameter { name: "point"; type: "QPointF" } |
20 | + name: "QAbstractProxyModel" |
21 | + prototype: "QAbstractItemModel" |
22 | + Property { name: "sourceModel"; type: "QAbstractItemModel"; isPointer: true } |
23 | + name: "QSortFilterProxyModel" |
24 | + prototype: "QAbstractProxyModel" |
25 | + Property { name: "filterRegExp"; type: "QRegExp" } |
26 | + Property { name: "filterKeyColumn"; type: "int" } |
27 | + Property { name: "dynamicSortFilter"; type: "bool" } |
28 | + Property { name: "filterCaseSensitivity"; type: "Qt::CaseSensitivity" } |
29 | + Property { name: "sortCaseSensitivity"; type: "Qt::CaseSensitivity" } |
30 | + Property { name: "isSortLocaleAware"; type: "bool" } |
31 | + Property { name: "sortRole"; type: "int" } |
32 | + Property { name: "filterRole"; type: "int" } |
33 | + Method { |
34 | + name: "setFilterRegExp" |
35 | + Parameter { name: "pattern"; type: "string" } |
36 | + Method { |
37 | + name: "setFilterWildcard" |
38 | + Parameter { name: "pattern"; type: "string" } |
39 | + Method { |
40 | + name: "setFilterFixedString" |
41 | + Parameter { name: "pattern"; type: "string" } |
42 | + Method { name: "clear" } |
43 | + Method { name: "invalidate" } |
44 | + name: "QSortFilterProxyModelQML" |
45 | + prototype: "QSortFilterProxyModel" |
46 | + exports: ["SortFilterModel 1.1"] |
47 | + Property { name: "model"; type: "QAbstractItemModel"; isPointer: true } |
48 | + Property { name: "count"; type: "int"; isReadonly: true } |
49 | + Property { name: "sort"; type: "SortBehavior"; isReadonly: true; isPointer: true } |
50 | + Property { name: "filter"; type: "FilterBehavior"; isReadonly: true; isPointer: true } |
51 | + Method { |
52 | + name: "get" |
53 | + Parameter { name: "row"; type: "int" } |
54 | + Method { |
55 | + name: "data" |
56 | + Parameter { name: "row"; type: "int" } |
57 | + Parameter { name: "role"; type: "int" } |
58 | + Method { name: "count"; type: "int" } |
59 | name: "ShapeItem" |
60 | prototype: "QQuickItem" |
61 | exports: ["Shape 0.1", "Shape 1.0"] |
62 | @@ -636,6 +680,11 @@ |
63 | Property { name: "borderSource"; type: "string" } |
64 | Signal { name: "borderChanged" } |
65 | Method { name: "gridUnitChanged" } |
66 | + name: "SortBehavior" |
67 | + prototype: "QObject" |
68 | + exports: ["SortBehavior 1.1"] |
69 | + Property { name: "property"; type: "string" } |
70 | + Property { name: "order"; type: "Qt::SortOrder" } |
71 | name: "UCAlarm" |
72 | prototype: "QObject" |
73 | exports: ["Alarm 0.1", "Alarm 1.0"] |
74 | |
75 | === modified file 'examples/ubuntu-ui-toolkit-gallery/ListItems.qml' |
76 | --- examples/ubuntu-ui-toolkit-gallery/ListItems.qml 2014-04-28 10:30:06 +0000 |
77 | +++ examples/ubuntu-ui-toolkit-gallery/ListItems.qml 2014-05-15 09:54:24 +0000 |
78 | @@ -15,7 +15,7 @@ |
79 | */ |
80 | |
81 | import QtQuick 2.0 |
82 | -import Ubuntu.Components 0.1 as Toolkit |
83 | +import Ubuntu.Components 1.1 as Toolkit |
84 | import Ubuntu.Components.ListItems 0.1 as ListItem |
85 | |
86 | Template { |
87 | @@ -259,11 +259,20 @@ |
88 | ListElement { name: "Potato"; details: "Vegetable" } |
89 | } |
90 | |
91 | + Toolkit.SortFilterModel { |
92 | + id: processedFruits |
93 | + model: fruitModel |
94 | + sort.property: "title" |
95 | + sort.order: Qt.DescendingOrder |
96 | + filter.property: "details" |
97 | + filter.pattern: /Vegetable/ |
98 | + } |
99 | + |
100 | Toolkit.UbuntuListView { |
101 | id: ubuntuListView |
102 | anchors { left: parent.left; right: parent.right } |
103 | height: units.gu(24) |
104 | - model: fruitModel |
105 | + model: processedFruits |
106 | clip: true |
107 | |
108 | delegate: ListItem.Expandable { |
109 | |
110 | === added file 'modules/Ubuntu/Components/plugin/filterbehavior.cpp' |
111 | --- modules/Ubuntu/Components/plugin/filterbehavior.cpp 1970-01-01 00:00:00 +0000 |
112 | +++ modules/Ubuntu/Components/plugin/filterbehavior.cpp 2014-05-15 09:54:24 +0000 |
113 | @@ -0,0 +1,47 @@ |
114 | +/* |
115 | + * Copyright (C) 2014 Canonical, Ltd. |
116 | + * |
117 | + * Authors: |
118 | + * Christian Dywan <christian.dywan@canonical.com> |
119 | + * |
120 | + * This program is free software; you can redistribute it and/or modify |
121 | + * it under the terms of the GNU Lesser General Public License as published by |
122 | + * the Free Software Foundation; version 3. |
123 | + * |
124 | + * This program is distributed in the hope that it will be useful, |
125 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
126 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
127 | + * GNU Lesser General Public License for more details. |
128 | + * |
129 | + * You should have received a copy of the GNU Lesser General Public License |
130 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
131 | + */ |
132 | + |
133 | +#include "filterbehavior.h" |
134 | + |
135 | +QString |
136 | +FilterBehavior::property() const |
137 | +{ |
138 | + return m_property; |
139 | +} |
140 | + |
141 | +void |
142 | +FilterBehavior::setProperty(const QString& property) |
143 | +{ |
144 | + m_property = property; |
145 | + Q_EMIT propertyChanged(); |
146 | +} |
147 | + |
148 | +QRegExp |
149 | +FilterBehavior::pattern() const |
150 | +{ |
151 | + return m_pattern; |
152 | +} |
153 | + |
154 | +void |
155 | +FilterBehavior::setPattern(QRegExp pattern) |
156 | +{ |
157 | + m_pattern = pattern; |
158 | + Q_EMIT patternChanged(); |
159 | +} |
160 | + |
161 | |
162 | === added file 'modules/Ubuntu/Components/plugin/filterbehavior.h' |
163 | --- modules/Ubuntu/Components/plugin/filterbehavior.h 1970-01-01 00:00:00 +0000 |
164 | +++ modules/Ubuntu/Components/plugin/filterbehavior.h 2014-05-15 09:54:24 +0000 |
165 | @@ -0,0 +1,46 @@ |
166 | +/* |
167 | + * Copyright (C) 2014 Canonical, Ltd. |
168 | + * |
169 | + * Authors: |
170 | + * Christian Dywan <christian.dywan@canonical.com> |
171 | + * |
172 | + * This program is free software; you can redistribute it and/or modify |
173 | + * it under the terms of the GNU Lesser General Public License as published by |
174 | + * the Free Software Foundation; version 3. |
175 | + * |
176 | + * This program is distributed in the hope that it will be useful, |
177 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
178 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
179 | + * GNU Lesser General Public License for more details. |
180 | + * |
181 | + * You should have received a copy of the GNU Lesser General Public License |
182 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
183 | + */ |
184 | + |
185 | +#ifndef FILTERBEHAVIOR_H |
186 | +#define FILTERBEHAVIOR_H |
187 | + |
188 | +#include <QSortFilterProxyModel> |
189 | + |
190 | +class FilterBehavior : public QObject { |
191 | + Q_OBJECT |
192 | + |
193 | + Q_PROPERTY(QString property READ property WRITE setProperty NOTIFY propertyChanged) |
194 | + Q_PROPERTY(QRegExp pattern READ pattern WRITE setPattern NOTIFY patternChanged) |
195 | + |
196 | +public: |
197 | + QString property() const; |
198 | + void setProperty(const QString& property); |
199 | + QRegExp pattern() const; |
200 | + void setPattern(QRegExp pattern); |
201 | + |
202 | +Q_SIGNALS: |
203 | + void propertyChanged(); |
204 | + void patternChanged(); |
205 | + |
206 | +private: |
207 | + QString m_property; |
208 | + QRegExp m_pattern; |
209 | +}; |
210 | + |
211 | +#endif // FILTERBEHAVIOR_H |
212 | |
213 | === modified file 'modules/Ubuntu/Components/plugin/plugin.cpp' |
214 | --- modules/Ubuntu/Components/plugin/plugin.cpp 2014-04-20 19:25:12 +0000 |
215 | +++ modules/Ubuntu/Components/plugin/plugin.cpp 2014-05-15 09:54:24 +0000 |
216 | @@ -1,5 +1,5 @@ |
217 | /* |
218 | - * Copyright 2012 Canonical Ltd. |
219 | + * Copyright 2012-2014 Canonical Ltd. |
220 | * |
221 | * This program is free software; you can redistribute it and/or modify |
222 | * it under the terms of the GNU Lesser General Public License as published by |
223 | @@ -48,6 +48,7 @@ |
224 | #include "ucurihandler.h" |
225 | #include "ucmouse.h" |
226 | #include "ucinversemouse.h" |
227 | +#include "sortfiltermodel.h" |
228 | |
229 | #include <sys/types.h> |
230 | #include <unistd.h> |
231 | @@ -186,6 +187,14 @@ |
232 | |
233 | // register custom event |
234 | ForwardedEvent::registerForwardedEvent(); |
235 | + |
236 | + // register parent type so that properties can get/ set it |
237 | + qmlRegisterUncreatableType<QAbstractItemModel>(uri, 1, 1, "QAbstractItemModel", "Not instantiable"); |
238 | + |
239 | + // register 1.1 only API |
240 | + qmlRegisterType<QSortFilterProxyModelQML>(uri, 1, 1, "SortFilterModel"); |
241 | + qmlRegisterUncreatableType<FilterBehavior>(uri, 1, 1, "FilterBehavior", "Not instantiable"); |
242 | + qmlRegisterUncreatableType<SortBehavior>(uri, 1, 1, "SortBehavior", "Not instantiable"); |
243 | } |
244 | |
245 | void UbuntuComponentsPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
246 | |
247 | === modified file 'modules/Ubuntu/Components/plugin/plugin.pro' |
248 | --- modules/Ubuntu/Components/plugin/plugin.pro 2014-03-25 06:46:36 +0000 |
249 | +++ modules/Ubuntu/Components/plugin/plugin.pro 2014-05-15 09:54:24 +0000 |
250 | @@ -55,6 +55,9 @@ |
251 | alarmrequest_p_p.h \ |
252 | adapters/alarmsadapter_p.h \ |
253 | ucstatesaver.h \ |
254 | + sortbehavior.h \ |
255 | + filterbehavior.h \ |
256 | + sortfiltermodel.h \ |
257 | statesaverbackend_p.h \ |
258 | ucstatesaver_p.h \ |
259 | ucurihandler.h \ |
260 | @@ -87,6 +90,9 @@ |
261 | thumbnailgenerator.cpp \ |
262 | alarmrequest_p.cpp \ |
263 | ucstatesaver.cpp \ |
264 | + sortbehavior.cpp \ |
265 | + filterbehavior.cpp \ |
266 | + sortfiltermodel.cpp \ |
267 | statesaverbackend_p.cpp \ |
268 | ucurihandler.cpp \ |
269 | ucmousefilters.cpp \ |
270 | |
271 | === added file 'modules/Ubuntu/Components/plugin/sortbehavior.cpp' |
272 | --- modules/Ubuntu/Components/plugin/sortbehavior.cpp 1970-01-01 00:00:00 +0000 |
273 | +++ modules/Ubuntu/Components/plugin/sortbehavior.cpp 2014-05-15 09:54:24 +0000 |
274 | @@ -0,0 +1,47 @@ |
275 | +/* |
276 | + * Copyright (C) 2014 Canonical, Ltd. |
277 | + * |
278 | + * Authors: |
279 | + * Christian Dywan <christian.dywan@canonical.com> |
280 | + * |
281 | + * This program is free software; you can redistribute it and/or modify |
282 | + * it under the terms of the GNU Lesser General Public License as published by |
283 | + * the Free Software Foundation; version 3. |
284 | + * |
285 | + * This program is distributed in the hope that it will be useful, |
286 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
287 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
288 | + * GNU Lesser General Public License for more details. |
289 | + * |
290 | + * You should have received a copy of the GNU Lesser General Public License |
291 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
292 | + */ |
293 | + |
294 | +#include "sortbehavior.h" |
295 | + |
296 | +QString |
297 | +SortBehavior::property() const |
298 | +{ |
299 | + return m_property; |
300 | +} |
301 | + |
302 | +Qt::SortOrder |
303 | +SortBehavior::order() const |
304 | +{ |
305 | + return m_order; |
306 | +} |
307 | + |
308 | +void |
309 | +SortBehavior::setProperty(const QString& property) |
310 | +{ |
311 | + m_property = property; |
312 | + Q_EMIT propertyChanged(); |
313 | +} |
314 | + |
315 | +void |
316 | +SortBehavior::setOrder(Qt::SortOrder order) |
317 | +{ |
318 | + m_order = order; |
319 | + Q_EMIT orderChanged(); |
320 | +} |
321 | + |
322 | |
323 | === added file 'modules/Ubuntu/Components/plugin/sortbehavior.h' |
324 | --- modules/Ubuntu/Components/plugin/sortbehavior.h 1970-01-01 00:00:00 +0000 |
325 | +++ modules/Ubuntu/Components/plugin/sortbehavior.h 2014-05-15 09:54:24 +0000 |
326 | @@ -0,0 +1,46 @@ |
327 | +/* |
328 | + * Copyright (C) 2014 Canonical, Ltd. |
329 | + * |
330 | + * Authors: |
331 | + * Christian Dywan <christian.dywan@canonical.com> |
332 | + * |
333 | + * This program is free software; you can redistribute it and/or modify |
334 | + * it under the terms of the GNU Lesser General Public License as published by |
335 | + * the Free Software Foundation; version 3. |
336 | + * |
337 | + * This program is distributed in the hope that it will be useful, |
338 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
339 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
340 | + * GNU Lesser General Public License for more details. |
341 | + * |
342 | + * You should have received a copy of the GNU Lesser General Public License |
343 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
344 | + */ |
345 | + |
346 | +#ifndef SORTBEHAVIOR_H |
347 | +#define SORTBEHAVIOR_H |
348 | + |
349 | +#include <QSortFilterProxyModel> |
350 | + |
351 | +class SortBehavior : public QObject { |
352 | + Q_OBJECT |
353 | + |
354 | + Q_PROPERTY(QString property READ property WRITE setProperty NOTIFY propertyChanged) |
355 | + Q_PROPERTY(Qt::SortOrder order READ order WRITE setOrder NOTIFY orderChanged) |
356 | + |
357 | +public: |
358 | + QString property() const; |
359 | + void setProperty(const QString& property); |
360 | + Qt::SortOrder order() const; |
361 | + void setOrder(Qt::SortOrder order); |
362 | + |
363 | +Q_SIGNALS: |
364 | + void propertyChanged(); |
365 | + void orderChanged(); |
366 | + |
367 | +private: |
368 | + QString m_property; |
369 | + Qt::SortOrder m_order; |
370 | +}; |
371 | + |
372 | +#endif // SORTBEHAVIOR_H |
373 | |
374 | === added file 'modules/Ubuntu/Components/plugin/sortfiltermodel.cpp' |
375 | --- modules/Ubuntu/Components/plugin/sortfiltermodel.cpp 1970-01-01 00:00:00 +0000 |
376 | +++ modules/Ubuntu/Components/plugin/sortfiltermodel.cpp 2014-05-15 09:54:24 +0000 |
377 | @@ -0,0 +1,250 @@ |
378 | +/* |
379 | + * Copyright (C) 2012-2014 Canonical, Ltd. |
380 | + * |
381 | + * Authors: |
382 | + * Michal Hruby <michal.hruby@canonical.com> |
383 | + * Christian Dywan <christian.dywan@canonical.com> |
384 | + * |
385 | + * This program is free software; you can redistribute it and/or modify |
386 | + * it under the terms of the GNU Lesser General Public License as published by |
387 | + * the Free Software Foundation; version 3. |
388 | + * |
389 | + * This program is distributed in the hope that it will be useful, |
390 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
391 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
392 | + * GNU Lesser General Public License for more details. |
393 | + * |
394 | + * You should have received a copy of the GNU Lesser General Public License |
395 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
396 | + */ |
397 | + |
398 | +#include "sortfiltermodel.h" |
399 | + |
400 | +/*! |
401 | + * \qmltype SortFilterModel |
402 | + * \instantiates QSortFilterProxyModelQML |
403 | + * \inqmlmodule Ubuntu.Components 0.1 |
404 | + * \ingroup ubuntu |
405 | + * \brief SortFilterModel sorts and filters rows from an existing model. |
406 | + * |
407 | + * The SortFilterModel takes an existing model such as a ListModel or |
408 | + * any QAbstractItemModel implementation. The original rows and role names |
409 | + * show up in the SortFilterModel with two basic differences. For one if |
410 | + * \l sort.property is set all rows will be sorted. Further more if |
411 | + * \l filter.property is set only rows matching the filter will be in the model. |
412 | + * |
413 | + * Example usage: |
414 | + * \qml |
415 | + * import QtQuick 2.0 |
416 | + * import Ubuntu.Components 1.1 |
417 | + * import Ubuntu.Components.ListItems 1.1 |
418 | + * |
419 | + * MainView { |
420 | + * width: units.gu(80) |
421 | + * height: units.gu(40) |
422 | + * |
423 | + * ListModel { |
424 | + * id: movies |
425 | + * ListElement { |
426 | + * title: "Esign" |
427 | + * producer: "Chris Larkee" |
428 | + * } |
429 | + * ListElement { |
430 | + * title: "Elephants Dream" |
431 | + * producer: "Blender" |
432 | + * } |
433 | + * ListElement { |
434 | + * title: "Big Buck Bunny" |
435 | + * producer: "Blender" |
436 | + * } |
437 | + * } |
438 | + * |
439 | + * SortFilterModel { |
440 | + * id: sortedMovies |
441 | + * model: movies |
442 | + * sort.property: "title" |
443 | + * sort.order: Qt.DescendingOrder |
444 | + * |
445 | + * filter.property: "producer" |
446 | + * filter.pattern: /blender/ |
447 | + * } |
448 | + * |
449 | + * ListView { |
450 | + * model: sortedMovies |
451 | + * anchors.fill: parent |
452 | + * |
453 | + * delegate: Subtitled { |
454 | + * text: title |
455 | + * subText: producer |
456 | + * } |
457 | + * |
458 | + * section.delegate: ListItem.Header { text: i18n.tr(section) } |
459 | + * section.property: "title" |
460 | + * section.criteria: ViewSection.FirstCharacter |
461 | + * } |
462 | + * } |
463 | + * \endqml |
464 | + * |
465 | + * Pay attention to the differences between the original model and the result: |
466 | + * \list |
467 | + * \li Big Buck Bunny will be the first row, because it's sorted by title |
468 | + * \li Esign won't be visible, because it's from the wrong producer |
469 | + * \endlist |
470 | + */ |
471 | + |
472 | + |
473 | +QSortFilterProxyModelQML::QSortFilterProxyModelQML(QObject *parent) |
474 | + : QSortFilterProxyModel(parent) |
475 | +{ |
476 | + // This is virtually always what you want in QML |
477 | + setDynamicSortFilter(true); |
478 | + connect(this, SIGNAL(modelReset()), SIGNAL(countChanged())); |
479 | + connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(countChanged())); |
480 | + connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(countChanged())); |
481 | + connect(&m_sortBehavior, &SortBehavior::propertyChanged, this, &QSortFilterProxyModelQML::sortChanged); |
482 | + connect(&m_sortBehavior, &SortBehavior::orderChanged, this, &QSortFilterProxyModelQML::sortChanged); |
483 | + connect(&m_filterBehavior, &FilterBehavior::propertyChanged, this, &QSortFilterProxyModelQML::filterChanged); |
484 | + connect(&m_filterBehavior, &FilterBehavior::patternChanged, this, &QSortFilterProxyModelQML::filterChanged); |
485 | +} |
486 | + |
487 | +int |
488 | +QSortFilterProxyModelQML::roleByName(const QString& roleName) const |
489 | +{ |
490 | + const QHash<int, QByteArray> roles = roleNames(); |
491 | + for(int role = 0; role < roles.count(); role++) |
492 | + if (roles[role] == roleName) |
493 | + return role; |
494 | + return 0; |
495 | +} |
496 | + |
497 | +/*! |
498 | + * \qmlproperty string SortFilterModel::sort.property |
499 | + * |
500 | + * If set to a valid role name, all rows will be sorted according to \l sort.order. |
501 | + */ |
502 | + |
503 | +/*! |
504 | + * \qmlproperty string SortFilterModel::sort.order |
505 | + * |
506 | + * The order, if \l sort.property is set. |
507 | + * Qt::AscendingOrder sorts results from A to Z or 0 to 9. |
508 | + * Qt::DescendingOrder sorts results from Z to A or 9 to 0. |
509 | + */ |
510 | + |
511 | +SortBehavior* |
512 | +QSortFilterProxyModelQML::sortBehavior() |
513 | +{ |
514 | + return &m_sortBehavior; |
515 | +} |
516 | + |
517 | +/*! |
518 | + * \qmlproperty string SortFilterModel::filter.pattern |
519 | + * |
520 | + * The pattern all rows must match, if \l filter.property is set. |
521 | + * |
522 | + * Some examples: |
523 | + * \list |
524 | + * \li /possible/ matches anywhere in a word, so both "impossible" and "possible". |
525 | + * \li /^sign/ matches "sign". But not "assignment" because ^ means start. |
526 | + * \li /vest$/ matches "safety vest" and "vest" but not "vested". |
527 | + * \endlist |
528 | + * |
529 | + * For more advanced uses it's recommended to read up on Javascript regular expressions. |
530 | + */ |
531 | + |
532 | +/*! |
533 | + * \qmlproperty string SortFilterModel::filter.property |
534 | + * |
535 | + * If set to a valid role name, only rows matching \l filter.pattern will be in the model. |
536 | + */ |
537 | + |
538 | +FilterBehavior* |
539 | +QSortFilterProxyModelQML::filterBehavior() |
540 | +{ |
541 | + return &m_filterBehavior; |
542 | +} |
543 | + |
544 | +void |
545 | +QSortFilterProxyModelQML::sortChanged() |
546 | +{ |
547 | + setSortRole(roleByName(m_sortBehavior.property())); |
548 | + sort(sortColumn() != -1 ? sortColumn() : 0, m_sortBehavior.order()); |
549 | +} |
550 | + |
551 | +void |
552 | +QSortFilterProxyModelQML::filterChanged() |
553 | +{ |
554 | + setFilterRole(roleByName(m_filterBehavior.property())); |
555 | + setFilterRegExp(m_filterBehavior.pattern()); |
556 | +} |
557 | + |
558 | +QHash<int, QByteArray> QSortFilterProxyModelQML::roleNames() const |
559 | +{ |
560 | + return sourceModel() ? sourceModel()->roleNames() : QHash<int, QByteArray>(); |
561 | +} |
562 | + |
563 | +/*! |
564 | + * \qmlproperty QAbstractItemModel SortFilterModel::model |
565 | + * |
566 | + * The source model to sort and/ or filter. |
567 | + */ |
568 | +void |
569 | +QSortFilterProxyModelQML::setModel(QAbstractItemModel *itemModel) |
570 | +{ |
571 | + if (itemModel == NULL) { |
572 | + return; |
573 | + } |
574 | + |
575 | + if (itemModel != sourceModel()) { |
576 | + if (sourceModel() != NULL) { |
577 | + sourceModel()->disconnect(this); |
578 | + } |
579 | + |
580 | + setSourceModel(itemModel); |
581 | + // Roles mapping to role names may change |
582 | + setSortRole(roleByName(m_sortBehavior.property())); |
583 | + setFilterRole(roleByName(m_filterBehavior.property())); |
584 | + Q_EMIT modelChanged(); |
585 | + } |
586 | +} |
587 | + |
588 | +QVariantMap |
589 | +QSortFilterProxyModelQML::get(int row) |
590 | +{ |
591 | + QVariantMap res; |
592 | + const QHash<int, QByteArray> roles = roleNames(); |
593 | + for(int role = 0; role < roles.count(); role++) |
594 | + res.insert (roles[role], data(row, role)); |
595 | + return res; |
596 | +} |
597 | + |
598 | +QVariant |
599 | +QSortFilterProxyModelQML::data(int row, int role) |
600 | +{ |
601 | + if (sourceModel() == NULL) { |
602 | + return QVariant(); |
603 | + } |
604 | + |
605 | + return index(row, 0).data(role); |
606 | +} |
607 | + |
608 | +int |
609 | +QSortFilterProxyModelQML::count() |
610 | +{ |
611 | + return rowCount(); |
612 | +} |
613 | + |
614 | +bool |
615 | +QSortFilterProxyModelQML::filterAcceptsRow(int sourceRow, |
616 | + const QModelIndex &sourceParent) const |
617 | +{ |
618 | + if (filterRegExp().isEmpty()) { |
619 | + return true; |
620 | + } |
621 | + |
622 | + bool result = QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent); |
623 | + return result; |
624 | +} |
625 | + |
626 | +#include "moc_sortfiltermodel.cpp" |
627 | + |
628 | |
629 | === added file 'modules/Ubuntu/Components/plugin/sortfiltermodel.h' |
630 | --- modules/Ubuntu/Components/plugin/sortfiltermodel.h 1970-01-01 00:00:00 +0000 |
631 | +++ modules/Ubuntu/Components/plugin/sortfiltermodel.h 2014-05-15 09:54:24 +0000 |
632 | @@ -0,0 +1,66 @@ |
633 | +/* |
634 | + * Copyright (C) 2012-2014 Canonical, Ltd. |
635 | + * |
636 | + * Authors: |
637 | + * Michal Hruby <michal.hruby@canonical.com> |
638 | + * Christian Dywan <christian.dywan@canonical.com> |
639 | + * |
640 | + * This program is free software; you can redistribute it and/or modify |
641 | + * it under the terms of the GNU Lesser General Public License as published by |
642 | + * the Free Software Foundation; version 3. |
643 | + * |
644 | + * This program is distributed in the hope that it will be useful, |
645 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
646 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
647 | + * GNU Lesser General Public License for more details. |
648 | + * |
649 | + * You should have received a copy of the GNU Lesser General Public License |
650 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
651 | + */ |
652 | + |
653 | +#ifndef QSORTFILTERPROXYMODELQML_H |
654 | +#define QSORTFILTERPROXYMODELQML_H |
655 | + |
656 | +#include <QSortFilterProxyModel> |
657 | +#include "sortbehavior.h" |
658 | +#include "filterbehavior.h" |
659 | + |
660 | +class Q_DECL_EXPORT QSortFilterProxyModelQML : public QSortFilterProxyModel |
661 | +{ |
662 | + Q_OBJECT |
663 | + |
664 | + Q_PROPERTY(QAbstractItemModel* model READ sourceModel WRITE setModel NOTIFY modelChanged) |
665 | + Q_PROPERTY(int count READ count NOTIFY countChanged) |
666 | + Q_PROPERTY(SortBehavior* sort READ sortBehavior) |
667 | + Q_PROPERTY(FilterBehavior* filter READ filterBehavior) |
668 | + |
669 | +public: |
670 | + explicit QSortFilterProxyModelQML(QObject *parent = 0); |
671 | + |
672 | + Q_INVOKABLE QVariantMap get(int row); |
673 | + Q_INVOKABLE QVariant data(int row, int role); |
674 | + Q_INVOKABLE int count(); |
675 | + virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; |
676 | + |
677 | + /* getters */ |
678 | + QHash<int, QByteArray> roleNames() const; |
679 | + |
680 | + /* setters */ |
681 | + void setFilterProperty(const QString& property); |
682 | + void setModel(QAbstractItemModel *model); |
683 | + |
684 | +Q_SIGNALS: |
685 | + void countChanged(); |
686 | + void modelChanged(); |
687 | + |
688 | +private: |
689 | + SortBehavior m_sortBehavior; |
690 | + SortBehavior* sortBehavior(); |
691 | + void sortChanged(); |
692 | + FilterBehavior m_filterBehavior; |
693 | + FilterBehavior* filterBehavior(); |
694 | + void filterChanged(); |
695 | + int roleByName(const QString& roleName) const; |
696 | +}; |
697 | + |
698 | +#endif // QSORTFILTERPROXYMODELQML_H |
699 | |
700 | === added file 'tests/unit/tst_components/tst_sortfiltermodel.qml' |
701 | --- tests/unit/tst_components/tst_sortfiltermodel.qml 1970-01-01 00:00:00 +0000 |
702 | +++ tests/unit/tst_components/tst_sortfiltermodel.qml 2014-05-15 09:54:24 +0000 |
703 | @@ -0,0 +1,108 @@ |
704 | +/* |
705 | + * Copyright 2014 Canonical Ltd. |
706 | + * |
707 | + * This program is free software; you can redistribute it and/or modify |
708 | + * it under the terms of the GNU Lesser General Public License as published by |
709 | + * the Free Software Foundation; version 3. |
710 | + * |
711 | + * This program is distributed in the hope that it will be useful, |
712 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
713 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
714 | + * GNU Lesser General Public License for more details. |
715 | + * |
716 | + * You should have received a copy of the GNU Lesser General Public License |
717 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
718 | + */ |
719 | + |
720 | +import QtQuick 2.0 |
721 | +import QtTest 1.0 |
722 | +import Ubuntu.Components 1.1 |
723 | + |
724 | +TestCase { |
725 | + name: "SortFilterModel" |
726 | + |
727 | + ListModel { |
728 | + id: things |
729 | + ListElement { foo: "den"; alpha: "bee"; num: 200 } |
730 | + ListElement { foo: "pub"; alpha: "cow"; num: 300 } |
731 | + ListElement { foo: "bar"; alpha: "ant"; num: 100 } |
732 | + } |
733 | + |
734 | + SortFilterModel { |
735 | + id: unmodified |
736 | + model: things |
737 | + } |
738 | + |
739 | + SortFilterModel { |
740 | + id: alphabetic |
741 | + model: things |
742 | + sort.property: "alpha" |
743 | + } |
744 | + |
745 | + SortFilterModel { |
746 | + id: alphaSecond |
747 | + model: things |
748 | + sort.property: "foo" |
749 | + } |
750 | + |
751 | + SortFilterModel { |
752 | + id: alphabeticRe |
753 | + model: things |
754 | + sort.property: "alpha" |
755 | + sort.order: Qt.DescendingOrder |
756 | + } |
757 | + |
758 | + SortFilterModel { |
759 | + id: numeric |
760 | + model: things |
761 | + sort.property: "num" |
762 | + } |
763 | + |
764 | + SortFilterModel { |
765 | + id: numericRe |
766 | + model: things |
767 | + sort.property: "num" |
768 | + sort.order: Qt.DescendingOrder |
769 | + } |
770 | + |
771 | + SortFilterModel { |
772 | + id: bee |
773 | + model: things |
774 | + filter.property: "alpha" |
775 | + filter.pattern: /e/ |
776 | + } |
777 | + |
778 | + function test_passthrough() { |
779 | + compare(unmodified.count, things.count) |
780 | + } |
781 | + |
782 | + function test_sort() { |
783 | + // Default is Ascending |
784 | + compare(alphabetic.sort.order, Qt.AscendingOrder) |
785 | + compare(alphabetic.get(0).alpha, "ant") |
786 | + compare(alphabetic.get(1).alpha, "bee") |
787 | + compare(alphabetic.get(2).alpha, "cow") |
788 | + |
789 | + // Ensure different columns work also |
790 | + compare(alphaSecond.get(0).foo, "bar") |
791 | + |
792 | + // Descending |
793 | + compare(alphabeticRe.sort.order, Qt.DescendingOrder) |
794 | + compare(alphabeticRe.get(0).alpha, "cow") |
795 | + compare(alphabeticRe.get(1).alpha, "bee") |
796 | + compare(alphabeticRe.get(2).alpha, "ant") |
797 | + |
798 | + // Numbers |
799 | + compare(numeric.get(0).num, 100) |
800 | + compare(numericRe.get(0).num, 300) |
801 | + } |
802 | + |
803 | + function test_filter() { |
804 | + // Default is an empty pattern |
805 | + compare(unmodified.filter.pattern, RegExp()) |
806 | + |
807 | + // Filter |
808 | + compare(bee.count, 1) |
809 | + compare(bee.get(0).alpha, "bee") |
810 | + } |
811 | +} |
118 + * model: movies
you need to give the model the id movies