24#include <QScriptEngine>
25#include <QScriptValueIterator>
34 class EcmaScript::Private
38 QScriptEngine* m_engine;
42 explicit Private(
EcmaScript* script) : m_script(script), m_engine(0) {}
43 ~Private() {
delete m_engine; }
50 m_engine =
new QScriptEngine();
51 m_engine->installTranslatorFunctions();
55 m_engine->importExtension(
"kross");
56 if( m_engine->hasUncaughtException() ) {
64 QScriptValue global = m_engine->globalObject();
65 m_kross = global.property(
"Kross");
66 Q_ASSERT( m_kross.isQObject() );
67 Q_ASSERT( ! m_engine->hasUncaughtException() );
72 m_self = m_engine->newQObject( m_script->
action() );
73 global.setProperty(
"self", m_self, QScriptValue::ReadOnly|QScriptValue::Undeletable);
78 for(; it !=
end; ++it)
79 global.setProperty(it.key(), m_engine->newQObject( it.value() ) );
85 for(; it !=
end; ++it) {
86 copyEnumsToProperties( it.value() );
87 global.setProperty(it.key(), m_engine->newQObject( it.value() ) );
91 return ! m_engine->hasUncaughtException();
94 void copyEnumsToProperties(
QObject*
object) {
95 const QMetaObject* meta =
object->metaObject();
96 for (
int i = 0; i < meta->enumeratorCount(); ++i) {
97 QMetaEnum metaenum = meta->enumerator(i);
98 for (
int j = 0; j < metaenum.keyCount(); ++j) {
99 object->setProperty(metaenum.key(j), metaenum.value(j));
104 void handleException() {
105 Q_ASSERT( m_engine );
106 Q_ASSERT( m_engine->hasUncaughtException() );
107 const QString err = m_engine->uncaughtException().toString();
108 const int linenr = m_engine->uncaughtExceptionLineNumber();
109 const QString trace = m_engine->uncaughtExceptionBacktrace().join(
"\n");
110 krossdebug( QString(
"%1, line:%2, backtrace:\n%3").arg(err).arg(linenr).arg(trace) );
112 m_engine->clearExceptions();
115 void addObject(
QObject*
object,
const QString& name = QString()) {
116 Q_ASSERT( m_engine );
117 Q_ASSERT( ! m_engine->hasUncaughtException() );
118 QScriptValue global = m_engine->globalObject();
119 QScriptValue value = m_engine->newQObject(
object);
120 global.setProperty(
name.isEmpty() ? object->objectName() : name, value);
124 Q_ASSERT( m_engine );
125 Q_ASSERT( ! m_engine->hasUncaughtException() );
127 QScriptValue global = m_engine->globalObject();
128 QHashIterator< QString, ChildrenInterface::Options > it( children->
objectOptions() );
129 while(it.hasNext()) {
135 QScriptValue obj = m_engine->globalObject().property(it.key());
136 if( ! obj.isQObject() )
138 const QMetaObject* mo = sender->metaObject();
139 const int count = mo->methodCount();
140 for(
int i = 0; i < count; ++i) {
141 QMetaMethod mm = mo->method(i);
142 const QString signature = mm.signature();
143 const QString
name = signature.left(signature.indexOf(
'('));
144 if( mm.methodType() == QMetaMethod::Signal ) {
145 QScriptValue func = global.property(name);
146 if( ! func.isFunction() ) {
150 krossdebug( QString(
"EcmaScript::connectFunctions Connecting with %1.%2").arg(it.key()).arg(name) );
151 eval += QString(
"try { %1.%2.connect(%3); } catch(e) { print(e); }\n").arg(it.key()).arg(name).arg(name);
156 Q_ASSERT( ! m_engine->hasUncaughtException() );
157 if( ! eval.isNull() ) {
158 m_engine->evaluate(eval);
159 Q_ASSERT( ! m_engine->hasUncaughtException() );
181 d->handleException();
186 if( scriptCode.startsWith(QLatin1String(
"#!")) )
187 scriptCode.remove(0, scriptCode.indexOf(
'\n'));
193 Q_ASSERT( d->m_engine );
195 if( d->m_engine->hasUncaughtException() ) {
196 d->m_engine->clearExceptions();
199 d->m_engine->evaluate( scriptCode, fileName );
201 if( d->m_engine->hasUncaughtException() ) {
202 d->handleException();
207 d->connectFunctions(
action() );
212 if( ! d->m_engine && ! d->init() ) {
213 d->handleException();
214 return QStringList();
217 QScriptValueIterator it( d->m_engine->globalObject() );
218 while( it.hasNext() ) {
220 if( it.value().isFunction() ) {
229 if( ! d->m_engine && ! d->init() ) {
230 d->handleException();
234 QScriptValue obj = d->m_engine->globalObject();
235 QScriptValue function = obj.property(
name);
236 if( ! function.isFunction() ) {
237 QString err = QString(
"No such function '%1'").arg(
name);
238 krosswarning( QString(
"EcmaScript::callFunction %1").arg(err) );
243 QScriptValueList arguments;
244 foreach(
const QVariant &v, args)
245 arguments << d->m_engine->toScriptValue(v);
246 QScriptValue result = function.call(obj, arguments);
247 if( d->m_engine->hasUncaughtException() ) {
248 d->handleException();
251 return result.toVariant();
256 if( ! d->m_engine && ! d->init() ) {
257 d->handleException();
261 QScriptValue result = d->m_engine->evaluate(code);
262 if( d->m_engine->hasUncaughtException() ) {
263 d->handleException();
266 return result.toVariant();
The Action class is an abstract container to deal with scripts like a single standalone script file.
Interface for managing Object collections.
QHash< QString, Options > objectOptions() const
QObject * object(const QString &name) const
@ AutoConnectSignals
auto connect signals with scripting functions.
QHash< QString, QObject * > objects() const
The EcmaScript class implements a Kross::Script to handle a single script.
EcmaScript(Kross::Interpreter *interpreter, Kross::Action *action)
Constructor.
virtual QVariant evaluate(const QByteArray &code)
Evaluate some scripting code.
virtual QVariant callFunction(const QString &name, const QVariantList &args=QVariantList())
Execute a function.
virtual void execute()
Executes the script.
virtual QStringList functionNames()
virtual ~EcmaScript()
Destructor.
void setError(const QString &errormessage, const QString &tracemessage=QString(), long lineno=-1)
Set the error message.
void clearError()
Clear the error.
Base class for interpreter implementations.
static Manager & self()
Return the Manager instance.
Base class for interpreter dependent functionality each script provides.
const char * name(StandardAction id)
void krosswarning(const QString &s)
Warning function.
void krossdebug(const QString &s)
Debugging function.