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