1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 
29 #include "qqmlenginedebugclient_p_p.h"
30 #include <private/qqmldebugconnection_p.h>
31 
32 QT_BEGIN_NAMESPACE
33 
34 struct QQmlObjectData {
35     QUrl url;
36     qint32 lineNumber = -1;
37     qint32 columnNumber = -1;
38     QString idString;
39     QString objectName;
40     QString objectType;
41     qint32 objectId = -1;
42     qint32 contextId = -1;
43     qint32 parentId = -1;
44 };
45 
operator >>(QPacket & ds,QQmlObjectData & data)46 QPacket &operator>>(QPacket &ds, QQmlObjectData &data)
47 {
48     ds >> data.url >> data.lineNumber >> data.columnNumber >> data.idString
49        >> data.objectName >> data.objectType >> data.objectId >> data.contextId
50        >> data.parentId;
51     return ds;
52 }
53 
54 struct QQmlObjectProperty {
55     enum Type { Unknown, Basic, Object, List, SignalProperty };
56     Type type = Unknown;
57     QString name;
58     QVariant value;
59     QString valueTypeName;
60     QString binding;
61     bool hasNotifySignal = false;
62 };
63 
operator >>(QPacket & ds,QQmlObjectProperty & data)64 QPacket &operator>>(QPacket &ds, QQmlObjectProperty &data)
65 {
66     qint32 type;
67     ds >> type >> data.name >> data.value >> data.valueTypeName
68        >> data.binding >> data.hasNotifySignal;
69     data.type = QQmlObjectProperty::Type(type);
70     return ds;
71 }
72 
QQmlEngineDebugClient(QQmlDebugConnection * connection)73 QQmlEngineDebugClient::QQmlEngineDebugClient(QQmlDebugConnection *connection) :
74     QQmlDebugClient(*new QQmlEngineDebugClientPrivate(connection))
75 {
76 }
77 
QQmlEngineDebugClientPrivate(QQmlDebugConnection * connection)78 QQmlEngineDebugClientPrivate::QQmlEngineDebugClientPrivate(QQmlDebugConnection *connection) :
79     QQmlDebugClientPrivate (QLatin1String("QmlDebugger"), connection)
80 {
81 }
82 
83 
addWatch(const QQmlEngineDebugPropertyReference & property,bool * success)84 qint32 QQmlEngineDebugClient::addWatch(
85         const QQmlEngineDebugPropertyReference &property, bool *success)
86 {
87     qint32 id = -1;
88     *success = false;
89     if (state() == QQmlDebugClient::Enabled) {
90         id = getId();
91         QPacket ds(connection()->currentDataStreamVersion());
92         ds << QByteArray("WATCH_PROPERTY") << id << property.objectDebugId
93            << property.name.toUtf8();
94         sendMessage(ds.data());
95         *success = true;
96     }
97     return id;
98 }
99 
addWatch(const QQmlEngineDebugContextReference &,const QString &,bool * success)100 qint32 QQmlEngineDebugClient::addWatch(
101         const QQmlEngineDebugContextReference &, const QString &, bool *success)
102 {
103     *success = false;
104     qWarning("QQmlEngineDebugClient::addWatch(): Not implemented");
105     return -1;
106 }
107 
addWatch(const QQmlEngineDebugObjectReference & object,const QString & expr,bool * success)108 qint32 QQmlEngineDebugClient::addWatch(
109         const QQmlEngineDebugObjectReference &object, const QString &expr,
110         bool *success)
111 {
112     qint32 id = -1;
113     *success = false;
114     if (state() == QQmlDebugClient::Enabled) {
115         id = getId();
116         QPacket ds(connection()->currentDataStreamVersion());
117         ds << QByteArray("WATCH_EXPR_OBJECT") << id << object.debugId << expr;
118         sendMessage(ds.data());
119         *success = true;
120     }
121     return id;
122 }
123 
addWatch(const QQmlEngineDebugObjectReference & object,bool * success)124 qint32 QQmlEngineDebugClient::addWatch(
125         const QQmlEngineDebugObjectReference &object, bool *success)
126 {
127     qint32 id = -1;
128     *success = false;
129     if (state() == QQmlDebugClient::Enabled) {
130         id = getId();
131         QPacket ds(connection()->currentDataStreamVersion());
132         ds << QByteArray("WATCH_OBJECT") << id << object.debugId;
133         sendMessage(ds.data());
134         *success = true;
135     }
136     return id;
137 }
138 
addWatch(const QQmlEngineDebugFileReference &,bool * success)139 qint32 QQmlEngineDebugClient::addWatch(
140         const QQmlEngineDebugFileReference &,  bool *success)
141 {
142     *success = false;
143     qWarning("QQmlEngineDebugClient::addWatch(): Not implemented");
144     return -1;
145 }
146 
removeWatch(qint32 id,bool * success)147 void QQmlEngineDebugClient::removeWatch(qint32 id, bool *success)
148 {
149     *success = false;
150     if (state() == QQmlDebugClient::Enabled) {
151         QPacket ds(connection()->currentDataStreamVersion());
152         ds << QByteArray("NO_WATCH") << id;
153         sendMessage(ds.data());
154         *success = true;
155     }
156 }
157 
queryAvailableEngines(bool * success)158 qint32 QQmlEngineDebugClient::queryAvailableEngines(bool *success)
159 {
160     Q_D(QQmlEngineDebugClient);
161     d->engines.clear();
162     qint32 id = -1;
163     *success = false;
164     if (state() == QQmlDebugClient::Enabled) {
165         id = getId();
166         QPacket ds(connection()->currentDataStreamVersion());
167         ds << QByteArray("LIST_ENGINES") << id;
168         sendMessage(ds.data());
169         *success = true;
170     }
171     return id;
172 }
173 
queryRootContexts(const QQmlEngineDebugEngineReference & engine,bool * success)174 qint32 QQmlEngineDebugClient::queryRootContexts(
175         const QQmlEngineDebugEngineReference &engine, bool *success)
176 {
177     Q_D(QQmlEngineDebugClient);
178     d->rootContext = QQmlEngineDebugContextReference();
179     qint32 id = -1;
180     *success = false;
181     if (state() == QQmlDebugClient::Enabled && engine.debugId != -1) {
182         id = getId();
183         QPacket ds(connection()->currentDataStreamVersion());
184         ds << QByteArray("LIST_OBJECTS") << id << engine.debugId;
185         sendMessage(ds.data());
186         *success = true;
187     }
188     return id;
189 }
190 
queryObject(const QQmlEngineDebugObjectReference & object,bool * success)191 qint32 QQmlEngineDebugClient::queryObject(
192         const QQmlEngineDebugObjectReference &object, bool *success)
193 {
194     Q_D(QQmlEngineDebugClient);
195     d->object = QQmlEngineDebugObjectReference();
196     qint32 id = -1;
197     *success = false;
198     if (state() == QQmlDebugClient::Enabled && object.debugId != -1) {
199         id = getId();
200         QPacket ds(connection()->currentDataStreamVersion());
201         ds << QByteArray("FETCH_OBJECT") << id << object.debugId << false << true;
202         sendMessage(ds.data());
203         *success = true;
204     }
205     return id;
206 }
207 
queryObjectsForLocation(const QString & file,qint32 lineNumber,qint32 columnNumber,bool * success)208 qint32 QQmlEngineDebugClient::queryObjectsForLocation(
209         const QString &file, qint32 lineNumber, qint32 columnNumber, bool *success)
210 {
211     Q_D(QQmlEngineDebugClient);
212     d->objects.clear();
213     qint32 id = -1;
214     *success = false;
215     if (state() == QQmlDebugClient::Enabled) {
216         id = getId();
217         QPacket ds(connection()->currentDataStreamVersion());
218         ds << QByteArray("FETCH_OBJECTS_FOR_LOCATION") << id << file << lineNumber
219            << columnNumber << false << true;
220         sendMessage(ds.data());
221         *success = true;
222     }
223     return id;
224 }
225 
queryObjectRecursive(const QQmlEngineDebugObjectReference & object,bool * success)226 qint32 QQmlEngineDebugClient::queryObjectRecursive(
227         const QQmlEngineDebugObjectReference &object, bool *success)
228 {
229     Q_D(QQmlEngineDebugClient);
230     d->object = QQmlEngineDebugObjectReference();
231     qint32 id = -1;
232     *success = false;
233     if (state() == QQmlDebugClient::Enabled && object.debugId != -1) {
234         id = getId();
235         QPacket ds(connection()->currentDataStreamVersion());
236         ds << QByteArray("FETCH_OBJECT") << id << object.debugId << true << true;
237         sendMessage(ds.data());
238         *success = true;
239     }
240     return id;
241 }
242 
queryObjectsForLocationRecursive(const QString & file,qint32 lineNumber,qint32 columnNumber,bool * success)243 qint32 QQmlEngineDebugClient::queryObjectsForLocationRecursive(const QString &file,
244         qint32 lineNumber, qint32 columnNumber, bool *success)
245 {
246     Q_D(QQmlEngineDebugClient);
247     d->objects.clear();
248     qint32 id = -1;
249     *success = false;
250     if (state() == QQmlDebugClient::Enabled) {
251         id = getId();
252         QPacket ds(connection()->currentDataStreamVersion());
253         ds << QByteArray("FETCH_OBJECTS_FOR_LOCATION") << id << file << lineNumber
254            << columnNumber << true << true;
255         sendMessage(ds.data());
256         *success = true;
257     }
258     return id;
259 }
260 
queryExpressionResult(qint32 objectDebugId,const QString & expr,bool * success)261 qint32 QQmlEngineDebugClient::queryExpressionResult(
262         qint32 objectDebugId, const QString &expr, bool *success)
263 {
264     Q_D(QQmlEngineDebugClient);
265     d->exprResult = QVariant();
266     qint32 id = -1;
267     *success = false;
268     if (state() == QQmlDebugClient::Enabled) {
269         id = getId();
270         QPacket ds(connection()->currentDataStreamVersion());
271         ds << QByteArray("EVAL_EXPRESSION") << id << objectDebugId << expr
272            << engines()[0].debugId;
273         sendMessage(ds.data());
274         *success = true;
275     }
276     return id;
277 }
278 
queryExpressionResultBC(qint32 objectDebugId,const QString & expr,bool * success)279 qint32 QQmlEngineDebugClient::queryExpressionResultBC(
280         qint32 objectDebugId, const QString &expr, bool *success)
281 {
282     Q_D(QQmlEngineDebugClient);
283     d->exprResult = QVariant();
284     qint32 id = -1;
285     *success = false;
286     if (state() == QQmlDebugClient::Enabled) {
287         id = getId();
288         QPacket ds(connection()->currentDataStreamVersion());
289         ds << QByteArray("EVAL_EXPRESSION") << id << objectDebugId << expr;
290         sendMessage(ds.data());
291         *success = true;
292     }
293     return id;
294 }
295 
setBindingForObject(qint32 objectDebugId,const QString & propertyName,const QVariant & bindingExpression,bool isLiteralValue,const QString & source,qint32 line,bool * success)296 qint32 QQmlEngineDebugClient::setBindingForObject(
297         qint32 objectDebugId,
298         const QString &propertyName,
299         const QVariant &bindingExpression,
300         bool isLiteralValue,
301         const QString &source, qint32 line,
302         bool *success)
303 {
304     qint32 id = -1;
305     *success = false;
306     if (state() == QQmlDebugClient::Enabled && objectDebugId != -1) {
307         id = getId();
308         QPacket ds(connection()->currentDataStreamVersion());
309         ds << QByteArray("SET_BINDING") << id << objectDebugId << propertyName
310            << bindingExpression << isLiteralValue << source << line;
311         sendMessage(ds.data());
312         *success = true;
313     }
314     return id;
315 }
316 
resetBindingForObject(qint32 objectDebugId,const QString & propertyName,bool * success)317 qint32 QQmlEngineDebugClient::resetBindingForObject(
318         qint32 objectDebugId,
319         const QString &propertyName,
320         bool *success)
321 {
322     qint32 id = -1;
323     *success = false;
324     if (state() == QQmlDebugClient::Enabled && objectDebugId != -1) {
325         id = getId();
326         QPacket ds(connection()->currentDataStreamVersion());
327         ds << QByteArray("RESET_BINDING") << id << objectDebugId << propertyName;
328         sendMessage(ds.data());
329         *success = true;
330     }
331     return id;
332 }
333 
setMethodBody(qint32 objectDebugId,const QString & methodName,const QString & methodBody,bool * success)334 qint32 QQmlEngineDebugClient::setMethodBody(
335         qint32 objectDebugId, const QString &methodName,
336         const QString &methodBody, bool *success)
337 {
338     qint32 id = -1;
339     *success = false;
340     if (state() == QQmlDebugClient::Enabled && objectDebugId != -1) {
341         id = getId();
342         QPacket ds(connection()->currentDataStreamVersion());
343         ds << QByteArray("SET_METHOD_BODY") << id << objectDebugId
344            << methodName << methodBody;
345         sendMessage(ds.data());
346         *success = true;
347     }
348     return id;
349 }
350 
decode(QPacket & ds,QQmlEngineDebugObjectReference & o,bool simple)351 void QQmlEngineDebugClient::decode(QPacket &ds,
352                                    QQmlEngineDebugObjectReference &o,
353                                    bool simple)
354 {
355     QQmlObjectData data;
356     ds >> data;
357     o.debugId = data.objectId;
358     o.className = data.objectType;
359     o.idString = data.idString;
360     o.name = data.objectName;
361     o.source.url = data.url;
362     o.source.lineNumber = data.lineNumber;
363     o.source.columnNumber = data.columnNumber;
364     o.contextDebugId = data.contextId;
365 
366     if (simple)
367         return;
368 
369     qint32 childCount;
370     bool recur;
371     ds >> childCount >> recur;
372 
373     for (qint32 ii = 0; ii < childCount; ++ii) {
374         o.children.append(QQmlEngineDebugObjectReference());
375         decode(ds, o.children.last(), !recur);
376     }
377 
378     qint32 propCount;
379     ds >> propCount;
380 
381     for (qint32 ii = 0; ii < propCount; ++ii) {
382         QQmlObjectProperty data;
383         ds >> data;
384         QQmlEngineDebugPropertyReference prop;
385         prop.objectDebugId = o.debugId;
386         prop.name = data.name;
387         prop.binding = data.binding;
388         prop.hasNotifySignal = data.hasNotifySignal;
389         prop.valueTypeName = data.valueTypeName;
390         switch (data.type) {
391         case QQmlObjectProperty::Basic:
392         case QQmlObjectProperty::List:
393         case QQmlObjectProperty::SignalProperty:
394         {
395             prop.value = data.value;
396             break;
397         }
398         case QQmlObjectProperty::Object:
399         {
400             QQmlEngineDebugObjectReference obj;
401             obj.name = data.value.toString();
402             obj.className = prop.valueTypeName;
403             prop.value = QVariant::fromValue(obj);
404             break;
405         }
406         case QQmlObjectProperty::Unknown:
407             break;
408         }
409         o.properties << prop;
410     }
411 }
412 
decode(QPacket & ds,QList<QQmlEngineDebugObjectReference> & o,bool simple)413 void QQmlEngineDebugClient::decode(QPacket &ds,
414                                    QList<QQmlEngineDebugObjectReference> &o,
415                                    bool simple)
416 {
417     qint32 count;
418     ds >> count;
419     for (qint32 i = 0; i < count; i++) {
420         QQmlEngineDebugObjectReference obj;
421         decode(ds, obj, simple);
422         o << obj;
423     }
424 }
425 
engines() const426 QList<QQmlEngineDebugEngineReference> QQmlEngineDebugClient::engines() const
427 {
428     Q_D(const QQmlEngineDebugClient);
429     return d->engines;
430 }
431 
rootContext() const432 QQmlEngineDebugContextReference QQmlEngineDebugClient::rootContext() const
433 {
434     Q_D(const QQmlEngineDebugClient);
435     return d->rootContext;
436 }
437 
object() const438 QQmlEngineDebugObjectReference QQmlEngineDebugClient::object() const
439 {
440     Q_D(const QQmlEngineDebugClient);
441     return d->object;
442 }
443 
objects() const444 QList<QQmlEngineDebugObjectReference> QQmlEngineDebugClient::objects() const
445 {
446     Q_D(const QQmlEngineDebugClient);
447     return d->objects;
448 }
449 
resultExpr() const450 QVariant QQmlEngineDebugClient::resultExpr() const
451 {
452     Q_D(const QQmlEngineDebugClient);
453     return d->exprResult;
454 }
455 
valid() const456 bool QQmlEngineDebugClient::valid() const
457 {
458     Q_D(const QQmlEngineDebugClient);
459     return d->valid;
460 }
461 
decode(QPacket & ds,QQmlEngineDebugContextReference & c)462 void QQmlEngineDebugClient::decode(QPacket &ds,
463                                    QQmlEngineDebugContextReference &c)
464 {
465     ds >> c.name >> c.debugId;
466 
467     qint32 contextCount;
468     ds >> contextCount;
469 
470     for (qint32 ii = 0; ii < contextCount; ++ii) {
471         c.contexts.append(QQmlEngineDebugContextReference());
472         decode(ds, c.contexts.last());
473     }
474 
475     qint32 objectCount;
476     ds >> objectCount;
477 
478     for (qint32 ii = 0; ii < objectCount; ++ii) {
479         QQmlEngineDebugObjectReference obj;
480         decode(ds, obj, true);
481 
482         obj.contextDebugId = c.debugId;
483         c.objects << obj;
484     }
485 }
486 
messageReceived(const QByteArray & data)487 void QQmlEngineDebugClient::messageReceived(const QByteArray &data)
488 {
489     Q_D(QQmlEngineDebugClient);
490     d->valid = false;
491     QPacket ds(connection()->currentDataStreamVersion(), data);
492 
493     qint32 queryId;
494     QByteArray type;
495     ds >> type >> queryId;
496 
497     //qDebug() << "QQmlEngineDebugPrivate::message()" << type;
498 
499     if (type == "LIST_ENGINES_R") {
500         qint32 count;
501         ds >> count;
502 
503         d->engines.clear();
504         for (qint32 ii = 0; ii < count; ++ii) {
505             QQmlEngineDebugEngineReference eng;
506             ds >> eng.name;
507             ds >> eng.debugId;
508             d->engines << eng;
509         }
510     } else if (type == "LIST_OBJECTS_R") {
511         if (!ds.atEnd())
512             decode(ds, d->rootContext);
513 
514     } else if (type == "FETCH_OBJECT_R") {
515         if (!ds.atEnd())
516             decode(ds, d->object, false);
517 
518     } else if (type == "FETCH_OBJECTS_FOR_LOCATION_R") {
519         if (!ds.atEnd())
520             decode(ds, d->objects, false);
521 
522     } else if (type == "EVAL_EXPRESSION_R") {;
523         ds >> d->exprResult;
524 
525     } else if (type == "WATCH_PROPERTY_R") {
526         ds >> d->valid;
527 
528     } else if (type == "WATCH_OBJECT_R") {
529         ds >> d->valid;
530 
531     } else if (type == "WATCH_EXPR_OBJECT_R") {
532         ds >> d->valid;
533 
534     } else if (type == "UPDATE_WATCH") {
535         qint32 debugId;
536         QByteArray name;
537         QVariant value;
538         ds >> debugId >> name >> value;
539         emit valueChanged(name, value);
540         return;
541 
542     } else if (type == "OBJECT_CREATED") {
543         qint32 engineId;
544         qint32 objectId;
545         qint32 parentId;
546         ds >> engineId >> objectId >> parentId;
547         emit newObject(objectId);
548         return;
549     } else if (type == "SET_BINDING_R") {
550         ds >> d->valid;
551     } else if (type == "RESET_BINDING_R") {
552         ds >> d->valid;
553     } else if (type == "SET_METHOD_BODY_R") {
554         ds >> d->valid;
555     } else if (type == "NO_WATCH_R") {
556         ds >> d->valid;
557     }
558     emit result();
559 }
560 
561 
getId()562 qint32 QQmlEngineDebugClient::getId()
563 {
564     Q_D(QQmlEngineDebugClient);
565     return d->nextId++;
566 }
567 
568 QT_END_NAMESPACE
569