Merge lp:~tpeeters/ubuntu-ui-toolkit/100-SectionBar into lp:ubuntu-ui-toolkit/staging

Proposed by Tim Peeters
Status: Merged
Approved by: Zsombor Egri
Approved revision: 1564
Merged at revision: 1535
Proposed branch: lp:~tpeeters/ubuntu-ui-toolkit/100-SectionBar
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 835 lines (+732/-0)
12 files modified
components.api (+4/-0)
examples/ubuntu-ui-toolkit-gallery/Sections.qml (+47/-0)
examples/ubuntu-ui-toolkit-gallery/WidgetsModel.qml (+5/-0)
modules/Ubuntu/Components/1.3/Sections.qml (+101/-0)
modules/Ubuntu/Components/Themes/Ambiance/1.3/SectionsStyle.qml (+119/-0)
modules/Ubuntu/Components/qmldir (+1/-0)
tests/autopilot/ubuntuuitoolkit/__init__.py (+2/-0)
tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/__init__.py (+2/-0)
tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_sections.py (+49/-0)
tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_sections.SectionsTestCase.qml (+42/-0)
tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_sections.py (+51/-0)
tests/unit_x11/tst_components/tst_sections.qml (+309/-0)
To merge this branch: bzr merge lp:~tpeeters/ubuntu-ui-toolkit/100-SectionBar
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Zsombor Egri Approve
Tim Peeters Needs Fixing
Review via email: mp+260502@code.launchpad.net

Commit message

Introduce the new Sections component.

Description of the change

Introduce the new Sections component.

This component will be used (in a following MR) in the new header to replace the sections selector in the current header divider. Sections will also be available as a separate component for convergence apps that need to place the Sections outside of the single standard header.

To post a comment you must log in.
1534. By Tim Peeters

docs

1535. By Tim Peeters

docs

1536. By Tim Peeters

spacing

1537. By Tim Peeters

spacing

1538. By Tim Peeters

update components.api

1539. By Tim Peeters

docs

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

remove empty functions from tst_sections

1541. By Tim Peeters

sections

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Zsombor Egri (zsombi) wrote :

Comments inline. I'm not good with the API.

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

38 +/*!
39 + \qmltype Sections
40 + \inqmlmodule Ubuntu.Components 1.3
41 + \ingroup ubuntu
42 + \since Ubuntu.Components 1.3
43 + \brief Display a list of sections that the user can select.
44 + */
> Zsombor Egri (zsombi) wrote 7 hours ago:
> Shouldn't you have more to say here?

Yes I can extend it a bit.

45 +StyledItem {
46 + id: sections
47 + style: theme.createStyleComponent("SectionsStyle.qml", sections)
> Zsombor Egri (zsombi) wrote 7 hours ago:
> This is wrong, once the styleName will get into staging, this will be broken. Please merge with
> styleName MR and fix this. With a small luck, we will get it soon if LP gets it.

Ok, will do. I thought I would land my MR before you land yours. ;)

48 +
49 + /*!
50 + List of strings that represent section names. Example:
51 + \qml
> Zsombor Egri (zsombi) wrote 7 hours ago:
> Hmm.... I was thinking shouldn't this be rather a list of actions? Then you don't need the
> model and the selectedIndex properties separated. The Action would drive the visual (you
> would also be able to show icons if design changes his mind - with the current setup an API
> change would be needed) and the trigger would tell which Action is selected. I feel we have
> to discuss more about this.

Ok. After our discussion, I'll make this a list of actions and keep the selectedIndex as well. Changing the selectedIndex will trigger the appropriate Action.

137 + Row {
138 + id: sectionsRow
> Zsombor Egri (zsombi) wrote 7 hours ago:
> Aren't the sections proportionally filling the space? What if a text exceeds the
> space available?

No. In the new designs, the sections are always aligned left and don't fill the space.
If the text exceeds the available space, the section list will be scrollable. I will add the scrolling in a following MR.

150 + AbstractButton {
151 + id: sectionButton
> Zsombor Egri (zsombi) wrote 7 hours ago:
> I feel like this should be rather that FlatButton instead...

We don't have a FlatButton yet. I think the AbstractButton is fine here, since the visuals are quite specific for the section selector.

399 + def test_click_unexisting_section_button(self):
400 + error = self.assertRaises(
Zsombor Egri (zsombi) wrote 7 hours ago:
> Why do you need this? Can't you cover this in unit test?

It does not test component functionality, only verifies that the CPO works as expected.

1542. By Tim Peeters

sync staging

1543. By Tim Peeters

use styleName in Sections

1544. By Tim Peeters

extend docs a bit

1545. By Tim Peeters

use Actions instead of strings for the model

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

changing selectedIndex triggers Action.

1547. By Tim Peeters

update components.api

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

sync staging

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Zsombor Egri (zsombi) wrote :

/tmp/buildd/ubuntu-ui-toolkit-1.3.1517+15.10.20150523bzr1548pkg0vivid571/modules/Ubuntu/Components/1.3/Sections.qml:36: warning: Unknown command '\selectedIndex'
/tmp/buildd/ubuntu-ui-toolkit-1.3.1517+15.10.20150523bzr1548pkg0vivid571/modules/Ubuntu/Components/1.3/Sections.qml:64: warning: Can't link to 'model'
Makefile:289: recipe for target 'docs' failed

review: Needs Fixing
1549. By Tim Peeters

fix docs

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 :

Ready for another review.

Note that Page.head.sections.model is currently a list of strings, see https://developer.ubuntu.com/api/apps/qml/sdk-14.10/Ubuntu.Components.PageHeadSections/

Do we want to break that API and replace it with a list of Actions?

Revision history for this message
Zsombor Egri (zsombi) wrote :

> Ready for another review.
>
> Note that Page.head.sections.model is currently a list of strings, see https:/
> /developer.ubuntu.com/api/apps/qml/sdk-14.10/Ubuntu.Components.PageHeadSection
> s/
>
> Do we want to break that API and replace it with a list of Actions?

Do we break the API if we say that it can be either strings - in which case we have more work - or it also can be a list of Actions? I think not.

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

Supporting both Actions and strings in PageHeadSections is problematic. Then in order to feed it to the Sections we need to convert the list of strings into a list of Actions. I don't see a simple way to do that in QML.

We can support strings and actions in Sections and PageHeadSections, and then inside Sections I'll have to support both in the Repeater. That is not difficult but I'd say it is a bit messy.

1550. By Tim Peeters

unit tests for list of strings as model

1551. By Tim Peeters

rename actions to model and support a list of strings as model

1552. By Tim Peeters

improve test app

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

split up unit tests

1554. By Tim Peeters

update components.api

1555. By Tim Peeters

merge staging

1556. By Tim Peeters

update docs

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

Updated and ready for another review. The 'actions' property was renamed to 'model' and now accepts either a list of Actions or a list of strings. Docs and unit tests were also updated.

1557. By Tim Peeters

fix components.api

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: Approve (continuous-integration)
Revision history for this message
Tim Peeters (tpeeters) wrote :

[10:55:46] <nerochiaro> timp: i am trying to use the Sections from your branch but when i follow the example and set actions to a list, like this "actions: [ Action { text: "A" } ]" QML gives me this error: "Cannot assign multiple values to a singular property"... any ideas why ?
[10:56:11] <nerochiaro> timp: if I create a list<Action> property and then assign it to the actions it works ok

review: Needs Fixing
1558. By Tim Peeters

fix

1559. By Tim Peeters

document actions/model

1560. By Tim Peeters

add Sections to the component gallery

1561. By Tim Peeters

clean tst_sections.qml

1562. By Tim Peeters

update components.api

1563. By Tim Peeters

update docs

1564. By Tim Peeters

fix docs

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
Zsombor Egri (zsombi) wrote :

Good to go.

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 'components.api'
2--- components.api 2015-06-02 12:37:41 +0000
3+++ components.api 2015-06-17 12:24:49 +0000
4@@ -793,6 +793,10 @@
5 property int align
6 property Flickable flickableItem
7 Ubuntu.Components.ScrollbarUtils 0.1 1.0
8+Ubuntu.Components.Sections 1.3: StyledItem
9+ readonly property Action actions
10+ property var model
11+ property int selectedIndex
12 Ubuntu.Components.ServiceProperties 1.1: QtObject
13 property string adaptorInterface
14 readonly property string error
15
16=== added file 'examples/ubuntu-ui-toolkit-gallery/Sections.qml'
17--- examples/ubuntu-ui-toolkit-gallery/Sections.qml 1970-01-01 00:00:00 +0000
18+++ examples/ubuntu-ui-toolkit-gallery/Sections.qml 2015-06-17 12:24:49 +0000
19@@ -0,0 +1,47 @@
20+/*
21+ * Copyright 2015 Canonical Ltd.
22+ *
23+ * This program is free software; you can redistribute it and/or modify
24+ * it under the terms of the GNU Lesser General Public License as published by
25+ * the Free Software Foundation; version 3.
26+ *
27+ * This program is distributed in the hope that it will be useful,
28+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
29+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30+ * GNU Lesser General Public License for more details.
31+ *
32+ * You should have received a copy of the GNU Lesser General Public License
33+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
34+ */
35+
36+import QtQuick 2.4
37+import Ubuntu.Components 1.3
38+
39+Template {
40+ objectName: "sectionsTemplate"
41+
42+ TemplateSection {
43+ title: "Sections"
44+ className: "Sections"
45+
46+ TemplateRow {
47+ title: i18n.tr("Enabled")
48+
49+ Sections {
50+ actions: [
51+ Action { text: "one" },
52+ Action { text: "two" },
53+ Action { text: "three" }
54+ ]
55+ }
56+ }
57+ TemplateRow {
58+ title: i18n.tr("Disabled")
59+
60+ Sections {
61+ model: ["one", "two", "three"]
62+ enabled: false
63+ }
64+ }
65+ }
66+}
67
68=== modified file 'examples/ubuntu-ui-toolkit-gallery/WidgetsModel.qml'
69--- examples/ubuntu-ui-toolkit-gallery/WidgetsModel.qml 2015-03-23 16:24:43 +0000
70+++ examples/ubuntu-ui-toolkit-gallery/WidgetsModel.qml 2015-06-17 12:24:49 +0000
71@@ -72,6 +72,11 @@
72 source: "ProgressBars.qml"
73 }
74 ListElement {
75+ objectName: "sectionsElement"
76+ label: "Sections"
77+ source: "Sections.qml"
78+ }
79+ ListElement {
80 objectName: "ubuntuShapesElement"
81 label: "Ubuntu Shape"
82 source: "UbuntuShape.qml"
83
84=== added file 'modules/Ubuntu/Components/1.3/Sections.qml'
85--- modules/Ubuntu/Components/1.3/Sections.qml 1970-01-01 00:00:00 +0000
86+++ modules/Ubuntu/Components/1.3/Sections.qml 2015-06-17 12:24:49 +0000
87@@ -0,0 +1,101 @@
88+/*
89+ * Copyright 2015 Canonical Ltd.
90+ *
91+ * This program is free software; you can redistribute it and/or modify
92+ * it under the terms of the GNU Lesser General Public License as published by
93+ * the Free Software Foundation; version 3.
94+ *
95+ * This program is distributed in the hope that it will be useful,
96+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
97+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
98+ * GNU Lesser General Public License for more details.
99+ *
100+ * You should have received a copy of the GNU Lesser General Public License
101+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
102+ */
103+
104+import QtQuick 2.4
105+import Ubuntu.Components 1.3
106+
107+/*!
108+ \qmltype Sections
109+ \inqmlmodule Ubuntu.Components 1.3
110+ \ingroup ubuntu
111+ \since Ubuntu.Components 1.3
112+ \brief Display a list of sections that the user can select. By tapping
113+ on a section name the \l selectedIndex will be updated, and the
114+ associated \l Action is triggered.
115+ */
116+StyledItem {
117+ id: sections
118+ styleName: "SectionsStyle"
119+
120+ /*!
121+ List of actions that represent the sections.
122+ The text of each action is displayed as the section name and clicking
123+ a section will update the \l selectedIndex.
124+
125+ When \l selectedIndex is changed (by user interaction or by setting
126+ the value), actions[selectedIndex] will be triggered.
127+
128+ Example:
129+ \qml
130+ Sections {
131+ actions: [
132+ Action {
133+ text: "first"
134+ onTriggered: print("one")
135+ },
136+ Action {
137+ text: "second"
138+ onTriggered: print("two")
139+ },
140+ Action {
141+ text: "third"
142+ onTriggered: print("three")
143+ }
144+ ]
145+ }
146+ \endqml
147+ It is strongly recommended to limit the number of sections to two or three.
148+ The actions are used as the model for the Sections by default.
149+ If no trigger functions need to be specified, \l model may be used directly
150+ without setting the actions property. If both \l actions and \l model are set,
151+ model overrides the actions.
152+ */
153+ property list<Action> actions
154+
155+ /*!
156+ The input model for the sections. By default model takes the \l actions
157+ as input, but if no trigger functions need to be specified, it can be
158+ simplified to a list of strings naming the sections:
159+ \qml
160+ Sections {
161+ model: [ "one", "two", "three" ]
162+ onSelectedIndexChanged: {
163+ print("Selected section " + model[selectedIndex]);
164+ }
165+ }
166+ \endqml
167+ */
168+ property var model: actions
169+ onModelChanged: {
170+ if (model && model.length > 3) {
171+ // FIXME: Make the Sections scrollable for more than 3 sections.
172+ console.warn("It is not YET recommended or supported to use more than three sections.");
173+ }
174+ }
175+
176+ /*!
177+ The index of the currently selected section in \l model.
178+ */
179+ property int selectedIndex: model ? 0 : -1
180+
181+ onSelectedIndexChanged: {
182+ if ((selectedIndex >= 0) && (selectedIndex < model.length)) {
183+ if (model[selectedIndex].hasOwnProperty("trigger")) {
184+ model[selectedIndex].trigger();
185+ }
186+ }
187+ }
188+}
189
190=== added file 'modules/Ubuntu/Components/Themes/Ambiance/1.3/SectionsStyle.qml'
191--- modules/Ubuntu/Components/Themes/Ambiance/1.3/SectionsStyle.qml 1970-01-01 00:00:00 +0000
192+++ modules/Ubuntu/Components/Themes/Ambiance/1.3/SectionsStyle.qml 2015-06-17 12:24:49 +0000
193@@ -0,0 +1,119 @@
194+/*
195+ * Copyright 2015 Canonical Ltd.
196+ *
197+ * This program is free software; you can redistribute it and/or modify
198+ * it under the terms of the GNU Lesser General Public License as published by
199+ * the Free Software Foundation; version 3.
200+ *
201+ * This program is distributed in the hope that it will be useful,
202+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
203+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
204+ * GNU Lesser General Public License for more details.
205+ *
206+ * You should have received a copy of the GNU Lesser General Public License
207+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
208+ */
209+import QtQuick 2.4
210+import Ubuntu.Components 1.3
211+
212+Item {
213+ id: sectionsStyle
214+
215+ implicitWidth: sectionsRow.width
216+ implicitHeight: units.gu(4)
217+
218+ enabled: styledItem.enabled
219+ opacity: enabled ? 1.0 : 0.5
220+
221+ /*!
222+ The foreground color of unselected sections.
223+ */
224+ property color sectionColor: theme.palette.selected.backgroundText
225+
226+ /*!
227+ The foreground color of the selected section.
228+ */
229+ property color selectedSectionColor: UbuntuColors.orange
230+
231+ /*!
232+ The background color for the pressed section button.
233+ */
234+ property color pressedBackgroundColor: theme.palette.selected.background
235+
236+ /*!
237+ The font size for the text in the buttons.
238+ */
239+ property string fontSize: "small"
240+
241+ /*!
242+ The spacing on the left and right sides of the label
243+ inside a section button.
244+ */
245+ property real horizontalLabelSpacing: units.gu(2)
246+
247+ /*!
248+ The height of the bar underlining the sections.
249+ */
250+ property real underlineHeight: units.dp(2)
251+
252+ Row {
253+ id: sectionsRow
254+ anchors {
255+ top: parent.top
256+ bottom: parent.bottom
257+ horizontalCenter: parent.horizontalCenter
258+ }
259+ width: childrenRect.width
260+
261+ Repeater {
262+ id: sectionsRepeater
263+ model: styledItem.model
264+ objectName: "sections_repeater"
265+ AbstractButton {
266+ id: sectionButton
267+ anchors {
268+ top: parent ? parent.top : undefined
269+ bottom: parent ? parent.bottom : undefined
270+ }
271+ objectName: "section_button_" + index
272+ width: label.width + 2 * sectionsStyle.horizontalLabelSpacing
273+ height: sectionsRow.height
274+ property bool selected: index === styledItem.selectedIndex
275+ onClicked: styledItem.selectedIndex = index
276+
277+ // Background pressed highlight
278+ Rectangle {
279+ visible: parent.pressed
280+ anchors.fill: parent
281+ color: sectionsStyle.pressedBackgroundColor
282+ }
283+
284+ // Section title
285+ Label {
286+ id: label
287+ objectName: "section_button_label_" + index
288+ // modelData may be either a string, or an Action
289+ text: modelData.hasOwnProperty("text") ? modelData.text : modelData
290+ fontSize: sectionsStyle.fontSize
291+ anchors.centerIn: parent
292+ color: sectionButton.selected ?
293+ sectionsStyle.selectedSectionColor :
294+ sectionsStyle.sectionColor
295+ }
296+
297+ // Section title underline
298+ Rectangle {
299+ anchors {
300+ bottom: parent.bottom
301+ left: parent.left
302+ right: parent.right
303+ }
304+ height: sectionsStyle.underlineHeight
305+ color: sectionButton.selected ?
306+ sectionsStyle.selectedSectionColor :
307+ sectionsStyle.sectionColor
308+ }
309+ }
310+ }
311+ }
312+}
313
314=== modified file 'modules/Ubuntu/Components/qmldir'
315--- modules/Ubuntu/Components/qmldir 2015-05-12 13:41:39 +0000
316+++ modules/Ubuntu/Components/qmldir 2015-06-17 12:24:49 +0000
317@@ -133,6 +133,7 @@
318 PageHeadConfiguration 1.3 1.3/PageHeadConfiguration.qml
319 PageHeadSections 1.3 1.3/PageHeadSections.qml
320 PageHeadState 1.3 1.3/PageHeadState.qml
321+Sections 1.3 1.3/Sections.qml
322 Header 1.3 1.3/Header.qml
323 CrossFadeImage 1.3 1.3/CrossFadeImage.qml
324 OrientationHelper 1.3 1.3/OrientationHelper.qml
325
326=== modified file 'tests/autopilot/ubuntuuitoolkit/__init__.py'
327--- tests/autopilot/ubuntuuitoolkit/__init__.py 2015-05-14 20:08:45 +0000
328+++ tests/autopilot/ubuntuuitoolkit/__init__.py 2015-06-17 12:24:49 +0000
329@@ -38,6 +38,7 @@
330 'QQuickFlickable',
331 'QQuickGridView',
332 'QQuickListView',
333+ 'Sections',
334 'TabBar',
335 'Tabs',
336 'tests',
337@@ -76,6 +77,7 @@
338 QQuickFlickable,
339 QQuickGridView,
340 QQuickListView,
341+ Sections,
342 TabBar,
343 Tabs,
344 TextArea,
345
346=== modified file 'tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/__init__.py'
347--- tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/__init__.py 2015-05-14 20:08:45 +0000
348+++ tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/__init__.py 2015-06-17 12:24:49 +0000
349@@ -35,6 +35,7 @@
350 'QQuickFlickable',
351 'QQuickGridView',
352 'QQuickListView',
353+ 'Sections',
354 'TabBar',
355 'Tabs',
356 'TextArea',
357@@ -46,6 +47,7 @@
358 ]
359
360 from ubuntuuitoolkit._custom_proxy_objects._actionbar import ActionBar
361+from ubuntuuitoolkit._custom_proxy_objects._sections import Sections
362 from ubuntuuitoolkit._custom_proxy_objects._checkbox import CheckBox
363 from ubuntuuitoolkit._custom_proxy_objects._common import (
364 check_autopilot_version,
365
366=== added file 'tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_sections.py'
367--- tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_sections.py 1970-01-01 00:00:00 +0000
368+++ tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_sections.py 2015-06-17 12:24:49 +0000
369@@ -0,0 +1,49 @@
370+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
371+#
372+# Copyright (C) 2015 Canonical Ltd.
373+#
374+# This program is free software; you can redistribute it and/or modify
375+# it under the terms of the GNU Lesser General Public License as published by
376+# the Free Software Foundation; version 3.
377+#
378+# This program is distributed in the hope that it will be useful,
379+# but WITHOUT ANY WARRANTY; without even the implied warranty of
380+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
381+# GNU Lesser General Public License for more details.
382+#
383+# You should have received a copy of the GNU Lesser General Public License
384+# along with this program. If not, see <http://www.gnu.org/licenses/>.
385+
386+import logging
387+
388+from autopilot import logging as autopilot_logging
389+from autopilot.introspection import dbus
390+from ubuntuuitoolkit._custom_proxy_objects import _common
391+
392+
393+logger = logging.getLogger(__name__)
394+
395+
396+class Sections(_common.UbuntuUIToolkitCustomProxyObjectBase):
397+ """Sections Autopilot custom proxy object."""
398+
399+ def _get_section_button(self, section_index):
400+ try:
401+ object_name = "section_button_" + str(section_index)
402+ button = self.select_single(objectName=object_name)
403+ except dbus.StateNotFoundError:
404+ raise _common.ToolkitException(
405+ 'Button not found in Sections.')
406+
407+ return button
408+
409+ @autopilot_logging.log_action(logger.info)
410+ def click_section_button(self, section_index):
411+ """Click a section button of the Sections.
412+
413+ :parameter section_index: The index of the section to click.
414+ :raise ToolkitException: If there is no section button with that index.
415+
416+ """
417+ button = self._get_section_button(section_index)
418+ self.pointing_device.click_object(button)
419
420=== added file 'tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_sections.SectionsTestCase.qml'
421--- tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_sections.SectionsTestCase.qml 1970-01-01 00:00:00 +0000
422+++ tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_sections.SectionsTestCase.qml 2015-06-17 12:24:49 +0000
423@@ -0,0 +1,42 @@
424+/*
425+ * Copyright 2015 Canonical Ltd.
426+ *
427+ * This program is free software; you can redistribute it and/or modify
428+ * it under the terms of the GNU Lesser General Public License as published by
429+ * the Free Software Foundation; version 3.
430+ *
431+ * This program is distributed in the hope that it will be useful,
432+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
433+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
434+ * GNU Lesser General Public License for more details.
435+ *
436+ * You should have received a copy of the GNU Lesser General Public License
437+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
438+ */
439+
440+import QtQuick 2.4
441+import Ubuntu.Components 1.3
442+
443+MainView {
444+ width: units.gu(48)
445+ height: units.gu(60)
446+ objectName: "mainView"
447+ Page {
448+ title: "Sections test"
449+ Label {
450+ id: label
451+ objectName: "label"
452+ anchors {
453+ top: parent.top
454+ horizontalCenter: parent.horizontalCenter
455+ }
456+ text: "Section " + sections.selectedIndex + " is selected."
457+ }
458+ Sections {
459+ id: sections
460+ objectName: "sections"
461+ anchors.centerIn: parent
462+ model: [ "first", "second", "third" ]
463+ }
464+ }
465+}
466
467=== added file 'tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_sections.py'
468--- tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_sections.py 1970-01-01 00:00:00 +0000
469+++ tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_sections.py 2015-06-17 12:24:49 +0000
470@@ -0,0 +1,51 @@
471+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
472+#
473+# Copyright (C) 2015 Canonical Ltd.
474+#
475+# This program is free software; you can redistribute it and/or modify
476+# it under the terms of the GNU Lesser General Public License as published by
477+# the Free Software Foundation; version 3.
478+#
479+# This program is distributed in the hope that it will be useful,
480+# but WITHOUT ANY WARRANTY; without even the implied warranty of
481+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
482+# GNU Lesser General Public License for more details.
483+#
484+# You should have received a copy of the GNU Lesser General Public License
485+# along with this program. If not, see <http://www.gnu.org/licenses/>.
486+
487+import os
488+import ubuntuuitoolkit
489+from ubuntuuitoolkit import tests
490+
491+
492+class SectionsTestCase(tests.QMLFileAppTestCase):
493+
494+ path = os.path.abspath(__file__)
495+ dir_path = os.path.dirname(path)
496+ test_qml_file_path = os.path.join(
497+ dir_path, 'test_sections.SectionsTestCase.qml')
498+
499+ def setUp(self):
500+ super().setUp()
501+ self.sections = self.app.select_single(
502+ 'Sections', objectName='sections')
503+ self.label = self.app.select_single(
504+ 'Label', objectName='label')
505+ self.assertEqual(self.label.text, 'Section 0 is selected.')
506+
507+ def test_custom_proxy_object(self):
508+ self.assertIsInstance(self.sections, ubuntuuitoolkit.Sections)
509+ self.assertTrue(self.sections.visible)
510+
511+ def test_click_section_button(self):
512+ self.sections.click_section_button(2)
513+ self.assertEqual(self.label.text, 'Section 2 is selected.')
514+
515+ def test_click_unexisting_section_button(self):
516+ error = self.assertRaises(
517+ ubuntuuitoolkit.ToolkitException,
518+ self.sections.click_section_button, 3)
519+ self.assertEqual(
520+ str(error),
521+ 'Button not found in Sections.')
522
523=== added file 'tests/unit_x11/tst_components/tst_sections.qml'
524--- tests/unit_x11/tst_components/tst_sections.qml 1970-01-01 00:00:00 +0000
525+++ tests/unit_x11/tst_components/tst_sections.qml 2015-06-17 12:24:49 +0000
526@@ -0,0 +1,309 @@
527+/*
528+ * Copyright 2015 Canonical Ltd.
529+ *
530+ * This program is free software; you can redistribute it and/or modify
531+ * it under the terms of the GNU Lesser General Public License as published by
532+ * the Free Software Foundation; version 3.
533+ *
534+ * This program is distributed in the hope that it will be useful,
535+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
536+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
537+ * GNU Lesser General Public License for more details.
538+ *
539+ * You should have received a copy of the GNU Lesser General Public License
540+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
541+ */
542+
543+import QtQuick 2.4
544+import Ubuntu.Test 1.0
545+import Ubuntu.Components 1.3
546+
547+Rectangle {
548+ id: root
549+ width: 400
550+ height: 600
551+ color: "white"
552+
553+ property list<Action> actionList: [
554+ Action {
555+ text: "first";
556+ onTriggered: label.text = "First action triggered.";
557+ },
558+ Action {
559+ text: "second";
560+ onTriggered: label.text = "Second action triggered.";
561+ },
562+ Action {
563+ text: "third";
564+ onTriggered: label.text = "Third action triggered.";
565+ }
566+ ]
567+
568+ property var stringList: [
569+ "string one", "string two", "string three"
570+ ]
571+
572+ Column {
573+ id: column
574+ anchors {
575+ left: parent.left
576+ right: parent.right
577+ top: parent.top
578+ margins: units.gu(2)
579+ }
580+ spacing: units.gu(2)
581+
582+ Label {
583+ anchors.horizontalCenter: parent.horizontalCenter
584+ text: "Sections with actions"
585+ }
586+ Label {
587+ anchors.left: parent.left
588+ text: "actions in-line:"
589+ fontSize: small
590+ }
591+ Sections {
592+ // Not used in the tests below, but added here to
593+ // verify that the Actions can be defined directly
594+ // inside the list of actions.
595+ actions: [
596+ Action { text: "1" },
597+ Action { text: "2" }
598+ ]
599+ }
600+ Label {
601+ anchors.left: parent.left
602+ text: "enabled:"
603+ fontSize: "small"
604+ }
605+ Sections {
606+ id: enabledSections
607+ actions: root.actionList
608+ }
609+ Label {
610+ text: "disabled:"
611+ fontSize: "small"
612+ }
613+ Sections {
614+ id: disabledSections
615+ actions: root.actionList
616+ enabled: false
617+ }
618+ Rectangle {
619+ anchors {
620+ left: parent.left
621+ right: parent.right
622+ margins: units.gu(2)
623+ }
624+ color: UbuntuColors.blue
625+ height: units.gu(10)
626+ Label {
627+ id: label
628+ anchors.centerIn: parent
629+ text: "No action triggered."
630+ color: "white"
631+ }
632+ }
633+ Label {
634+ anchors.horizontalCenter: parent.horizontalCenter
635+ text: "Sections with strings"
636+ }
637+ Label {
638+ anchors.left: parent.left
639+ text: "enabled:"
640+ fontSize: "small"
641+ }
642+ Sections {
643+ id: enabledStringSections
644+ model: root.stringList
645+ }
646+ Label {
647+ anchors.left: parent.left
648+ text: "disabled:"
649+ fontSize: "small"
650+ }
651+ Sections {
652+ id: disabledStringSections
653+ model: root.stringList
654+ enabled: false
655+ }
656+ }
657+
658+ UbuntuTestCase {
659+ id: testCase
660+ name: "SectionsApi"
661+ when: windowShown
662+
663+ function initTestCase() {
664+ compare(label.text, "No action triggered.", "An action was triggered initially.");
665+ }
666+
667+ function cleanup() {
668+ enabledSections.selectedIndex = 0;
669+ disabledSections.selectedIndex = 0;
670+ enabledStringSections.selectedIndex = 0;
671+ disabledStringSections.selectedIndex = 0;
672+ }
673+
674+ function wait_for_animation(sections) {
675+ // TODO when animations are added
676+ }
677+
678+ function get_number_of_section_buttons(sections) {
679+ var repeater = findChild(sections, "sections_repeater");
680+ return repeater.count;
681+ }
682+
683+ // return the index of the selected section button,
684+ // or -1 if no selected section button is found.
685+ function get_selected_section_button_index(sections) {
686+ var n = get_number_of_section_buttons(sections);
687+ var button;
688+ for (var i=0; i < n; i++) {
689+ button = findChild(sections, "section_button_"+i);
690+ if (button.selected) {
691+ return i;
692+ }
693+ }
694+ return -1;
695+ }
696+
697+ function get_selected_section_button_text(sections) {
698+ var index = get_selected_section_button_index(sections);
699+ if (index < 0) return "BUTTON NOT FOUND.";
700+ var button = findChild(sections, "section_button_label_"+index);
701+ return button.text;
702+ }
703+
704+ function click_section_button(sections, sectionName) {
705+ var index = -1;
706+ var object;
707+ for (index = 0; index < sections.model.length; index++) {
708+ object = sections.model[index];
709+ // object may be a string or an Action
710+ if (object.hasOwnProperty("text")) {
711+ if (object.text === sectionName) {
712+ break;
713+ }
714+ } else {
715+ if (object === sectionName) {
716+ break;
717+ }
718+ }
719+ }
720+ verify(index >= 0, "Button with name \'"+sectionName+"\' not found.");
721+ var button = findChild(sections, "section_button_"+index);
722+ mouseClick(button, button.width/2, button.height/2);
723+ }
724+
725+ function check_selected_section(sections, index, name) {
726+ var v = sections.selectedIndex;
727+ compare(v, index, "selectedIndex "+v+" does not match "+index);
728+ v = get_selected_section_button_index(sections);
729+ compare(v, index, "selected button index "+v+" does not match "+index);
730+ var w = get_selected_section_button_text(sections);
731+ compare(w, name, "selected button text \'"+w+"\' does not match \'"+name+"\'");
732+ }
733+
734+ // in each test function below, test the desired behavior
735+ // for both enabledSections and disabledSections.
736+
737+ function test_0_first_section_initially_selected_actions_enabled() {
738+ check_selected_section(enabledSections, 0, "first");
739+ }
740+ function test_0_first_section_initially_selected_actions_disabled() {
741+ check_selected_section(disabledSections, 0, "first");
742+ }
743+ function test_0_first_section_initially_selected_strings_enabled() {
744+ check_selected_section(enabledStringSections, 0, "string one");
745+ }
746+ function test_0_first_section_initially_selected_strings_disabled() {
747+ check_selected_section(disabledStringSections, 0, "string one");
748+ }
749+
750+ function test_number_of_section_buttons() {
751+ var n = root.actionList.length;
752+ compare(get_number_of_section_buttons(enabledSections), n,
753+ "Showing incorrect number of sections.");
754+ compare(get_number_of_section_buttons(disabledSections), n,
755+ "Showing incorrect number of disabled sections.")
756+ }
757+
758+ function test_click_to_select_section_and_trigger_action() {
759+ var index = 2;
760+ var name = "third";
761+ click_section_button(enabledSections, name);
762+ wait_for_animation(enabledSections);
763+ check_selected_section(enabledSections, index, name);
764+ var text = "Third action triggered.";
765+ compare(label.text, text, "Action for clicked button not triggered.");
766+ }
767+
768+ function test_click_disabled_section_action() {
769+ var index = 2;
770+ var name = "third";
771+ click_section_button(disabledSections, name);
772+ wait_for_animation(disabledSections);
773+ // first button should still be selected:
774+ index = 0;
775+ name = "first";
776+ check_selected_section(disabledSections, index, name);
777+ var text = "No action triggered.";
778+ compare(label.text, text, "Clicking disabled button triggered something.");
779+ }
780+
781+ function test_click_to_select_section_string() {
782+ var index = 2;
783+ var name = "string three";
784+ click_section_button(enabledStringSections, name);
785+ wait_for_animation(enabledStringSections);
786+ check_selected_section(enabledStringSections, index, name);
787+ }
788+
789+ function test_click_disabled_section_string() {
790+ var name = "string three";
791+ click_section_button(disabledStringSections, name);
792+ wait_for_animation(disabledStringSections);
793+ // first button should still be selected:
794+ var index = 0;
795+ name = "string one";
796+ check_selected_section(disabledStringSections, index, name);
797+ }
798+
799+ function test_set_selectedIndex_to_select_section_and_trigger_action_enabled() {
800+ var index = 1;
801+ var name = "second";
802+ enabledSections.selectedIndex = index;
803+ wait_for_animation(enabledSections);
804+ check_selected_section(enabledSections, index, name);
805+ var text = "Second action triggered.";
806+ compare(label.text, text, "Changing selected index did not trigger action.");
807+ }
808+
809+ function test_set_selectedIndex_to_select_section_and_trigger_action_disabled() {
810+ var index = 2;
811+ var name = "third";
812+ disabledSections.selectedIndex = index;
813+ wait_for_animation(disabledSections);
814+ check_selected_section(disabledSections, index, name);
815+ var text = "Third action triggered.";
816+ compare(label.text, text, "Changing selected index for disabled Sections " +
817+ "did not trigger action.");
818+ }
819+
820+ function test_set_selectedIndex_to_select_section_string_enabled() {
821+ var index = 1;
822+ var name = "string two";
823+ enabledStringSections.selectedIndex = index;
824+ wait_for_animation(enabledStringSections);
825+ check_selected_section(enabledStringSections, index, name);
826+ }
827+
828+ function test_set_selectedIndex_to_select_section_string_disabled() {
829+ var index = 2;
830+ var name = "string three";
831+ disabledStringSections.selectedIndex = index;
832+ check_selected_section(disabledStringSections, index, name);
833+ }
834+ }
835+}

Subscribers

People subscribed via source and target branches