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