Merge lp:~autopilot/autopilot-qt/experimental into lp:autopilot-qt

Proposed by Thomi Richards
Status: Merged
Approved by: Thomi Richards
Approved revision: 85
Merged at revision: 71
Proposed branch: lp:~autopilot/autopilot-qt/experimental
Merge into: lp:autopilot-qt
Diff against target: 1194 lines (+610/-161)
15 files modified
debian/changelog (+7/-0)
debian/control (+4/-2)
driver/autopilot_types.h (+26/-0)
driver/dbus_adaptor.cpp (+1/-1)
driver/dbus_object.cpp (+4/-2)
driver/driver.pro (+2/-1)
driver/introspection.cpp (+62/-25)
driver/introspection.h (+1/-1)
driver/qtnode.cpp (+125/-50)
driver/qtnode.h (+29/-8)
driver/qttestability.cpp (+3/-0)
driver/rootnode.cpp (+15/-26)
driver/rootnode.h (+2/-4)
tests/unittests/tst_introspection.cpp (+326/-39)
tests/unittests/unittests.pro (+3/-2)
To merge this branch: bzr merge lp:~autopilot/autopilot-qt/experimental
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Autopilot Hackers Pending
Review via email: mp+185843@code.launchpad.net

Commit message

1.4 wire protocol changes.

Description of the change

Merge 1.4 changes.

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

Add Breaks clause on binary package.

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
=== modified file 'debian/changelog'
--- debian/changelog 2013-08-14 02:04:35 +0000
+++ debian/changelog 2013-09-16 18:00:39 +0000
@@ -1,3 +1,10 @@
1autopilot-qt (1.4-0ubuntu1) saucy; urgency=low
2
3 [ Thomi Richards ]
4 * Update to new xpathselect 1.4 API. Version bump to 1.4.
5
6 -- Thomi Richards <thomi.richards@canonical.com> Thu, 15 Aug 2013 11:23:33 +1200
7
1autopilot-qt (1.3+13.10.20130814-0ubuntu1) saucy; urgency=low8autopilot-qt (1.3+13.10.20130814-0ubuntu1) saucy; urgency=low
29
3 [ Robert Bruce Park ]10 [ Robert Bruce Park ]
411
=== modified file 'debian/control'
--- debian/control 2013-08-13 22:39:44 +0000
+++ debian/control 2013-09-16 18:00:39 +0000
@@ -6,7 +6,7 @@
6 libgl1-mesa-dev,6 libgl1-mesa-dev,
7 libgles2-mesa-dev,7 libgles2-mesa-dev,
8 libqt4-dev,8 libqt4-dev,
9 libxpathselect-dev (>= 1.3),9 libxpathselect-dev (>= 1.4),
10 mesa-common-dev,10 mesa-common-dev,
11 pkg-config,11 pkg-config,
12 qt4-qmake,12 qt4-qmake,
@@ -27,9 +27,11 @@
27Package: libautopilot-qt27Package: libautopilot-qt
28Section: libs28Section: libs
29Architecture: any29Architecture: any
30Depends: libxpathselect1.3,30Depends: libxpathselect1.4,
31 ${misc:Depends},31 ${misc:Depends},
32 ${shlibs:Depends},32 ${shlibs:Depends},
33Breaks: python-autopilot (<< 1.4),
34 python3-autopilot (<< 1.4)
33Replaces: autopilot-qt,35Replaces: autopilot-qt,
34 autopilot-qt5,36 autopilot-qt5,
35Conflicts: autopilot-qt,37Conflicts: autopilot-qt,
3638
=== added file 'driver/autopilot_types.h'
--- driver/autopilot_types.h 1970-01-01 00:00:00 +0000
+++ driver/autopilot_types.h 2013-09-16 18:00:39 +0000
@@ -0,0 +1,26 @@
1/*
2Copyright 2012 Canonical
3
4This program is free software: you can redistribute it and/or modify it
5under the terms of the GNU General Public License version 3, as published
6by the Free Software Foundation.
7*/
8
9
10#ifndef AUTOPILOT_TYPES_H
11#define AUTOPILOT_TYPES_H
12
13/// IMPORTANT: THese constants are taken from the autopilot XPathSelect protocol document.
14/// Only add options here if the support has been added for them in autopilot itself.
15enum autopilot_type_id
16{
17 TYPE_PLAIN = 0,
18 TYPE_RECT = 1,
19 TYPE_POINT = 2,
20 TYPE_SIZE = 3,
21 TYPE_COLOR = 4,
22 TYPE_DATETIME = 5,
23 TYPE_TIME = 6,
24};
25
26#endif
027
=== modified file 'driver/dbus_adaptor.cpp'
--- driver/dbus_adaptor.cpp 2013-05-07 23:46:49 +0000
+++ driver/dbus_adaptor.cpp 2013-09-16 18:00:39 +0000
@@ -51,7 +51,7 @@
51void AutopilotAdaptor::GetVersion(const QDBusMessage &message)51void AutopilotAdaptor::GetVersion(const QDBusMessage &message)
52{52{
53 QDBusMessage reply = message.createReply();53 QDBusMessage reply = message.createReply();
54 reply << QVariant(QString("1.3"));54 reply << QVariant(QString("1.4"));
55 QDBusConnection::sessionBus().send(reply);55 QDBusConnection::sessionBus().send(reply);
56}56}
5757
5858
=== modified file 'driver/dbus_object.cpp'
--- driver/dbus_object.cpp 2013-06-27 16:27:11 +0000
+++ driver/dbus_object.cpp 2013-09-16 18:00:39 +0000
@@ -294,10 +294,12 @@
294void DBusObject::ProcessQuery()294void DBusObject::ProcessQuery()
295{295{
296 Query query = _queries.takeFirst();296 Query query = _queries.takeFirst();
297 QList<QVariant> state = Introspect(query.first);297 QList<NodeIntrospectionData> state = Introspect(query.first);
298298
299 QDBusMessage msg = query.second;299 QDBusMessage msg = query.second;
300 msg << QVariant(state);300 QVariant var;
301 var.setValue(state);
302 msg << var;
301303
302 QDBusConnection::sessionBus().send(msg);304 QDBusConnection::sessionBus().send(msg);
303}305}
304306
=== modified file 'driver/driver.pro'
--- driver/driver.pro 2013-01-17 20:20:44 +0000
+++ driver/driver.pro 2013-09-16 18:00:39 +0000
@@ -29,7 +29,8 @@
29 rootnode.h \29 rootnode.h \
30 qtnode.h \30 qtnode.h \
31 introspection.h \31 introspection.h \
32 dbus_adaptor_qt.h32 dbus_adaptor_qt.h \
33 autopilot_types.h
3334
34target.file = libtestability*35target.file = libtestability*
3536
3637
=== modified file 'driver/introspection.cpp'
--- driver/introspection.cpp 2013-06-26 09:00:13 +0000
+++ driver/introspection.cpp 2013-09-16 18:00:39 +0000
@@ -37,6 +37,7 @@
37#include <QUrl>37#include <QUrl>
38#include <QDateTime>38#include <QDateTime>
3939
40#include "autopilot_types.h"
40#include "introspection.h"41#include "introspection.h"
41#include "qtnode.h"42#include "qtnode.h"
42#include "rootnode.h"43#include "rootnode.h"
@@ -47,13 +48,13 @@
47QStringList GetNodeChildNames(QObject* obj);48QStringList GetNodeChildNames(QObject* obj);
48void AddCustomProperties(QObject* obj, QVariantMap& properties);49void AddCustomProperties(QObject* obj, QVariantMap& properties);
4950
50QList<QVariant> Introspect(QString const& query_string)51QList<NodeIntrospectionData> Introspect(QString const& query_string)
51{52{
52 QList<QVariant> state;53 QList<NodeIntrospectionData> state;
53 QList<QtNode::Ptr> node_list = GetNodesThatMatchQuery(query_string);54 QList<QtNode::Ptr> node_list = GetNodesThatMatchQuery(query_string);
54 foreach (QtNode::Ptr obj, node_list)55 foreach (QtNode::Ptr obj, node_list)
55 {56 {
56 state.append(obj->IntrospectNode());57 state.append(obj->GetIntrospectionData());
57 }58 }
5859
59 return state;60 return state;
@@ -85,11 +86,11 @@
85#endif86#endif
86 QList<QtNode::Ptr> node_list;87 QList<QtNode::Ptr> node_list;
8788
88 xpathselect::NodeList list = xpathselect::SelectNodes(root, query_string.toStdString());89 xpathselect::NodeVector list = xpathselect::SelectNodes(root, query_string.toStdString());
89 for (auto node : list)90 for (auto node : list)
90 {91 {
91 // node may be our root node wrapper *or* an ordinary qobject wrapper92 // node may be our root node wrapper *or* an ordinary qobject wrapper
92 auto object_ptr = std::static_pointer_cast<QtNode>(node);93 auto object_ptr = std::static_pointer_cast<const QtNode>(node);
93 if (object_ptr)94 if (object_ptr)
94 {95 {
95 node_list.append(object_ptr);96 node_list.append(object_ptr);
@@ -154,7 +155,7 @@
154 // add the 'Children' pseudo-property:155 // add the 'Children' pseudo-property:
155 QStringList children = GetNodeChildNames(obj);156 QStringList children = GetNodeChildNames(obj);
156 if (!children.empty())157 if (!children.empty())
157 object_properties["Children"] = children;158 object_properties["Children"] = PackProperty(children);
158159
159 return object_properties;160 return object_properties;
160}161}
@@ -211,69 +212,105 @@
211 case QVariant::StringList:212 case QVariant::StringList:
212 case QVariant::Double:213 case QVariant::Double:
213 {214 {
214 return prop;215 return QList<QVariant> {
216 QVariant(TYPE_PLAIN),
217 prop
218 };
215 }219 }
216220
217 case QVariant::ByteArray:221 case QVariant::ByteArray:
218 {222 {
219 return QVariant(QString(qvariant_cast<QByteArray>(prop)));223 return QList<QVariant> {
224 QVariant(TYPE_PLAIN),
225 QVariant(QString(qvariant_cast<QByteArray>(prop)))
226 };
220 }227 }
221228
222 case QVariant::Point:229 case QVariant::Point:
223 {230 {
224 QPoint p = qvariant_cast<QPoint>(prop);231 QPoint p = qvariant_cast<QPoint>(prop);
225 QList<QVariant> l = {QVariant(p.x()), QVariant(p.y())};232 return QList<QVariant> {
226 return QVariant(l);233 QVariant(TYPE_POINT),
234 QVariant(p.x()),
235 QVariant(p.y())
236 };
227 }237 }
228238
229 case QVariant::Rect:239 case QVariant::Rect:
230 {240 {
231 QRect r = qvariant_cast<QRect>(prop);241 QRect r = qvariant_cast<QRect>(prop);
232 QList<QVariant> l = {242 return QList<QVariant> {
243 QVariant(TYPE_RECT),
233 QVariant(r.x()),244 QVariant(r.x()),
234 QVariant(r.y()),245 QVariant(r.y()),
235 QVariant(r.width()),246 QVariant(r.width()),
236 QVariant(r.height()) };247 QVariant(r.height()) };
237 return QVariant(l);
238 }248 }
239249
240 case QVariant::Size:250 case QVariant::Size:
241 {251 {
242 QSize s = qvariant_cast<QSize>(prop);252 QSize s = qvariant_cast<QSize>(prop);
243 QList<QVariant> l = { QVariant(s.width()), QVariant(s.height()) };253 return QList<QVariant> {
244 return QVariant(l);254 QVariant(TYPE_SIZE),
255 QVariant(s.width()),
256 QVariant(s.height())
257 };
245 }258 }
246259
247 case QVariant::Color:260 case QVariant::Color:
248 {261 {
249 QColor color = qvariant_cast<QColor>(prop).toRgb();262 QColor color = qvariant_cast<QColor>(prop).toRgb();
250 QList<QVariant> l = { QVariant(color.red()),263 return QList<QVariant> {
251 QVariant(color.green()),264 QVariant(TYPE_COLOR),
252 QVariant(color.blue()),265 QVariant(color.red()),
253 QVariant(color.alpha())266 QVariant(color.green()),
254 };267 QVariant(color.blue()),
255 return QVariant(l);268 QVariant(color.alpha())
269 };
256 }270 }
257271
258 case QVariant::Url:272 case QVariant::Url:
259 {273 {
260 return QVariant(prop.toUrl().toString());274 return QList<QVariant> {
275 QVariant(TYPE_PLAIN),
276 QVariant(prop.toUrl().toString())
277 };
261 }278 }
262279
263 // Depending on the architecture, floating points might be of type QMetaType::Float instead of QVariant::Double280 // Depending on the architecture, floating points might be of type QMetaType::Float instead of QVariant::Double
264 // QDBus however, can only carry QVariant types, so lets convert it to QVariant::Double281 // QDBus however, can only carry QVariant types, so lets convert it to QVariant::Double
265 case QMetaType::Float:282 case QMetaType::Float:
266 {283 {
267 return QVariant(prop.toDouble());284 return QList<QVariant> {
285 QVariant(TYPE_PLAIN),
286 QVariant(prop.toDouble())
287 };
268 }288 }
289
269 case QVariant::Date:290 case QVariant::Date:
270 case QVariant::DateTime:291 case QVariant::DateTime:
271 return QVariant(prop.toDateTime().toTime_t());292 {
293 return QList<QVariant> {
294 QVariant(TYPE_DATETIME),
295 QVariant(prop.toDateTime().toTime_t())
296 };
297 }
298
272 case QVariant::Time:299 case QVariant::Time:
273 return QVariant(prop.toTime().toString("hh:mm:ss"));300 {
301 QTime t = qvariant_cast<QTime>(prop);
302 return QList<QVariant> {
303 QVariant(TYPE_TIME),
304 QVariant(t.hour()),
305 QVariant(t.minute()),
306 QVariant(t.second()),
307 QVariant(t.msec())
308 };
309 }
310
274 default:311 default:
275 {312 {
276 return QVariant();313 return QVariant(); // unsupported type, will not be sent to the client.
277 }314 }
278 }315 }
279}316}
280317
=== modified file 'driver/introspection.h'
--- driver/introspection.h 2012-08-23 22:01:03 +0000
+++ driver/introspection.h 2013-09-16 18:00:39 +0000
@@ -14,7 +14,7 @@
14#include <QVariantMap>14#include <QVariantMap>
1515
16/// Introspect 'obj' and return it's properties in a QVariantMap.16/// Introspect 'obj' and return it's properties in a QVariantMap.
17QList<QVariant> Introspect(const QString& query_string);17QList<NodeIntrospectionData> Introspect(const QString& query_string);
1818
19/// Get a list of QtNode pointers that match the given query.19/// Get a list of QtNode pointers that match the given query.
20QList<QtNode::Ptr> GetNodesThatMatchQuery(QString const& query_string);20QList<QtNode::Ptr> GetNodesThatMatchQuery(QString const& query_string);
2121
=== modified file 'driver/qtnode.cpp'
--- driver/qtnode.cpp 2013-06-19 10:56:21 +0000
+++ driver/qtnode.cpp 2013-09-16 18:00:39 +0000
@@ -15,41 +15,54 @@
15 #include <QGraphicsScene>15 #include <QGraphicsScene>
16 #include <QGraphicsObject>16 #include <QGraphicsObject>
17#endif17#endif
18#include <QDBusArgument>
19
20// Marshall the NodeIntrospectionData data into a D-Bus argument
21 QDBusArgument &operator<<(QDBusArgument &argument, const NodeIntrospectionData &node_data)
22 {
23 argument.beginStructure();
24 argument << node_data.object_path << node_data.state;
25 argument.endStructure();
26 return argument;
27 }
28
29 // Retrieve the NodeIntrospectionData data from the D-Bus argument
30 const QDBusArgument &operator>>(const QDBusArgument &argument, NodeIntrospectionData &node_data)
31 {
32 argument.beginStructure();
33 argument >> node_data.object_path >> node_data.state;
34 argument.endStructure();
35 return argument;
36 }
1837
19const QByteArray AP_ID_NAME("_autopilot_id");38const QByteArray AP_ID_NAME("_autopilot_id");
2039
21QtNode::QtNode(QObject *obj, std::string const& parent_path)40QtNode::QtNode(QObject *obj, QtNode::Ptr parent)
22 : object_(obj)41: object_(obj)
42, parent_(parent)
23{43{
44 std::string parent_path = parent ? parent->GetPath() : "";
24 full_path_ = parent_path + "/" + GetName();45 full_path_ = parent_path + "/" + GetName();
25}46}
2647
48QtNode::QtNode(QObject* obj)
49: object_(obj)
50{
51 full_path_ = "/" + GetName();
52}
53
27QObject* QtNode::getWrappedObject() const54QObject* QtNode::getWrappedObject() const
28{55{
29 return object_;56 return object_;
30}57}
3158
32QVariant QtNode::IntrospectNode() const59NodeIntrospectionData QtNode::GetIntrospectionData() const
33{60{
34 // return must be (name, state_map)61 NodeIntrospectionData data;
35 QString object_name = QString::fromStdString(GetPath());62 data.object_path = QString::fromStdString(GetPath());
36 QVariantMap object_properties = GetNodeProperties(object_);63 data.state = GetNodeProperties(object_);
37 object_properties["id"] = GetObjectId();64 data.state["id"] = PackProperty(GetId());
38 QList<QVariant> object_tuple = { QVariant(object_name), QVariant(object_properties) };65 return data;
39 return QVariant(object_tuple);
40}
41
42qint64 QtNode::GetObjectId() const
43{
44 // Note: This starts at 1 for a reason - 1 is reserved for the pseudo root node, and
45 // so must never be allocated to a regular object.
46 static qint64 next_id=1;
47
48 QList<QByteArray> property_names = object_->dynamicPropertyNames();
49 if (!property_names.contains(AP_ID_NAME))
50 object_->setProperty(AP_ID_NAME, QVariant(++next_id));
51 return object_->property(AP_ID_NAME).toLongLong();
52
53}66}
5467
55std::string QtNode::GetName() const68std::string QtNode::GetName() const
@@ -68,30 +81,86 @@
68 return full_path_;81 return full_path_;
69}82}
7083
71bool QtNode::MatchProperty(const std::string& name, const std::string& value) const84int32_t QtNode::GetId() const
85{
86 // Note: This method is used to assign ids to both the root node (with a QApplication object) and
87 // child nodes. This used to be separate code, but now that we export QApplication properties,
88 // we can use this one method everywhere.
89 static int32_t next_id=0;
90
91 QList<QByteArray> property_names = object_->dynamicPropertyNames();
92 if (!property_names.contains(AP_ID_NAME))
93 {
94 int32_t new_id = ++next_id;
95 object_->setProperty(AP_ID_NAME, QVariant(new_id));
96 }
97 return qvariant_cast<int32_t>(object_->property(AP_ID_NAME));
98}
99
100bool QtNode::MatchStringProperty(const std::string& name, const std::string& value) const
101{
102 QVariantMap properties = GetNodeProperties(object_);
103
104 QString qname = QString::fromStdString(name);
105 if (! properties.contains(qname))
106 return false;
107
108 QVariant object_value = qvariant_cast<QVariantList>(properties[qname]).at(1);
109 QVariant check_value(QString::fromStdString(value));
110 if (check_value.canConvert(object_value.type()))
111 {
112 check_value.convert(object_value.type());
113 return check_value == object_value;
114 }
115
116 return false;
117}
118
119bool QtNode::MatchIntegerProperty(const std::string& name, int32_t value) const
72{120{
73 if (name == "id")121 if (name == "id")
74 return QString::fromStdString(value).toLongLong() == GetObjectId();122 return value == GetId();
75 QVariantMap properties = GetNodeProperties(object_);123
76124 QVariantMap properties = GetNodeProperties(object_);
77 QString qname = QString::fromStdString(name);125
78 if (! properties.contains(qname))126 QString qname = QString::fromStdString(name);
79 return false;127 if (! properties.contains(qname))
80128 return false;
81 QVariant object_value = properties[qname];129
82 QVariant check_value(QString::fromStdString(value));130 QVariant object_value = qvariant_cast<QVariantList>(properties[qname]).at(1);
83 if (check_value.canConvert(object_value.type()))131 QVariant check_value(value);
84 {132 if (check_value.canConvert(object_value.type()))
85 check_value.convert(object_value.type());133 {
86 return check_value == object_value;134 check_value.convert(object_value.type());
87 }135 return check_value == object_value;
88136 }
89 return false;137
90}138 return false;
91139}
92xpathselect::NodeList QtNode::Children() const140
93{141bool QtNode::MatchBooleanProperty(const std::string& name, bool value) const
94 xpathselect::NodeList children;142{
143 QVariantMap properties = GetNodeProperties(object_);
144
145 QString qname = QString::fromStdString(name);
146 if (! properties.contains(qname))
147 return false;
148
149 QVariant object_value = qvariant_cast<QVariantList>(properties[qname]).at(1);
150 QVariant check_value(value);
151
152 if (check_value.canConvert(object_value.type()))
153 {
154 check_value.convert(object_value.type());
155 return check_value == object_value;
156 }
157
158 return false;
159}
160
161xpathselect::NodeVector QtNode::Children() const
162{
163 xpathselect::NodeVector children;
95164
96#ifdef QT5_SUPPORT165#ifdef QT5_SUPPORT
97 // Qt5's hierarchy for QML has changed a bit:166 // Qt5's hierarchy for QML has changed a bit:
@@ -101,21 +170,21 @@
101170
102 QQuickView *view = qobject_cast<QQuickView*>(object_);171 QQuickView *view = qobject_cast<QQuickView*>(object_);
103 if (view && view->rootObject() != 0) {172 if (view && view->rootObject() != 0) {
104 children.push_back(std::make_shared<QtNode>(view->rootObject(), GetPath()));173 children.push_back(std::make_shared<QtNode>(view->rootObject(), shared_from_this()));
105 }174 }
106175
107 QQuickItem* item = qobject_cast<QQuickItem*>(object_);176 QQuickItem* item = qobject_cast<QQuickItem*>(object_);
108 if (item) {177 if (item) {
109 foreach (QQuickItem *childItem, item->childItems()) {178 foreach (QQuickItem *childItem, item->childItems()) {
110 if (childItem->parentItem() == item) {179 if (childItem->parentItem() == item) {
111 children.push_back(std::make_shared<QtNode>(childItem, GetPath()));180 children.push_back(std::make_shared<QtNode>(childItem, shared_from_this()));
112 }181 }
113 }182 }
114 } else {183 } else {
115 foreach (QObject *child, object_->children())184 foreach (QObject *child, object_->children())
116 {185 {
117 if (child->parent() == object_)186 if (child->parent() == object_)
118 children.push_back(std::make_shared<QtNode>(child, GetPath()));187 children.push_back(std::make_shared<QtNode>(child, shared_from_this()));
119 }188 }
120 }189 }
121190
@@ -123,7 +192,7 @@
123 foreach (QObject *child, object_->children())192 foreach (QObject *child, object_->children())
124 {193 {
125 if (child->parent() == object_)194 if (child->parent() == object_)
126 children.push_back(std::make_shared<QtNode>(child, GetPath()));195 children.push_back(std::make_shared<QtNode>(child, shared_from_this()));
127 }196 }
128197
129 // If our wrapped object is a QGraphicsScene, we need to explicitly grab any child graphics198 // If our wrapped object is a QGraphicsScene, we need to explicitly grab any child graphics
@@ -137,10 +206,16 @@
137 {206 {
138 QGraphicsObject *obj = item->toGraphicsObject();207 QGraphicsObject *obj = item->toGraphicsObject();
139 if (obj && ! obj->parent())208 if (obj && ! obj->parent())
140 children.push_back(std::make_shared<QtNode>(obj, GetPath()));209 children.push_back(std::make_shared<QtNode>(obj, shared_from_this()));
141 }210 }
142 }211 }
143#endif212#endif
144213
145 return children;214 return children;
146}215}
216
217
218xpathselect::Node::Ptr QtNode::GetParent() const
219{
220 return parent_;
221}
147222
=== modified file 'driver/qtnode.h'
--- driver/qtnode.h 2013-04-18 03:44:31 +0000
+++ driver/qtnode.h 2013-09-16 18:00:39 +0000
@@ -1,33 +1,54 @@
1#ifndef QTNODE_H1#ifndef QTNODE_H
2#define QTNODE_H2#define QTNODE_H
33
4#include <cstdint>
4#include <QVariant>5#include <QVariant>
6#include <QDBusArgument>
5#include <xpathselect/node.h>7#include <xpathselect/node.h>
68
9/// A simple data structure representing the state of a single node:
10struct NodeIntrospectionData
11{
12 QString object_path;
13 QVariantMap state;
14};
15
16Q_DECLARE_METATYPE(NodeIntrospectionData);
17Q_DECLARE_METATYPE(QList<NodeIntrospectionData>);
18
19QDBusArgument &operator<<(QDBusArgument &argument, const NodeIntrospectionData &node_data);
20const QDBusArgument &operator>>(const QDBusArgument &argument, NodeIntrospectionData &node_data);
21
7/// Base class for all Qt-based object nodes.22/// Base class for all Qt-based object nodes.
8///23///
9/// QtNode wraps a single QObject pointer. It derives from xpathselect::Node and,24/// QtNode wraps a single QObject pointer. It derives from xpathselect::Node and,
10/// like that class, is designed to be allocated on the heap and stored in a25/// like that class, is designed to be allocated on the heap and stored in a
11/// std::shared_ptr.26/// std::shared_ptr.
12class QtNode: public xpathselect::Node27class QtNode: public xpathselect::Node, public std::enable_shared_from_this<QtNode>
13{28{
14public:29public:
15 typedef std::shared_ptr<QtNode> Ptr;30 typedef std::shared_ptr<const QtNode> Ptr;
1631
17 QtNode(QObject* object, std::string const& parent_path);32 QtNode(QObject* object, Ptr parent);
33 explicit QtNode(QObject* object);
1834
19 QObject* getWrappedObject() const;35 QObject* getWrappedObject() const;
2036 xpathselect::Node::Ptr GetParent() const;
21 virtual QVariant IntrospectNode() const;37
22 virtual qint64 GetObjectId() const;38 virtual NodeIntrospectionData GetIntrospectionData() const;
39
2340
24 virtual std::string GetName() const;41 virtual std::string GetName() const;
25 virtual std::string GetPath() const;42 virtual std::string GetPath() const;
26 virtual bool MatchProperty(const std::string& name, const std::string& value) const;43 virtual int32_t GetId() const;
27 virtual xpathselect::NodeList Children() const;44 virtual bool MatchStringProperty(const std::string& name, const std::string& value) const;
45 virtual bool MatchIntegerProperty(const std::string& name, int32_t value) const;
46 virtual bool MatchBooleanProperty(const std::string& name, bool value) const;
47 virtual xpathselect::NodeVector Children() const;
28private:48private:
29 QObject *object_;49 QObject *object_;
30 std::string full_path_;50 std::string full_path_;
51 Ptr parent_;
31};52};
3253
33#endif // QTNODE_H54#endif // QTNODE_H
3455
=== modified file 'driver/qttestability.cpp'
--- driver/qttestability.cpp 2012-12-19 12:27:25 +0000
+++ driver/qttestability.cpp 2013-09-16 18:00:39 +0000
@@ -10,6 +10,7 @@
10#include "dbus_adaptor.h"10#include "dbus_adaptor.h"
11#include "dbus_adaptor_qt.h"11#include "dbus_adaptor_qt.h"
12#include "dbus_object.h"12#include "dbus_object.h"
13#include "qtnode.h"
1314
14#include <QCoreApplication>15#include <QCoreApplication>
15#include <QDebug>16#include <QDebug>
@@ -20,6 +21,8 @@
20void qt_testability_init(void)21void qt_testability_init(void)
21{22{
22 qDebug() << "Loading testability driver.";23 qDebug() << "Loading testability driver.";
24 qDBusRegisterMetaType<NodeIntrospectionData>();
25 qDBusRegisterMetaType<QList<NodeIntrospectionData> >();
2326
24 DBusObject* obj = new DBusObject;27 DBusObject* obj = new DBusObject;
25 new AutopilotAdaptor(obj);28 new AutopilotAdaptor(obj);
2629
=== modified file 'driver/rootnode.cpp'
--- driver/rootnode.cpp 2013-04-18 04:46:44 +0000
+++ driver/rootnode.cpp 2013-09-16 18:00:39 +0000
@@ -1,35 +1,32 @@
1#include "rootnode.h"1#include "rootnode.h"
2#include "introspection.h"
23
3#include <QObject>4#include <QObject>
4#include <QCoreApplication>5#include <QCoreApplication>
5#include <QStringList>6#include <QStringList>
7#include <QDebug>
68
7RootNode::RootNode(QCoreApplication* application)9RootNode::RootNode(QCoreApplication* application)
8 : QtNode(application, std::string())10 : QtNode(application)
9 , application_(application)11 , application_(application)
10{12{
11}13}
1214
13QVariant RootNode::IntrospectNode() const15
16NodeIntrospectionData RootNode::GetIntrospectionData() const
14{17{
15 // return must be (name, state_map)18 NodeIntrospectionData data;
16 QString object_name = QString::fromStdString(GetPath());19 data.object_path = QString::fromStdString(GetPath());
20 data.state = GetNodeProperties(application_);
17 QStringList child_names;21 QStringList child_names;
18 foreach(QObject* child, children_)22 foreach(QObject* child, children_)
19 {23 {
20 child_names.append(child->metaObject()->className());24 child_names.append(child->metaObject()->className());
21 }25 }
2226
23 QVariantMap object_properties;27 data.state["Children"] = PackProperty(child_names);
24 object_properties["Children"] = child_names;28 data.state["id"] = PackProperty(GetId());
25 object_properties["id"] = GetObjectId();29 return data;
26 QList<QVariant> object_tuple = { QVariant(object_name), QVariant(object_properties) };
27 return QVariant(object_tuple);
28}
29
30qint64 RootNode::GetObjectId() const
31{
32 return 1;
33}30}
3431
35void RootNode::AddChild(QObject* child)32void RootNode::AddChild(QObject* child)
@@ -48,18 +45,10 @@
48 return "/" + GetName();45 return "/" + GetName();
49}46}
5047
51bool RootNode::MatchProperty(const std::string& name, const std::string& value) const48xpathselect::NodeVector RootNode::Children() const
52{49{
53 if (name == "id")50 xpathselect::NodeVector children;
54 return QString::fromStdString(value).toLongLong() == GetObjectId();
55
56 return false;
57}
58
59xpathselect::NodeList RootNode::Children() const
60{
61 xpathselect::NodeList children;
62 foreach(QObject* child, children_)51 foreach(QObject* child, children_)
63 children.push_back(std::make_shared<QtNode>(child, GetPath()));52 children.push_back(std::make_shared<QtNode>(child, shared_from_this()));
64 return children;53 return children;
65}54}
6655
=== modified file 'driver/rootnode.h'
--- driver/rootnode.h 2013-04-18 04:46:44 +0000
+++ driver/rootnode.h 2013-09-16 18:00:39 +0000
@@ -13,15 +13,13 @@
13public:13public:
14 RootNode(QCoreApplication* application);14 RootNode(QCoreApplication* application);
1515
16 virtual QVariant IntrospectNode() const;16 virtual NodeIntrospectionData GetIntrospectionData() const;
17 virtual qint64 GetObjectId() const;
1817
19 void AddChild(QObject* child);18 void AddChild(QObject* child);
2019
21 virtual std::string GetName() const;20 virtual std::string GetName() const;
22 virtual std::string GetPath() const;21 virtual std::string GetPath() const;
23 virtual bool MatchProperty(const std::string& name, const std::string& value) const;22 virtual xpathselect::NodeVector Children() const;
24 virtual xpathselect::NodeList Children() const;
25private:23private:
26 QCoreApplication* application_;24 QCoreApplication* application_;
27 QList<QObject*> children_;25 QList<QObject*> children_;
2826
=== modified file 'tests/unittests/tst_introspection.cpp'
--- tests/unittests/tst_introspection.cpp 2013-06-26 09:00:13 +0000
+++ tests/unittests/tst_introspection.cpp 2013-09-16 18:00:39 +0000
@@ -26,6 +26,7 @@
26#include <QPushButton>26#include <QPushButton>
2727
28#include "introspection.h"28#include "introspection.h"
29#include "qtnode.h"
2930
30QVariant IntrospectNode(QObject* obj);31QVariant IntrospectNode(QObject* obj);
3132
@@ -46,6 +47,8 @@
46 void test_properties_data();47 void test_properties_data();
47 void test_properties();48 void test_properties();
4849
50 void test_property_matching();
51
49private:52private:
50 QMainWindow *m_object;53 QMainWindow *m_object;
51};54};
@@ -74,6 +77,7 @@
7477
75 m_object->setObjectName("testWindow");78 m_object->setObjectName("testWindow");
76 m_object->setProperty("dynamicTestProperty", "testValue");79 m_object->setProperty("dynamicTestProperty", "testValue");
80 m_object->setProperty("dynamicStringProperty", QString("testValue"));
77 m_object->setProperty("myUInt", QVariant(quint8(5)));81 m_object->setProperty("myUInt", QVariant(quint8(5)));
78 m_object->setProperty("myStringList", QVariant(QStringList() << "string1" << "string2" << "string3"));82 m_object->setProperty("myStringList", QVariant(QStringList() << "string1" << "string2" << "string3"));
79 m_object->setProperty("myColor", QColor("red"));83 m_object->setProperty("myColor", QColor("red"));
@@ -113,25 +117,155 @@
113 QTest::addColumn<QVariant>("firstResultPropertyValue");117 QTest::addColumn<QVariant>("firstResultPropertyValue");
114118
115#ifdef QT5_SUPPORT119#ifdef QT5_SUPPORT
116 QTest::newRow("/") << "/" << 1 << "/tst_introspection" << "Children" << QVariant(QStringList() << "QMainWindow" << "QWidgetWindow");120 QTest::newRow("/")
117 QTest::newRow("//QWidget[id=6]") << "//QWidget[id=6]" << 1 << "/tst_introspection/QMainWindow/QWidget" << "objectName" << QVariant("centralTestWidget");121 << "/"
118 QTest::newRow("//QPushButton[id=9]") << "//QPushButton[id=9]" << 1 << "/tst_introspection/QMainWindow/QWidget/QPushButton" << "objectName" << QVariant("myButton2");122 << 1
123 << "/tst_introspection"
124 << "Children"
125 << QVariant(
126 QVariantList()
127 << 0
128 << QVariant(
129 QStringList()
130 << "QMainWindow"
131 << "QWidgetWindow"
132 )
133 );
134
135 QTest::newRow("//QWidget[id=6]")
136 << "//QWidget[id=6]"
137 << 1
138 << "/tst_introspection/QMainWindow/QWidget"
139 << "objectName"
140 << QVariant(
141 QVariantList()
142 << 0
143 << "centralTestWidget"
144 );
145
146 QTest::newRow("//QPushButton[id=9]")
147 << "//QPushButton[id=9]"
148 << 1
149 << "/tst_introspection/QMainWindow/QWidget/QPushButton"
150 << "objectName"
151 << QVariant(
152 QVariantList()
153 << 0
154 << "myButton2"
155 );
119#else156#else
120 QTest::newRow("/") << "/" << 1 << "/tst_introspection" << "Children" << QVariant(QStringList() << "QMainWindow");157 QTest::newRow("/")
121 QTest::newRow("//QWidget[id=5]") << "//QWidget[id=5]" << 1 << "/tst_introspection/QMainWindow/QWidget" << "objectName" << QVariant("centralTestWidget");158 << "/"
159 << 1
160 << "/tst_introspection"
161 << "Children"
162 << QVariant(
163 QVariantList()
164 << 0
165 << "QMainWindow"
166 );
167
168 QTest::newRow("//QWidget[id=5]")
169 << "//QWidget[id=5]"
170 << 1
171 << "/tst_introspection/QMainWindow/QWidget"
172 << "objectName"
173 << QVariant(
174 QVariantList()
175 << 0
176 << "centralTestWidget"
177 );
122178
123 // Depending on the environment, Qt4 could add a second QWidget at position 6. That moves other items down by one.179 // Depending on the environment, Qt4 could add a second QWidget at position 6. That moves other items down by one.
124 if (Introspect("//QWidget[id=6]").count() > 0) {180 if (Introspect("//QWidget[id=6]").count() > 0)
125 QTest::newRow("//QPushButton[id=9]") << "//QPushButton[id=9]" << 1 << "/tst_introspection/QMainWindow/QWidget/QPushButton" << "objectName" << QVariant("myButton2");181 {
126 } else {182 QTest::newRow("//QPushButton[id=9]")
127 QTest::newRow("//QPushButton[id=8]") << "//QPushButton[id=8]" << 1 << "/tst_introspection/QMainWindow/QWidget/QPushButton" << "objectName" << QVariant("myButton2");183 << "//QPushButton[id=9]"
184 << 1
185 << "/tst_introspection/QMainWindow/QWidget/QPushButton"
186 << "objectName"
187 << QVariant(
188 QVariantList()
189 << 0
190 << "myButton2"
191 );
192 }
193 else
194 {
195 QTest::newRow("//QPushButton[id=8]")
196 << "//QPushButton[id=8]"
197 << 1
198 << "/tst_introspection/QMainWindow/QWidget/QPushButton"
199 << "objectName"
200 << QVariant(
201 QVariantList()
202 << 0
203 << "myButton2"
204 );
128 }205 }
129#endif206#endif
130207
131 QTest::newRow("//GridLayout") << "//QGridLayout" << 1 << "/tst_introspection/QMainWindow/QWidget/QGridLayout" << "objectName" << QVariant("myTestLayout");208 QTest::newRow("/tst_introspection/QMainWindow/QWidget/QGridLayout")
132 QTest::newRow("//QPushButton") << "//QPushButton" << 2 << "/tst_introspection/QMainWindow/QWidget/QPushButton" << "objectName" << QVariant("myButton1");209 << "//QGridLayout"
133 QTest::newRow("//QWidget/*") << "//QWidget/*" << 5 << "/tst_introspection/QMainWindow/QWidget/QGridLayout" << "objectName" << QVariant("myTestLayout");210 << 1
134 QTest::newRow("broken query") << "broken query" << 0 << QString() << QString() << QVariant();211 << "/tst_introspection/QMainWindow/QWidget/QGridLayout"
212 << "objectName"
213 << QVariant(
214 QVariantList()
215 << 0
216 << "myTestLayout"
217 );
218
219 QTest::newRow("parent of leaf node")
220 << "/tst_introspection/QMainWindow/QWidget/QGridLayout/.."
221 << 1
222 << "/tst_introspection/QMainWindow/QWidget"
223 << "objectName"
224 << QVariant(
225 QVariantList()
226 << 0
227 << "centralTestWidget"
228 );
229
230 QTest::newRow("parent of root node")
231 << "/tst_introspection/.."
232 << 1
233 << "/tst_introspection"
234 << "id"
235 << QVariant(
236 QVariantList()
237 << 0
238 << 1
239 );
240
241 QTest::newRow("//QPushButton")
242 << "//QPushButton"
243 << 2
244 << "/tst_introspection/QMainWindow/QWidget/QPushButton"
245 << "objectName"
246 << QVariant(
247 QVariantList()
248 << 0
249 << "myButton1"
250 );
251
252 QTest::newRow("//QWidget/*")
253 << "//QWidget/*"
254 << 5
255 << "/tst_introspection/QMainWindow/QWidget/QGridLayout"
256 << "objectName"
257 << QVariant(
258 QVariantList()
259 << 0
260 << "myTestLayout"
261 );
262
263 QTest::newRow("broken query")
264 << "broken query"
265 << 0
266 << QString()
267 << QString()
268 << QVariant();
135}269}
136270
137void tst_Introspection::test_introspect()271void tst_Introspection::test_introspect()
@@ -142,16 +276,15 @@
142 QFETCH(QString, firstResultPropertyName);276 QFETCH(QString, firstResultPropertyName);
143 QFETCH(QVariant, firstResultPropertyValue);277 QFETCH(QVariant, firstResultPropertyValue);
144278
145 QList<QVariant> resultList = Introspect(xpath);279 QList<NodeIntrospectionData> resultList = Introspect(xpath);
146280
147 QCOMPARE(resultList.count(), resultCount);281 QCOMPARE(resultList.count(), resultCount);
148282
149 if (resultCount > 0) {283 if (resultCount > 0) {
150 QVariant firstResult = resultList.first();284 NodeIntrospectionData first_object = resultList.first();
151 QVariantMap firstResultProperties = firstResult.toList().last().toMap();
152285
153 QCOMPARE(firstResult.toList().first().toString(), firstResultType);286 QCOMPARE(first_object.object_path, firstResultType);
154 QCOMPARE(firstResultProperties.value(firstResultPropertyName), firstResultPropertyValue);287 QCOMPARE(first_object.state.value(firstResultPropertyName), firstResultPropertyValue);
155 }288 }
156}289}
157290
@@ -171,9 +304,9 @@
171 qApp->setApplicationName(app_name);304 qApp->setApplicationName(app_name);
172305
173#ifdef QT5_SUPPORT306#ifdef QT5_SUPPORT
174 QList<QVariant> result = Introspect("//QWidgetWindow");307 QList<NodeIntrospectionData> result = Introspect("//QWidgetWindow");
175#else308#else
176 QList<QVariant> result = Introspect("//QMainWindow");309 QList<NodeIntrospectionData> result = Introspect("//QMainWindow");
177#endif310#endif
178311
179 QVERIFY(!result.isEmpty());312 QVERIFY(!result.isEmpty());
@@ -185,25 +318,169 @@
185 QTest::addColumn<QVariant>("propertyValue");318 QTest::addColumn<QVariant>("propertyValue");
186 QTest::addColumn<bool>("fuzzyCompare");319 QTest::addColumn<bool>("fuzzyCompare");
187320
188 QTest::newRow("static property") << "objectName" << QVariant(m_object->objectName()) << false;321 QTest::newRow("static property")
189 QTest::newRow("dynamic property") << "dynamicTestProperty" << m_object->property("dynamicTestProperty") << false;322 << "objectName"
190323 << QVariant(
191 QTest::newRow("int") << "width" << QVariant(m_object->width()) << false;324 QVariantList()
192 QTest::newRow("uint") << "myUInt" << m_object->property("myUInt") << false;325 << 0
193 QTest::newRow("bool") << "visible" << QVariant(m_object->isVisible()) << false;326 << m_object->objectName()
194 QTest::newRow("double") << "windowOpacity" << QVariant(m_object->windowOpacity()) << true;327 )
195328 << false;
196 QTest::newRow("QString") << "objectName" << QVariant(m_object->objectName()) << false;329
197 QTest::newRow("QStringList") << "myStringList" << m_object->property("myStringList") << false;330 QTest::newRow("dynamic property")
198 QTest::newRow("QSize") << "maximumSize" << QVariant(QList<QVariant>() << m_object->maximumWidth() << m_object->maximumHeight()) << false;331 << "dynamicTestProperty"
199 QTest::newRow("QPoint") << "pos" << QVariant(QList<QVariant>() << m_object->x() << m_object->y()) << false;332 << QVariant(
200 QTest::newRow("QRect") << "geometry" << QVariant(QList<QVariant>() << m_object->geometry().x() << m_object->geometry().y() << m_object->geometry().width() << m_object->geometry().height()) << false;333 QVariantList()
201 QTest::newRow("QColor") << "myColor" << QVariant(QList<QVariant>() << 255 << 0 << 0 << 255) << false;334 << 0
202 QTest::newRow("QByteArray") << "myByteArray" << m_object->property("myByteArray") << false;335 << m_object->property("dynamicTestProperty")
203 QTest::newRow("QUrl") << "myUrl" << m_object->property("myUrl") << false;336 )
204 QTest::newRow("QDateTime") << "myDateTime" << QVariant(m_object->property("myDateTime").toDateTime().toTime_t()) << false;337 << false;
205 QTest::newRow("QDate") << "myDate" << QVariant(m_object->property("myDate").toDateTime().toTime_t()) << false;338
206 QTest::newRow("QTime") << "myTime" << QVariant(m_object->property("myTime").toTime().toString("hh:mm:ss")) << false;339 QTest::newRow("int")
340 << "width"
341 << QVariant(
342 QVariantList()
343 << 0
344 << m_object->width()
345 )
346 << false;
347
348 QTest::newRow("uint")
349 << "myUInt"
350 << QVariant(
351 QVariantList()
352 << 0
353 << m_object->property("myUInt")
354 )
355 << false;
356
357 QTest::newRow("bool")
358 << "visible"
359 << QVariant(
360 QVariantList()
361 << 0
362 << m_object->isVisible()
363 )
364 << false;
365
366 QTest::newRow("double")
367 << "windowOpacity"
368 << QVariant(
369 QVariantList()
370 << 0
371 << m_object->windowOpacity()
372 )
373 << true;
374
375 QTest::newRow("QString")
376 << "objectName"
377 << QVariant(
378 QVariantList()
379 << 0
380 << m_object->objectName()
381 )
382 << false;
383
384 QTest::newRow("QStringList")
385 << "myStringList"
386 << QVariant(
387 QVariantList()
388 << 0
389 << m_object->property("myStringList")
390 )
391 << false;
392
393 QTest::newRow("QSize")
394 << "maximumSize"
395 << QVariant(
396 QVariantList()
397 << 3
398 << m_object->maximumWidth()
399 << m_object->maximumHeight()
400 )
401 << false;
402
403 QTest::newRow("QPoint")
404 << "pos"
405 << QVariant(
406 QVariantList()
407 << 2
408 << m_object->x()
409 << m_object->y()
410 )
411 << false;
412
413 QTest::newRow("QRect")
414 << "geometry"
415 << QVariant(
416 QVariantList()
417 << 1
418 << m_object->geometry().x()
419 << m_object->geometry().y()
420 << m_object->geometry().width()
421 << m_object->geometry().height()
422 )
423 << false;
424
425 QTest::newRow("QColor")
426 << "myColor"
427 << QVariant(
428 QVariantList()
429 << 4
430 << qvariant_cast<QColor>(m_object->property("myColor")).red()
431 << qvariant_cast<QColor>(m_object->property("myColor")).green()
432 << qvariant_cast<QColor>(m_object->property("myColor")).blue()
433 << qvariant_cast<QColor>(m_object->property("myColor")).alpha()
434 )
435 << false;
436
437 QTest::newRow("QByteArray")
438 << "myByteArray"
439 << QVariant(
440 QVariantList()
441 << 0
442 << m_object->property("myByteArray")
443 )
444 << false;
445
446 QTest::newRow("QUrl")
447 << "myUrl"
448 << QVariant(
449 QVariantList()
450 << 0
451 << m_object->property("myUrl")
452 )
453 << false;
454
455 QTest::newRow("QDateTime")
456 << "myDateTime"
457 << QVariant(
458 QVariantList()
459 << 5
460 << m_object->property("myDateTime").toDateTime().toTime_t()
461 )
462 << false;
463
464 QTest::newRow("QDate")
465 << "myDate"
466 << QVariant(
467 QVariantList()
468 << 5
469 << m_object->property("myDate").toDateTime().toTime_t()
470 )
471 << false;
472
473 QTest::newRow("QTime")
474 << "myTime"
475 << QVariant(
476 QVariantList()
477 << 6
478 << m_object->property("myTime").toTime().hour()
479 << m_object->property("myTime").toTime().minute()
480 << m_object->property("myTime").toTime().second()
481 << m_object->property("myTime").toTime().msec()
482 )
483 << false;
207}484}
208485
209void tst_Introspection::test_properties()486void tst_Introspection::test_properties()
@@ -224,6 +501,16 @@
224 }501 }
225}502}
226503
504void tst_Introspection::test_property_matching()
505{
506 QtNode n(m_object);
507
508 QVERIFY(n.MatchStringProperty("dynamicStringProperty", "testValue") == true);
509 QVERIFY(n.MatchStringProperty("dynamicTestProperty", "testValue") == true);
510 QVERIFY(n.MatchIntegerProperty("myUInt", 5) == true);
511 QVERIFY(n.MatchBooleanProperty("visible", true) == true);
512}
513
227QTEST_MAIN(tst_Introspection)514QTEST_MAIN(tst_Introspection)
228515
229#include "tst_introspection.moc"516#include "tst_introspection.moc"
230517
=== modified file 'tests/unittests/unittests.pro'
--- tests/unittests/unittests.pro 2013-03-17 16:53:30 +0000
+++ tests/unittests/unittests.pro 2013-09-16 18:00:39 +0000
@@ -5,7 +5,7 @@
55
6QT += testlib dbus widgets quick6QT += testlib dbus widgets quick
77
8CONFIG += link_pkgconfig8CONFIG += link_pkgconfig debug
9PKGCONFIG += xpathselect9PKGCONFIG += xpathselect
10QMAKE_CXXFLAGS += -std=c++0x -Wl,--no-undefined10QMAKE_CXXFLAGS += -std=c++0x -Wl,--no-undefined
1111
@@ -15,7 +15,8 @@
1515
16INCLUDEPATH += ../../driver16INCLUDEPATH += ../../driver
1717
18SOURCES += tst_introspection.cpp \18SOURCES += \
19 tst_introspection.cpp \
19 ../../driver/introspection.cpp \20 ../../driver/introspection.cpp \
20 ../../driver/rootnode.cpp \21 ../../driver/rootnode.cpp \
21 ../../driver/qtnode.cpp22 ../../driver/qtnode.cpp

Subscribers

People subscribed via source and target branches

to all changes: