Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2024 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 : #include "extensionsuiengine.h"
23 :
24 : #include <QQmlEngine>
25 : #include <QQmlContext>
26 :
27 : #include "global/api/apiutils.h"
28 :
29 : #include "log.h"
30 :
31 : using namespace muse::extensions;
32 :
33 0 : ExtensionsUiEngine::~ExtensionsUiEngine()
34 : {
35 0 : delete m_api;
36 0 : delete m_apiEngine;
37 0 : delete m_engine;
38 :
39 0 : delete m_apiV1;
40 0 : delete m_apiEngineV1;
41 0 : delete m_engineV1;
42 0 : }
43 :
44 0 : void ExtensionsUiEngine::setup()
45 : {
46 0 : QmlIoCContext* qmlIoc = new QmlIoCContext(this);
47 0 : qmlIoc->ctx = iocContext();
48 :
49 0 : QQmlContext* rootContext = m_engine->rootContext();
50 0 : rootContext->setObjectName(QString("Root QQmlContext: %1").arg(qmlIoc->ctx->id));
51 0 : rootContext->setContextProperty("ioc_context", QVariant::fromValue(qmlIoc));
52 0 : m_engine->setProperty("ioc_context", QVariant::fromValue(qmlIoc));
53 :
54 0 : m_engine->setProperty("apiversion", 2);
55 :
56 : //! NOTE Needed for UI components, should not be used directly in extensions
57 0 : QObject* ui = dynamic_cast<QObject*>(uiEngine.get().get());
58 0 : rootContext->setContextProperty("ui", ui);
59 :
60 0 : m_apiEngine = new muse::api::JsApiEngine(m_engine, iocContext());
61 0 : QJSValue globalObject = m_engine->globalObject();
62 0 : m_api = new api::ExtApi(m_apiEngine, m_engine);
63 0 : globalObject.setProperty("api", m_engine->newQObject(m_api));
64 :
65 0 : const std::vector<muse::api::IApiRegister::GlobalEnum>& globalEnums = apiRegister()->globalEnums();
66 0 : for (const muse::api::IApiRegister::GlobalEnum& e : globalEnums) {
67 0 : QString name = QString::fromStdString(e.name);
68 0 : QJSValue enumObj = muse::api::enumToJsValue(m_apiEngine, e.meta, e.type);
69 0 : globalObject.setProperty(name, enumObj);
70 0 : }
71 0 : }
72 :
73 0 : QQmlEngine* ExtensionsUiEngine::engine()
74 : {
75 0 : if (!m_engine) {
76 0 : m_engine = new QQmlEngine(this);
77 0 : setup();
78 : }
79 :
80 0 : return m_engine;
81 : }
82 :
83 0 : QQmlEngine* ExtensionsUiEngine::qmlEngine() const
84 : {
85 0 : return const_cast<ExtensionsUiEngine*>(this)->engine();
86 : }
87 :
88 : // =====================================================
89 : // Api V1
90 : // =====================================================
91 0 : QQmlEngine* ExtensionsUiEngine::engineV1()
92 : {
93 0 : if (!m_engineV1) {
94 0 : m_engineV1 = new QQmlEngine(this);
95 0 : setupV1();
96 : }
97 :
98 0 : return m_engineV1;
99 : }
100 :
101 0 : void ExtensionsUiEngine::setupV1()
102 : {
103 0 : QmlIoCContext* qmlIoc = new QmlIoCContext(this);
104 0 : qmlIoc->ctx = iocContext();
105 :
106 0 : QQmlContext* rootContext = m_engineV1->rootContext();
107 0 : rootContext->setObjectName(QString("Root QQmlContext: %1").arg(qmlIoc->ctx->id));
108 0 : rootContext->setContextProperty("ioc_context", QVariant::fromValue(qmlIoc));
109 0 : m_engineV1->setProperty("ioc_context", QVariant::fromValue(qmlIoc));
110 :
111 0 : m_engineV1->setProperty("apiversion", 1);
112 :
113 : //! NOTE Needed for UI components, should not be used directly in extensions
114 0 : QObject* ui = dynamic_cast<QObject*>(uiEngine.get().get());
115 0 : rootContext->setContextProperty("ui", ui);
116 :
117 0 : m_apiEngineV1 = new muse::api::JsApiEngine(m_engineV1, iocContext());
118 0 : m_apiV1 = new apiv1::ExtApiV1(m_apiEngineV1, m_engineV1);
119 0 : m_engineV1->globalObject().setProperty("api", m_engineV1->newQObject(m_apiV1));
120 :
121 : //! NOTE Old plugins could use standard modules (for example MuseScore.UiComponents),
122 : //! we need to think about how to limit this or quickly abandon old plugins.
123 0 : m_engineV1->addImportPath(":/qml");
124 0 : }
125 :
126 0 : QQmlEngine* ExtensionsUiEngine::qmlEngineApiV1() const
127 : {
128 0 : return const_cast<ExtensionsUiEngine*>(this)->engineV1();
129 : }
130 :
131 0 : void ExtensionsUiEngine::clearComponentCache()
132 : {
133 : //! NOTE The engines cache every QML component they have compiled, so a plugin
134 : //! edited on disk keeps running its old code until the cache is dropped.
135 : //! The engines themselves stay: a plugin window left open was built by one of
136 : //! them, and outlives the reload.
137 0 : if (m_engine) {
138 0 : m_engine->clearComponentCache();
139 : }
140 :
141 0 : if (m_engineV1) {
142 0 : m_engineV1->clearComponentCache();
143 : }
144 0 : }
|