Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
globalinspector.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "globalinspector.h"
5#include "highlight.h"
6#include "inspecttool.h"
7
8#include <private/qqmldebugserviceinterfaces_p.h>
9#include <private/qabstractanimation_p.h>
10#include <private/qqmlcomponent_p.h>
11#include <private/qqmldebugconnector_p.h>
12#include <private/qversionedpacket_p.h>
13
14#include <QtGui/qwindow.h>
15#if QT_CONFIG(regularexpression)
16# include <QtCore/qregularexpression.h>
17#endif
18//INSPECTOR SERVICE PROTOCOL
19// <HEADER><COMMAND><DATA>
20// <HEADER> : <type{request, response, event}><requestId/eventId>[<response_success_bool>]
21// <COMMAND> : {"enable", "disable", "select", "setAnimationSpeed",
22// "showAppOnTop", "createObject", "destroyObject", "moveObject"}
23// <DATA> : select: <debugIds_int_list>
24// setAnimationSpeed: <speed_real>
25// showAppOnTop: <set_bool>
26// createObject: <qml_string><parentId_int><imports_string_list><filename_string>
27// destroyObject: <debugId_int>
28// moveObject: <debugId_int><newParentId_int>
29// Response for "destroyObject" carries the <debugId_int> of the destroyed object.
30
32
33using QQmlDebugPacket = QVersionedPacket<QQmlDebugConnector>;
34
35const char REQUEST[] = "request";
36const char RESPONSE[] = "response";
37const char EVENT[] = "event";
38const char ENABLE[] = "enable";
39const char DISABLE[] = "disable";
40const char SELECT[] = "select";
41const char SET_ANIMATION_SPEED[] = "setAnimationSpeed";
42const char SHOW_APP_ON_TOP[] = "showAppOnTop";
43const char CREATE_OBJECT[] = "createObject";
44const char DESTROY_OBJECT[] = "destroyObject";
45const char MOVE_OBJECT[] = "moveObject";
46
47namespace QmlJSDebugger {
48
49void GlobalInspector::removeFromSelectedItems(QObject *object)
50{
51 if (QQuickItem *item = qobject_cast<QQuickItem*>(object)) {
52 if (m_selectedItems.removeOne(item))
53 delete m_highlightItems.take(item);
54 }
55}
56
57void GlobalInspector::setSelectedItems(const QList<QQuickItem *> &items)
58{
59 if (!syncSelectedItems(items))
60 return;
61
62 QList<QObject*> objectList;
63 objectList.reserve(items.size());
64 for (QQuickItem *item : items)
65 objectList << item;
66
67 sendCurrentObjects(objectList);
68}
69
71{
72 SelectionHighlight *highlightItem = m_highlightItems.value(item, 0);
73 if (highlightItem)
74 highlightItem->showName(point);
75}
76
77void GlobalInspector::sendCurrentObjects(const QList<QObject*> &objects)
78{
80
81 ds << QByteArray(EVENT) << m_eventId++ << QByteArray(SELECT);
82
83 QList<int> debugIds;
84 debugIds.reserve(objects.size());
85 for (QObject *object : objects)
86 debugIds << QQmlDebugService::idForObject(object);
87 ds << debugIds;
88
89 emit messageToClient(QQmlInspectorService::s_key, ds.data());
90}
91
92static bool reparentQmlObject(QObject *object, QObject *newParent)
93{
94 if (!newParent)
95 return false;
96
97 object->setParent(newParent);
98 QQuickItem *newParentItem = qobject_cast<QQuickItem*>(newParent);
100 if (newParentItem && item)
101 item->setParentItem(newParentItem);
102 return true;
103}
104
105class ObjectCreator : public QObject
106{
108public:
110 QObject(parent), m_component(engine), m_requestId(requestId)
111 {
113 }
114
115 void run(const QByteArray &qml, const QUrl &filename)
116 {
117 m_component.setData(qml, filename);
118 }
119
121 {
122 switch (status) {
124 emit result(m_requestId, false);
125 delete this;
126 return;
128 // Stuff might have changed. We have to lookup the parentContext again.
130 if (!parentContext) {
131 emit result(m_requestId, false);
132 } else {
133 QObject *newObject = m_component.create(parentContext);
134 if (newObject && reparentQmlObject(newObject, parent()))
135 emit result(m_requestId, true);
136 else
137 emit result(m_requestId, false);
138 }
139 deleteLater(); // The component might send more signals
140 return;
141 }
142 default:
143 break;
144 }
145 }
146
147signals:
148 void result(int requestId, bool success);
149
150private:
151 QQmlComponent m_component;
152 int m_requestId;
153};
154
155bool GlobalInspector::createQmlObject(int requestId, const QString &qml, QObject *parent,
156 const QStringList &importList, const QString &filename)
157{
158 if (!parent)
159 return false;
160
162 if (!parentContext)
163 return false;
164
165 QString imports;
166 for (const QString &s : importList)
167 imports += s + QLatin1Char('\n');
168
169 ObjectCreator *objectCreator = new ObjectCreator(requestId, parentContext->engine(), parent);
170 connect(objectCreator, &ObjectCreator::result, this, &GlobalInspector::sendResult);
171 objectCreator->run((imports + qml).toUtf8(), QUrl::fromLocalFile(filename));
172 return true;
173}
174
176{
177 m_windowInspectors.append(new QQuickWindowInspector(window, this));
178}
179
181{
182 for (QList<QmlJSDebugger::QQuickWindowInspector *>::Iterator i = m_windowInspectors.begin();
183 i != m_windowInspectors.end();) {
184 if ((*i)->quickWindow() == window) {
185 delete *i;
186 i = m_windowInspectors.erase(i);
187 } else {
188 ++i;
189 }
190 }
191}
192
194{
195 for (QmlJSDebugger::QQuickWindowInspector *inspector : std::as_const(m_windowInspectors)) {
196 if (inspector->quickWindow() == window)
197 inspector->setParentWindow(parentWindow);
198 }
199}
200
201bool GlobalInspector::syncSelectedItems(const QList<QQuickItem *> &items)
202{
203 bool selectionChanged = false;
204
205 // Disconnect and remove items that are no longer selected
206 const auto selectedItemsCopy = m_selectedItems;
207 for (QQuickItem *item : selectedItemsCopy) {
208 if (items.contains(item))
209 continue;
210
211 selectionChanged = true;
212 item->disconnect(this);
213 m_selectedItems.removeOne(item);
214 delete m_highlightItems.take(item);
215 }
216
217 // Connect and add newly selected items
218 for (QQuickItem *item : items) {
219 if (m_selectedItems.contains(item))
220 continue;
221
222 selectionChanged = true;
223 connect(item, &QObject::destroyed, this, &GlobalInspector::removeFromSelectedItems);
224 m_selectedItems.append(item);
225 for (QQuickWindowInspector *inspector : std::as_const(m_windowInspectors)) {
226 if (inspector->isEnabled() && inspector->quickWindow() == item->window()) {
227 m_highlightItems.insert(item, new SelectionHighlight(titleForItem(item), item,
228 inspector->overlay()));
229 break;
230 }
231 }
232 }
233
234 return selectionChanged;
235}
236
237QString GlobalInspector::titleForItem(QQuickItem *item) const
238{
239 QString className = QLatin1String(item->metaObject()->className());
240 QString objectStringId = idStringForObject(item);
241
242#if QT_CONFIG(regularexpression)
243 className.remove(QRegularExpression(QLatin1String("_QMLTYPE_\\d+")));
244 className.remove(QRegularExpression(QLatin1String("_QML_\\d+")));
245#endif
246 if (className.startsWith(QLatin1String("QQuick")))
247 className = className.mid(6);
248
249 QString constructedName;
250
251 if (!objectStringId.isEmpty()) {
252 constructedName = objectStringId + QLatin1String(" (") + className + QLatin1Char(')');
253 } else if (!item->objectName().isEmpty()) {
254 constructedName = item->objectName() + QLatin1String(" (") + className + QLatin1Char(')');
255 } else {
256 constructedName = className;
257 }
258
259 return constructedName;
260}
261
262QString GlobalInspector::idStringForObject(QObject *obj) const
263{
265 if (context) {
266 QQmlRefPointer<QQmlContextData> cdata = QQmlContextData::get(context);
267 if (cdata)
268 return cdata->findObjectId(obj);
269 }
270 return QString();
271}
272
274{
275 bool success = true;
277
279 ds >> type;
280
281 int requestId = -1;
282 if (type == REQUEST) {
283 QByteArray command;
284 ds >> requestId >> command;
285
286 if (command == ENABLE) {
287 for (QQuickWindowInspector *inspector : std::as_const(m_windowInspectors))
288 inspector->setEnabled(true);
289 success = !m_windowInspectors.isEmpty();
290 } else if (command == DISABLE) {
291 setSelectedItems(QList<QQuickItem*>());
292 for (QQuickWindowInspector *inspector : std::as_const(m_windowInspectors))
293 inspector->setEnabled(false);
294 success = !m_windowInspectors.isEmpty();
295 } else if (command == SELECT) {
296 QList<int> debugIds;
297 ds >> debugIds;
298
299 QList<QQuickItem *> selectedObjects;
300 for (int debugId : std::as_const(debugIds)) {
301 if (QQuickItem *obj =
302 qobject_cast<QQuickItem *>(QQmlDebugService::objectForId(debugId)))
303 selectedObjects << obj;
304 }
305 syncSelectedItems(selectedObjects);
306 } else if (command == SET_ANIMATION_SPEED) {
307 qreal speed;
308 ds >> speed;
309 QUnifiedTimer::instance()->setSlowModeEnabled(speed != 1.0);
310 QUnifiedTimer::instance()->setSlowdownFactor(speed);
311 } else if (command == SHOW_APP_ON_TOP) {
312 bool showOnTop;
313 ds >> showOnTop;
314 for (QmlJSDebugger::QQuickWindowInspector *inspector : std::as_const(m_windowInspectors))
315 inspector->setShowAppOnTop(showOnTop);
316 success = !m_windowInspectors.isEmpty();
317 } else if (command == CREATE_OBJECT) {
318 QString qml;
319 int parentId;
320 QString filename;
321 QStringList imports;
322 ds >> qml >> parentId >> imports >> filename;
324 if (createQmlObject(requestId, qml, parent, imports, filename))
325 return; // will callback for result
326 else {
327 success = false;
328 }
329 } else {
330 success = false;
331 }
332
333 } else if (command == DESTROY_OBJECT) {
334 int debugId;
335 ds >> debugId;
337 delete obj;
338 else
339 success = false;
340
341 } else if (command == MOVE_OBJECT) {
342 int debugId, newParent;
343 ds >> debugId >> newParent;
346 } else {
347 qWarning() << "Warning: Not handling command:" << command;
348 success = false;
349 }
350 } else {
351 qWarning() << "Warning: Not handling type:" << type << REQUEST;
352 success = false;
353 }
354
355 sendResult(requestId, success);
356}
357
358void GlobalInspector::sendResult(int requestId, bool success)
359{
361 rs << QByteArray(RESPONSE) << requestId << success;
362 emit messageToClient(QQmlInspectorService::s_key, rs.data());
363}
364
366{
367 // Everything else is parented
368 qDeleteAll(m_highlightItems);
369}
370
371}
372
374
375#include "moc_globalinspector.cpp"
376
377#include <globalinspector.moc>
\inmodule QtCore
Definition qbytearray.h:57
QGraphicsWidget * window() const
void setParentItem(QGraphicsItem *parent)
Sets this item's parent item to newParent.
qsizetype size() const noexcept
Definition qlist.h:397
bool removeOne(const AT &t)
Definition qlist.h:598
void append(parameter_type t)
Definition qlist.h:458
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
void deleteLater()
\threadsafe
Definition qobject.cpp:2435
const QByteArray & data() const
Returns a reference to the raw packet data.
Definition qpacket.cpp:77
\inmodule QtCore\reentrant
Definition qpoint.h:217
The QQmlComponent class encapsulates a QML component definition.
Status
\qmltype Component \instantiates QQmlComponent\inqmlmodule QtQml
void setData(const QByteArray &, const QUrl &baseUrl)
Sets the QQmlComponent to use the given QML data.
virtual QObject * create(QQmlContext *context=nullptr)
Create an object instance from this component, within the specified context.
void statusChanged(QQmlComponent::Status)
Emitted whenever the component's status changes.
static QQmlRefPointer< QQmlContextData > get(QQmlContext *context)
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
QQmlEngine * engine() const
Return the context's QQmlEngine, or \nullptr if the context has no QQmlEngine or the QQmlEngine was d...
static QObject * objectForId(int id)
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
static QQmlContext * contextForObject(const QObject *)
Returns the QQmlContext for the object, or nullptr if no context has been set.
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
\inmodule QtCore \reentrant
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QUnifiedTimer * instance()
\inmodule QtCore
Definition qurl.h:94
static QUrl fromLocalFile(const QString &localfile)
Returns a QUrl representation of localFile, interpreted as a local file.
Definition qurl.cpp:3368
\inmodule QtGui
Definition qwindow.h:63
void processMessage(const QByteArray &message)
void setParentWindow(QQuickWindow *window, QWindow *parentWindow)
void removeWindow(QQuickWindow *window)
void messageToClient(const QString &name, const QByteArray &data)
void showSelectedItemName(QQuickItem *item, const QPointF &point)
void setSelectedItems(const QList< QQuickItem * > &items)
void addWindow(QQuickWindow *window)
void run(const QByteArray &qml, const QUrl &filename)
ObjectCreator(int requestId, QQmlEngine *engine, QObject *parent)
void result(int requestId, bool success)
void tryCreateObject(QQmlComponent::Status status)
void showName(const QPointF &displayPoint)
qDeleteAll(list.begin(), list.end())
const char EVENT[]
const char SET_ANIMATION_SPEED[]
const char CREATE_OBJECT[]
const char SHOW_APP_ON_TOP[]
const char MOVE_OBJECT[]
const char DESTROY_OBJECT[]
const char REQUEST[]
const char SELECT[]
const char RESPONSE[]
const char ENABLE[]
const char DISABLE[]
Combined button and popup list for selecting options.
static bool reparentQmlObject(QObject *object, QObject *newParent)
static void * context
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
QNearFieldTarget::RequestId requestId
#define qWarning
Definition qlogging.h:166
GLuint object
[3]
GLenum type
GLuint GLsizei const GLchar * message
GLhandleARB obj
[2]
GLdouble s
[6]
Definition qopenglext.h:235
GLuint64EXT * result
[6]
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:75
QQuickItem * qobject_cast< QQuickItem * >(QObject *o)
Definition qquickitem.h:492
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define Q_OBJECT
#define signals
#define emit
double qreal
Definition qtypes.h:187
const char className[16]
[1]
Definition qwizard.cpp:100
QGraphicsItem * item
QList< QTreeWidgetItem * > items
aWidget window() -> setWindowTitle("New Window Title")
[2]
QJSEngine engine
[0]
\inmodule QtCore \reentrant
Definition qchar.h:18
bool contains(const AT &t) const noexcept
Definition qlist.h:45