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
32QT_BEGIN_NAMESPACE
33
34struct 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
46QPacket &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
54struct 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
64QPacket &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
73QQmlEngineDebugClient::QQmlEngineDebugClient(QQmlDebugConnection *connection) :
74 QQmlDebugClient(*new QQmlEngineDebugClientPrivate(connection))
75{
76}
77
78QQmlEngineDebugClientPrivate::QQmlEngineDebugClientPrivate(QQmlDebugConnection *connection) :
79 QQmlDebugClientPrivate (QLatin1String("QmlDebugger"), connection)
80{
81}
82
83
84qint32 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(message: ds.data());
95 *success = true;
96 }
97 return id;
98}
99
100qint32 QQmlEngineDebugClient::addWatch(
101 const QQmlEngineDebugContextReference &, const QString &, bool *success)
102{
103 *success = false;
104 qWarning(msg: "QQmlEngineDebugClient::addWatch(): Not implemented");
105 return -1;
106}
107
108qint32 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(message: ds.data());
119 *success = true;
120 }
121 return id;
122}
123
124qint32 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(message: ds.data());
134 *success = true;
135 }
136 return id;
137}
138
139qint32 QQmlEngineDebugClient::addWatch(
140 const QQmlEngineDebugFileReference &, bool *success)
141{
142 *success = false;
143 qWarning(msg: "QQmlEngineDebugClient::addWatch(): Not implemented");
144 return -1;
145}
146
147void 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(message: ds.data());
154 *success = true;
155 }
156}
157
158qint32 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(message: ds.data());
169 *success = true;
170 }
171 return id;
172}
173
174qint32 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(message: ds.data());
186 *success = true;
187 }
188 return id;
189}
190
191qint32 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(message: ds.data());
203 *success = true;
204 }
205 return id;
206}
207
208qint32 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(message: ds.data());
221 *success = true;
222 }
223 return id;
224}
225
226qint32 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(message: ds.data());
238 *success = true;
239 }
240 return id;
241}
242
243qint32 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(message: ds.data());
256 *success = true;
257 }
258 return id;
259}
260
261qint32 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(message: ds.data());
274 *success = true;
275 }
276 return id;
277}
278
279qint32 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(message: ds.data());
291 *success = true;
292 }
293 return id;
294}
295
296qint32 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(message: ds.data());
312 *success = true;
313 }
314 return id;
315}
316
317qint32 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(message: ds.data());
329 *success = true;
330 }
331 return id;
332}
333
334qint32 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(message: ds.data());
346 *success = true;
347 }
348 return id;
349}
350
351void 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(t: QQmlEngineDebugObjectReference());
375 decode(ds, o&: o.children.last(), simple: !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(value: obj);
404 break;
405 }
406 case QQmlObjectProperty::Unknown:
407 break;
408 }
409 o.properties << prop;
410 }
411}
412
413void 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, o&: obj, simple);
422 o << obj;
423 }
424}
425
426QList<QQmlEngineDebugEngineReference> QQmlEngineDebugClient::engines() const
427{
428 Q_D(const QQmlEngineDebugClient);
429 return d->engines;
430}
431
432QQmlEngineDebugContextReference QQmlEngineDebugClient::rootContext() const
433{
434 Q_D(const QQmlEngineDebugClient);
435 return d->rootContext;
436}
437
438QQmlEngineDebugObjectReference QQmlEngineDebugClient::object() const
439{
440 Q_D(const QQmlEngineDebugClient);
441 return d->object;
442}
443
444QList<QQmlEngineDebugObjectReference> QQmlEngineDebugClient::objects() const
445{
446 Q_D(const QQmlEngineDebugClient);
447 return d->objects;
448}
449
450QVariant QQmlEngineDebugClient::resultExpr() const
451{
452 Q_D(const QQmlEngineDebugClient);
453 return d->exprResult;
454}
455
456bool QQmlEngineDebugClient::valid() const
457{
458 Q_D(const QQmlEngineDebugClient);
459 return d->valid;
460}
461
462void 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(t: QQmlEngineDebugContextReference());
472 decode(ds, c&: 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, o&: obj, simple: true);
481
482 obj.contextDebugId = c.debugId;
483 c.objects << obj;
484 }
485}
486
487void 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, c&: d->rootContext);
513
514 } else if (type == "FETCH_OBJECT_R") {
515 if (!ds.atEnd())
516 decode(ds, o&: d->object, simple: false);
517
518 } else if (type == "FETCH_OBJECTS_FOR_LOCATION_R") {
519 if (!ds.atEnd())
520 decode(ds, o&: d->objects, simple: 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
562qint32 QQmlEngineDebugClient::getId()
563{
564 Q_D(QQmlEngineDebugClient);
565 return d->nextId++;
566}
567
568QT_END_NAMESPACE
569

source code of qtdeclarative/src/qmldebug/qqmlenginedebugclient.cpp