|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/scriptengine.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/scriptbinding.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/scriptbinding_files.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "trenderer.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/toonzfolders.h"
|
|
Toshihiro Shimizu |
890ddd |
#include <qscriptengine></qscriptengine>
|
|
Toshihiro Shimizu |
890ddd |
#include <qscriptprogram></qscriptprogram>
|
|
Toshihiro Shimizu |
890ddd |
#include <qfile></qfile>
|
|
Toshihiro Shimizu |
890ddd |
#include <qtextstream></qtextstream>
|
|
Toshihiro Shimizu |
890ddd |
#include <qthread></qthread>
|
|
Toshihiro Shimizu |
890ddd |
#include <qmutex></qmutex>
|
|
Toshihiro Shimizu |
890ddd |
#include <qwaitcondition></qwaitcondition>
|
|
Toshihiro Shimizu |
890ddd |
#include <qtglobal></qtglobal>
|
|
Toshihiro Shimizu |
890ddd |
#include <qapplication></qapplication>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//=========================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
namespace
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void sleep(unsigned long msec)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
QMutex mutex;
|
|
Toshihiro Shimizu |
890ddd |
mutex.lock();
|
|
Toshihiro Shimizu |
890ddd |
QWaitCondition waitCondition;
|
|
Toshihiro Shimizu |
890ddd |
waitCondition.wait(&mutex, msec);
|
|
Toshihiro Shimizu |
890ddd |
mutex.unlock();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QString print(QScriptValue arg, bool addQuotes)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (arg.isArray()) {
|
|
Toshihiro Shimizu |
890ddd |
QString s = "[";
|
|
Toshihiro Shimizu |
890ddd |
quint32 len = arg.property(QLatin1String("length")).toUInt32();
|
|
Toshihiro Shimizu |
890ddd |
for (quint32 i = 0; i < len; ++i) {
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue item = arg.property(i);
|
|
Toshihiro Shimizu |
890ddd |
if (i > 0)
|
|
Toshihiro Shimizu |
890ddd |
s += ",";
|
|
Toshihiro Shimizu |
890ddd |
s += print(item, addQuotes);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
s += "]";
|
|
Toshihiro Shimizu |
890ddd |
return s;
|
|
Toshihiro Shimizu |
890ddd |
} else if (arg.isBool()) {
|
|
Toshihiro Shimizu |
890ddd |
return arg.toBool() ? "true" : "false";
|
|
Toshihiro Shimizu |
890ddd |
} else if (arg.isString()) {
|
|
Toshihiro Shimizu |
890ddd |
if (addQuotes)
|
|
Toshihiro Shimizu |
890ddd |
return "\"" + arg.toString() + "\"";
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
return arg.toString();
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
return arg.toString();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue printFunction(QScriptContext *context, QScriptEngine *engine)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
QString result;
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i < context->argumentCount(); ++i) {
|
|
Toshihiro Shimizu |
890ddd |
if (i > 0)
|
|
Toshihiro Shimizu |
890ddd |
result.append(" ");
|
|
Toshihiro Shimizu |
890ddd |
result.append(print(context->argument(i), false));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue calleeData = context->callee().data();
|
|
Toshihiro Shimizu |
890ddd |
ScriptEngine *se = qobject_cast<scriptengine *="">(calleeData.toQObject());</scriptengine>
|
|
Toshihiro Shimizu |
890ddd |
se->emitOutput(ScriptEngine::SimpleText, result);
|
|
Toshihiro Shimizu |
890ddd |
sleep(50);
|
|
Toshihiro Shimizu |
890ddd |
return se->voidValue();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue warningFunction(QScriptContext *context, QScriptEngine *engine)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
QString result;
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i < context->argumentCount(); ++i) {
|
|
Toshihiro Shimizu |
890ddd |
if (i > 0)
|
|
Toshihiro Shimizu |
890ddd |
result.append(" ");
|
|
Toshihiro Shimizu |
890ddd |
result.append(print(context->argument(i), false));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue calleeData = context->callee().data();
|
|
Toshihiro Shimizu |
890ddd |
ScriptEngine *se = qobject_cast<scriptengine *="">(calleeData.toQObject());</scriptengine>
|
|
Toshihiro Shimizu |
890ddd |
se->emitOutput(ScriptEngine::Warning, result);
|
|
Toshihiro Shimizu |
890ddd |
sleep(50);
|
|
Toshihiro Shimizu |
890ddd |
return se->voidValue();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue runFunction(QScriptContext *context, QScriptEngine *engine)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (context->argumentCount() != 1) {
|
|
Toshihiro Shimizu |
890ddd |
return context->throwError("expected one parameter");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
TFilePath fp;
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue err = TScriptBinding::checkFilePath(context, context->argument(0), fp);
|
|
Toshihiro Shimizu |
890ddd |
if (err.isError())
|
|
Toshihiro Shimizu |
890ddd |
return err;
|
|
Toshihiro Shimizu |
890ddd |
if (!fp.isAbsolute()) {
|
|
Toshihiro Shimizu |
890ddd |
fp = ToonzFolder::getLibraryFolder() + "scripts" + fp;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QString fpStr = QString::fromStdWString(fp.getWideString());
|
|
Toshihiro Shimizu |
890ddd |
QFile file(fpStr);
|
|
Toshihiro Shimizu |
890ddd |
if (!file.open(QIODevice::ReadOnly)) {
|
|
Toshihiro Shimizu |
890ddd |
return context->throwError("can't read file " + fpStr);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
QTextStream in(&file);
|
|
Toshihiro Shimizu |
890ddd |
QString content = in.readAll();
|
|
Toshihiro Shimizu |
890ddd |
file.close();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QScriptProgram program(content, fpStr);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QScriptContext *parent = context->parentContext();
|
|
Toshihiro Shimizu |
890ddd |
if (parent != 0) {
|
|
Toshihiro Shimizu |
890ddd |
context->setActivationObject(context->parentContext()->activationObject());
|
|
Toshihiro Shimizu |
890ddd |
context->setThisObject(context->parentContext()->thisObject());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue ret = engine->evaluate(program);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (engine->hasUncaughtException()) {
|
|
Toshihiro Shimizu |
890ddd |
int line = engine->uncaughtExceptionLineNumber();
|
|
Toshihiro Shimizu |
890ddd |
return context->throwError(QString("%1, at line %2 of %3").arg(ret.toString()).arg(line).arg(fpStr));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return ret;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue glub(QScriptContext *context, QScriptEngine *engine)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue global = engine->globalObject();
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue te = global.property("_engine");
|
|
Toshihiro Shimizu |
890ddd |
ScriptEngine *se = qscriptvalue_cast<scriptengine*>(te);</scriptengine*>
|
|
Toshihiro Shimizu |
890ddd |
se->postCommand(context->argument(0));
|
|
Toshihiro Shimizu |
890ddd |
return 0;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
} // namespace
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//=========================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
class ScriptEngine::Executor : public QThread
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
ScriptEngine *m_engine;
|
|
Toshihiro Shimizu |
890ddd |
QString m_cmd;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Toshihiro Shimizu |
890ddd |
Executor(ScriptEngine *engine, const QString &cmd) : m_engine(engine), m_cmd(cmd) {}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void run()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_engine->m_engine->collectGarbage();
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue result = m_engine->m_engine->evaluate(m_cmd);
|
|
Toshihiro Shimizu |
890ddd |
if (result.isError()) {
|
|
Toshihiro Shimizu |
890ddd |
m_engine->emitOutput(ScriptEngine::SyntaxError, result.toString());
|
|
Toshihiro Shimizu |
890ddd |
} else if (result.isUndefined()) {
|
|
Toshihiro Shimizu |
890ddd |
m_engine->emitOutput(ScriptEngine::UndefinedEvaluationResult, "undefined");
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
if (qscriptvalue_cast<tscriptbinding::void *="">(result)) {</tscriptbinding::void>
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
m_engine->emitOutput(ScriptEngine::EvaluationResult, print(result, true));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
class ScriptEngine::MainThreadEvaluationData
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Toshihiro Shimizu |
890ddd |
QMutex m_mutex;
|
|
Toshihiro Shimizu |
890ddd |
QWaitCondition m_cond;
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue m_fun, m_args, m_result;
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//=========================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
inline void defineFunction(ScriptEngine *se, const QString &name, QScriptEngine::FunctionSignature f)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
QScriptEngine *engine = se->getQScriptEngine();
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue fObj = engine->newFunction(f);
|
|
Toshihiro Shimizu |
890ddd |
fObj.setData(engine->newQObject(se));
|
|
Toshihiro Shimizu |
890ddd |
engine->globalObject().setProperty(name, fObj);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//=========================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
ScriptEngine::ScriptEngine()
|
|
Toshihiro Shimizu |
890ddd |
: m_executor(0), m_engine(new QScriptEngine())
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
// I must call TRenderer::initialize(), because a script could cause a rendering driven by a working thread
|
|
Toshihiro Shimizu |
890ddd |
TRenderer::initialize();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_mainThreadEvaluationData = new MainThreadEvaluationData();
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue global = m_engine->globalObject();
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue ctor;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QScriptEngine &engine = *m_engine;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
defineFunction(this, "print", printFunction);
|
|
Toshihiro Shimizu |
890ddd |
defineFunction(this, "warning", warningFunction);
|
|
Toshihiro Shimizu |
890ddd |
defineFunction(this, "run", runFunction);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue print = engine.newFunction(printFunction);
|
|
Toshihiro Shimizu |
890ddd |
print.setData(engine.newQObject(this));
|
|
Toshihiro Shimizu |
890ddd |
engine.globalObject().setProperty("print", print);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue print = engine.newFunction(printFunction);
|
|
Toshihiro Shimizu |
890ddd |
print.setData(engine.newQObject(this));
|
|
Toshihiro Shimizu |
890ddd |
engine.globalObject().setProperty("print", print);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QScriptValue run = engine.newFunction(runFunction);
|
|
Toshihiro Shimizu |
890ddd |
run.setData(engine.newQObject(this));
|
|
Toshihiro Shimizu |
890ddd |
engine.globalObject().setProperty("run", run);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
//QScriptValue g = engine.newFunction(glub);
|
|
Toshihiro Shimizu |
890ddd |
//g.setData(engine.newQObject(this));
|
|
Toshihiro Shimizu |
890ddd |
//engine.globalObject().setProperty("glub", g);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// engine.globalObject().setProperty("_engine", engine.newQObject(this));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_voidValue = new QScriptValue();
|
|
Toshihiro Shimizu |
890ddd |
*m_voidValue = engine.newQObject(new TScriptBinding::Void(), QScriptEngine::AutoOwnership);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
engine.globalObject().setProperty("void", *m_voidValue);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TScriptBinding::bindAll(engine);
|
|
Toshihiro Shimizu |
890ddd |
bool ret = connect(this, SIGNAL(mainThreadEvaluationPosted()), this, SLOT(onMainThreadEvaluationPosted()));
|
|
Toshihiro Shimizu |
890ddd |
assert(ret);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
ScriptEngine::~ScriptEngine()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
delete m_mainThreadEvaluationData;
|
|
Toshihiro Shimizu |
890ddd |
delete m_voidValue;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
const QScriptValue &ScriptEngine::evaluateOnMainThread(const QScriptValue &fun, const QScriptValue &arguments)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
MainThreadEvaluationData *d = m_mainThreadEvaluationData;
|
|
Toshihiro Shimizu |
890ddd |
QMutexLocker locker(&d->m_mutex);
|
|
Toshihiro Shimizu |
890ddd |
d->m_fun = fun;
|
|
Toshihiro Shimizu |
890ddd |
d->m_args = arguments;
|
|
Toshihiro Shimizu |
890ddd |
d->m_result = QScriptValue();
|
|
Toshihiro Shimizu |
890ddd |
emit mainThreadEvaluationPosted();
|
|
Toshihiro Shimizu |
890ddd |
d->m_cond.wait(&d->m_mutex);
|
|
Toshihiro Shimizu |
890ddd |
return d->m_result;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void ScriptEngine::onMainThreadEvaluationPosted()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
Q_ASSERT(qApp && qApp->thread() == QThread::currentThread());
|
|
Toshihiro Shimizu |
890ddd |
MainThreadEvaluationData *d = m_mainThreadEvaluationData;
|
|
Toshihiro Shimizu |
890ddd |
QMutexLocker locker(&d->m_mutex);
|
|
Toshihiro Shimizu |
890ddd |
d->m_result = d->m_fun.call(d->m_fun, d->m_args);
|
|
Toshihiro Shimizu |
890ddd |
d->m_cond.wakeOne();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void ScriptEngine::evaluate(const QString &cmd)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (m_executor)
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
m_executor = new Executor(this, cmd);
|
|
Toshihiro Shimizu |
890ddd |
connect(m_executor, SIGNAL(finished()), this, SLOT(onTerminated()));
|
|
Toshihiro Shimizu |
890ddd |
m_executor->start();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool ScriptEngine::isEvaluating() const
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
return m_engine->isEvaluating();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void ScriptEngine::interrupt()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_engine->abortEvaluation();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void ScriptEngine::onTerminated()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
emit evaluationDone();
|
|
Toshihiro Shimizu |
890ddd |
delete m_executor;
|
|
Toshihiro Shimizu |
890ddd |
m_executor = 0;
|
|
Toshihiro Shimizu |
890ddd |
}
|