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