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

Proposed by Zsombor Egri on 2015-08-19
Status: Merged
Approved by: Zsombor Egri on 2015-08-25
Approved revision: 1638
Merged at revision: 1618
Proposed branch: lp:~zsombi/ubuntu-ui-toolkit/cppAbstractButton
Merge into: lp:ubuntu-ui-toolkit/staging
Prerequisite: lp:~zsombi/ubuntu-ui-toolkit/cppHaptics
Diff against target: 807 lines (+449/-125)
21 files modified
components.api (+2/-2)
src/Ubuntu/Components/1.3/AbstractButton.qml (+0/-109)
src/Ubuntu/Components/1.3/Button.qml (+1/-1)
src/Ubuntu/Components/1.3/ComboButton.qml (+1/-0)
src/Ubuntu/Components/1.3/TextField.qml (+1/-1)
src/Ubuntu/Components/ComponentModule.pro (+1/-2)
src/Ubuntu/Components/ListItems/1.3/SingleControl.qml (+2/-1)
src/Ubuntu/Components/plugin/plugin.cpp (+2/-0)
src/Ubuntu/Components/plugin/plugin.pri (+4/-2)
src/Ubuntu/Components/plugin/ucabstractbutton.cpp (+156/-0)
src/Ubuntu/Components/plugin/ucabstractbutton.h (+64/-0)
src/Ubuntu/Components/plugin/ucaction.cpp (+2/-1)
src/Ubuntu/Components/plugin/ucactionitem.cpp (+15/-4)
src/Ubuntu/Components/plugin/ucactionitem.h (+2/-0)
src/Ubuntu/Components/qmldir (+0/-1)
tests/unit/tst_components/tst_action.qml (+16/-0)
tests/unit/tst_performance/AbstractButton13Grid.qml (+30/-0)
tests/unit/tst_performance/AbstractButtonGrid.qml (+30/-0)
tests/unit/tst_performance/tst_performance.cpp (+2/-0)
tests/unit/tst_performance/tst_performance.pro (+3/-1)
tests/unit_x11/tst_components/tst_abstractbutton13.qml (+115/-0)
To merge this branch: bzr merge lp:~zsombi/ubuntu-ui-toolkit/cppAbstractButton
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve on 2015-08-25
Christian Dywan Approve on 2015-08-25
Tim Peeters 2015-08-19 Approve on 2015-08-24
Review via email: mp+268442@code.launchpad.net

Commit Message

AbstractButton to C++.

To post a comment you must log in.
Tim Peeters (tpeeters) wrote :

Why are you not importing the latest versions (not only of Ubuntu.Components, but also QtQuick and Ambience) in the performance tests?

686 === added file 'tests/unit/tst_performance/AbstractButtonGrid.qml'
706 +import QtQuick 2.0
707 +import Ubuntu.Components 1.1
708 +import Ubuntu.Components.Themes.Ambiance 0.1

722 === modified file 'tests/unit/tst_performance/ButtonGrid.qml'
728 import QtQuick 2.0
729 -import Ubuntu.Components 1.1
730 +import Ubuntu.Components 1.3
731 import Ubuntu.Components.Themes.Ambiance 0.1

Tim Peeters (tpeeters) wrote :

883 + // fixing bugs 1365471 and 1458028
884 + function test_no_pressAndHold_connected_clicks() {

890 + // fixing bugs 1365471 and 1458028
891 + function test_pressAndHold_connected_suppresses_clicks() {

We have the policy to add _bugXXX to the function names. Let's do that here too because when a test starts to fail like that we can look up the bug immediately without going into the test code first.

review: Needs Fixing
Tim Peeters (tpeeters) wrote :

351 === modified file 'src/Ubuntu/Components/ListItems/1.2/SingleControl.qml'
360 + /*! \internal - overriding readonly pressed property due to the buggy pressed property exposure in former AbstractButton */
361 + property bool pressed: __mouseArea.pressed || (control && control.hasOwnProperty("pressed") && control.pressed)

I think we should override the property in Empty.qml instead to avoid problems in apps that have their own components deriving from Empty.

Tim Peeters (tpeeters) wrote :

^maybe for 'hovered' too, to be sure.

Zsombor Egri (zsombi) wrote :

> Why are you not importing the latest versions (not only of Ubuntu.Components,
> but also QtQuick and Ambience) in the performance tests?
>
> 686 === added file 'tests/unit/tst_performance/AbstractButtonGrid.qml'
> 706 +import QtQuick 2.0
> 707 +import Ubuntu.Components 1.1
> 708 +import Ubuntu.Components.Themes.Ambiance 0.1

Copy-paste bug :)
>
> 722 === modified file 'tests/unit/tst_performance/ButtonGrid.qml'
> 728 import QtQuick 2.0
> 729 -import Ubuntu.Components 1.1
> 730 +import Ubuntu.Components 1.3
> 731 import Ubuntu.Components.Themes.Ambiance 0.1

This is the same reason we must get rid of the deprecation warnings... I'll roll this back

Zsombor Egri (zsombi) wrote :

> 351 === modified file
> 'src/Ubuntu/Components/ListItems/1.2/SingleControl.qml'
> 360 + /*! \internal - overriding readonly pressed property due to the
> buggy pressed property exposure in former AbstractButton */
> 361 + property bool pressed: __mouseArea.pressed || (control &&
> control.hasOwnProperty("pressed") && control.pressed)
>
>
> I think we should override the property in Empty.qml instead to avoid problems
> in apps that have their own components deriving from Empty.

Well, the property was there in SingleControl, so why would I move that to Empty?Beside, this should not happen according to the new design, so when you tap on a widget, that should not highlight the component.

Tim Peeters (tpeeters) wrote :

> > 351 === modified file
> > 'src/Ubuntu/Components/ListItems/1.2/SingleControl.qml'
> > 360 + /*! \internal - overriding readonly pressed property due to the
> > buggy pressed property exposure in former AbstractButton */
> > 361 + property bool pressed: __mouseArea.pressed || (control &&
> > control.hasOwnProperty("pressed") && control.pressed)
> >
> >
> > I think we should override the property in Empty.qml instead to avoid
> problems
> > in apps that have their own components deriving from Empty.
>
> Well, the property was there in SingleControl, so why would I move that to
> Empty?Beside, this should not happen according to the new design, so when you
> tap on a widget, that should not highlight the component.

Like SingleControl, custom list items may set the value of pressed. Making it read-only will break those custom list items. Of course we cannot be sure that this is (still) happening without checking the code of the apps.

Tim Peeters (tpeeters) wrote :

Because it is cpp, the change will affect also 0.1-1.2... so it is dangerous.

Tim Peeters (tpeeters) wrote :

Okay, looks good now.

Note that in all import versions we change the RW properties hovered and pressed to read-only. That makes sense (overriding the values of the properties would break the button's functionality), but before it lands we make sure that no apps are setting the properties.

Happroving.

review: Approve
1633. By Zsombor Egri on 2015-08-24

roll back AbstractButton for versions earlier than 1.3 to avoid API break

Christian Dywan (kalikiana) wrote :

Leaving the 1.2 at QML is a good idea that I didn't consider an option. That way we're safe in terms of compatibility. Nice!
Let's see that the tests agree, too.

review: Approve
1634. By Zsombor Egri on 2015-08-24

documentation fix

Tim Peeters (tpeeters) wrote :

there are some failures:

Test Result (2 failures / ±0)
components.AbstractButtonAPI::test_no_pressAndHold_connected_clicks_bug1365471_bug1458028
components.ListItemsEmptyAPI::test_hovered

1635. By Zsombor Egri on 2015-08-25

reverting unit test move for API 1.2

1636. By Zsombor Egri on 2015-08-25

separate 1.3 tests from earlier versions; add 1.3 performance tests

1637. By Zsombor Egri on 2015-08-25

overridden trigger() function support

Tim Peeters (tpeeters) wrote :

222 === modified file 'src/Ubuntu/Components/ListItems/1.2/Empty.qml'
223 --- src/Ubuntu/Components/ListItems/1.2/Empty.qml 2015-04-30 08:32:44 +0000
224 +++ src/Ubuntu/Components/ListItems/1.2/Empty.qml 2015-08-25 11:31:46 +0000
225 @@ -158,6 +158,10 @@
226 */
227 property real __contentsMargins: units.gu(2)
228
229 + // override pressed and hovered as those were declared writable
230 + property bool pressed: __mouseArea.pressed
231 + property bool hovered: __acceptEvents && __mouseArea.containsMouse
232 +

do we still need this? 1.2 now has the old AbstractButton where those properties are already writable.

1638. By Zsombor Egri on 2015-08-25

revert unneeded 1.2 changes

Christian Dywan (kalikiana) wrote :

Nice!

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-08-20 08:10:44 +0000
3+++ components.api 2015-08-25 13:10:33 +0000
4@@ -4,10 +4,10 @@
5 signal pressAndHold()
6 property bool pressed
7 Ubuntu.Components.AbstractButton 1.3: ActionItem
8- property bool hovered
9+ readonly property bool hovered
10 signal clicked()
11 signal pressAndHold()
12- property bool pressed
13+ readonly property bool pressed
14 Ubuntu.Components.Action 1.3 1.0 0.1: QtObject
15 property string description
16 property bool enabled
17
18=== removed file 'src/Ubuntu/Components/1.3/AbstractButton.qml'
19--- src/Ubuntu/Components/1.3/AbstractButton.qml 2015-04-25 08:54:58 +0000
20+++ src/Ubuntu/Components/1.3/AbstractButton.qml 1970-01-01 00:00:00 +0000
21@@ -1,109 +0,0 @@
22-/*
23- * Copyright 2012 Canonical Ltd.
24- *
25- * This program is free software; you can redistribute it and/or modify
26- * it under the terms of the GNU Lesser General Public License as published by
27- * the Free Software Foundation; version 3.
28- *
29- * This program is distributed in the hope that it will be useful,
30- * but WITHOUT ANY WARRANTY; without even the implied warranty of
31- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32- * GNU Lesser General Public License for more details.
33- *
34- * You should have received a copy of the GNU Lesser General Public License
35- * along with this program. If not, see <http://www.gnu.org/licenses/>.
36- */
37-
38-import QtQuick 2.4
39-import Ubuntu.Components 1.3
40-
41-/*!
42- \qmlabstract AbstractButton
43- \inqmlmodule Ubuntu.Components 1.1
44- \ingroup ubuntu
45- \brief The AbstractButton class defines the behavior of the button.
46-
47- This class defines the behavior of the button: it defines the MouseArea
48- and the states.
49- All components deriving from this class support haptic feedback out of the box.
50-*/
51-ActionItem {
52- id: button
53-
54- /*!
55- If an action is specified, the button's clicked signal will trigger the action.
56- Subclasses of AbstractButton can use other properties of action (for example
57- the text and iconName).
58- \qmlproperty Action action
59- */
60-
61- /*!
62- This handler is called when there is a mouse click on the button
63- and the button is not disabled. If \b action is defined,
64- the action will be triggered.
65- */
66- signal clicked()
67-
68- /*!
69- If a button is clicked, its triggered() signal will automatically be called.
70- */
71- onClicked: button.trigger()
72-
73- Keys.onEnterPressed: clicked()
74- Keys.onReturnPressed: clicked()
75-
76- /*!
77- This handler is called when there is a long press.
78- */
79- signal pressAndHold()
80-
81- /*!
82- True if the user presses a mouse button in the button's mouse area.
83- */
84- property bool pressed: mouseArea.pressed
85-
86- /*!
87- True if the mouse cursor hovers over the button's mouse area.
88- */
89- property bool hovered: __acceptEvents && mouseArea.containsMouse
90-
91- /*!
92- \internal
93- Disable or enable signal emition by default.
94- Some classes want to emit the signal by themselves (ListItem.Standard)
95- */
96- property bool __acceptEvents: true
97-
98- /*!
99- \internal
100- To get the properties of the mouse area in subclasses.
101- */
102- property alias __mouseArea: mouseArea
103-
104- activeFocusOnPress: true
105-
106- MouseArea {
107- id: mouseArea
108- anchors.fill: parent
109- // if mouseArea is given a new value, disable defaultMouseArea
110- // as it might occlude the newly assigned mouse area.
111- hoverEnabled: true
112-
113- // invoke Haptics singleton earlier than we press the button,
114- // so we give some time for the singleton to sync settings with the service
115- property bool hapticsEnabled: Haptics.enabled
116-
117- onClicked: {
118- if (button.__acceptEvents) {
119- // FIXME (Vivid) call this in the style rather than from AbstractButton
120- Haptics.play();
121- button.clicked()
122- }
123- }
124- onPressAndHold: {
125- if (button.__acceptEvents) {
126- button.pressAndHold()
127- }
128- }
129- }
130-}
131
132=== modified file 'src/Ubuntu/Components/1.3/Button.qml'
133--- src/Ubuntu/Components/1.3/Button.qml 2015-05-26 15:05:46 +0000
134+++ src/Ubuntu/Components/1.3/Button.qml 2015-08-25 13:10:33 +0000
135@@ -105,7 +105,7 @@
136 /*!
137 The font used for the button's text.
138 */
139- property font font: __styleInstance ? __styleInstance.defaultFont : Qt.font({family: "Ubuntu", pixelSize: FontUtils.sizeToPixels("medium")})
140+ property font font: __styleInstance.defaultFont
141
142 /*!
143 The position of the icon relative to the text. Options
144
145=== modified file 'src/Ubuntu/Components/1.3/ComboButton.qml'
146--- src/Ubuntu/Components/1.3/ComboButton.qml 2015-05-21 10:50:35 +0000
147+++ src/Ubuntu/Components/1.3/ComboButton.qml 2015-08-25 13:10:33 +0000
148@@ -15,6 +15,7 @@
149 */
150
151 import QtQuick 2.4
152+import Ubuntu.Components 1.3
153 import Ubuntu.Components.Popups 1.3
154
155 /*!
156
157=== modified file 'src/Ubuntu/Components/1.3/TextField.qml'
158--- src/Ubuntu/Components/1.3/TextField.qml 2015-08-18 15:51:43 +0000
159+++ src/Ubuntu/Components/1.3/TextField.qml 2015-08-25 13:10:33 +0000
160@@ -896,7 +896,7 @@
161 }
162 }
163
164- AbstractButton {
165+ Ubuntu.AbstractButton {
166 id: clearButton
167 objectName: "clear_button"
168 activeFocusOnPress: false
169
170=== modified file 'src/Ubuntu/Components/ComponentModule.pro'
171--- src/Ubuntu/Components/ComponentModule.pro 2015-08-19 08:57:18 +0000
172+++ src/Ubuntu/Components/ComponentModule.pro 2015-08-25 13:10:33 +0000
173@@ -80,8 +80,7 @@
174 1.2/UbuntuNumberAnimation.qml
175
176 #1.3
177-QML_FILES += 1.3/AbstractButton.qml \
178- 1.3/ActionBar.qml \
179+QML_FILES += 1.3/ActionBar.qml \
180 1.3/ActionList.qml \
181 1.3/ActivityIndicator.qml \
182 1.3/AdaptivePageLayout.qml \
183
184=== modified file 'src/Ubuntu/Components/ListItems/1.3/SingleControl.qml'
185--- src/Ubuntu/Components/ListItems/1.3/SingleControl.qml 2015-04-29 07:21:29 +0000
186+++ src/Ubuntu/Components/ListItems/1.3/SingleControl.qml 2015-08-25 13:10:33 +0000
187@@ -54,7 +54,8 @@
188
189 /*! \internal */
190 onClicked: if (control && control.enabled && control.hasOwnProperty("clicked")) control.clicked()
191- pressed: __mouseArea.pressed || (control && control.hasOwnProperty("pressed") && control.pressed)
192+ /*! \internal */
193+ property bool pressed: __mouseArea.pressed || (control && control.hasOwnProperty("pressed") && control.pressed)
194 /*! \internal */
195 onPressedChanged: if (control && control.enabled && control.hasOwnProperty("pressed")) control.pressed = singleControlListItem.pressed
196
197
198=== modified file 'src/Ubuntu/Components/plugin/plugin.cpp'
199--- src/Ubuntu/Components/plugin/plugin.cpp 2015-08-19 08:44:45 +0000
200+++ src/Ubuntu/Components/plugin/plugin.cpp 2015-08-25 13:10:33 +0000
201@@ -64,6 +64,7 @@
202 #include "ucnamespace.h"
203 #include "ucactionitem.h"
204 #include "uchaptics.h"
205+#include "ucabstractbutton.h"
206
207 #include <sys/types.h>
208 #include <unistd.h>
209@@ -232,6 +233,7 @@
210 qmlRegisterType<UCUbuntuShape, 2>(uri, 1, 3, "UbuntuShape");
211 qmlRegisterType<UCProportionalShape>(uri, 1, 3, "ProportionalShape");
212 qmlRegisterType<LiveTimer>(uri, 1, 3, "LiveTimer");
213+ qmlRegisterType<UCAbstractButton>(uri, 1, 3, "AbstractButton");
214 }
215
216 void UbuntuComponentsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
217
218=== modified file 'src/Ubuntu/Components/plugin/plugin.pri'
219--- src/Ubuntu/Components/plugin/plugin.pri 2015-08-20 11:35:51 +0000
220+++ src/Ubuntu/Components/plugin/plugin.pri 2015-08-25 13:10:33 +0000
221@@ -82,7 +82,8 @@
222 $$PWD/livetimer_p.h \
223 $$PWD/timeutils_p.h \
224 $$PWD/ucactionitem.h \
225- $$PWD/uchaptics.h
226+ $$PWD/uchaptics.h \
227+ $$PWD/ucabstractbutton.h
228
229 SOURCES += $$PWD/plugin.cpp \
230 $$PWD/uctheme.cpp \
231@@ -136,7 +137,8 @@
232 $$PWD/livetimer.cpp \
233 $$PWD/livetimer_p.cpp \
234 $$PWD/ucactionitem.cpp \
235- $$PWD/uchaptics.cpp
236+ $$PWD/uchaptics.cpp \
237+ $$PWD/ucabstractbutton.cpp
238
239 # adapters
240 SOURCES += $$PWD/adapters/alarmsadapter_organizer.cpp
241
242=== added file 'src/Ubuntu/Components/plugin/ucabstractbutton.cpp'
243--- src/Ubuntu/Components/plugin/ucabstractbutton.cpp 1970-01-01 00:00:00 +0000
244+++ src/Ubuntu/Components/plugin/ucabstractbutton.cpp 2015-08-25 13:10:33 +0000
245@@ -0,0 +1,156 @@
246+/*
247+ * Copyright 2015 Canonical Ltd.
248+ *
249+ * This program is free software; you can redistribute it and/or modify
250+ * it under the terms of the GNU Lesser General Public License as published by
251+ * the Free Software Foundation; version 3.
252+ *
253+ * This program is distributed in the hope that it will be useful,
254+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
255+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
256+ * GNU Lesser General Public License for more details.
257+ *
258+ * You should have received a copy of the GNU Lesser General Public License
259+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
260+ */
261+
262+#include "ucabstractbutton.h"
263+#include "uchaptics.h"
264+#include <QtQuick/private/qquickitem_p.h>
265+#include <QtQuick/private/qquickmousearea_p.h>
266+#include <QtQml/private/qqmlglobal_p.h>
267+
268+/*!
269+ \qmltype AbstractButton
270+ \instantiates UCAbstractButton
271+ \inqmlmodule Ubuntu.Components 1.1
272+ \ingroup ubuntu
273+ \brief The AbstractButton class defines the behavior of the button.
274+
275+ This class defines the behavior of the button. All components deriving from
276+ this class support haptic feedback out of the box.
277+
278+ If an action is specified, the button's clicked signal will trigger the action.
279+ Subclasses of AbstractButton can use other properties of action (for example
280+ the text and iconName).
281+*/
282+
283+/*!
284+ *
285+ * \qmlsignal AbstractButton::clicked()
286+ * This handler is called when there is a mouse click on the button and the button
287+ * is not disabled. If \l {ActionItem::action}{action} is defined, the action will be triggered.
288+ */
289+
290+/*!
291+ *
292+ * \qmlsignal AbstractButton::pressAndHold()
293+ * This handler is called when there is a long press.
294+ */
295+
296+UCAbstractButton::UCAbstractButton(QQuickItem *parent)
297+ : UCActionItem(parent)
298+ , m_mouseArea(new QQuickMouseArea)
299+ , m_acceptEvents(true)
300+{
301+ setActiveFocusOnPress(true);
302+}
303+
304+bool UCAbstractButton::isPressAndHoldConnected()
305+{
306+ static QMetaMethod method = QMetaMethod::fromSignal(&UCAbstractButton::pressAndHold);
307+ static int signalIdx = QMetaObjectPrivate::signalIndex(method);
308+ return QObjectPrivate::get(this)->isSignalConnected(signalIdx);
309+}
310+
311+void UCAbstractButton::classBegin()
312+{
313+ UCActionItem::classBegin();
314+
315+ // make sure we have the haptics set up!
316+ HapticsProxy::instance().initialize();
317+
318+ // set up mouse area
319+ QQml_setParent_noEvent(m_mouseArea, this);
320+ m_mouseArea->setParentItem(this);
321+ QQuickAnchors *anchors = QQuickItemPrivate::get(m_mouseArea)->anchors();
322+ anchors->setFill(this);
323+ m_mouseArea->setHoverEnabled(true);
324+}
325+
326+void UCAbstractButton::componentComplete()
327+{
328+ UCActionItem::componentComplete();
329+ // connect to the right slot, using macros so we get the proper slot
330+ connect(this, SIGNAL(clicked()), this, SLOT(trigger()));
331+
332+ // bind mouse area
333+ connect(m_mouseArea, &QQuickMouseArea::pressedChanged, this, &UCAbstractButton::pressedChanged);
334+ connect(m_mouseArea, &QQuickMouseArea::hoveredChanged, this, &UCAbstractButton::hoveredChanged);
335+ connect(m_mouseArea, SIGNAL(clicked(QQuickMouseEvent*)), this, SLOT(_q_mouseAreaClicked()));
336+ if (isPressAndHoldConnected()) {
337+ connect(m_mouseArea, SIGNAL(pressAndHold(QQuickMouseEvent*)), this, SLOT(_q_mouseAreaPressAndHold()));
338+ }
339+}
340+
341+// handle mouseClicked with Haptics
342+void UCAbstractButton::_q_mouseAreaClicked()
343+{
344+ // required by the deprecated ListItem module
345+ if (!m_acceptEvents) {
346+ return;
347+ }
348+ // play haptics
349+ HapticsProxy::instance().play(QVariant());
350+ Q_EMIT clicked();
351+}
352+
353+// handle pressAndHold
354+void UCAbstractButton::_q_mouseAreaPressAndHold()
355+{
356+ // required by the deprecated ListItem module
357+ if (!m_acceptEvents) {
358+ return;
359+ }
360+ Q_EMIT pressAndHold();
361+}
362+
363+// emit clicked when Enter/Return is pressed
364+void UCAbstractButton::keyPressEvent(QKeyEvent *event)
365+{
366+ UCActionItem::keyPressEvent(event);
367+
368+ switch (event->key()) {
369+ case Qt::Key_Enter:
370+ case Qt::Key_Return:
371+ // FIXME: space may also come here, however that depends on the button type
372+ // (i.e default Dialog btn) so we may need to add that to Button
373+ {
374+ Q_EMIT clicked();
375+ break;
376+ }
377+ }
378+}
379+
380+/*!
381+ * \qmlproperty bool AbstractButton::pressed
382+ * True if the user presses a mouse button in the button's mouse area.
383+ */
384+bool UCAbstractButton::pressed() const
385+{
386+ return m_mouseArea ? m_mouseArea->pressed() : false;
387+}
388+
389+/*!
390+ * \qmlproperty bool AbstractButton::hovered
391+ * True if the mouse cursor hovers over the button's mouse area.
392+ */
393+bool UCAbstractButton::hovered() const
394+{
395+ return m_mouseArea ? m_mouseArea->hovered() : false;
396+}
397+
398+QQuickMouseArea *UCAbstractButton::privateMouseArea() const
399+{
400+ return m_mouseArea;
401+}
402
403=== added file 'src/Ubuntu/Components/plugin/ucabstractbutton.h'
404--- src/Ubuntu/Components/plugin/ucabstractbutton.h 1970-01-01 00:00:00 +0000
405+++ src/Ubuntu/Components/plugin/ucabstractbutton.h 2015-08-25 13:10:33 +0000
406@@ -0,0 +1,64 @@
407+/*
408+ * Copyright 2015 Canonical Ltd.
409+ *
410+ * This program is free software; you can redistribute it and/or modify
411+ * it under the terms of the GNU Lesser General Public License as published by
412+ * the Free Software Foundation; version 3.
413+ *
414+ * This program is distributed in the hope that it will be useful,
415+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
416+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
417+ * GNU Lesser General Public License for more details.
418+ *
419+ * You should have received a copy of the GNU Lesser General Public License
420+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
421+ */
422+
423+#ifndef UCABSTRACTBUTTON_H
424+#define UCABSTRACTBUTTON_H
425+
426+#include "ucactionitem.h"
427+
428+class QQuickMouseArea;
429+class UCAbstractButton : public UCActionItem
430+{
431+ Q_OBJECT
432+ Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged)
433+ Q_PROPERTY(bool hovered READ hovered NOTIFY hoveredChanged)
434+
435+ // internal, declared to support the deprecated ListItem module
436+ Q_PROPERTY(bool __acceptEvents MEMBER m_acceptEvents)
437+ Q_PROPERTY(QQuickMouseArea *__mouseArea READ privateMouseArea CONSTANT)
438+public:
439+ explicit UCAbstractButton(QQuickItem *parent = 0);
440+
441+ bool pressed() const;
442+ bool hovered() const;
443+
444+ bool privateAcceptEvents() const;
445+ void setPrivateAcceptEvents(bool accept);
446+ QQuickMouseArea *privateMouseArea() const;
447+
448+protected:
449+ void classBegin();
450+ void componentComplete();
451+ void keyPressEvent(QKeyEvent *key);
452+
453+Q_SIGNALS:
454+ void pressedChanged();
455+ void hoveredChanged();
456+ void clicked();
457+ void pressAndHold();
458+
459+protected Q_SLOTS:
460+ void _q_mouseAreaClicked();
461+ void _q_mouseAreaPressAndHold();
462+
463+protected:
464+ QQuickMouseArea *m_mouseArea;
465+ bool m_acceptEvents:1;
466+
467+ bool isPressAndHoldConnected();
468+};
469+
470+#endif // UCABSTRACTBUTTON_H
471
472=== modified file 'src/Ubuntu/Components/plugin/ucaction.cpp'
473--- src/Ubuntu/Components/plugin/ucaction.cpp 2015-08-18 15:51:43 +0000
474+++ src/Ubuntu/Components/plugin/ucaction.cpp 2015-08-25 13:10:33 +0000
475@@ -301,7 +301,8 @@
476 return false;
477 }
478
479- trigger();
480+ // do not call trigger() directly but invoke, as it may get overridden in QML
481+ metaObject()->invokeMethod(this, "trigger");
482 return true;
483 }
484
485
486=== modified file 'src/Ubuntu/Components/plugin/ucactionitem.cpp'
487--- src/Ubuntu/Components/plugin/ucactionitem.cpp 2015-08-19 06:56:56 +0000
488+++ src/Ubuntu/Components/plugin/ucactionitem.cpp 2015-08-25 13:10:33 +0000
489@@ -44,6 +44,17 @@
490 connect(this, &UCActionItem::enabledChanged, this, &UCActionItem::_q_enabledChanged);
491 }
492
493+void UCActionItem::componentComplete()
494+{
495+ UCStyledItemBase::componentComplete();
496+ // make sure we connect to the right signals, so we detach and re-attach actions
497+ // to make sure the SLOT macro picks up the custom trigger() slot
498+ if (m_action) {
499+ attachAction(false);
500+ attachAction(true);
501+ }
502+}
503+
504 void UCActionItem::_q_visibleChanged()
505 {
506 m_flags |= CustomVisible;
507@@ -96,8 +107,8 @@
508 void UCActionItem::attachAction(bool attach)
509 {
510 if (attach) {
511- connect(this, &UCActionItem::triggered,
512- m_action, &UCAction::triggered, Qt::DirectConnection);
513+ connect(this, SIGNAL(triggered(QVariant)),
514+ m_action, SLOT(trigger(QVariant)), Qt::DirectConnection);
515 connect(m_action, &UCAction::visibleChanged,
516 this, &UCActionItem::_q_updateVisible, Qt::DirectConnection);
517 connect(m_action, &UCAction::enabledChanged,
518@@ -115,8 +126,8 @@
519 this, &UCActionItem::iconNameChanged, Qt::DirectConnection);
520 }
521 } else {
522- disconnect(this, &UCActionItem::triggered,
523- m_action, &UCAction::triggered);
524+ disconnect(this, SIGNAL(triggered(QVariant)),
525+ m_action, SLOT(trigger(QVariant)));
526 disconnect(m_action, &UCAction::visibleChanged,
527 this, &UCActionItem::_q_updateVisible);
528 disconnect(m_action, &UCAction::enabledChanged,
529
530=== modified file 'src/Ubuntu/Components/plugin/ucactionitem.h'
531--- src/Ubuntu/Components/plugin/ucactionitem.h 2015-08-19 06:55:11 +0000
532+++ src/Ubuntu/Components/plugin/ucactionitem.h 2015-08-25 13:10:33 +0000
533@@ -70,6 +70,8 @@
534 UCAction *m_action;
535 quint8 m_flags;
536
537+ void componentComplete();
538+
539 void updateProperties();
540 void attachAction(bool attach);
541 };
542
543=== modified file 'src/Ubuntu/Components/qmldir'
544--- src/Ubuntu/Components/qmldir 2015-08-19 08:44:45 +0000
545+++ src/Ubuntu/Components/qmldir 2015-08-25 13:10:33 +0000
546@@ -115,7 +115,6 @@
547 TabBar 1.3 1.3/TabBar.qml
548 Tabs 1.3 1.3/Tabs.qml
549 Label 1.3 1.3/Label.qml
550-AbstractButton 1.3 1.3/AbstractButton.qml
551 ActivityIndicator 1.3 1.3/ActivityIndicator.qml
552 ProgressBar 1.3 1.3/ProgressBar.qml
553 TextField 1.3 1.3/TextField.qml
554
555=== modified file 'tests/unit/tst_components/tst_action.qml'
556--- tests/unit/tst_components/tst_action.qml 2015-07-09 17:55:03 +0000
557+++ tests/unit/tst_components/tst_action.qml 2015-08-25 13:10:33 +0000
558@@ -34,6 +34,11 @@
559 return false;
560 }
561
562+ function cleanup() {
563+ triggeredSignalSpy.target = action;
564+ triggeredSignalSpy.clear();
565+ }
566+
567 function initTestCase() {
568 compare(action.text, "", "text is empty string set by default")
569 compare(action.iconSource, "", "iconSource is empty string by default")
570@@ -132,6 +137,12 @@
571 verify(!data.inactive.active, "Context deactivation error");
572 }
573
574+ function test_overloaded_action_trigger() {
575+ triggeredSignalSpy.target = suppressTrigger;
576+ suppressTrigger.trigger();
577+ compare(triggeredSignalSpy.count, 0, "Overloaded trigger should not trigger action");
578+ }
579+
580 Action {
581 id: action
582 }
583@@ -185,4 +196,9 @@
584 id: context2
585 }
586
587+ Action {
588+ id: suppressTrigger
589+ function trigger() {}
590+ }
591+
592 }
593
594=== added file 'tests/unit/tst_performance/AbstractButton13Grid.qml'
595--- tests/unit/tst_performance/AbstractButton13Grid.qml 1970-01-01 00:00:00 +0000
596+++ tests/unit/tst_performance/AbstractButton13Grid.qml 2015-08-25 13:10:33 +0000
597@@ -0,0 +1,30 @@
598+/*
599+ * Copyright 2015 Canonical Ltd.
600+ *
601+ * This program is free software; you can redistribute it and/or modify
602+ * it under the terms of the GNU Lesser General Public License as published by
603+ * the Free Software Foundation; version 3.
604+ *
605+ * This program is distributed in the hope that it will be useful,
606+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
607+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
608+ * GNU Lesser General Public License for more details.
609+ *
610+ * You should have received a copy of the GNU Lesser General Public License
611+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
612+ */
613+
614+import QtQuick 2.0
615+import Ubuntu.Components 1.3
616+
617+Grid {
618+ width: 800
619+ height: 600
620+ rows: 16
621+ columns: 16
622+ Repeater {
623+ model: 16*16
624+ AbstractButton {
625+ }
626+ }
627+}
628
629=== added file 'tests/unit/tst_performance/AbstractButtonGrid.qml'
630--- tests/unit/tst_performance/AbstractButtonGrid.qml 1970-01-01 00:00:00 +0000
631+++ tests/unit/tst_performance/AbstractButtonGrid.qml 2015-08-25 13:10:33 +0000
632@@ -0,0 +1,30 @@
633+/*
634+ * Copyright 2015 Canonical Ltd.
635+ *
636+ * This program is free software; you can redistribute it and/or modify
637+ * it under the terms of the GNU Lesser General Public License as published by
638+ * the Free Software Foundation; version 3.
639+ *
640+ * This program is distributed in the hope that it will be useful,
641+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
642+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
643+ * GNU Lesser General Public License for more details.
644+ *
645+ * You should have received a copy of the GNU Lesser General Public License
646+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
647+ */
648+
649+import QtQuick 2.0
650+import Ubuntu.Components 1.1
651+
652+Grid {
653+ width: 800
654+ height: 600
655+ rows: 16
656+ columns: 16
657+ Repeater {
658+ model: 16*16
659+ AbstractButton {
660+ }
661+ }
662+}
663
664=== modified file 'tests/unit/tst_performance/tst_performance.cpp'
665--- tests/unit/tst_performance/tst_performance.cpp 2015-04-14 07:41:52 +0000
666+++ tests/unit/tst_performance/tst_performance.cpp 2015-08-25 13:10:33 +0000
667@@ -102,6 +102,8 @@
668 QTest::addColumn<QString>("document");
669 QTest::addColumn<QUrl>("theme");
670
671+ QTest::newRow("AbstractButton 1.2") << "AbstractButtonGrid.qml" << QUrl();
672+ QTest::newRow("AbstractButton 1.3") << "AbstractButton13Grid.qml" << QUrl();
673 QTest::newRow("grid with Rectangle") << "RectangleGrid.qml" << QUrl();
674 QTest::newRow("grid with Text") << "TextGrid.qml" << QUrl();
675 QTest::newRow("grid with Label") << "LabelGrid.qml" << QUrl();
676
677=== modified file 'tests/unit/tst_performance/tst_performance.pro'
678--- tests/unit/tst_performance/tst_performance.pro 2015-04-01 08:33:53 +0000
679+++ tests/unit/tst_performance/tst_performance.pro 2015-08-25 13:10:33 +0000
680@@ -30,4 +30,6 @@
681 Styling.qml \
682 PaletteConfigurationOneColor.qml \
683 PaletteConfigurationAllColors.qml \
684- StyledItemNewTheming.qml
685+ StyledItemNewTheming.qml \
686+ AbstractButtonGrid.qml \
687+ AbstractButton13Grid.qml
688
689=== added file 'tests/unit_x11/tst_components/tst_abstractbutton13.qml'
690--- tests/unit_x11/tst_components/tst_abstractbutton13.qml 1970-01-01 00:00:00 +0000
691+++ tests/unit_x11/tst_components/tst_abstractbutton13.qml 2015-08-25 13:10:33 +0000
692@@ -0,0 +1,115 @@
693+/*
694+ * Copyright 2012 Canonical Ltd.
695+ *
696+ * This program is free software; you can redistribute it and/or modify
697+ * it under the terms of the GNU Lesser General Public License as published by
698+ * the Free Software Foundation; version 3.
699+ *
700+ * This program is distributed in the hope that it will be useful,
701+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
702+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
703+ * GNU Lesser General Public License for more details.
704+ *
705+ * You should have received a copy of the GNU Lesser General Public License
706+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
707+ */
708+
709+import QtQuick 2.0
710+import QtTest 1.0
711+import Ubuntu.Test 1.0
712+import Ubuntu.Components 1.3
713+
714+Item {
715+ width: units.gu(40)
716+ height: units.gu(71)
717+
718+ Column {
719+ AbstractButton {
720+ id: absButton
721+ width: units.gu(10)
722+ height: units.gu(10)
723+ }
724+ AbstractButton {
725+ id: absLongTap
726+ width: units.gu(10)
727+ height: width
728+ onPressAndHold: {}
729+ }
730+ AbstractButton {
731+ id: suppressTrigger
732+ width: units.gu(10)
733+ height: width
734+ function trigger() {}
735+ }
736+ }
737+
738+ Action {
739+ id: action1
740+ property int triggerCount: 0
741+ onTriggered: triggerCount++
742+ }
743+
744+ SignalSpy {
745+ id: signalSpy
746+ target: absButton
747+ signalName: "clicked"
748+ }
749+
750+ SignalSpy {
751+ id: pressAndHoldSpy
752+ target: absLongTap
753+ signalName: "pressAndHold"
754+ }
755+
756+ SignalSpy {
757+ id: triggeredSpy
758+ signalName: "triggered"
759+ }
760+
761+ UbuntuTestCase {
762+ name: "AbstractButtonAPI"
763+ when: windowShown
764+
765+ function cleanup() {
766+ signalSpy.clear();
767+ triggeredSpy.clear();
768+ }
769+
770+ function test_action() {
771+ compare(absButton.action, null,"Action is null by default")
772+ absButton.action = action1
773+ compare(absButton.action, action1, "Action can be set")
774+ var numTriggers = action1.triggerCount
775+ absButton.clicked()
776+ compare(action1.triggerCount, numTriggers+1, "Button clicked triggers action")
777+ absButton.action = null
778+ }
779+
780+ function test_custom_trigger_function() {
781+ suppressTrigger.action = action1;
782+ triggeredSpy.target = action1;
783+ mouseClick(suppressTrigger, centerOf(suppressTrigger).x, centerOf(suppressTrigger).y);
784+ compare(triggeredSpy.count, 0, "Trigger should be overridden");
785+ }
786+
787+ // fixing bugs 1365471 and 1458028
788+ function test_no_pressAndHold_connected_clicks_bug1365471_bug1458028() {
789+ signalSpy.target = absButton;
790+ mouseLongPress(absButton, centerOf(absButton).x, centerOf(absButton).y);
791+ mouseRelease(absButton, centerOf(absButton).x, centerOf(absButton).y);
792+ signalSpy.wait();
793+ }
794+
795+ // fixing bugs 1365471 and 1458028
796+ function test_pressAndHold_connected_suppresses_clicks_bug1365471_bug1458028() {
797+ function testFunc() {}
798+ signalSpy.target = absButton;
799+ absLongTap.pressAndHold.connect(testFunc);
800+ mouseLongPress(absLongTap, centerOf(absLongTap).x, centerOf(absLongTap).y);
801+ absLongTap.pressAndHold.disconnect(testFunc);
802+ pressAndHoldSpy.wait();
803+ mouseRelease(absLongTap, centerOf(absLongTap).x, centerOf(absLongTap).y);
804+ compare(signalSpy.count, 0, "click() must be suppressed when pressAndHold handler is implemented");
805+ }
806+ }
807+}

Subscribers

People subscribed via source and target branches