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 | |
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 | |
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 | |
73 | QQmlEngineDebugClient::QQmlEngineDebugClient(QQmlDebugConnection *connection) : |
74 | QQmlDebugClient(*new QQmlEngineDebugClientPrivate(connection)) |
75 | { |
76 | } |
77 | |
78 | QQmlEngineDebugClientPrivate::QQmlEngineDebugClientPrivate(QQmlDebugConnection *connection) : |
79 | QQmlDebugClientPrivate (QLatin1String("QmlDebugger" ), connection) |
80 | { |
81 | } |
82 | |
83 | |
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(message: ds.data()); |
95 | *success = true; |
96 | } |
97 | return id; |
98 | } |
99 | |
100 | qint32 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 | |
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(message: ds.data()); |
119 | *success = true; |
120 | } |
121 | return id; |
122 | } |
123 | |
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(message: ds.data()); |
134 | *success = true; |
135 | } |
136 | return id; |
137 | } |
138 | |
139 | qint32 QQmlEngineDebugClient::addWatch( |
140 | const QQmlEngineDebugFileReference &, bool *success) |
141 | { |
142 | *success = false; |
143 | qWarning(msg: "QQmlEngineDebugClient::addWatch(): Not implemented" ); |
144 | return -1; |
145 | } |
146 | |
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(message: ds.data()); |
154 | *success = true; |
155 | } |
156 | } |
157 | |
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(message: ds.data()); |
169 | *success = true; |
170 | } |
171 | return id; |
172 | } |
173 | |
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(message: ds.data()); |
186 | *success = true; |
187 | } |
188 | return id; |
189 | } |
190 | |
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(message: ds.data()); |
203 | *success = true; |
204 | } |
205 | return id; |
206 | } |
207 | |
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(message: ds.data()); |
221 | *success = true; |
222 | } |
223 | return id; |
224 | } |
225 | |
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(message: ds.data()); |
238 | *success = true; |
239 | } |
240 | return id; |
241 | } |
242 | |
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(message: ds.data()); |
256 | *success = true; |
257 | } |
258 | return id; |
259 | } |
260 | |
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(message: ds.data()); |
274 | *success = true; |
275 | } |
276 | return id; |
277 | } |
278 | |
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(message: ds.data()); |
291 | *success = true; |
292 | } |
293 | return id; |
294 | } |
295 | |
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(message: ds.data()); |
312 | *success = true; |
313 | } |
314 | return id; |
315 | } |
316 | |
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(message: ds.data()); |
329 | *success = true; |
330 | } |
331 | return id; |
332 | } |
333 | |
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(message: ds.data()); |
346 | *success = true; |
347 | } |
348 | return id; |
349 | } |
350 | |
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(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 | |
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, o&: obj, simple); |
422 | o << obj; |
423 | } |
424 | } |
425 | |
426 | QList<QQmlEngineDebugEngineReference> QQmlEngineDebugClient::engines() const |
427 | { |
428 | Q_D(const QQmlEngineDebugClient); |
429 | return d->engines; |
430 | } |
431 | |
432 | QQmlEngineDebugContextReference QQmlEngineDebugClient::rootContext() const |
433 | { |
434 | Q_D(const QQmlEngineDebugClient); |
435 | return d->rootContext; |
436 | } |
437 | |
438 | QQmlEngineDebugObjectReference QQmlEngineDebugClient::object() const |
439 | { |
440 | Q_D(const QQmlEngineDebugClient); |
441 | return d->object; |
442 | } |
443 | |
444 | QList<QQmlEngineDebugObjectReference> QQmlEngineDebugClient::objects() const |
445 | { |
446 | Q_D(const QQmlEngineDebugClient); |
447 | return d->objects; |
448 | } |
449 | |
450 | QVariant QQmlEngineDebugClient::resultExpr() const |
451 | { |
452 | Q_D(const QQmlEngineDebugClient); |
453 | return d->exprResult; |
454 | } |
455 | |
456 | bool QQmlEngineDebugClient::valid() const |
457 | { |
458 | Q_D(const QQmlEngineDebugClient); |
459 | return d->valid; |
460 | } |
461 | |
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(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 | |
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, 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 | |
562 | qint32 QQmlEngineDebugClient::getId() |
563 | { |
564 | Q_D(QQmlEngineDebugClient); |
565 | return d->nextId++; |
566 | } |
567 | |
568 | QT_END_NAMESPACE |
569 | |