Merge lp:~mzanetti/autopilot-qt/qt5support into lp:autopilot-qt

Proposed by Michael Zanetti
Status: Merged
Approved by: Martin Mrazik
Approved revision: 34
Merged at revision: 24
Proposed branch: lp:~mzanetti/autopilot-qt/qt5support
Merge into: lp:autopilot-qt
Diff against target: 391 lines (+220/-12)
12 files modified
debian/autopilot-qt.install (+1/-0)
debian/autopilot-qt5.install (+1/-0)
debian/changelog (+5/-0)
debian/compat (+1/-0)
debian/control (+23/-0)
debian/copyright (+42/-0)
debian/lintian-overrides (+1/-0)
debian/rules (+34/-0)
lib/dbus_object.cpp (+21/-1)
lib/introspection.cpp (+38/-8)
lib/lib.pro (+9/-1)
lib/qtnode.cpp (+44/-2)
To merge this branch: bzr merge lp:~mzanetti/autopilot-qt/qt5support
Reviewer Review Type Date Requested Status
Sergio Schvezov Approve
jenkins (community) continuous-integration Approve
Thomi Richards (community) Approve
Review via email: mp+128475@code.launchpad.net

Commit message

This adds Qt5 support for autopilot-qt. UI tests are working for qmlscene powered QtQuick 2.0 apps.

Description of the change

This adds Qt5 support for autopilot-qt. UI tests are working for qmlscene powered QtQuick 2.0 apps.

I would suggest to have two separate packages for Qt4 and Qt5 to avoid having dependencies to both with one package.

To post a comment you must log in.
Revision history for this message
jenkins (martin-mrazik+qa) wrote :
review: Approve (continuous-integration)
Revision history for this message
Martin Mrazik (mrazik) wrote :

So the idea here is to have 1 codebase and two packaging branches. Depending on which packaging branch is used the result is either autopilot-qt (for qt4) or autopilot-qt5 (for qt5). The qt5 packaging branch is here:
lp:~mzanetti/autopilot-qt/packaging-qt5

Sergio: could you have a look on the packaging bits?

Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

Hi,

A few comments:

First, I'm not sure that this is correct:

150 + target.path = /opt/qt5/lib

Ubuntu packages typically don't install to /opt - I guess you're doing this because the qt5 packages install there? If that's the case then we should convince whoever packages qt5 to fix their packages sooner rather than later, so we can be conformant to Ubuntu packaging policy.

Second, regarding the multiple packaging branches, why not have one packaging branch that builds two binary packages? I'd suggest that having two packaging branches is going to cause trouble in the future. In fact, I recommend that we keep the packaging information in the source tree (I've come to the conclusion that separate packaging branches are more trouble than they're worth). The main advantage of this is that it's still only one step to build *all* the binary packages from the source branch - it also means we only need to maintain one change-log.

Finally, I'm not a huge fan of this:

#if QT_VERSION >= 0x050000

... but I can see that it's a necessary evil. I wonder if it wouldn't be better to do something like:

#if QT5_SUPPORT

and define that ourselves? Not sure on this one - thought I'd mention it anyway.

I'm not putting "Needs Fixing" on this MP, since I'm now officially washing my hands of responsibility for this project! Welcome aboard Michael, in your first week you're lumped with maintaining a project - good luck!

:P

lp:~mzanetti/autopilot-qt/qt5support updated
29. By Michael Zanetti

add missing properties of type LongLong and Double.

Really needed for QML UI testing as some of the most important properties are of type double (x, y, opacity, scale etc.)

Revision history for this message
jenkins (martin-mrazik+qa) wrote :
review: Approve (continuous-integration)
Revision history for this message
Sergio Schvezov (sergiusens) wrote :

> Hi,
>
> A few comments:
>
> First, I'm not sure that this is correct:
>
> 150 + target.path = /opt/qt5/lib
>
> Ubuntu packages typically don't install to /opt - I guess you're doing this
> because the qt5 packages install there? If that's the case then we should
> convince whoever packages qt5 to fix their packages sooner rather than later,
> so we can be conformant to Ubuntu packaging policy.

This is ppa:canonical-qt5-edgers/qt5-beta1 and sadly it's set to /opt/ and these are unofficial packages until the real ones land for R.

> Second, regarding the multiple packaging branches, why not have one packaging
> branch that builds two binary packages? I'd suggest that having two packaging
> branches is going to cause trouble in the future. In fact, I recommend that we
> keep the packaging information in the source tree (I've come to the conclusion
> that separate packaging branches are more trouble than they're worth). The
> main advantage of this is that it's still only one step to build *all* the
> binary packages from the source branch - it also means we only need to
> maintain one change-log.

+1

It's nice to see that more people are getting convinced by this :-)
I can help out.

> Finally, I'm not a huge fan of this:
>
> #if QT_VERSION >= 0x050000
>
> ... but I can see that it's a necessary evil. I wonder if it wouldn't be
> better to do something like:
>
> #if QT5_SUPPORT
>
> and define that ourselves? Not sure on this one - thought I'd mention it
> anyway.

That looks cleaner to me. But no strong opinion and not sure about the 'Qt' way.

Revision history for this message
Sergio Schvezov (sergiusens) wrote :

There's no MR for the packaging stuff; that would ideally be solved if thomi's comment is addressed.

The debian/substvars file is usually generated and modified dynamically by debian/rules targets, in which case it must be removed by the clean target.

Each debhelper command will record when it's successfully run in
debian/package.debhelper.log. (Which dh_clean deletes.) So dh can tell
which commands have already been run, for which packages, and skip
running those commands again.

That mean remove the substvars and debhelper.log from revision control

--

This is more of a question, is autopilot-qt1.dirs needed? I thought that was more for empty directories
dirs

This file specifies any directories which we need but which are not created by the normal installation procedure (make install DESTDIR=... invoked by dh_auto_install). This generally means there is a problem with the Makefile.

Files listed in an install file don't need their directories created first. See Section 5.11, “install”.

It is best to try to run the installation first and only use this if you run into trouble. There is no preceding slash on the directory names listed in the dirs file.

--

debian/changelog

Just make it one version since it is basically the first and remove the '-' (dash)

autopilot-qt5 (0.1) quantal; urgency=low

  * added missing build dependency to mesa

 -- Michael Zanetti <email address hidden> Mon, 08 Oct 2012 16:58:28 +0200

autopilot-qt5 (0.1-0) quantal; urgency=low

  * Initial release, based on autopilot-qt

 -- Michael Zanetti <email address hidden> Mon, 08 Oct 2012 14:23:32 +0200

--

debian/copyright

Copyright: 2012 <email address hidden>
and the other entry

Should be
Copyright: 2012 Canonical Ltd.

--

delete debian/docs

--

debian/control

I don't think I am the maintainer of this :-)
make sure you are depending on the latest version of debhelper (I think it's 9.0.0)

review: Needs Fixing (packaging)
lp:~mzanetti/autopilot-qt/qt5support updated
30. By Michael Zanetti

replace Qt version check macros with self defined, cleaner one

31. By Michael Zanetti

added packaging files for Qt4 and Qt5 based libraries

Revision history for this message
jenkins (martin-mrazik+qa) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
jenkins (martin-mrazik+qa) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
jenkins (martin-mrazik+qa) wrote :
review: Approve (continuous-integration)
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) :
review: Approve
Revision history for this message
Sergio Schvezov (sergiusens) wrote :

> --
>
> delete debian/docs

I think you missed this comment.

110 +autopilot-qt binary: non-dev-pkg-with-shlib-symlink

Add a new line at EOF.

What follows is just a question, is the symlink needed and can it be removed from the qmake stuff?

22 + -- Michael Zanetti <email address hidden> Mon, 08 Oct 2012 14:23:32 +0200

This is not important, but is that the email you wanted? I don't think there is a problem with that though, just a question.

review: Needs Fixing (packaging)
lp:~mzanetti/autopilot-qt/qt5support updated
32. By Michael Zanetti

removed unneeded docs file from packaging

33. By Michael Zanetti

fix lintian file EOF

34. By Michael Zanetti

fixed email address

Revision history for this message
jenkins (martin-mrazik+qa) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

Ok... Should be fine now. About the symlink: It probably could go as well as its not really needed, but given we don't have a -dev package for this, it could be useful at some point.

Revision history for this message
Sergio Schvezov (sergiusens) wrote :

Just for the books

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'debian'
2=== added file 'debian/autopilot-qt.install'
3--- debian/autopilot-qt.install 1970-01-01 00:00:00 +0000
4+++ debian/autopilot-qt.install 2012-10-10 07:46:20 +0000
5@@ -0,0 +1,1 @@
6+usr/lib/lib*.so.*
7
8=== added file 'debian/autopilot-qt5.install'
9--- debian/autopilot-qt5.install 1970-01-01 00:00:00 +0000
10+++ debian/autopilot-qt5.install 2012-10-10 07:46:20 +0000
11@@ -0,0 +1,1 @@
12+opt/qt5/lib/lib*.so.*
13
14=== added file 'debian/changelog'
15--- debian/changelog 1970-01-01 00:00:00 +0000
16+++ debian/changelog 2012-10-10 07:46:20 +0000
17@@ -0,0 +1,5 @@
18+autopilot-qt (0.1) quantal; urgency=low
19+
20+ * Initial release
21+
22+ -- Michael Zanetti <michael.zanetti@canonical.com> Mon, 08 Oct 2012 14:23:32 +0200
23
24=== added file 'debian/compat'
25--- debian/compat 1970-01-01 00:00:00 +0000
26+++ debian/compat 2012-10-10 07:46:20 +0000
27@@ -0,0 +1,1 @@
28+8
29
30=== added file 'debian/control'
31--- debian/control 1970-01-01 00:00:00 +0000
32+++ debian/control 2012-10-10 07:46:20 +0000
33@@ -0,0 +1,23 @@
34+Source: autopilot-qt
35+Priority: extra
36+Maintainer: Michael Zanetti <michael.zanetti@canonical.com>
37+Build-Depends: debhelper (>= 8.0.0), libindicate-qt-dev, pkg-config, qt4-qmake, libqt4-dev, qtbase, qtdeclarative, libxpathselect-dev, mesa-common-dev, libgl1-mesa-dev
38+Standards-Version: 3.9.3
39+Section: libs
40+Homepage: https://launchpad.net/autopilot-qt
41+
42+Package: autopilot-qt
43+Section: libs
44+Architecture: any
45+Depends: ${shlibs:Depends}, ${misc:Depends}
46+Description: This project makes Qt4 applications introspectable by autopilot.
47+ This allows autopilot to test any existing Qt4 application,
48+ without having to rebuild the application under test.
49+
50+Package: autopilot-qt5
51+Section: libs
52+Architecture: any
53+Depends: ${shlibs:Depends}, ${misc:Depends}
54+Description: This project makes Qt5 applications introspectable by autopilot.
55+ This allows autopilot to test any existing Qt5 application,
56+ without having to rebuild the application under test.
57
58=== added file 'debian/copyright'
59--- debian/copyright 1970-01-01 00:00:00 +0000
60+++ debian/copyright 2012-10-10 07:46:20 +0000
61@@ -0,0 +1,42 @@
62+Format: http://dep.debian.net/deps/dep5
63+Upstream-Name: autopilot-qt
64+Source: https://code.launchpad.net/~private-ps-quality-team/autopilot-qt/trunk
65+
66+Files: *
67+Copyright: 2012 Canonical Ltd.
68+License:
69+ This program is free software: you can redistribute it and/or modify it
70+ under the terms of the the GNU General Public License version 3, as
71+ published by the Free Software Foundation.
72+ .
73+ This program is distributed in the hope that it will be useful, but
74+ WITHOUT ANY WARRANTY; without even the implied warranties of
75+ MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
76+ PURPOSE. See the applicable version of the GNU Lesser General Public
77+ License for more details.
78+ .
79+ You should have received a copy of the GNU General Public License
80+ along with this program. If not, see <http://www.gnu.org/licenses/>.
81+ .
82+ On Debian systems, the complete text of the GNU General
83+ Public License v3 can be found in `/usr/share/common-licenses/GPL-3'.
84+
85+Files: debian/*
86+Copyright: 2012 Canonical Ltd.
87+License: GPL-2+
88+ This package is free software; you can redistribute it and/or modify
89+ it under the terms of the GNU General Public License as published by
90+ the Free Software Foundation; either version 2 of the License, or
91+ (at your option) any later version.
92+ .
93+ This package is distributed in the hope that it will be useful,
94+ but WITHOUT ANY WARRANTY; without even the implied warranty of
95+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
96+ GNU General Public License for more details.
97+ .
98+ You should have received a copy of the GNU General Public License
99+ along with this program. If not, see <http://www.gnu.org/licenses/>
100+ .
101+ On Debian systems, the complete text of the GNU General
102+ Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
103+
104
105=== added file 'debian/lintian-overrides'
106--- debian/lintian-overrides 1970-01-01 00:00:00 +0000
107+++ debian/lintian-overrides 2012-10-10 07:46:20 +0000
108@@ -0,0 +1,1 @@
109+autopilot-qt binary: non-dev-pkg-with-shlib-symlink
110
111=== added file 'debian/rules'
112--- debian/rules 1970-01-01 00:00:00 +0000
113+++ debian/rules 2012-10-10 07:46:20 +0000
114@@ -0,0 +1,34 @@
115+#!/usr/bin/make -f
116+# -*- makefile -*-
117+# Sample debian/rules that uses debhelper.
118+# This file was originally written by Joey Hess and Craig Small.
119+# As a special exception, when this file is copied by dh-make into a
120+# dh-make output file, you may use that output file without restriction.
121+# This special exception was added by Craig Small in version 0.37 of dh-make.
122+
123+# Uncomment this to turn on verbose mode.
124+export DH_VERBOSE=1
125+
126+%:
127+ dh $@
128+
129+override_dh_auto_configure:
130+ mkdir qt4
131+ mkdir qt5
132+ cd qt4 && qmake ../autopilot-qt.pro
133+ cd qt5 && /opt/qt5/bin/qmake ../autopilot-qt.pro
134+
135+override_dh_auto_build:
136+ cd qt4 && make
137+ cd qt5 && make
138+
139+override_dh_clean:
140+ dh_clean
141+ rm -rf qt4
142+ rm -rf qt5
143+
144+override_dh_install:
145+ mkdir -p $(CURDIR)/debian/autopilot-qt/usr/lib/
146+ mkdir -p $(CURDIR)/debian/autopilot-qt5/opt/qt5/lib/
147+ cp -pP qt4/libqttestability* $(CURDIR)/debian/autopilot-qt/usr/lib/
148+ cp -pP qt5/libqttestability* $(CURDIR)/debian/autopilot-qt5/opt/qt5/lib/
149
150=== modified file 'lib/dbus_object.cpp'
151--- lib/dbus_object.cpp 2012-09-06 05:29:12 +0000
152+++ lib/dbus_object.cpp 2012-10-10 07:46:20 +0000
153@@ -13,7 +13,13 @@
154 #include <QList>
155 #include <QVariantMap>
156 #include <QDebug>
157-#include <QApplication>
158+
159+#ifdef QT5_SUPPORT
160+ #include <QtWidgets/QApplication>
161+#else
162+ #include <QApplication>
163+#endif
164+
165 #include <QDBusConnection>
166 #include <QThread>
167
168@@ -125,7 +131,11 @@
169 QMetaMethod method = meta->method(i);
170 if (method.methodType() == QMetaMethod::Signal)
171 {
172+#ifdef QT5_SUPPORT
173+ QString signature = QString::fromLatin1(method.methodSignature());
174+#else
175 QString signature = QString::fromLatin1(method.signature());
176+#endif
177 signal_list.append(QVariant(signature));
178 }
179 }
180@@ -157,7 +167,11 @@
181 if (method.methodType() == QMetaMethod::Slot ||
182 method.methodType() == QMetaMethod::Method)
183 {
184+#ifdef QT5_SUPPORT
185+ QString signature = QString::fromLatin1(method.methodSignature());
186+#else
187 QString signature = QString::fromLatin1(method.signature());
188+#endif
189 method_list.append(QVariant(signature));
190 }
191 }
192@@ -199,8 +213,14 @@
193
194 qDebug() << "Method parameter names:" << method.parameterNames();
195 qDebug() << "Method parameter types:" << method.parameterTypes();
196+
197+#ifdef QT5_SUPPORT
198+ qDebug() << "Method signature:" << method.methodSignature()
199+ << "return type:" << method.typeName();
200+#else
201 qDebug() << "Method signature:" << method.signature()
202 << "return type:" << method.typeName();
203+#endif
204
205 QVector<QGenericArgument> generic_args(10);
206 QList<QByteArray> parameterTypes = method.parameterTypes();
207
208=== modified file 'lib/introspection.cpp'
209--- lib/introspection.cpp 2012-09-07 02:03:32 +0000
210+++ lib/introspection.cpp 2012-10-10 07:46:20 +0000
211@@ -10,17 +10,29 @@
212 #include <xpathselect/node.h>
213 #include <xpathselect/xpathselect.h>
214
215-#include <QApplication>
216 #include <QDebug>
217+
218+#ifdef QT5_SUPPORT
219+ #include <QtGui/QGuiApplication>
220+ #include <QtWidgets/QGraphicsItem>
221+ #include <QtWidgets/QGraphicsScene>
222+ #include <QtWidgets/QGraphicsView>
223+ #include <QtWidgets/QWidget>
224+ #include <QtQuick/QQuickItem>
225+ #include <QtQuick/QQuickWindow>
226+#else
227+ #include <QGraphicsItem>
228+ #include <QGraphicsScene>
229+ #include <QGraphicsView>
230+ #include <QApplication>
231+ #include <QWidget>
232+#endif
233+
234 #include <QMap>
235 #include <QMetaProperty>
236 #include <QObject>
237 #include <QStringList>
238-#include <QGraphicsItem>
239-#include <QGraphicsScene>
240-#include <QGraphicsView>
241 #include <QVariant>
242-#include <QWidget>
243 #include <QRect>
244
245 #include "introspection.h"
246@@ -49,13 +61,19 @@
247
248 QList<QtNode::Ptr> GetNodesThatMatchQuery(QString const& query_string)
249 {
250+#ifdef QT5_SUPPORT
251+ std::shared_ptr<RootNode> root = std::make_shared<RootNode>(QGuiApplication::instance());
252+ foreach (QWindow *widget, QGuiApplication::topLevelWindows())
253+ {
254+ root->AddChild((QObject*) widget);
255+ }
256+#else
257 std::shared_ptr<RootNode> root = std::make_shared<RootNode>(QApplication::instance());
258-
259 foreach (QWidget *widget, QApplication::topLevelWidgets())
260 {
261 root->AddChild((QObject*) widget);
262 }
263-
264+#endif
265 QList<QtNode::Ptr> node_list;
266
267 xpathselect::NodeList list = xpathselect::SelectNodes(root, query_string.toStdString());
268@@ -148,7 +166,17 @@
269 scene_rect.size());
270 properties["globalRect"] = PackProperty(global_rect);
271 }
272-
273+#ifdef QT5_SUPPORT
274+ // ... and support for QQuickItems (aka. Qt5 Declarative items)
275+ else if (QQuickItem *i = qobject_cast<QQuickItem*>(obj))
276+ {
277+ QQuickWindow *view = i->window();
278+ QRectF bounding_rect = i->boundingRect();
279+ bounding_rect = i->mapRectToScene(bounding_rect);
280+ QRect global_rect = QRect(view->mapToGlobal(bounding_rect.toRect().topLeft()), bounding_rect.size().toSize());
281+ properties["globalRect"] = PackProperty(global_rect);
282+ }
283+#endif
284 }
285
286 QVariant PackProperty(QVariant const& prop)
287@@ -159,8 +187,10 @@
288 case QVariant::Bool:
289 case QVariant::String:
290 case QVariant::UInt:
291+ case QVariant::LongLong:
292 case QVariant::ULongLong:
293 case QVariant::StringList:
294+ case QVariant::Double:
295 {
296 return prop;
297 }
298
299=== modified file 'lib/lib.pro'
300--- lib/lib.pro 2012-08-23 22:01:03 +0000
301+++ lib/lib.pro 2012-10-10 07:46:20 +0000
302@@ -25,5 +25,13 @@
303 dbus_adaptor_qt.h
304
305 target.file = libtestability*
306-target.path = /usr/lib
307+
308+#version check qt
309+contains(QT_VERSION, ^5\\..\\..*) {
310+ DEFINES += QT5_SUPPORT
311+ target.path = /opt/qt5/lib
312+} else {
313+ target.path = /usr/lib
314+}
315+
316 INSTALLS += target
317
318=== modified file 'lib/qtnode.cpp'
319--- lib/qtnode.cpp 2012-08-23 22:01:03 +0000
320+++ lib/qtnode.cpp 2012-10-10 07:46:20 +0000
321@@ -2,8 +2,19 @@
322
323 #include "introspection.h"
324
325-#include <QGraphicsScene>
326-#include <QGraphicsObject>
327+#include <QDebug>
328+
329+#ifdef QT5_SUPPORT
330+ #include <QtWidgets/QGraphicsScene>
331+ #include <QtWidgets/QGraphicsObject>
332+ #include <QtQml/QQmlEngine>
333+ #include <QtQml/QQmlContext>
334+ #include <QtQuick/QQuickView>
335+ #include <QtQuick/QQuickItem>
336+#else
337+ #include <QGraphicsScene>
338+ #include <QGraphicsObject>
339+#endif
340
341 const QByteArray AP_ID_NAME("_autopilot_id");
342
343@@ -75,11 +86,40 @@
344 xpathselect::NodeList QtNode::Children() const
345 {
346 xpathselect::NodeList children;
347+
348+#ifdef QT5_SUPPORT
349+ // Qt5's hierarchy for QML has changed a bit:
350+ // - On top there's a QQuickView which holds all the QQuick items
351+ // - QQuickItems don't always follow the QObject type hierarchy (e.g. QQuickListView does not), therefore we use the QQuickItem's childItems()
352+ // - In case it is not a QQuickItem, fall back to the standard QObject hierarchy
353+
354+ QQuickView *view = qobject_cast<QQuickView*>(object_);
355+ if (view) {
356+ children.push_back(std::make_shared<QtNode>(view->rootItem()));
357+ }
358+
359+ QQuickItem* item = qobject_cast<QQuickItem*>(object_);
360+ if (item) {
361+ foreach (QQuickItem *childItem, item->childItems()) {
362+ if (childItem->parentItem() == item) {
363+ children.push_back(std::make_shared<QtNode>(childItem));
364+ }
365+ }
366+ } else {
367+ foreach (QObject *child, object_->children())
368+ {
369+ if (child->parent() == object_)
370+ children.push_back(std::make_shared<QtNode>(child));
371+ }
372+ }
373+
374+#else
375 foreach (QObject *child, object_->children())
376 {
377 if (child->parent() == object_)
378 children.push_back(std::make_shared<QtNode>(child));
379 }
380+
381 // If our wrapped object is a QGraphicsScene, we need to explicitly grab any child graphics
382 // items that are derived from QObjects. Declarative UIs use this idiom, so this need to be
383 // done to support QML applications.
384@@ -94,5 +134,7 @@
385 children.push_back(std::make_shared<QtNode>(obj));
386 }
387 }
388+#endif
389+
390 return children;
391 }

Subscribers

People subscribed via source and target branches