1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include "baseenginedebugclient.h"
27 #include "qmldebugconstants.h"
28 #include "qpacketprotocol.h"
29
30 namespace QmlDebug {
31
32 struct QmlObjectData {
33 QUrl url;
34 int lineNumber;
35 int columnNumber;
36 QString idString;
37 QString objectName;
38 QString objectType;
39 int objectId;
40 int contextId;
41 };
42
operator >>(QDataStream & ds,QmlObjectData & data)43 QDataStream &operator>>(QDataStream &ds, QmlObjectData &data)
44 {
45 ds >> data.url >> data.lineNumber >> data.columnNumber >> data.idString
46 >> data.objectName >> data.objectType >> data.objectId >> data.contextId;
47 return ds;
48 }
49
50 struct QmlObjectProperty {
51 enum Type { Unknown, Basic, Object, List, SignalProperty, Variant };
52 Type type;
53 QString name;
54 QVariant value;
55 QString valueTypeName;
56 QString binding;
57 bool hasNotifySignal;
58 };
59
operator >>(QDataStream & ds,QmlObjectProperty & data)60 QDataStream &operator>>(QDataStream &ds, QmlObjectProperty &data)
61 {
62 int type;
63 ds >> type >> data.name >> data.value >> data.valueTypeName
64 >> data.binding >> data.hasNotifySignal;
65 data.type = (QmlObjectProperty::Type)type;
66 return ds;
67 }
68
decode(QDataStream & ds,ObjectReference & o,bool simple)69 void BaseEngineDebugClient::decode(QDataStream &ds,
70 ObjectReference &o,
71 bool simple)
72 {
73 QmlObjectData data;
74 int parentId = -1;
75 ds >> data >> parentId;
76 o.m_debugId = data.objectId;
77 o.m_className = data.objectType;
78 o.m_idString = data.idString;
79 o.m_name = data.objectName;
80 o.m_source.m_url = data.url;
81 o.m_source.m_lineNumber = data.lineNumber;
82 o.m_source.m_columnNumber = data.columnNumber;
83 o.m_contextDebugId = data.contextId;
84 o.m_needsMoreData = simple;
85 o.m_parentId = parentId;
86
87 if (simple)
88 return;
89
90 int childCount;
91 bool recur;
92 ds >> childCount >> recur;
93
94 for (int ii = 0; ii < childCount; ++ii) {
95 o.m_children.append(ObjectReference());
96 decode(ds, o.m_children.last(), !recur);
97 }
98
99 int propCount;
100 ds >> propCount;
101
102 for (int ii = 0; ii < propCount; ++ii) {
103 QmlObjectProperty data;
104 ds >> data;
105 PropertyReference prop;
106 prop.m_objectDebugId = o.m_debugId;
107 prop.m_name = data.name;
108 prop.m_binding = data.binding;
109 prop.m_hasNotifySignal = data.hasNotifySignal;
110 prop.m_valueTypeName = data.valueTypeName;
111 switch (data.type) {
112 case QmlObjectProperty::Basic:
113 case QmlObjectProperty::List:
114 case QmlObjectProperty::SignalProperty:
115 case QmlObjectProperty::Variant:
116 {
117 prop.m_value = data.value;
118 break;
119 }
120 case QmlObjectProperty::Object:
121 {
122 ObjectReference obj;
123 obj.m_debugId = prop.m_value.toInt();
124 prop.m_value = QVariant::fromValue(obj);
125 break;
126 }
127 case QmlObjectProperty::Unknown:
128 break;
129 }
130 o.m_properties << prop;
131 }
132 }
133
decode(QDataStream & ds,QVariantList & o,bool simple)134 void BaseEngineDebugClient::decode(QDataStream &ds,
135 QVariantList &o,
136 bool simple)
137 {
138 int count;
139 ds >> count;
140 for (int i = 0; i < count; i++) {
141 ObjectReference obj;
142 decode(ds, obj, simple);
143 o << QVariant::fromValue(obj);
144 }
145 }
146
decode(QDataStream & ds,ContextReference & c)147 void BaseEngineDebugClient::decode(QDataStream &ds,
148 ContextReference &c)
149 {
150 ds >> c.m_name >> c.m_debugId;
151
152 int contextCount;
153 ds >> contextCount;
154
155 for (int ii = 0; ii < contextCount && !ds.atEnd(); ++ii) {
156 c.m_contexts.append(ContextReference());
157 decode(ds, c.m_contexts.last());
158 }
159
160 int objectCount;
161 ds >> objectCount;
162
163 for (int ii = 0; ii < objectCount && !ds.atEnd(); ++ii) {
164 ObjectReference obj;
165 decode(ds, obj, true);
166 obj.m_contextDebugId = c.m_debugId;
167 c.m_objects << obj;
168 }
169 }
170
stateChanged(State state)171 void BaseEngineDebugClient::stateChanged(State state)
172 {
173 emit newState(state);
174 }
175
messageReceived(const QByteArray & data)176 void BaseEngineDebugClient::messageReceived(const QByteArray &data)
177 {
178 QPacket ds(dataStreamVersion(), data);
179 int queryId;
180 QByteArray type;
181 ds >> type >> queryId;
182
183 if (type == "OBJECT_CREATED") {
184 int engineId;
185 int objectId;
186 int parentId;
187 ds >> engineId >> objectId >> parentId;
188 emit newObject(engineId, objectId, parentId);
189 } else if (type == "LIST_ENGINES_R") {
190 int count;
191 ds >> count;
192 QList<EngineReference> engines;
193 engines.reserve(count);
194 for (int ii = 0; ii < count; ++ii) {
195 EngineReference eng;
196 ds >> eng.m_name;
197 ds >> eng.m_debugId;
198 engines << eng;
199 }
200 emit result(queryId, QVariant::fromValue(engines), type);
201 } else if (type == "LIST_OBJECTS_R") {
202 ContextReference rootContext;
203 if (!ds.atEnd())
204 decode(ds, rootContext);
205 emit result(queryId, QVariant::fromValue(rootContext), type);
206 } else if (type == "FETCH_OBJECT_R") {
207 ObjectReference object;
208 if (!ds.atEnd())
209 decode(ds, object, false);
210 emit result(queryId, QVariant::fromValue(object), type);
211 } else if (type == "FETCH_OBJECTS_FOR_LOCATION_R") {
212 QVariantList objects;
213 if (!ds.atEnd())
214 decode(ds, objects, false);
215 emit result(queryId, objects, type);
216 } else if (type == "EVAL_EXPRESSION_R") {;
217 QVariant exprResult;
218 ds >> exprResult;
219 emit result(queryId, exprResult, type);
220 } else if (type == "WATCH_PROPERTY_R" ||
221 type == "WATCH_OBJECT_R" ||
222 type == "WATCH_EXPR_OBJECT_R" ||
223 type == "SET_BINDING_R" ||
224 type == "RESET_BINDING_R" ||
225 type == "SET_METHOD_BODY_R") {
226 bool valid;
227 ds >> valid;
228 emit result(queryId, valid, type);
229 } else if (type == "UPDATE_WATCH") {
230 int debugId;
231 QByteArray name;
232 QVariant value;
233 ds >> debugId >> name >> value;
234 emit valueChanged(debugId, name, value);
235 }
236 }
237
BaseEngineDebugClient(const QString & clientName,QmlDebugConnection * conn)238 BaseEngineDebugClient::BaseEngineDebugClient(const QString &clientName,
239 QmlDebugConnection *conn)
240 : QmlDebugClient(clientName, conn),
241 m_nextId(1)
242 {
243 setObjectName(clientName);
244 }
245
addWatch(const PropertyReference & property)246 quint32 BaseEngineDebugClient::addWatch(const PropertyReference &property)
247 {
248 quint32 id = 0;
249 if (state() == Enabled) {
250 id = getId();
251 QPacket ds(dataStreamVersion());
252 ds << QByteArray("WATCH_PROPERTY") << id << property.m_objectDebugId
253 << property.m_name.toUtf8();
254 sendMessage(ds.data());
255 }
256 return id;
257 }
258
addWatch(const ContextReference &,const QString &)259 quint32 BaseEngineDebugClient::addWatch(const ContextReference &/*context*/,
260 const QString &/*id*/)
261 {
262 qWarning("QmlEngineDebugClient::addWatch(): Not implemented");
263 return 0;
264 }
265
addWatch(const ObjectReference & object,const QString & expr)266 quint32 BaseEngineDebugClient::addWatch(const ObjectReference &object,
267 const QString &expr)
268 {
269 quint32 id = 0;
270 if (state() == Enabled) {
271 id = getId();
272 QPacket ds(dataStreamVersion());
273 ds << QByteArray("WATCH_EXPR_OBJECT") << id << object.m_debugId << expr;
274 sendMessage(ds.data());
275 }
276 return id;
277 }
278
addWatch(int objectDebugId)279 quint32 BaseEngineDebugClient::addWatch(int objectDebugId)
280 {
281 quint32 id = 0;
282 if (state() == Enabled) {
283 id = getId();
284 QPacket ds(dataStreamVersion());
285 ds << QByteArray("WATCH_OBJECT") << id << objectDebugId;
286 sendMessage(ds.data());
287 }
288 return id;
289 }
290
addWatch(const FileReference &)291 quint32 BaseEngineDebugClient::addWatch(const FileReference &/*file*/)
292 {
293 qWarning("QmlEngineDebugClient::addWatch(): Not implemented");
294 return 0;
295 }
296
removeWatch(quint32 id)297 void BaseEngineDebugClient::removeWatch(quint32 id)
298 {
299 if (state() == Enabled) {
300 QPacket ds(dataStreamVersion());
301 ds << QByteArray("NO_WATCH") << id;
302 sendMessage(ds.data());
303 }
304 }
305
queryAvailableEngines()306 quint32 BaseEngineDebugClient::queryAvailableEngines()
307 {
308 quint32 id = 0;
309 if (state() == Enabled) {
310 id = getId();
311 QPacket ds(dataStreamVersion());
312 ds << QByteArray("LIST_ENGINES") << id;
313 sendMessage(ds.data());
314 }
315 return id;
316 }
317
queryRootContexts(const EngineReference & engine)318 quint32 BaseEngineDebugClient::queryRootContexts(const EngineReference &engine)
319 {
320 quint32 id = 0;
321 if (state() == Enabled && engine.m_debugId != -1) {
322 id = getId();
323 QPacket ds(dataStreamVersion());
324 ds << QByteArray("LIST_OBJECTS") << id << engine.m_debugId;
325 sendMessage(ds.data());
326 }
327 return id;
328 }
329
queryObject(int objectId)330 quint32 BaseEngineDebugClient::queryObject(int objectId)
331 {
332 quint32 id = 0;
333 if (state() == Enabled && objectId != -1) {
334 id = getId();
335 QPacket ds(dataStreamVersion());
336 ds << QByteArray("FETCH_OBJECT") << id << objectId << false <<
337 true;
338 sendMessage(ds.data());
339 }
340 return id;
341 }
342
queryObjectRecursive(int objectId)343 quint32 BaseEngineDebugClient::queryObjectRecursive(int objectId)
344 {
345 quint32 id = 0;
346 if (state() == Enabled && objectId != -1) {
347 id = getId();
348 QPacket ds(dataStreamVersion());
349 ds << QByteArray("FETCH_OBJECT") << id << objectId << true <<
350 true;
351 sendMessage(ds.data());
352 }
353 return id;
354 }
355
queryExpressionResult(int objectDebugId,const QString & expr,int engineId)356 quint32 BaseEngineDebugClient::queryExpressionResult(int objectDebugId,
357 const QString &expr,
358 int engineId)
359 {
360 quint32 id = 0;
361 if (state() == Enabled && objectDebugId != -1) {
362 id = getId();
363 QPacket ds(dataStreamVersion());
364 ds << QByteArray("EVAL_EXPRESSION") << id << objectDebugId << expr
365 << engineId;
366 sendMessage(ds.data());
367 }
368 return id;
369 }
370
setBindingForObject(int objectDebugId,const QString & propertyName,const QVariant & bindingExpression,bool isLiteralValue,QString source,int line)371 quint32 BaseEngineDebugClient::setBindingForObject(
372 int objectDebugId,
373 const QString &propertyName,
374 const QVariant &bindingExpression,
375 bool isLiteralValue,
376 QString source, int line)
377 {
378 quint32 id = 0;
379 if (state() == Enabled && objectDebugId != -1) {
380 id = getId();
381 QPacket ds(dataStreamVersion());
382 ds << QByteArray("SET_BINDING") << id << objectDebugId << propertyName
383 << bindingExpression << isLiteralValue << source << line;
384 sendMessage(ds.data());
385 }
386 return id;
387 }
388
resetBindingForObject(int objectDebugId,const QString & propertyName)389 quint32 BaseEngineDebugClient::resetBindingForObject(
390 int objectDebugId,
391 const QString &propertyName)
392 {
393 quint32 id = 0;
394 if (state() == Enabled && objectDebugId != -1) {
395 id = getId();
396 QPacket ds(dataStreamVersion());
397 ds << QByteArray("RESET_BINDING") << id << objectDebugId << propertyName;
398 sendMessage(ds.data());
399 }
400 return id;
401 }
402
setMethodBody(int objectDebugId,const QString & methodName,const QString & methodBody)403 quint32 BaseEngineDebugClient::setMethodBody(
404 int objectDebugId, const QString &methodName,
405 const QString &methodBody)
406 {
407 quint32 id = 0;
408 if (state() == Enabled && objectDebugId != -1) {
409 id = getId();
410 QPacket ds(dataStreamVersion());
411 ds << QByteArray("SET_METHOD_BODY") << id << objectDebugId
412 << methodName << methodBody;
413 sendMessage(ds.data());
414 }
415 return id;
416 }
417
queryObjectsForLocation(const QString & fileName,int lineNumber,int columnNumber)418 quint32 BaseEngineDebugClient::queryObjectsForLocation(
419 const QString &fileName, int lineNumber, int columnNumber)
420 {
421 quint32 id = 0;
422 if (state() == Enabled) {
423 id = getId();
424 QPacket ds(dataStreamVersion());
425 ds << QByteArray("FETCH_OBJECTS_FOR_LOCATION") << id <<
426 fileName << lineNumber << columnNumber << false <<
427 true;
428 sendMessage(ds.data());
429 }
430 return id;
431 }
432
433 } // namespace QmlDebug
434