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

Proposed by Zsombor Egri
Status: Merged
Approved by: Zsombor Egri
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
Cris Dywan Approve
Tim Peeters Approve
Review via email: mp+268442@code.launchpad.net

Commit message

AbstractButton to C++.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
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

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

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

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

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

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

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

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

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

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
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
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1633. By Zsombor Egri

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

Revision history for this message
Cris 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
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1634. By Zsombor Egri

documentation fix

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

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

reverting unit test move for API 1.2

1636. By Zsombor Egri

separate 1.3 tests from earlier versions; add 1.3 performance tests

1637. By Zsombor Egri

overridden trigger() function support

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
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

revert unneeded 1.2 changes

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

Nice!

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

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