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