Merge lp:~tpeeters/ubuntu-ui-toolkit/tabfix into lp:ubuntu-ui-toolkit
- tabfix
- Merge into trunk
Status: | Merged | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Approved by: | Zsombor Egri | ||||||||||||||||
Approved revision: | 469 | ||||||||||||||||
Merged at revision: | 480 | ||||||||||||||||
Proposed branch: | lp:~tpeeters/ubuntu-ui-toolkit/tabfix | ||||||||||||||||
Merge into: | lp:ubuntu-ui-toolkit | ||||||||||||||||
Diff against target: |
483 lines (+236/-83) 6 files modified
modules/Ubuntu/Components/Tab.qml (+2/-0) modules/Ubuntu/Components/Tabs.qml (+50/-11) tests/resources/tabs/MyCustomPage.qml (+50/-0) tests/resources/tabs/Tabs.qml (+99/-0) themes/Ambiance/qmltheme/NewTabBar.qml (+30/-19) themes/Ambiance/qmltheme/NewTabsDelegate.qml (+5/-53) |
||||||||||||||||
To merge this branch: | bzr merge lp:~tpeeters/ubuntu-ui-toolkit/tabfix | ||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Zsombor Egri | Approve | ||
Review via email: mp+161902@code.launchpad.net |
Commit message
Remove VisualItemModel from Tabs internals, and make it work with a Repeater to define the tabs.
Description of the change
Remove VisualItemModel from Tabs internals, and make it work with a Repeater to define the tabs.
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:457
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:458
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:460
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:461
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:463
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:464
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Zsombor Egri (zsombi) wrote : | # |
You have not documented the Repeater limitation in the Tabs.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:467
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
Unapproved changes made after approval.
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:469
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'modules/Ubuntu/Components/Tab.qml' | |||
2 | --- modules/Ubuntu/Components/Tab.qml 2013-04-03 12:21:17 +0000 | |||
3 | +++ modules/Ubuntu/Components/Tab.qml 2013-05-07 11:26:29 +0000 | |||
4 | @@ -59,4 +59,6 @@ | |||
5 | 59 | */ | 59 | */ |
6 | 60 | active: parentNode && parentNode.active && | 60 | active: parentNode && parentNode.active && |
7 | 61 | parentNode.hasOwnProperty("selectedTab") && parentNode.selectedTab === tab | 61 | parentNode.hasOwnProperty("selectedTab") && parentNode.selectedTab === tab |
8 | 62 | |||
9 | 63 | visible: active | ||
10 | 62 | } | 64 | } |
11 | 63 | 65 | ||
12 | === modified file 'modules/Ubuntu/Components/Tabs.qml' | |||
13 | --- modules/Ubuntu/Components/Tabs.qml 2013-04-08 13:32:34 +0000 | |||
14 | +++ modules/Ubuntu/Components/Tabs.qml 2013-05-07 11:26:29 +0000 | |||
15 | @@ -90,6 +90,10 @@ | |||
16 | 90 | 90 | ||
17 | 91 | \endqml | 91 | \endqml |
18 | 92 | As the example above shows, an external \l Page inside a \l Tab can be loaded using a Loader. | 92 | As the example above shows, an external \l Page inside a \l Tab can be loaded using a Loader. |
19 | 93 | |||
20 | 94 | It is possible to use a Repeater to generate tabs, but when doing so, ensure that the Repeater | ||
21 | 95 | is declared inside the Tabs at the end, because otherwise the shuffling of | ||
22 | 96 | the order of children by the Repeater can cause incorrect ordering of the tabs. | ||
23 | 93 | */ | 97 | */ |
24 | 94 | 98 | ||
25 | 95 | PageTreeNode { | 99 | PageTreeNode { |
26 | @@ -104,13 +108,13 @@ | |||
27 | 104 | The first tab is 0, and -1 means that no tab is selected. | 108 | The first tab is 0, and -1 means that no tab is selected. |
28 | 105 | The initial value is 0 if Tabs has contents, or -1 otherwise. | 109 | The initial value is 0 if Tabs has contents, or -1 otherwise. |
29 | 106 | */ | 110 | */ |
31 | 107 | property int selectedTabIndex: tabsModel.count > 0 ? 0 : -1 | 111 | property int selectedTabIndex: tabs.__tabs.length > 0 ? 0 : -1 |
32 | 108 | 112 | ||
33 | 109 | /*! | 113 | /*! |
34 | 110 | \preliminary | 114 | \preliminary |
35 | 111 | The currently selected tab. | 115 | The currently selected tab. |
36 | 112 | */ | 116 | */ |
38 | 113 | readonly property Tab selectedTab: (selectedTabIndex < 0) || (tabsModel.count <= selectedTabIndex) ? | 117 | readonly property Tab selectedTab: (selectedTabIndex < 0) || (__tabs.length <= selectedTabIndex) ? |
39 | 114 | null : __tabs[selectedTabIndex] | 118 | null : __tabs[selectedTabIndex] |
40 | 115 | 119 | ||
41 | 116 | /*! | 120 | /*! |
42 | @@ -139,21 +143,56 @@ | |||
43 | 139 | "Pages will automatically update the toolbar when activated. "+ | 143 | "Pages will automatically update the toolbar when activated. "+ |
44 | 140 | "See CHANGES file, and use toolbar.tools instead when needed."); | 144 | "See CHANGES file, and use toolbar.tools instead when needed."); |
45 | 141 | 145 | ||
53 | 142 | 146 | /*! | |
54 | 143 | // FIXME: Using the VisualItemModel as a workaround for this bug: | 147 | \internal |
55 | 144 | // "theming: contentItem does work when it is a VisualItemModel" | 148 | Used by the delegate to create the tabs header. |
56 | 145 | // https://bugs.launchpad.net/tavastia/+bug/1080330 | 149 | */ |
57 | 146 | // The workaround does not break the regular TabsDelegate. | 150 | property alias __tabs: tabsModel.tabList |
58 | 147 | /*! \internal */ | 151 | |
59 | 148 | default property alias __tabs: tabsModel.children | 152 | /*! |
60 | 153 | Children are placed in a separate item that has functionality to extract the Tab items. | ||
61 | 154 | \qmlproperty list<Item> tabChildren | ||
62 | 155 | */ | ||
63 | 156 | default property alias tabChildren: tabsModel.children | ||
64 | 157 | |||
65 | 158 | /*! | ||
66 | 159 | Used by the tabs delegate to update the tabs header with the titles of all the tabs. | ||
67 | 160 | This signal is used in an intermediate step in transitioning the tabs to a new | ||
68 | 161 | implementation and may be removed in the future. | ||
69 | 162 | */ | ||
70 | 163 | signal modelChanged() | ||
71 | 149 | 164 | ||
72 | 150 | /*! | 165 | /*! |
73 | 151 | \internal | 166 | \internal |
74 | 152 | required by NewTabsDelegate | 167 | required by NewTabsDelegate |
75 | 153 | */ | 168 | */ |
78 | 154 | property alias __tabsModel: tabsModel | 169 | Item { |
79 | 155 | VisualItemModel { | 170 | anchors.fill: parent |
80 | 156 | id: tabsModel | 171 | id: tabsModel |
81 | 172 | |||
82 | 173 | property var tabList: [] | ||
83 | 174 | onChildrenChanged: { | ||
84 | 175 | updateTabList(); | ||
85 | 176 | } | ||
86 | 177 | |||
87 | 178 | function updateTabList() { | ||
88 | 179 | var list = []; | ||
89 | 180 | for (var i=0; i < children.length; i++) { | ||
90 | 181 | if (isTab(tabsModel.children[i])) list.push(tabsModel.children[i]); | ||
91 | 182 | } | ||
92 | 183 | tabList = list; | ||
93 | 184 | tabs.modelChanged(); | ||
94 | 185 | } | ||
95 | 186 | |||
96 | 187 | function isTab(item) { | ||
97 | 188 | if (item && item.hasOwnProperty("__isPageTreeNode") | ||
98 | 189 | && item.__isPageTreeNode && item.hasOwnProperty("title") | ||
99 | 190 | && item.hasOwnProperty("page")) { | ||
100 | 191 | return true; | ||
101 | 192 | } else { | ||
102 | 193 | return false; | ||
103 | 194 | } | ||
104 | 195 | } | ||
105 | 157 | } | 196 | } |
106 | 158 | 197 | ||
107 | 159 | /*! \internal */ | 198 | /*! \internal */ |
108 | 160 | 199 | ||
109 | === added directory 'tests/resources/tabs' | |||
110 | === added file 'tests/resources/tabs/MyCustomPage.qml' | |||
111 | --- tests/resources/tabs/MyCustomPage.qml 1970-01-01 00:00:00 +0000 | |||
112 | +++ tests/resources/tabs/MyCustomPage.qml 2013-05-07 11:26:29 +0000 | |||
113 | @@ -0,0 +1,50 @@ | |||
114 | 1 | /* | ||
115 | 2 | * Copyright 2012 Canonical Ltd. | ||
116 | 3 | * | ||
117 | 4 | * This program is free software; you can redistribute it and/or modify | ||
118 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
119 | 6 | * the Free Software Foundation; version 3. | ||
120 | 7 | * | ||
121 | 8 | * This program is distributed in the hope that it will be useful, | ||
122 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
123 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
124 | 11 | * GNU Lesser General Public License for more details. | ||
125 | 12 | * | ||
126 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
127 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
128 | 15 | */ | ||
129 | 16 | |||
130 | 17 | import QtQuick 2.0 | ||
131 | 18 | import Ubuntu.Components 0.1 | ||
132 | 19 | |||
133 | 20 | Page { | ||
134 | 21 | title: i18n.tr("My custom page") | ||
135 | 22 | |||
136 | 23 | Flickable { | ||
137 | 24 | anchors.fill: parent | ||
138 | 25 | contentHeight: parent.height + units.gu(10) | ||
139 | 26 | Label { | ||
140 | 27 | anchors { | ||
141 | 28 | top: parent.top | ||
142 | 29 | topMargin: units.gu(16) | ||
143 | 30 | horizontalCenter: parent.horizontalCenter | ||
144 | 31 | } | ||
145 | 32 | |||
146 | 33 | text: i18n.tr("This is an external page\nwith a locked toolbar.") | ||
147 | 34 | color: "#757373" | ||
148 | 35 | } | ||
149 | 36 | } | ||
150 | 37 | |||
151 | 38 | tools: ToolbarActions { | ||
152 | 39 | Action { | ||
153 | 40 | text: "action 1" | ||
154 | 41 | iconSource: Qt.resolvedUrl("call_icon.png") | ||
155 | 42 | } | ||
156 | 43 | Action { | ||
157 | 44 | text: "action 2" | ||
158 | 45 | iconSource: Qt.resolvedUrl("call_icon.png") | ||
159 | 46 | } | ||
160 | 47 | opened: true | ||
161 | 48 | locked: true | ||
162 | 49 | } | ||
163 | 50 | } | ||
164 | 0 | 51 | ||
165 | === added file 'tests/resources/tabs/Tabs.qml' | |||
166 | --- tests/resources/tabs/Tabs.qml 1970-01-01 00:00:00 +0000 | |||
167 | +++ tests/resources/tabs/Tabs.qml 2013-05-07 11:26:29 +0000 | |||
168 | @@ -0,0 +1,99 @@ | |||
169 | 1 | /* | ||
170 | 2 | * Copyright 2012 Canonical Ltd. | ||
171 | 3 | * | ||
172 | 4 | * This program is free software; you can redistribute it and/or modify | ||
173 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
174 | 6 | * the Free Software Foundation; version 3. | ||
175 | 7 | * | ||
176 | 8 | * This program is distributed in the hope that it will be useful, | ||
177 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
178 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
179 | 11 | * GNU Lesser General Public License for more details. | ||
180 | 12 | * | ||
181 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
182 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
183 | 15 | */ | ||
184 | 16 | |||
185 | 17 | import QtQuick 2.0 | ||
186 | 18 | import Ubuntu.Components 0.1 | ||
187 | 19 | import Ubuntu.Components.ListItems 0.1 as ListItem | ||
188 | 20 | |||
189 | 21 | MainView { | ||
190 | 22 | width: 800 | ||
191 | 23 | height: 600 | ||
192 | 24 | Tabs { | ||
193 | 25 | id: tabs | ||
194 | 26 | selectedTabIndex: 0 | ||
195 | 27 | Item { | ||
196 | 28 | // does this mess up stuff? nope. | ||
197 | 29 | } | ||
198 | 30 | |||
199 | 31 | Tab { | ||
200 | 32 | title: i18n.tr("Simple page") | ||
201 | 33 | page: Page { | ||
202 | 34 | Label { | ||
203 | 35 | id: label | ||
204 | 36 | anchors.centerIn: parent | ||
205 | 37 | text: "A centered label" | ||
206 | 38 | } | ||
207 | 39 | tools: ToolbarActions { | ||
208 | 40 | Action { | ||
209 | 41 | text: "action" | ||
210 | 42 | iconSource: "call_icon.png" | ||
211 | 43 | onTriggered: print("action triggered") | ||
212 | 44 | } | ||
213 | 45 | } | ||
214 | 46 | } | ||
215 | 47 | } | ||
216 | 48 | Repeater { | ||
217 | 49 | model: 3 | ||
218 | 50 | Tab { | ||
219 | 51 | title: "Extra " + index | ||
220 | 52 | page: Page { | ||
221 | 53 | Column { | ||
222 | 54 | anchors.centerIn: parent | ||
223 | 55 | width: units.gu(40) | ||
224 | 56 | Label { | ||
225 | 57 | anchors { | ||
226 | 58 | left: parent.left | ||
227 | 59 | right: parent.right | ||
228 | 60 | } | ||
229 | 61 | text: "Extra tab number "+index | ||
230 | 62 | } | ||
231 | 63 | Button { | ||
232 | 64 | anchors { | ||
233 | 65 | left: parent.left | ||
234 | 66 | right: parent.right | ||
235 | 67 | } | ||
236 | 68 | text: "Previous" | ||
237 | 69 | onClicked: if (tabs.selectedTabIndex > 0) tabs.selectedTabIndex-- | ||
238 | 70 | } | ||
239 | 71 | } | ||
240 | 72 | } | ||
241 | 73 | } | ||
242 | 74 | } | ||
243 | 75 | Tab { | ||
244 | 76 | id: externalTab | ||
245 | 77 | title: i18n.tr("External") | ||
246 | 78 | page: Loader { | ||
247 | 79 | parent: externalTab | ||
248 | 80 | anchors.fill: parent | ||
249 | 81 | source: (tabs.selectedTab === externalTab) ? Qt.resolvedUrl("MyCustomPage.qml") : "" | ||
250 | 82 | } | ||
251 | 83 | } | ||
252 | 84 | Tab { | ||
253 | 85 | title: i18n.tr("List view") | ||
254 | 86 | page: Page { | ||
255 | 87 | ListView { | ||
256 | 88 | clip: true | ||
257 | 89 | anchors.fill: parent | ||
258 | 90 | model: 20 | ||
259 | 91 | delegate: ListItem.Standard { | ||
260 | 92 | icon: Qt.resolvedUrl("call_icon.png") | ||
261 | 93 | text: "Item "+modelData | ||
262 | 94 | } | ||
263 | 95 | } | ||
264 | 96 | } | ||
265 | 97 | } | ||
266 | 98 | } | ||
267 | 99 | } | ||
268 | 0 | 100 | ||
269 | === added file 'tests/resources/tabs/call_icon@8.png' | |||
270 | 1 | Binary files tests/resources/tabs/call_icon@8.png 1970-01-01 00:00:00 +0000 and tests/resources/tabs/call_icon@8.png 2013-05-07 11:26:29 +0000 differ | 101 | Binary files tests/resources/tabs/call_icon@8.png 1970-01-01 00:00:00 +0000 and tests/resources/tabs/call_icon@8.png 2013-05-07 11:26:29 +0000 differ |
271 | === modified file 'themes/Ambiance/qmltheme/NewTabBar.qml' | |||
272 | --- themes/Ambiance/qmltheme/NewTabBar.qml 2013-05-02 00:57:01 +0000 | |||
273 | +++ themes/Ambiance/qmltheme/NewTabBar.qml 2013-05-07 11:26:29 +0000 | |||
274 | @@ -66,6 +66,7 @@ | |||
275 | 66 | Connections { | 66 | Connections { |
276 | 67 | target: tabs | 67 | target: tabs |
277 | 68 | onSelectedTabIndexChanged: buttonView.selectButton(tabs.selectedTabIndex) | 68 | onSelectedTabIndexChanged: buttonView.selectButton(tabs.selectedTabIndex) |
278 | 69 | onModelChanged: buttonView.selectButton(tabs.selectedTabIndex) | ||
279 | 69 | } | 70 | } |
280 | 70 | 71 | ||
281 | 71 | Component { | 72 | Component { |
282 | @@ -79,9 +80,17 @@ | |||
283 | 79 | width: childrenRect.width | 80 | width: childrenRect.width |
284 | 80 | property int rowNumber: modelData | 81 | property int rowNumber: modelData |
285 | 81 | 82 | ||
286 | 83 | Component.onCompleted: { | ||
287 | 84 | if (rowNumber === 0) { | ||
288 | 85 | buttonView.buttonRow1 = theRow; | ||
289 | 86 | } else { | ||
290 | 87 | buttonView.buttonRow2 = theRow; | ||
291 | 88 | } | ||
292 | 89 | } | ||
293 | 90 | |||
294 | 82 | Repeater { | 91 | Repeater { |
295 | 83 | id: repeater | 92 | id: repeater |
297 | 84 | model: tabs.__tabsModel.children | 93 | model: tabs.__tabs |
298 | 85 | 94 | ||
299 | 86 | AbstractButton { | 95 | AbstractButton { |
300 | 87 | id: button | 96 | id: button |
301 | @@ -97,7 +106,6 @@ | |||
302 | 97 | property bool selected: (tabBar.active && buttonView.needsScrolling) ? tabs.selectedTabIndex === index : buttonView.selectedButtonIndex === button.buttonIndex | 106 | property bool selected: (tabBar.active && buttonView.needsScrolling) ? tabs.selectedTabIndex === index : buttonView.selectedButtonIndex === button.buttonIndex |
303 | 98 | property real offset: theRow.rowNumber + 1 - button.x / theRow.width; | 107 | property real offset: theRow.rowNumber + 1 - button.x / theRow.width; |
304 | 99 | property int buttonIndex: index + theRow.rowNumber*repeater.count | 108 | property int buttonIndex: index + theRow.rowNumber*repeater.count |
305 | 100 | Component.onCompleted: buttonView.buttons.push(button) | ||
306 | 101 | 109 | ||
307 | 102 | // Use opacity 0 to hide instead of setting visibility to false in order to | 110 | // Use opacity 0 to hide instead of setting visibility to false in order to |
308 | 103 | // make fading work well, and not to mess up width/offset computations | 111 | // make fading work well, and not to mess up width/offset computations |
309 | @@ -109,7 +117,7 @@ | |||
310 | 109 | 117 | ||
311 | 110 | // When we don't need scrolling, we want to avoid showing a button that is fading | 118 | // When we don't need scrolling, we want to avoid showing a button that is fading |
312 | 111 | // while sliding in from the right side when a new button was selected | 119 | // while sliding in from the right side when a new button was selected |
314 | 112 | var numTabs = tabs.__tabsModel.count; | 120 | var numTabs = tabs.__tabs.length; |
315 | 113 | var minimum = buttonView.selectedButtonIndex; | 121 | var minimum = buttonView.selectedButtonIndex; |
316 | 114 | var maximum = buttonView.selectedButtonIndex + numTabs - 1; | 122 | var maximum = buttonView.selectedButtonIndex + numTabs - 1; |
317 | 115 | if (MathUtils.clamp(buttonIndex, minimum, maximum) === buttonIndex) return true; | 123 | if (MathUtils.clamp(buttonIndex, minimum, maximum) === buttonIndex) return true; |
318 | @@ -176,7 +184,7 @@ | |||
319 | 176 | // Select this button | 184 | // Select this button |
320 | 177 | function select() { | 185 | function select() { |
321 | 178 | buttonView.selectedButtonIndex = button.buttonIndex; | 186 | buttonView.selectedButtonIndex = button.buttonIndex; |
323 | 179 | buttonView.updateOffset(); | 187 | buttonView.updateOffset(button.offset); |
324 | 180 | } | 188 | } |
325 | 181 | } | 189 | } |
326 | 182 | } | 190 | } |
327 | @@ -192,12 +200,14 @@ | |||
328 | 192 | } | 200 | } |
329 | 193 | 201 | ||
330 | 194 | // set to the width of one tabButtonRow in Component.onCompleted. | 202 | // set to the width of one tabButtonRow in Component.onCompleted. |
332 | 195 | property real buttonRowWidth | 203 | property real buttonRowWidth: buttonRow1 ? buttonRow1.width : 0 |
333 | 196 | 204 | ||
335 | 197 | property var buttons: [] | 205 | // set by the delegate when the components are completed. |
336 | 206 | property Row buttonRow1 | ||
337 | 207 | property Row buttonRow2 | ||
338 | 198 | 208 | ||
339 | 199 | // Track which button was last clicked | 209 | // Track which button was last clicked |
341 | 200 | property int selectedButtonIndex: 0 | 210 | property int selectedButtonIndex: -1 |
342 | 201 | 211 | ||
343 | 202 | delegate: tabButtonRow | 212 | delegate: tabButtonRow |
344 | 203 | model: 2 // The second buttonRow shows the buttons that disappear on the left | 213 | model: 2 // The second buttonRow shows the buttons that disappear on the left |
345 | @@ -222,21 +232,23 @@ | |||
346 | 222 | 232 | ||
347 | 223 | // Select the closest of the two buttons that represent the given tab index | 233 | // Select the closest of the two buttons that represent the given tab index |
348 | 224 | function selectButton(tabIndex) { | 234 | function selectButton(tabIndex) { |
351 | 225 | var b1 = buttons[tabIndex]; | 235 | if (tabIndex < 0 || tabIndex >= tabs.__tabs.length) return; |
352 | 226 | var b2 = buttons[tabIndex + tabs.__tabsModel.children.length]; | 236 | if (buttonView.buttonRow1 && buttonView.buttonRow2) { |
353 | 237 | var b1 = buttonView.buttonRow1.children[tabIndex]; | ||
354 | 238 | var b2 = buttonView.buttonRow2.children[tabIndex]; | ||
355 | 227 | 239 | ||
363 | 228 | // find the button with the nearest offset | 240 | // find the button with the nearest offset |
364 | 229 | var d1 = cyclicDistance(b1.offset, buttonView.offset, 2); | 241 | var d1 = cyclicDistance(b1.offset, buttonView.offset, 2); |
365 | 230 | var d2 = cyclicDistance(b2.offset, buttonView.offset, 2); | 242 | var d2 = cyclicDistance(b2.offset, buttonView.offset, 2); |
366 | 231 | if (d1 < d2) { | 243 | if (d1 < d2) { |
367 | 232 | b1.select(); | 244 | b1.select(); |
368 | 233 | } else { | 245 | } else { |
369 | 234 | b2.select(); | 246 | b2.select(); |
370 | 247 | } | ||
371 | 235 | } | 248 | } |
372 | 236 | } | 249 | } |
373 | 237 | 250 | ||
376 | 238 | function updateOffset() { | 251 | function updateOffset(newOffset) { |
375 | 239 | var newOffset = buttonView.buttons[buttonView.selectedButtonIndex].offset; | ||
377 | 240 | if (offset - newOffset < -1) newOffset = newOffset - 2; | 252 | if (offset - newOffset < -1) newOffset = newOffset - 2; |
378 | 241 | offset = newOffset; | 253 | offset = newOffset; |
379 | 242 | } | 254 | } |
380 | @@ -250,7 +262,6 @@ | |||
381 | 250 | 262 | ||
382 | 251 | Component.onCompleted: { | 263 | Component.onCompleted: { |
383 | 252 | selectButton(tabs.selectedTabIndex); | 264 | selectButton(tabs.selectedTabIndex); |
384 | 253 | buttonRowWidth = currentItem.width; | ||
385 | 254 | } | 265 | } |
386 | 255 | 266 | ||
387 | 256 | onDragEnded: activatingTimer.stop() | 267 | onDragEnded: activatingTimer.stop() |
388 | 257 | 268 | ||
389 | === modified file 'themes/Ambiance/qmltheme/NewTabsDelegate.qml' | |||
390 | --- themes/Ambiance/qmltheme/NewTabsDelegate.qml 2013-04-30 23:55:32 +0000 | |||
391 | +++ themes/Ambiance/qmltheme/NewTabsDelegate.qml 2013-05-07 11:26:29 +0000 | |||
392 | @@ -32,22 +32,23 @@ | |||
393 | 32 | the next/previous tab. | 32 | the next/previous tab. |
394 | 33 | */ | 33 | */ |
395 | 34 | property bool swipeToSwitchTabs | 34 | property bool swipeToSwitchTabs |
397 | 35 | onSwipeToSwitchTabsChanged: print("swipeToSwitchTabs property is DEPRECATED. Please do not rely on swiping the Page's contents to switch tabs, this functionality will be removed.") | 35 | /*! |
398 | 36 | \deprecated | ||
399 | 37 | \internal | ||
400 | 38 | */ | ||
401 | 39 | onSwipeToSwitchTabsChanged: print("swipeToSwitchTabs property is DEPRECATED.") | ||
402 | 36 | 40 | ||
403 | 37 | property color headerTextColor | 41 | property color headerTextColor |
404 | 38 | property color headerTextSelectedColor | 42 | property color headerTextSelectedColor |
405 | 39 | property real headerTextOpacity | 43 | property real headerTextOpacity |
406 | 40 | property real headerTextSelectedOpacity | 44 | property real headerTextSelectedOpacity |
407 | 41 | |||
408 | 42 | property int headerTextFadeDuration | 45 | property int headerTextFadeDuration |
409 | 43 | property string headerFontSize | 46 | property string headerFontSize |
410 | 44 | property int headerFontWeight | 47 | property int headerFontWeight |
411 | 45 | property real headerTextLeftMargin | 48 | property real headerTextLeftMargin |
412 | 46 | property real headerTextRightMargin | 49 | property real headerTextRightMargin |
413 | 47 | property real headerTextBottomMargin | 50 | property real headerTextBottomMargin |
414 | 48 | |||
415 | 49 | property url indicatorImageSource | 51 | property url indicatorImageSource |
416 | 50 | |||
417 | 51 | property real tabBarHeight | 52 | property real tabBarHeight |
418 | 52 | 53 | ||
419 | 53 | /*! | 54 | /*! |
420 | @@ -64,8 +65,6 @@ | |||
421 | 64 | id: tabsDelegate | 65 | id: tabsDelegate |
422 | 65 | anchors.fill: parent | 66 | anchors.fill: parent |
423 | 66 | 67 | ||
424 | 67 | property VisualItemModel tabModel: item.__tabsModel | ||
425 | 68 | |||
426 | 69 | // use theTabs property because item gives problems in the loader | 68 | // use theTabs property because item gives problems in the loader |
427 | 70 | property Tabs theTabs: item | 69 | property Tabs theTabs: item |
428 | 71 | property Component headerContents: Component { | 70 | property Component headerContents: Component { |
429 | @@ -94,54 +93,7 @@ | |||
430 | 94 | } | 93 | } |
431 | 95 | } | 94 | } |
432 | 96 | 95 | ||
433 | 97 | ListView { | ||
434 | 98 | id: tabView | ||
435 | 99 | anchors.fill: parent | ||
436 | 100 | |||
437 | 101 | interactive: tabsDelegate.swipeToSwitchTabs | ||
438 | 102 | model: tabsDelegate.tabModel | ||
439 | 103 | onModelChanged: tabView.updatePages() | ||
440 | 104 | currentIndex: item.selectedTabIndex | ||
441 | 105 | onCurrentIndexChanged: if (item.__tabsModel.count > 0) item.selectedTabIndex = tabView.currentIndex | ||
442 | 106 | |||
443 | 107 | orientation: ListView.Horizontal | ||
444 | 108 | snapMode: ListView.SnapOneItem | ||
445 | 109 | boundsBehavior: Flickable.DragOverBounds | ||
446 | 110 | highlightFollowsCurrentItem: true | ||
447 | 111 | highlightRangeMode: ListView.StrictlyEnforceRange | ||
448 | 112 | |||
449 | 113 | function updatePages() { | ||
450 | 114 | if (!tabsDelegate.tabModel) return; // not initialized yet | ||
451 | 115 | |||
452 | 116 | var tabList = tabsDelegate.tabModel.children | ||
453 | 117 | var tab; | ||
454 | 118 | for (var i=0; i < tabList.length; i++) { | ||
455 | 119 | tab = tabList[i]; | ||
456 | 120 | tab.anchors.fill = undefined; | ||
457 | 121 | tab.width = tabView.width; | ||
458 | 122 | tab.height = tabView.height | ||
459 | 123 | } | ||
460 | 124 | tabView.updateSelectedTabIndex(); | ||
461 | 125 | } | ||
462 | 126 | |||
463 | 127 | function updateSelectedTabIndex() { | ||
464 | 128 | if (tabView.currentIndex === item.selectedTabIndex) return; | ||
465 | 129 | // The view is automatically updated, because highlightFollowsCurrentItem | ||
466 | 130 | tabView.currentIndex = item.selectedTabIndex; | ||
467 | 131 | } | ||
468 | 132 | } | ||
469 | 133 | |||
470 | 134 | Connections { | ||
471 | 135 | target: item | ||
472 | 136 | onSelectedTabIndexChanged: { | ||
473 | 137 | tabView.updateSelectedTabIndex(); | ||
474 | 138 | } | ||
475 | 139 | } | ||
476 | 140 | |||
477 | 141 | onWidthChanged: tabView.updatePages(); | ||
478 | 142 | onHeightChanged: tabView.updatePages(); | ||
479 | 143 | Component.onCompleted: { | 96 | Component.onCompleted: { |
480 | 144 | item.__headerContents = headerContents; | 97 | item.__headerContents = headerContents; |
481 | 145 | tabView.updatePages(); | ||
482 | 146 | } | 98 | } |
483 | 147 | } | 99 | } |
FAILED: Continuous integration, rev:455 /code.launchpad .net/~tpeeters/ ubuntu- ui-toolkit/ tabfix/ +merge/ 161902/ +edit-commit- message
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
http:// jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- ci/1112/ jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- ci/./build= panda-pbuilder, distribution= quantal, flavor= armhf/1112 jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- ci/./build= pbuilder- master, distribution= quantal, flavor= amd64/1112 jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- ci/./build= pbuilder- master, distribution= quantal, flavor= i386/1112
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ ubuntu- ui-toolkit- ci/1112/ rebuild
http://