Merge lp:~zsombi/ubuntu-ui-toolkit/cppBottomEdgeHint into lp:ubuntu-ui-toolkit/staging

Proposed by Zsombor Egri
Status: Merged
Approved by: Cris Dywan
Approved revision: 1724
Merged at revision: 1710
Proposed branch: lp:~zsombi/ubuntu-ui-toolkit/cppBottomEdgeHint
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 1351 lines (+873/-186)
18 files modified
components.api (+7/-0)
examples/ubuntu-ui-toolkit-gallery/BottomEdgePage.qml (+1/-1)
examples/ubuntu-ui-toolkit-gallery/MainPage.qml (+19/-0)
src/Ubuntu/Components/1.3/BottomEdgeHint.qml (+0/-110)
src/Ubuntu/Components/ComponentModule.pro (+0/-1)
src/Ubuntu/Components/Themes/Ambiance/1.3/BottomEdgeHintStyle.qml (+12/-47)
src/Ubuntu/Components/plugin/plugin.cpp (+2/-0)
src/Ubuntu/Components/plugin/plugin.pri (+6/-2)
src/Ubuntu/Components/plugin/privates/gesturedetector.cpp (+132/-0)
src/Ubuntu/Components/plugin/privates/gesturedetector.h (+73/-0)
src/Ubuntu/Components/plugin/quickutils.cpp (+2/-1)
src/Ubuntu/Components/plugin/quickutils.h (+8/-0)
src/Ubuntu/Components/plugin/ucbottomedgehint.cpp (+347/-0)
src/Ubuntu/Components/plugin/ucbottomedgehint.h (+92/-0)
src/Ubuntu/Components/qmldir (+0/-1)
src/Ubuntu/Test/plugin/uctestextras.cpp (+5/-0)
src/Ubuntu/Test/plugin/uctestextras.h (+5/-1)
tests/unit_x11/tst_components/tst_bottomedgehint.qml (+162/-22)
To merge this branch: bzr merge lp:~zsombi/ubuntu-ui-toolkit/cppBottomEdgeHint
Reviewer Review Type Date Requested Status
Cris Dywan Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+276627@code.launchpad.net

Commit message

BottomEdgeHint API changes, deprecating state property, introducing locked property to drive visuals lock and click handling.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1711. By Zsombor Egri

Enter and Return key handling

1712. By Zsombor Egri

segfault fixed

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)
1713. By Zsombor Egri

touch functionality and test added

1714. By Zsombor Egri

redo removed state handling for Hidden and Visible

1715. By Zsombor Egri

roll back unneeded change

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)
1716. By Zsombor Egri

adding Status enum to replace locked property, the property is writable

1717. By Zsombor Egri

fixing API, adjusting style and tests

1718. By Zsombor Egri

introduce activateByGesture and deactivateTimeout properties with handling

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

separate gesture detection and do a proper detection state handling

1720. By Zsombor Egri

test code removed

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

remove activateByGesture and make it sole part of the component

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

add possibility to turn mouse on/off from menu

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

move click support from the style into the component

1724. By Zsombor Egri

final touch

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Cris Dywan (kalikiana) wrote :

I like.

Perhaps a follow-up bug report ought to be filed for implementing mouse discovery?

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'components.api'
2--- components.api 2015-11-04 14:58:18 +0000
3+++ components.api 2015-11-05 14:29:06 +0000
4@@ -176,11 +176,18 @@
5 property bool iconFrame
6 property bool progression
7 Ubuntu.Components.BottomEdgeHint 1.3: StyledItem
8+ property int deactivateTimeout
9 property Flickable flickable
10 property string iconName
11 property url iconSource
12 signal clicked()
13+ property Status status
14 property string text
15+Ubuntu.Components.BottomEdgeHint.Status: Enum
16+ Active
17+ Hidden
18+ Inactive
19+ Locked
20 Ubuntu.Components.Button 1.0 0.1: AbstractButton
21 property color color
22 property QFont font
23
24=== modified file 'examples/ubuntu-ui-toolkit-gallery/BottomEdgePage.qml'
25--- examples/ubuntu-ui-toolkit-gallery/BottomEdgePage.qml 2015-10-23 06:50:14 +0000
26+++ examples/ubuntu-ui-toolkit-gallery/BottomEdgePage.qml 2015-11-05 14:29:06 +0000
27@@ -33,6 +33,6 @@
28 BottomEdgeHint {
29 iconName: "stock_message"
30 text: "Compose a new message"
31- onClicked: state = "Idle"
32+ onClicked: state = "Hidden"
33 }
34 }
35
36=== modified file 'examples/ubuntu-ui-toolkit-gallery/MainPage.qml'
37--- examples/ubuntu-ui-toolkit-gallery/MainPage.qml 2015-10-23 14:46:16 +0000
38+++ examples/ubuntu-ui-toolkit-gallery/MainPage.qml 2015-11-05 14:29:06 +0000
39@@ -53,6 +53,18 @@
40 text: i18n.tr('About')
41 iconName: "info"
42 onTriggered: mainPage.pageStack.addPageToCurrentColumn(mainPage, Qt.resolvedUrl("About.qml"))
43+ },
44+ Action {
45+ text: i18n.tr("Deactivate mouse")
46+ iconName: "non-starred"
47+ visible: QuickUtils.mouseAttached
48+ onTriggered: QuickUtils.mouseAttached = false
49+ },
50+ Action {
51+ text: i18n.tr("Activate mouse")
52+ iconName: "starred"
53+ visible: !QuickUtils.mouseAttached
54+ onTriggered: QuickUtils.mouseAttached = true
55 }
56 ]
57 }
58@@ -120,4 +132,11 @@
59 }
60 highlightMoveDuration: 0
61 }
62+
63+ BottomEdgeHint {
64+ flickable: widgetList
65+ text: i18n.tr('About')
66+ iconName: "info"
67+ onClicked: mainPage.pageStack.addPageToCurrentColumn(mainPage, Qt.resolvedUrl("About.qml"))
68+ }
69 }
70
71=== removed file 'src/Ubuntu/Components/1.3/BottomEdgeHint.qml'
72--- src/Ubuntu/Components/1.3/BottomEdgeHint.qml 2015-10-23 16:37:49 +0000
73+++ src/Ubuntu/Components/1.3/BottomEdgeHint.qml 1970-01-01 00:00:00 +0000
74@@ -1,110 +0,0 @@
75-/*
76- * Copyright 2015 Canonical Ltd.
77- *
78- * This program is free software; you can redistribute it and/or modify
79- * it under the terms of the GNU Lesser General Public License as published by
80- * the Free Software Foundation; version 3.
81- *
82- * This program is distributed in the hope that it will be useful,
83- * but WITHOUT ANY WARRANTY; without even the implied warranty of
84- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
85- * GNU Lesser General Public License for more details.
86- *
87- * You should have received a copy of the GNU Lesser General Public License
88- * along with this program. If not, see <http://www.gnu.org/licenses/>.
89- */
90-
91-import QtQuick 2.4
92-import Ubuntu.Components 1.3
93-
94-/*!
95- \qmltype BottomEdgeHint
96- \inqmlmodule Ubuntu.Components 1.3
97- \ingroup ubuntu
98- \inherits StyledItem
99- \brief The BottomEdgeHint shows the availability of extra features
100- available from the bottom edge of the application.
101-
102- It displays either a label or an icon at the bottom of the application.
103-
104- It has 4 states: Hidden, Idle, Active and Locked. When Idle, part of it is
105- still visible hinting the existence of the bottom edge.
106-
107- When used with a mouse it acts like a button. The typical action associated
108- with clicking on it should be revealing the extra features provided by the
109- bottom edge. However, the click can only happen if the hint is in \e Locked
110- state.
111-
112- Example:
113- \qml
114- BottomEdgeHint {
115- id: bottomEdgeHint
116- text: i18n.tr("Favorites")
117- onClicked: revealBottomEdge()
118- }
119- \endqml
120-
121- The component is styled through \b BottomEdgeHintStyle.
122-*/
123-StyledItem {
124- id: bottomEdgeHint
125-
126- anchors.bottom: parent.bottom
127-
128- /*!
129- This handler is called when there is a mouse click on the BottomEdgeHint
130- and the BottomEdgeHint is not disabled.
131- */
132- signal clicked()
133-
134- Keys.onEnterPressed: clicked()
135- Keys.onReturnPressed: clicked()
136-
137- /*!
138- \qmlproperty string text
139- The label displayed by the BottomEdgeHint.
140- */
141- property string text
142-
143- /*!
144- \qmlproperty url iconSource
145- The icon displayed by the BottomEdgeHint.
146-
147- This is the URL of any image file.
148- If both iconSource and iconName are defined, iconName will be ignored.
149- */
150- property url iconSource
151-
152- /*!
153- \qmlproperty string iconName
154- The icon associated with the BottomEdgeHint in the icon theme.
155-
156- If both iconSource and iconName are defined, iconName will be ignored.
157- */
158- property string iconName
159-
160- /*!
161- The property holds the flickable, which when flicked hides the hint.
162- \e Hidden state is reached when this property is set to a Flickable
163- which is flicking or moving. It is recommended to set the property
164- when the hint is placed above a flickable content. Defaults to null.
165- */
166- property Flickable flickable: null
167-
168- /*!
169- \qmlproperty string state
170- BottomEdgeHint can take 4 states of visibility: "Hidden", "Idle", "Active"
171- and "Locked".
172-
173- When \e Hidden, the hint is not shown at all. When \e Active, the full hint
174- with its content is shown. When \e Idle, only part of the hint is visible
175- leaving more space for application content. \e Idle extends the empty state.
176- \e Locked is similar to Active, except that it is a final state, meaning the
177- hint will be shown no matter of the flickable's status.
178-
179- Defaults to \e Idle.
180- */
181- state: "Idle"
182-
183- styleName: "BottomEdgeHintStyle"
184-}
185
186=== modified file 'src/Ubuntu/Components/ComponentModule.pro'
187--- src/Ubuntu/Components/ComponentModule.pro 2015-10-20 11:05:53 +0000
188+++ src/Ubuntu/Components/ComponentModule.pro 2015-11-05 14:29:06 +0000
189@@ -132,7 +132,6 @@
190 1.3/UbuntuListView.qml \
191 1.3/UbuntuNumberAnimation.qml \
192 1.3/ListItemPopover.qml \
193- 1.3/BottomEdgeHint.qml \
194 1.3/PageColumn.qml \
195 1.3/PageColumnsLayout.qml \
196 1.3/ProgressionSlot.qml \
197
198=== modified file 'src/Ubuntu/Components/Themes/Ambiance/1.3/BottomEdgeHintStyle.qml'
199--- src/Ubuntu/Components/Themes/Ambiance/1.3/BottomEdgeHintStyle.qml 2015-10-23 16:37:49 +0000
200+++ src/Ubuntu/Components/Themes/Ambiance/1.3/BottomEdgeHintStyle.qml 2015-11-05 14:29:06 +0000
201@@ -23,15 +23,22 @@
202 implicitWidth: styledItem.parent.width
203 implicitHeight: units.gu(4)
204
205- state: styledItem.state
206+ readonly property BottomEdgeHint hint: styledItem
207+
208+ // translate hint status into state
209+ state: {
210+ switch (hint.status) {
211+ case BottomEdgeHint.Hidden: return "Hidden";
212+ case BottomEdgeHint.Inactive: return "Inactive"
213+ case BottomEdgeHint.Active: return "Active"
214+ case BottomEdgeHint.Locked: return "Locked"
215+ }
216+ }
217
218 states: [
219 State {
220- name: "Idle"
221+ name: "Inactive"
222 extend: ""
223- StateChangeScript {
224- script: turnToIdleTimer.stop()
225- }
226 },
227 State {
228 name: "Active"
229@@ -46,18 +53,11 @@
230 },
231 State {
232 name: "Hidden"
233- when: styledItem.flickable && (styledItem.flickable.flicking || styledItem.flickable.moving)
234 PropertyChanges {
235 target: styledItem
236 opacity: 0.0
237 }
238- PropertyChanges {
239- target: mouseHover
240- enabled: false
241- }
242 },
243- // FIXME: locked should be set and be final if mouse is attached
244- // requires QSystemInfo support, which is ongoing work upstream
245 State {
246 name: "Locked"
247 PropertyChanges {
248@@ -68,11 +68,6 @@
249 target: h2
250 anchors.topMargin: 0
251 }
252- PropertyChanges {
253- target: turnToIdleTimer
254- running: false
255-
256- }
257 }
258 ]
259 transitions: [
260@@ -97,27 +92,6 @@
261 }
262 ]
263
264- // FIXME ZSOMBI: temporary functionality till SwipeGesture integration
265- MouseArea {
266- id: mouseHover
267- anchors.fill: parent
268- hoverEnabled: true
269- acceptedButtons: Qt.NoButton
270- enabled: styledItem.state != "Locked"
271- onEntered: {
272- styledItem.state = "Active";
273- turnToIdleTimer.stop();
274- }
275- onExited: if (styledItem.state == "Active") turnToIdleTimer.restart()
276- }
277-
278- Timer {
279- id: turnToIdleTimer
280- interval: 800
281- repeat: false
282- onTriggered: styledItem.state = "Idle"
283- }
284-
285 clip: true
286
287 Icon {
288@@ -145,15 +119,6 @@
289 anchors.top: parent.top
290 }
291
292- MouseArea {
293- anchors.fill: parent
294- onClicked: {
295- Haptics.play();
296- styledItem.clicked();
297- mouse.accepted = false;
298- }
299- }
300-
301 Row {
302 anchors {
303 top: parent.top
304
305=== modified file 'src/Ubuntu/Components/plugin/plugin.cpp'
306--- src/Ubuntu/Components/plugin/plugin.cpp 2015-10-20 09:19:50 +0000
307+++ src/Ubuntu/Components/plugin/plugin.cpp 2015-11-05 14:29:06 +0000
308@@ -70,6 +70,7 @@
309 #include "ucheader.h"
310 #include "uclabel.h"
311 #include "uclistitemlayout.h"
312+#include "ucbottomedgehint.h"
313
314 #include <sys/types.h>
315 #include <unistd.h>
316@@ -248,6 +249,7 @@
317 qmlRegisterType<UCListItemLayout>(uri, 1, 3, "ListItemLayout");
318 qmlRegisterType<UCHeader>(uri, 1, 3, "Header");
319 qmlRegisterType<UCLabel>(uri, 1, 3, "Label");
320+ qmlRegisterType<UCBottomEdgeHint>(uri, 1, 3, "BottomEdgeHint");
321 }
322
323 void UbuntuComponentsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
324
325=== modified file 'src/Ubuntu/Components/plugin/plugin.pri'
326--- src/Ubuntu/Components/plugin/plugin.pri 2015-10-01 12:40:52 +0000
327+++ src/Ubuntu/Components/plugin/plugin.pri 2015-11-05 14:29:06 +0000
328@@ -92,7 +92,9 @@
329 $$PWD/uclabel.h \
330 $$PWD/uclistitemlayout.h \
331 $$PWD/privates/threelabelsslot_p.h \
332- $$PWD/ucimportversionchecker_p.h
333+ $$PWD/ucimportversionchecker_p.h \
334+ $$PWD/ucbottomedgehint.h \
335+ $$PWD/privates/gesturedetector.h
336
337 SOURCES += $$PWD/plugin.cpp \
338 $$PWD/uctheme.cpp \
339@@ -155,7 +157,9 @@
340 $$PWD/uclabel.cpp \
341 $$PWD/uclistitemlayout.cpp \
342 $$PWD/privates/threelabelsslot_p.cpp \
343- $$PWD/ucimportversionchecker_p.cpp
344+ $$PWD/ucimportversionchecker_p.cpp \
345+ $$PWD/ucbottomedgehint.cpp \
346+ $$PWD/privates/gesturedetector.cpp
347
348 # adapters
349 SOURCES += $$PWD/adapters/alarmsadapter_organizer.cpp
350
351=== added file 'src/Ubuntu/Components/plugin/privates/gesturedetector.cpp'
352--- src/Ubuntu/Components/plugin/privates/gesturedetector.cpp 1970-01-01 00:00:00 +0000
353+++ src/Ubuntu/Components/plugin/privates/gesturedetector.cpp 2015-11-05 14:29:06 +0000
354@@ -0,0 +1,132 @@
355+/*
356+ * Copyright 2015 Canonical Ltd.
357+ *
358+ * This program is free software; you can redistribute it and/or modify
359+ * it under the terms of the GNU Lesser General Public License as published by
360+ * the Free Software Foundation; version 3.
361+ *
362+ * This program is distributed in the hope that it will be useful,
363+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
364+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
365+ * GNU Lesser General Public License for more details.
366+ *
367+ * You should have received a copy of the GNU Lesser General Public License
368+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
369+ *
370+ * Authors: Zsombor Egri <zsombor.egri@canonical.com>
371+ */
372+
373+#include "gesturedetector.h"
374+#include "ucunits.h"
375+#include <QtCore/QEvent>
376+#include <QtCore/QRectF>
377+#include <QtGui/QTouchEvent>
378+#include <QtQuick/QQuickItem>
379+#include <QtGui/QGuiApplication>
380+#include <QtGui/QStyleHints>
381+
382+#define DETECTION_AREA_THICKNESS_GU 1.2
383+
384+GestureDetector::GestureDetector(QObject *parent)
385+ : QObject(parent)
386+ , m_owner(qobject_cast<QQuickItem*>(parent))
387+ , m_status(Ready)
388+ , m_bottomUpSwipeDetected(false)
389+{
390+ Q_ASSERT(m_owner);
391+}
392+GestureDetector::~GestureDetector()
393+{
394+ Q_FOREACH(QObject *object, m_filteredItems) {
395+ object->removeEventFilter(this);
396+ }
397+ m_filteredItems.clear();
398+}
399+
400+void GestureDetector::setStatus(Status status)
401+{
402+ if (status == m_status) {
403+ return;
404+ }
405+ m_status = status;
406+ Q_EMIT statusChanged(m_status);
407+}
408+
409+bool GestureDetector::isDetecting()
410+{
411+ return (m_status > Ready && m_status < Completed);
412+}
413+
414+void GestureDetector::setItemFilter(QObject *item)
415+{
416+ m_filteredItems.append(item);
417+ item->installEventFilter(this);
418+}
419+
420+void GestureDetector::removeItemFilter(QObject *item)
421+{
422+ m_filteredItems.removeAll(item);
423+ item->removeEventFilter(this);
424+}
425+
426+bool GestureDetector::handleTouchEvent(QObject *target, QTouchEvent *event)
427+{
428+ switch (event->type()) {
429+ case QEvent::TouchBegin: {
430+ setStatus(Ready);
431+ QPointF itemPoint = m_owner->mapFromScene(event->touchPoints()[0].scenePos());
432+ qreal thickness = UCUnits::instance().gu(DETECTION_AREA_THICKNESS_GU);
433+ QRectF detectionArea(0.0, m_owner->height() - thickness, m_owner->width(), thickness);
434+ if (detectionArea.contains(itemPoint)) {
435+ m_startPoint = itemPoint;
436+ setStatus(Started);
437+ if (target == parent()) {
438+ event->accept();
439+ return true;
440+ }
441+ }
442+ return false;
443+ }
444+ case QEvent::TouchEnd:
445+ {
446+ m_startPoint = QPointF();
447+ setStatus(Completed);
448+ return false;
449+ }
450+ case QEvent::TouchCancel: {
451+ m_startPoint = QPointF();
452+ setStatus(Ready);
453+ return false;
454+ }
455+ case QEvent::TouchUpdate: {
456+ if (m_status == Started) {
457+ QPointF itemPoint = m_owner->mapFromScene(event->touchPoints()[0].scenePos());
458+ if (abs(m_startPoint.y() - itemPoint.y()) >= qApp->styleHints()->startDragDistance()) {
459+ setStatus(Detected);
460+ Q_EMIT bottomUpSwipeDetected();
461+ }
462+ }
463+ return false;
464+ }
465+ default: return false;
466+ }
467+}
468+
469+bool GestureDetector::eventFilter(QObject *target, QEvent *event)
470+{
471+ if (m_filteredItems.contains(target)) {
472+ QEvent::Type type = event->type();
473+ if (type == QEvent::TouchBegin
474+ || type == QEvent::TouchUpdate
475+ || type == QEvent::TouchEnd
476+ || type == QEvent::TouchCancel) {
477+ QTouchEvent *touch = static_cast<QTouchEvent*>(event);
478+ return handleTouchEvent(target, touch);
479+ } else {
480+ // pass it on
481+ return false;
482+ }
483+ } else {
484+ return QObject::eventFilter(target, event);
485+ }
486+}
487
488=== added file 'src/Ubuntu/Components/plugin/privates/gesturedetector.h'
489--- src/Ubuntu/Components/plugin/privates/gesturedetector.h 1970-01-01 00:00:00 +0000
490+++ src/Ubuntu/Components/plugin/privates/gesturedetector.h 2015-11-05 14:29:06 +0000
491@@ -0,0 +1,73 @@
492+/*
493+ * Copyright 2015 Canonical Ltd.
494+ *
495+ * This program is free software; you can redistribute it and/or modify
496+ * it under the terms of the GNU Lesser General Public License as published by
497+ * the Free Software Foundation; version 3.
498+ *
499+ * This program is distributed in the hope that it will be useful,
500+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
501+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
502+ * GNU Lesser General Public License for more details.
503+ *
504+ * You should have received a copy of the GNU Lesser General Public License
505+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
506+ *
507+ * Authors: Zsombor Egri <zsombor.egri@canonical.com>
508+ */
509+
510+#ifndef GESTUREDETECTOR_H
511+#define GESTUREDETECTOR_H
512+
513+#include <QtCore/QObject>
514+#include <QtCore/QPointF>
515+#include <QtCore/QList>
516+
517+/*
518+ * A simple gesture detection filter class that can be used in components to detect
519+ * various gestures. Yet swipe from bottom up is the only gesture handled.
520+ * It does not grab or consume the event from the environment, acts as a filter.
521+ */
522+class QTouchEvent;
523+class QQuickItem;
524+class GestureDetector : public QObject
525+{
526+ Q_OBJECT
527+public:
528+ enum Status {
529+ Ready,
530+ Started,
531+ Detected,
532+ Completed
533+ };
534+ explicit GestureDetector(QObject *parent = 0);
535+ ~GestureDetector();
536+
537+ bool isDetecting();
538+
539+ void setItemFilter(QObject *item);
540+ void removeItemFilter(QObject *item);
541+
542+ bool handleTouchEvent(QObject *target, QTouchEvent *event);
543+
544+Q_SIGNALS:
545+ void statusChanged(Status status);
546+
547+ void bottomUpSwipeDetected();
548+
549+public Q_SLOTS:
550+
551+protected:
552+ bool eventFilter(QObject *target, QEvent *event);
553+
554+ void setStatus(Status status);
555+
556+private:
557+ QList<QObject*> m_filteredItems;
558+ QPointF m_startPoint;
559+ QQuickItem *m_owner;
560+ Status m_status;
561+ bool m_bottomUpSwipeDetected:1;
562+};
563+
564+#endif // GESTUREDETECTOR_H
565
566=== modified file 'src/Ubuntu/Components/plugin/quickutils.cpp'
567--- src/Ubuntu/Components/plugin/quickutils.cpp 2015-08-24 12:55:50 +0000
568+++ src/Ubuntu/Components/plugin/quickutils.cpp 2015-11-05 14:29:06 +0000
569@@ -32,7 +32,8 @@
570
571 QuickUtils::QuickUtils(QObject *parent) :
572 QObject(parent),
573- m_rootView(0)
574+ m_rootView(0),
575+ m_mouseAttached(true)
576 {
577 QGuiApplication::instance()->installEventFilter(this);
578 m_omitIM << "ibus" << "none" << "compose";
579
580=== modified file 'src/Ubuntu/Components/plugin/quickutils.h'
581--- src/Ubuntu/Components/plugin/quickutils.h 2015-08-24 12:55:50 +0000
582+++ src/Ubuntu/Components/plugin/quickutils.h 2015-11-05 14:29:06 +0000
583@@ -31,6 +31,7 @@
584 Q_PROPERTY(QQuickItem *rootObject READ rootObject NOTIFY rootObjectChanged)
585 Q_PROPERTY(QString inputMethodProvider READ inputMethodProvider)
586 Q_PROPERTY(bool touchScreenAvailable READ touchScreenAvailable NOTIFY touchScreenAvailableChanged)
587+ Q_PROPERTY(bool mouseAttached MEMBER m_mouseAttached NOTIFY mouseAttachedChanged)
588 public:
589 static QuickUtils& instance()
590 {
591@@ -48,11 +49,17 @@
592 QObject* createQmlObject(const QUrl &url, QQmlEngine *engine);
593 static bool showDeprecationWarnings();
594
595+ bool mouseAttached()
596+ {
597+ return m_mouseAttached;
598+ }
599+
600 Q_SIGNALS:
601 void rootObjectChanged();
602 void activated();
603 void deactivated();
604 void touchScreenAvailableChanged();
605+ void mouseAttachedChanged();
606
607 protected:
608 bool eventFilter(QObject *, QEvent *);
609@@ -61,6 +68,7 @@
610 explicit QuickUtils(QObject *parent = 0);
611 QPointer<QQuickView> m_rootView;
612 QStringList m_omitIM;
613+ bool m_mouseAttached;
614
615 void lookupQuickView();
616 };
617
618=== added file 'src/Ubuntu/Components/plugin/ucbottomedgehint.cpp'
619--- src/Ubuntu/Components/plugin/ucbottomedgehint.cpp 1970-01-01 00:00:00 +0000
620+++ src/Ubuntu/Components/plugin/ucbottomedgehint.cpp 2015-11-05 14:29:06 +0000
621@@ -0,0 +1,347 @@
622+/*
623+ * Copyright 2015 Canonical Ltd.
624+ *
625+ * This program is free software; you can redistribute it and/or modify
626+ * it under the terms of the GNU Lesser General Public License as published by
627+ * the Free Software Foundation; version 3.
628+ *
629+ * This program is distributed in the hope that it will be useful,
630+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
631+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
632+ * GNU Lesser General Public License for more details.
633+ *
634+ * You should have received a copy of the GNU Lesser General Public License
635+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
636+ *
637+ * Authors: Zsombor Egri <zsombor.egri@canonical.com>
638+ */
639+
640+#include "ucbottomedgehint.h"
641+#include "ucstyleditembase_p.h"
642+#include "quickutils.h"
643+#include "ucunits.h"
644+#include <QtQml/private/qqmlproperty_p.h>
645+#include <QtQuick/private/qquickflickable_p.h>
646+
647+/*!
648+ \qmltype BottomEdgeHint
649+ \inqmlmodule Ubuntu.Components 1.3
650+ \ingroup ubuntu
651+ \inherits StyledItem
652+ \brief The BottomEdgeHint shows the availability of extra features
653+ available from the bottom edge of the application.
654+
655+ It displays a label and/or an icon at the bottom of the component it is
656+ attached to.
657+
658+ When used with a mouse it acts like a button. The typical action associated
659+ with clicking on it should be revealing the extra features provided by the
660+ bottom edge.
661+
662+ Example:
663+ \qml
664+ BottomEdgeHint {
665+ id: bottomEdgeHint
666+ text: i18n.tr("Favorites")
667+ onClicked: revealBottomEdge()
668+ }
669+ \endqml
670+
671+ The component is styled through \b BottomEdgeHintStyle.
672+*/
673+UCBottomEdgeHint::UCBottomEdgeHint(QQuickItem *parent)
674+ : UCStyledItemBase(parent)
675+ , m_gestureDetector(this)
676+ , m_flickable(Q_NULLPTR)
677+ , m_deactivateTimeout(800)
678+ // FIXME: we need QInputDeviceInfo to be complete with the locked!!
679+ , m_status(QuickUtils::instance().mouseAttached() ? Locked : Inactive)
680+ , m_pressed(false)
681+{
682+ /*
683+ * we cannot use setStyleName as that will trigger style loading
684+ * and the qmlEngine is not known at this phase of the of the initialization
685+ * Therefore we simply set the style name default. Style loading will
686+ * happen during component completion.
687+ */
688+ UCStyledItemBasePrivate::get(this)->styleDocument = "BottomEdgeHintStyle";
689+
690+ // connect old stateChanged
691+ connect(this, &QQuickItem::stateChanged, this, &UCBottomEdgeHint::stateChanged);
692+
693+ // connect to gesture detection
694+ connect(&m_gestureDetector, &GestureDetector::bottomUpSwipeDetected,
695+ this, &UCBottomEdgeHint::onBottomUpSwipeDetected);
696+ connect(&m_gestureDetector, &GestureDetector::statusChanged,
697+ this, &UCBottomEdgeHint::onGestureStatusChanged);
698+
699+ // FIXME: use QInputDeviceInfo once available
700+ connect(&QuickUtils::instance(), &QuickUtils::mouseAttachedChanged, [this]() {
701+ setStatus(QuickUtils::instance().mouseAttached() ? Locked : Active);
702+ if (m_status == Active) {
703+ m_deactivationTimer.start(m_deactivateTimeout, this);
704+ }
705+ });
706+
707+ // accept mouse events
708+ setAcceptedMouseButtons(Qt::LeftButton);
709+}
710+
711+void UCBottomEdgeHint::itemChange(ItemChange change, const ItemChangeData &data)
712+{
713+ UCStyledItemBase::itemChange(change, data);
714+ if (change == ItemParentHasChanged) {
715+ QQmlProperty bottomAnchors(this, "anchors.bottom", qmlContext(this));
716+ if (data.item && !QQmlPropertyPrivate::binding(bottomAnchors)) {
717+ QQuickAnchors *anchors = QQuickItemPrivate::get(this)->anchors();
718+ anchors->setBottom(QQuickItemPrivate::get(data.item)->bottom());
719+ }
720+ }
721+}
722+
723+void UCBottomEdgeHint::timerEvent(QTimerEvent *event)
724+{
725+ UCStyledItemBase::timerEvent(event);
726+ if (event->timerId() == m_deactivationTimer.timerId()) {
727+ setStatus(Inactive);
728+ m_deactivationTimer.stop();
729+ }
730+}
731+
732+// handle clicked event when locked and enter or return is pressed
733+void UCBottomEdgeHint::keyPressEvent(QKeyEvent *event)
734+{
735+ UCStyledItemBase::keyPressEvent(event);
736+ if ((status() >= Active) && (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return)) {
737+ Q_EMIT clicked();
738+ }
739+}
740+
741+// handle gesture detection
742+void UCBottomEdgeHint::touchEvent(QTouchEvent *event)
743+{
744+ UCStyledItemBase::touchEvent(event);
745+ m_gestureDetector.handleTouchEvent(this, event);
746+}
747+
748+// handle click event
749+void UCBottomEdgeHint::mousePressEvent(QMouseEvent *event)
750+{
751+ if (contains(event->localPos()) && (m_status >= Active)) {
752+ m_pressed = true;
753+ } else {
754+ UCStyledItemBase::mousePressEvent(event);
755+ }
756+}
757+void UCBottomEdgeHint::mouseReleaseEvent(QMouseEvent *event)
758+{
759+ UCStyledItemBase::mouseReleaseEvent(event);
760+ if (m_pressed && (m_status >= Active)) {
761+ Q_EMIT clicked();
762+ }
763+}
764+
765+// watch gesture detection status changes
766+void UCBottomEdgeHint::onBottomUpSwipeDetected()
767+{
768+ m_deactivationTimer.stop();
769+ setStatus(Active);
770+}
771+
772+void UCBottomEdgeHint::onGestureStatusChanged(GestureDetector::Status status)
773+{
774+ if (status == GestureDetector::Completed) {
775+ if (m_status == Active) {
776+ m_deactivationTimer.start(m_deactivateTimeout, this);
777+ }
778+ }
779+}
780+
781+/*!
782+ \qmlsignal void BottomEdgeHint::clicked()
783+ This handler is called when there is a mouse click on the BottomEdgeHint
784+ and the BottomEdgeHint is not disabled.
785+*/
786+
787+/*!
788+ \qmlproperty string BottomEdgeHint::text
789+ The label displayed by the BottomEdgeHint.
790+ */
791+
792+/*!
793+ \qmlproperty url BottomEdgeHint::iconSource
794+ The icon displayed by the BottomEdgeHint.
795+
796+ This is the URL of any image file.
797+ If both iconSource and \l iconName are defined, \l iconName will be ignored.
798+ */
799+
800+/*!
801+ \qmlproperty string BottomEdgeHint::iconName
802+ The icon associated with the BottomEdgeHint in the icon theme.
803+
804+ If both \l iconSource and iconName are defined, iconName will be ignored.
805+ */
806+
807+/*!
808+ \qmlproperty Flickable BottomEdgeHint::flickable
809+ The property holds the flickable, which when flicked hides the hint.
810+ \e Hidden state is reached when this property is set to a Flickable
811+ which is flicking or moving. It is recommended to set the property
812+ when the hint is placed above a flickable content. Defaults to null.
813+ */
814+void UCBottomEdgeHint::setFlickable(QQuickFlickable *flickable)
815+{
816+ if (flickable == m_flickable) {
817+ return;
818+ }
819+ if (m_flickable) {
820+ disconnect(m_flickable, &QQuickFlickable::flickingChanged,
821+ this, &UCBottomEdgeHint::handleFlickableActivation);
822+ disconnect(m_flickable, &QQuickFlickable::movingChanged,
823+ this, &UCBottomEdgeHint::handleFlickableActivation);
824+ m_gestureDetector.removeItemFilter(m_flickable);
825+ }
826+ m_flickable = flickable;
827+ if (m_flickable) {
828+ connect(m_flickable, &QQuickFlickable::flickingChanged,
829+ this, &UCBottomEdgeHint::handleFlickableActivation, Qt::DirectConnection);
830+ connect(m_flickable, &QQuickFlickable::movingChanged,
831+ this, &UCBottomEdgeHint::handleFlickableActivation, Qt::DirectConnection);
832+ m_gestureDetector.setItemFilter(m_flickable);
833+ }
834+ Q_EMIT flickableChanged();
835+}
836+
837+// flickable moves hide the hint only if the current status is not Locked
838+void UCBottomEdgeHint::handleFlickableActivation()
839+{
840+ if (m_status < Locked && !m_gestureDetector.isDetecting() && !m_deactivationTimer.isActive()) {
841+ bool moving = m_flickable->isFlicking() || m_flickable->isMoving();
842+ if (moving) {
843+ setStatus(Hidden);
844+ } else if (m_status == Hidden) {
845+ setStatus(Inactive);
846+ }
847+ }
848+}
849+
850+/*!
851+ \qmlproperty string BottomEdgeHint::state
852+ \deprecated
853+ BottomEdgeHint can take 2 states of visibility: \e Hidden, \e Visible.
854+ \table
855+ \header
856+ \li State
857+ \li Description
858+ \row
859+ \li Hidden
860+ \li The hint is not shown at all and cannot be activated.
861+ \row
862+ \li Visible
863+ \li The hint is in a state where it is visible but not active. \l clicked
864+ signal is not emitted.
865+ \endtable
866+
867+ Defaults to \e Visible.
868+ */
869+QString UCBottomEdgeHint::state() const
870+{
871+ return QQuickItem::state();
872+}
873+void UCBottomEdgeHint::setState(const QString &state)
874+{
875+ QQuickItem::setState(state);
876+
877+ qmlInfo(this) << "Overloaded 'state' property deprecated, will be removed from 1.3 release. Use 'status' instead.";
878+ QQuickItem *style = UCStyledItemBasePrivate::get(this)->styleItem;
879+ if (!style) {
880+ return;
881+ }
882+ if (state == "Hidden") {
883+ setStatus(Hidden);
884+ }
885+ if (state == "Visible") {
886+ setStatus(Inactive);
887+ }
888+}
889+
890+/*!
891+ \qmlproperty Status BottomEdgeHint::status
892+ The property represents the status of the hint. The property is writable so it
893+ can be set to any of the following values programatically:
894+ \table
895+ \header
896+ \li Status
897+ \li Description
898+ \row
899+ \li Hidden
900+ \li The hint is not shown. Equivalent with setting \e visible to \c false,
901+ however visuals may do animations when altering this property. It can
902+ only be set if the current status is not \e Locked.
903+ \row
904+ \li Inactive
905+ \li The hint is shown and inactive. Styles can represent this state with
906+ different visuals. When inactive, \l clicked signal cannot be emitted.
907+ \row
908+ \li Active
909+ \li The hint is shown and active, meaning \l clicked signal is emitted when
910+ clicked with mouse.
911+ \row
912+ \li Locked
913+ \li Similar to \e Active the hint is shown and active, but no automatic transition
914+ to any other state is allowed. This is relevant for style implementations.
915+ \endtable
916+ \note \e Locked status value is set automatically when the system detects a
917+ mouse attached. In this case any change into other state value than \e Locked
918+ is rejected.
919+ Defaults to
920+ \list
921+ \li Inactive if no mouse is attached or
922+ \li Locked if there is a mouse detected.
923+ \endlist
924+ */
925+UCBottomEdgeHint::Status UCBottomEdgeHint::status()
926+{
927+ // FIXME: we won't need this once we get the QInputDeviceInfo reporting mouse attach/detach
928+ if (QuickUtils::instance().mouseAttached()) {
929+ m_status = Locked;
930+ }
931+ return m_status;
932+}
933+
934+void UCBottomEdgeHint::setStatus(Status status)
935+{
936+ // FIXME: we need QInputDeviceInfo to complete this!
937+ // cannot unlock if mouse is attached or we don't have touch screen available
938+ if (status == m_status || (status != Locked && QuickUtils::instance().mouseAttached())) {
939+ return;
940+ }
941+ m_status = status;
942+ // make sure we stop the deactivation timer if Inactive or Locked
943+ if (status != Active && m_deactivationTimer.isActive()) {
944+ m_deactivationTimer.stop();
945+ }
946+ Q_EMIT statusChanged();
947+}
948+
949+/*!
950+ * \qmlproperty int BottomEdgeHint::deactivateTimeout
951+ * The property specifies the timeout interval in milliseconds the \l status
952+ * is set to \e Inactive after a gesture based activation. Gesture based activation
953+ * is only possible when mouse is not attached to the device. Defaults to 800
954+ * milliseconds.
955+ */
956+
957+void UCBottomEdgeHint::setDeactivateTimeout(int timeout)
958+{
959+ if (timeout == m_deactivateTimeout || timeout < 0) {
960+ return;
961+ }
962+ m_deactivateTimeout = timeout;
963+ if (m_deactivationTimer.isActive()) {
964+ m_deactivationTimer.stop();
965+ m_deactivationTimer.start(m_deactivateTimeout, this);
966+ }
967+ Q_EMIT deactivateTimeoutChanged();
968+}
969
970=== added file 'src/Ubuntu/Components/plugin/ucbottomedgehint.h'
971--- src/Ubuntu/Components/plugin/ucbottomedgehint.h 1970-01-01 00:00:00 +0000
972+++ src/Ubuntu/Components/plugin/ucbottomedgehint.h 2015-11-05 14:29:06 +0000
973@@ -0,0 +1,92 @@
974+/*
975+ * Copyright 2015 Canonical Ltd.
976+ *
977+ * This program is free software; you can redistribute it and/or modify
978+ * it under the terms of the GNU Lesser General Public License as published by
979+ * the Free Software Foundation; version 3.
980+ *
981+ * This program is distributed in the hope that it will be useful,
982+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
983+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
984+ * GNU Lesser General Public License for more details.
985+ *
986+ * You should have received a copy of the GNU Lesser General Public License
987+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
988+ *
989+ * Authors: Zsombor Egri <zsombor.egri@canonical.com>
990+ */
991+
992+#ifndef UCBOTTOMEDGEHINT_H
993+#define UCBOTTOMEDGEHINT_H
994+
995+#include "ucstyleditembase.h"
996+#include "privates/gesturedetector.h"
997+
998+class QQuickFlickable;
999+class UCBottomEdgeHint : public UCStyledItemBase
1000+{
1001+ Q_OBJECT
1002+ Q_ENUMS(Status)
1003+ Q_PROPERTY(QString text MEMBER m_text NOTIFY textChanged FINAL)
1004+ Q_PROPERTY(QUrl iconSource MEMBER m_iconSource NOTIFY iconSourceChanged FINAL)
1005+ Q_PROPERTY(QString iconName MEMBER m_iconName NOTIFY iconNameChanged FINAL)
1006+ Q_PROPERTY(QQuickFlickable *flickable MEMBER m_flickable WRITE setFlickable NOTIFY flickableChanged FINAL)
1007+ Q_PROPERTY(Status status MEMBER m_status WRITE setStatus NOTIFY statusChanged FINAL)
1008+ Q_PROPERTY(int deactivateTimeout MEMBER m_deactivateTimeout WRITE setDeactivateTimeout NOTIFY deactivateTimeoutChanged FINAL)
1009+ // deprecated
1010+ Q_PROPERTY(QString state READ state WRITE setState NOTIFY stateChanged)
1011+public:
1012+ enum Status {
1013+ Hidden,
1014+ Inactive,
1015+ Active,
1016+ Locked
1017+ };
1018+ explicit UCBottomEdgeHint(QQuickItem *parent = 0);
1019+
1020+ void setFlickable(QQuickFlickable *flickable);
1021+ Status status();
1022+ void setStatus(Status status);
1023+
1024+ // deprecated
1025+ QString state() const;
1026+ void setState(const QString &state);
1027+ void setDeactivateTimeout(int timeout);
1028+
1029+Q_SIGNALS:
1030+ void textChanged();
1031+ void iconSourceChanged();
1032+ void iconNameChanged();
1033+ void flickableChanged();
1034+ void statusChanged();
1035+ void deactivateTimeoutChanged();
1036+
1037+ void clicked();
1038+
1039+ // deprecated
1040+ void stateChanged();
1041+protected:
1042+ void itemChange(ItemChange change, const ItemChangeData &data);
1043+ void timerEvent(QTimerEvent *event);
1044+ void keyPressEvent(QKeyEvent *event);
1045+ void touchEvent(QTouchEvent *event);
1046+ void mousePressEvent(QMouseEvent *event);
1047+ void mouseReleaseEvent(QMouseEvent *event);
1048+
1049+ void handleFlickableActivation();
1050+ void onBottomUpSwipeDetected();
1051+ void onGestureStatusChanged(GestureDetector::Status status);
1052+
1053+private:
1054+ GestureDetector m_gestureDetector;
1055+ QBasicTimer m_deactivationTimer;
1056+ QString m_text;
1057+ QUrl m_iconSource;
1058+ QString m_iconName;
1059+ QQuickFlickable *m_flickable;
1060+ int m_deactivateTimeout;
1061+ Status m_status;
1062+ bool m_pressed:1;
1063+};
1064+
1065+#endif // UCBOTTOMEDGEHINT_H
1066
1067=== modified file 'src/Ubuntu/Components/qmldir'
1068--- src/Ubuntu/Components/qmldir 2015-10-02 22:48:13 +0000
1069+++ src/Ubuntu/Components/qmldir 2015-11-05 14:29:06 +0000
1070@@ -139,6 +139,5 @@
1071 MathUtils 1.3 1.3/mathUtils.js
1072 internal ColorUtils 1.3/colorUtils.js
1073 DateUtils 1.3 1.3/dateUtils.js
1074-BottomEdgeHint 1.3 1.3/BottomEdgeHint.qml
1075 ProgressionSlot 1.3 1.3/ProgressionSlot.qml
1076 PageHeader 1.3 1.3/PageHeader.qml
1077
1078=== modified file 'src/Ubuntu/Test/plugin/uctestextras.cpp'
1079--- src/Ubuntu/Test/plugin/uctestextras.cpp 2015-02-02 11:10:46 +0000
1080+++ src/Ubuntu/Test/plugin/uctestextras.cpp 2015-11-05 14:29:06 +0000
1081@@ -37,6 +37,7 @@
1082 }
1083
1084 QTouchDevice *UCTestExtras::m_touchDevice = 0;
1085+UCTestExtras *UCTestExtras::m_testExtras = 0;
1086
1087 /*!
1088 * \qmltype TestExtras
1089@@ -52,6 +53,7 @@
1090 UCTestExtras::UCTestExtras(QObject *parent) :
1091 QObject(parent)
1092 {
1093+ m_testExtras = this;
1094 }
1095
1096 /*!
1097@@ -127,6 +129,9 @@
1098 m_touchDevice = new QTouchDevice;
1099 m_touchDevice->setType(QTouchDevice::TouchScreen);
1100 QWindowSystemInterface::registerTouchDevice(m_touchDevice);
1101+ if (m_testExtras) {
1102+ Q_EMIT m_testExtras->touchDevicePresentChanged();
1103+ }
1104 }
1105 }
1106
1107
1108=== modified file 'src/Ubuntu/Test/plugin/uctestextras.h'
1109--- src/Ubuntu/Test/plugin/uctestextras.h 2015-01-05 13:31:51 +0000
1110+++ src/Ubuntu/Test/plugin/uctestextras.h 2015-11-05 14:29:06 +0000
1111@@ -24,10 +24,13 @@
1112 class UCTestExtras : public QObject
1113 {
1114 Q_OBJECT
1115- Q_PROPERTY(bool touchPresent READ touchDevicePresent)
1116+ Q_PROPERTY(bool touchPresent READ touchDevicePresent NOTIFY touchDevicePresentChanged)
1117 public:
1118 explicit UCTestExtras(QObject *parent = 0);
1119
1120+Q_SIGNALS:
1121+ void touchDevicePresentChanged();
1122+
1123 public Q_SLOTS:
1124 static QString openGLflavor();
1125 static QString cpuArchitecture();
1126@@ -43,6 +46,7 @@
1127
1128 private:
1129 static QTouchDevice *m_touchDevice;
1130+ static UCTestExtras *m_testExtras;
1131 };
1132
1133 #endif // TESTEXTRAS_H
1134
1135=== modified file 'tests/unit_x11/tst_components/tst_bottomedgehint.qml'
1136--- tests/unit_x11/tst_components/tst_bottomedgehint.qml 2015-10-23 16:37:49 +0000
1137+++ tests/unit_x11/tst_components/tst_bottomedgehint.qml 2015-11-05 14:29:06 +0000
1138@@ -24,51 +24,191 @@
1139 width: units.gu(40)
1140 height: units.gu(71)
1141
1142+ ListView {
1143+ id: listView
1144+ anchors.fill: parent
1145+ model: 100
1146+ delegate: Label {
1147+ height: units.gu(5)
1148+ text: "Item #" + index
1149+ }
1150+ }
1151+
1152 BottomEdgeHint {
1153 id: bottomEdgeHint
1154 }
1155+ BottomEdgeHint {
1156+ id: floatingHint
1157+ anchors.bottom: parent.top
1158+ }
1159+ Item {
1160+ id: floatingItem
1161+ }
1162
1163 UbuntuTestCase {
1164 name: "BottomEdgeHint"
1165 when: windowShown
1166
1167+ // FIXME: the criteria must be adjusted when QSystemInfo will report
1168+ // attached mouses, till then we stick to the touch presence
1169+ property bool hasMouseAttached: QuickUtils.mouseAttached
1170+
1171 SignalSpy {
1172 id: clickSpy
1173 target: bottomEdgeHint
1174 signalName: "onClicked"
1175 }
1176
1177- function cleanup() {
1178- bottomEdgeHint.iconName = "";
1179- bottomEdgeHint.state = "Idle";
1180- clickSpy.clear();
1181- }
1182-
1183- function test_0_default_state() {
1184+ function initTestCase() {
1185+ // register test touch device
1186+ TestExtras.registerTouchDevice();
1187+
1188+ // FIXME: this test case must be adjusted after we get the QInputDeviceInfo
1189+ // available to detect attached mouse
1190+ // the test must be executed before we register touch device
1191+ if (!hasMouseAttached) {
1192+ // we don't have mouse attached, so we should be able to lock/unlock
1193+ compare(bottomEdgeHint.status, BottomEdgeHint.Inactive, "Wrong initial status when no mouse attached");
1194+ bottomEdgeHint.status = BottomEdgeHint.Locked;
1195+ compare(bottomEdgeHint.status, BottomEdgeHint.Locked, "Could not toggle status");
1196+ } else {
1197+ // we have the mouse attached, should not be able to unlock it
1198+ compare(bottomEdgeHint.status, BottomEdgeHint.Locked, "Wrong initial status when mouse attached");
1199+ bottomEdgeHint.status = BottomEdgeHint.Inactive;
1200+ compare(bottomEdgeHint.status, BottomEdgeHint.Locked, "The bottom edge must not be unlockable as long as mouse is attached!");
1201+ }
1202+ QuickUtils.mouseAttached = !QuickUtils.mouseAttached;
1203+
1204+ // and then turn locked off if possible
1205+ bottomEdgeHint.status = BottomEdgeHint.Inactive;
1206+ if (!hasMouseAttached) {
1207+ compare(bottomEdgeHint.status, BottomEdgeHint.Inactive, "Cannot unlock hint!");
1208+ }
1209+
1210+ // defaults
1211 compare(bottomEdgeHint.iconName, "");
1212 compare(bottomEdgeHint.text, "");
1213- compare(bottomEdgeHint.state, "Idle");
1214 compare(bottomEdgeHint.width, mainView.width);
1215 compare(bottomEdgeHint.height, units.gu(4));
1216 compare(bottomEdgeHint.y, mainView.height - bottomEdgeHint.height);
1217+ compare(bottomEdgeHint.flickable, null, "No flickable");
1218 compare(clickSpy.count, 0, "The BottomEdgeHint should not have received a click.");
1219+ compare(bottomEdgeHint.deactivateTimeout, 800, "default deactivationTimeout");
1220+
1221+ // set the flickable
1222+ bottomEdgeHint.flickable = listView;
1223+ }
1224+
1225+ function cleanup() {
1226+ listView.positionViewAtBeginning();
1227+ bottomEdgeHint.visible = true;
1228+ bottomEdgeHint.iconName = "";
1229+ bottomEdgeHint.status = BottomEdgeHint.Inactive;
1230+ clickSpy.clear();
1231+ wait(400);
1232 }
1233
1234 function test_hiding() {
1235- bottomEdgeHint.state = "Hidden";
1236- tryCompare(bottomEdgeHint, "opacity", 0.0);
1237- }
1238-
1239- function test_clicking() {
1240- bottomEdgeHint.state = "Locked";
1241- mouseClick(bottomEdgeHint, centerOf(bottomEdgeHint).x, centerOf(bottomEdgeHint).y);
1242- clickSpy.wait();
1243- }
1244-
1245- function test_no_clicking_while_unlocked() {
1246- mouseClick(bottomEdgeHint, centerOf(bottomEdgeHint).x, centerOf(bottomEdgeHint).y);
1247- expectFail("", "No click if not Locked");
1248- clickSpy.wait(200);
1249+ var flickDy = listView.height - units.gu(5);
1250+ flick(listView, centerOf(listView).x, flickDy, centerOf(listView).x, -flickDy, 0, 6);
1251+ if (hasMouseAttached) {
1252+ expectFailContinue("", "No hiding when mouse attached");
1253+ }
1254+ tryCompare(bottomEdgeHint, "status", BottomEdgeHint.Hidden);
1255+ }
1256+
1257+ function test_no_hiding_when_locked() {
1258+ var flickDy = listView.height - units.gu(10);
1259+ bottomEdgeHint.status = BottomEdgeHint.Locked;
1260+ flick(listView, centerOf(listView).x, flickDy, centerOf(listView).x, -flickDy, 0, 6);
1261+ expectFailContinue("", "No hiding when Locked");
1262+ tryCompare(bottomEdgeHint, "status", BottomEdgeHint.Hidden, 500);
1263+ }
1264+
1265+ function test_clicking_data() {
1266+ return [
1267+ {tag: "when Locked", status: BottomEdgeHint.Locked, xfail: false},
1268+ {tag: "when Active", status: BottomEdgeHint.Active, xfail: hasMouseAttached},
1269+ {tag: "when Inactive", status: BottomEdgeHint.Inactive, xfail: true},
1270+ {tag: "when Hidden", status: BottomEdgeHint.Hidden, xfail: true},
1271+ ];
1272+ }
1273+ function test_clicking(data) {
1274+ bottomEdgeHint.status = data.status;
1275+ compare(bottomEdgeHint.status, data.status);
1276+ mouseClick(bottomEdgeHint, centerOf(bottomEdgeHint).x, centerOf(bottomEdgeHint).y);
1277+ if (data.xfail) {
1278+ expectFailContinue(data.tag, "No click is expected");
1279+ }
1280+ clickSpy.wait(500);
1281+ }
1282+
1283+ function test_alter_deprecated_state_data() {
1284+ return [
1285+ {tag: "Hidden", status: BottomEdgeHint.Hidden},
1286+ {tag: "Visible", status: BottomEdgeHint.Inactive},
1287+ ];
1288+ }
1289+ function test_alter_deprecated_state(data) {
1290+ ignoreWarning(warningFormat(37, 5, "QML BottomEdgeHint: Overloaded 'state' property deprecated, will be removed from 1.3 release. Use 'status' instead."));
1291+ bottomEdgeHint.state = data.tag;
1292+ compare(bottomEdgeHint.status, data.status, "Wrong component status: " + data.status);
1293+ }
1294+
1295+ function test_anchoring() {
1296+ compare(floatingHint.anchors.bottom, mainView.top, "Anhors are broken");
1297+ floatingHint.parent = floatingItem;
1298+ compare(floatingHint.anchors.bottom, floatingItem.top, "Anhors are broken after reparenting");
1299+ }
1300+
1301+ function test_no_clicking_data() {
1302+ return [
1303+ {tag: "when hidden", property: "visible"},
1304+ {tag: "when disabled", property: "enabled"},
1305+ ];
1306+ }
1307+ function test_no_clicking(data) {
1308+ bottomEdgeHint.status = BottomEdgeHint.Locked;
1309+ bottomEdgeHint[data.property] = false;
1310+ mouseClick(bottomEdgeHint, centerOf(bottomEdgeHint).x, centerOf(bottomEdgeHint).y);
1311+ expectFailContinue("", "No click " + data.tag);
1312+ clickSpy.wait(400);
1313+ }
1314+
1315+ function test_activate_by_key_data() {
1316+ return [
1317+ {tag: "enter and unlocked", key: Qt.Key_Return, status: BottomEdgeHint.Inactive},
1318+ {tag: "return and unlocked", key: Qt.Key_Enter, status: BottomEdgeHint.Inactive},
1319+ {tag: "enter and locked", key: Qt.Key_Return, status: BottomEdgeHint.Locked},
1320+ {tag: "return and locked", key: Qt.Key_Enter, status: BottomEdgeHint.Locked},
1321+ ];
1322+ }
1323+ function test_activate_by_key(data) {
1324+ if (hasMouseAttached && !data.locked) {
1325+ skip(data.tag, "Test requires ability to unlock");
1326+ }
1327+ bottomEdgeHint.status = data.status;
1328+ bottomEdgeHint.forceActiveFocus();
1329+ keyPress(data.key);
1330+ if (bottomEdgeHint.status != BottomEdgeHint.Locked) {
1331+ expectFailContinue(data.tag, "should fail");
1332+ }
1333+ clickSpy.wait(400);
1334+ keyRelease(data.key);
1335+ }
1336+
1337+ // FIXME: must be executed before the test_hiding as flick with mouse affects
1338+ // the touch drag on ListView for some unknown reason
1339+ function test_touch_gesture() {
1340+ if (hasMouseAttached) {
1341+ skip("", "The test requires touch environment");
1342+ }
1343+ bottomEdgeHint.text = "Touch Activated";
1344+ var gestureStartPoint = Qt.point(centerOf(bottomEdgeHint).x, bottomEdgeHint.height - 1);
1345+ TestExtras.touchDrag(0, bottomEdgeHint, gestureStartPoint, Qt.point(0, -units.gu(8)), 6);
1346+ tryCompare(bottomEdgeHint, "status", BottomEdgeHint.Active, 400);
1347+ // then wait till we get back to Idle
1348+ tryCompare(bottomEdgeHint, "status", BottomEdgeHint.Inactive, 1000);
1349 }
1350 }
1351 }

Subscribers

People subscribed via source and target branches