Merge lp:~kalikiana/ubuntu-ui-toolkit/sortFilterModel into lp:ubuntu-ui-toolkit/staging

Proposed by Cris Dywan
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
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

To post a comment you must log in.
Revision history for this message
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal

118 + * model: movies

you need to give the model the id movies

review: Needs Fixing
Revision history for this message
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal

fix quotes

122 + * filter.property: "producer
123 + * filter.pattern: /blender/

Revision history for this message
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal

141 + * Label {
142 + * text: {
143 + * var firstRow = sortedMovies.findFirst("title", /Elephant/))

isn't /Elephant/ supposed to be a string?

144 + * var sourceRow = sortedMovies.mapToSource(firstRow)
145 + * var foundTitle = movies.get(sourceRow).title
146 + * i18n.tr("First matching movie: %1").arg(foundTitle)

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

Revision history for this message
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal

TODO: documentation of properties

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Cris Dywan (kalikiana) wrote : Posted in a previous version of this proposal

modules/Ubuntu/Components/plugin/sortfiltermodel.cpp:72: warning: Unable to parse QML snippet: "Expected a qualified name id" at line 7, column 19

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Cris Dywan (kalikiana) wrote : Posted in a previous version of this proposal

FTR failures in ubuntuuitoolkit.tests.gallery.test_textinput/optionselector/buttons

989. By Cris Dywan

Revert uncommenting of gallery sections

990. By Cris Dywan

SortFilterModel should be Ubuntu.Components 1.1

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
991. By Cris Dywan

Also register *Behavior and AbstractItemModel with version 1.1

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:991
http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/143/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-trusty-touch/537/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty/5165/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-trusty-amd64-ci/143
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-trusty-armhf-ci/143
        deb: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-trusty-armhf-ci/143/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-trusty-i386-ci/143
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/471/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/4812
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/4812/artifact/work/output/*zip*/output.zip
    FAILURE: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/6584/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-trusty/4438/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/5370
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/5370/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/143/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Cris Dywan (kalikiana) wrote :

Looks like J has unrelated problems:
The following packages have unmet dependencies:
 libmirserver18 : Depends: libmirplatform (= 0.1.8+14.04.20140411-0ubuntu1) but 0.1.9bzr1570pkg0utopic1343+autopilot0 is to be installed
                  Depends: libmirplatformgraphics-mesa (= 0.1.8+14.04.20140411-0ubuntu1) but 0.1.9bzr1570pkg0utopic1343+autopilot0 is to be installed or
                           libmirplatformgraphics-android (= 0.1.8+14.04.20140411-0ubuntu1) but 0.1.9bzr1570pkg0utopic1343+autopilot0 is to be installed
 ubuntu-ui-toolkit-doc : Depends: qtdeclarative5-doc-html but it is not going to be installed
                         Depends: qtwebkit5-doc-html but it is not going to be installed
                         Depends: qtsvg5-doc-html but it is not going to be installed
                         Depends: qtscript5-doc-html but it is not going to be installed
                         Depends: qtmultimedia5-doc-html but it is not going to be installed
                         Depends: unity-action-doc but it is not going to be installed
E: Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution).

992. By Cris Dywan

Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/staging

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:992
http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/179/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/54
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/48
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-amd64-ci/11
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-ci/11
        deb: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-ci/11/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-i386-ci/11
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/564
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/155
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/155/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/6878
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/49
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/75
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/75/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/179/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Cris Dywan (kalikiana) wrote :

FTR random failure in test_optionselector_expanded

Revision history for this message
Tim Peeters (tpeeters) wrote :

Copyright in plugin.cpp may be updated

Revision history for this message
Tim Peeters (tpeeters) wrote :

Why do you need to register the QAbstractItemModel?

Revision history for this message
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?

Revision history for this message
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?

Revision history for this message
Tim Peeters (tpeeters) wrote :

181 + * \qmltype SortFilterModel
182 + * \instantiates QSortFilterProxyModelQML
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.Components.ListItems 0.1

Ubuntu.Components 1.1

Revision history for this message
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.FirstCharacter
239 + * }

file:///home/tim/dev/ubuntu-ui-toolkit/r/sortFilterModel/test.qml:35: ReferenceError: sortedMovies is not defined
file:///home/tim/dev/ubuntu-ui-toolkit/r/sortFilterModel/test.qml:42: ReferenceError: sectionDelegate is not defined

Revision history for this message
Tim Peeters (tpeeters) wrote :

the ListView in your example needs anchors.fill: parent to show anything

review: Needs Fixing
Revision history for this message
Tim Peeters (tpeeters) wrote :

your example is not working, output of the SortFilterModel is empty.

review: Needs Fixing
Revision history for this message
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.

Revision history for this message
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.

Revision history for this message
Tim Peeters (tpeeters) wrote :

    qmlRegisterType<FilterBehavior>(uri, 1, 1, "FilterBehavior");
    qmlRegisterType<SortBehavior>(uri, 1, 1, "SortBehavior");

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

Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/staging

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:996
http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/231/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/234
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/214
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-amd64-ci/63
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-ci/63
        deb: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-ci/63/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-i386-ci/63
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/726
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/491
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/491/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/7200
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/196
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/268
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/268/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/231/rebuild

review: Approve (continuous-integration)
Revision history for this message
Tim Peeters (tpeeters) wrote :

good stuff, I like the changes!

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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+}

Subscribers

People subscribed via source and target branches