Merge lp:~unity-team/ubuntu-ui-toolkit/fix-1242647 into lp:ubuntu-ui-toolkit
- fix-1242647
- Merge into trunk
Status: | Work in progress |
---|---|
Proposed branch: | lp:~unity-team/ubuntu-ui-toolkit/fix-1242647 |
Merge into: | lp:ubuntu-ui-toolkit |
Diff against target: |
451 lines (+126/-72) 8 files modified
CHANGES (+2/-0) components.api (+2/-0) examples/ubuntu-ui-toolkit-gallery/OptionSelectors.qml (+7/-11) modules/Ubuntu/Components/ListItems/ItemSelector.qml (+25/-5) modules/Ubuntu/Components/OptionSelector.qml (+34/-17) modules/Ubuntu/Components/OptionSelectorDelegate.qml (+20/-2) tests/autopilot/ubuntuuitoolkit/tests/gallery/test_optionselector.py (+6/-5) tests/unit_x11/tst_components/tst_optionselector.qml (+30/-32) |
To merge this branch: | bzr merge lp:~unity-team/ubuntu-ui-toolkit/fix-1242647 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Needs Fixing | |
Tim Peeters | Pending | ||
Review via email: mp+203901@code.launchpad.net |
This proposal supersedes a proposal from 2013-11-29.
Commit message
Added isSelected() and full support for multiple choice selection with or without a custom model.
Added multiple choice example with custom model to show the use of multi selection.
Cleaned up OptionSelector signal test.
Changed documentation to illustrate these changes.
Description of the change
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:851
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Nicolas d'Offay (nicolas-doffay) wrote : Posted in a previous version of this proposal | # |
I've taken a different approach for this. Since there's no way to get a delegate's property, we're forced to use custom models to bind the 'selected' property to a role. I've illustrated how to use this to check/uncheck a delegate in a multiple choice selector. While I don't consider this the most ideal, QML doesn't currently support the alternative due to the aforementioned inability to get delegate properties which aren't roles.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:869
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: 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:870
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: 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:871
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: 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:872
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: 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:873
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: 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:874
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: 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:875
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: 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:876
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: 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:877
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:878
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
In OptionSelectors
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
99 + if (typeof model.get === "function") {
100 + selected = model.get(
101 + }
What happens if there is no "get" property (or function)? Will this give an error?
perhaps it should be:
if (model.
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
(OptionSelector
> onDelegateClicked: print("SELECTION ARRAY: " + isSelected(index));
> onDelegateClicked: print("SELECTED ROLE: " + isSelected(index));
The prints are a bit abstract, and it is not clear why you print two different things in onDelegateClicked.
I prefer something like this:
onDelegateClicked: print("Item "+index+" selected = "+isSelected(
in both cases.
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
200 + Is i of our model currently selected?
Is item i of our model currently selected?
(or option i)
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
Can you check the initialization of your variables in tst_optionselec
So, add a function initTestCase() to the TestCase which is executed before all the other test.
expanded: false can be removed in "selector" because it is the default.
then, initTestCase() add tests to check the initial state of currentlyExpanded:
compare(
compare(
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
267 + if (typeof listView.
Same comment as before when using typeof. Do we need to check listView.
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
266 + //Only update our selected model property if 'model' inherits from QAbstractListModel
267 + if (typeof listView.
268 + listView.
269 + } else {
270 + //Sync the selections array which we can access to check our current selection.
271 + listView.
272 + }
Please document this behavior. You can add to the description of the model of the OptionSelector/
Nicolas d'Offay (nicolas-doffay) wrote : Posted in a previous version of this proposal | # |
"What happens if there is no "get" property (or function)? Will this give an error?
perhaps it should be:"
No, it falls back to the array of selection values. I'll update the documentation accordingly.
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
listview.selections is initialized as [], and then it is assigned values with selections[i] = value. It is never given a size, how can this work?
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
198 + /*!
199 + \preliminary
200 + Is i of our model currently selected?
201 + */
202 + function isSelected(i) {
203 + var selected = list.selections[i];
204 + if (typeof model.get === "function") {
205 + selected = model.get(
206 + }
207 + return selected;
208 + }
I think it is cleaner if you put selected = list.selections[i] in an else { }, when the model does not have a get function.
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
Can you add a test that checks:
- An item in a multiselector is not selected
- Click the item
- the item is now selected (verify with isSelected(i)).
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
test_optionsele
Nicolas d'Offay (nicolas-doffay) wrote : Posted in a previous version of this proposal | # |
I'm going to be amending the current expanded test to include the multiple choice one. This already tests the functionality. I don't think we need to include an initTestCase().
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:879
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Nicolas d'Offay (nicolas-doffay) wrote : Posted in a previous version of this proposal | # |
"listview.
Javascript can assign values to an empty array. This is evident when the values change and are printed out in the gallery example without the custom model.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:881
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: 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:884
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: 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:885
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: 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:886
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:887
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:888
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
134 + property var selections: []
can you add a little comment here explaining where the property is is initialized and used?
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
388 + compare(
you're checking the expanded property, but the text says "multi selector".
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
398 + function test_clicked_
399 + skip('FIXME: This test doesn\'t pass in CI')
400 + mouseClick(
401 + clickedSignal.
402 + compare(
403 +
404 + //Second option.
405 + mouseClick(
406 + clickedSignal.
407 + //Did the second index get clicked?
408 + compare(
409 + }
410 +
can you add a string saying what went wrong (if something went wrong) to the compare() calls?
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:890
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: 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:891
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
Unit tests pass, but I get a bunch of warnings: http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:892
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
112 + selected = list.selections[i]
add a ; in the end of the line
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:893
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: 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:896
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
code looks good now, we only need to fix the tests (warnings locally, and one fail on jenkins)
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
The warnings are caused by this bug:
https:/
Can be solved in a separate MR. Here it is sufficient to remove that extra delegate which is not necessary.
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
The skip() call in the test is my only complain left, but it is already there in our trunk, so this is good to go. Let's see what jenkins says.
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
apps work on device (including ubuntu-
investigating..
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:897
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Tim Peeters (tpeeters) wrote : Posted in a previous version of this proposal | # |
> apps work on device (including ubuntu-
> ubuntu_
>
> investigating..
I get the same AP failures for ubuntu-
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:899
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:899
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Unmerged revisions
- 899. By Nicolas d'Offay
-
Added additional skip to test.
- 898. By Nicolas d'Offay
-
Removed test and standalone selector delegate.
- 897. By Nicolas d'Offay
-
Readded skip for test which fails in CI. Removed prints.
- 896. By Nicolas d'Offay
-
Removed unused selectorDelegate.
- 895. By Nicolas d'Offay
-
Added semicolon.
- 894. By Nicolas d'Offay
-
Instantiated SelectorDelegate in class creation instead of externally as a component.
- 893. By Nicolas d'Offay
-
Removed skips in test.
- 892. By Nicolas d'Offay
-
Merged trunk.
- 891. By Nicolas d'Offay
-
Changed comment.
- 890. By Nicolas d'Offay
-
Fixed comment.
Preview Diff
1 | === modified file 'CHANGES' |
2 | --- CHANGES 2013-12-05 14:54:53 +0000 |
3 | +++ CHANGES 2014-01-30 09:34:41 +0000 |
4 | @@ -9,7 +9,9 @@ |
5 | |
6 | API Changes |
7 | *********** |
8 | +* ADDED IN: OptionSelector: function isSelected(i) |
9 | * ADDED IN: PickerDelegate: readonly property Picker picker |
10 | +* ADDED IN: ItemSelector: function isSelected(i) |
11 | * CHANGED IN: OptionSelector: readonly property bool currentlyExpanded TO property bool currentlyExpanded |
12 | * CHANGED IN: ItemSelector: readonly property bool currentlyExpanded TO property bool currentlyExpanded |
13 | * ADDED IN: Action: property string iconName |
14 | |
15 | === modified file 'components.api' |
16 | --- components.api 2013-12-17 14:05:43 +0000 |
17 | +++ components.api 2014-01-30 09:34:41 +0000 |
18 | @@ -122,6 +122,7 @@ |
19 | readonly property real itemHeight |
20 | signal delegateClicked(int index) |
21 | signal expansionCompleted() |
22 | + function isSelected(i) |
23 | modules/Ubuntu/Components/ListItems/MultiValue.qml |
24 | Base |
25 | property variant values |
26 | @@ -196,6 +197,7 @@ |
27 | readonly property real itemHeight |
28 | signal delegateClicked(int index) |
29 | signal expansionCompleted() |
30 | + function isSelected(i) |
31 | modules/Ubuntu/Components/OptionSelectorDelegate.qml |
32 | ListItem.Standard |
33 | property string text |
34 | |
35 | === modified file 'examples/ubuntu-ui-toolkit-gallery/OptionSelectors.qml' |
36 | --- examples/ubuntu-ui-toolkit-gallery/OptionSelectors.qml 2013-12-02 14:03:16 +0000 |
37 | +++ examples/ubuntu-ui-toolkit-gallery/OptionSelectors.qml 2014-01-30 09:34:41 +0000 |
38 | @@ -59,24 +59,20 @@ |
39 | |
40 | OptionSelector { |
41 | objectName: "optionselector_custommodel" |
42 | - text: i18n.tr("Custom Model") |
43 | + text: i18n.tr("Custom Model Multiple Selection") |
44 | model: customModel |
45 | expanded: true |
46 | + multiSelection: true |
47 | colourImage: true |
48 | - delegate: selectorDelegate |
49 | - } |
50 | - |
51 | - Component { |
52 | - id: selectorDelegate |
53 | - OptionSelectorDelegate { text: name; subText: description; iconSource: image } |
54 | + delegate: OptionSelectorDelegate { text: name; subText: description; iconSource: image; selected: selected } |
55 | } |
56 | |
57 | ListModel { |
58 | id: customModel |
59 | - ListElement { name: "Name 1"; description: "Description 1"; image: "images.png" } |
60 | - ListElement { name: "Name 2"; description: "Description 2"; image: "images.png" } |
61 | - ListElement { name: "Name 3"; description: "Description 3"; image: "images.png" } |
62 | - ListElement { name: "Name 4"; description: "Description 4"; image: "images.png" } |
63 | + ListElement { name: "Name 1"; description: "Description 1"; image: "images.png"; selected: true} |
64 | + ListElement { name: "Name 2"; description: "Description 2"; image: "images.png"; selected: false } |
65 | + ListElement { name: "Name 3"; description: "Description 3"; image: "images.png"; selected: true } |
66 | + ListElement { name: "Name 4"; description: "Description 4"; image: "images.png"; selected: false } |
67 | } |
68 | |
69 | OptionSelector { |
70 | |
71 | === modified file 'modules/Ubuntu/Components/ListItems/ItemSelector.qml' |
72 | --- modules/Ubuntu/Components/ListItems/ItemSelector.qml 2013-12-05 17:00:33 +0000 |
73 | +++ modules/Ubuntu/Components/ListItems/ItemSelector.qml 2014-01-30 09:34:41 +0000 |
74 | @@ -118,7 +118,8 @@ |
75 | |
76 | /*! |
77 | \preliminary |
78 | - The list of values that will be shown under the label text. This is a model. |
79 | + The list of values that will be shown under the label text. This is a model. If the selector is a multiple selection and this model doesn't inherit from QAbstractListModel |
80 | + then we fall back to using an internal array of booleans to keep track of the selection. |
81 | */ |
82 | property var model |
83 | |
84 | @@ -182,7 +183,7 @@ |
85 | readonly property alias itemHeight: list.itemHeight |
86 | |
87 | /*! |
88 | - Called when delegate is clicked. |
89 | + Called when delegate is clicked. Parameters are the index clicked. |
90 | */ |
91 | signal delegateClicked(int index) |
92 | |
93 | @@ -191,6 +192,21 @@ |
94 | */ |
95 | signal expansionCompleted() |
96 | |
97 | + /*! |
98 | + \preliminary |
99 | + Is option i of our model currently selected? |
100 | + */ |
101 | + function isSelected(i) { |
102 | + var selected; |
103 | + if (typeof model.get === "function") { |
104 | + selected = model.get(i).selected; |
105 | + } else { |
106 | + selected = list.selections[i] |
107 | + } |
108 | + |
109 | + return selected; |
110 | + } |
111 | + |
112 | __height: column.height |
113 | showDivider: false |
114 | |
115 | @@ -223,7 +239,7 @@ |
116 | left: parent.left |
117 | right: parent.right |
118 | } |
119 | - state: itemSelector.expanded ? "expanded" : "collapsed" |
120 | + state: itemSelector.expanded || itemSelector.multiSelection ? "expanded" : "collapsed" |
121 | style: Theme.createStyleComponent("ListItemOptionSelectorStyle.qml", listContainer) |
122 | |
123 | states: [ State { |
124 | @@ -266,17 +282,21 @@ |
125 | id: list |
126 | objectName: "listView" |
127 | |
128 | + property var selections: [] |
129 | + |
130 | property int previousIndex: list.currentIndex |
131 | + property real itemHeight |
132 | + |
133 | readonly property alias expanded: itemSelector.expanded |
134 | readonly property alias multiSelection: itemSelector.multiSelection |
135 | readonly property alias container: listContainer |
136 | - property real itemHeight |
137 | + |
138 | signal delegateClicked(int index) |
139 | |
140 | onDelegateClicked: itemSelector.delegateClicked(index); |
141 | interactive: listContainer.height !== list.contentHeight && listContainer.currentlyExpanded ? true : false |
142 | clip: true |
143 | - currentIndex: 0 |
144 | + currentIndex: multiSelection ? -1 : 0 |
145 | model: itemSelector.model |
146 | anchors.fill: parent |
147 | |
148 | |
149 | === modified file 'modules/Ubuntu/Components/OptionSelector.qml' |
150 | --- modules/Ubuntu/Components/OptionSelector.qml 2013-12-13 15:50:35 +0000 |
151 | +++ modules/Ubuntu/Components/OptionSelector.qml 2014-01-30 09:34:41 +0000 |
152 | @@ -51,7 +51,6 @@ |
153 | } |
154 | |
155 | OptionSelector { |
156 | - objectName: "optionselector_multipleselection" |
157 | text: i18n.tr("Multiple Selection") |
158 | expanded: false |
159 | multiSelection: true |
160 | @@ -62,24 +61,20 @@ |
161 | } |
162 | |
163 | OptionSelector { |
164 | - text: i18n.tr("Label") |
165 | + text: i18n.tr("Multiple Choice Custom Model") |
166 | model: customModel |
167 | expanded: true |
168 | colourImage: true |
169 | - delegate: selectorDelegate |
170 | - } |
171 | - |
172 | - Component { |
173 | - id: selectorDelegate |
174 | - OptionSelectorDelegate { text: name; subText: description; iconSource: image } |
175 | + multiSelection: true |
176 | + delegate: OptionSelectorDelegate { text: name; subText: description; iconSource: image; selected: selected } |
177 | } |
178 | |
179 | ListModel { |
180 | id: customModel |
181 | - ListElement { name: "Name 1"; description: "Description 1"; image: "images.png" } |
182 | - ListElement { name: "Name 2"; description: "Description 2"; image: "images.png" } |
183 | - ListElement { name: "Name 3"; description: "Description 3"; image: "images.png" } |
184 | - ListElement { name: "Name 4"; description: "Description 4"; image: "images.png" } |
185 | + ListElement { name: "Name 1"; description: "Description 1"; image: "images.png"; selected: true} |
186 | + ListElement { name: "Name 2"; description: "Description 2"; image: "images.png"; selected: false } |
187 | + ListElement { name: "Name 3"; description: "Description 3"; image: "images.png"; selected: true } |
188 | + ListElement { name: "Name 4"; description: "Description 4"; image: "images.png"; selected: false } |
189 | } |
190 | |
191 | OptionSelector { |
192 | @@ -117,7 +112,8 @@ |
193 | |
194 | /*! |
195 | \preliminary |
196 | - The list of values that will be shown under the label text. This is a model. |
197 | + The list of values that will be shown under the label text. This is a model. If the selector is a multiple selection and this model doesn't inherit from QAbstractListModel |
198 | + then we fall back to using an internal array of booleans to keep track of the selection. |
199 | */ |
200 | property var model |
201 | |
202 | @@ -181,7 +177,7 @@ |
203 | readonly property alias itemHeight: list.itemHeight |
204 | |
205 | /*! |
206 | - Called when delegate is clicked. |
207 | + Called when delegate is clicked. Parameters are the index clicked. |
208 | */ |
209 | signal delegateClicked(int index) |
210 | |
211 | @@ -190,6 +186,21 @@ |
212 | */ |
213 | signal expansionCompleted() |
214 | |
215 | + /*! |
216 | + \preliminary |
217 | + Is option i of our model currently selected? |
218 | + */ |
219 | + function isSelected(i) { |
220 | + var selected; |
221 | + if (typeof model.get === "function") { |
222 | + selected = model.get(i).selected; |
223 | + } else { |
224 | + selected = list.selections[i]; |
225 | + } |
226 | + |
227 | + return selected; |
228 | + } |
229 | + |
230 | /*! |
231 | \internal |
232 | Trigger the action, passing the current index. |
233 | @@ -231,7 +242,7 @@ |
234 | left: parent.left |
235 | right: parent.right |
236 | } |
237 | - state: optionSelector.expanded ? "expanded" : "collapsed" |
238 | + state: optionSelector.expanded || optionSelector.multiSelection ? "expanded" : "collapsed" |
239 | style: Theme.createStyleComponent("OptionSelectorStyle.qml", listContainer) |
240 | states: [ State { |
241 | name: "expanded" |
242 | @@ -272,17 +283,23 @@ |
243 | ListView { |
244 | id: list |
245 | |
246 | + /*This array is initialised on an index by index basis in each OptionSelectorDelegate's onCompleted call. |
247 | + Values are reset everytime a multiple choice selection is clicked.*/ |
248 | + property var selections: [] |
249 | + |
250 | property int previousIndex: -1 |
251 | + property real itemHeight |
252 | + |
253 | readonly property alias expanded: optionSelector.expanded |
254 | readonly property alias multiSelection: optionSelector.multiSelection |
255 | readonly property alias container: listContainer |
256 | - property real itemHeight |
257 | + |
258 | signal delegateClicked(int index) |
259 | |
260 | onDelegateClicked: optionSelector.delegateClicked(index); |
261 | interactive: listContainer.height !== list.contentHeight && listContainer.currentlyExpanded ? true : false |
262 | clip: true |
263 | - currentIndex: 0 |
264 | + currentIndex: multiSelection ? -1 : 0 |
265 | model: optionSelector.model |
266 | anchors.fill: parent |
267 | |
268 | |
269 | === modified file 'modules/Ubuntu/Components/OptionSelectorDelegate.qml' |
270 | --- modules/Ubuntu/Components/OptionSelectorDelegate.qml 2013-12-04 15:51:58 +0000 |
271 | +++ modules/Ubuntu/Components/OptionSelectorDelegate.qml 2014-01-30 09:34:41 +0000 |
272 | @@ -147,16 +147,26 @@ |
273 | left: parent.left |
274 | right: parent.right |
275 | } |
276 | + |
277 | + /*! \internal */ |
278 | onClicked: { |
279 | if (listView.container.currentlyExpanded) { |
280 | - listView.delegateClicked(index); |
281 | - |
282 | if (!listView.multiSelection) { |
283 | + //Set the current index which changes currentItem if multiple choice isn't active. |
284 | listView.previousIndex = listView.currentIndex; |
285 | listView.currentIndex = index; |
286 | } else { |
287 | selected = !selected; |
288 | + //Only update our selected model property if 'model' inherits from QAbstractListModel |
289 | + if (typeof listView.model.setProperty === "function") { |
290 | + listView.model.setProperty(index, "selected", selected); |
291 | + } else { |
292 | + //Sync the selections array which we can access to check our current selection. |
293 | + listView.selections[index] = selected; |
294 | + } |
295 | } |
296 | + |
297 | + listView.delegateClicked(index); |
298 | } |
299 | |
300 | if (!listView.expanded && !listView.multiSelection) { |
301 | @@ -165,6 +175,14 @@ |
302 | } |
303 | |
304 | Component.onCompleted: { |
305 | + if (listView.multiSelection) { |
306 | + if (typeof listView.model.get === "function") { |
307 | + selected = listView.model.get(index).selected; |
308 | + } else { |
309 | + listView.selections[index] = selected; |
310 | + } |
311 | + } |
312 | + |
313 | height = listView.itemHeight = childrenRect.height; |
314 | } |
315 | |
316 | |
317 | === modified file 'tests/autopilot/ubuntuuitoolkit/tests/gallery/test_optionselector.py' |
318 | --- tests/autopilot/ubuntuuitoolkit/tests/gallery/test_optionselector.py 2013-11-08 09:19:02 +0000 |
319 | +++ tests/autopilot/ubuntuuitoolkit/tests/gallery/test_optionselector.py 2014-01-30 09:34:41 +0000 |
320 | @@ -81,16 +81,17 @@ |
321 | self.reveal_item_by_flick(custommodel, flickable, FlickDirection.UP) |
322 | self.assertThat(flickable.flicking, Eventually(Equals(False))) |
323 | |
324 | - self.assertThat(custommodel.selectedIndex, Equals(0)) |
325 | - selectedValue = custommodel.select_single('Label', text='Name 4') |
326 | + selectedValue = custommodel.select_single('OptionSelectorDelegate', |
327 | + text='Name 4') |
328 | self.assertIsNotNone(selectedValue) |
329 | self.pointing_device.click_object(selectedValue) |
330 | - self.assertThat(custommodel.selectedIndex, Eventually(Equals(3))) |
331 | + self.assertThat(selectedValue.selected, Eventually(Equals(True))) |
332 | |
333 | - selectedValue = custommodel.select_single('Label', text='Name 1') |
334 | + selectedValue = custommodel.select_single('OptionSelectorDelegate', |
335 | + text='Name 1') |
336 | self.assertIsNotNone(selectedValue) |
337 | self.pointing_device.click_object(selectedValue) |
338 | - self.assertThat(custommodel.selectedIndex, Eventually(Equals(0))) |
339 | + self.assertThat(selectedValue.selected, Eventually(Equals(False))) |
340 | |
341 | #scroll the page downward now. |
342 | collapsed = self.getObject("optionselector_collapsed") |
343 | |
344 | === modified file 'tests/unit_x11/tst_components/tst_optionselector.qml' |
345 | --- tests/unit_x11/tst_components/tst_optionselector.qml 2013-12-18 12:40:20 +0000 |
346 | +++ tests/unit_x11/tst_components/tst_optionselector.qml 2014-01-30 09:34:41 +0000 |
347 | @@ -33,9 +33,13 @@ |
348 | id: selector |
349 | |
350 | text: "TEST" |
351 | - delegate: selectorDelegate |
352 | + delegate: OptionSelectorDelegate { |
353 | + text: name |
354 | + subText: description |
355 | + iconSource: image |
356 | + constrainImage: true |
357 | + } |
358 | model: customModel |
359 | - expanded: true |
360 | |
361 | action: { |
362 | enabled: true |
363 | @@ -45,24 +49,12 @@ |
364 | } |
365 | } |
366 | |
367 | - OptionSelectorDelegate { |
368 | - id: testDelegate |
369 | + OptionSelector { |
370 | + id: multiSelector |
371 | |
372 | text: "TEST" |
373 | - subText: "test" |
374 | - iconSource: "../../resources/optionselector/test.png" |
375 | - constrainImage: true |
376 | - } |
377 | - } |
378 | - |
379 | - Component { |
380 | - id: selectorDelegate |
381 | - |
382 | - OptionSelectorDelegate { |
383 | - text: name |
384 | - subText: description |
385 | - iconSource: image |
386 | - constrainImage: true |
387 | + model: [1, 2, 3, 4] |
388 | + multiSelection: true |
389 | } |
390 | } |
391 | |
392 | @@ -76,7 +68,7 @@ |
393 | |
394 | SignalSpy { |
395 | id: clickedSignal |
396 | - target: selector |
397 | + target: multiSelector |
398 | signalName: "delegateClicked" |
399 | } |
400 | |
401 | @@ -99,7 +91,8 @@ |
402 | function test_expanded() { |
403 | var listContainer = findChild(selector, "listContainer"); |
404 | |
405 | - selector.expanded = false; |
406 | + compare(multiSelector.expanded, false, "expanded should be false on startup.") |
407 | + |
408 | compare(listContainer.currentlyExpanded, false, "expanded should be true if list is an expanded one"); |
409 | compare(listContainer.state, "collapsed", "state should be collapsed"); |
410 | |
411 | @@ -127,23 +120,28 @@ |
412 | |
413 | function test_custom_model_delegate() { |
414 | compare(selector.model, customModel, "Model wasn't set correctly."); |
415 | - compare(selector.delegate, selectorDelegate, "Delegate hasn't been set correctly"); |
416 | - } |
417 | - |
418 | - function test_image_constraint() { |
419 | - var image = findChild(testDelegate, "icon"); |
420 | - compare(image.height, testDelegate.height); |
421 | - } |
422 | - |
423 | - function test_signal() { |
424 | - skip('FIXME: This test doesn\'t pass in CI') |
425 | + } |
426 | + |
427 | + function test_clicked_signal() { |
428 | + skip('FIXME: This test doesn\'t pass in CI. Passes locally for anyone who tried.') |
429 | + mouseClick(multiSelector, 100, 100, Qt.LeftButton); |
430 | + clickedSignal.wait(); |
431 | + compare(multiSelector.isSelected(clickedSignal.signalArguments[0][0]), true, "Clicked signal was not emitted and option was not selected."); |
432 | + |
433 | + //Second option. |
434 | + mouseClick(multiSelector, 100, 100, Qt.LeftButton); |
435 | + clickedSignal.wait(); |
436 | + //Did the second index get clicked? |
437 | + compare(multiSelector.isSelected(clickedSignal.signalArguments[1][0]), false, "Clicked signal was not emitted and option was not deselected."); |
438 | + } |
439 | + |
440 | + function test_expansion_signal() { |
441 | mouseClick(selector, 100, 100, Qt.LeftButton); |
442 | - clickedSignal.wait(); |
443 | expansionSignal.wait(); |
444 | } |
445 | |
446 | function test_triggered() { |
447 | - skip('FIXME: This test doesn\'t pass in CI') |
448 | + skip('FIXME: This test doesn\'t pass in CI. Passes locally for anyone who tried.') |
449 | mouseClick(selector, 100, 100, Qt.LeftButton); |
450 | triggeredSignal.wait(); |
451 | } |
PASSED: Continuous integration, rev:850 jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- ci/1359/ jenkins. qa.ubuntu. com/job/ generic- mediumtests- trusty/ 1296 jenkins. qa.ubuntu. com/job/ generic- mediumtests- trusty- touch/1270 jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- trusty- amd64-ci/ 307 jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- trusty- armhf-ci/ 307 jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- trusty- armhf-ci/ 307/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ autopilot- testrunner- otto-trusty/ 1151 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- trusty- amd64/1296 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- trusty- amd64/1296/ artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- trusty- armhf/1270 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- trusty- armhf/1270/ artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ generic- mediumtests- runner- mako/3817 s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 1937
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/ubuntu- ui-toolkit- ci/1359/ rebuild
http://