1/****************************************************************************
2**
3** Copyright (C) 2018 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QML preview debug service.
7**
8** $QT_BEGIN_LICENSE:LGPL$
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 Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qqmlpreviewservice.h"
41
42#include <QtCore/qpointer.h>
43#include <QtQml/qqmlengine.h>
44#include <QtQml/qqmlcomponent.h>
45#include <QtQuick/qquickwindow.h>
46#include <QtQuick/qquickitem.h>
47#include <QtGui/qguiapplication.h>
48
49#include <private/qquickpixmapcache_p.h>
50#include <private/qqmldebugconnector_p.h>
51#include <private/qversionedpacket_p.h>
52
53QT_BEGIN_NAMESPACE
54
55const QString QQmlPreviewServiceImpl::s_key = QStringLiteral("QmlPreview");
56using QQmlDebugPacket = QVersionedPacket<QQmlDebugConnector>;
57
58QQmlPreviewServiceImpl::QQmlPreviewServiceImpl(QObject *parent) :
59 QQmlDebugService(s_key, 1.0f, parent)
60{
61 m_loader.reset(other: new QQmlPreviewFileLoader(this));
62 connect(sender: this, signal: &QQmlPreviewServiceImpl::load,
63 receiver: m_loader.data(), slot: &QQmlPreviewFileLoader::whitelist, type: Qt::DirectConnection);
64 connect(sender: this, signal: &QQmlPreviewServiceImpl::load, receiver: &m_handler, slot: &QQmlPreviewHandler::loadUrl);
65 connect(sender: this, signal: &QQmlPreviewServiceImpl::rerun, receiver: &m_handler, slot: &QQmlPreviewHandler::rerun);
66 connect(sender: this, signal: &QQmlPreviewServiceImpl::zoom, receiver: &m_handler, slot: &QQmlPreviewHandler::zoom);
67#if QT_CONFIG(translation)
68 connect(sender: this, signal: &QQmlPreviewServiceImpl::language, receiver: &m_handler, slot: &QQmlPreviewHandler::language);
69#endif
70 connect(sender: &m_handler, signal: &QQmlPreviewHandler::error, receiver: this, slot: &QQmlPreviewServiceImpl::forwardError,
71 type: Qt::DirectConnection);
72 connect(sender: &m_handler, signal: &QQmlPreviewHandler::fps, receiver: this, slot: &QQmlPreviewServiceImpl::forwardFps,
73 type: Qt::DirectConnection);
74}
75
76QQmlPreviewServiceImpl::~QQmlPreviewServiceImpl()
77{
78}
79
80void QQmlPreviewServiceImpl::messageReceived(const QByteArray &data)
81{
82 QQmlDebugPacket packet(data);
83 qint8 command;
84
85 packet >> command;
86 switch (command) {
87 case File: {
88 QString path;
89 QByteArray contents;
90 packet >> path >> contents;
91 emit file(file: path, contents);
92
93 // Replace the whole scene with the first file successfully loaded over the debug
94 // connection. This is an OK approximation of the root component, and if the client wants
95 // something specific, it will send an explicit Load anyway.
96 if (m_currentUrl.isEmpty() && path.endsWith(s: ".qml")) {
97 if (path.startsWith(c: ':'))
98 m_currentUrl = QUrl("qrc" + path);
99 else
100 m_currentUrl = QUrl::fromLocalFile(localfile: path);
101 emit load(url: m_currentUrl);
102 }
103 break;
104 }
105 case Directory: {
106 QString path;
107 QStringList entries;
108 packet >> path >> entries;
109 emit directory(file: path, entries);
110 break;
111 }
112 case Load: {
113 QUrl url;
114 packet >> url;
115 if (url.isEmpty())
116 url = m_currentUrl;
117 else
118 m_currentUrl = url;
119 emit load(url);
120 break;
121 }
122 case Error: {
123 QString file;
124 packet >> file;
125 emit error(file);
126 break;
127 }
128 case Rerun:
129 emit rerun();
130 break;
131 case ClearCache:
132 emit clearCache();
133 break;
134 case Zoom: {
135 float factor;
136 packet >> factor;
137 emit zoom(factor: static_cast<qreal>(factor));
138 break;
139 }
140#if QT_CONFIG(translation)
141 case Language: {
142 QUrl context;
143 QString locale;
144 packet >> context >> locale;
145 emit language(context: context.isEmpty() ? m_currentUrl : context,
146 locale: locale.isEmpty() ? QLocale() : QLocale(locale));
147 break;
148 }
149#endif
150 default:
151 forwardError(error: QString::fromLatin1(str: "Invalid command: %1").arg(a: command));
152 break;
153 }
154}
155
156void QQmlPreviewServiceImpl::engineAboutToBeAdded(QJSEngine *engine)
157{
158 if (QQmlEngine *qmlEngine = qobject_cast<QQmlEngine *>(object: engine))
159 m_handler.addEngine(engine: qmlEngine);
160 emit attachedToEngine(engine);
161}
162
163void QQmlPreviewServiceImpl::engineAboutToBeRemoved(QJSEngine *engine)
164{
165 if (QQmlEngine *qmlEngine = qobject_cast<QQmlEngine *>(object: engine))
166 m_handler.removeEngine(engine: qmlEngine);
167 emit detachedFromEngine(engine);
168}
169
170void QQmlPreviewServiceImpl::stateChanged(QQmlDebugService::State state)
171{
172 m_fileEngine.reset(other: state == Enabled ? new QQmlPreviewFileEngineHandler(m_loader.data())
173 : nullptr);
174}
175
176void QQmlPreviewServiceImpl::forwardRequest(const QString &file)
177{
178 QQmlDebugPacket packet;
179 packet << static_cast<qint8>(Request) << file;
180 emit messageToClient(name: name(), message: 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: name(), message: 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: name(), message: packet.data());
197}
198
199QT_END_NAMESPACE
200

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