Merge lp:~zsombi/ubuntu-ui-toolkit/dynamic-tabs-reloaded into lp:ubuntu-ui-toolkit
- dynamic-tabs-reloaded
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~zsombi/ubuntu-ui-toolkit/dynamic-tabs-reloaded |
Merge into: | lp:ubuntu-ui-toolkit |
Diff against target: |
1137 lines (+767/-49) 14 files modified
CHANGES (+1/-0) components.api (+8/-1) modules/Ubuntu/Components/Tab.qml (+0/-7) modules/Ubuntu/Components/Tabs.qml (+292/-20) modules/Ubuntu/Components/Themes/Ambiance/TabBarStyle.qml (+9/-2) modules/Ubuntu/Components/plugin/quickutils.cpp (+15/-0) modules/Ubuntu/Components/plugin/quickutils.h (+1/-0) modules/Ubuntu/Test/UbuntuTestCase.qml (+69/-1) modules/Ubuntu/Test/deployment.pri (+6/-1) tests/resources/navigation/Tabs.qml (+90/-1) tests/unit/runtest.sh (+1/-1) tests/unit_x11/tst_components/ExternalTab.qml (+21/-0) tests/unit_x11/tst_components/tst_tabs.qml (+151/-0) tests/unit_x11/tst_test/tst_ubuntutestcase.qml (+103/-15) |
To merge this branch: | bzr merge lp:~zsombi/ubuntu-ui-toolkit/dynamic-tabs-reloaded |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Tim Peeters | Approve | ||
Cris Dywan | provided moveitembefore docs are fixed | Approve | |
Review via email: mp+199620@code.launchpad.net |
This proposal has been superseded by a proposal from 2014-04-10.
Commit message
Extending Tabs with functions to dynamically add, move and remove tabs.
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:901
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Tim Peeters (tpeeters) wrote : | # |
637 + * Copyright 2012 Canonical Ltd.
2013
Cris Dywan (kalikiana) wrote : | # |
I'm seeing a number of errors while using the tabbar test:
modules/
coming from connectToRepeaters
modules/
coming from insertTab
modules/
coming from anchors.top on the Repeater, not sure what this is
Cris Dywan (kalikiana) wrote : | # |
I'm liking the documentation which is quite decent. I love that the API keeps the different types of tabs behind the scenes.
> // but move only if there are more than on eitems in the list
Typo.
// QQuickItem *parentItem = item->parentItem();
Please remove this one.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:902
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:902
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Zsombor Egri (zsombi) wrote : | # |
> 637 + * Copyright 2012 Canonical Ltd.
>
> 2013
It's 2014 now :)
Zsombor Egri (zsombi) wrote : | # |
> I'm liking the documentation which is quite decent. I love that the API keeps
> the different types of tabs behind the scenes.
>
> > // but move only if there are more than on eitems in the list
> Typo.
>
> // QQuickItem *parentItem = item->parentItem();
> Please remove this one.
Fixed in revno 903
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:903
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:904
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Tim Peeters (tpeeters) wrote : | # |
+/*!
463 + * \internal
464 + * Moves a given item to the specified index in its parent's child list.
465 + */
466 +void QuickUtils:
description doesn't exactly match the function specs.
* Moves a given item before the specified item in their parent's child list
?
Cris Dywan (kalikiana) wrote : | # |
That one escaped me; I'll give green light with the above sentence fixed.
Cris Dywan (kalikiana) wrote : | # |
CI@HOME OK http://
Tim Peeters (tpeeters) wrote : | # |
note that you didn't fix the doc yet
Tim Peeters (tpeeters) wrote : | # |
I changed the status back to needs review, because we need to re-do the CI@home with qt52.
Zsombor Egri (zsombi) wrote : | # |
> note that you didn't fix the doc yet
Sorry, done now.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:906
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Tim Peeters (tpeeters) wrote : | # |
> modules/
> defined
This is still broken. Please add the include in Tabs.qml.
Tim Peeters (tpeeters) wrote : | # |
> I'm seeing a number of errors while using the tabbar test:
>
> modules/
> 'indexOf' of undefined
> coming from connectToRepeaters
> modules/
> defined
> coming from insertTab
> modules/
> Cannot read property of null
> coming from anchors.top on the Repeater, not sure what this is
please double-check that all these are fixed
Zsombor Egri (zsombi) wrote : | # |
>
> > modules/
> > defined
>
> This is still broken. Please add the include in Tabs.qml.
I'm wondering why was it passing till now???
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:907
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:908
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:909
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:911
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
ABORTED: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:911
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:912
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 913. By Zsombor Egri
-
staging merge
Unmerged revisions
Preview Diff
1 | === modified file 'CHANGES' | |||
2 | --- CHANGES 2014-02-24 22:03:55 +0000 | |||
3 | +++ CHANGES 2014-04-10 11:34:46 +0000 | |||
4 | @@ -9,6 +9,7 @@ | |||
5 | 9 | 9 | ||
6 | 10 | API Changes | 10 | API Changes |
7 | 11 | *********** | 11 | *********** |
8 | 12 | * DEPRECATED IN: Tabs: default property list<Item> tabChildren | ||
9 | 12 | * ADDED IN: PickerDelegate: readonly property Picker picker | 13 | * ADDED IN: PickerDelegate: readonly property Picker picker |
10 | 13 | * CHANGED IN: OptionSelector: readonly property bool currentlyExpanded TO property bool currentlyExpanded | 14 | * CHANGED IN: OptionSelector: readonly property bool currentlyExpanded TO property bool currentlyExpanded |
11 | 14 | * CHANGED IN: ItemSelector: readonly property bool currentlyExpanded TO property bool currentlyExpanded | 15 | * CHANGED IN: ItemSelector: readonly property bool currentlyExpanded TO property bool currentlyExpanded |
12 | 15 | 16 | ||
13 | === modified file 'components.api' | |||
14 | --- components.api 2014-04-01 12:57:27 +0000 | |||
15 | +++ components.api 2014-04-10 11:34:46 +0000 | |||
16 | @@ -417,9 +417,14 @@ | |||
17 | 417 | readonly property Tab selectedTab | 417 | readonly property Tab selectedTab |
18 | 418 | readonly property Item currentPage | 418 | readonly property Item currentPage |
19 | 419 | property TabBar tabBar | 419 | property TabBar tabBar |
21 | 420 | default property list<Item> tabChildren | 420 | property list<Item> tabChildren |
22 | 421 | readonly property int count | 421 | readonly property int count |
23 | 422 | signal modelChanged() | 422 | signal modelChanged() |
24 | 423 | function addTab(title, tab) | ||
25 | 424 | function insertTab(index, title, tab) | ||
26 | 425 | function getTab(index) | ||
27 | 426 | function moveTab(from, to) | ||
28 | 427 | function removeTab(index) | ||
29 | 423 | modules/Ubuntu/Components/TextArea.qml | 428 | modules/Ubuntu/Components/TextArea.qml |
30 | 424 | StyledItem | 429 | StyledItem |
31 | 425 | property bool highlighted | 430 | property bool highlighted |
32 | @@ -593,6 +598,8 @@ | |||
33 | 593 | function findChild(obj,objectName) | 598 | function findChild(obj,objectName) |
34 | 594 | function findInvisibleChild(obj,objectName) | 599 | function findInvisibleChild(obj,objectName) |
35 | 595 | function mouseMoveSlowly(item,x,y,dx,dy,steps,stepdelay) | 600 | function mouseMoveSlowly(item,x,y,dx,dy,steps,stepdelay) |
36 | 601 | function flick(item, x, y, dx, dy, pressTimeout, steps, button, modifiers, delay) | ||
37 | 602 | function mouseLongPress(item, x, y, button, modifiers, delay) | ||
38 | 596 | function tryCompareFunction(func, expectedResult, timeout) | 603 | function tryCompareFunction(func, expectedResult, timeout) |
39 | 597 | plugins.qmltypes | 604 | plugins.qmltypes |
40 | 598 | name: "InverseMouseAreaType" | 605 | name: "InverseMouseAreaType" |
41 | 599 | 606 | ||
42 | === modified file 'modules/Ubuntu/Components/Tab.qml' | |||
43 | --- modules/Ubuntu/Components/Tab.qml 2013-11-07 07:26:01 +0000 | |||
44 | +++ modules/Ubuntu/Components/Tab.qml 2014-04-10 11:34:46 +0000 | |||
45 | @@ -105,12 +105,5 @@ | |||
46 | 105 | Tab is destroyed upon removal. | 105 | Tab is destroyed upon removal. |
47 | 106 | */ | 106 | */ |
48 | 107 | property bool dynamic: false | 107 | property bool dynamic: false |
49 | 108 | |||
50 | 109 | /* | ||
51 | 110 | This flag is used by the Tabs to determine whether the pre-declared Tab was removed | ||
52 | 111 | from the Tabs model or not. The flag guards adding back pre-declared tabs upon Tabs | ||
53 | 112 | component stack (children) change. | ||
54 | 113 | */ | ||
55 | 114 | property bool removedFromTabs: false | ||
56 | 115 | } | 108 | } |
57 | 116 | } | 109 | } |
58 | 117 | 110 | ||
59 | === modified file 'modules/Ubuntu/Components/Tabs.qml' | |||
60 | --- modules/Ubuntu/Components/Tabs.qml 2014-04-08 12:38:35 +0000 | |||
61 | +++ modules/Ubuntu/Components/Tabs.qml 2014-04-10 11:34:46 +0000 | |||
62 | @@ -15,6 +15,7 @@ | |||
63 | 15 | */ | 15 | */ |
64 | 16 | 16 | ||
65 | 17 | import QtQuick 2.0 | 17 | import QtQuick 2.0 |
66 | 18 | import "mathUtils.js" as MathUtils | ||
67 | 18 | 19 | ||
68 | 19 | /*! | 20 | /*! |
69 | 20 | \qmltype Tabs | 21 | \qmltype Tabs |
70 | @@ -149,6 +150,110 @@ | |||
71 | 149 | } | 150 | } |
72 | 150 | } | 151 | } |
73 | 151 | \endqml | 152 | \endqml |
74 | 153 | |||
75 | 154 | \section2 Dynamic tabs | ||
76 | 155 | So far all Tab elements were pre-declared, but there can be situations when | ||
77 | 156 | tabs need to be added dynamically. There are two ways to solve this, depending | ||
78 | 157 | on the output needed. | ||
79 | 158 | |||
80 | 159 | \section3 Using Repeaters | ||
81 | 160 | A Repeater can be used to create the necessary tabs depending on a given model. | ||
82 | 161 | In this way the number of tabs will be driven by the model itself. | ||
83 | 162 | An example of such a dynamic tab: | ||
84 | 163 | \qml | ||
85 | 164 | // DynamicTab.qml | ||
86 | 165 | import QtQuick 2.0 | ||
87 | 166 | import Ubuntu.Components 0.1 | ||
88 | 167 | |||
89 | 168 | Tabs { | ||
90 | 169 | property alias model: tabRepeater.model | ||
91 | 170 | Repeater { | ||
92 | 171 | id: tabRepeater | ||
93 | 172 | model: 5 | ||
94 | 173 | Tab { | ||
95 | 174 | title: "Tab #" + index | ||
96 | 175 | page: Page { | ||
97 | 176 | // [...] | ||
98 | 177 | } | ||
99 | 178 | } | ||
100 | 179 | } | ||
101 | 180 | } | ||
102 | 181 | \endqml | ||
103 | 182 | Note that in the example above the Tabs will be re-created each time the model | ||
104 | 183 | changes. This will cause state losing of each Tab, which depending on the | ||
105 | 184 | content type can be solved at some extent using StateSaver. Using a Loader | ||
106 | 185 | or specifying the Tab instance/component in the model the state can be preserved, | ||
107 | 186 | however may increase code complexity. | ||
108 | 187 | |||
109 | 188 | \section3 Dynamic tabs | ||
110 | 189 | Tabs provides functions to add Tab elements dynamically on runtime, without | ||
111 | 190 | destroying the state of the existing tabs. You can add, move and remove any | ||
112 | 191 | kind of Tab element, pre-declared or dynamically created ones. When removing | ||
113 | 192 | pre-declared tabs, those will all be held back and hidden by Tabs, and can be | ||
114 | 193 | added back any time either to the same or to a different position. | ||
115 | 194 | |||
116 | 195 | \qml | ||
117 | 196 | import QtQuick 2.0 | ||
118 | 197 | import Ubuntu.Components 0.1 | ||
119 | 198 | |||
120 | 199 | MainView { | ||
121 | 200 | width: units.gu(40) | ||
122 | 201 | height: units.gu(71) | ||
123 | 202 | |||
124 | 203 | Component { | ||
125 | 204 | id: dynamicTab | ||
126 | 205 | Tab { | ||
127 | 206 | page: Page { | ||
128 | 207 | Label { | ||
129 | 208 | text: title | ||
130 | 209 | anchors.centerIn: parent | ||
131 | 210 | } | ||
132 | 211 | } | ||
133 | 212 | } | ||
134 | 213 | } | ||
135 | 214 | Tabs { | ||
136 | 215 | id: tabs | ||
137 | 216 | Tab { | ||
138 | 217 | title: "Main tab" | ||
139 | 218 | page: Page { | ||
140 | 219 | toolbar: ToolbarItems { | ||
141 | 220 | ToolbarButton { | ||
142 | 221 | text: "remove predeclared" | ||
143 | 222 | onTriggered: tabs.removeTab(preDeclared.index) | ||
144 | 223 | } | ||
145 | 224 | ToolbarButton { | ||
146 | 225 | text: "add new" | ||
147 | 226 | onTriggered: tabs.addTab("New tab", dynamicTab) | ||
148 | 227 | } | ||
149 | 228 | ToolbarButton { | ||
150 | 229 | text: "insert predeclared" | ||
151 | 230 | onTriggered: tabs.insertTab("", 0) | ||
152 | 231 | } | ||
153 | 232 | } | ||
154 | 233 | } | ||
155 | 234 | } | ||
156 | 235 | Tab { | ||
157 | 236 | id: preDeclared | ||
158 | 237 | title: "Pre-declared tab" | ||
159 | 238 | page: Page { | ||
160 | 239 | Label { | ||
161 | 240 | text: "This is a predeclared tab at index #" + index | ||
162 | 241 | anchors.centerIn: parent | ||
163 | 242 | } | ||
164 | 243 | } | ||
165 | 244 | } | ||
166 | 245 | } | ||
167 | 246 | } | ||
168 | 247 | \endqml | ||
169 | 248 | |||
170 | 249 | \section3 Using Repeater and functions together | ||
171 | 250 | Repeaters re-create their delegates as many times the model changes. Tabs added | ||
172 | 251 | or moved in between the tabs maintained by the Repeater, as well as reordered | ||
173 | 252 | through the Tabs functions will be re-arranged once the Repeater's model changes. | ||
174 | 253 | This should be taken into account when designing the application, and the use | ||
175 | 254 | of Repeater and functions toghether should be avoided if possible, or at least | ||
176 | 255 | Repeater should always add tabs to te tail of the tab stack, and no tab insertion | ||
177 | 256 | happens in that area. | ||
178 | 152 | */ | 257 | */ |
179 | 153 | PageTreeNode { | 258 | PageTreeNode { |
180 | 154 | id: tabs | 259 | id: tabs |
181 | @@ -186,10 +291,14 @@ | |||
182 | 186 | } | 291 | } |
183 | 187 | 292 | ||
184 | 188 | /*! | 293 | /*! |
186 | 189 | Children are placed in a separate item that has functionality to extract the Tab items. | 294 | \deprecated |
187 | 295 | Children are placed in a separate item that has functionality to extract | ||
188 | 296 | the Tab items. | ||
189 | 297 | Note: this property is deprecated. Tab components are directly parented | ||
190 | 298 | to Tabs' data property. | ||
191 | 190 | \qmlproperty list<Item> tabChildren | 299 | \qmlproperty list<Item> tabChildren |
192 | 191 | */ | 300 | */ |
194 | 192 | default property alias tabChildren: tabStack.data | 301 | property alias tabChildren: tabs.data |
195 | 193 | 302 | ||
196 | 194 | /*! | 303 | /*! |
197 | 195 | \qmlproperty int count | 304 | \qmlproperty int count |
198 | @@ -206,36 +315,180 @@ | |||
199 | 206 | signal modelChanged() | 315 | signal modelChanged() |
200 | 207 | 316 | ||
201 | 208 | /*! | 317 | /*! |
202 | 318 | Appends a Tab dynamically to the list of tabs. The \a title specifies the | ||
203 | 319 | title of the Tab. The \a tab can be either a Component, a URL to a Tab | ||
204 | 320 | component to be loaded or an instance of a pre-declared tab that has been | ||
205 | 321 | previously removed. The Tab's title will be replaced with the given \a title, | ||
206 | 322 | unless the value is an empty string or undefined. | ||
207 | 323 | Returns the instance of the added Tab. | ||
208 | 324 | */ | ||
209 | 325 | function addTab(title, tab) { | ||
210 | 326 | return insertTab(count, title, tab); | ||
211 | 327 | } | ||
212 | 328 | |||
213 | 329 | /*! | ||
214 | 330 | Inserts a Tab at the given index. If the \a index is less or equal than 0, | ||
215 | 331 | the Tab will be added to the front, and to the end of the tab stack in case | ||
216 | 332 | the \a index is greater than \l count. \a title and \a tab are used in the | ||
217 | 333 | same way as with \l addTab(). | ||
218 | 334 | Returns the instance of the inserted Tab. | ||
219 | 335 | */ | ||
220 | 336 | function insertTab(index, title, tab) { | ||
221 | 337 | // check if the given component is a Tab instance | ||
222 | 338 | var tabObject = null; | ||
223 | 339 | |||
224 | 340 | if (typeof tab === "string") { | ||
225 | 341 | // we have a URL | ||
226 | 342 | var tabComponent = Qt.createComponent(tab); | ||
227 | 343 | if (tabComponent.status === Component.Error) { | ||
228 | 344 | console.error(tabComponent.errorString()); | ||
229 | 345 | return null; | ||
230 | 346 | } | ||
231 | 347 | tabObject = tabComponent.createObject(); | ||
232 | 348 | tabObject.__protected.dynamic = true; | ||
233 | 349 | } else if (tab.hasOwnProperty("createObject")) { | ||
234 | 350 | // we have a Component | ||
235 | 351 | tabObject = tab.createObject(); | ||
236 | 352 | tabObject.__protected.dynamic = true; | ||
237 | 353 | } else if (tab.hasOwnProperty("parent") && tab.parent === trashedTabs) { | ||
238 | 354 | // we have a pre-declared tab that has been removed | ||
239 | 355 | tabObject = tab; | ||
240 | 356 | } else { | ||
241 | 357 | console.error(i18n.tr("The object is not a URL, Component or a removed Tab: ") + tab); | ||
242 | 358 | return null; | ||
243 | 359 | } | ||
244 | 360 | |||
245 | 361 | // fix title | ||
246 | 362 | if (title !== undefined && title !== "") { | ||
247 | 363 | tabObject.title = title; | ||
248 | 364 | } | ||
249 | 365 | |||
250 | 366 | // insert the created tab into the model | ||
251 | 367 | index = MathUtils.clamp(index, 0, count); | ||
252 | 368 | tabObject.__protected.inserted = true; | ||
253 | 369 | tabObject.__protected.index = index; | ||
254 | 370 | tabsModel.insertTab(tabObject, index); | ||
255 | 371 | if (tabs.selectedTabIndex >= index) { | ||
256 | 372 | // move the selected index to the next index | ||
257 | 373 | tabs.selectedTabIndex += 1; | ||
258 | 374 | } else { | ||
259 | 375 | internal.sync(); | ||
260 | 376 | } | ||
261 | 377 | return tabObject; | ||
262 | 378 | } | ||
263 | 379 | |||
264 | 380 | /*! | ||
265 | 381 | The function returns the Tab from the given \a index, or null if the \a index | ||
266 | 382 | is invalid (less than \c 0 and greater than \l count). | ||
267 | 383 | */ | ||
268 | 384 | function getTab(index) { | ||
269 | 385 | return (index >=0) && (index < count) ? tabsModel.get(index).tab : null; | ||
270 | 386 | } | ||
271 | 387 | |||
272 | 388 | /*! | ||
273 | 389 | Moves the tab from the given \a from position to the position given in \a to. | ||
274 | 390 | Returns true if the indexes were in 0..\l count - 1 boundary and if the operation | ||
275 | 391 | succeeds, and false otherwise. The \l selectedTabIndex is updated if it is | ||
276 | 392 | affected by the move (it is equal with \a from or falls between \a from and | ||
277 | 393 | \a to indexes). | ||
278 | 394 | */ | ||
279 | 395 | function moveTab(from, to) { | ||
280 | 396 | if (from < 0 || from >= count || to < 0 || to >= count || from === to) return false; | ||
281 | 397 | var tabFrom = tabsModel.get(from).tab; | ||
282 | 398 | var tabTo = tabsModel.get(to).tab; | ||
283 | 399 | |||
284 | 400 | // move tab | ||
285 | 401 | QuickUtils.moveItemBefore(tabFrom, tabTo); | ||
286 | 402 | tabsModel.updateTabList(tabs.children); | ||
287 | 403 | |||
288 | 404 | // fix selected tab | ||
289 | 405 | if (selectedTabIndex === from) { | ||
290 | 406 | selectedTabIndex = to; | ||
291 | 407 | } else if (selectedTabIndex >= Math.min(from, to) && selectedTabIndex <= Math.max(from, to)) { | ||
292 | 408 | selectedTabIndex--; | ||
293 | 409 | } else { | ||
294 | 410 | internal.sync(); | ||
295 | 411 | } | ||
296 | 412 | |||
297 | 413 | return true; | ||
298 | 414 | } | ||
299 | 415 | |||
300 | 416 | /*! | ||
301 | 417 | Removes the Tab from the given \a index. Returns true if the \a index falls | ||
302 | 418 | into 0..\l count - 1 boundary and the operation succeeds, and false on error. | ||
303 | 419 | The function removes also the pre-declared tabs. These can be added back using | ||
304 | 420 | \l addTab or \l insertTab by specifying the instance of the Tab to be added as | ||
305 | 421 | component. The \l selectedTabIndex is updated if is affected by the removal | ||
306 | 422 | (it is identical or greater than the tab index to be removed). | ||
307 | 423 | */ | ||
308 | 424 | function removeTab(index) { | ||
309 | 425 | if (index < 0 || index >= count) return false; | ||
310 | 426 | var tab = tabsModel.get(index).tab; | ||
311 | 427 | var activeIndex = (selectedTabIndex >= index) ? MathUtils.clamp(selectedTabIndex, 0, count - 2) : -1; | ||
312 | 428 | |||
313 | 429 | // remove from Tabs; Tabs children change will remove the tab from the model | ||
314 | 430 | tab.parent = null; | ||
315 | 431 | if (tab.__protected.dynamic) { | ||
316 | 432 | tab.destroy(); | ||
317 | 433 | } else { | ||
318 | 434 | // pre-declared tab, mark it as removed, so we don't update it next time | ||
319 | 435 | // the tabs stack children is updated | ||
320 | 436 | tab.parent = trashedTabs; | ||
321 | 437 | } | ||
322 | 438 | |||
323 | 439 | // move active tab if needed | ||
324 | 440 | if (activeIndex >= 0 && activeIndex !== selectedTabIndex) { | ||
325 | 441 | selectedTabIndex = activeIndex; | ||
326 | 442 | } else { | ||
327 | 443 | internal.sync(); | ||
328 | 444 | } | ||
329 | 445 | |||
330 | 446 | return true; | ||
331 | 447 | } | ||
332 | 448 | |||
333 | 449 | /*! \internal */ | ||
334 | 450 | onChildrenChanged: { | ||
335 | 451 | internal.connectToRepeaters(tabs.children); | ||
336 | 452 | tabsModel.updateTabList(tabs.children); | ||
337 | 453 | } | ||
338 | 454 | |||
339 | 455 | /*! | ||
340 | 209 | \internal | 456 | \internal |
341 | 210 | required by TabsStyle | 457 | required by TabsStyle |
342 | 211 | */ | 458 | */ |
343 | 212 | ListModel { | 459 | ListModel { |
344 | 213 | id: tabsModel | 460 | id: tabsModel |
345 | 214 | 461 | ||
346 | 462 | property bool updateDisabled: false | ||
347 | 463 | |||
348 | 215 | function listModel(tab) { | 464 | function listModel(tab) { |
349 | 216 | return {"title": tab.title, "tab": tab}; | 465 | return {"title": tab.title, "tab": tab}; |
350 | 217 | } | 466 | } |
351 | 218 | 467 | ||
352 | 219 | function updateTabList(tabsList) { | 468 | function updateTabList(tabsList) { |
353 | 469 | if (updateDisabled) return; | ||
354 | 220 | var offset = 0; | 470 | var offset = 0; |
356 | 221 | var tabIndex; | 471 | var tabIndex = -1; |
357 | 222 | for (var i in tabsList) { | 472 | for (var i in tabsList) { |
358 | 223 | var tab = tabsList[i]; | 473 | var tab = tabsList[i]; |
359 | 224 | if (internal.isTab(tab)) { | 474 | if (internal.isTab(tab)) { |
360 | 225 | tabIndex = i - offset; | 475 | tabIndex = i - offset; |
361 | 226 | // make sure we have the right parent | 476 | // make sure we have the right parent |
363 | 227 | tab.parent = tabStack; | 477 | tab.parent = tabs; |
364 | 228 | 478 | ||
365 | 229 | if (!tab.__protected.inserted) { | 479 | if (!tab.__protected.inserted) { |
366 | 230 | tab.__protected.index = tabIndex; | 480 | tab.__protected.index = tabIndex; |
367 | 231 | tab.__protected.inserted = true; | 481 | tab.__protected.inserted = true; |
368 | 232 | insert(tabIndex, listModel(tab)); | 482 | insert(tabIndex, listModel(tab)); |
370 | 233 | } else if (!tab.__protected.removedFromTabs && tabsModel.count > tab.index) { | 483 | } else { |
371 | 234 | get(tab.index).title = tab.title; | 484 | get(tab.index).title = tab.title; |
372 | 235 | } | 485 | } |
373 | 236 | 486 | ||
374 | 237 | // always makes sure that tabsModel has the same order as tabsList | 487 | // always makes sure that tabsModel has the same order as tabsList |
376 | 238 | move(tab.__protected.index, tabIndex, 1); | 488 | // but move only if there is more than one item in the list |
377 | 489 | if (count > 1) { | ||
378 | 490 | move(tab.__protected.index, tabIndex, 1); | ||
379 | 491 | } | ||
380 | 239 | reindex(); | 492 | reindex(); |
381 | 240 | } else { | 493 | } else { |
382 | 241 | // keep track of children that are not tabs so that we compute | 494 | // keep track of children that are not tabs so that we compute |
383 | @@ -243,6 +496,10 @@ | |||
384 | 243 | offset += 1; | 496 | offset += 1; |
385 | 244 | } | 497 | } |
386 | 245 | } | 498 | } |
387 | 499 | // remove deleted tabs, those should be at the end of the list by now | ||
388 | 500 | if ((tabIndex >= 0) && (tabIndex + 1) < count) { | ||
389 | 501 | remove(tabIndex + 1, count - tabIndex - 1); | ||
390 | 502 | } | ||
391 | 246 | internal.sync(); | 503 | internal.sync(); |
392 | 247 | } | 504 | } |
393 | 248 | 505 | ||
394 | @@ -257,18 +514,31 @@ | |||
395 | 257 | tab.__protected.index = i; | 514 | tab.__protected.index = i; |
396 | 258 | } | 515 | } |
397 | 259 | } | 516 | } |
398 | 517 | |||
399 | 518 | function insertTab(tab, index) { | ||
400 | 519 | // fix index | ||
401 | 520 | if (index < 0) { | ||
402 | 521 | index = 0; | ||
403 | 522 | } | ||
404 | 523 | // get the tab before which the item will be inserted | ||
405 | 524 | var itemAtIndex = ((index >= 0) && (index < count)) ? get(index).tab : null; | ||
406 | 525 | // disable update only if we insert, append can keep the logic rolling | ||
407 | 526 | updateDisabled = (itemAtIndex !== null); | ||
408 | 527 | insert(index, listModel(tab)); | ||
409 | 528 | tab.parent = tabs; | ||
410 | 529 | updateDisabled = false; | ||
411 | 530 | if (itemAtIndex) { | ||
412 | 531 | QuickUtils.moveItemBefore(tab, itemAtIndex); | ||
413 | 532 | updateTabList(tabs.children); | ||
414 | 533 | } | ||
415 | 534 | } | ||
416 | 260 | } | 535 | } |
417 | 261 | 536 | ||
420 | 262 | // FIXME: this component is not really needed, as it doesn't really bring any | 537 | // invisible component stacking removed pre-declared components |
419 | 263 | // value; should be removed in a later MR | ||
421 | 264 | Item { | 538 | Item { |
429 | 265 | anchors.fill: parent | 539 | id: trashedTabs |
430 | 266 | id: tabStack | 540 | visible: false |
431 | 267 | 541 | opacity: 0.0 | |
425 | 268 | onChildrenChanged: { | ||
426 | 269 | internal.connectToRepeaters(tabStack.children); | ||
427 | 270 | tabsModel.updateTabList(tabStack.children); | ||
428 | 271 | } | ||
432 | 272 | } | 542 | } |
433 | 273 | 543 | ||
434 | 274 | /* | 544 | /* |
435 | @@ -283,7 +553,7 @@ | |||
436 | 283 | interval: 1 | 553 | interval: 1 |
437 | 284 | running: false | 554 | running: false |
438 | 285 | onTriggered: { | 555 | onTriggered: { |
440 | 286 | tabsModel.updateTabList(tabStack.children); | 556 | tabsModel.updateTabList(tabs.children); |
441 | 287 | internal.sync(); | 557 | internal.sync(); |
442 | 288 | } | 558 | } |
443 | 289 | } | 559 | } |
444 | @@ -295,8 +565,8 @@ | |||
445 | 295 | Binding { | 565 | Binding { |
446 | 296 | target: tabBar | 566 | target: tabBar |
447 | 297 | property: "animate" | 567 | property: "animate" |
450 | 298 | when: internal.header && internal.header.hasOwnProperty("animate") | 568 | when: (internal.header !== null) && internal.header.hasOwnProperty("animate") |
451 | 299 | value: internal.header.animate | 569 | value: internal.header ? internal.header.animate : "false" |
452 | 300 | } | 570 | } |
453 | 301 | 571 | ||
454 | 302 | /* | 572 | /* |
455 | @@ -332,7 +602,9 @@ | |||
456 | 332 | function connectToRepeaters(children) { | 602 | function connectToRepeaters(children) { |
457 | 333 | for (var i = 0; i < children.length; i++) { | 603 | for (var i = 0; i < children.length; i++) { |
458 | 334 | var child = children[i]; | 604 | var child = children[i]; |
460 | 335 | if (internal.isRepeater(child) && (internal.repeaters.indexOf(child) < 0)) { | 605 | if (internal.isRepeater(child) && |
461 | 606 | (internal.repeaters !== undefined) && | ||
462 | 607 | (internal.repeaters.indexOf(child) < 0)) { | ||
463 | 336 | internal.connectRepeater(child); | 608 | internal.connectRepeater(child); |
464 | 337 | } | 609 | } |
465 | 338 | } | 610 | } |
466 | @@ -355,7 +627,7 @@ | |||
467 | 355 | https://bugreports.qt-project.org/browse/QTBUG-32438 | 627 | https://bugreports.qt-project.org/browse/QTBUG-32438 |
468 | 356 | */ | 628 | */ |
469 | 357 | function updateTabsModel() { | 629 | function updateTabsModel() { |
471 | 358 | tabsModel.updateTabList(tabStack.children); | 630 | tabsModel.updateTabList(tabs.children); |
472 | 359 | } | 631 | } |
473 | 360 | 632 | ||
474 | 361 | /* | 633 | /* |
475 | 362 | 634 | ||
476 | === modified file 'modules/Ubuntu/Components/Themes/Ambiance/TabBarStyle.qml' | |||
477 | --- modules/Ubuntu/Components/Themes/Ambiance/TabBarStyle.qml 2014-04-08 12:38:35 +0000 | |||
478 | +++ modules/Ubuntu/Components/Themes/Ambiance/TabBarStyle.qml 2014-04-10 11:34:46 +0000 | |||
479 | @@ -116,8 +116,8 @@ | |||
480 | 116 | AbstractButton { | 116 | AbstractButton { |
481 | 117 | id: button | 117 | id: button |
482 | 118 | anchors { | 118 | anchors { |
485 | 119 | top: parent.top | 119 | top: parent ? parent.top : undefined |
486 | 120 | bottom: parent.bottom | 120 | bottom: parent ? parent.bottom: undefined |
487 | 121 | } | 121 | } |
488 | 122 | width: text.paintedWidth + text.anchors.leftMargin + text.anchors.rightMargin | 122 | width: text.paintedWidth + text.anchors.leftMargin + text.anchors.rightMargin |
489 | 123 | 123 | ||
490 | @@ -150,6 +150,13 @@ | |||
491 | 150 | return false; | 150 | return false; |
492 | 151 | } | 151 | } |
493 | 152 | 152 | ||
494 | 153 | // update the offset of the buttonRow | ||
495 | 154 | onOffsetChanged: { | ||
496 | 155 | if (selected) { | ||
497 | 156 | buttonView.updateOffset(button.offset); | ||
498 | 157 | } | ||
499 | 158 | } | ||
500 | 159 | |||
501 | 153 | Behavior on opacity { | 160 | Behavior on opacity { |
502 | 154 | NumberAnimation { | 161 | NumberAnimation { |
503 | 155 | duration: headerTextFadeDuration | 162 | duration: headerTextFadeDuration |
504 | 156 | 163 | ||
505 | === modified file 'modules/Ubuntu/Components/plugin/quickutils.cpp' | |||
506 | --- modules/Ubuntu/Components/plugin/quickutils.cpp 2014-03-20 15:46:28 +0000 | |||
507 | +++ modules/Ubuntu/Components/plugin/quickutils.cpp 2014-04-10 11:34:46 +0000 | |||
508 | @@ -119,6 +119,21 @@ | |||
509 | 119 | return result.left(result.indexOf("_QML")); | 119 | return result.left(result.indexOf("_QML")); |
510 | 120 | } | 120 | } |
511 | 121 | 121 | ||
512 | 122 | /*! | ||
513 | 123 | * \internal | ||
514 | 124 | * Moves a given \a item before the \a other one in the object stack. Both \a item | ||
515 | 125 | * and \a other must have the same parent item. | ||
516 | 126 | */ | ||
517 | 127 | void QuickUtils::moveItemBefore(QQuickItem *item, QQuickItem *other) | ||
518 | 128 | { | ||
519 | 129 | Q_ASSERT(item); | ||
520 | 130 | Q_ASSERT(item->parentItem()); | ||
521 | 131 | if (other) { | ||
522 | 132 | Q_ASSERT(other->parentItem() == item->parentItem()); | ||
523 | 133 | item->stackBefore(other); | ||
524 | 134 | } | ||
525 | 135 | } | ||
526 | 136 | |||
527 | 122 | 137 | ||
528 | 123 | /*! | 138 | /*! |
529 | 124 | * \internal | 139 | * \internal |
530 | 125 | 140 | ||
531 | === modified file 'modules/Ubuntu/Components/plugin/quickutils.h' | |||
532 | --- modules/Ubuntu/Components/plugin/quickutils.h 2014-03-20 15:46:28 +0000 | |||
533 | +++ modules/Ubuntu/Components/plugin/quickutils.h 2014-04-10 11:34:46 +0000 | |||
534 | @@ -42,6 +42,7 @@ | |||
535 | 42 | QString inputMethodProvider() const; | 42 | QString inputMethodProvider() const; |
536 | 43 | 43 | ||
537 | 44 | Q_INVOKABLE static QString className(QObject *item); | 44 | Q_INVOKABLE static QString className(QObject *item); |
538 | 45 | Q_INVOKABLE void moveItemBefore(QQuickItem *item, QQuickItem *before); | ||
539 | 45 | QObject* createQmlObject(const QUrl &url, QQmlEngine *engine); | 46 | QObject* createQmlObject(const QUrl &url, QQmlEngine *engine); |
540 | 46 | 47 | ||
541 | 47 | Q_SIGNALS: | 48 | Q_SIGNALS: |
542 | 48 | 49 | ||
543 | === modified file 'modules/Ubuntu/Test/UbuntuTestCase.qml' | |||
544 | --- modules/Ubuntu/Test/UbuntuTestCase.qml 2014-02-25 12:36:27 +0000 | |||
545 | +++ modules/Ubuntu/Test/UbuntuTestCase.qml 2014-04-10 11:34:46 +0000 | |||
546 | @@ -87,7 +87,75 @@ | |||
547 | 87 | } | 87 | } |
548 | 88 | } | 88 | } |
549 | 89 | 89 | ||
551 | 90 | /*! | 90 | /*! |
552 | 91 | \qmlmethod UbuntuTestCase::flick(item, x, y, dx, dy, pressTimeout = -1, steps = -1, button = Qt.LeftButton, modifiers = Qt.NoModifiers, delay = -1) | ||
553 | 92 | |||
554 | 93 | The function produces a flick event when executed on Flickables. When used | ||
555 | 94 | on other components it provides the same functionality as \l mouseDrag() | ||
556 | 95 | function. The optional \a pressTimeout parameter can be used to introduce | ||
557 | 96 | a small delay between the mouse press and the first mouse move. Setting a | ||
558 | 97 | negative or zero value will disable the timeout. | ||
559 | 98 | |||
560 | 99 | The default flick velocity is built up using 5 move points. This can be altered | ||
561 | 100 | by setting a positive value to \a steps parameter. The bigger the number the | ||
562 | 101 | longer the flick will be. When a negative or zero value is given, the default | ||
563 | 102 | of 5 move points will be used. | ||
564 | 103 | |||
565 | 104 | \note The function can be used to select a text in a TextField or TextArea by | ||
566 | 105 | specifying at least 400 millisecods to \a pressTimeout. | ||
567 | 106 | */ | ||
568 | 107 | function flick(item, x, y, dx, dy, pressTimeout, steps, button, modifiers, delay) { | ||
569 | 108 | if (item === undefined || item.x === undefined || item.y === undefined) | ||
570 | 109 | return | ||
571 | 110 | if (button === undefined) | ||
572 | 111 | button = Qt.LeftButton | ||
573 | 112 | if (modifiers === undefined) | ||
574 | 113 | modifiers = Qt.NoModifier | ||
575 | 114 | if (steps === undefined || steps <= 0) | ||
576 | 115 | steps = 4; | ||
577 | 116 | // make sure we have at least two move steps so the flick will be sensed | ||
578 | 117 | steps += 1; | ||
579 | 118 | if (delay === undefined) | ||
580 | 119 | delay = -1; | ||
581 | 120 | |||
582 | 121 | var ddx = dx / steps; | ||
583 | 122 | var ddy = dy / steps; | ||
584 | 123 | |||
585 | 124 | mousePress(item, x, y, button, modifiers, delay); | ||
586 | 125 | if (pressTimeout !== undefined && pressTimeout > 0) { | ||
587 | 126 | wait(pressTimeout); | ||
588 | 127 | } | ||
589 | 128 | for (var i = 1; i <= steps; i++) { | ||
590 | 129 | // mouse moves are all processed immediately, without delay in between events | ||
591 | 130 | mouseMove(item, x + i * ddx, y + i * ddy, -1, button); | ||
592 | 131 | } | ||
593 | 132 | mouseRelease(item, x + dx, y + dy, button, modifiers, delay); | ||
594 | 133 | // empty event buffer | ||
595 | 134 | wait(200); | ||
596 | 135 | } | ||
597 | 136 | |||
598 | 137 | /*! | ||
599 | 138 | \qmlmethod UbuntuTestCase::mouseLongPress(item, x, y, button = Qt.LeftButton, modifiers = Qt.NoModifiers, delay = -1) | ||
600 | 139 | |||
601 | 140 | Simulates a long press on a mouse \a button with an optional \a modifier | ||
602 | 141 | on an \a item. The position is defined by \a x and \a y. If \a delay is | ||
603 | 142 | specified, the test will wait the specified amount of milliseconds before | ||
604 | 143 | the press. | ||
605 | 144 | |||
606 | 145 | The position given by \a x and \a y is transformed from the co-ordinate | ||
607 | 146 | system of \a item into window co-ordinates and then delivered. | ||
608 | 147 | If \a item is obscured by another item, or a child of \a item occupies | ||
609 | 148 | that position, then the event will be delivered to the other item instead. | ||
610 | 149 | |||
611 | 150 | \sa mouseRelease(), mouseClick(), mouseDoubleClick(), mouseMove(), mouseDrag(), mouseWheel() | ||
612 | 151 | */ | ||
613 | 152 | function mouseLongPress(item, x, y, button, modifiers, delay) { | ||
614 | 153 | mousePress(item, x, y, button, modifiers, delay); | ||
615 | 154 | // the delay is taken from QQuickMouseArea | ||
616 | 155 | wait(800); | ||
617 | 156 | } | ||
618 | 157 | |||
619 | 158 | /*! | ||
620 | 91 | Keeps executing a given parameter-less function until it returns the given | 159 | Keeps executing a given parameter-less function until it returns the given |
621 | 92 | expected result or the timemout is reached (in which case a test failure | 160 | expected result or the timemout is reached (in which case a test failure |
622 | 93 | is generated) | 161 | is generated) |
623 | 94 | 162 | ||
624 | === modified file 'modules/Ubuntu/Test/deployment.pri' | |||
625 | --- modules/Ubuntu/Test/deployment.pri 2014-01-17 12:30:05 +0000 | |||
626 | +++ modules/Ubuntu/Test/deployment.pri 2014-04-10 11:34:46 +0000 | |||
627 | @@ -7,9 +7,14 @@ | |||
628 | 7 | # make found deployables visible in Qt Creator | 7 | # make found deployables visible in Qt Creator |
629 | 8 | OTHER_FILES += $$QMLDIR_FILE | 8 | OTHER_FILES += $$QMLDIR_FILE |
630 | 9 | 9 | ||
631 | 10 | QML_FILES = $$system(ls *.qml) | ||
632 | 11 | JS_FILES = $$system(ls *.js) | ||
633 | 12 | |||
634 | 10 | # define deployment for found deployables | 13 | # define deployment for found deployables |
635 | 11 | qmldir_file.path = $$installPath | 14 | qmldir_file.path = $$installPath |
636 | 12 | qmldir_file.files = $$QMLDIR_FILE | 15 | qmldir_file.files = $$QMLDIR_FILE |
637 | 16 | qml_files.path = $$installPath | ||
638 | 17 | qml_files.files = $$QML_FILES | ||
639 | 13 | js_files.path = $$installPath | 18 | js_files.path = $$installPath |
640 | 14 | js_files.files = $$JS_FILES | 19 | js_files.files = $$JS_FILES |
641 | 15 | 20 | ||
642 | @@ -20,4 +25,4 @@ | |||
643 | 20 | # https://bugreports.qt-project.org/browse/QTBUG-36243 | 25 | # https://bugreports.qt-project.org/browse/QTBUG-36243 |
644 | 21 | plugins_qmltypes.extra = $$[QT_INSTALL_BINS]/qmlplugindump -notrelocatable Ubuntu.Test 0.1 ../../ 2>/dev/null > $(INSTALL_ROOT)/$$installPath/plugins.qmltypes | 26 | plugins_qmltypes.extra = $$[QT_INSTALL_BINS]/qmlplugindump -notrelocatable Ubuntu.Test 0.1 ../../ 2>/dev/null > $(INSTALL_ROOT)/$$installPath/plugins.qmltypes |
645 | 22 | 27 | ||
647 | 23 | INSTALLS += qmldir_file plugins_qmltypes | 28 | INSTALLS += qmldir_file plugins_qmltypes qml_files js_files |
648 | 24 | 29 | ||
649 | === modified file 'tests/resources/navigation/Tabs.qml' | |||
650 | --- tests/resources/navigation/Tabs.qml 2014-04-07 10:03:39 +0000 | |||
651 | +++ tests/resources/navigation/Tabs.qml 2014-04-10 11:34:46 +0000 | |||
652 | @@ -19,9 +19,47 @@ | |||
653 | 19 | import Ubuntu.Components.ListItems 0.1 as ListItem | 19 | import Ubuntu.Components.ListItems 0.1 as ListItem |
654 | 20 | 20 | ||
655 | 21 | MainView { | 21 | MainView { |
656 | 22 | id: root | ||
657 | 22 | width: 800 | 23 | width: 800 |
658 | 23 | height: 600 | 24 | height: 600 |
659 | 24 | 25 | ||
660 | 26 | property var repeaterModel: 3 | ||
661 | 27 | |||
662 | 28 | Component { | ||
663 | 29 | id: dynamicTab | ||
664 | 30 | Tab { | ||
665 | 31 | page: Page { | ||
666 | 32 | Label { | ||
667 | 33 | text: title + " at index " + index | ||
668 | 34 | anchors.centerIn: parent | ||
669 | 35 | } | ||
670 | 36 | tools: ToolbarItems { | ||
671 | 37 | ToolbarButton { | ||
672 | 38 | text: "move @1" | ||
673 | 39 | onTriggered: { | ||
674 | 40 | print("MOVE TAB TO #1") | ||
675 | 41 | tabs.moveTab(index, 1) | ||
676 | 42 | } | ||
677 | 43 | } | ||
678 | 44 | ToolbarButton { | ||
679 | 45 | text: "remove me" | ||
680 | 46 | onTriggered: { | ||
681 | 47 | print("REMOVE CURENT TAB") | ||
682 | 48 | tabs.removeTab(index) | ||
683 | 49 | } | ||
684 | 50 | } | ||
685 | 51 | ToolbarButton { | ||
686 | 52 | text: "remove first" | ||
687 | 53 | onTriggered: { | ||
688 | 54 | print("REMOVE TAB AT #0") | ||
689 | 55 | tabs.removeTab(0) | ||
690 | 56 | } | ||
691 | 57 | } | ||
692 | 58 | } | ||
693 | 59 | } | ||
694 | 60 | } | ||
695 | 61 | } | ||
696 | 62 | |||
697 | 25 | Tabs { | 63 | Tabs { |
698 | 26 | id: tabs | 64 | id: tabs |
699 | 27 | selectedTabIndex: 0 | 65 | selectedTabIndex: 0 |
700 | @@ -31,6 +69,7 @@ | |||
701 | 31 | 69 | ||
702 | 32 | Tab { | 70 | Tab { |
703 | 33 | id: simpleTab | 71 | id: simpleTab |
704 | 72 | objectName: title | ||
705 | 34 | title: i18n.tr("Simple page #" + index) | 73 | title: i18n.tr("Simple page #" + index) |
706 | 35 | page: Page { | 74 | page: Page { |
707 | 36 | Row { | 75 | Row { |
708 | @@ -55,13 +94,60 @@ | |||
709 | 55 | iconSource: "call_icon.png" | 94 | iconSource: "call_icon.png" |
710 | 56 | onTriggered: print("action triggered") | 95 | onTriggered: print("action triggered") |
711 | 57 | } | 96 | } |
712 | 97 | ToolbarButton { | ||
713 | 98 | text: "append" | ||
714 | 99 | onTriggered: { | ||
715 | 100 | print("APPEND TAB") | ||
716 | 101 | tabs.addTab("Appended tab", dynamicTab) | ||
717 | 102 | } | ||
718 | 103 | } | ||
719 | 104 | ToolbarButton { | ||
720 | 105 | text: "insert@1" | ||
721 | 106 | onTriggered: { | ||
722 | 107 | print("INSERT TAB TO #1") | ||
723 | 108 | tabs.insertTab(1, "Inserted tab", dynamicTab) | ||
724 | 109 | } | ||
725 | 110 | } | ||
726 | 111 | ToolbarButton { | ||
727 | 112 | text: "insert@2" | ||
728 | 113 | onTriggered: { | ||
729 | 114 | print("INSERT BETWEEN REPEATERS #1") | ||
730 | 115 | tabs.insertTab(2, "Between repeaters", dynamicTab) | ||
731 | 116 | } | ||
732 | 117 | } | ||
733 | 118 | ToolbarButton { | ||
734 | 119 | text: "insert@here" | ||
735 | 120 | onTriggered: { | ||
736 | 121 | print("INSERT AFTER ME") | ||
737 | 122 | tabs.insertTab(simpleTab.index, "Inserted tab", dynamicTab) | ||
738 | 123 | } | ||
739 | 124 | } | ||
740 | 125 | ToolbarButton { | ||
741 | 126 | text: "incRep" | ||
742 | 127 | onTriggered: { | ||
743 | 128 | print("INCREASE REPEATER MODEL") | ||
744 | 129 | root.repeaterModel += 1 | ||
745 | 130 | } | ||
746 | 131 | } | ||
747 | 132 | ToolbarButton { | ||
748 | 133 | text: "remove last" | ||
749 | 134 | onTriggered: { | ||
750 | 135 | print("REMOVE LAST TAB") | ||
751 | 136 | tabs.removeTab(tabs.count - 1) | ||
752 | 137 | } | ||
753 | 138 | } | ||
754 | 139 | ToolbarButton { | ||
755 | 140 | text: "append predec" | ||
756 | 141 | onTriggered: tabs.addTab("Re-added ListView", listViewTab) | ||
757 | 142 | } | ||
758 | 58 | } | 143 | } |
759 | 59 | } | 144 | } |
760 | 60 | } | 145 | } |
761 | 61 | Repeater { | 146 | Repeater { |
763 | 62 | model: 3 | 147 | model: root.repeaterModel |
764 | 63 | Tab { | 148 | Tab { |
765 | 64 | id: tab | 149 | id: tab |
766 | 150 | objectName: title | ||
767 | 65 | title: "Extra #" + tab.index | 151 | title: "Extra #" + tab.index |
768 | 66 | page: Page { | 152 | page: Page { |
769 | 67 | Column { | 153 | Column { |
770 | @@ -88,6 +174,7 @@ | |||
771 | 88 | } | 174 | } |
772 | 89 | Tab { | 175 | Tab { |
773 | 90 | id: externalTab | 176 | id: externalTab |
774 | 177 | objectName: title | ||
775 | 91 | title: i18n.tr("External #" + index) | 178 | title: i18n.tr("External #" + index) |
776 | 92 | page: Loader { | 179 | page: Loader { |
777 | 93 | parent: externalTab | 180 | parent: externalTab |
778 | @@ -96,6 +183,8 @@ | |||
779 | 96 | } | 183 | } |
780 | 97 | } | 184 | } |
781 | 98 | Tab { | 185 | Tab { |
782 | 186 | id: listViewTab | ||
783 | 187 | objectName: title | ||
784 | 99 | title: i18n.tr("List view #" + index) | 188 | title: i18n.tr("List view #" + index) |
785 | 100 | page: Page { | 189 | page: Page { |
786 | 101 | ListView { | 190 | ListView { |
787 | 102 | 191 | ||
788 | === modified file 'tests/unit/runtest.sh' | |||
789 | --- tests/unit/runtest.sh 2014-03-31 18:26:46 +0000 | |||
790 | +++ tests/unit/runtest.sh 2014-04-10 11:34:46 +0000 | |||
791 | @@ -33,7 +33,7 @@ | |||
792 | 33 | if [ $_TARGET != $_TESTFILE ]; then | 33 | if [ $_TARGET != $_TESTFILE ]; then |
793 | 34 | _CMD="$_CMD -input $_TESTFILE" | 34 | _CMD="$_CMD -input $_TESTFILE" |
794 | 35 | fi | 35 | fi |
796 | 36 | _CMD="$_CMD -maxwarnings 4" | 36 | _CMD="$_CMD -maxwarnings 40" |
797 | 37 | } | 37 | } |
798 | 38 | 38 | ||
799 | 39 | function execute_test_cmd { | 39 | function execute_test_cmd { |
800 | 40 | 40 | ||
801 | === added file 'tests/unit_x11/tst_components/ExternalTab.qml' | |||
802 | --- tests/unit_x11/tst_components/ExternalTab.qml 1970-01-01 00:00:00 +0000 | |||
803 | +++ tests/unit_x11/tst_components/ExternalTab.qml 2014-04-10 11:34:46 +0000 | |||
804 | @@ -0,0 +1,21 @@ | |||
805 | 1 | /* | ||
806 | 2 | * Copyright 2014 Canonical Ltd. | ||
807 | 3 | * | ||
808 | 4 | * This program is free software; you can redistribute it and/or modify | ||
809 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
810 | 6 | * the Free Software Foundation; version 3. | ||
811 | 7 | * | ||
812 | 8 | * This program is distributed in the hope that it will be useful, | ||
813 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
814 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
815 | 11 | * GNU Lesser General Public License for more details. | ||
816 | 12 | * | ||
817 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
818 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
819 | 15 | */ | ||
820 | 16 | |||
821 | 17 | import QtQuick 2.0 | ||
822 | 18 | import Ubuntu.Components 0.1 | ||
823 | 19 | |||
824 | 20 | Tab { | ||
825 | 21 | } | ||
826 | 0 | 22 | ||
827 | === modified file 'tests/unit_x11/tst_components/tst_tabs.qml' | |||
828 | --- tests/unit_x11/tst_components/tst_tabs.qml 2014-01-13 12:43:12 +0000 | |||
829 | +++ tests/unit_x11/tst_components/tst_tabs.qml 2014-04-10 11:34:46 +0000 | |||
830 | @@ -27,6 +27,13 @@ | |||
831 | 27 | id: emptyTabs | 27 | id: emptyTabs |
832 | 28 | } | 28 | } |
833 | 29 | 29 | ||
834 | 30 | Component { | ||
835 | 31 | id: dynamicTab | ||
836 | 32 | Tab{ | ||
837 | 33 | title: "OriginalTitle" | ||
838 | 34 | } | ||
839 | 35 | } | ||
840 | 36 | |||
841 | 30 | MainView { | 37 | MainView { |
842 | 31 | id: mainView | 38 | id: mainView |
843 | 32 | anchors.fill: parent | 39 | anchors.fill: parent |
844 | @@ -424,5 +431,149 @@ | |||
845 | 424 | mouseRelease(tabs.tabBar, tabs.tabBar.width/2, tabs.tabBar.height/2); | 431 | mouseRelease(tabs.tabBar, tabs.tabBar.width/2, tabs.tabBar.height/2); |
846 | 425 | compare(tabs.tabBar.pressed, false, "After releasing, pressed is false"); | 432 | compare(tabs.tabBar.pressed, false, "After releasing, pressed is false"); |
847 | 426 | } | 433 | } |
848 | 434 | |||
849 | 435 | |||
850 | 436 | |||
851 | 437 | // these tests should not be mixed with Repeaters | ||
852 | 438 | function test_z_addTab() { | ||
853 | 439 | var newTab = tabs.addTab("Dynamic Tab", dynamicTab); | ||
854 | 440 | compare((newTab !== null), true, "tab added"); | ||
855 | 441 | compare(newTab.active, false, "the inserted tab is inactive"); | ||
856 | 442 | compare(newTab.index, tabs.count - 1, "the tab is the last one"); | ||
857 | 443 | } | ||
858 | 444 | |||
859 | 445 | function test_z_addExternalTab() { | ||
860 | 446 | var newTab = tabs.addTab("External Tab", Qt.resolvedUrl("ExternalTab.qml")); | ||
861 | 447 | compare((newTab !== null), true, "tab added"); | ||
862 | 448 | compare(newTab.active, false, "the inserted tab is inactive"); | ||
863 | 449 | compare(newTab.index, tabs.count - 1, "the tab is the last one"); | ||
864 | 450 | } | ||
865 | 451 | |||
866 | 452 | function test_z_addTabWithDefaultTitle() { | ||
867 | 453 | var newTab = tabs.addTab("", dynamicTab); | ||
868 | 454 | compare((newTab !== null), true, "tab added"); | ||
869 | 455 | compare(newTab.title, "OriginalTitle", "tab created with original title"); | ||
870 | 456 | } | ||
871 | 457 | |||
872 | 458 | function test_z_insertTab() { | ||
873 | 459 | var tabIndex = Math.ceil(tabs.count / 2); | ||
874 | 460 | var newTab = tabs.insertTab(tabIndex, "Inserted tab", dynamicTab); | ||
875 | 461 | compare((newTab !== null), true, "tab inserted"); | ||
876 | 462 | compare(newTab.index, tabIndex, "this is the first tab"); | ||
877 | 463 | compare(tabs.selectedTab !== newTab, true, "the new tab is not the active one"); | ||
878 | 464 | } | ||
879 | 465 | |||
880 | 466 | function test_z_insertExternalTab() { | ||
881 | 467 | var tabIndex = Math.ceil(tabs.count / 2); | ||
882 | 468 | var newTab = tabs.insertTab(tabIndex, "Inserted External tab", Qt.resolvedUrl("ExternalTab.qml")); | ||
883 | 469 | compare((newTab !== null), true, "tab inserted"); | ||
884 | 470 | compare(newTab.index, tabIndex, "this is the first tab"); | ||
885 | 471 | compare(tabs.selectedTab !== newTab, true, "the new tab is not the active one"); | ||
886 | 472 | } | ||
887 | 473 | |||
888 | 474 | function test_z_insertTabAtSelectedIndex() { | ||
889 | 475 | tabs.selectedTabIndex = 1; | ||
890 | 476 | var tabIndex = tabs.selectedTabIndex - 1; | ||
891 | 477 | var newTab = tabs.insertTab(tabIndex, "InsertedAtSelected tab", dynamicTab); | ||
892 | 478 | compare((newTab !== null), true, "tab inserted"); | ||
893 | 479 | compare(newTab.index, tabIndex, "inserted at selected tab"); | ||
894 | 480 | compare(tabs.selectedTabIndex != (tabIndex + 1), true, "it is not the selected tab"); | ||
895 | 481 | } | ||
896 | 482 | |||
897 | 483 | function test_z_insertTabFront() { | ||
898 | 484 | var newTab = tabs.insertTab(-1, "PreTab", dynamicTab); | ||
899 | 485 | compare(newTab !== null, true, "pre-tab inserted"); | ||
900 | 486 | compare(newTab.index, 0, "this is the new first tab"); | ||
901 | 487 | compare(tabs.selectedTab !== newTab, true, "the new tab is not the active one"); | ||
902 | 488 | } | ||
903 | 489 | |||
904 | 490 | function test_z_insertTabEnd() { | ||
905 | 491 | var newTab = tabs.insertTab(tabs.count, "PostTab", dynamicTab); | ||
906 | 492 | compare(newTab !== null, true, "post-tab inserted"); | ||
907 | 493 | compare(newTab.index, tabs.count - 1, "thsi is the new last tab"); | ||
908 | 494 | compare(tabs.selectedTab !== newTab, true, "the new tab is not the active one"); | ||
909 | 495 | } | ||
910 | 496 | |||
911 | 497 | function test_z_insertTabAndActivate() { | ||
912 | 498 | var newTab = tabs.addTab("Inserted tab", dynamicTab); | ||
913 | 499 | compare((newTab !== null), true, "tab inserted"); | ||
914 | 500 | compare(newTab.index, tabs.count - 1, "the tab is the last one"); | ||
915 | 501 | tabs.selectedTabIndex = newTab.index; | ||
916 | 502 | compare(tabs.selectedTab, newTab, "the inserted tab is selected"); | ||
917 | 503 | compare(newTab.active, true, "the new tab is active"); | ||
918 | 504 | } | ||
919 | 505 | |||
920 | 506 | function test_z_moveTab() { | ||
921 | 507 | var selectedIndex = tabs.count - 1; | ||
922 | 508 | tabs.selectedTabIndex = selectedIndex; | ||
923 | 509 | compare(tabs.moveTab(0, selectedIndex), true, "first tab moved to last"); | ||
924 | 510 | compare(tabs.selectedTabIndex, selectedIndex - 1, "the selected index moved backwards"); | ||
925 | 511 | tabs.selectedTabIndex = selectedIndex = 0; | ||
926 | 512 | compare(tabs.moveTab(selectedIndex, selectedIndex + 1), true, "selected tab moved as next"); | ||
927 | 513 | compare(tabs.selectedTabIndex, selectedIndex + 1, "the selected index moved forewards"); | ||
928 | 514 | } | ||
929 | 515 | |||
930 | 516 | function test_z_moveSelectedTab() { | ||
931 | 517 | tabs.selectedTabIndex = 0; | ||
932 | 518 | tabs.moveTab(0, 1); | ||
933 | 519 | compare(tabs.selectedTabIndex, 1, "selected tab moved"); | ||
934 | 520 | } | ||
935 | 521 | |||
936 | 522 | function test_z_moveTabFail() { | ||
937 | 523 | compare(tabs.moveTab(-1, tabs.count - 1), false, "from-parameter out of range"); | ||
938 | 524 | compare(tabs.moveTab(0, tabs.count), false, "to-parameter out of range"); | ||
939 | 525 | } | ||
940 | 526 | |||
941 | 527 | function test_z_removeTab() { | ||
942 | 528 | compare(tabs.removeTab(tabs.count - 1), true, "last tab removed"); | ||
943 | 529 | tabs.selectedTabIndex = 0; | ||
944 | 530 | compare(tabs.removeTab(0), true, "active tab removed"); | ||
945 | 531 | compare(tabs.selectedTabIndex, 0, "the next tab is selected") | ||
946 | 532 | } | ||
947 | 533 | |||
948 | 534 | function test_z_removeActiveTab() { | ||
949 | 535 | tabs.selectedTabIndex = 1; | ||
950 | 536 | compare(tabs.removeTab(1), true, "selected tab removed"); | ||
951 | 537 | compare(tabs.selectedTabIndex, 1, "selected tab is next"); | ||
952 | 538 | |||
953 | 539 | tabs.selectedTabIndex = tabs.count - 1; | ||
954 | 540 | compare(tabs.removeTab(tabs.count - 1), true, "last tab removed"); | ||
955 | 541 | compare(tabs.selectedTabIndex, tabs.count - 1, "selected tab moved to last item"); | ||
956 | 542 | } | ||
957 | 543 | |||
958 | 544 | function test_z_removeTabAfterActiveTab() { | ||
959 | 545 | var activeTab = tabs.count - 2; | ||
960 | 546 | tabs.selectedTabIndex = activeTab; | ||
961 | 547 | compare(tabs.removeTab(tabs.count - 1), true, "last tab removed"); | ||
962 | 548 | compare(tabs.selectedTabIndex, activeTab, "the selected tab wasn't moved"); | ||
963 | 549 | } | ||
964 | 550 | |||
965 | 551 | function test_z_removeTabBeforeActiveTab() { | ||
966 | 552 | var activeTab = tabs.count - 1; | ||
967 | 553 | tabs.selectedTabIndex = activeTab; | ||
968 | 554 | compare(tabs.removeTab(0), true, "first tab removed"); | ||
969 | 555 | compare(tabs.selectedTabIndex, activeTab - 1, "the selected tab index decreased"); | ||
970 | 556 | } | ||
971 | 557 | |||
972 | 558 | function test_zz_addTabAfterCleaningUpTabs() { | ||
973 | 559 | while (tabs.count > 1) { | ||
974 | 560 | tabs.removeTab(tabs.count - 1); | ||
975 | 561 | } | ||
976 | 562 | compare(tabs.selectedTabIndex, 0, "the only tab is the selected one"); | ||
977 | 563 | // add a new tab anc check the count (default added tas should not be added anymore | ||
978 | 564 | tabs.addTab("Second tab", dynamicTab); | ||
979 | 565 | compare(tabs.count, 2, "we have two tabs only"); | ||
980 | 566 | } | ||
981 | 567 | |||
982 | 568 | function test_zz_addPredeclaredTab() { | ||
983 | 569 | tabs.removeTab(tab1.index); | ||
984 | 570 | |||
985 | 571 | // add a predeclared tab back with original title | ||
986 | 572 | compare(tabs.addTab("", tab1), tab1, "tab1 was not added back"); | ||
987 | 573 | compare(tab1.title, "tab 1", "the original title differs"); | ||
988 | 574 | |||
989 | 575 | // add a predeclared tab which was added already | ||
990 | 576 | compare(tabs.addTab("", tab1), null, "tab1 is already in tabs"); | ||
991 | 577 | } | ||
992 | 427 | } | 578 | } |
993 | 428 | } | 579 | } |
994 | 429 | 580 | ||
995 | === modified file 'tests/unit_x11/tst_test/tst_ubuntutestcase.qml' | |||
996 | --- tests/unit_x11/tst_test/tst_ubuntutestcase.qml 2014-02-13 10:27:14 +0000 | |||
997 | +++ tests/unit_x11/tst_test/tst_ubuntutestcase.qml 2014-04-10 11:34:46 +0000 | |||
998 | @@ -23,30 +23,57 @@ | |||
999 | 23 | width: 800 | 23 | width: 800 |
1000 | 24 | height: 600 | 24 | height: 600 |
1001 | 25 | 25 | ||
1010 | 26 | MouseArea { | 26 | Column { |
1011 | 27 | id: mouseArea | 27 | anchors.fill: parent |
1012 | 28 | objectName: "myMouseArea" | 28 | MouseArea { |
1013 | 29 | anchors.fill: parent | 29 | id: mouseArea |
1014 | 30 | hoverEnabled: true | 30 | objectName: "myMouseArea" |
1015 | 31 | property int testX : 0 | 31 | width: parent.width |
1016 | 32 | property int testY : 0 | 32 | height: 300 |
1017 | 33 | property int steps : 0 | 33 | hoverEnabled: true |
1018 | 34 | acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton | ||
1019 | 35 | property int testX : 0 | ||
1020 | 36 | property int testY : 0 | ||
1021 | 37 | property int steps : 0 | ||
1022 | 34 | 38 | ||
1028 | 35 | onPositionChanged: { | 39 | onPositionChanged: { |
1029 | 36 | testX = mouseX; | 40 | testX = mouseX; |
1030 | 37 | testY = mouseY; | 41 | testY = mouseY; |
1031 | 38 | steps++; | 42 | steps++; |
1032 | 39 | } | 43 | } |
1033 | 44 | } | ||
1034 | 45 | Flickable { | ||
1035 | 46 | id: flicker | ||
1036 | 47 | width: parent.width | ||
1037 | 48 | height: 400 | ||
1038 | 49 | contentWidth: rect.width | ||
1039 | 50 | contentHeight: rect.height | ||
1040 | 51 | clip: true | ||
1041 | 52 | Rectangle { | ||
1042 | 53 | id: rect | ||
1043 | 54 | color: "blue" | ||
1044 | 55 | width: 1000 | ||
1045 | 56 | height: 1000 | ||
1046 | 57 | } | ||
1047 | 58 | } | ||
1048 | 40 | } | 59 | } |
1049 | 41 | 60 | ||
1050 | 42 | UbuntuTestCase { | 61 | UbuntuTestCase { |
1051 | 43 | name: "TestTheUbuntuTestCase" | 62 | name: "TestTheUbuntuTestCase" |
1052 | 44 | when: windowShown | 63 | when: windowShown |
1053 | 45 | 64 | ||
1054 | 65 | function init() { | ||
1055 | 66 | mouseArea.steps = 0; | ||
1056 | 67 | } | ||
1057 | 68 | function cleanup() { | ||
1058 | 69 | movementSpy.clear(); | ||
1059 | 70 | longPressSpy.clear(); | ||
1060 | 71 | } | ||
1061 | 72 | |||
1062 | 46 | function test_mouseMoveSlowly() { | 73 | function test_mouseMoveSlowly() { |
1064 | 47 | mouseMoveSlowly(root,0,0,800,600,10,100); | 74 | mouseMoveSlowly(root,0,0,800,300,10,100); |
1065 | 48 | compare(mouseArea.testX,800); | 75 | compare(mouseArea.testX,800); |
1067 | 49 | compare(mouseArea.testY,600); | 76 | compare(mouseArea.testY,300); |
1068 | 50 | compare(mouseArea.steps,10); | 77 | compare(mouseArea.steps,10); |
1069 | 51 | } | 78 | } |
1070 | 52 | 79 | ||
1071 | @@ -58,5 +85,66 @@ | |||
1072 | 58 | child = findChild(root,"NoSuchChildHere"); | 85 | child = findChild(root,"NoSuchChildHere"); |
1073 | 59 | compare(child===null,true,"When there is no child, function should return null"); | 86 | compare(child===null,true,"When there is no child, function should return null"); |
1074 | 60 | } | 87 | } |
1075 | 88 | |||
1076 | 89 | SignalSpy { | ||
1077 | 90 | id: longPressSpy | ||
1078 | 91 | target: mouseArea | ||
1079 | 92 | signalName: "onPressAndHold" | ||
1080 | 93 | } | ||
1081 | 94 | |||
1082 | 95 | function test_longPress_left() { | ||
1083 | 96 | longPressSpy.clear(); | ||
1084 | 97 | mouseLongPress(mouseArea, mouseArea.width / 2, mouseArea.height / 2); | ||
1085 | 98 | longPressSpy.wait(); | ||
1086 | 99 | // cleanup | ||
1087 | 100 | mouseRelease(mouseArea, mouseArea.width / 2, mouseArea.height / 2); | ||
1088 | 101 | } | ||
1089 | 102 | |||
1090 | 103 | function test_longPress_right() { | ||
1091 | 104 | longPressSpy.clear(); | ||
1092 | 105 | mouseLongPress(mouseArea, mouseArea.width / 2, mouseArea.height / 2, Qt.RightButton); | ||
1093 | 106 | longPressSpy.wait(); | ||
1094 | 107 | // cleanup | ||
1095 | 108 | mouseRelease(mouseArea, mouseArea.width / 2, mouseArea.height / 2, Qt.RightButton); | ||
1096 | 109 | } | ||
1097 | 110 | |||
1098 | 111 | function test_longPress_middle() { | ||
1099 | 112 | longPressSpy.clear(); | ||
1100 | 113 | mouseLongPress(mouseArea, mouseArea.width / 2, mouseArea.height / 2, Qt.MiddleButton); | ||
1101 | 114 | longPressSpy.wait(); | ||
1102 | 115 | // cleanup | ||
1103 | 116 | mouseRelease(mouseArea, mouseArea.width / 2, mouseArea.height / 2, Qt.MiddleButton); | ||
1104 | 117 | } | ||
1105 | 118 | |||
1106 | 119 | SignalSpy { | ||
1107 | 120 | id: movementSpy | ||
1108 | 121 | target: flicker | ||
1109 | 122 | signalName: "onMovementEnded" | ||
1110 | 123 | } | ||
1111 | 124 | |||
1112 | 125 | function test_flick_default() { | ||
1113 | 126 | flick(flicker, 0, 0, flicker.width, flicker.height); | ||
1114 | 127 | movementSpy.wait(); | ||
1115 | 128 | } | ||
1116 | 129 | function test_flick_long() { | ||
1117 | 130 | flick(flicker, 0, 0, flicker.width, flicker.height, -1, 10); | ||
1118 | 131 | movementSpy.wait(); | ||
1119 | 132 | } | ||
1120 | 133 | function test_flick_short() { | ||
1121 | 134 | flick(flicker, 0, 0, flicker.width, flicker.height, -1, 1); | ||
1122 | 135 | movementSpy.wait(); | ||
1123 | 136 | } | ||
1124 | 137 | function test_flick_pressTimeout() { | ||
1125 | 138 | flick(flicker, 0, 0, flicker.width, flicker.height, 400); | ||
1126 | 139 | movementSpy.wait(); | ||
1127 | 140 | } | ||
1128 | 141 | function test_flick_pressTimeout_short() { | ||
1129 | 142 | flick(flicker, flicker.width, flicker.height, -flicker.width, -flicker.height, 400, 1); | ||
1130 | 143 | movementSpy.wait(); | ||
1131 | 144 | } | ||
1132 | 145 | function test_flick_pressTimeout_long() { | ||
1133 | 146 | flick(flicker, flicker.width, flicker.height, -flicker.width, -flicker.height, 400, 100); | ||
1134 | 147 | movementSpy.wait(); | ||
1135 | 148 | } | ||
1136 | 61 | } | 149 | } |
1137 | 62 | } | 150 | } |
FAILED: Continuous integration, rev:900 jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- ci/1483/ jenkins. qa.ubuntu. com/job/ generic- mediumtests- trusty/ 1856/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- trusty- touch/1773/ console jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- trusty- amd64-ci/ 431/console jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- trusty- armhf-ci/ 431/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- trusty- amd64/1856/ console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- trusty- armhf/1773/ console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/ubuntu- ui-toolkit- ci/1483/ rebuild
http://