2#include <JS/Qml/QmlObjects.hpp>
3#include <Library/LibrarySettings.hpp>
4#include <score/application/ApplicationContext.hpp>
5#include <score/application/GUIApplicationContext.hpp>
7#include <ossia/detail/logger.hpp>
8#include <ossia-qt/invoke.hpp>
9#include <ossia-qt/qml_engine_functions.hpp>
10#include <JS/ConsolePanel.hpp>
13#include <QQmlComponent>
15#include <QStandardPaths>
18#if __has_include(<boost/hash2/xxh3.hpp>)
19#include <boost/hash2/xxh3.hpp>
20#include <boost/algorithm/hex.hpp>
26static inline QString hashFileData(
const QByteArray& str)
29#if __has_include(<boost/hash2/xxh3.hpp>)
30 boost::hash2::xxh3_128 hasher;
31 hasher.update(str.constData(), str.size());
32 const auto result = hasher.result();
33 std::string hexString;
34 boost::algorithm::hex(result.begin(), result.end(), std::back_inserter(hexString));
37 hexName.push_back(
"-");
38 hexName.append(hexString.data());
47inline bool copyDirectoryRecursively(
const QString& sourcePath,
const QString& destPath)
49 QDir sourceDir(sourcePath);
50 if(!sourceDir.exists())
55 QDir destDir(destPath);
57 if(!destDir.exists() && !destDir.mkpath(
"."))
65 const QFileInfoList entries = sourceDir.entryInfoList(
66 QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden | QDir::System);
68 for(
const QFileInfo& entryInfo : entries)
70 QString newDestPath = destDir.absoluteFilePath(entryInfo.fileName());
75 if(!copyDirectoryRecursively(entryInfo.absoluteFilePath(), newDestPath))
83 if(QFile::exists(newDestPath))
85 QFile::remove(newDestPath);
88 if(!QFile::copy(entryInfo.absoluteFilePath(), newDestPath))
98inline bool copyParentFolderContents(
const QString& rootPath,
const QString& dst)
100 QFileInfo fileInfo(rootPath);
102 QString parentFolder = fileInfo.absolutePath();
104 return copyDirectoryRecursively(parentFolder, dst);
109inline QString ensureJSCacheFile(
const QByteArray& str,
bool is_ui)
111#if __has_include(<boost/hash2/xxh3.hpp>)
112 static const auto cache_path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
113 QString path = cache_path +
"/Script" + hashFileData(str) + (is_ui ?
".ui.qml" :
".qml");
115 if(f.open(QIODevice::ReadWrite))
117 if(str != f.readAll())
131inline void loadJSObjectFromString(
132 const QString& rootPath,
const QByteArray& str, QQmlComponent& comp,
bool is_ui)
134 auto path = ensureJSCacheFile(str, is_ui);
137 static const auto cache_path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
138 copyParentFolderContents(rootPath, cache_path);
140 comp.loadUrl(QUrl::fromLocalFile(path));
144 comp.setData(str, QUrl::fromLocalFile(rootPath));
148inline JS::Script* createJSObject(QQmlComponent& c, QQmlContext* context)
150 const auto& errs = c.errors();
153 ossia::logger().error(
154 "Uncaught exception at line {} : {}", errs[0].line(),
155 errs[0].toString().toStdString());
160 auto object = c.create(context);
161 auto obj = qobject_cast<JS::Script*>(
object);
170 const QString& rootPath,
const QString& val, QQmlEngine* engine,
171 QQmlContext* context)
173 if(val.trimmed().startsWith(
"import"))
175 QQmlComponent c{engine};
176 loadJSObjectFromString(rootPath, val.toUtf8(), c,
false);
177 return createJSObject(c, context);
179 else if(QFile::exists(val))
181 QQmlComponent c{engine, QUrl::fromLocalFile(val)};
182 return createJSObject(c, context);
187inline void setupExecFuncs(
auto* self, QObject* context, ossia::qt::qml_engine_functions* m_execFuncs)
190 m_execFuncs, &ossia::qt::qml_engine_functions::system, qApp,
191 [](
const QString& code) {
192 std::thread{[code] { ::system(code.toStdString().c_str()); }}.detach();
193 }, Qt::QueuedConnection);
198 m_execFuncs, &ossia::qt::qml_engine_functions::exec, js_panel,
199 &JS::PanelDelegate::evaluate, Qt::QueuedConnection);
202 m_execFuncs, &ossia::qt::qml_engine_functions::compute, m_execFuncs,
203 [self, context, m_execFuncs, js_panel](
const QString& code,
const QString& cbname) {
208 , context=QPointer{context}
209 , cur = QPointer{self->m_object}
211 , cbname] (
const QVariant& v) {
216 ossia::qt::run_async(m_execFuncs, [self, context, cur, v, cbname] {
219 if(self->m_object != cur)
222 auto mo = self->m_object->metaObject();
223 for(
int i = 0; i < mo->methodCount(); i++)
225 if(mo->method(i).name() == cbname)
227 mo->method(i).invoke(
228 self->m_object, Qt::DirectConnection, QGenericReturnArgument(),
229 QArgument<QVariant>{
"v", v});
236 ossia::qt::run_async(js_panel, [js_panel, code, cb]() {
237 js_panel->compute(code, cb);
239 }, Qt::DirectConnection);
Definition ConsolePanel.hpp:40
Definition QmlObjects.hpp:845