Merge lp:~zsombi/ubuntu-ui-toolkit/bottomedgehint_with_swipearea into lp:ubuntu-ui-toolkit/staging
- bottomedgehint_with_swipearea
- Merge into staging
Status: | Merged |
---|---|
Approved by: | Cris Dywan |
Approved revision: | 1720 |
Merged at revision: | 1722 |
Proposed branch: | lp:~zsombi/ubuntu-ui-toolkit/bottomedgehint_with_swipearea |
Merge into: | lp:ubuntu-ui-toolkit/staging |
Prerequisite: | lp:~zsombi/ubuntu-ui-toolkit/migrate_unity8_gestures |
Diff against target: |
646 lines (+108/-281) 8 files modified
components.api (+2/-4) examples/ubuntu-ui-toolkit-gallery/MainPage.qml (+2/-3) src/Ubuntu/Components/plugin/plugin.pri (+0/-2) src/Ubuntu/Components/plugin/privates/gesturedetector.cpp (+0/-142) src/Ubuntu/Components/plugin/privates/gesturedetector.h (+0/-75) src/Ubuntu/Components/plugin/ucbottomedgehint.cpp (+76/-40) src/Ubuntu/Components/plugin/ucbottomedgehint.h (+14/-14) tests/unit_x11/tst_components/tst_bottomedgehint.qml (+14/-1) |
To merge this branch: | bzr merge lp:~zsombi/ubuntu-ui-toolkit/bottomedgehint_with_swipearea |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Cris Dywan | Approve | ||
PS Jenkins bot | continuous-integration | Approve | |
Review via email: mp+277684@code.launchpad.net |
Commit message
Remove GestureDetector in favor of SwipeArea in BottomEdgeHint. Also make possible to assign Action to the component.
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
- 1719. By Zsombor Egri
-
staging sync
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1719
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 1720. By Zsombor Egri
-
replace base class calls
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1720
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Cris Dywan (kalikiana) wrote : | # |
Like the rebase on ActionItem.
Like the QML-friendly trigger.
Like the use of the SwipeArea.
Like the comments and bug references.
No change in behavior, which is good.
Preview Diff
1 | === modified file 'components.api' | |||
2 | --- components.api 2015-11-17 14:44:49 +0000 | |||
3 | +++ components.api 2015-11-19 10:02:45 +0000 | |||
4 | @@ -175,14 +175,12 @@ | |||
5 | 175 | property var icon | 175 | property var icon |
6 | 176 | property bool iconFrame | 176 | property bool iconFrame |
7 | 177 | property bool progression | 177 | property bool progression |
9 | 178 | Ubuntu.Components.BottomEdgeHint 1.3: StyledItem | 178 | Ubuntu.Components.BottomEdgeHint 1.3: ActionItem |
10 | 179 | property int deactivateTimeout | 179 | property int deactivateTimeout |
11 | 180 | property Flickable flickable | 180 | property Flickable flickable |
12 | 181 | property string iconName | ||
13 | 182 | property url iconSource | ||
14 | 183 | signal clicked() | 181 | signal clicked() |
15 | 184 | property Status status | 182 | property Status status |
17 | 185 | property string text | 183 | readonly property SwipeArea swipeArea |
18 | 186 | Ubuntu.Components.BottomEdgeHint.Status: Enum | 184 | Ubuntu.Components.BottomEdgeHint.Status: Enum |
19 | 187 | Active | 185 | Active |
20 | 188 | Hidden | 186 | Hidden |
21 | 189 | 187 | ||
22 | === modified file 'examples/ubuntu-ui-toolkit-gallery/MainPage.qml' | |||
23 | --- examples/ubuntu-ui-toolkit-gallery/MainPage.qml 2015-11-05 13:41:35 +0000 | |||
24 | +++ examples/ubuntu-ui-toolkit-gallery/MainPage.qml 2015-11-19 10:02:45 +0000 | |||
25 | @@ -50,6 +50,7 @@ | |||
26 | 50 | onTriggered: gallery.theme.name = 'Ubuntu.Components.Themes.Ambiance' | 50 | onTriggered: gallery.theme.name = 'Ubuntu.Components.Themes.Ambiance' |
27 | 51 | }, | 51 | }, |
28 | 52 | Action { | 52 | Action { |
29 | 53 | id: aboutAction | ||
30 | 53 | text: i18n.tr('About') | 54 | text: i18n.tr('About') |
31 | 54 | iconName: "info" | 55 | iconName: "info" |
32 | 55 | onTriggered: mainPage.pageStack.addPageToCurrentColumn(mainPage, Qt.resolvedUrl("About.qml")) | 56 | onTriggered: mainPage.pageStack.addPageToCurrentColumn(mainPage, Qt.resolvedUrl("About.qml")) |
33 | @@ -135,8 +136,6 @@ | |||
34 | 135 | 136 | ||
35 | 136 | BottomEdgeHint { | 137 | BottomEdgeHint { |
36 | 137 | flickable: widgetList | 138 | flickable: widgetList |
40 | 138 | text: i18n.tr('About') | 139 | action: aboutAction |
38 | 139 | iconName: "info" | ||
39 | 140 | onClicked: mainPage.pageStack.addPageToCurrentColumn(mainPage, Qt.resolvedUrl("About.qml")) | ||
41 | 141 | } | 140 | } |
42 | 142 | } | 141 | } |
43 | 143 | 142 | ||
44 | === modified file 'src/Ubuntu/Components/plugin/plugin.pri' | |||
45 | --- src/Ubuntu/Components/plugin/plugin.pri 2015-11-09 16:51:41 +0000 | |||
46 | +++ src/Ubuntu/Components/plugin/plugin.pri 2015-11-19 10:02:45 +0000 | |||
47 | @@ -94,7 +94,6 @@ | |||
48 | 94 | $$PWD/privates/threelabelsslot_p.h \ | 94 | $$PWD/privates/threelabelsslot_p.h \ |
49 | 95 | $$PWD/ucimportversionchecker_p.h \ | 95 | $$PWD/ucimportversionchecker_p.h \ |
50 | 96 | $$PWD/ucbottomedgehint.h \ | 96 | $$PWD/ucbottomedgehint.h \ |
51 | 97 | $$PWD/privates/gesturedetector.h \ | ||
52 | 98 | $$PWD/gestures/ucswipearea.h \ | 97 | $$PWD/gestures/ucswipearea.h \ |
53 | 99 | $$PWD/gestures/ucswipearea_p.h \ | 98 | $$PWD/gestures/ucswipearea_p.h \ |
54 | 100 | $$PWD/gestures/damper.h \ | 99 | $$PWD/gestures/damper.h \ |
55 | @@ -163,7 +162,6 @@ | |||
56 | 163 | $$PWD/privates/threelabelsslot_p.cpp \ | 162 | $$PWD/privates/threelabelsslot_p.cpp \ |
57 | 164 | $$PWD/ucimportversionchecker_p.cpp \ | 163 | $$PWD/ucimportversionchecker_p.cpp \ |
58 | 165 | $$PWD/ucbottomedgehint.cpp \ | 164 | $$PWD/ucbottomedgehint.cpp \ |
59 | 166 | $$PWD/privates/gesturedetector.cpp \ | ||
60 | 167 | $$PWD/gestures/ucswipearea.cpp \ | 165 | $$PWD/gestures/ucswipearea.cpp \ |
61 | 168 | 166 | ||
62 | 169 | # adapters | 167 | # adapters |
63 | 170 | 168 | ||
64 | === removed file 'src/Ubuntu/Components/plugin/privates/gesturedetector.cpp' | |||
65 | --- src/Ubuntu/Components/plugin/privates/gesturedetector.cpp 2015-11-13 09:02:23 +0000 | |||
66 | +++ src/Ubuntu/Components/plugin/privates/gesturedetector.cpp 1970-01-01 00:00:00 +0000 | |||
67 | @@ -1,142 +0,0 @@ | |||
68 | 1 | /* | ||
69 | 2 | * Copyright 2015 Canonical Ltd. | ||
70 | 3 | * | ||
71 | 4 | * This program is free software; you can redistribute it and/or modify | ||
72 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
73 | 6 | * the Free Software Foundation; version 3. | ||
74 | 7 | * | ||
75 | 8 | * This program is distributed in the hope that it will be useful, | ||
76 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
77 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
78 | 11 | * GNU Lesser General Public License for more details. | ||
79 | 12 | * | ||
80 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
81 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
82 | 15 | * | ||
83 | 16 | * Authors: Zsombor Egri <zsombor.egri@canonical.com> | ||
84 | 17 | */ | ||
85 | 18 | |||
86 | 19 | #include "gesturedetector.h" | ||
87 | 20 | #include "ucunits.h" | ||
88 | 21 | #include <QtCore/QEvent> | ||
89 | 22 | #include <QtCore/QRectF> | ||
90 | 23 | #include <QtGui/QTouchEvent> | ||
91 | 24 | #include <QtQuick/QQuickItem> | ||
92 | 25 | #include <QtGui/QGuiApplication> | ||
93 | 26 | #include <QtGui/QStyleHints> | ||
94 | 27 | |||
95 | 28 | #define DETECTION_AREA_THICKNESS_GU 1.2 | ||
96 | 29 | |||
97 | 30 | GestureDetector::GestureDetector(QObject *parent) | ||
98 | 31 | : QObject(parent) | ||
99 | 32 | , m_owner(qobject_cast<QQuickItem*>(parent)) | ||
100 | 33 | , m_status(Ready) | ||
101 | 34 | , m_bottomUpSwipeDetected(false) | ||
102 | 35 | { | ||
103 | 36 | Q_ASSERT(m_owner); | ||
104 | 37 | } | ||
105 | 38 | GestureDetector::~GestureDetector() | ||
106 | 39 | { | ||
107 | 40 | Q_FOREACH(QObject *object, m_filteredItems) { | ||
108 | 41 | object->removeEventFilter(this); | ||
109 | 42 | } | ||
110 | 43 | m_filteredItems.clear(); | ||
111 | 44 | } | ||
112 | 45 | |||
113 | 46 | void GestureDetector::onFilteredItemDeleted(QObject *object) | ||
114 | 47 | { | ||
115 | 48 | if (object) { | ||
116 | 49 | object->removeEventFilter(this); | ||
117 | 50 | m_filteredItems.removeAll(object); | ||
118 | 51 | } | ||
119 | 52 | } | ||
120 | 53 | |||
121 | 54 | void GestureDetector::setStatus(Status status) | ||
122 | 55 | { | ||
123 | 56 | if (status == m_status) { | ||
124 | 57 | return; | ||
125 | 58 | } | ||
126 | 59 | m_status = status; | ||
127 | 60 | Q_EMIT statusChanged(m_status); | ||
128 | 61 | } | ||
129 | 62 | |||
130 | 63 | bool GestureDetector::isDetecting() | ||
131 | 64 | { | ||
132 | 65 | return (m_status > Ready && m_status < Completed); | ||
133 | 66 | } | ||
134 | 67 | |||
135 | 68 | void GestureDetector::setItemFilter(QObject *item) | ||
136 | 69 | { | ||
137 | 70 | m_filteredItems.append(item); | ||
138 | 71 | item->installEventFilter(this); | ||
139 | 72 | connect(item, &QObject::destroyed, this, &GestureDetector::onFilteredItemDeleted); | ||
140 | 73 | } | ||
141 | 74 | |||
142 | 75 | void GestureDetector::removeItemFilter(QObject *item) | ||
143 | 76 | { | ||
144 | 77 | m_filteredItems.removeAll(item); | ||
145 | 78 | item->removeEventFilter(this); | ||
146 | 79 | disconnect(item, &QObject::destroyed, this, &GestureDetector::onFilteredItemDeleted); | ||
147 | 80 | } | ||
148 | 81 | |||
149 | 82 | bool GestureDetector::handleTouchEvent(QObject *target, QTouchEvent *event) | ||
150 | 83 | { | ||
151 | 84 | switch (event->type()) { | ||
152 | 85 | case QEvent::TouchBegin: { | ||
153 | 86 | setStatus(Ready); | ||
154 | 87 | QPointF itemPoint = m_owner->mapFromScene(event->touchPoints()[0].scenePos()); | ||
155 | 88 | qreal thickness = UCUnits::instance().gu(DETECTION_AREA_THICKNESS_GU); | ||
156 | 89 | QRectF detectionArea(0.0, m_owner->height() - thickness, m_owner->width(), thickness); | ||
157 | 90 | if (detectionArea.contains(itemPoint)) { | ||
158 | 91 | m_startPoint = itemPoint; | ||
159 | 92 | setStatus(Started); | ||
160 | 93 | if (target == parent()) { | ||
161 | 94 | event->accept(); | ||
162 | 95 | return true; | ||
163 | 96 | } | ||
164 | 97 | } | ||
165 | 98 | return false; | ||
166 | 99 | } | ||
167 | 100 | case QEvent::TouchEnd: | ||
168 | 101 | { | ||
169 | 102 | m_startPoint = QPointF(); | ||
170 | 103 | setStatus(Completed); | ||
171 | 104 | return false; | ||
172 | 105 | } | ||
173 | 106 | case QEvent::TouchCancel: { | ||
174 | 107 | m_startPoint = QPointF(); | ||
175 | 108 | setStatus(Ready); | ||
176 | 109 | return false; | ||
177 | 110 | } | ||
178 | 111 | case QEvent::TouchUpdate: { | ||
179 | 112 | if (m_status == Started) { | ||
180 | 113 | QPointF itemPoint = m_owner->mapFromScene(event->touchPoints()[0].scenePos()); | ||
181 | 114 | if (abs(m_startPoint.y() - itemPoint.y()) >= qApp->styleHints()->startDragDistance()) { | ||
182 | 115 | setStatus(Detected); | ||
183 | 116 | Q_EMIT bottomUpSwipeDetected(); | ||
184 | 117 | } | ||
185 | 118 | } | ||
186 | 119 | return false; | ||
187 | 120 | } | ||
188 | 121 | default: return false; | ||
189 | 122 | } | ||
190 | 123 | } | ||
191 | 124 | |||
192 | 125 | bool GestureDetector::eventFilter(QObject *target, QEvent *event) | ||
193 | 126 | { | ||
194 | 127 | if (m_filteredItems.contains(target)) { | ||
195 | 128 | QEvent::Type type = event->type(); | ||
196 | 129 | if (type == QEvent::TouchBegin | ||
197 | 130 | || type == QEvent::TouchUpdate | ||
198 | 131 | || type == QEvent::TouchEnd | ||
199 | 132 | || type == QEvent::TouchCancel) { | ||
200 | 133 | QTouchEvent *touch = static_cast<QTouchEvent*>(event); | ||
201 | 134 | return handleTouchEvent(target, touch); | ||
202 | 135 | } else { | ||
203 | 136 | // pass it on | ||
204 | 137 | return false; | ||
205 | 138 | } | ||
206 | 139 | } else { | ||
207 | 140 | return QObject::eventFilter(target, event); | ||
208 | 141 | } | ||
209 | 142 | } | ||
210 | 143 | 0 | ||
211 | === removed file 'src/Ubuntu/Components/plugin/privates/gesturedetector.h' | |||
212 | --- src/Ubuntu/Components/plugin/privates/gesturedetector.h 2015-11-13 09:02:23 +0000 | |||
213 | +++ src/Ubuntu/Components/plugin/privates/gesturedetector.h 1970-01-01 00:00:00 +0000 | |||
214 | @@ -1,75 +0,0 @@ | |||
215 | 1 | /* | ||
216 | 2 | * Copyright 2015 Canonical Ltd. | ||
217 | 3 | * | ||
218 | 4 | * This program is free software; you can redistribute it and/or modify | ||
219 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
220 | 6 | * the Free Software Foundation; version 3. | ||
221 | 7 | * | ||
222 | 8 | * This program is distributed in the hope that it will be useful, | ||
223 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
224 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
225 | 11 | * GNU Lesser General Public License for more details. | ||
226 | 12 | * | ||
227 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
228 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
229 | 15 | * | ||
230 | 16 | * Authors: Zsombor Egri <zsombor.egri@canonical.com> | ||
231 | 17 | */ | ||
232 | 18 | |||
233 | 19 | #ifndef GESTUREDETECTOR_H | ||
234 | 20 | #define GESTUREDETECTOR_H | ||
235 | 21 | |||
236 | 22 | #include <QtCore/QObject> | ||
237 | 23 | #include <QtCore/QPointF> | ||
238 | 24 | #include <QtCore/QList> | ||
239 | 25 | |||
240 | 26 | /* | ||
241 | 27 | * A simple gesture detection filter class that can be used in components to detect | ||
242 | 28 | * various gestures. Yet swipe from bottom up is the only gesture handled. | ||
243 | 29 | * It does not grab or consume the event from the environment, acts as a filter. | ||
244 | 30 | */ | ||
245 | 31 | class QTouchEvent; | ||
246 | 32 | class QQuickItem; | ||
247 | 33 | class GestureDetector : public QObject | ||
248 | 34 | { | ||
249 | 35 | Q_OBJECT | ||
250 | 36 | public: | ||
251 | 37 | enum Status { | ||
252 | 38 | Ready, | ||
253 | 39 | Started, | ||
254 | 40 | Detected, | ||
255 | 41 | Completed | ||
256 | 42 | }; | ||
257 | 43 | explicit GestureDetector(QObject *parent = 0); | ||
258 | 44 | ~GestureDetector(); | ||
259 | 45 | |||
260 | 46 | bool isDetecting(); | ||
261 | 47 | |||
262 | 48 | void setItemFilter(QObject *item); | ||
263 | 49 | void removeItemFilter(QObject *item); | ||
264 | 50 | |||
265 | 51 | bool handleTouchEvent(QObject *target, QTouchEvent *event); | ||
266 | 52 | |||
267 | 53 | Q_SIGNALS: | ||
268 | 54 | void statusChanged(Status status); | ||
269 | 55 | |||
270 | 56 | void bottomUpSwipeDetected(); | ||
271 | 57 | |||
272 | 58 | public Q_SLOTS: | ||
273 | 59 | |||
274 | 60 | protected: | ||
275 | 61 | bool eventFilter(QObject *target, QEvent *event); | ||
276 | 62 | |||
277 | 63 | void setStatus(Status status); | ||
278 | 64 | |||
279 | 65 | private: | ||
280 | 66 | QList<QObject*> m_filteredItems; | ||
281 | 67 | QPointF m_startPoint; | ||
282 | 68 | QQuickItem *m_owner; | ||
283 | 69 | Status m_status; | ||
284 | 70 | bool m_bottomUpSwipeDetected:1; | ||
285 | 71 | |||
286 | 72 | void onFilteredItemDeleted(QObject *object); | ||
287 | 73 | }; | ||
288 | 74 | |||
289 | 75 | #endif // GESTUREDETECTOR_H | ||
290 | 76 | 0 | ||
291 | === modified file 'src/Ubuntu/Components/plugin/ucbottomedgehint.cpp' | |||
292 | --- src/Ubuntu/Components/plugin/ucbottomedgehint.cpp 2015-11-05 14:28:58 +0000 | |||
293 | +++ src/Ubuntu/Components/plugin/ucbottomedgehint.cpp 2015-11-19 10:02:45 +0000 | |||
294 | @@ -20,14 +20,17 @@ | |||
295 | 20 | #include "ucstyleditembase_p.h" | 20 | #include "ucstyleditembase_p.h" |
296 | 21 | #include "quickutils.h" | 21 | #include "quickutils.h" |
297 | 22 | #include "ucunits.h" | 22 | #include "ucunits.h" |
298 | 23 | #include "gestures/ucswipearea.h" | ||
299 | 23 | #include <QtQml/private/qqmlproperty_p.h> | 24 | #include <QtQml/private/qqmlproperty_p.h> |
300 | 24 | #include <QtQuick/private/qquickflickable_p.h> | 25 | #include <QtQuick/private/qquickflickable_p.h> |
301 | 25 | 26 | ||
302 | 27 | #define SWIPE_AREA_HEIGHT_GU 3 | ||
303 | 28 | |||
304 | 26 | /*! | 29 | /*! |
305 | 27 | \qmltype BottomEdgeHint | 30 | \qmltype BottomEdgeHint |
306 | 28 | \inqmlmodule Ubuntu.Components 1.3 | 31 | \inqmlmodule Ubuntu.Components 1.3 |
307 | 29 | \ingroup ubuntu | 32 | \ingroup ubuntu |
309 | 30 | \inherits StyledItem | 33 | \inherits ActionItem |
310 | 31 | \brief The BottomEdgeHint shows the availability of extra features | 34 | \brief The BottomEdgeHint shows the availability of extra features |
311 | 32 | available from the bottom edge of the application. | 35 | available from the bottom edge of the application. |
312 | 33 | 36 | ||
313 | @@ -50,14 +53,19 @@ | |||
314 | 50 | The component is styled through \b BottomEdgeHintStyle. | 53 | The component is styled through \b BottomEdgeHintStyle. |
315 | 51 | */ | 54 | */ |
316 | 52 | UCBottomEdgeHint::UCBottomEdgeHint(QQuickItem *parent) | 55 | UCBottomEdgeHint::UCBottomEdgeHint(QQuickItem *parent) |
319 | 53 | : UCStyledItemBase(parent) | 56 | : UCActionItem(parent) |
320 | 54 | , m_gestureDetector(this) | 57 | , m_swipeArea(new UCSwipeArea) |
321 | 55 | , m_flickable(Q_NULLPTR) | 58 | , m_flickable(Q_NULLPTR) |
322 | 56 | , m_deactivateTimeout(800) | 59 | , m_deactivateTimeout(800) |
323 | 57 | // FIXME: we need QInputDeviceInfo to be complete with the locked!! | 60 | // FIXME: we need QInputDeviceInfo to be complete with the locked!! |
324 | 61 | // https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1276808 | ||
325 | 58 | , m_status(QuickUtils::instance().mouseAttached() ? Locked : Inactive) | 62 | , m_status(QuickUtils::instance().mouseAttached() ? Locked : Inactive) |
326 | 59 | , m_pressed(false) | 63 | , m_pressed(false) |
327 | 60 | { | 64 | { |
328 | 65 | connect(this, &UCBottomEdgeHint::clicked, [=]() { | ||
329 | 66 | // make sure the overloaded trigger is called! | ||
330 | 67 | metaObject()->invokeMethod(this, "trigger", Q_ARG(QVariant, QVariant())); | ||
331 | 68 | }); | ||
332 | 61 | /* | 69 | /* |
333 | 62 | * we cannot use setStyleName as that will trigger style loading | 70 | * we cannot use setStyleName as that will trigger style loading |
334 | 63 | * and the qmlEngine is not known at this phase of the of the initialization | 71 | * and the qmlEngine is not known at this phase of the of the initialization |
335 | @@ -69,13 +77,8 @@ | |||
336 | 69 | // connect old stateChanged | 77 | // connect old stateChanged |
337 | 70 | connect(this, &QQuickItem::stateChanged, this, &UCBottomEdgeHint::stateChanged); | 78 | connect(this, &QQuickItem::stateChanged, this, &UCBottomEdgeHint::stateChanged); |
338 | 71 | 79 | ||
339 | 72 | // connect to gesture detection | ||
340 | 73 | connect(&m_gestureDetector, &GestureDetector::bottomUpSwipeDetected, | ||
341 | 74 | this, &UCBottomEdgeHint::onBottomUpSwipeDetected); | ||
342 | 75 | connect(&m_gestureDetector, &GestureDetector::statusChanged, | ||
343 | 76 | this, &UCBottomEdgeHint::onGestureStatusChanged); | ||
344 | 77 | |||
345 | 78 | // FIXME: use QInputDeviceInfo once available | 80 | // FIXME: use QInputDeviceInfo once available |
346 | 81 | // https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1276808 | ||
347 | 79 | connect(&QuickUtils::instance(), &QuickUtils::mouseAttachedChanged, [this]() { | 82 | connect(&QuickUtils::instance(), &QuickUtils::mouseAttachedChanged, [this]() { |
348 | 80 | setStatus(QuickUtils::instance().mouseAttached() ? Locked : Active); | 83 | setStatus(QuickUtils::instance().mouseAttached() ? Locked : Active); |
349 | 81 | if (m_status == Active) { | 84 | if (m_status == Active) { |
350 | @@ -87,9 +90,44 @@ | |||
351 | 87 | setAcceptedMouseButtons(Qt::LeftButton); | 90 | setAcceptedMouseButtons(Qt::LeftButton); |
352 | 88 | } | 91 | } |
353 | 89 | 92 | ||
354 | 93 | void UCBottomEdgeHint::classBegin() | ||
355 | 94 | { | ||
356 | 95 | UCActionItem::classBegin(); | ||
357 | 96 | init(); | ||
358 | 97 | } | ||
359 | 98 | |||
360 | 99 | void UCBottomEdgeHint::init() | ||
361 | 100 | { | ||
362 | 101 | QQml_setParent_noEvent(m_swipeArea, this); | ||
363 | 102 | m_swipeArea->setParentItem(this); | ||
364 | 103 | |||
365 | 104 | // set context | ||
366 | 105 | QQmlEngine::setContextForObject(m_swipeArea, qmlContext(this)); | ||
367 | 106 | |||
368 | 107 | // initialize swipe area size | ||
369 | 108 | QQuickAnchors *anchors = QQuickItemPrivate::get(m_swipeArea)->anchors(); | ||
370 | 109 | QQuickItemPrivate *thisPrivate = QQuickItemPrivate::get(this); | ||
371 | 110 | anchors->setLeft(thisPrivate->left()); | ||
372 | 111 | anchors->setBottom(thisPrivate->bottom()); | ||
373 | 112 | anchors->setRight(thisPrivate->right()); | ||
374 | 113 | m_swipeArea->setImplicitHeight(UCUnits::instance().gu(SWIPE_AREA_HEIGHT_GU)); | ||
375 | 114 | |||
376 | 115 | // direction | ||
377 | 116 | m_swipeArea->setDirection(UCSwipeArea::Upwards); | ||
378 | 117 | |||
379 | 118 | // grid unit sync | ||
380 | 119 | connect(&UCUnits::instance(), &UCUnits::gridUnitChanged, [this] { | ||
381 | 120 | m_swipeArea->setImplicitHeight(UCUnits::instance().gu(SWIPE_AREA_HEIGHT_GU)); | ||
382 | 121 | }); | ||
383 | 122 | |||
384 | 123 | // connect to gesture detection | ||
385 | 124 | connect(m_swipeArea, &UCSwipeArea::draggingChanged, | ||
386 | 125 | this, &UCBottomEdgeHint::onDraggingChanged, Qt::DirectConnection); | ||
387 | 126 | } | ||
388 | 127 | |||
389 | 90 | void UCBottomEdgeHint::itemChange(ItemChange change, const ItemChangeData &data) | 128 | void UCBottomEdgeHint::itemChange(ItemChange change, const ItemChangeData &data) |
390 | 91 | { | 129 | { |
392 | 92 | UCStyledItemBase::itemChange(change, data); | 130 | UCActionItem::itemChange(change, data); |
393 | 93 | if (change == ItemParentHasChanged) { | 131 | if (change == ItemParentHasChanged) { |
394 | 94 | QQmlProperty bottomAnchors(this, "anchors.bottom", qmlContext(this)); | 132 | QQmlProperty bottomAnchors(this, "anchors.bottom", qmlContext(this)); |
395 | 95 | if (data.item && !QQmlPropertyPrivate::binding(bottomAnchors)) { | 133 | if (data.item && !QQmlPropertyPrivate::binding(bottomAnchors)) { |
396 | @@ -101,7 +139,7 @@ | |||
397 | 101 | 139 | ||
398 | 102 | void UCBottomEdgeHint::timerEvent(QTimerEvent *event) | 140 | void UCBottomEdgeHint::timerEvent(QTimerEvent *event) |
399 | 103 | { | 141 | { |
401 | 104 | UCStyledItemBase::timerEvent(event); | 142 | UCActionItem::timerEvent(event); |
402 | 105 | if (event->timerId() == m_deactivationTimer.timerId()) { | 143 | if (event->timerId() == m_deactivationTimer.timerId()) { |
403 | 106 | setStatus(Inactive); | 144 | setStatus(Inactive); |
404 | 107 | m_deactivationTimer.stop(); | 145 | m_deactivationTimer.stop(); |
405 | @@ -111,49 +149,37 @@ | |||
406 | 111 | // handle clicked event when locked and enter or return is pressed | 149 | // handle clicked event when locked and enter or return is pressed |
407 | 112 | void UCBottomEdgeHint::keyPressEvent(QKeyEvent *event) | 150 | void UCBottomEdgeHint::keyPressEvent(QKeyEvent *event) |
408 | 113 | { | 151 | { |
410 | 114 | UCStyledItemBase::keyPressEvent(event); | 152 | UCActionItem::keyPressEvent(event); |
411 | 115 | if ((status() >= Active) && (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return)) { | 153 | if ((status() >= Active) && (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return)) { |
412 | 116 | Q_EMIT clicked(); | 154 | Q_EMIT clicked(); |
413 | 117 | } | 155 | } |
414 | 118 | } | 156 | } |
415 | 119 | 157 | ||
416 | 120 | // handle gesture detection | ||
417 | 121 | void UCBottomEdgeHint::touchEvent(QTouchEvent *event) | ||
418 | 122 | { | ||
419 | 123 | UCStyledItemBase::touchEvent(event); | ||
420 | 124 | m_gestureDetector.handleTouchEvent(this, event); | ||
421 | 125 | } | ||
422 | 126 | |||
423 | 127 | // handle click event | 158 | // handle click event |
424 | 128 | void UCBottomEdgeHint::mousePressEvent(QMouseEvent *event) | 159 | void UCBottomEdgeHint::mousePressEvent(QMouseEvent *event) |
425 | 129 | { | 160 | { |
426 | 130 | if (contains(event->localPos()) && (m_status >= Active)) { | 161 | if (contains(event->localPos()) && (m_status >= Active)) { |
427 | 131 | m_pressed = true; | 162 | m_pressed = true; |
428 | 132 | } else { | 163 | } else { |
430 | 133 | UCStyledItemBase::mousePressEvent(event); | 164 | UCActionItem::mousePressEvent(event); |
431 | 134 | } | 165 | } |
432 | 135 | } | 166 | } |
433 | 136 | void UCBottomEdgeHint::mouseReleaseEvent(QMouseEvent *event) | 167 | void UCBottomEdgeHint::mouseReleaseEvent(QMouseEvent *event) |
434 | 137 | { | 168 | { |
436 | 138 | UCStyledItemBase::mouseReleaseEvent(event); | 169 | UCActionItem::mouseReleaseEvent(event); |
437 | 139 | if (m_pressed && (m_status >= Active)) { | 170 | if (m_pressed && (m_status >= Active)) { |
438 | 140 | Q_EMIT clicked(); | 171 | Q_EMIT clicked(); |
439 | 141 | } | 172 | } |
440 | 142 | } | 173 | } |
441 | 143 | 174 | ||
442 | 144 | // watch gesture detection status changes | 175 | // watch gesture detection status changes |
455 | 145 | void UCBottomEdgeHint::onBottomUpSwipeDetected() | 176 | void UCBottomEdgeHint::onDraggingChanged(bool dragging) |
456 | 146 | { | 177 | { |
457 | 147 | m_deactivationTimer.stop(); | 178 | if (dragging) { |
458 | 148 | setStatus(Active); | 179 | m_deactivationTimer.stop(); |
459 | 149 | } | 180 | setStatus(Active); |
460 | 150 | 181 | } else if (m_status == Active) { | |
461 | 151 | void UCBottomEdgeHint::onGestureStatusChanged(GestureDetector::Status status) | 182 | m_deactivationTimer.start(m_deactivateTimeout, this); |
450 | 152 | { | ||
451 | 153 | if (status == GestureDetector::Completed) { | ||
452 | 154 | if (m_status == Active) { | ||
453 | 155 | m_deactivationTimer.start(m_deactivateTimeout, this); | ||
454 | 156 | } | ||
462 | 157 | } | 183 | } |
463 | 158 | } | 184 | } |
464 | 159 | 185 | ||
465 | @@ -200,7 +226,6 @@ | |||
466 | 200 | this, &UCBottomEdgeHint::handleFlickableActivation); | 226 | this, &UCBottomEdgeHint::handleFlickableActivation); |
467 | 201 | disconnect(m_flickable, &QQuickFlickable::movingChanged, | 227 | disconnect(m_flickable, &QQuickFlickable::movingChanged, |
468 | 202 | this, &UCBottomEdgeHint::handleFlickableActivation); | 228 | this, &UCBottomEdgeHint::handleFlickableActivation); |
469 | 203 | m_gestureDetector.removeItemFilter(m_flickable); | ||
470 | 204 | } | 229 | } |
471 | 205 | m_flickable = flickable; | 230 | m_flickable = flickable; |
472 | 206 | if (m_flickable) { | 231 | if (m_flickable) { |
473 | @@ -208,7 +233,6 @@ | |||
474 | 208 | this, &UCBottomEdgeHint::handleFlickableActivation, Qt::DirectConnection); | 233 | this, &UCBottomEdgeHint::handleFlickableActivation, Qt::DirectConnection); |
475 | 209 | connect(m_flickable, &QQuickFlickable::movingChanged, | 234 | connect(m_flickable, &QQuickFlickable::movingChanged, |
476 | 210 | this, &UCBottomEdgeHint::handleFlickableActivation, Qt::DirectConnection); | 235 | this, &UCBottomEdgeHint::handleFlickableActivation, Qt::DirectConnection); |
477 | 211 | m_gestureDetector.setItemFilter(m_flickable); | ||
478 | 212 | } | 236 | } |
479 | 213 | Q_EMIT flickableChanged(); | 237 | Q_EMIT flickableChanged(); |
480 | 214 | } | 238 | } |
481 | @@ -216,7 +240,7 @@ | |||
482 | 216 | // flickable moves hide the hint only if the current status is not Locked | 240 | // flickable moves hide the hint only if the current status is not Locked |
483 | 217 | void UCBottomEdgeHint::handleFlickableActivation() | 241 | void UCBottomEdgeHint::handleFlickableActivation() |
484 | 218 | { | 242 | { |
486 | 219 | if (m_status < Locked && !m_gestureDetector.isDetecting() && !m_deactivationTimer.isActive()) { | 243 | if (m_status < Locked && !m_swipeArea->dragging() && !m_deactivationTimer.isActive()) { |
487 | 220 | bool moving = m_flickable->isFlicking() || m_flickable->isMoving(); | 244 | bool moving = m_flickable->isFlicking() || m_flickable->isMoving(); |
488 | 221 | if (moving) { | 245 | if (moving) { |
489 | 222 | setStatus(Hidden); | 246 | setStatus(Hidden); |
490 | @@ -304,6 +328,7 @@ | |||
491 | 304 | UCBottomEdgeHint::Status UCBottomEdgeHint::status() | 328 | UCBottomEdgeHint::Status UCBottomEdgeHint::status() |
492 | 305 | { | 329 | { |
493 | 306 | // FIXME: we won't need this once we get the QInputDeviceInfo reporting mouse attach/detach | 330 | // FIXME: we won't need this once we get the QInputDeviceInfo reporting mouse attach/detach |
494 | 331 | // https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1276808 | ||
495 | 307 | if (QuickUtils::instance().mouseAttached()) { | 332 | if (QuickUtils::instance().mouseAttached()) { |
496 | 308 | m_status = Locked; | 333 | m_status = Locked; |
497 | 309 | } | 334 | } |
498 | @@ -313,15 +338,19 @@ | |||
499 | 313 | void UCBottomEdgeHint::setStatus(Status status) | 338 | void UCBottomEdgeHint::setStatus(Status status) |
500 | 314 | { | 339 | { |
501 | 315 | // FIXME: we need QInputDeviceInfo to complete this! | 340 | // FIXME: we need QInputDeviceInfo to complete this! |
502 | 341 | // https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1276808 | ||
503 | 316 | // cannot unlock if mouse is attached or we don't have touch screen available | 342 | // cannot unlock if mouse is attached or we don't have touch screen available |
504 | 317 | if (status == m_status || (status != Locked && QuickUtils::instance().mouseAttached())) { | 343 | if (status == m_status || (status != Locked && QuickUtils::instance().mouseAttached())) { |
505 | 318 | return; | 344 | return; |
506 | 319 | } | 345 | } |
507 | 346 | // if the previous state was Locked and the new one is Active, start deactivation timer | ||
508 | 347 | if (m_status == Locked && status == Active && !m_deactivationTimer.isActive()) { | ||
509 | 348 | m_deactivationTimer.start(m_deactivateTimeout, this); | ||
510 | 349 | } else if (status != Active && m_deactivationTimer.isActive()) { | ||
511 | 350 | // make sure we stop the deactivation timer if Inactive or Locked | ||
512 | 351 | m_deactivationTimer.stop(); | ||
513 | 352 | } | ||
514 | 320 | m_status = status; | 353 | m_status = status; |
515 | 321 | // make sure we stop the deactivation timer if Inactive or Locked | ||
516 | 322 | if (status != Active && m_deactivationTimer.isActive()) { | ||
517 | 323 | m_deactivationTimer.stop(); | ||
518 | 324 | } | ||
519 | 325 | Q_EMIT statusChanged(); | 354 | Q_EMIT statusChanged(); |
520 | 326 | } | 355 | } |
521 | 327 | 356 | ||
522 | @@ -345,3 +374,10 @@ | |||
523 | 345 | } | 374 | } |
524 | 346 | Q_EMIT deactivateTimeoutChanged(); | 375 | Q_EMIT deactivateTimeoutChanged(); |
525 | 347 | } | 376 | } |
526 | 377 | |||
527 | 378 | /*! | ||
528 | 379 | * \qmlproperty SwipeArea BottomEdgeHint::swipeArea | ||
529 | 380 | * \readonly | ||
530 | 381 | * The property specifies the SwipeArea attached to the component driving its | ||
531 | 382 | * behavior. | ||
532 | 383 | */ | ||
533 | 348 | 384 | ||
534 | === modified file 'src/Ubuntu/Components/plugin/ucbottomedgehint.h' | |||
535 | --- src/Ubuntu/Components/plugin/ucbottomedgehint.h 2015-11-05 14:06:36 +0000 | |||
536 | +++ src/Ubuntu/Components/plugin/ucbottomedgehint.h 2015-11-19 10:02:45 +0000 | |||
537 | @@ -19,20 +19,18 @@ | |||
538 | 19 | #ifndef UCBOTTOMEDGEHINT_H | 19 | #ifndef UCBOTTOMEDGEHINT_H |
539 | 20 | #define UCBOTTOMEDGEHINT_H | 20 | #define UCBOTTOMEDGEHINT_H |
540 | 21 | 21 | ||
543 | 22 | #include "ucstyleditembase.h" | 22 | #include "ucactionitem.h" |
542 | 23 | #include "privates/gesturedetector.h" | ||
544 | 24 | 23 | ||
545 | 25 | class QQuickFlickable; | 24 | class QQuickFlickable; |
547 | 26 | class UCBottomEdgeHint : public UCStyledItemBase | 25 | class UCSwipeArea; |
548 | 26 | class UCBottomEdgeHint : public UCActionItem | ||
549 | 27 | { | 27 | { |
550 | 28 | Q_OBJECT | 28 | Q_OBJECT |
551 | 29 | Q_ENUMS(Status) | 29 | Q_ENUMS(Status) |
552 | 30 | Q_PROPERTY(QString text MEMBER m_text NOTIFY textChanged FINAL) | ||
553 | 31 | Q_PROPERTY(QUrl iconSource MEMBER m_iconSource NOTIFY iconSourceChanged FINAL) | ||
554 | 32 | Q_PROPERTY(QString iconName MEMBER m_iconName NOTIFY iconNameChanged FINAL) | ||
555 | 33 | Q_PROPERTY(QQuickFlickable *flickable MEMBER m_flickable WRITE setFlickable NOTIFY flickableChanged FINAL) | 30 | Q_PROPERTY(QQuickFlickable *flickable MEMBER m_flickable WRITE setFlickable NOTIFY flickableChanged FINAL) |
556 | 34 | Q_PROPERTY(Status status MEMBER m_status WRITE setStatus NOTIFY statusChanged FINAL) | 31 | Q_PROPERTY(Status status MEMBER m_status WRITE setStatus NOTIFY statusChanged FINAL) |
557 | 35 | Q_PROPERTY(int deactivateTimeout MEMBER m_deactivateTimeout WRITE setDeactivateTimeout NOTIFY deactivateTimeoutChanged FINAL) | 32 | Q_PROPERTY(int deactivateTimeout MEMBER m_deactivateTimeout WRITE setDeactivateTimeout NOTIFY deactivateTimeoutChanged FINAL) |
558 | 33 | Q_PROPERTY(UCSwipeArea* swipeArea READ swipeArea CONSTANT FINAL) | ||
559 | 36 | // deprecated | 34 | // deprecated |
560 | 37 | Q_PROPERTY(QString state READ state WRITE setState NOTIFY stateChanged) | 35 | Q_PROPERTY(QString state READ state WRITE setState NOTIFY stateChanged) |
561 | 38 | public: | 36 | public: |
562 | @@ -47,11 +45,15 @@ | |||
563 | 47 | void setFlickable(QQuickFlickable *flickable); | 45 | void setFlickable(QQuickFlickable *flickable); |
564 | 48 | Status status(); | 46 | Status status(); |
565 | 49 | void setStatus(Status status); | 47 | void setStatus(Status status); |
566 | 48 | void setDeactivateTimeout(int timeout); | ||
567 | 49 | UCSwipeArea *swipeArea() const | ||
568 | 50 | { | ||
569 | 51 | return m_swipeArea; | ||
570 | 52 | } | ||
571 | 50 | 53 | ||
572 | 51 | // deprecated | 54 | // deprecated |
573 | 52 | QString state() const; | 55 | QString state() const; |
574 | 53 | void setState(const QString &state); | 56 | void setState(const QString &state); |
575 | 54 | void setDeactivateTimeout(int timeout); | ||
576 | 55 | 57 | ||
577 | 56 | Q_SIGNALS: | 58 | Q_SIGNALS: |
578 | 57 | void textChanged(); | 59 | void textChanged(); |
579 | @@ -66,23 +68,21 @@ | |||
580 | 66 | // deprecated | 68 | // deprecated |
581 | 67 | void stateChanged(); | 69 | void stateChanged(); |
582 | 68 | protected: | 70 | protected: |
583 | 71 | void classBegin(); | ||
584 | 69 | void itemChange(ItemChange change, const ItemChangeData &data); | 72 | void itemChange(ItemChange change, const ItemChangeData &data); |
585 | 70 | void timerEvent(QTimerEvent *event); | 73 | void timerEvent(QTimerEvent *event); |
586 | 71 | void keyPressEvent(QKeyEvent *event); | 74 | void keyPressEvent(QKeyEvent *event); |
587 | 72 | void touchEvent(QTouchEvent *event); | ||
588 | 73 | void mousePressEvent(QMouseEvent *event); | 75 | void mousePressEvent(QMouseEvent *event); |
589 | 74 | void mouseReleaseEvent(QMouseEvent *event); | 76 | void mouseReleaseEvent(QMouseEvent *event); |
590 | 75 | 77 | ||
591 | 76 | void handleFlickableActivation(); | 78 | void handleFlickableActivation(); |
594 | 77 | void onBottomUpSwipeDetected(); | 79 | void onDraggingChanged(bool dragging); |
595 | 78 | void onGestureStatusChanged(GestureDetector::Status status); | 80 | |
596 | 81 | void init(); | ||
597 | 79 | 82 | ||
598 | 80 | private: | 83 | private: |
599 | 81 | GestureDetector m_gestureDetector; | ||
600 | 82 | QBasicTimer m_deactivationTimer; | 84 | QBasicTimer m_deactivationTimer; |
604 | 83 | QString m_text; | 85 | UCSwipeArea *m_swipeArea; |
602 | 84 | QUrl m_iconSource; | ||
603 | 85 | QString m_iconName; | ||
605 | 86 | QQuickFlickable *m_flickable; | 86 | QQuickFlickable *m_flickable; |
606 | 87 | int m_deactivateTimeout; | 87 | int m_deactivateTimeout; |
607 | 88 | Status m_status; | 88 | Status m_status; |
608 | 89 | 89 | ||
609 | === modified file 'tests/unit_x11/tst_components/tst_bottomedgehint.qml' | |||
610 | --- tests/unit_x11/tst_components/tst_bottomedgehint.qml 2015-11-05 14:28:58 +0000 | |||
611 | +++ tests/unit_x11/tst_components/tst_bottomedgehint.qml 2015-11-19 10:02:45 +0000 | |||
612 | @@ -36,6 +36,11 @@ | |||
613 | 36 | 36 | ||
614 | 37 | BottomEdgeHint { | 37 | BottomEdgeHint { |
615 | 38 | id: bottomEdgeHint | 38 | id: bottomEdgeHint |
616 | 39 | property int triggerCount: 0 | ||
617 | 40 | function trigger(v) | ||
618 | 41 | { | ||
619 | 42 | triggerCount++; | ||
620 | 43 | } | ||
621 | 39 | } | 44 | } |
622 | 40 | BottomEdgeHint { | 45 | BottomEdgeHint { |
623 | 41 | id: floatingHint | 46 | id: floatingHint |
624 | @@ -199,7 +204,7 @@ | |||
625 | 199 | 204 | ||
626 | 200 | // FIXME: must be executed before the test_hiding as flick with mouse affects | 205 | // FIXME: must be executed before the test_hiding as flick with mouse affects |
627 | 201 | // the touch drag on ListView for some unknown reason | 206 | // the touch drag on ListView for some unknown reason |
629 | 202 | function test_touch_gesture() { | 207 | function test_0_touch_gesture() { |
630 | 203 | if (hasMouseAttached) { | 208 | if (hasMouseAttached) { |
631 | 204 | skip("", "The test requires touch environment"); | 209 | skip("", "The test requires touch environment"); |
632 | 205 | } | 210 | } |
633 | @@ -210,5 +215,13 @@ | |||
634 | 210 | // then wait till we get back to Idle | 215 | // then wait till we get back to Idle |
635 | 211 | tryCompare(bottomEdgeHint, "status", BottomEdgeHint.Inactive, 1000); | 216 | tryCompare(bottomEdgeHint, "status", BottomEdgeHint.Inactive, 1000); |
636 | 212 | } | 217 | } |
637 | 218 | |||
638 | 219 | function test_custom_trigger_on_clicked() { | ||
639 | 220 | bottomEdgeHint.status = BottomEdgeHint.Locked; | ||
640 | 221 | var prevCount = bottomEdgeHint.triggerCount; | ||
641 | 222 | mouseClick(bottomEdgeHint, centerOf(bottomEdgeHint).x, centerOf(bottomEdgeHint).y); | ||
642 | 223 | clickSpy.wait(500); | ||
643 | 224 | compare(bottomEdgeHint.triggerCount, prevCount + 1, "Overloaded trigger not called"); | ||
644 | 225 | } | ||
645 | 213 | } | 226 | } |
646 | 214 | } | 227 | } |
PASSED: Continuous integration, rev:1718 jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- ci/2493/ jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-amd64- ci/1221 jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-armhf- ci/1223 jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-armhf- ci/1223/ artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-i386- ci/1220
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/ubuntu- sdk-team- ubuntu- ui-toolkit- staging- ci/2493/ rebuild
http://