Merge lp:~zsombi/ubuntu-ui-toolkit/dynamic-tabs-reloaded into lp:ubuntu-ui-toolkit

Proposed by Zsombor Egri
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
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.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Tim Peeters (tpeeters) wrote :

637 + * Copyright 2012 Canonical Ltd.

2013

Revision history for this message
Cris Dywan (kalikiana) wrote :

I'm seeing a number of errors while using the tabbar test:

modules/Ubuntu/Components/Tabs.qml:598: TypeError: Cannot call method 'indexOf' of undefined
coming from connectToRepeaters
modules/Ubuntu/Components/Tabs.qml:360: ReferenceError: MathUtils is not defined
coming from insertTab
modules/Ubuntu/Components/Themes/Ambiance/TabBarStyle.qml:119: TypeError: Cannot read property of null
coming from anchors.top on the Repeater, not sure what this is

review: Needs Fixing
Revision history for this message
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.

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

> 637 + * Copyright 2012 Canonical Ltd.
>
> 2013

It's 2014 now :)

Revision history for this message
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

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

+/*!
463 + * \internal
464 + * Moves a given item to the specified index in its parent's child list.
465 + */
466 +void QuickUtils::moveItemBefore(QQuickItem *item, QQuickItem *before)

description doesn't exactly match the function specs.
* Moves a given item before the specified item in their parent's child list
?

Revision history for this message
Cris Dywan (kalikiana) wrote :

That one escaped me; I'll give green light with the above sentence fixed.

review: Approve (provided moveitembefore docs are fixed)
Revision history for this message
Cris Dywan (kalikiana) wrote :
Revision history for this message
Tim Peeters (tpeeters) wrote :

note that you didn't fix the doc yet

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

I changed the status back to needs review, because we need to re-do the CI@home with qt52.

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

> note that you didn't fix the doc yet

Sorry, done now.

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

> modules/Ubuntu/Components/Tabs.qml:360: ReferenceError: MathUtils is not
> defined

This is still broken. Please add the include in Tabs.qml.

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

> I'm seeing a number of errors while using the tabbar test:
>
> modules/Ubuntu/Components/Tabs.qml:598: TypeError: Cannot call method
> 'indexOf' of undefined
> coming from connectToRepeaters
> modules/Ubuntu/Components/Tabs.qml:360: ReferenceError: MathUtils is not
> defined
> coming from insertTab
> modules/Ubuntu/Components/Themes/Ambiance/TabBarStyle.qml:119: TypeError:
> 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

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

>
> > modules/Ubuntu/Components/Tabs.qml:360: ReferenceError: MathUtils is not
> > defined
>
> This is still broken. Please add the include in Tabs.qml.

I'm wondering why was it passing till now???

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

ok

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

staging merge

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CHANGES'
--- CHANGES 2014-02-24 22:03:55 +0000
+++ CHANGES 2014-04-10 11:34:46 +0000
@@ -9,6 +9,7 @@
99
10API Changes10API Changes
11***********11***********
12* DEPRECATED IN: Tabs: default property list<Item> tabChildren
12* ADDED IN: PickerDelegate: readonly property Picker picker13* ADDED IN: PickerDelegate: readonly property Picker picker
13* CHANGED IN: OptionSelector: readonly property bool currentlyExpanded TO property bool currentlyExpanded14* CHANGED IN: OptionSelector: readonly property bool currentlyExpanded TO property bool currentlyExpanded
14* CHANGED IN: ItemSelector: readonly property bool currentlyExpanded TO property bool currentlyExpanded15* CHANGED IN: ItemSelector: readonly property bool currentlyExpanded TO property bool currentlyExpanded
1516
=== modified file 'components.api'
--- components.api 2014-04-01 12:57:27 +0000
+++ components.api 2014-04-10 11:34:46 +0000
@@ -417,9 +417,14 @@
417 readonly property Tab selectedTab417 readonly property Tab selectedTab
418 readonly property Item currentPage418 readonly property Item currentPage
419 property TabBar tabBar419 property TabBar tabBar
420 default property list<Item> tabChildren420 property list<Item> tabChildren
421 readonly property int count421 readonly property int count
422 signal modelChanged()422 signal modelChanged()
423 function addTab(title, tab)
424 function insertTab(index, title, tab)
425 function getTab(index)
426 function moveTab(from, to)
427 function removeTab(index)
423modules/Ubuntu/Components/TextArea.qml428modules/Ubuntu/Components/TextArea.qml
424StyledItem429StyledItem
425 property bool highlighted430 property bool highlighted
@@ -593,6 +598,8 @@
593 function findChild(obj,objectName)598 function findChild(obj,objectName)
594 function findInvisibleChild(obj,objectName)599 function findInvisibleChild(obj,objectName)
595 function mouseMoveSlowly(item,x,y,dx,dy,steps,stepdelay)600 function mouseMoveSlowly(item,x,y,dx,dy,steps,stepdelay)
601 function flick(item, x, y, dx, dy, pressTimeout, steps, button, modifiers, delay)
602 function mouseLongPress(item, x, y, button, modifiers, delay)
596 function tryCompareFunction(func, expectedResult, timeout)603 function tryCompareFunction(func, expectedResult, timeout)
597plugins.qmltypes604plugins.qmltypes
598 name: "InverseMouseAreaType"605 name: "InverseMouseAreaType"
599606
=== modified file 'modules/Ubuntu/Components/Tab.qml'
--- modules/Ubuntu/Components/Tab.qml 2013-11-07 07:26:01 +0000
+++ modules/Ubuntu/Components/Tab.qml 2014-04-10 11:34:46 +0000
@@ -105,12 +105,5 @@
105 Tab is destroyed upon removal.105 Tab is destroyed upon removal.
106 */106 */
107 property bool dynamic: false107 property bool dynamic: false
108
109 /*
110 This flag is used by the Tabs to determine whether the pre-declared Tab was removed
111 from the Tabs model or not. The flag guards adding back pre-declared tabs upon Tabs
112 component stack (children) change.
113 */
114 property bool removedFromTabs: false
115 }108 }
116}109}
117110
=== modified file 'modules/Ubuntu/Components/Tabs.qml'
--- modules/Ubuntu/Components/Tabs.qml 2014-04-08 12:38:35 +0000
+++ modules/Ubuntu/Components/Tabs.qml 2014-04-10 11:34:46 +0000
@@ -15,6 +15,7 @@
15 */15 */
1616
17import QtQuick 2.017import QtQuick 2.0
18import "mathUtils.js" as MathUtils
1819
19/*!20/*!
20 \qmltype Tabs21 \qmltype Tabs
@@ -149,6 +150,110 @@
149 }150 }
150 }151 }
151 \endqml152 \endqml
153
154 \section2 Dynamic tabs
155 So far all Tab elements were pre-declared, but there can be situations when
156 tabs need to be added dynamically. There are two ways to solve this, depending
157 on the output needed.
158
159 \section3 Using Repeaters
160 A Repeater can be used to create the necessary tabs depending on a given model.
161 In this way the number of tabs will be driven by the model itself.
162 An example of such a dynamic tab:
163 \qml
164 // DynamicTab.qml
165 import QtQuick 2.0
166 import Ubuntu.Components 0.1
167
168 Tabs {
169 property alias model: tabRepeater.model
170 Repeater {
171 id: tabRepeater
172 model: 5
173 Tab {
174 title: "Tab #" + index
175 page: Page {
176 // [...]
177 }
178 }
179 }
180 }
181 \endqml
182 Note that in the example above the Tabs will be re-created each time the model
183 changes. This will cause state losing of each Tab, which depending on the
184 content type can be solved at some extent using StateSaver. Using a Loader
185 or specifying the Tab instance/component in the model the state can be preserved,
186 however may increase code complexity.
187
188 \section3 Dynamic tabs
189 Tabs provides functions to add Tab elements dynamically on runtime, without
190 destroying the state of the existing tabs. You can add, move and remove any
191 kind of Tab element, pre-declared or dynamically created ones. When removing
192 pre-declared tabs, those will all be held back and hidden by Tabs, and can be
193 added back any time either to the same or to a different position.
194
195 \qml
196 import QtQuick 2.0
197 import Ubuntu.Components 0.1
198
199 MainView {
200 width: units.gu(40)
201 height: units.gu(71)
202
203 Component {
204 id: dynamicTab
205 Tab {
206 page: Page {
207 Label {
208 text: title
209 anchors.centerIn: parent
210 }
211 }
212 }
213 }
214 Tabs {
215 id: tabs
216 Tab {
217 title: "Main tab"
218 page: Page {
219 toolbar: ToolbarItems {
220 ToolbarButton {
221 text: "remove predeclared"
222 onTriggered: tabs.removeTab(preDeclared.index)
223 }
224 ToolbarButton {
225 text: "add new"
226 onTriggered: tabs.addTab("New tab", dynamicTab)
227 }
228 ToolbarButton {
229 text: "insert predeclared"
230 onTriggered: tabs.insertTab("", 0)
231 }
232 }
233 }
234 }
235 Tab {
236 id: preDeclared
237 title: "Pre-declared tab"
238 page: Page {
239 Label {
240 text: "This is a predeclared tab at index #" + index
241 anchors.centerIn: parent
242 }
243 }
244 }
245 }
246 }
247 \endqml
248
249 \section3 Using Repeater and functions together
250 Repeaters re-create their delegates as many times the model changes. Tabs added
251 or moved in between the tabs maintained by the Repeater, as well as reordered
252 through the Tabs functions will be re-arranged once the Repeater's model changes.
253 This should be taken into account when designing the application, and the use
254 of Repeater and functions toghether should be avoided if possible, or at least
255 Repeater should always add tabs to te tail of the tab stack, and no tab insertion
256 happens in that area.
152*/257*/
153PageTreeNode {258PageTreeNode {
154 id: tabs259 id: tabs
@@ -186,10 +291,14 @@
186 }291 }
187292
188 /*!293 /*!
189 Children are placed in a separate item that has functionality to extract the Tab items.294 \deprecated
295 Children are placed in a separate item that has functionality to extract
296 the Tab items.
297 Note: this property is deprecated. Tab components are directly parented
298 to Tabs' data property.
190 \qmlproperty list<Item> tabChildren299 \qmlproperty list<Item> tabChildren
191 */300 */
192 default property alias tabChildren: tabStack.data301 property alias tabChildren: tabs.data
193302
194 /*!303 /*!
195 \qmlproperty int count304 \qmlproperty int count
@@ -206,36 +315,180 @@
206 signal modelChanged()315 signal modelChanged()
207316
208 /*!317 /*!
318 Appends a Tab dynamically to the list of tabs. The \a title specifies the
319 title of the Tab. The \a tab can be either a Component, a URL to a Tab
320 component to be loaded or an instance of a pre-declared tab that has been
321 previously removed. The Tab's title will be replaced with the given \a title,
322 unless the value is an empty string or undefined.
323 Returns the instance of the added Tab.
324 */
325 function addTab(title, tab) {
326 return insertTab(count, title, tab);
327 }
328
329 /*!
330 Inserts a Tab at the given index. If the \a index is less or equal than 0,
331 the Tab will be added to the front, and to the end of the tab stack in case
332 the \a index is greater than \l count. \a title and \a tab are used in the
333 same way as with \l addTab().
334 Returns the instance of the inserted Tab.
335 */
336 function insertTab(index, title, tab) {
337 // check if the given component is a Tab instance
338 var tabObject = null;
339
340 if (typeof tab === "string") {
341 // we have a URL
342 var tabComponent = Qt.createComponent(tab);
343 if (tabComponent.status === Component.Error) {
344 console.error(tabComponent.errorString());
345 return null;
346 }
347 tabObject = tabComponent.createObject();
348 tabObject.__protected.dynamic = true;
349 } else if (tab.hasOwnProperty("createObject")) {
350 // we have a Component
351 tabObject = tab.createObject();
352 tabObject.__protected.dynamic = true;
353 } else if (tab.hasOwnProperty("parent") && tab.parent === trashedTabs) {
354 // we have a pre-declared tab that has been removed
355 tabObject = tab;
356 } else {
357 console.error(i18n.tr("The object is not a URL, Component or a removed Tab: ") + tab);
358 return null;
359 }
360
361 // fix title
362 if (title !== undefined && title !== "") {
363 tabObject.title = title;
364 }
365
366 // insert the created tab into the model
367 index = MathUtils.clamp(index, 0, count);
368 tabObject.__protected.inserted = true;
369 tabObject.__protected.index = index;
370 tabsModel.insertTab(tabObject, index);
371 if (tabs.selectedTabIndex >= index) {
372 // move the selected index to the next index
373 tabs.selectedTabIndex += 1;
374 } else {
375 internal.sync();
376 }
377 return tabObject;
378 }
379
380 /*!
381 The function returns the Tab from the given \a index, or null if the \a index
382 is invalid (less than \c 0 and greater than \l count).
383 */
384 function getTab(index) {
385 return (index >=0) && (index < count) ? tabsModel.get(index).tab : null;
386 }
387
388 /*!
389 Moves the tab from the given \a from position to the position given in \a to.
390 Returns true if the indexes were in 0..\l count - 1 boundary and if the operation
391 succeeds, and false otherwise. The \l selectedTabIndex is updated if it is
392 affected by the move (it is equal with \a from or falls between \a from and
393 \a to indexes).
394 */
395 function moveTab(from, to) {
396 if (from < 0 || from >= count || to < 0 || to >= count || from === to) return false;
397 var tabFrom = tabsModel.get(from).tab;
398 var tabTo = tabsModel.get(to).tab;
399
400 // move tab
401 QuickUtils.moveItemBefore(tabFrom, tabTo);
402 tabsModel.updateTabList(tabs.children);
403
404 // fix selected tab
405 if (selectedTabIndex === from) {
406 selectedTabIndex = to;
407 } else if (selectedTabIndex >= Math.min(from, to) && selectedTabIndex <= Math.max(from, to)) {
408 selectedTabIndex--;
409 } else {
410 internal.sync();
411 }
412
413 return true;
414 }
415
416 /*!
417 Removes the Tab from the given \a index. Returns true if the \a index falls
418 into 0..\l count - 1 boundary and the operation succeeds, and false on error.
419 The function removes also the pre-declared tabs. These can be added back using
420 \l addTab or \l insertTab by specifying the instance of the Tab to be added as
421 component. The \l selectedTabIndex is updated if is affected by the removal
422 (it is identical or greater than the tab index to be removed).
423 */
424 function removeTab(index) {
425 if (index < 0 || index >= count) return false;
426 var tab = tabsModel.get(index).tab;
427 var activeIndex = (selectedTabIndex >= index) ? MathUtils.clamp(selectedTabIndex, 0, count - 2) : -1;
428
429 // remove from Tabs; Tabs children change will remove the tab from the model
430 tab.parent = null;
431 if (tab.__protected.dynamic) {
432 tab.destroy();
433 } else {
434 // pre-declared tab, mark it as removed, so we don't update it next time
435 // the tabs stack children is updated
436 tab.parent = trashedTabs;
437 }
438
439 // move active tab if needed
440 if (activeIndex >= 0 && activeIndex !== selectedTabIndex) {
441 selectedTabIndex = activeIndex;
442 } else {
443 internal.sync();
444 }
445
446 return true;
447 }
448
449 /*! \internal */
450 onChildrenChanged: {
451 internal.connectToRepeaters(tabs.children);
452 tabsModel.updateTabList(tabs.children);
453 }
454
455 /*!
209 \internal456 \internal
210 required by TabsStyle457 required by TabsStyle
211 */458 */
212 ListModel {459 ListModel {
213 id: tabsModel460 id: tabsModel
214461
462 property bool updateDisabled: false
463
215 function listModel(tab) {464 function listModel(tab) {
216 return {"title": tab.title, "tab": tab};465 return {"title": tab.title, "tab": tab};
217 }466 }
218467
219 function updateTabList(tabsList) {468 function updateTabList(tabsList) {
469 if (updateDisabled) return;
220 var offset = 0;470 var offset = 0;
221 var tabIndex;471 var tabIndex = -1;
222 for (var i in tabsList) {472 for (var i in tabsList) {
223 var tab = tabsList[i];473 var tab = tabsList[i];
224 if (internal.isTab(tab)) {474 if (internal.isTab(tab)) {
225 tabIndex = i - offset;475 tabIndex = i - offset;
226 // make sure we have the right parent476 // make sure we have the right parent
227 tab.parent = tabStack;477 tab.parent = tabs;
228478
229 if (!tab.__protected.inserted) {479 if (!tab.__protected.inserted) {
230 tab.__protected.index = tabIndex;480 tab.__protected.index = tabIndex;
231 tab.__protected.inserted = true;481 tab.__protected.inserted = true;
232 insert(tabIndex, listModel(tab));482 insert(tabIndex, listModel(tab));
233 } else if (!tab.__protected.removedFromTabs && tabsModel.count > tab.index) {483 } else {
234 get(tab.index).title = tab.title;484 get(tab.index).title = tab.title;
235 }485 }
236486
237 // always makes sure that tabsModel has the same order as tabsList487 // always makes sure that tabsModel has the same order as tabsList
238 move(tab.__protected.index, tabIndex, 1);488 // but move only if there is more than one item in the list
489 if (count > 1) {
490 move(tab.__protected.index, tabIndex, 1);
491 }
239 reindex();492 reindex();
240 } else {493 } else {
241 // keep track of children that are not tabs so that we compute494 // keep track of children that are not tabs so that we compute
@@ -243,6 +496,10 @@
243 offset += 1;496 offset += 1;
244 }497 }
245 }498 }
499 // remove deleted tabs, those should be at the end of the list by now
500 if ((tabIndex >= 0) && (tabIndex + 1) < count) {
501 remove(tabIndex + 1, count - tabIndex - 1);
502 }
246 internal.sync();503 internal.sync();
247 }504 }
248505
@@ -257,18 +514,31 @@
257 tab.__protected.index = i;514 tab.__protected.index = i;
258 }515 }
259 }516 }
517
518 function insertTab(tab, index) {
519 // fix index
520 if (index < 0) {
521 index = 0;
522 }
523 // get the tab before which the item will be inserted
524 var itemAtIndex = ((index >= 0) && (index < count)) ? get(index).tab : null;
525 // disable update only if we insert, append can keep the logic rolling
526 updateDisabled = (itemAtIndex !== null);
527 insert(index, listModel(tab));
528 tab.parent = tabs;
529 updateDisabled = false;
530 if (itemAtIndex) {
531 QuickUtils.moveItemBefore(tab, itemAtIndex);
532 updateTabList(tabs.children);
533 }
534 }
260 }535 }
261536
262 // FIXME: this component is not really needed, as it doesn't really bring any537 // invisible component stacking removed pre-declared components
263 // value; should be removed in a later MR
264 Item {538 Item {
265 anchors.fill: parent539 id: trashedTabs
266 id: tabStack540 visible: false
267541 opacity: 0.0
268 onChildrenChanged: {
269 internal.connectToRepeaters(tabStack.children);
270 tabsModel.updateTabList(tabStack.children);
271 }
272 }542 }
273543
274 /*544 /*
@@ -283,7 +553,7 @@
283 interval: 1553 interval: 1
284 running: false554 running: false
285 onTriggered: {555 onTriggered: {
286 tabsModel.updateTabList(tabStack.children);556 tabsModel.updateTabList(tabs.children);
287 internal.sync();557 internal.sync();
288 }558 }
289 }559 }
@@ -295,8 +565,8 @@
295 Binding {565 Binding {
296 target: tabBar566 target: tabBar
297 property: "animate"567 property: "animate"
298 when: internal.header && internal.header.hasOwnProperty("animate")568 when: (internal.header !== null) && internal.header.hasOwnProperty("animate")
299 value: internal.header.animate569 value: internal.header ? internal.header.animate : "false"
300 }570 }
301571
302 /*572 /*
@@ -332,7 +602,9 @@
332 function connectToRepeaters(children) {602 function connectToRepeaters(children) {
333 for (var i = 0; i < children.length; i++) {603 for (var i = 0; i < children.length; i++) {
334 var child = children[i];604 var child = children[i];
335 if (internal.isRepeater(child) && (internal.repeaters.indexOf(child) < 0)) {605 if (internal.isRepeater(child) &&
606 (internal.repeaters !== undefined) &&
607 (internal.repeaters.indexOf(child) < 0)) {
336 internal.connectRepeater(child);608 internal.connectRepeater(child);
337 }609 }
338 }610 }
@@ -355,7 +627,7 @@
355 https://bugreports.qt-project.org/browse/QTBUG-32438627 https://bugreports.qt-project.org/browse/QTBUG-32438
356 */628 */
357 function updateTabsModel() {629 function updateTabsModel() {
358 tabsModel.updateTabList(tabStack.children);630 tabsModel.updateTabList(tabs.children);
359 }631 }
360632
361 /*633 /*
362634
=== modified file 'modules/Ubuntu/Components/Themes/Ambiance/TabBarStyle.qml'
--- modules/Ubuntu/Components/Themes/Ambiance/TabBarStyle.qml 2014-04-08 12:38:35 +0000
+++ modules/Ubuntu/Components/Themes/Ambiance/TabBarStyle.qml 2014-04-10 11:34:46 +0000
@@ -116,8 +116,8 @@
116 AbstractButton {116 AbstractButton {
117 id: button117 id: button
118 anchors {118 anchors {
119 top: parent.top119 top: parent ? parent.top : undefined
120 bottom: parent.bottom120 bottom: parent ? parent.bottom: undefined
121 }121 }
122 width: text.paintedWidth + text.anchors.leftMargin + text.anchors.rightMargin122 width: text.paintedWidth + text.anchors.leftMargin + text.anchors.rightMargin
123123
@@ -150,6 +150,13 @@
150 return false;150 return false;
151 }151 }
152152
153 // update the offset of the buttonRow
154 onOffsetChanged: {
155 if (selected) {
156 buttonView.updateOffset(button.offset);
157 }
158 }
159
153 Behavior on opacity {160 Behavior on opacity {
154 NumberAnimation {161 NumberAnimation {
155 duration: headerTextFadeDuration162 duration: headerTextFadeDuration
156163
=== modified file 'modules/Ubuntu/Components/plugin/quickutils.cpp'
--- modules/Ubuntu/Components/plugin/quickutils.cpp 2014-03-20 15:46:28 +0000
+++ modules/Ubuntu/Components/plugin/quickutils.cpp 2014-04-10 11:34:46 +0000
@@ -119,6 +119,21 @@
119 return result.left(result.indexOf("_QML"));119 return result.left(result.indexOf("_QML"));
120}120}
121121
122/*!
123 * \internal
124 * Moves a given \a item before the \a other one in the object stack. Both \a item
125 * and \a other must have the same parent item.
126 */
127void QuickUtils::moveItemBefore(QQuickItem *item, QQuickItem *other)
128{
129 Q_ASSERT(item);
130 Q_ASSERT(item->parentItem());
131 if (other) {
132 Q_ASSERT(other->parentItem() == item->parentItem());
133 item->stackBefore(other);
134 }
135}
136
122137
123/*!138/*!
124 * \internal139 * \internal
125140
=== modified file 'modules/Ubuntu/Components/plugin/quickutils.h'
--- modules/Ubuntu/Components/plugin/quickutils.h 2014-03-20 15:46:28 +0000
+++ modules/Ubuntu/Components/plugin/quickutils.h 2014-04-10 11:34:46 +0000
@@ -42,6 +42,7 @@
42 QString inputMethodProvider() const;42 QString inputMethodProvider() const;
4343
44 Q_INVOKABLE static QString className(QObject *item);44 Q_INVOKABLE static QString className(QObject *item);
45 Q_INVOKABLE void moveItemBefore(QQuickItem *item, QQuickItem *before);
45 QObject* createQmlObject(const QUrl &url, QQmlEngine *engine);46 QObject* createQmlObject(const QUrl &url, QQmlEngine *engine);
4647
47Q_SIGNALS:48Q_SIGNALS:
4849
=== modified file 'modules/Ubuntu/Test/UbuntuTestCase.qml'
--- modules/Ubuntu/Test/UbuntuTestCase.qml 2014-02-25 12:36:27 +0000
+++ modules/Ubuntu/Test/UbuntuTestCase.qml 2014-04-10 11:34:46 +0000
@@ -87,7 +87,75 @@
87 }87 }
88 }88 }
8989
90 /*!90 /*!
91 \qmlmethod UbuntuTestCase::flick(item, x, y, dx, dy, pressTimeout = -1, steps = -1, button = Qt.LeftButton, modifiers = Qt.NoModifiers, delay = -1)
92
93 The function produces a flick event when executed on Flickables. When used
94 on other components it provides the same functionality as \l mouseDrag()
95 function. The optional \a pressTimeout parameter can be used to introduce
96 a small delay between the mouse press and the first mouse move. Setting a
97 negative or zero value will disable the timeout.
98
99 The default flick velocity is built up using 5 move points. This can be altered
100 by setting a positive value to \a steps parameter. The bigger the number the
101 longer the flick will be. When a negative or zero value is given, the default
102 of 5 move points will be used.
103
104 \note The function can be used to select a text in a TextField or TextArea by
105 specifying at least 400 millisecods to \a pressTimeout.
106 */
107 function flick(item, x, y, dx, dy, pressTimeout, steps, button, modifiers, delay) {
108 if (item === undefined || item.x === undefined || item.y === undefined)
109 return
110 if (button === undefined)
111 button = Qt.LeftButton
112 if (modifiers === undefined)
113 modifiers = Qt.NoModifier
114 if (steps === undefined || steps <= 0)
115 steps = 4;
116 // make sure we have at least two move steps so the flick will be sensed
117 steps += 1;
118 if (delay === undefined)
119 delay = -1;
120
121 var ddx = dx / steps;
122 var ddy = dy / steps;
123
124 mousePress(item, x, y, button, modifiers, delay);
125 if (pressTimeout !== undefined && pressTimeout > 0) {
126 wait(pressTimeout);
127 }
128 for (var i = 1; i <= steps; i++) {
129 // mouse moves are all processed immediately, without delay in between events
130 mouseMove(item, x + i * ddx, y + i * ddy, -1, button);
131 }
132 mouseRelease(item, x + dx, y + dy, button, modifiers, delay);
133 // empty event buffer
134 wait(200);
135 }
136
137 /*!
138 \qmlmethod UbuntuTestCase::mouseLongPress(item, x, y, button = Qt.LeftButton, modifiers = Qt.NoModifiers, delay = -1)
139
140 Simulates a long press on a mouse \a button with an optional \a modifier
141 on an \a item. The position is defined by \a x and \a y. If \a delay is
142 specified, the test will wait the specified amount of milliseconds before
143 the press.
144
145 The position given by \a x and \a y is transformed from the co-ordinate
146 system of \a item into window co-ordinates and then delivered.
147 If \a item is obscured by another item, or a child of \a item occupies
148 that position, then the event will be delivered to the other item instead.
149
150 \sa mouseRelease(), mouseClick(), mouseDoubleClick(), mouseMove(), mouseDrag(), mouseWheel()
151 */
152 function mouseLongPress(item, x, y, button, modifiers, delay) {
153 mousePress(item, x, y, button, modifiers, delay);
154 // the delay is taken from QQuickMouseArea
155 wait(800);
156 }
157
158 /*!
91 Keeps executing a given parameter-less function until it returns the given159 Keeps executing a given parameter-less function until it returns the given
92 expected result or the timemout is reached (in which case a test failure160 expected result or the timemout is reached (in which case a test failure
93 is generated)161 is generated)
94162
=== modified file 'modules/Ubuntu/Test/deployment.pri'
--- modules/Ubuntu/Test/deployment.pri 2014-01-17 12:30:05 +0000
+++ modules/Ubuntu/Test/deployment.pri 2014-04-10 11:34:46 +0000
@@ -7,9 +7,14 @@
7# make found deployables visible in Qt Creator7# make found deployables visible in Qt Creator
8OTHER_FILES += $$QMLDIR_FILE8OTHER_FILES += $$QMLDIR_FILE
99
10QML_FILES = $$system(ls *.qml)
11JS_FILES = $$system(ls *.js)
12
10# define deployment for found deployables13# define deployment for found deployables
11qmldir_file.path = $$installPath14qmldir_file.path = $$installPath
12qmldir_file.files = $$QMLDIR_FILE15qmldir_file.files = $$QMLDIR_FILE
16qml_files.path = $$installPath
17qml_files.files = $$QML_FILES
13js_files.path = $$installPath18js_files.path = $$installPath
14js_files.files = $$JS_FILES19js_files.files = $$JS_FILES
1520
@@ -20,4 +25,4 @@
20# https://bugreports.qt-project.org/browse/QTBUG-3624325# https://bugreports.qt-project.org/browse/QTBUG-36243
21plugins_qmltypes.extra = $$[QT_INSTALL_BINS]/qmlplugindump -notrelocatable Ubuntu.Test 0.1 ../../ 2>/dev/null > $(INSTALL_ROOT)/$$installPath/plugins.qmltypes26plugins_qmltypes.extra = $$[QT_INSTALL_BINS]/qmlplugindump -notrelocatable Ubuntu.Test 0.1 ../../ 2>/dev/null > $(INSTALL_ROOT)/$$installPath/plugins.qmltypes
2227
23INSTALLS += qmldir_file plugins_qmltypes28INSTALLS += qmldir_file plugins_qmltypes qml_files js_files
2429
=== modified file 'tests/resources/navigation/Tabs.qml'
--- tests/resources/navigation/Tabs.qml 2014-04-07 10:03:39 +0000
+++ tests/resources/navigation/Tabs.qml 2014-04-10 11:34:46 +0000
@@ -19,9 +19,47 @@
19import Ubuntu.Components.ListItems 0.1 as ListItem19import Ubuntu.Components.ListItems 0.1 as ListItem
2020
21MainView {21MainView {
22 id: root
22 width: 80023 width: 800
23 height: 60024 height: 600
2425
26 property var repeaterModel: 3
27
28 Component {
29 id: dynamicTab
30 Tab {
31 page: Page {
32 Label {
33 text: title + " at index " + index
34 anchors.centerIn: parent
35 }
36 tools: ToolbarItems {
37 ToolbarButton {
38 text: "move @1"
39 onTriggered: {
40 print("MOVE TAB TO #1")
41 tabs.moveTab(index, 1)
42 }
43 }
44 ToolbarButton {
45 text: "remove me"
46 onTriggered: {
47 print("REMOVE CURENT TAB")
48 tabs.removeTab(index)
49 }
50 }
51 ToolbarButton {
52 text: "remove first"
53 onTriggered: {
54 print("REMOVE TAB AT #0")
55 tabs.removeTab(0)
56 }
57 }
58 }
59 }
60 }
61 }
62
25 Tabs {63 Tabs {
26 id: tabs64 id: tabs
27 selectedTabIndex: 065 selectedTabIndex: 0
@@ -31,6 +69,7 @@
3169
32 Tab {70 Tab {
33 id: simpleTab71 id: simpleTab
72 objectName: title
34 title: i18n.tr("Simple page #" + index)73 title: i18n.tr("Simple page #" + index)
35 page: Page {74 page: Page {
36 Row {75 Row {
@@ -55,13 +94,60 @@
55 iconSource: "call_icon.png"94 iconSource: "call_icon.png"
56 onTriggered: print("action triggered")95 onTriggered: print("action triggered")
57 }96 }
97 ToolbarButton {
98 text: "append"
99 onTriggered: {
100 print("APPEND TAB")
101 tabs.addTab("Appended tab", dynamicTab)
102 }
103 }
104 ToolbarButton {
105 text: "insert@1"
106 onTriggered: {
107 print("INSERT TAB TO #1")
108 tabs.insertTab(1, "Inserted tab", dynamicTab)
109 }
110 }
111 ToolbarButton {
112 text: "insert@2"
113 onTriggered: {
114 print("INSERT BETWEEN REPEATERS #1")
115 tabs.insertTab(2, "Between repeaters", dynamicTab)
116 }
117 }
118 ToolbarButton {
119 text: "insert@here"
120 onTriggered: {
121 print("INSERT AFTER ME")
122 tabs.insertTab(simpleTab.index, "Inserted tab", dynamicTab)
123 }
124 }
125 ToolbarButton {
126 text: "incRep"
127 onTriggered: {
128 print("INCREASE REPEATER MODEL")
129 root.repeaterModel += 1
130 }
131 }
132 ToolbarButton {
133 text: "remove last"
134 onTriggered: {
135 print("REMOVE LAST TAB")
136 tabs.removeTab(tabs.count - 1)
137 }
138 }
139 ToolbarButton {
140 text: "append predec"
141 onTriggered: tabs.addTab("Re-added ListView", listViewTab)
142 }
58 }143 }
59 }144 }
60 }145 }
61 Repeater {146 Repeater {
62 model: 3147 model: root.repeaterModel
63 Tab {148 Tab {
64 id: tab149 id: tab
150 objectName: title
65 title: "Extra #" + tab.index151 title: "Extra #" + tab.index
66 page: Page {152 page: Page {
67 Column {153 Column {
@@ -88,6 +174,7 @@
88 }174 }
89 Tab {175 Tab {
90 id: externalTab176 id: externalTab
177 objectName: title
91 title: i18n.tr("External #" + index)178 title: i18n.tr("External #" + index)
92 page: Loader {179 page: Loader {
93 parent: externalTab180 parent: externalTab
@@ -96,6 +183,8 @@
96 }183 }
97 }184 }
98 Tab {185 Tab {
186 id: listViewTab
187 objectName: title
99 title: i18n.tr("List view #" + index)188 title: i18n.tr("List view #" + index)
100 page: Page {189 page: Page {
101 ListView {190 ListView {
102191
=== modified file 'tests/unit/runtest.sh'
--- tests/unit/runtest.sh 2014-03-31 18:26:46 +0000
+++ tests/unit/runtest.sh 2014-04-10 11:34:46 +0000
@@ -33,7 +33,7 @@
33 if [ $_TARGET != $_TESTFILE ]; then33 if [ $_TARGET != $_TESTFILE ]; then
34 _CMD="$_CMD -input $_TESTFILE"34 _CMD="$_CMD -input $_TESTFILE"
35 fi35 fi
36 _CMD="$_CMD -maxwarnings 4"36 _CMD="$_CMD -maxwarnings 40"
37}37}
3838
39function execute_test_cmd {39function execute_test_cmd {
4040
=== added file 'tests/unit_x11/tst_components/ExternalTab.qml'
--- tests/unit_x11/tst_components/ExternalTab.qml 1970-01-01 00:00:00 +0000
+++ tests/unit_x11/tst_components/ExternalTab.qml 2014-04-10 11:34:46 +0000
@@ -0,0 +1,21 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.0
18import Ubuntu.Components 0.1
19
20Tab {
21}
022
=== modified file 'tests/unit_x11/tst_components/tst_tabs.qml'
--- tests/unit_x11/tst_components/tst_tabs.qml 2014-01-13 12:43:12 +0000
+++ tests/unit_x11/tst_components/tst_tabs.qml 2014-04-10 11:34:46 +0000
@@ -27,6 +27,13 @@
27 id: emptyTabs27 id: emptyTabs
28 }28 }
2929
30 Component {
31 id: dynamicTab
32 Tab{
33 title: "OriginalTitle"
34 }
35 }
36
30 MainView {37 MainView {
31 id: mainView38 id: mainView
32 anchors.fill: parent39 anchors.fill: parent
@@ -424,5 +431,149 @@
424 mouseRelease(tabs.tabBar, tabs.tabBar.width/2, tabs.tabBar.height/2);431 mouseRelease(tabs.tabBar, tabs.tabBar.width/2, tabs.tabBar.height/2);
425 compare(tabs.tabBar.pressed, false, "After releasing, pressed is false");432 compare(tabs.tabBar.pressed, false, "After releasing, pressed is false");
426 }433 }
434
435
436
437 // these tests should not be mixed with Repeaters
438 function test_z_addTab() {
439 var newTab = tabs.addTab("Dynamic Tab", dynamicTab);
440 compare((newTab !== null), true, "tab added");
441 compare(newTab.active, false, "the inserted tab is inactive");
442 compare(newTab.index, tabs.count - 1, "the tab is the last one");
443 }
444
445 function test_z_addExternalTab() {
446 var newTab = tabs.addTab("External Tab", Qt.resolvedUrl("ExternalTab.qml"));
447 compare((newTab !== null), true, "tab added");
448 compare(newTab.active, false, "the inserted tab is inactive");
449 compare(newTab.index, tabs.count - 1, "the tab is the last one");
450 }
451
452 function test_z_addTabWithDefaultTitle() {
453 var newTab = tabs.addTab("", dynamicTab);
454 compare((newTab !== null), true, "tab added");
455 compare(newTab.title, "OriginalTitle", "tab created with original title");
456 }
457
458 function test_z_insertTab() {
459 var tabIndex = Math.ceil(tabs.count / 2);
460 var newTab = tabs.insertTab(tabIndex, "Inserted tab", dynamicTab);
461 compare((newTab !== null), true, "tab inserted");
462 compare(newTab.index, tabIndex, "this is the first tab");
463 compare(tabs.selectedTab !== newTab, true, "the new tab is not the active one");
464 }
465
466 function test_z_insertExternalTab() {
467 var tabIndex = Math.ceil(tabs.count / 2);
468 var newTab = tabs.insertTab(tabIndex, "Inserted External tab", Qt.resolvedUrl("ExternalTab.qml"));
469 compare((newTab !== null), true, "tab inserted");
470 compare(newTab.index, tabIndex, "this is the first tab");
471 compare(tabs.selectedTab !== newTab, true, "the new tab is not the active one");
472 }
473
474 function test_z_insertTabAtSelectedIndex() {
475 tabs.selectedTabIndex = 1;
476 var tabIndex = tabs.selectedTabIndex - 1;
477 var newTab = tabs.insertTab(tabIndex, "InsertedAtSelected tab", dynamicTab);
478 compare((newTab !== null), true, "tab inserted");
479 compare(newTab.index, tabIndex, "inserted at selected tab");
480 compare(tabs.selectedTabIndex != (tabIndex + 1), true, "it is not the selected tab");
481 }
482
483 function test_z_insertTabFront() {
484 var newTab = tabs.insertTab(-1, "PreTab", dynamicTab);
485 compare(newTab !== null, true, "pre-tab inserted");
486 compare(newTab.index, 0, "this is the new first tab");
487 compare(tabs.selectedTab !== newTab, true, "the new tab is not the active one");
488 }
489
490 function test_z_insertTabEnd() {
491 var newTab = tabs.insertTab(tabs.count, "PostTab", dynamicTab);
492 compare(newTab !== null, true, "post-tab inserted");
493 compare(newTab.index, tabs.count - 1, "thsi is the new last tab");
494 compare(tabs.selectedTab !== newTab, true, "the new tab is not the active one");
495 }
496
497 function test_z_insertTabAndActivate() {
498 var newTab = tabs.addTab("Inserted tab", dynamicTab);
499 compare((newTab !== null), true, "tab inserted");
500 compare(newTab.index, tabs.count - 1, "the tab is the last one");
501 tabs.selectedTabIndex = newTab.index;
502 compare(tabs.selectedTab, newTab, "the inserted tab is selected");
503 compare(newTab.active, true, "the new tab is active");
504 }
505
506 function test_z_moveTab() {
507 var selectedIndex = tabs.count - 1;
508 tabs.selectedTabIndex = selectedIndex;
509 compare(tabs.moveTab(0, selectedIndex), true, "first tab moved to last");
510 compare(tabs.selectedTabIndex, selectedIndex - 1, "the selected index moved backwards");
511 tabs.selectedTabIndex = selectedIndex = 0;
512 compare(tabs.moveTab(selectedIndex, selectedIndex + 1), true, "selected tab moved as next");
513 compare(tabs.selectedTabIndex, selectedIndex + 1, "the selected index moved forewards");
514 }
515
516 function test_z_moveSelectedTab() {
517 tabs.selectedTabIndex = 0;
518 tabs.moveTab(0, 1);
519 compare(tabs.selectedTabIndex, 1, "selected tab moved");
520 }
521
522 function test_z_moveTabFail() {
523 compare(tabs.moveTab(-1, tabs.count - 1), false, "from-parameter out of range");
524 compare(tabs.moveTab(0, tabs.count), false, "to-parameter out of range");
525 }
526
527 function test_z_removeTab() {
528 compare(tabs.removeTab(tabs.count - 1), true, "last tab removed");
529 tabs.selectedTabIndex = 0;
530 compare(tabs.removeTab(0), true, "active tab removed");
531 compare(tabs.selectedTabIndex, 0, "the next tab is selected")
532 }
533
534 function test_z_removeActiveTab() {
535 tabs.selectedTabIndex = 1;
536 compare(tabs.removeTab(1), true, "selected tab removed");
537 compare(tabs.selectedTabIndex, 1, "selected tab is next");
538
539 tabs.selectedTabIndex = tabs.count - 1;
540 compare(tabs.removeTab(tabs.count - 1), true, "last tab removed");
541 compare(tabs.selectedTabIndex, tabs.count - 1, "selected tab moved to last item");
542 }
543
544 function test_z_removeTabAfterActiveTab() {
545 var activeTab = tabs.count - 2;
546 tabs.selectedTabIndex = activeTab;
547 compare(tabs.removeTab(tabs.count - 1), true, "last tab removed");
548 compare(tabs.selectedTabIndex, activeTab, "the selected tab wasn't moved");
549 }
550
551 function test_z_removeTabBeforeActiveTab() {
552 var activeTab = tabs.count - 1;
553 tabs.selectedTabIndex = activeTab;
554 compare(tabs.removeTab(0), true, "first tab removed");
555 compare(tabs.selectedTabIndex, activeTab - 1, "the selected tab index decreased");
556 }
557
558 function test_zz_addTabAfterCleaningUpTabs() {
559 while (tabs.count > 1) {
560 tabs.removeTab(tabs.count - 1);
561 }
562 compare(tabs.selectedTabIndex, 0, "the only tab is the selected one");
563 // add a new tab anc check the count (default added tas should not be added anymore
564 tabs.addTab("Second tab", dynamicTab);
565 compare(tabs.count, 2, "we have two tabs only");
566 }
567
568 function test_zz_addPredeclaredTab() {
569 tabs.removeTab(tab1.index);
570
571 // add a predeclared tab back with original title
572 compare(tabs.addTab("", tab1), tab1, "tab1 was not added back");
573 compare(tab1.title, "tab 1", "the original title differs");
574
575 // add a predeclared tab which was added already
576 compare(tabs.addTab("", tab1), null, "tab1 is already in tabs");
577 }
427 }578 }
428}579}
429580
=== modified file 'tests/unit_x11/tst_test/tst_ubuntutestcase.qml'
--- tests/unit_x11/tst_test/tst_ubuntutestcase.qml 2014-02-13 10:27:14 +0000
+++ tests/unit_x11/tst_test/tst_ubuntutestcase.qml 2014-04-10 11:34:46 +0000
@@ -23,30 +23,57 @@
23 width: 80023 width: 800
24 height: 60024 height: 600
2525
26 MouseArea {26 Column {
27 id: mouseArea27 anchors.fill: parent
28 objectName: "myMouseArea"28 MouseArea {
29 anchors.fill: parent29 id: mouseArea
30 hoverEnabled: true30 objectName: "myMouseArea"
31 property int testX : 031 width: parent.width
32 property int testY : 032 height: 300
33 property int steps : 033 hoverEnabled: true
34 acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
35 property int testX : 0
36 property int testY : 0
37 property int steps : 0
3438
35 onPositionChanged: {39 onPositionChanged: {
36 testX = mouseX;40 testX = mouseX;
37 testY = mouseY;41 testY = mouseY;
38 steps++;42 steps++;
39 }43 }
44 }
45 Flickable {
46 id: flicker
47 width: parent.width
48 height: 400
49 contentWidth: rect.width
50 contentHeight: rect.height
51 clip: true
52 Rectangle {
53 id: rect
54 color: "blue"
55 width: 1000
56 height: 1000
57 }
58 }
40 }59 }
41 60
42 UbuntuTestCase {61 UbuntuTestCase {
43 name: "TestTheUbuntuTestCase"62 name: "TestTheUbuntuTestCase"
44 when: windowShown63 when: windowShown
4564
65 function init() {
66 mouseArea.steps = 0;
67 }
68 function cleanup() {
69 movementSpy.clear();
70 longPressSpy.clear();
71 }
72
46 function test_mouseMoveSlowly() {73 function test_mouseMoveSlowly() {
47 mouseMoveSlowly(root,0,0,800,600,10,100);74 mouseMoveSlowly(root,0,0,800,300,10,100);
48 compare(mouseArea.testX,800);75 compare(mouseArea.testX,800);
49 compare(mouseArea.testY,600);76 compare(mouseArea.testY,300);
50 compare(mouseArea.steps,10);77 compare(mouseArea.steps,10);
51 }78 }
5279
@@ -58,5 +85,66 @@
58 child = findChild(root,"NoSuchChildHere");85 child = findChild(root,"NoSuchChildHere");
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");
60 }87 }
88
89 SignalSpy {
90 id: longPressSpy
91 target: mouseArea
92 signalName: "onPressAndHold"
93 }
94
95 function test_longPress_left() {
96 longPressSpy.clear();
97 mouseLongPress(mouseArea, mouseArea.width / 2, mouseArea.height / 2);
98 longPressSpy.wait();
99 // cleanup
100 mouseRelease(mouseArea, mouseArea.width / 2, mouseArea.height / 2);
101 }
102
103 function test_longPress_right() {
104 longPressSpy.clear();
105 mouseLongPress(mouseArea, mouseArea.width / 2, mouseArea.height / 2, Qt.RightButton);
106 longPressSpy.wait();
107 // cleanup
108 mouseRelease(mouseArea, mouseArea.width / 2, mouseArea.height / 2, Qt.RightButton);
109 }
110
111 function test_longPress_middle() {
112 longPressSpy.clear();
113 mouseLongPress(mouseArea, mouseArea.width / 2, mouseArea.height / 2, Qt.MiddleButton);
114 longPressSpy.wait();
115 // cleanup
116 mouseRelease(mouseArea, mouseArea.width / 2, mouseArea.height / 2, Qt.MiddleButton);
117 }
118
119 SignalSpy {
120 id: movementSpy
121 target: flicker
122 signalName: "onMovementEnded"
123 }
124
125 function test_flick_default() {
126 flick(flicker, 0, 0, flicker.width, flicker.height);
127 movementSpy.wait();
128 }
129 function test_flick_long() {
130 flick(flicker, 0, 0, flicker.width, flicker.height, -1, 10);
131 movementSpy.wait();
132 }
133 function test_flick_short() {
134 flick(flicker, 0, 0, flicker.width, flicker.height, -1, 1);
135 movementSpy.wait();
136 }
137 function test_flick_pressTimeout() {
138 flick(flicker, 0, 0, flicker.width, flicker.height, 400);
139 movementSpy.wait();
140 }
141 function test_flick_pressTimeout_short() {
142 flick(flicker, flicker.width, flicker.height, -flicker.width, -flicker.height, 400, 1);
143 movementSpy.wait();
144 }
145 function test_flick_pressTimeout_long() {
146 flick(flicker, flicker.width, flicker.height, -flicker.width, -flicker.height, 400, 100);
147 movementSpy.wait();
148 }
61 }149 }
62}150}

Subscribers

People subscribed via source and target branches

to status/vote changes: