Merge lp:~zsombi/ubuntu-ui-toolkit/multicolumnview into lp:ubuntu-ui-toolkit/staging
- multicolumnview
- Merge into staging
Status: | Merged |
---|---|
Merge reported by: | Cris Dywan |
Merged at revision: | not available |
Proposed branch: | lp:~zsombi/ubuntu-ui-toolkit/multicolumnview |
Merge into: | lp:ubuntu-ui-toolkit/staging |
Diff against target: |
1172 lines (+1033/-4) 14 files modified
components.api (+15/-0) modules/Ubuntu/Components/1.2/stack.js (+1/-0) modules/Ubuntu/Components/1.3/ColumnMetrics.qml (+52/-0) modules/Ubuntu/Components/1.3/MultiColumnView.qml (+569/-0) modules/Ubuntu/Components/1.3/Page.qml (+1/-0) modules/Ubuntu/Components/1.3/PageHeadConfiguration.qml (+2/-0) modules/Ubuntu/Components/1.3/PageWrapper.qml (+37/-0) modules/Ubuntu/Components/1.3/stack.js (+75/-0) modules/Ubuntu/Components/Themes/Ambiance/1.3/PageHeadStyle.qml (+2/-2) modules/Ubuntu/Components/qmldir (+2/-0) tests/resources/navigation/MyCustomPage.qml (+1/-1) tests/resources/navigation/SplitViewStack.qml (+137/-0) tests/unit_x11/tst_components/tst_components.pro (+2/-1) tests/unit_x11/tst_components/tst_multicolumnview.qml (+137/-0) |
To merge this branch: | bzr merge lp:~zsombi/ubuntu-ui-toolkit/multicolumnview |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tim Peeters | Needs Fixing | ||
PS Jenkins bot | continuous-integration | Approve | |
Review via email: mp+261703@code.launchpad.net |
Commit message
MultiColumnView component
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1538
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1540
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Tim Peeters (tpeeters) wrote : | # |
23 + default readonly property QtObject data
why?
Tim Peeters (tpeeters) wrote : | # |
41 === modified file 'modules/
42 --- modules/
43 +++ modules/
44 @@ -41,4 +41,5 @@
45 if (this.size() < 1) return undefined;
46 return elements[
47 }
48 +
49 }
undo
Tim Peeters (tpeeters) wrote : | # |
82 + /*!
83 + 1-based value identifying the column the metrics to be applied to.
84 + */
85 + property int column
Why not start at 0, as is common?
Tim Peeters (tpeeters) wrote : | # |
87 + /*!
88 + Specifies whether the width of the column should fill the available space
89 + of the MultiColumnView column or not. Defaults to \a false.
90 + */
91 + property bool fillWidth: false
if fillWidth = true, then defaultColumnWidth will be used (if that is within the borders of the min and max width for the colum)? Can you describe that explicitly here?
Tim Peeters (tpeeters) wrote : | # |
144 + MultiColumnView stores pages added in a tree. Pages are added relative to a
145 + given page, either as sibling (\l addPageToCurren
146 + (\l addPageToNextCo
147 + tree will remove all its children from the page tree.
I don't agree with the terminology here. They are both children, in either of the columns.
Tim Peeters (tpeeters) wrote : | # |
152 + the column next to the source page. Giving a null value to the source page will
153 + add the page to the leftmost column of the view.
No, adding a null value is forbidden.
Tim Peeters (tpeeters) wrote : | # |
160 + \note Unlike PageStack, the component does not fill its parent content.
why not?
Tim Peeters (tpeeters) wrote : | # |
I'm reading this - http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1543
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Zsombor Egri (zsombi) wrote : | # |
> 23 + default readonly property QtObject data
>
> why?
That wasn't me, it is the qmlapicheck, sorry.
Zsombor Egri (zsombi) wrote : | # |
> 41 === modified file 'modules/
> 42 --- modules/
> +0000
> 43 +++ modules/
> +0000
> 44 @@ -41,4 +41,5 @@
> 45 if (this.size() < 1) return undefined;
> 46 return elements[
> 47 }
> 48 +
> 49 }
>
> undo
ehh... will undo soon.
Zsombor Egri (zsombi) wrote : | # |
> 82 + /*!
> 83 + 1-based value identifying the column the metrics to be applied
> to.
> 84 + */
> 85 + property int column
>
> Why not start at 0, as is common?
Well, doesn't matter, we can start from 0 then.
Zsombor Egri (zsombi) wrote : | # |
> 87 + /*!
> 88 + Specifies whether the width of the column should fill the
> available space
> 89 + of the MultiColumnView column or not. Defaults to \a false.
> 90 + */
> 91 + property bool fillWidth: false
>
> if fillWidth = true, then defaultColumnWidth will be used (if that is within
> the borders of the min and max width for the colum)? Can you describe that
> explicitly here?
if fillWidth == true => every value is omitted, just like in Layout.
Zsombor Egri (zsombi) wrote : | # |
> 160 + \note Unlike PageStack, the component does not fill its parent
> content.
>
> why not?
This was something people complained a lot in PageStack. if you want different aching, you have to set anchor.fill: undefined first, then change the anchors.
Zsombor Egri (zsombi) wrote : | # |
> I'm reading this - http://
> they have GridLayout, RowLayout and ColumnLayout. I'm wondering whether we
> should name our component MultiColumnView (similar to our MainView), or we
> adapt naming similar to that used in Layouts, so MultiColumnLayout?
Not a bad idea!!!!!
Tim Peeters (tpeeters) wrote : | # |
293 + The proeprty can hold either a Page instance, a component holding a Page
proeprty
Tim Peeters (tpeeters) wrote : | # |
293 + The proeprty can hold either a Page instance, a component holding a Page
294 + or a QML document defining the Page. The property cannot be changed after
295 + component completion.
296 + */
297 + property var primaryPage
Why? What is the use case for this flexibility? So we just make it property Item primaryPage or even property Page primaryPage.
Tim Peeters (tpeeters) wrote : | # |
300 + Specifies the number of columns in the view. A condition must be set to
301 + control the number of columns depending on the space available.
It is not a requirement that a condition is set.
Tim Peeters (tpeeters) wrote : | # |
311 + /*!
312 + The property specifies the default width of each column. The property is
313 + applied on each column. If the \a minimumWidth specified for the column is
Not on the last column. That will use full width.
314 + bigger than this value, the minimum width will be applied.
315 + */
316 + property real defaultColumnWidth: units.gu(40)
Tim Peeters (tpeeters) wrote : | # |
323 + is empty. Only columns requiring special handling than the default should
324 + be specified.
325 + */
+different from
Tim Peeters (tpeeters) wrote : | # |
329 + \qmlmethod Item addPageToCurren
this doesn't seem to do anything in the generated docs.
Tim Peeters (tpeeters) wrote : | # |
330 + Adds a \c page to the column the \c sourcePage resides in. If \c sourcePage
331 + is null, the \c page will be added to the leftmost column. \c page can be a
332
Null is not allowed. Update docs.
Tim Peeters (tpeeters) wrote : | # |
336 + function addPageToCurren
363 + function addPageToNextCo
These share a lot of implementation. Add an internal addPageToColumn(i, sourcePage, page, properties) function that they call.
Tim Peeters (tpeeters) wrote : | # |
409 + console.warn("There must me a minimum of one column set.");
BE
Preview Diff
1 | === modified file 'components.api' |
2 | --- components.api 2015-06-02 12:37:41 +0000 |
3 | +++ components.api 2015-06-17 14:25:30 +0000 |
4 | @@ -204,6 +204,11 @@ |
5 | function clear() |
6 | function QQuickMimeData* newData() |
7 | Ubuntu.Components.ColorUtils 0.1 1.0 |
8 | +Ubuntu.Components.ColumnMetrics 1.3: QtObject |
9 | + property int column |
10 | + property bool fillWidth |
11 | + property double maximumWidth |
12 | + property double minimumWidth |
13 | Ubuntu.Components.ComboButton 1.1: Button |
14 | property double collapsedHeight |
15 | default readonly property QtObject comboList |
16 | @@ -521,6 +526,15 @@ |
17 | Ubuntu.Components.Mouse.Priority: Enum |
18 | AfterItem |
19 | BeforeItem |
20 | +Ubuntu.Components.MultiColumnView 1.3: PageTreeNode |
21 | + readonly property ColumnMetrics columnMetrics |
22 | + property int columns |
23 | + default readonly property QtObject data |
24 | + property double defaultColumnWidth |
25 | + function var addPageToCurrentColumn(var sourcePage, var page, var properties) |
26 | + function var addPageToNextColumn(var sourcePage, var page, var properties) |
27 | + function var removePages(var page) |
28 | + property var primaryPage |
29 | Ubuntu.Components.ListItems.MultiValue 1.0 0.1: Base |
30 | property var values |
31 | Ubuntu.Components.ListItems.MultiValue 1.3: Base |
32 | @@ -605,6 +619,7 @@ |
33 | property bool locked |
34 | property string preset |
35 | readonly property PageHeadSections sections |
36 | + property string title |
37 | property bool visible |
38 | Ubuntu.Components.PageHeadSections 1.1: QtObject |
39 | property bool enabled |
40 | |
41 | === modified file 'modules/Ubuntu/Components/1.2/stack.js' |
42 | --- modules/Ubuntu/Components/1.2/stack.js 2015-04-30 08:32:44 +0000 |
43 | +++ modules/Ubuntu/Components/1.2/stack.js 2015-06-17 14:25:30 +0000 |
44 | @@ -41,4 +41,5 @@ |
45 | if (this.size() < 1) return undefined; |
46 | return elements[elements.length-1]; |
47 | } |
48 | + |
49 | } |
50 | |
51 | === added file 'modules/Ubuntu/Components/1.3/ColumnMetrics.qml' |
52 | --- modules/Ubuntu/Components/1.3/ColumnMetrics.qml 1970-01-01 00:00:00 +0000 |
53 | +++ modules/Ubuntu/Components/1.3/ColumnMetrics.qml 2015-06-17 14:25:30 +0000 |
54 | @@ -0,0 +1,52 @@ |
55 | +/* |
56 | + * Copyright 2015 Canonical Ltd. |
57 | + * |
58 | + * This program is free software; you can redistribute it and/or modify |
59 | + * it under the terms of the GNU Lesser General Public License as published by |
60 | + * the Free Software Foundation; version 3. |
61 | + * |
62 | + * This program is distributed in the hope that it will be useful, |
63 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
64 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
65 | + * GNU Lesser General Public License for more details. |
66 | + * |
67 | + * You should have received a copy of the GNU Lesser General Public License |
68 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
69 | + */ |
70 | + |
71 | +import QtQuick 2.4 |
72 | + |
73 | +/*! |
74 | + \qmltype ColumnMetrics |
75 | + \inqmlmodule Ubuntu.Components 1.3 |
76 | + \since Ubuntu.Components 1.3 |
77 | + \ingroup ubuntu |
78 | + \brief Component configuring the metrics of a column in MultiColumnView. |
79 | + |
80 | + */ |
81 | +QtObject { |
82 | + /*! |
83 | + 1-based value identifying the column the metrics to be applied to. |
84 | + */ |
85 | + property int column |
86 | + |
87 | + /*! |
88 | + Specifies whether the width of the column should fill the available space |
89 | + of the MultiColumnView column or not. Defaults to \a false. |
90 | + */ |
91 | + property bool fillWidth: false |
92 | + |
93 | + /*! |
94 | + Specifies the minimum width of the column. If the value is greater than |
95 | + \l MultiColumnView::defaultColumnWidth, the value will be set as width for |
96 | + the column. |
97 | + */ |
98 | + property real minimumWidth: 0 |
99 | + |
100 | + /*! |
101 | + Specifies the maximum width of the column. If the value is smaller than |
102 | + \l MultiColumnView::defaultColumnWidth, the value will be set as width for |
103 | + the column. A maximum value of 0 will be ignored. |
104 | + */ |
105 | + property real maximumWidth: Number.POSITIVE_INFINITY |
106 | +} |
107 | |
108 | === added file 'modules/Ubuntu/Components/1.3/MultiColumnView.qml' |
109 | --- modules/Ubuntu/Components/1.3/MultiColumnView.qml 1970-01-01 00:00:00 +0000 |
110 | +++ modules/Ubuntu/Components/1.3/MultiColumnView.qml 2015-06-17 14:25:30 +0000 |
111 | @@ -0,0 +1,569 @@ |
112 | +/* |
113 | + * Copyright 2015 Canonical Ltd. |
114 | + * |
115 | + * This program is free software; you can redistribute it and/or modify |
116 | + * it under the terms of the GNU Lesser General Public License as published by |
117 | + * the Free Software Foundation; version 3. |
118 | + * |
119 | + * This program is distributed in the hope that it will be useful, |
120 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
121 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
122 | + * GNU Lesser General Public License for more details. |
123 | + * |
124 | + * You should have received a copy of the GNU Lesser General Public License |
125 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
126 | + */ |
127 | + |
128 | +import QtQuick 2.4 |
129 | +import QtQuick.Layouts 1.1 |
130 | +import Ubuntu.Components 1.3 |
131 | +import "stack.js" as Stack |
132 | + |
133 | +/*! |
134 | + \qmltype MultiColumnView |
135 | + \inqmlmodule Ubuntu.Components 1.3 |
136 | + \since Ubuntu.Components 1.3 |
137 | + \ingroup ubuntu |
138 | + \brief View with multiple columns of Pages. |
139 | + |
140 | + The component provides a flexible way of viewing a stack of pages in one or |
141 | + more columns. Unlike in PageStack, there can be more than one Page active at |
142 | + a time, depending on the number of the columns in the view. |
143 | + |
144 | + MultiColumnView stores pages added in a tree. Pages are added relative to a |
145 | + given page, either as sibling (\l addPageToCurrentColumn) or as child |
146 | + (\l addPageToNextColumn). This means that removing a non-leaf page from the Page |
147 | + tree will remove all its children from the page tree. |
148 | + |
149 | + The columns are populated from left to right. The column a page is added to is |
150 | + detected based on the source page that is given to the functions adding the page. |
151 | + The pages can be added either to the same column the source page resides or to |
152 | + the column next to the source page. Giving a null value to the source page will |
153 | + add the page to the leftmost column of the view. |
154 | + |
155 | + The primary page, the very first page must be specified through the \l primaryPage |
156 | + property. The property cannot be changed after component completion and can hold |
157 | + a Page instance, a Component or a url to a document defining a Page. The page |
158 | + cannot be removed from the view. |
159 | + |
160 | + \note Unlike PageStack, the component does not fill its parent content. |
161 | + |
162 | + \qml |
163 | + import QtQuick 2.4 |
164 | + import Ubuntu.Components 1.3 |
165 | + |
166 | + MainView { |
167 | + width: units.gu(80) |
168 | + height: units.gu(71) |
169 | + |
170 | + MultiColumnView { |
171 | + anchors.fill: parent |
172 | + columns: 2 |
173 | + primaryPage: page1 |
174 | + Page { |
175 | + id: page1 |
176 | + title: "Main page" |
177 | + Column { |
178 | + Button { |
179 | + text: "Add Page2 above " + title |
180 | + onClicked: page1.pageStack.addPageToCurrentColumn(page1, page2) |
181 | + } |
182 | + Button { |
183 | + text: "Add Page3 next to " + title |
184 | + onClicked: page1.pageStack.addPageToNextColumn(page1, page3) |
185 | + } |
186 | + } |
187 | + } |
188 | + Page { |
189 | + id: page2 |
190 | + title: "Page #2" |
191 | + } |
192 | + Page { |
193 | + id: page3 |
194 | + title: "Page #3" |
195 | + } |
196 | + } |
197 | + } |
198 | + \endqml |
199 | + |
200 | + Column widths are controlled by the \l defaultColumnWidth property and the \l columnMetrics |
201 | + properties. The \l columnMetrics contains a list of metrics configuring a specific |
202 | + column. If no metrics are set, the component will use \l defaultColumnWidth on |
203 | + each column. If the component is set to have one column only, the content will |
204 | + be stretched to the entire component area no matter of the metrics specified. |
205 | + When multiple columns are set, the last column is set to fill the available |
206 | + width and the rest are configured with the \l defaultColumnWidth. This behavior |
207 | + can be changed by specifying the \l ColumnMetrics::fillWidth for the column that |
208 | + needs to fill the available width. There can be more columns filling the available |
209 | + width at a time. |
210 | + |
211 | + Let's modify the example above, to have 3 columns, where columns 1 and 3 |
212 | + should have fixed widths of 40 GU and column 2 should fill to the space |
213 | + available. The code handling this would look as follows: |
214 | + \qml |
215 | + MultiColumnView { |
216 | + columns: 3 |
217 | + defaultColumnWidth: units.gu(40) |
218 | + columnMetrics: [ |
219 | + ColumnMetrics { |
220 | + column: 2 |
221 | + fillWidth: true |
222 | + }, |
223 | + ColumnMetrics { |
224 | + column: 3 |
225 | + fillWidth: false |
226 | + } |
227 | + ] |
228 | + } |
229 | + \endqml |
230 | + |
231 | + MultiColumnView supports adaptive column handling. When columns number changes |
232 | + runtime, the pages are automatically rearranged to the closest columns they were |
233 | + added to. To understand it better, let's take the following example: |
234 | + \qml |
235 | + import QtQuick 2.4 |
236 | + import Ubuntu.Components 1.3 |
237 | + |
238 | + MainView { |
239 | + width: units.gu(120) |
240 | + height: units.gu(71) |
241 | + |
242 | + MultiColumnView { |
243 | + anchors.fill: parent |
244 | + columns: width > units.gu(100) ? 3 : |
245 | + (width >= units.gu(80) ? 2 : 1) |
246 | + primaryPage: page1 |
247 | + Page { |
248 | + id: page1 |
249 | + title: "Main page" |
250 | + Button { |
251 | + text: "Add Page2 next to " + title |
252 | + onClicked: page1.pageStack.addPageToNextColumn(page1, page2) |
253 | + } |
254 | + } |
255 | + Page { |
256 | + id: page2 |
257 | + title: "Page #2" |
258 | + Button { |
259 | + text: "Add Page3 next to " + title |
260 | + onClicked: page2.pageStack.addPageToNextColumn(page2, page3) |
261 | + } |
262 | + } |
263 | + Page { |
264 | + id: page3 |
265 | + title: "Page #3" |
266 | + } |
267 | + } |
268 | + } |
269 | + \endqml |
270 | + |
271 | + When the code is run on desktop, it will launch with a space for three columns. |
272 | + \c page1 is set to be the primary page, \c page2 will be added to column next to |
273 | + \c page1 (to column 2) and \c page3 next to \c page2 (column 3). When the window |
274 | + is resized to have its size below 100 GU, the component will switch to 2 column |
275 | + mode, and \c page3 will be placed in the last column, and the header for \c page2 |
276 | + will have a back button, indicating that there is a page below it. If the window |
277 | + is resized to contain only one column, all pages will be shown in that column, so |
278 | + the component will act as PageStack. Resizing the window back to 2 respectively |
279 | + 3 columns will place the pages side-by-side. |
280 | + |
281 | + \note In the above example if \c page2 is removed, that will remove all its child |
282 | + pages, meaning \c page3 will also be removed. |
283 | + |
284 | + \sa PageStack, ColumnMetrics |
285 | +*/ |
286 | + |
287 | +PageTreeNode { |
288 | + id: multiColumnView |
289 | + |
290 | + /*! |
291 | + The property holds the first Page which will be added to the view. If the |
292 | + view has more than one column, the page will be added to the leftmost column. |
293 | + The proeprty can hold either a Page instance, a component holding a Page |
294 | + or a QML document defining the Page. The property cannot be changed after |
295 | + component completion. |
296 | + */ |
297 | + property var primaryPage |
298 | + |
299 | + /*! |
300 | + Specifies the number of columns in the view. A condition must be set to |
301 | + control the number of columns depending on the space available. |
302 | + \qml |
303 | + MultiColumnView { |
304 | + id: view |
305 | + columns: view.width > units.gu(50) ? 2 : 1 |
306 | + } |
307 | + \endqml |
308 | + */ |
309 | + property int columns: 1 |
310 | + |
311 | + /*! |
312 | + The property specifies the default width of each column. The property is |
313 | + applied on each column. If the \a minimumWidth specified for the column is |
314 | + bigger than this value, the minimum width will be applied. |
315 | + */ |
316 | + property real defaultColumnWidth: units.gu(40) |
317 | + |
318 | + /*! |
319 | + The property configures the size constraints and area filling for columns. |
320 | + If a column is not specified, the default sizing and filling will be applied. |
321 | + By default, only the last column is filling the available width, al other |
322 | + columns are sized to \l defaultColumnWidth as maximum. By default the list |
323 | + is empty. Only columns requiring special handling than the default should |
324 | + be specified. |
325 | + */ |
326 | + property list<ColumnMetrics> columnMetrics |
327 | + |
328 | + /*! |
329 | + \qmlmethod Item addPageToCurrentColumn(Item sourcePage, var page[, var properties]) |
330 | + Adds a \c page to the column the \c sourcePage resides in. If \c sourcePage |
331 | + is null, the \c page will be added to the leftmost column. \c page can be a |
332 | + Component or a file. \c properties is a JSon object containing properties |
333 | + to be set when page is created. \c sourcePage must be active. Returns the |
334 | + instance of the page created. |
335 | + */ |
336 | + function addPageToCurrentColumn(sourcePage, page, properties) { |
337 | + if (columns <= 0) { |
338 | + return; |
339 | + } |
340 | + if (!sourcePage) { |
341 | + console.warn("No sourcePage specified. Page will not be added."); |
342 | + return; |
343 | + } |
344 | + if (!d.stack.find(sourcePage)) { |
345 | + console.warn("sourcePage must be added to the view to add new page."); |
346 | + return; |
347 | + } |
348 | + |
349 | + var wrapper = d.createWrapper(page, properties); |
350 | + wrapper.column = d.columnForPage(sourcePage); |
351 | + wrapper.parentPage = sourcePage; |
352 | + d.addPage(wrapper); |
353 | + return wrapper.object; |
354 | + } |
355 | + |
356 | + /*! |
357 | + \qmlmethod Item addPageToNextColumn(Item sourcePage, var page[, var properties]) |
358 | + Same as \l addPageToCurrentColumn except that the \c page is added to the column |
359 | + next to the one the \c sourcePage resides. If \c sourcePage is null, the new |
360 | + page will be added to the leftmost column. If \c sourcePage is located in the |
361 | + rightmost column, the new page will be pushed to the same column as \c sourcePage. |
362 | + */ |
363 | + function addPageToNextColumn(sourcePage, page, properties) { |
364 | + if (columns <= 0) { |
365 | + return; |
366 | + } |
367 | + if (!sourcePage) { |
368 | + console.warn("No sourcePage specified. Page will not be added."); |
369 | + return; |
370 | + } |
371 | + if (!d.stack.find(sourcePage)) { |
372 | + console.warn("sourcePage must be added to the view to add new page."); |
373 | + return; |
374 | + } |
375 | + |
376 | + var wrapper = d.createWrapper(page, properties); |
377 | + wrapper.column = (!sourcePage) ? 0 : d.columnForPage(sourcePage) + 1; |
378 | + wrapper.parentPage = sourcePage; |
379 | + d.addPage(wrapper); |
380 | + return wrapper.object; |
381 | + } |
382 | + |
383 | + /*! |
384 | + \qmlmethod void removePages(Item page) |
385 | + The function removes and deletes all pages from the view columns until \c page |
386 | + is reached. If the \a page is the same as the \l primaryPage, only its child |
387 | + pages will be removed. |
388 | + */ |
389 | + function removePages(page) { |
390 | + // remove nodes which have page as ascendant |
391 | + var node = d.stack.top(); |
392 | + while (node && node.childOf(page)) { |
393 | + d.popAndSetPageForColumn(node); |
394 | + node = d.stack.top(); |
395 | + } |
396 | + while (node && node.object == page && node != d.stack.first()) { |
397 | + d.popAndSetPageForColumn(node); |
398 | + node = d.stack.top(); |
399 | + } |
400 | + } |
401 | + |
402 | + /* |
403 | + internals |
404 | + */ |
405 | + |
406 | + /*! internal */ |
407 | + onColumnsChanged: { |
408 | + if (columns <= 0) { |
409 | + console.warn("There must me a minimum of one column set."); |
410 | + } |
411 | + d.relayout(); |
412 | + } |
413 | + Component.onCompleted: { |
414 | + d.relayout(); |
415 | + d.completed = true; |
416 | + if (primaryPage) { |
417 | + var wrapper = d.createWrapper(primaryPage); |
418 | + d.addPage(wrapper); |
419 | + } else { |
420 | + console.warn("No primary page set. No pages can be added without a primary page."); |
421 | + } |
422 | + } |
423 | + onPrimaryPageChanged: { |
424 | + if (d.completed) { |
425 | + console.warn("Cannot change primaryPage after completion."); |
426 | + return; |
427 | + } |
428 | + } |
429 | + onDefaultColumnWidthChanged: body.applyMetrics() |
430 | + |
431 | + QtObject { |
432 | + id: d |
433 | + |
434 | + property bool completed: false |
435 | + property var stack: new Stack.Stack() |
436 | + |
437 | + function createWrapper(page, properties) { |
438 | + var wrapperComponent = Qt.createComponent("PageWrapper.qml"); |
439 | + var wrapperObject = wrapperComponent.createObject(hiddenPages); |
440 | + wrapperObject.pageStack = multiColumnView; |
441 | + wrapperObject.properties = properties; |
442 | + // set reference last because it will trigger creation of the object |
443 | + // with specified properties. |
444 | + wrapperObject.reference = page; |
445 | + return wrapperObject; |
446 | + } |
447 | + |
448 | + function addPage(pageWrapper) { |
449 | + stack.push(pageWrapper); |
450 | + pageWrapper.parentWrapper = stack.find(pageWrapper.parentPage); |
451 | + var targetColumn = MathUtils.clamp(pageWrapper.column, 0, columns - 1); |
452 | + // replace page holder's child |
453 | + var holder = body.children[targetColumn]; |
454 | + holder.detachCurrentPage(); |
455 | + holder.attachPage(pageWrapper) |
456 | + } |
457 | + |
458 | + function columnForPage(page) { |
459 | + var wrapper = stack.find(page); |
460 | + return wrapper ? wrapper.column : 0; |
461 | + } |
462 | + |
463 | + // node is a triplet of {page, column, parentPage} |
464 | + function popAndSetPageForColumn(node) { |
465 | + stack.pop(); |
466 | + var effectiveColumn = MathUtils.clamp(node.column, 0, columns - 1); |
467 | + var columnHolder = body.children[effectiveColumn]; |
468 | + // is the page in a column? |
469 | + if (node == columnHolder.pageWrapper) { |
470 | + // detach page from column |
471 | + columnHolder.detachCurrentPage(); |
472 | + } |
473 | + node.parent = null; |
474 | + var prevPage = stack.topForColumn(effectiveColumn, effectiveColumn < columns - 1); |
475 | + if (prevPage) { |
476 | + columnHolder.attachPage(prevPage); |
477 | + } |
478 | + if (node.canDestroy) { |
479 | + node.destroyObject(); |
480 | + } |
481 | + } |
482 | + |
483 | + // relayouts when column count changes |
484 | + function relayout() { |
485 | + if (body.children.length == columns) return; |
486 | + if (body.children.length > columns) { |
487 | + // need to remove few columns, the last ones |
488 | + while (body.children.length > columns) { |
489 | + var holder = body.children[body.children.length - 1]; |
490 | + holder.detachCurrentPage(); |
491 | + holder.parent = null; |
492 | + holder.destroy(); |
493 | + } |
494 | + } else { |
495 | + var prevColumns = body.children.length; |
496 | + |
497 | + // add columns |
498 | + for (var i = 0; i < columns - prevColumns; i++) { |
499 | + pageHolderComponent.createObject(body); |
500 | + } |
501 | + } |
502 | + rearrangePages(); |
503 | + } |
504 | + |
505 | + function rearrangePages() { |
506 | + for (var column = columns - 1; column >= 0; column--) { |
507 | + var holder = body.children[column]; |
508 | + var pageWrapper = stack.topForColumn(column, column < (columns - 1)); |
509 | + if (!pageWrapper) { |
510 | + continue; |
511 | + } |
512 | + if (!pageWrapper.parent) { |
513 | + // this should never happen, so if it does, we have a bug! |
514 | + console.error("Found a page which wasn't parented anywhere!", pageWrapper.object.title); |
515 | + continue; |
516 | + } |
517 | + // detach current page from holder if differs |
518 | + if (holder.pageWrapper != pageWrapper) { |
519 | + holder.detachCurrentPage(); |
520 | + } |
521 | + if (pageWrapper.parent == hiddenPages) { |
522 | + // add the page to the column |
523 | + holder.attachPage(pageWrapper); |
524 | + } else if (pageWrapper.pageHolder != holder) { |
525 | + // detach the pageWrapper from its holder |
526 | + if (pageWrapper.pageHolder) { |
527 | + pageWrapper.pageHolder.detachCurrentPage(); |
528 | + } |
529 | + // then attach to this holder |
530 | + holder.attachPage(pageWrapper); |
531 | + } |
532 | + } |
533 | + } |
534 | + } |
535 | + |
536 | + // default metrics |
537 | + Component { |
538 | + id: defaultMetrics |
539 | + ColumnMetrics { |
540 | + fillWidth: column == columns |
541 | + minimumWidth: defaultColumnWidth |
542 | + } |
543 | + } |
544 | + |
545 | + // Page holder component, can have only one Page as child at a time, all stacked pages |
546 | + // will be parented into hiddenPages |
547 | + Component { |
548 | + id: pageHolderComponent |
549 | + Item { |
550 | + id: holder |
551 | + objectName: "ColumnHolder" + column |
552 | + property PageWrapper pageWrapper |
553 | + property int column |
554 | + property alias config: header.config |
555 | + property ColumnMetrics metrics: setDefaultMetrics() |
556 | + |
557 | + Layout.fillWidth: metrics.fillWidth |
558 | + Layout.fillHeight: true |
559 | + Layout.preferredWidth: metrics.maximumWidth > 0 ? |
560 | + MathUtils.clamp(defaultColumnWidth, metrics.minimumWidth, metrics.maximumWidth) : |
561 | + defaultColumnWidth |
562 | + Layout.minimumWidth: metrics.minimumWidth |
563 | + Layout.maximumWidth: metrics.maximumWidth |
564 | + |
565 | + // header |
566 | + StyledItem { |
567 | + id: header |
568 | + anchors { |
569 | + left: parent.left |
570 | + top: parent.top |
571 | + right: parent.right |
572 | + } |
573 | + implicitHeight: units.gu(8) |
574 | +// styleName: config ? "PageHeadStyle" : "" |
575 | + |
576 | + property PageHeadConfiguration config: null |
577 | + property Item contents: null |
578 | + |
579 | + property color dividerColor: theme.palette.normal.background |
580 | + property color panelColor |
581 | + } |
582 | + |
583 | + Rectangle { |
584 | + id: divider |
585 | + anchors { |
586 | + top: parent.top |
587 | + bottom: parent.bottom |
588 | + right: parent.right |
589 | + } |
590 | + width: (column == (columns - 1)) || !pageWrapper ? 0 : units.dp(2) |
591 | + color: theme.palette.normal.background |
592 | + } |
593 | + |
594 | + Item { |
595 | + id: holderBody |
596 | + objectName: parent.objectName + "Body" |
597 | + anchors { |
598 | + fill: parent |
599 | +// topMargin: header.height |
600 | + rightMargin: divider.width |
601 | + } |
602 | + } |
603 | + |
604 | + function attachPage(page) { |
605 | + if (!page) return; |
606 | + pageWrapper = page; |
607 | + pageWrapper.parent = holderBody; |
608 | + pageWrapper.pageHolder = holder; |
609 | + pageWrapper.active = true; |
610 | + if (pageWrapper.object.hasOwnProperty("head")) { |
611 | + header.config = pageWrapper.object.head; |
612 | + } |
613 | + } |
614 | + function detachCurrentPage() { |
615 | + if (!pageWrapper) return undefined; |
616 | + var wrapper = pageWrapper; |
617 | + // remove header |
618 | + wrapper.active = false; |
619 | + header.config = null; |
620 | + pageWrapper = null; |
621 | + wrapper.parent = hiddenPages; |
622 | + wrapper.pageHolder = null; |
623 | + return wrapper; |
624 | + } |
625 | + |
626 | + function setDefaultMetrics() { |
627 | + var result = defaultMetrics.createObject(holder); |
628 | + result.column = Qt.binding(function() { return holder.column + 1; }); |
629 | + return result; |
630 | + } |
631 | + } |
632 | + } |
633 | + |
634 | + /*! \internal */ |
635 | + // Pages declared as children will be placed directly into hiddenPages |
636 | + default property alias data: hiddenPages.data |
637 | + Item { |
638 | + id: hiddenPages |
639 | + objectName: "HiddenPagePool" |
640 | + visible: false |
641 | + // make sure nothing is shown eventually |
642 | + clip: true |
643 | + } |
644 | + |
645 | + // Holds the columns holding the pages visible. Each column has only one page |
646 | + // as child, the invisible stacked ones are all stored in the hiddenPages |
647 | + // component. The stack keeps the column index onto which those should be moved |
648 | + // once they become visible. |
649 | + RowLayout { |
650 | + id: body |
651 | + anchors.fill: parent |
652 | + spacing: 0 |
653 | + |
654 | + onChildrenChanged: { |
655 | + // all children should have Layout.fillWidth false, except the last one |
656 | + for (var i = 0; i < children.length; i++) { |
657 | + children[i].column = i; |
658 | + } |
659 | + applyMetrics(); |
660 | + } |
661 | + |
662 | + function applyMetrics() { |
663 | + for (var i = 0; i < children.length; i++) { |
664 | + var holder = children[i]; |
665 | + // search for the column metrics |
666 | + var metrics = null; |
667 | + for (var j = 0; j < columnMetrics.length; j++) { |
668 | + if (columnMetrics[j].column == (i + 1)) { |
669 | + metrics = columnMetrics[j]; |
670 | + break; |
671 | + } |
672 | + } |
673 | + if (!metrics) { |
674 | + metrics = holder.setDefaultMetrics(); |
675 | + } |
676 | + holder.metrics = metrics; |
677 | + } |
678 | + } |
679 | + } |
680 | +} |
681 | |
682 | === modified file 'modules/Ubuntu/Components/1.3/Page.qml' |
683 | --- modules/Ubuntu/Components/1.3/Page.qml 2015-04-30 08:32:44 +0000 |
684 | +++ modules/Ubuntu/Components/1.3/Page.qml 2015-06-17 14:25:30 +0000 |
685 | @@ -43,6 +43,7 @@ |
686 | readonly property alias head: headerConfig |
687 | Toolkit13.PageHeadConfiguration { |
688 | id: headerConfig |
689 | + title: page.title |
690 | } |
691 | |
692 | Toolkit13.Object { |
693 | |
694 | === modified file 'modules/Ubuntu/Components/1.3/PageHeadConfiguration.qml' |
695 | --- modules/Ubuntu/Components/1.3/PageHeadConfiguration.qml 2015-04-30 08:32:44 +0000 |
696 | +++ modules/Ubuntu/Components/1.3/PageHeadConfiguration.qml 2015-06-17 14:25:30 +0000 |
697 | @@ -56,4 +56,6 @@ |
698 | |
699 | // auto-updated by AppHeader, but may be set by the developer |
700 | property bool visible |
701 | + |
702 | + property string title |
703 | } |
704 | |
705 | === modified file 'modules/Ubuntu/Components/1.3/PageWrapper.qml' |
706 | --- modules/Ubuntu/Components/1.3/PageWrapper.qml 2015-05-05 16:23:29 +0000 |
707 | +++ modules/Ubuntu/Components/1.3/PageWrapper.qml 2015-06-17 14:25:30 +0000 |
708 | @@ -46,6 +46,43 @@ |
709 | property bool canDestroy: false |
710 | |
711 | /*! |
712 | + Column number in MultiColumnView. |
713 | + */ |
714 | + property int column: 0 |
715 | + |
716 | + /*! |
717 | + Parent page. |
718 | + */ |
719 | + property Item parentPage |
720 | + |
721 | + /*! |
722 | + Parent PageWrapper or the parentPage. |
723 | + */ |
724 | + property Item parentWrapper |
725 | + |
726 | + /*! |
727 | + Page holder in MultiColumnView |
728 | + */ |
729 | + property Item pageHolder |
730 | + |
731 | + /*! |
732 | + Returns true if the current PageWrapper is a child of the given page |
733 | + */ |
734 | + function childOf(page) { |
735 | + if (parentPage == page) return true; |
736 | + if (page && parentWrapper) { |
737 | + var wrapper = parentWrapper; |
738 | + while (wrapper) { |
739 | + if (wrapper.object == page) { |
740 | + return true; |
741 | + } |
742 | + wrapper = wrapper.parentWrapper; |
743 | + } |
744 | + } |
745 | + return false; |
746 | + } |
747 | + |
748 | + /*! |
749 | This value is updated when a PageWrapper is pushed to/popped from a PageStack. |
750 | */ |
751 | active: false |
752 | |
753 | === added file 'modules/Ubuntu/Components/1.3/stack.js' |
754 | --- modules/Ubuntu/Components/1.3/stack.js 1970-01-01 00:00:00 +0000 |
755 | +++ modules/Ubuntu/Components/1.3/stack.js 2015-06-17 14:25:30 +0000 |
756 | @@ -0,0 +1,75 @@ |
757 | +/* |
758 | + * Copyright 2015 Canonical Ltd. |
759 | + * |
760 | + * This program is free software; you can redistribute it and/or modify |
761 | + * it under the terms of the GNU Lesser General Public License as published by |
762 | + * the Free Software Foundation; version 3. |
763 | + * |
764 | + * This program is distributed in the hope that it will be useful, |
765 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
766 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
767 | + * GNU Lesser General Public License for more details. |
768 | + * |
769 | + * You should have received a copy of the GNU Lesser General Public License |
770 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
771 | + */ |
772 | + |
773 | +.pragma library |
774 | +// By defining Stack as a function, we can make its variables private, |
775 | +// and force calls to Stack to make use of the functions we define. |
776 | +function Stack() { |
777 | + var elements; |
778 | + this.clear = function() { |
779 | + elements = []; |
780 | + } |
781 | + |
782 | + this.clear(); |
783 | + |
784 | + this.push = function(element) { |
785 | + elements.push(element); |
786 | + }; |
787 | + |
788 | + this.pop = function() { |
789 | + elements.pop(); |
790 | + }; |
791 | + |
792 | + this.size = function() { |
793 | + return elements.length; |
794 | + } |
795 | + |
796 | + this.first = function() { |
797 | + return this.size() > 0 ? elements[0] : null; |
798 | + } |
799 | + |
800 | + this.top = function() { |
801 | + if (this.size() < 1) return undefined; |
802 | + return elements[elements.length-1]; |
803 | + } |
804 | + |
805 | + // returns the topmost element for the column, using exact column match |
806 | + // in case the column to be extracted is less than the columns available |
807 | + this.topForColumn = function(column, exactMatch) { |
808 | + if (exactMatch == undefined) { |
809 | + exactMatch = false; |
810 | + } |
811 | + |
812 | + for (var i = elements.length - 1; i >= 0; i--) { |
813 | + var node = elements[i]; |
814 | + if ((exactMatch && elements[i].column == column) || (!exactMatch && elements[i].column >= column)) { |
815 | + return elements[i]; |
816 | + } |
817 | + } |
818 | + return undefined; |
819 | + } |
820 | + |
821 | + // returns the node the Page is stored; undefined if not found |
822 | + this.find = function(page) { |
823 | + if (!page) return null; |
824 | + for (var i = elements.length - 1; i >= 0; i--) { |
825 | + if (elements[i].object == page) { |
826 | + return elements[i]; |
827 | + } |
828 | + } |
829 | + return null; |
830 | + } |
831 | +} |
832 | |
833 | === modified file 'modules/Ubuntu/Components/Themes/Ambiance/1.3/PageHeadStyle.qml' |
834 | --- modules/Ubuntu/Components/Themes/Ambiance/1.3/PageHeadStyle.qml 2015-05-22 13:54:38 +0000 |
835 | +++ modules/Ubuntu/Components/Themes/Ambiance/1.3/PageHeadStyle.qml 2015-06-17 14:25:30 +0000 |
836 | @@ -23,7 +23,7 @@ |
837 | objectName: "PageHeadStyle" // used in unit tests |
838 | contentHeight: units.gu(7) |
839 | fontWeight: Font.Light |
840 | - fontSize: "x-large" |
841 | + fontSize: "large" |
842 | textLeftMargin: units.gu(2) |
843 | maximumNumberOfActions: 3 |
844 | |
845 | @@ -394,7 +394,7 @@ |
846 | right: parent.right |
847 | verticalCenter: parent.verticalCenter |
848 | } |
849 | - text: styledItem.title |
850 | + text: styledItem.config.title |
851 | font.weight: headerStyle.fontWeight |
852 | fontSize: headerStyle.fontSize |
853 | color: headerStyle.titleColor |
854 | |
855 | === modified file 'modules/Ubuntu/Components/qmldir' |
856 | --- modules/Ubuntu/Components/qmldir 2015-05-12 13:41:39 +0000 |
857 | +++ modules/Ubuntu/Components/qmldir 2015-06-17 14:25:30 +0000 |
858 | @@ -140,3 +140,5 @@ |
859 | PullToRefresh 1.3 1.3/PullToRefresh.qml |
860 | UbuntuListView 1.3 1.3/UbuntuListView11.qml |
861 | Captions 1.3 1.3/Captions.qml |
862 | +MultiColumnView 1.3 1.3/MultiColumnView.qml |
863 | +ColumnMetrics 1.3 1.3/ColumnMetrics.qml |
864 | |
865 | === modified file 'tests/resources/navigation/MyCustomPage.qml' |
866 | --- tests/resources/navigation/MyCustomPage.qml 2015-03-03 13:20:06 +0000 |
867 | +++ tests/resources/navigation/MyCustomPage.qml 2015-06-17 14:25:30 +0000 |
868 | @@ -15,7 +15,7 @@ |
869 | */ |
870 | |
871 | import QtQuick 2.2 |
872 | -import Ubuntu.Components 1.1 |
873 | +import Ubuntu.Components 1.3 |
874 | |
875 | Page { |
876 | title: i18n.tr("My custom page") |
877 | |
878 | === added file 'tests/resources/navigation/SplitViewStack.qml' |
879 | --- tests/resources/navigation/SplitViewStack.qml 1970-01-01 00:00:00 +0000 |
880 | +++ tests/resources/navigation/SplitViewStack.qml 2015-06-17 14:25:30 +0000 |
881 | @@ -0,0 +1,137 @@ |
882 | +/* |
883 | + * Copyright 2015 Canonical Ltd. |
884 | + * |
885 | + * This program is free software; you can redistribute it and/or modify |
886 | + * it under the terms of the GNU Lesser General Public License as published by |
887 | + * the Free Software Foundation; version 3. |
888 | + * |
889 | + * This program is distributed in the hope that it will be useful, |
890 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
891 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
892 | + * GNU Lesser General Public License for more details. |
893 | + * |
894 | + * You should have received a copy of the GNU Lesser General Public License |
895 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
896 | + */ |
897 | + |
898 | +import QtQuick 2.4 |
899 | +import Ubuntu.Components 1.3 |
900 | +import QtQuick.Layouts 1.1 |
901 | + |
902 | +MainView { |
903 | + id: main |
904 | + width: units.gu(100) |
905 | + height: units.gu(71) |
906 | + |
907 | + MultiColumnView { |
908 | + id: view |
909 | + anchors.fill: parent |
910 | + columns: { |
911 | + if (width > units.gu(120)) return 3; |
912 | + if (width > units.gu(80)) return 2; |
913 | + return 1; |
914 | + } |
915 | + columnMetrics: [ |
916 | + ColumnMetrics { |
917 | + column: 2 |
918 | + fillWidth: true |
919 | + }, |
920 | + ColumnMetrics { |
921 | + column: 3 |
922 | + fillWidth: false |
923 | + minimumWidth: units.gu(50) |
924 | + } |
925 | + ] |
926 | + primaryPage: page1 |
927 | + |
928 | + Page { |
929 | + id: page1 |
930 | + title: "Page #1" |
931 | + |
932 | + Rectangle { |
933 | + anchors.fill: parent |
934 | + color: "red" |
935 | + } |
936 | + Column { |
937 | + Button { |
938 | + text: "Add page2 next" |
939 | + onClicked: page1.pageStack.addPageToNextColumn(page1, page2) |
940 | + } |
941 | + Button { |
942 | + text: "Add page4 above" |
943 | + onClicked: page1.pageStack.addPageToCurrentColumn(page1, page4) |
944 | + } |
945 | + } |
946 | + } |
947 | + |
948 | + Page { |
949 | + id: page2 |
950 | + title: "Page #2" |
951 | + |
952 | + Rectangle { |
953 | + anchors.fill: parent |
954 | + color: "green" |
955 | + } |
956 | + Column { |
957 | + Button { |
958 | + text: "Back..." |
959 | + onClicked: page2.pageStack.removePages(page2) |
960 | + } |
961 | + Button { |
962 | + text: "Add page3 next" |
963 | + onClicked: page2.pageStack.addPageToNextColumn(page2, page3) |
964 | + } |
965 | + } |
966 | + } |
967 | + Page { |
968 | + id: page3 |
969 | + title: "Page #3" |
970 | + |
971 | + Rectangle { |
972 | + anchors.fill: parent |
973 | + color: "blue" |
974 | + } |
975 | + Button { |
976 | + text: "Back..." |
977 | + onClicked: page3.pageStack.removePages(page3) |
978 | + } |
979 | + } |
980 | + Page { |
981 | + id: page4 |
982 | + title: "Page #4" |
983 | + |
984 | + Rectangle { |
985 | + anchors.fill: parent |
986 | + color: "teal" |
987 | + } |
988 | + Column { |
989 | + Button { |
990 | + text: "Back..." |
991 | + onClicked: page4.pageStack.removePages(page4) |
992 | + } |
993 | + Button { |
994 | + text: "Add page5 next" |
995 | + onClicked: page4.pageStack.addPageToNextColumn(page4, page5) |
996 | + } |
997 | + } |
998 | + } |
999 | + Page { |
1000 | + id: page5 |
1001 | + title: "Page #5" |
1002 | + Rectangle { |
1003 | + anchors.fill: parent |
1004 | + color: "tan" |
1005 | + } |
1006 | + Column { |
1007 | + Button { |
1008 | + text: "Back..." |
1009 | + onClicked: page5.pageStack.removePages(page5) |
1010 | + } |
1011 | + Button { |
1012 | + text: "Custom page on same column" |
1013 | + onClicked: page5.pageStack.addPageToCurrentColumn(page5, Qt.resolvedUrl("MyCustomPage.qml")) |
1014 | + } |
1015 | + } |
1016 | + } |
1017 | + } |
1018 | +} |
1019 | |
1020 | === modified file 'tests/unit_x11/tst_components/tst_components.pro' |
1021 | --- tests/unit_x11/tst_components/tst_components.pro 2015-04-25 07:10:57 +0000 |
1022 | +++ tests/unit_x11/tst_components/tst_components.pro 2015-06-17 14:25:30 +0000 |
1023 | @@ -7,5 +7,6 @@ |
1024 | SOURCES += tst_components.cpp tabsmodel.cpp |
1025 | HEADERS += tabsmodel.h |
1026 | |
1027 | -OTHER_FILES += $$system(ls *.qml) |
1028 | +OTHER_FILES += $$system(ls *.qml) \ |
1029 | + tst_multicolumnview.qml |
1030 | OTHER_FILES += $$system(ls AppTheme/*) |
1031 | |
1032 | === added file 'tests/unit_x11/tst_components/tst_multicolumnview.qml' |
1033 | --- tests/unit_x11/tst_components/tst_multicolumnview.qml 1970-01-01 00:00:00 +0000 |
1034 | +++ tests/unit_x11/tst_components/tst_multicolumnview.qml 2015-06-17 14:25:30 +0000 |
1035 | @@ -0,0 +1,137 @@ |
1036 | +/* |
1037 | + * Copyright 2015 Canonical Ltd. |
1038 | + * |
1039 | + * This program is free software; you can redistribute it and/or modify |
1040 | + * it under the terms of the GNU Lesser General Public License as published by |
1041 | + * the Free Software Foundation; version 3. |
1042 | + * |
1043 | + * This program is distributed in the hope that it will be useful, |
1044 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1045 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1046 | + * GNU Lesser General Public License for more details. |
1047 | + * |
1048 | + * You should have received a copy of the GNU Lesser General Public License |
1049 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1050 | + */ |
1051 | + |
1052 | +import QtQuick 2.4 |
1053 | +import QtTest 1.0 |
1054 | +import Ubuntu.Test 1.0 |
1055 | +import Ubuntu.Components 1.3 |
1056 | + |
1057 | +Item { |
1058 | + id: test |
1059 | + width: units.gu(120) |
1060 | + height: units.gu(71) |
1061 | + |
1062 | + MultiColumnView { |
1063 | + id: testView |
1064 | + width: parent.width |
1065 | + height: parent.height |
1066 | + |
1067 | + columns: width > units.gu(100) ? 3 : (width > units.gu(80) ? 2 : 1) |
1068 | + primaryPage: page1 |
1069 | + |
1070 | + Page { |
1071 | + id: page1 |
1072 | + title: "Page1" |
1073 | + } |
1074 | + Page { |
1075 | + id: page2 |
1076 | + title: "Page2" |
1077 | + } |
1078 | + Page { |
1079 | + id: page3 |
1080 | + title: "Page3" |
1081 | + } |
1082 | + Page { |
1083 | + id: page4 |
1084 | + title: "Page4" |
1085 | + } |
1086 | + } |
1087 | + |
1088 | + MultiColumnView { |
1089 | + id: defaults |
1090 | + } |
1091 | + |
1092 | + UbuntuTestCase { |
1093 | + when: windowShown |
1094 | + |
1095 | + function cleanup() { |
1096 | +// testView.columns = Qt.binding(function() { |
1097 | +// return test.width > units.gu(100) ? 3 : (test.width > units.gu(80) ? 2 : 1); |
1098 | +// }); |
1099 | + testView.width = test.width; |
1100 | + testView.height = test.height; |
1101 | + // remove allpages |
1102 | + testView.removePages(page1); |
1103 | + } |
1104 | + |
1105 | + function test_0_API() { |
1106 | + compare(defaults.columns, 1, "wrong columns"); |
1107 | + compare(defaults.defaultColumnWidth, units.gu(40), "wrong defaultColumnWidth"); |
1108 | + compare(defaults.columnMetrics.length, 0, "wrong columnMetrics list"); |
1109 | + compare(defaults.primaryPage, undefined, "wrong primaryPage"); |
1110 | + } |
1111 | + |
1112 | + function test_add_to_first_column_data() { |
1113 | + return [ |
1114 | + {tag: "null sourcePage, fail", sourcePage: null, page: page2, failMsg: "No sourcePage specified. Page will not be added."}, |
1115 | + {tag: "valid sourcePage, pass", sourcePage: page1, page: page2, failMsg: ""}, |
1116 | + ] |
1117 | + } |
1118 | + function test_add_to_first_column(data) { |
1119 | + if (data.failMsg != "") { |
1120 | + ignoreWarning(data.failMsg); |
1121 | + } |
1122 | + |
1123 | + testView.addPageToCurrentColumn(data.sourcePage, data.page); |
1124 | + var firstColumn = findChild(testView, "ColumnHolder0"); |
1125 | + verify(firstColumn); |
1126 | + if (data.failMsg != "") { |
1127 | + expectFail(data.tag, "Fail"); |
1128 | + } |
1129 | + compare(firstColumn.pageWrapper.object, data.page); |
1130 | + } |
1131 | + |
1132 | + function test_add_to_next_column_data() { |
1133 | + return [ |
1134 | + {tag: "null sourcePage, fail", sourcePage: null, page: page2, failMsg: "No sourcePage specified. Page will not be added."}, |
1135 | + {tag: "valid sourcePage, pass", sourcePage: page1, page: page2, failMsg: ""}, |
1136 | + ] |
1137 | + } |
1138 | + function test_add_to_next_column(data) { |
1139 | + if (data.failMsg != "") { |
1140 | + ignoreWarning(data.failMsg); |
1141 | + } |
1142 | + |
1143 | + testView.addPageToNextColumn(data.sourcePage, data.page); |
1144 | + var secondColumn = findChild(testView, "ColumnHolder1"); |
1145 | + verify(secondColumn); |
1146 | + if (data.failMsg != "") { |
1147 | + expectFail(data.tag, "Fail"); |
1148 | + } |
1149 | + verify(secondColumn.pageWrapper); |
1150 | + } |
1151 | + |
1152 | + function test_invalid_column() { |
1153 | + ignoreWarning("There must me a minimum of one column set."); |
1154 | + defaults.columns = 0; |
1155 | + } |
1156 | + |
1157 | + function test_change_primaryPage() { |
1158 | + ignoreWarning("Cannot change primaryPage after completion."); |
1159 | + testView.primaryPage = page3; |
1160 | + } |
1161 | + |
1162 | + function test_add_to_same_column_when_source_page_not_in_stack() { |
1163 | + ignoreWarning("sourcePage must be added to the view to add new page."); |
1164 | + testView.addPageToCurrentColumn(page2, page3); |
1165 | + } |
1166 | + |
1167 | + function test_add_to_next_column_when_source_page_not_in_stack() { |
1168 | + ignoreWarning("sourcePage must be added to the view to add new page."); |
1169 | + testView.addPageToNextColumn(page2, page3); |
1170 | + } |
1171 | + } |
1172 | +} |
FAILED: Continuous integration, rev:1536 jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- ci/1886/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- vivid-touch/ 3192/console jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-amd64- ci/614/ console jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-armhf- ci/616/ console jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-i386- ci/613/ console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 3190/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/ubuntu- sdk-team- ubuntu- ui-toolkit- staging- ci/1886/ rebuild
http://