Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmlpreviewservice.cpp
Go to the documentation of this file.
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// Qt-Security score:significant
4
8
9#include <QtCore/qpointer.h>
10#include <QtQml/qqmlengine.h>
11#include <QtQml/qqmlcomponent.h>
12#include <QtQuick/qquickwindow.h>
13#include <QtQuick/qquickitem.h>
14#include <QtGui/qguiapplication.h>
15
16#include <private/qquickpixmap_p.h>
17#include <private/qqmldebugconnector_p.h>
18#include <private/qversionedpacket_p.h>
19
21
22const QString QQmlPreviewServiceImpl::s_key = QStringLiteral("QmlPreview");
23using QQmlDebugPacket = QVersionedPacket<QQmlDebugConnector>;
24
28{
29 m_handler->connectToService(this);
30}
31
35
36void QQmlPreviewServiceImpl::switchToInPlaceHandler()
37{
38 // Transfer engines from the old handler to the new one
39 const auto engineList = m_handler->engines();
40 m_handler = std::make_unique<QQmlInPlacePreviewHandler>();
41 m_handler->connectToService(this);
42 for (QQmlEngine *engine : engineList)
43 m_handler->addEngine(engine);
44
45 // Send confirmation back to the client
46 QQmlDebugPacket response;
47 const bool enableInPlaceUpdates = true;
48 response << static_cast<qint8>(Confirmation) << enableInPlaceUpdates;
49 emit messageToClient(name(), response.data());
50}
51
52void QQmlPreviewServiceImpl::messageReceived(const QByteArray &data)
53{
54 QQmlDebugPacket packet(data);
55 qint8 command;
56
57 packet >> command;
58 switch (command) {
59 case File: {
60 QString path;
61 QByteArray contents;
62 packet >> path >> contents;
63
64 const QUrl url = path.startsWith(QLatin1Char(':'))
65 ? QUrl(QLatin1String("qrc") + path)
66 : QUrl::fromLocalFile(path);
67
68 emit drop(url);
69 emit file(path, contents);
70
71 // Remember the first .qml file as the current URL, so that a Load command
72 // without an explicit URL can fall back to it.
73 if (m_currentUrl.isEmpty() && path.endsWith(".qml"))
74 m_currentUrl = url;
75
76 // Never auto-load here. The client must send an explicit Load command
77 // to trigger loading. Auto-loading based on File responses is racy
78 // (the Configuration message may not have arrived yet) and creates
79 // duplicate objects when the host process has already loaded the scene.
80 break;
81 }
82 case Directory: {
83 QString path;
84 QStringList entries;
85 packet >> path >> entries;
86 emit directory(path, entries);
87 break;
88 }
89 case Load: {
90 QUrl url;
91 packet >> url;
92 if (url.isEmpty())
93 url = m_currentUrl;
94 else
95 m_currentUrl = url;
96 emit load(url);
97 break;
98 }
99 case Error: {
100 QString file;
101 packet >> file;
102 emit error(file);
103 break;
104 }
105 case Rerun:
106 emit rerun();
107 break;
108 case ClearCache:
110 break;
111 case Zoom: {
112 float factor;
113 packet >> factor;
114 emit zoom(static_cast<qreal>(factor));
115 break;
116 }
117 case AnimationSpeed: {
118 float factor;
119 packet >> factor;
120 emit animationSpeed(qreal(factor));
121 break;
122 }
123 case Configuration: {
124 if (qEnvironmentVariableIsSet("QMLPREVIEW_HOTRELOAD")) {
125 bool enableInPlaceUpdates;
126 packet >> enableInPlaceUpdates;
127 if (enableInPlaceUpdates
128 && !qobject_cast<QQmlInPlacePreviewHandler *>(m_handler.get())) {
129 // Schedule this to the main thread where the handler lives
130 // We're on the debug server thread here.
131 QMetaObject::invokeMethod(this, &QQmlPreviewServiceImpl::switchToInPlaceHandler);
132 } else if (!enableInPlaceUpdates
133 && qobject_cast<QQmlInPlacePreviewHandler *>(m_handler.get())) {
134 forwardError(QLatin1String("Cannot disable in-place updates once enabled"));
135 }
136 break;
137 } else {
138 Q_FALLTHROUGH();
139 }
140 }
141 default:
142 forwardError(QString::fromLatin1("Invalid command: %1").arg(command));
143 break;
144 }
145}
146
148{
149 if (QQmlEngine *qmlEngine = qobject_cast<QQmlEngine *>(engine))
150 m_handler->addEngine(qmlEngine);
151 emit attachedToEngine(engine);
152}
153
155{
156 if (QQmlEngine *qmlEngine = qobject_cast<QQmlEngine *>(engine))
157 m_handler->removeEngine(qmlEngine);
158 emit detachedFromEngine(engine);
159}
160
161void QQmlPreviewServiceImpl::stateChanged(QQmlDebugService::State state)
162{
163 if (state == Enabled) {
164 m_loader.reset(new QQmlPreviewFileLoader(this));
165 connect(this, &QQmlPreviewServiceImpl::load,
166 m_loader.data(), &QQmlPreviewFileLoader::whitelist, Qt::DirectConnection);
167 QV4::ExecutionEngine::setPreviewing(true);
168 m_fileEngine.reset(new QQmlPreviewFileEngineHandler(m_loader.data()));
169 } else {
170 QV4::ExecutionEngine::setPreviewing(false);
171 m_fileEngine.reset();
172 m_loader.reset();
173 }
174}
175
176void QQmlPreviewServiceImpl::forwardRequest(const QString &file)
177{
178 QQmlDebugPacket packet;
179 packet << static_cast<qint8>(Request) << file;
180 emit messageToClient(name(), packet.data());
181}
182
183void QQmlPreviewServiceImpl::forwardError(const QString &error)
184{
185 QQmlDebugPacket packet;
186 packet << static_cast<qint8>(Error) << error;
187 emit messageToClient(name(), packet.data());
188}
189
190void QQmlPreviewServiceImpl::forwardFps(const QQmlPreviewHandler::FpsInfo &frames)
191{
192 QQmlDebugPacket packet;
193 packet << static_cast<qint8>(Fps)
194 << frames.numSyncs << frames.minSync << frames.maxSync << frames.totalSync
195 << frames.numRenders << frames.minRender << frames.maxRender << frames.totalRender;
196 emit messageToClient(name(), packet.data());
197}
198
200{
201 QQmlDebugPacket packet;
202 packet << static_cast<qint8>(HotReloadFailure) << reason;
203 emit messageToClient(name(), packet.data());
204}
205
207{
208 return m_handler->currentRootItem();
209}
210
211QT_END_NAMESPACE
212
213#include "moc_qqmlpreviewservice.cpp"
void forwardRequest(const QString &file)
void engineAboutToBeRemoved(QJSEngine *engine) override
QQmlPreviewServiceImpl(QObject *parent=nullptr)
void forwardHotReloadFailure(const QString &reason)
void engineAboutToBeAdded(QJSEngine *engine) override
void forwardFps(const QQmlPreviewHandler::FpsInfo &frames)
static const QString s_key
void stateChanged(State state) override
void forwardError(const QString &error)
void messageReceived(const QByteArray &message) override
void clearCache()
Clears cached information about loaded files, including any type data, scripts and qmldir information...
Combined button and popup list for selecting options.