1// Copyright (C) 2018 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 "qqmlpreviewservice.h"
5
6#include <QtCore/qpointer.h>
7#include <QtQml/qqmlengine.h>
8#include <QtQml/qqmlcomponent.h>
9#include <QtQuick/qquickwindow.h>
10#include <QtQuick/qquickitem.h>
11#include <QtGui/qguiapplication.h>
12
13#include <private/qquickpixmapcache_p.h>
14#include <private/qqmldebugconnector_p.h>
15#include <private/qversionedpacket_p.h>
16
17QT_BEGIN_NAMESPACE
18
19const QString QQmlPreviewServiceImpl::s_key = QStringLiteral("QmlPreview");
20using QQmlDebugPacket = QVersionedPacket<QQmlDebugConnector>;
21
22QQmlPreviewServiceImpl::QQmlPreviewServiceImpl(QObject *parent) :
23 QQmlDebugService(s_key, 1.0f, parent)
24{
25 m_loader.reset(other: new QQmlPreviewFileLoader(this));
26 connect(sender: this, signal: &QQmlPreviewServiceImpl::load,
27 context: m_loader.data(), slot: &QQmlPreviewFileLoader::whitelist, type: Qt::DirectConnection);
28 connect(sender: this, signal: &QQmlPreviewServiceImpl::load, context: &m_handler, slot: &QQmlPreviewHandler::loadUrl);
29 connect(sender: this, signal: &QQmlPreviewServiceImpl::rerun, context: &m_handler, slot: &QQmlPreviewHandler::rerun);
30 connect(sender: this, signal: &QQmlPreviewServiceImpl::zoom, context: &m_handler, slot: &QQmlPreviewHandler::zoom);
31 connect(sender: &m_handler, signal: &QQmlPreviewHandler::error, context: this, slot: &QQmlPreviewServiceImpl::forwardError,
32 type: Qt::DirectConnection);
33 connect(sender: &m_handler, signal: &QQmlPreviewHandler::fps, context: this, slot: &QQmlPreviewServiceImpl::forwardFps,
34 type: Qt::DirectConnection);
35}
36
37QQmlPreviewServiceImpl::~QQmlPreviewServiceImpl()
38{
39}
40
41void QQmlPreviewServiceImpl::messageReceived(const QByteArray &data)
42{
43 QQmlDebugPacket packet(data);
44 qint8 command;
45
46 packet >> command;
47 switch (command) {
48 case File: {
49 QString path;
50 QByteArray contents;
51 packet >> path >> contents;
52 emit file(file: path, contents);
53
54 // Replace the whole scene with the first file successfully loaded over the debug
55 // connection. This is an OK approximation of the root component, and if the client wants
56 // something specific, it will send an explicit Load anyway.
57 if (m_currentUrl.isEmpty() && path.endsWith(s: ".qml")) {
58 if (path.startsWith(c: ':'))
59 m_currentUrl = QUrl("qrc" + path);
60 else
61 m_currentUrl = QUrl::fromLocalFile(localfile: path);
62 emit load(url: m_currentUrl);
63 }
64 break;
65 }
66 case Directory: {
67 QString path;
68 QStringList entries;
69 packet >> path >> entries;
70 emit directory(file: path, entries);
71 break;
72 }
73 case Load: {
74 QUrl url;
75 packet >> url;
76 if (url.isEmpty())
77 url = m_currentUrl;
78 else
79 m_currentUrl = url;
80 emit load(url);
81 break;
82 }
83 case Error: {
84 QString file;
85 packet >> file;
86 emit error(file);
87 break;
88 }
89 case Rerun:
90 emit rerun();
91 break;
92 case ClearCache:
93 emit clearCache();
94 break;
95 case Zoom: {
96 float factor;
97 packet >> factor;
98 emit zoom(factor: static_cast<qreal>(factor));
99 break;
100 }
101 default:
102 forwardError(error: QString::fromLatin1(ba: "Invalid command: %1").arg(a: command));
103 break;
104 }
105}
106
107void QQmlPreviewServiceImpl::engineAboutToBeAdded(QJSEngine *engine)
108{
109 if (QQmlEngine *qmlEngine = qobject_cast<QQmlEngine *>(object: engine))
110 m_handler.addEngine(engine: qmlEngine);
111 emit attachedToEngine(engine);
112}
113
114void QQmlPreviewServiceImpl::engineAboutToBeRemoved(QJSEngine *engine)
115{
116 if (QQmlEngine *qmlEngine = qobject_cast<QQmlEngine *>(object: engine))
117 m_handler.removeEngine(engine: qmlEngine);
118 emit detachedFromEngine(engine);
119}
120
121void QQmlPreviewServiceImpl::stateChanged(QQmlDebugService::State state)
122{
123 m_fileEngine.reset(other: state == Enabled ? new QQmlPreviewFileEngineHandler(m_loader.data())
124 : nullptr);
125}
126
127void QQmlPreviewServiceImpl::forwardRequest(const QString &file)
128{
129 QQmlDebugPacket packet;
130 packet << static_cast<qint8>(Request) << file;
131 emit messageToClient(name: name(), message: packet.data());
132}
133
134void QQmlPreviewServiceImpl::forwardError(const QString &error)
135{
136 QQmlDebugPacket packet;
137 packet << static_cast<qint8>(Error) << error;
138 emit messageToClient(name: name(), message: packet.data());
139}
140
141void QQmlPreviewServiceImpl::forwardFps(const QQmlPreviewHandler::FpsInfo &frames)
142{
143 QQmlDebugPacket packet;
144 packet << static_cast<qint8>(Fps)
145 << frames.numSyncs << frames.minSync << frames.maxSync << frames.totalSync
146 << frames.numRenders << frames.minRender << frames.maxRender << frames.totalRender;
147 emit messageToClient(name: name(), message: packet.data());
148}
149
150QQuickItem *QQmlPreviewServiceImpl::currentRootItem()
151{
152 return m_handler.currentRootItem();
153}
154
155QT_END_NAMESPACE
156
157#include "moc_qqmlpreviewservice.cpp"
158

source code of qtdeclarative/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp