Merge lp:~nicolas-doffay/ubuntu-ui-toolkit/selectors-multi-selection into lp:ubuntu-ui-toolkit

Proposed by Nicolas d'Offay
Status: Merged
Approved by: Tim Peeters
Approved revision: 797
Merged at revision: 796
Proposed branch: lp:~nicolas-doffay/ubuntu-ui-toolkit/selectors-multi-selection
Merge into: lp:ubuntu-ui-toolkit
Diff against target: 1012 lines (+412/-212)
9 files modified
CHANGES (+10/-0)
components.api (+10/-2)
examples/ubuntu-ui-toolkit-gallery/ListItems.qml (+77/-39)
examples/ubuntu-ui-toolkit-gallery/OptionSelectors.qml (+72/-33)
modules/Ubuntu/Components/ListItems/ItemSelector.qml (+106/-45)
modules/Ubuntu/Components/OptionSelector.qml (+105/-43)
modules/Ubuntu/Components/OptionSelectorDelegate.qml (+18/-15)
tests/unit_x11/tst_components/tst_listitems_itemselector.qml (+4/-18)
tests/unit_x11/tst_components/tst_optionselector.qml (+10/-17)
To merge this branch: bzr merge lp:~nicolas-doffay/ubuntu-ui-toolkit/selectors-multi-selection
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Tim Peeters Approve
Review via email: mp+190605@code.launchpad.net

Commit message

Added multiSelection bool and supporting code to OptionSelector and ItemSelector. This turns either component into a multiple choice selector.

Fixed linked bugs.

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

14 +* ADDED IN: OptionSelector: readonly property alias currentlyExpanded
15 +* ADDED IN: ItemSelector: readonly property alias currentlyExpanded

it would be more useful to list the types there instead of 'alias'

Also, all properties are about the current state, so what do you think about naming the property "expanded"?

793. By Nicolas d'Offay

Specified types of aliases in CHANGES.

Revision history for this message
Nicolas d'Offay (nicolas-doffay) wrote :

The reason I didn't name it expanded was due to the fact that an expanded property already exists which dictates whether the list is an expanded list or a collapsible one.

Any suggestions on better naming conventions are welcome!

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Tim Peeters (tpeeters) wrote :

10 +* ADDED IN: OptionSelector: readonly property alias (real) itemHeight
11 +* ADDED IN: ItemSelector: readonly property alias (real) itemHeight
12 +* ADDED IN: OptionSelector: signal expansionCompleted()
13 +* ADDED IN: ItemSelector: signal expansionCompleted()
14 +* ADDED IN: OptionSelector: readonly property alias (bool) currentlyExpanded
15 +* ADDED IN: ItemSelector: readonly property alias (bool) currentlyExpanded

no need to mention alias there. readonly property alias itemHeight woud be enough

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

Could you reformat the documentation strings to be at most 70-80 characters per line?
I'm not sure if we do it for all components, but I do it and it improves readability when reading the docs from the source.

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

> The reason I didn't name it expanded was due to the fact that an expanded
> property already exists which dictates whether the list is an expanded list or
> a collapsible one.
>
> Any suggestions on better naming conventions are welcome!

so 'expanded' means always expanded or not collapsible?

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

            OptionSelector {
                objectName: "optionselector_multipleselection"

you don't use that objectName in the example code so you can remove it

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

you need to add "import QtQuick 2.0" to the first example to make it work.

Also, if you want the example code to be executable and work, width and height (and perhaps a flickable / listview) needs to be added to the column.

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

it is nice that you can set the containerHeight, but when it is set and the contents does not fit, I do not see an indication that I can scroll. Is this intended to be like this?

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

for me it would be more natural if the "expanded" property holds the current state of the expansion, and an "alwaysExpanded" property is true if the selector is not collapsible.

Of course we need to make sure that we don't break apps that use the expandable property already.

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

I don't like using abbreviations such as "multiSelection" (I realize that we have a MultiValue list item currently. In retrospect I don't like that name also). Are there other names we can use? For example, "multipleSelection" or "allowMultiple"

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

Are there use cases for having single selection that is not collapsible? If there are none (ask design), we don't need an alwaysExpanded property.

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

Why is there an ItemSelector and an OptionSelector? Are they the same??

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

in ItemSelector:

    /*!
      \qmlproperty real itemHeight
      Is our list currently expanded?
     */
    readonly property alias itemHeight: list.itemHeight

I think this is the doc for the currentlyExpanded property

review: Needs Fixing
Revision history for this message
Nicolas d'Offay (nicolas-doffay) wrote :

The ItemSelector is the version of the OptionSelector which is a ListItem, the OptionSelector uses an UbuntuShape.

794. By Nicolas d'Offay

Fixed up docs and naming convention.

795. By Nicolas d'Offay

Fixed up tests and refactored the naming conventions of both lists.

796. By Nicolas d'Offay

Removed unused signals.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Tim Peeters (tpeeters) wrote :

> The ItemSelector is the version of the OptionSelector which is a ListItem, the
> OptionSelector uses an UbuntuShape.

Do we really need two components that have practically the same API and implementation? It duplicates a lot of code. Perhaps the ItemSelector can simply use an UbuntuShape and an OptionSelector? Or perhaps it is not needed and OptionSelector can be put in a list?

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

Can you check if and which applications are using OptionSelector.expanded? If there are none, go ahead and update the API. If there are, make sure you discuss the API change with the app developers that use it.

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

property bool expanded became read-only. That is fine with me if you do not want the developer to have the freedom to expand/collapse an collapsible (not alwaysExpanded) OptionSelector. If it is unclear whether that will be needed, then the more restrictive (readonly) has my preference because it is easier to expand an API later than to restrict it.

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

Can you update the API doc with the new properties? thanks.

Revision history for this message
Nicolas d'Offay (nicolas-doffay) wrote :

Hey Tim, Florian advised me to separate the components, I'm assuming his reasoning was to be specific about it since the one most definitely is a ListItem (even with all the code repetition). However I obviously acknowledge that having two components with almost identical code isn't exactly ideal.

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

Ok, since the separation of OptionSelector and ItemSelector was there before this MR, we don't need to resolve it here. Still I don't find it ideal, so I reported a bug about it: https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1240019

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

you can replace
* ADDED IN: OptionSelector: readonly property alias (real) itemHeight

by
* ADDED IN: OptionSelector: readonly property real itemHeight

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

> Hey Tim, Florian advised me to separate the components, I'm assuming his
> reasoning was to be specific about it since the one most definitely is a
> ListItem (even with all the code repetition). However I obviously acknowledge
> that having two components with almost identical code isn't exactly ideal.

OptionSelector also inherits from ListItem.Empty, so the distinction you mention does not exist

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

> > Hey Tim, Florian advised me to separate the components, I'm assuming his
> > reasoning was to be specific about it since the one most definitely is a
> > ListItem (even with all the code repetition). However I obviously
> acknowledge
> > that having two components with almost identical code isn't exactly ideal.
>
> OptionSelector also inherits from ListItem.Empty, so the distinction you
> mention does not exist

But making the changes to get rid of the code duplication can be part of the fix for https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1240019 which can be done in a separate MR.

Revision history for this message
Nicolas d'Offay (nicolas-doffay) wrote :

> > OptionSelector also inherits from ListItem.Empty, so the distinction you mention does not exist.

It does indeed exist. It's to do with the styling. One inherits from StyledItem and the other from ListItem.Empty. This was the initial reason they had to be separated.

797. By Nicolas d'Offay

removed bracketed types from CHANGES.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Tim Peeters (tpeeters) wrote :

This MR is all good now.

review: Approve
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 'CHANGES'
2--- CHANGES 2013-10-02 06:38:07 +0000
3+++ CHANGES 2013-10-16 12:35:36 +0000
4@@ -9,8 +9,18 @@
5
6 API Changes
7 ***********
8+* CHANGED IN: OptionSelector: property bool expanded TO bool alwaysExpanded
9+* CHANGED IN: ItemSelector: property bool expanded TO bool alwaysExpanded
10+* ADDED IN: OptionSelector: readonly property bool expanded
11+* ADDED IN: ItemSelector: readonly property bool expanded
12 * ADDED IN: Tab: readonly property int index
13 * ADDED IN: ListItem.Empty: property bool confirmRemoval
14+* ADDED IN: OptionSelector: property bool multiSelection
15+* ADDED IN: ItemSelector: property bool multiSelection
16+* ADDED IN: OptionSelector: readonly property real itemHeight
17+* ADDED IN: ItemSelector: readonly property real itemHeight
18+* ADDED IN: OptionSelector: signal expansionCompleted()
19+* ADDED IN: ItemSelector: signal expansionCompleted()
20 * ADDED IN: OptionSelectorDelegate: property bool constrainImage
21 * ADDED IN: Empty: property alias divider
22 * ADDED IN: ListItems/OptionSelector: signal delegateSelected()
23
24=== modified file 'components.api'
25--- components.api 2013-10-03 06:27:08 +0000
26+++ components.api 2013-10-16 12:35:36 +0000
27@@ -100,11 +100,15 @@
28 modules/Ubuntu/Components/OptionSelector.qml
29 ListItem.Empty
30 property var model
31- property bool expanded
32+ property bool alwaysExpanded
33+ property bool multiSelection
34 property bool colourImage
35 property real containerHeight
36 property int selectedIndex
37+ readonly property bool expanded
38+ readonly property real itemHeight
39 signal delegateClicked(int index)
40+ signal expansionCompleted()
41 modules/Ubuntu/Components/OptionSelectorDelegate.qml
42 ListItem.Standard
43 property string text
44@@ -432,11 +436,15 @@
45 modules/Ubuntu/Components/ListItems/ItemSelector.qml
46 ListItem.Empty
47 property var model
48- property bool expanded
49+ property bool alwaysExpanded
50+ property bool multiSelection
51 property bool colourImage
52 property real containerHeight
53 property int selectedIndex
54+ readonly property bool expanded
55+ readonly property real itemHeight
56 signal delegateClicked(int index)
57+ signal expansionCompleted()
58 modules/Ubuntu/Components/ListItems/LabelVisual.qml
59 Label
60 property bool selected
61
62=== modified file 'examples/ubuntu-ui-toolkit-gallery/ListItems.qml'
63--- examples/ubuntu-ui-toolkit-gallery/ListItems.qml 2013-09-18 00:02:20 +0000
64+++ examples/ubuntu-ui-toolkit-gallery/ListItems.qml 2013-10-16 12:35:36 +0000
65@@ -77,51 +77,89 @@
66 }
67
68 ListItemsSection {
69- title: i18n.tr("Option selector")
70- className: "OptionSelector"
71+ title: i18n.tr("Item selector")
72+ className: "ItemSelector"
73
74 Column {
75 anchors.left: parent.left
76 anchors.right: parent.right
77 spacing: units.gu(3)
78
79- ListItem.ItemSelector {
80- text: i18n.tr("Label")
81- model: [i18n.tr("Value 1"),
82- i18n.tr("Value 2"),
83- i18n.tr("Value 3"),
84- i18n.tr("Value 4")]
85- }
86-
87- ListItem.ItemSelector {
88- text: i18n.tr("Label")
89- expanded: true
90- model: [i18n.tr("Value 1"),
91- i18n.tr("Value 2"),
92- i18n.tr("Value 3"),
93- i18n.tr("Value 4")]
94- }
95-
96- ListItem.ItemSelector {
97- text: i18n.tr("Label")
98- model: customModel
99- expanded: true
100- colourImage: true
101- delegate: selectorDelegate
102- }
103-
104- Component {
105- id: selectorDelegate
106- Toolkit.OptionSelectorDelegate { text: name; subText: description; icon: image }
107- }
108-
109- ListModel {
110- id: customModel
111- ListElement { name: "Name 1"; description: "Description 1"; image: "images.png" }
112- ListElement { name: "Name 2"; description: "Description 2"; image: "images.png" }
113- ListElement { name: "Name 3"; description: "Description 3"; image: "images.png" }
114- ListElement { name: "Name 4"; description: "Description 4"; image: "images.png" }
115- }
116+ ListItem.ItemSelector {
117+ text: i18n.tr("Expanding")
118+ model: [i18n.tr("Value 1"),
119+ i18n.tr("Value 2"),
120+ i18n.tr("Value 3"),
121+ i18n.tr("Value 4")]
122+ }
123+
124+ ListItem.ItemSelector {
125+ text: i18n.tr("Expanded")
126+ alwaysExpanded: true
127+ model: [i18n.tr("Value 1"),
128+ i18n.tr("Value 2"),
129+ i18n.tr("Value 3"),
130+ i18n.tr("Value 4")]
131+ }
132+
133+ ListItem.ItemSelector {
134+ text: i18n.tr("Multiple Selection")
135+ alwaysExpanded: false
136+ multiSelection: true
137+ model: [i18n.tr("Value 1"),
138+ i18n.tr("Value 2"),
139+ i18n.tr("Value 3"),
140+ i18n.tr("Value 4")]
141+ }
142+
143+ ListItem.ItemSelector {
144+ text: i18n.tr("Custom Model")
145+ model: customModel
146+ alwaysExpanded: true
147+ colourImage: true
148+ delegate: selectorDelegate
149+ }
150+
151+ Component {
152+ id: selectorDelegate
153+ Toolkit.OptionSelectorDelegate { text: name; subText: description; icon: image }
154+ }
155+
156+ ListModel {
157+ id: customModel
158+ ListElement { name: "Name 1"; description: "Description 1"; image: "images.png" }
159+ ListElement { name: "Name 2"; description: "Description 2"; image: "images.png" }
160+ ListElement { name: "Name 3"; description: "Description 3"; image: "images.png" }
161+ ListElement { name: "Name 4"; description: "Description 4"; image: "images.png" }
162+ }
163+
164+ ListItem.ItemSelector {
165+ text: i18n.tr("Label")
166+ model: [i18n.tr("Value 1"),
167+ i18n.tr("Value 2"),
168+ i18n.tr("Value 3"),
169+ i18n.tr("Value 4"),
170+ i18n.tr("Value 5"),
171+ i18n.tr("Value 6"),
172+ i18n.tr("Value 7"),
173+ i18n.tr("Value 8")]
174+ containerHeight: itemHeight * 4
175+ }
176+
177+ ListItem.ItemSelector {
178+ text: i18n.tr("Label")
179+ alwaysExpanded: true
180+ selectedIndex: -1
181+ model: [i18n.tr("Value 1"),
182+ i18n.tr("Value 2"),
183+ i18n.tr("Value 3"),
184+ i18n.tr("Value 4"),
185+ i18n.tr("Value 5"),
186+ i18n.tr("Value 6"),
187+ i18n.tr("Value 7"),
188+ i18n.tr("Value 8")]
189+ containerHeight: itemHeight * 4
190+ }
191 }
192 }
193
194
195=== modified file 'examples/ubuntu-ui-toolkit-gallery/OptionSelectors.qml'
196--- examples/ubuntu-ui-toolkit-gallery/OptionSelectors.qml 2013-10-02 09:45:48 +0000
197+++ examples/ubuntu-ui-toolkit-gallery/OptionSelectors.qml 2013-10-16 12:35:36 +0000
198@@ -27,46 +27,85 @@
199 anchors.right: parent.right
200 spacing: units.gu(3)
201
202- OptionSelector {
203+ OptionSelector {
204 objectName: "optionselector_collapsed"
205 text: i18n.tr("Collapsed")
206- model: [i18n.tr("Value 1"),
207- i18n.tr("Value 2"),
208- i18n.tr("Value 3"),
209- i18n.tr("Value 4")]
210- }
211+ model: [i18n.tr("Value 1"),
212+ i18n.tr("Value 2"),
213+ i18n.tr("Value 3"),
214+ i18n.tr("Value 4")]
215+ }
216
217- OptionSelector {
218+ OptionSelector {
219 objectName: "optionselector_expanded"
220 text: i18n.tr("Epanded")
221- expanded: true
222- model: [i18n.tr("Value 1"),
223- i18n.tr("Value 2"),
224- i18n.tr("Value 3"),
225- i18n.tr("Value 4")]
226- }
227-
228- OptionSelector {
229+ alwaysExpanded: true
230+ model: [i18n.tr("Value 1"),
231+ i18n.tr("Value 2"),
232+ i18n.tr("Value 3"),
233+ i18n.tr("Value 4")]
234+ }
235+
236+ OptionSelector {
237+ objectName: "optionselector_multipleselection"
238+ text: i18n.tr("Multiple Selection")
239+ alwaysExpanded: false
240+ multiSelection: true
241+ model: [i18n.tr("Value 1"),
242+ i18n.tr("Value 2"),
243+ i18n.tr("Value 3"),
244+ i18n.tr("Value 4")]
245+ }
246+
247+ OptionSelector {
248 objectName: "optionselector_custommodel"
249 text: i18n.tr("Custom Model")
250- model: customModel
251- expanded: true
252- colourImage: true
253- delegate: selectorDelegate
254- }
255-
256- Component {
257- id: selectorDelegate
258- OptionSelectorDelegate { text: name; subText: description; icon: image }
259- }
260-
261- ListModel {
262- id: customModel
263- ListElement { name: "Name 1"; description: "Description 1"; image: "images.png" }
264- ListElement { name: "Name 2"; description: "Description 2"; image: "images.png" }
265- ListElement { name: "Name 3"; description: "Description 3"; image: "images.png" }
266- ListElement { name: "Name 4"; description: "Description 4"; image: "images.png" }
267- }
268+ model: customModel
269+ alwaysExpanded: true
270+ colourImage: true
271+ delegate: selectorDelegate
272+ }
273+
274+ Component {
275+ id: selectorDelegate
276+ OptionSelectorDelegate { text: name; subText: description; icon: image }
277+ }
278+
279+ ListModel {
280+ id: customModel
281+ ListElement { name: "Name 1"; description: "Description 1"; image: "images.png" }
282+ ListElement { name: "Name 2"; description: "Description 2"; image: "images.png" }
283+ ListElement { name: "Name 3"; description: "Description 3"; image: "images.png" }
284+ ListElement { name: "Name 4"; description: "Description 4"; image: "images.png" }
285+ }
286+
287+ OptionSelector {
288+ text: i18n.tr("Label")
289+ model: [i18n.tr("Value 1"),
290+ i18n.tr("Value 2"),
291+ i18n.tr("Value 3"),
292+ i18n.tr("Value 4"),
293+ i18n.tr("Value 5"),
294+ i18n.tr("Value 6"),
295+ i18n.tr("Value 7"),
296+ i18n.tr("Value 8")]
297+ containerHeight: itemHeight * 4
298+ }
299+
300+ OptionSelector {
301+ text: i18n.tr("Label")
302+ alwaysExpanded: true
303+ selectedIndex: -1
304+ model: [i18n.tr("Value 1"),
305+ i18n.tr("Value 2"),
306+ i18n.tr("Value 3"),
307+ i18n.tr("Value 4"),
308+ i18n.tr("Value 5"),
309+ i18n.tr("Value 6"),
310+ i18n.tr("Value 7"),
311+ i18n.tr("Value 8")]
312+ containerHeight: itemHeight * 4
313+ }
314 }
315 }
316 }
317
318=== modified file 'modules/Ubuntu/Components/ListItems/ItemSelector.qml'
319--- modules/Ubuntu/Components/ListItems/ItemSelector.qml 2013-09-04 12:27:58 +0000
320+++ modules/Ubuntu/Components/ListItems/ItemSelector.qml 2013-10-16 12:35:36 +0000
321@@ -20,45 +20,61 @@
322
323 /*!
324 \qmltype ItemSelector
325- \inqmlmodule Components.Components.ListItems 0.1
326+ \inqmlmodule Ubuntu.Components.ListItems 0.1
327 \ingroup ubuntu-listitems
328- \brief ListItem displaying a single selected value with and optional image and subtext when not expanded, where expanding
329- it opens a listing of all the possible values for selection with an additional option of always being expanded.
330+ \brief ListItem displaying either a single selected value or expanded multiple choice with an optional image and subtext when not expanded, when expanding it opens a
331+ listing of all the possible values for selection with an additional option of always being expanded. If multiple choice is selected the list is expanded automatically.
332
333 \b{This component is under heavy development.}
334
335 Examples:
336 \qml
337- import Components.Components.ListItems 0.1 as ListItem
338+ import Ubuntu.Components.ListItems 0.1 as ListItem
339 Column {
340- width: 250
341- ListItem.ItemSelector {
342- text: "Standard"
343- model: ["Value 1", "Value 2", "Value 3", "Value 4"]
344- }
345- ListItem.ItemSelector {
346- text: "Disabled"
347- model: ["Value 1", "Value 2", "Value 3", "Value 4"]
348- enabled: false
349- }
350- ListItem.ItemSelector {
351- text: "Expanded"
352- model: ["Value 1", "Value 2", "Value 3", "Value 4"]
353- expanded: true
354- }
355- ListItem.ItemSelector {
356- text: "Icon"
357- icon: Qt.resolvedUrl("icon.png")
358- values: ["Value 1", "Value 2", "Value 3", "Value 4"]
359- selectedIndex: 2
360- }
361+ anchors.left: parent.left
362+ anchors.right: parent.right
363+ spacing: units.gu(3)
364+
365+ ListItem.ItemSelector {
366+ text: i18n.tr("Label")
367+ model: [i18n.tr("Value 1"),
368+ i18n.tr("Value 2"),
369+ i18n.tr("Value 3"),
370+ i18n.tr("Value 4")]
371+ }
372+
373+ ListItem.ItemSelector {
374+ text: i18n.tr("Label")
375+ alwaysExpanded: true
376+ model: [i18n.tr("Value 1"),
377+ i18n.tr("Value 2"),
378+ i18n.tr("Value 3"),
379+ i18n.tr("Value 4")]
380+ }
381+
382+ ListItem.ItemSelector {
383+ text: i18n.tr("Multiple Selection")
384+ alwaysExpanded: false
385+ multiSelection: true
386+ model: [i18n.tr("Value 1"),
387+ i18n.tr("Value 2"),
388+ i18n.tr("Value 3"),
389+ i18n.tr("Value 4")]
390+ }
391+
392 ListItem.ItemSelector {
393 text: i18n.tr("Label")
394 model: customModel
395- expanded: true
396+ alwaysExpanded: true
397 colourImage: true
398- delegate: OptionSelectorDelegate { text: name; subText: description; icon: image }
399- }
400+ delegate: selectorDelegate
401+ }
402+
403+ Component {
404+ id: selectorDelegate
405+ Toolkit.OptionSelectorDelegate { text: name; subText: description; icon: image }
406+ }
407+
408 ListModel {
409 id: customModel
410 ListElement { name: "Name 1"; description: "Description 1"; image: "images.png" }
411@@ -66,6 +82,33 @@
412 ListElement { name: "Name 3"; description: "Description 3"; image: "images.png" }
413 ListElement { name: "Name 4"; description: "Description 4"; image: "images.png" }
414 }
415+
416+ ListItem.ItemSelector {
417+ text: i18n.tr("Label")
418+ model: [i18n.tr("Value 1"),
419+ i18n.tr("Value 2"),
420+ i18n.tr("Value 3"),
421+ i18n.tr("Value 4"),
422+ i18n.tr("Value 5"),
423+ i18n.tr("Value 6"),
424+ i18n.tr("Value 7"),
425+ i18n.tr("Value 8")]
426+ containerHeight: itemHeight * 4
427+ }
428+
429+ ListItem.ItemSelector {
430+ text: i18n.tr("Label")
431+ alwaysExpanded: true
432+ model: [i18n.tr("Value 1"),
433+ i18n.tr("Value 2"),
434+ i18n.tr("Value 3"),
435+ i18n.tr("Value 4"),
436+ i18n.tr("Value 5"),
437+ i18n.tr("Value 6"),
438+ i18n.tr("Value 7"),
439+ i18n.tr("Value 8")]
440+ containerHeight: itemHeight * 4
441+ }
442 }
443 \endqml
444 */
445@@ -82,9 +125,15 @@
446
447 /*!
448 \preliminary
449- Specifies whether the list is always expanded.
450- */
451- property bool expanded: false
452+ Specifies whether the list is always alwaysExpanded.
453+ */
454+ property bool alwaysExpanded: false
455+
456+ /*!
457+ \preliminary
458+ If the list is alwaysExpanded, multiple choice selection is enabled.
459+ */
460+ property bool multiSelection: false
461
462 /*!
463 \preliminary
464@@ -111,10 +160,27 @@
465 property alias selectedIndex: list.currentIndex
466
467 /*!
468+ \qmlproperty bool expanded
469+ Is our list currently alwaysExpanded?
470+ */
471+ readonly property alias expanded: listContainer.expanded
472+
473+ /*!
474+ \qmlproperty real itemHeight
475+ Height of an individual list item.
476+ */
477+ readonly property alias itemHeight: list.itemHeight
478+
479+ /*!
480 Called when delegate is clicked.
481 */
482 signal delegateClicked(int index)
483
484+ /*!
485+ Called when the selector has finished expanding or collapsing.
486+ */
487+ signal expansionCompleted()
488+
489 showDivider: false
490
491 Column {
492@@ -138,25 +204,25 @@
493 readonly property url tick: __styleInstance.tick
494 readonly property color themeColour: Theme.palette.selected.fieldText
495 readonly property alias colourImage: itemSelector.colourImage
496- property bool isExpanded: expanded
497+ property bool expanded: alwaysExpanded || multiSelection
498
499 anchors {
500 left: parent.left
501 right: parent.right
502 }
503- state: itemSelector.expanded ? state = "expanded" : state = "collapsed"
504+ state: itemSelector.alwaysExpanded ? state = "alwaysExpanded" : state = "collapsed"
505 style: Theme.createStyleComponent("ListItemOptionSelectorStyle.qml", listContainer)
506
507 states: [ State {
508 name: "expanded"
509- when: listContainer.isExpanded
510+ when: listContainer.expanded
511 PropertyChanges {
512 target: listContainer
513 height: list.contentHeight < containerHeight ? list.contentHeight : containerHeight
514 }
515 }, State {
516 name: "collapsed"
517- when: !listContainer.isExpanded
518+ when: !listContainer.expanded
519 PropertyChanges {
520 target: listContainer
521 height: list.itemHeight
522@@ -172,13 +238,8 @@
523 }
524 ScriptAction {
525 script: {
526- //Nudge the list up if we're able to scroll.
527- if (listContainer.isExpanded && !list.atYBeginning && !list.atYBeginning && !list.atYEnd) {
528- list.contentY += list.itemHeight / 2
529- }
530- //On collapse if we've selected the same index nudge it back down again.
531- else if (!listContainer.isExpanded && list.previousIndex === list.currentIndex && !list.atYBeginning && !list.atYEnd) {
532- list.contentY -= list.itemHeight / 2
533+ if (listContainer.expanded) {
534+ expansionCompleted();
535 }
536 }
537 }
538@@ -191,14 +252,14 @@
539 objectName: "listView"
540
541 property int previousIndex: list.currentIndex
542- readonly property alias expanded: itemSelector.expanded
543+ readonly property alias alwaysExpanded: itemSelector.alwaysExpanded
544+ readonly property alias multiSelection: itemSelector.multiSelection
545 readonly property alias container: listContainer
546 property real itemHeight
547 signal delegateClicked(int index)
548
549 onDelegateClicked: itemSelector.delegateClicked(index);
550- boundsBehavior: Flickable.StopAtBounds
551- interactive: listContainer.height !== list.contentHeight && listContainer.isExpanded ? true : false
552+ interactive: listContainer.height !== list.contentHeight && listContainer.expanded ? true : false
553 clip: true
554 currentIndex: 0
555 model: itemSelector.model
556
557=== modified file 'modules/Ubuntu/Components/OptionSelector.qml'
558--- modules/Ubuntu/Components/OptionSelector.qml 2013-10-01 12:39:21 +0000
559+++ modules/Ubuntu/Components/OptionSelector.qml 2013-10-16 12:35:36 +0000
560@@ -20,45 +20,60 @@
561
562 /*!
563 \qmltype OptionSelector
564- \inqmlmodule Components.Components 0.1
565+ \inqmlmodule Ubuntu.Components 0.1
566 \ingroup ubuntu-components
567- \brief Component displaying a single selected value with and optional image and subtext when not expanded, where expanding
568- it opens a listing of all the possible values for selection with an additional option of always being expanded.
569+ \brief Component displaying either a single selected value or expanded multiple choice with an optional image and subtext when not expanded, when expanding it opens a
570+ listing of all the possible values for selection with an additional option of always being expanded. If multiple choice is selected the list is expanded automatically.
571
572 \b{This component is under heavy development.}
573
574 Examples:
575 \qml
576- import Components.Components 0.1
577+ import Ubuntu.Components 0.1
578 Column {
579- width: 250
580- OptionSelector {
581- text: "Standard"
582- model: ["Value 1", "Value 2", "Value 3", "Value 4"]
583- }
584- OptionSelector {
585- text: "Disabled"
586- model: ["Value 1", "Value 2", "Value 3", "Value 4"]
587- enabled: false
588- }
589- OptionSelector {
590- text: "Expanded"
591- model: ["Value 1", "Value 2", "Value 3", "Value 4"]
592- expanded: true
593- }
594- OptionSelector {
595- text: "Icon"
596- icon: Qt.resolvedUrl("icon.png")
597- values: ["Value 1", "Value 2", "Value 3", "Value 4"]
598- selectedIndex: 2
599- }
600+ spacing: units.gu(3)
601+
602+ OptionSelector {
603+ text: i18n.tr("Label")
604+ model: [i18n.tr("Value 1"),
605+ i18n.tr("Value 2"),
606+ i18n.tr("Value 3"),
607+ i18n.tr("Value 4")]
608+ }
609+
610+ OptionSelector {
611+ text: i18n.tr("Label")
612+ alwaysExpanded: true
613+ model: [i18n.tr("Value 1"),
614+ i18n.tr("Value 2"),
615+ i18n.tr("Value 3"),
616+ i18n.tr("Value 4")]
617+ }
618+
619+ OptionSelector {
620+ objectName: "optionselector_multipleselection"
621+ text: i18n.tr("Multiple Selection")
622+ alwaysExpanded: false
623+ multiSelection: true
624+ model: [i18n.tr("Value 1"),
625+ i18n.tr("Value 2"),
626+ i18n.tr("Value 3"),
627+ i18n.tr("Value 4")]
628+ }
629+
630 OptionSelector {
631 text: i18n.tr("Label")
632 model: customModel
633- expanded: true
634+ alwaysExpanded: true
635 colourImage: true
636- delegate: OptionSelectorDelegate { text: name; subText: description; icon: image }
637- }
638+ delegate: selectorDelegate
639+ }
640+
641+ Component {
642+ id: selectorDelegate
643+ OptionSelectorDelegate { text: name; subText: description; icon: image }
644+ }
645+
646 ListModel {
647 id: customModel
648 ListElement { name: "Name 1"; description: "Description 1"; image: "images.png" }
649@@ -66,6 +81,33 @@
650 ListElement { name: "Name 3"; description: "Description 3"; image: "images.png" }
651 ListElement { name: "Name 4"; description: "Description 4"; image: "images.png" }
652 }
653+
654+ OptionSelector {
655+ text: i18n.tr("Label")
656+ model: [i18n.tr("Value 1"),
657+ i18n.tr("Value 2"),
658+ i18n.tr("Value 3"),
659+ i18n.tr("Value 4"),
660+ i18n.tr("Value 5"),
661+ i18n.tr("Value 6"),
662+ i18n.tr("Value 7"),
663+ i18n.tr("Value 8")]
664+ containerHeight: itemHeight * 4
665+ }
666+
667+ OptionSelector {
668+ text: i18n.tr("Label")
669+ alwaysExpanded: true
670+ model: [i18n.tr("Value 1"),
671+ i18n.tr("Value 2"),
672+ i18n.tr("Value 3"),
673+ i18n.tr("Value 4"),
674+ i18n.tr("Value 5"),
675+ i18n.tr("Value 6"),
676+ i18n.tr("Value 7"),
677+ i18n.tr("Value 8")]
678+ containerHeight: itemHeight * 4
679+ }
680 }
681 \endqml
682 */
683@@ -84,7 +126,13 @@
684 \preliminary
685 Specifies whether the list is always expanded.
686 */
687- property bool expanded: false
688+ property bool alwaysExpanded: false
689+
690+ /*!
691+ \preliminary
692+ If the list is expanded, multiple choice selection is enabled.
693+ */
694+ property bool multiSelection: false
695
696 /*!
697 \preliminary
698@@ -111,11 +159,28 @@
699 property alias selectedIndex: list.currentIndex
700
701 /*!
702+ \qmlproperty bool expanded
703+ Is our list currently expanded?
704+ */
705+ readonly property alias expanded: listContainer.expanded
706+
707+ /*!
708+ \qmlproperty real itemHeight
709+ Height of an individual list item.
710+ */
711+ readonly property alias itemHeight: list.itemHeight
712+
713+ /*!
714 Called when delegate is clicked.
715 */
716 signal delegateClicked(int index)
717
718 /*!
719+ Called when the selector has finished expanding or collapsing.
720+ */
721+ signal expansionCompleted()
722+
723+ /*!
724 \internal
725 Trigger the action, passing the current index.
726 */
727@@ -136,6 +201,8 @@
728 }
729
730 Label {
731+ id : label
732+
733 text: optionSelector.text
734 visible: optionSelector.text !== "" ? true : false
735 }
736@@ -148,24 +215,24 @@
737 readonly property url tick: __styleInstance.tick
738 readonly property color themeColour: Theme.palette.selected.fieldText
739 readonly property alias colourImage: optionSelector.colourImage
740- property bool isExpanded: expanded
741+ property bool expanded: alwaysExpanded || multiSelection
742
743 anchors {
744 left: parent.left
745 right: parent.right
746 }
747- state: optionSelector.expanded ? state = "expanded" : state = "collapsed"
748+ state: optionSelector.alwaysExpanded ? state = "expanded" : state = "collapsed"
749 style: Theme.createStyleComponent("OptionSelectorStyle.qml", listContainer)
750 states: [ State {
751 name: "expanded"
752- when: listContainer.isExpanded
753+ when: listContainer.expanded
754 PropertyChanges {
755 target: listContainer
756 height: list.contentHeight < containerHeight ? list.contentHeight : containerHeight
757 }
758 }, State {
759 name: "collapsed"
760- when: !listContainer.isExpanded
761+ when: !listContainer.expanded
762 PropertyChanges {
763 target: listContainer
764 height: list.itemHeight
765@@ -181,13 +248,8 @@
766 }
767 ScriptAction {
768 script: {
769- //Nudge the list up if we're able to scroll.
770- if (listContainer.isExpanded && !list.atYBeginning && !list.atYBeginning && !list.atYEnd) {
771- list.contentY += list.itemHeight / 2
772- }
773- //On collapse if we've selected the same index nudge it back down again.
774- else if (!listContainer.isExpanded && list.previousIndex === list.currentIndex && !list.atYBeginning && !list.atYEnd) {
775- list.contentY -= list.itemHeight / 2
776+ if (listContainer.expanded) {
777+ expansionCompleted();
778 }
779 }
780 }
781@@ -199,14 +261,14 @@
782 id: list
783
784 property int previousIndex: -1
785- readonly property alias expanded: optionSelector.expanded
786+ readonly property alias alwaysExpanded: optionSelector.alwaysExpanded
787+ readonly property alias multiSelection: optionSelector.multiSelection
788 readonly property alias container: listContainer
789 property real itemHeight
790 signal delegateClicked(int index)
791
792 onDelegateClicked: optionSelector.delegateClicked(index);
793- boundsBehavior: Flickable.StopAtBounds
794- interactive: listContainer.height !== list.contentHeight && listContainer.isExpanded ? true : false
795+ interactive: listContainer.height !== list.contentHeight && listContainer.expanded ? true : false
796 clip: true
797 currentIndex: 0
798 model: optionSelector.model
799
800=== modified file 'modules/Ubuntu/Components/OptionSelectorDelegate.qml'
801--- modules/Ubuntu/Components/OptionSelectorDelegate.qml 2013-09-03 10:12:39 +0000
802+++ modules/Ubuntu/Components/OptionSelectorDelegate.qml 2013-10-16 12:35:36 +0000
803@@ -16,8 +16,8 @@
804
805 /*!
806 \qmltype OptionSelectorDelegate
807- \inqmlmodule Toolkit.Toolkit 0.1
808- \ingroup ubuntu-Toolkit
809+ \inqmlmodule Ubuntu.Components 0.1
810+ \ingroup ubuntu-components
811 \brief OptionSelector delegate which can display text, subtext and an image from a custom model.
812
813 \b{This component is under heavy development.}
814@@ -107,24 +107,27 @@
815 gl_FragColor = colour * sourceColour.a * qt_Opacity;
816 }"
817
818- width: parent.width + units.gu(2)
819 showDivider: index !== listView.count - 1 ? 1 : 0
820 highlightWhenPressed: false
821 selected: ListView.isCurrentItem
822 anchors {
823 left: parent.left
824- leftMargin: units.gu(-1)
825+ right: parent.right
826 }
827 onClicked: {
828- if (listView.container.isExpanded) {
829+ if (listView.container.expanded) {
830 listView.delegateClicked(index);
831
832- listView.previousIndex = listView.currentIndex;
833- listView.currentIndex = index;
834+ if (!listView.multiSelection) {
835+ listView.previousIndex = listView.currentIndex;
836+ listView.currentIndex = index;
837+ } else {
838+ selected = !selected;
839+ }
840 }
841
842- if (!listView.expanded) {
843- listView.container.isExpanded = !listView.container.isExpanded;
844+ if (!listView.alwaysExpanded && !listView.multiSelection) {
845+ listView.container.expanded = !listView.container.expanded;
846 }
847 }
848
849@@ -165,14 +168,14 @@
850 resources: [
851 Connections {
852 target: listView.container
853- onIsExpandedChanged: {
854+ onExpandedChanged: {
855 optionExpansion.stop();
856 imageExpansion.stop();
857 optionCollapse.stop();
858 selectedImageCollapse.stop();
859 deselectedImageCollapse.stop();
860
861- if (listView.container.isExpanded === true) {
862+ if (listView.container.expanded === true) {
863 if (!option.selected) {
864 optionExpansion.start();
865
866@@ -294,7 +297,7 @@
867
868 anchors {
869 left: parent.left
870- leftMargin: units.gu(3)
871+ leftMargin: units.gu(2)
872 verticalCenter: parent.verticalCenter
873 }
874
875@@ -338,17 +341,17 @@
876
877 width: units.gu(2)
878 height: units.gu(2)
879- source: listView.expanded ? listView.container.tick : listView.container.chevron
880+ source: listView.alwaysExpanded || listView.multiSelection ? listView.container.tick : listView.container.chevron
881 opacity: option.selected ? 1.0 : 0.0
882 anchors {
883 right: parent.right
884- rightMargin: units.gu(3)
885+ rightMargin: units.gu(2)
886 verticalCenter: parent.verticalCenter
887 }
888
889 //Our behaviour is only enabled for our expanded list due to flickering bugs in relation to all this other animations running on the expanding version.
890 Behavior on opacity {
891- enabled: listView.expanded
892+ enabled: listView.alwaysExpanded
893
894 Toolkit.UbuntuNumberAnimation {
895 properties: "opacity"
896
897=== modified file 'tests/unit_x11/tst_components/tst_listitems_itemselector.qml'
898--- tests/unit_x11/tst_components/tst_listitems_itemselector.qml 2013-09-03 10:12:39 +0000
899+++ tests/unit_x11/tst_components/tst_listitems_itemselector.qml 2013-10-16 12:35:36 +0000
900@@ -35,7 +35,6 @@
901 text: "TEST"
902 delegate: selectorDelegate
903 model: customModel
904- expanded: true
905 }
906
907 OptionSelectorDelegate {
908@@ -67,12 +66,6 @@
909 ListElement { name: "Name 4"; description: "Description 4"; image: "../../resources/optionselector/test.png" }
910 }
911
912- SignalSpy {
913- id: clickedSignal
914- target: selector
915- signalName: "delegateClicked"
916- }
917-
918 UbuntuTestCase {
919 name: "ItemSelectorAPI"
920 when: windowShown
921@@ -80,12 +73,12 @@
922 function test_expanded() {
923 var listContainer = findChild(selector, "listContainer");
924
925- selector.expanded = false;
926- compare(listContainer.isExpanded, false, "isExpanded should be true if list is an expanded one");
927+ selector.alwaysExpanded = false;
928+ compare(listContainer.expanded, false, "expanded should be true if list is an expanded one");
929 compare(listContainer.state, "collapsed", "state should be collapsed");
930
931- selector.expanded = true;
932- compare(listContainer.isExpanded, true, "isExpanded should be false if list is an expanded one");
933+ selector.alwaysExpanded = true;
934+ compare(listContainer.expanded, true, "expanded should be false if list is an expanded one");
935 compare(listContainer.state, "expanded", "state should be expanded");
936 }
937
938@@ -115,12 +108,5 @@
939 var image = findChild(testDelegate, "icon");
940 compare(image.height, testDelegate.height);
941 }
942-
943- function test_signal() {
944- mouseMove(selector, 100, 100);
945- mouseClick(selector, 100, 100, Qt.LeftButton);
946- wait(100)
947- compare(clickedSignal.count, 1, "Clicked not emitted.");
948- }
949 }
950 }
951
952=== modified file 'tests/unit_x11/tst_components/tst_optionselector.qml'
953--- tests/unit_x11/tst_components/tst_optionselector.qml 2013-10-01 12:39:21 +0000
954+++ tests/unit_x11/tst_components/tst_optionselector.qml 2013-10-16 12:35:36 +0000
955@@ -35,7 +35,7 @@
956 text: "TEST"
957 delegate: selectorDelegate
958 model: customModel
959- expanded: true
960+ alwaysExpanded: true
961
962 action: {
963 enabled: true
964@@ -81,9 +81,9 @@
965 }
966
967 SignalSpy {
968- id: triggeredSignal
969+ id: expansionSignal
970 target: selector
971- signalName: "triggered"
972+ signalName: "expansionCompleted"
973 }
974
975 UbuntuTestCase {
976@@ -93,12 +93,12 @@
977 function test_expanded() {
978 var listContainer = findChild(selector, "listContainer");
979
980- selector.expanded = false;
981- compare(listContainer.isExpanded, false, "isExpanded should be true if list is an expanded one");
982+ selector.alwaysExpanded = false;
983+ compare(listContainer.expanded, false, "expanded should be true if list is an expanded one");
984 compare(listContainer.state, "collapsed", "state should be collapsed");
985
986- selector.expanded = true;
987- compare(listContainer.isExpanded, true, "isExpanded should be false if list is an expanded one");
988+ selector.alwaysExpanded = true;
989+ compare(listContainer.expanded, true, "expanded should be false if list is an expanded one");
990 compare(listContainer.state, "expanded", "state should be expanded");
991 }
992
993@@ -130,16 +130,9 @@
994 }
995
996 function test_signal() {
997- mouseMove(selector, 100, 100);
998- mouseClick(selector, 100, 100, Qt.LeftButton);
999- wait(100)
1000- compare(clickedSignal.count, 1, "Clicked not emitted.");
1001- }
1002-
1003- function test_triggered() {
1004- mouseMove(selector, 100, 100);
1005- mouseClick(selector, 100, 100, Qt.LeftButton);
1006- triggeredSignal.wait()
1007+ mouseClick(selector, 100, 100, Qt.LeftButton);
1008+ tryCompare(clickedSignal, "count", 1);
1009+ tryCompare(expansionSignal, "count", 1);
1010 }
1011 }
1012 }

Subscribers

People subscribed via source and target branches

to status/vote changes: