• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Kross

script.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  * script.cpp
00003  * This file is part of the KDE project
00004  * copyright (C)2007-2008 by Sebastian Sauer (mail@dipe.org)
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Library General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2 of the License, or (at your option) any later version.
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  * You should have received a copy of the GNU Library General Public License
00015  * along with this program; see the file COPYING.  If not, write to
00016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018  ***************************************************************************/
00019 
00020 #include "script.h"
00021 
00022 #include <QMetaObject>
00023 #include <QMetaMethod>
00024 #include <QScriptEngine>
00025 #include <QScriptValueIterator>
00026 
00027 #include <kapplication.h>
00028 
00029 using namespace Kross;
00030 
00031 namespace Kross {
00032 
00034     class EcmaScript::Private
00035     {
00036         public:
00037             EcmaScript* m_script;
00038             QScriptEngine* m_engine;
00039             QScriptValue m_kross;
00040             QScriptValue m_self;
00041 
00042             explicit Private(EcmaScript* script) : m_script(script), m_engine(0) {}
00043             ~Private() { delete m_engine; }
00044 
00045             bool init() {
00046                 if( m_script->action()->hadError() )
00047                     m_script->action()->clearError();
00048 
00049                 delete m_engine;
00050                 m_engine = new QScriptEngine();
00051 
00052                 // load the Kross QScriptExtensionPlugin plugin that provides
00053                 // us a bridge between Kross and QtScript. See here plugin.h
00054                 m_engine->importExtension("kross");
00055                 if( m_engine->hasUncaughtException() ) {
00056                     handleException();
00057                     delete m_engine;
00058                     m_engine = 0;
00059                     return false;
00060                 }
00061 
00062                 // the Kross QScriptExtensionPlugin exports the "Kross" property.
00063                 QScriptValue global = m_engine->globalObject();
00064                 m_kross = global.property("Kross");
00065                 Q_ASSERT( m_kross.isQObject() );
00066                 Q_ASSERT( ! m_engine->hasUncaughtException() );
00067 
00068                 // Attach our Kross::Action instance to be able to access it in
00069                 // scripts. Just like at the Kjs-backend we publish our own
00070                 // action as "self".
00071                 m_self = m_engine->newQObject( m_script->action() );
00072                 global.setProperty("self", m_self, QScriptValue::ReadOnly|QScriptValue::Undeletable);
00073 
00074                 { // publish the global objects.
00075                     QHash< QString, QObject* > objects = Manager::self().objects();
00076                     QHash< QString, QObject* >::Iterator it(objects.begin()), end(objects.end());
00077                     for(; it != end; ++it)
00078                         global.setProperty(it.key(), m_engine->newQObject( it.value() ) );
00079                 }
00080 
00081                 { // publish the local objects.
00082                     QHash< QString, QObject* > objects = m_script->action()->objects();
00083                     QHash< QString, QObject* >::Iterator it(objects.begin()), end(objects.end());
00084                     for(; it != end; ++it) {
00085                         copyEnumsToProperties( it.value() );
00086                         global.setProperty(it.key(), m_engine->newQObject( it.value() ) );
00087                     }
00088                 }
00089 
00090                 return ! m_engine->hasUncaughtException();
00091             }
00092 
00093             void copyEnumsToProperties(QObject* object) {
00094                 const QMetaObject* meta = object->metaObject();
00095                 for (int i = 0; i < meta->enumeratorCount(); ++i) {
00096                     QMetaEnum metaenum = meta->enumerator(i);
00097                     for (int j = 0; j < metaenum.keyCount(); ++j) {
00098                         object->setProperty(metaenum.key(j), metaenum.value(j));
00099                     }
00100                 }
00101             }
00102 
00103             void handleException() {
00104                 Q_ASSERT( m_engine );
00105                 Q_ASSERT( m_engine->hasUncaughtException() );
00106                 const QString err = m_engine->uncaughtException().toString();
00107                 const int linenr = m_engine->uncaughtExceptionLineNumber();
00108                 const QString trace = m_engine->uncaughtExceptionBacktrace().join("\n");
00109                 krossdebug( QString("%1, line:%2, backtrace:\n%3").arg(err).arg(linenr).arg(trace) );
00110                 m_script->action()->setError(err, trace, linenr);
00111                 m_engine->clearExceptions();
00112             }
00113 
00114             void addObject(QObject* object, const QString& name = QString()) {
00115                 Q_ASSERT( m_engine );
00116                 Q_ASSERT( ! m_engine->hasUncaughtException() );
00117                 QScriptValue global = m_engine->globalObject();
00118                 QScriptValue value = m_engine->newQObject(object);
00119                 global.setProperty(name.isEmpty() ? object->objectName() : name, value);
00120             }
00121 
00122             void connectFunctions(ChildrenInterface* children) {
00123                 Q_ASSERT( m_engine );
00124                 Q_ASSERT( ! m_engine->hasUncaughtException() );
00125                 QString eval;
00126                 QScriptValue global = m_engine->globalObject();
00127                 QHashIterator< QString, ChildrenInterface::Options > it( children->objectOptions() );
00128                 while(it.hasNext()) {
00129                     it.next();
00130                     if( it.value() & ChildrenInterface::AutoConnectSignals ) {
00131                         QObject* sender = children->object(it.key());
00132                         if( ! sender )
00133                             continue;
00134                         QScriptValue obj = m_engine->globalObject().property(it.key());
00135                         if( ! obj.isQObject() )
00136                             continue;
00137                         const QMetaObject* mo = sender->metaObject();
00138                         const int count = mo->methodCount();
00139                         for(int i = 0; i < count; ++i) {
00140                             QMetaMethod mm = mo->method(i);
00141                             const QString signature = mm.signature();
00142                             const QString name = signature.left(signature.indexOf('('));
00143                             if( mm.methodType() == QMetaMethod::Signal ) {
00144                                 QScriptValue func = global.property(name);
00145                                 if( ! func.isFunction() ) {
00146                                     //krossdebug( QString("EcmaScript::connectFunctions No function to connect with %1.%2").arg(it.key()).arg(name) );
00147                                     continue;
00148                                 }
00149                                 krossdebug( QString("EcmaScript::connectFunctions Connecting with %1.%2").arg(it.key()).arg(name) );
00150                                 eval += QString("try { %1.%2.connect(%3); } catch(e) { print(e); }\n").arg(it.key()).arg(name).arg(name);
00151                             }
00152                         }
00153                     }
00154                 }
00155                 Q_ASSERT( ! m_engine->hasUncaughtException() );
00156                 if( ! eval.isNull() ) {
00157                     m_engine->evaluate(eval);
00158                     Q_ASSERT( ! m_engine->hasUncaughtException() );
00159                 }
00160             }
00161 
00162     };
00163 
00164 }
00165 
00166 EcmaScript::EcmaScript(Interpreter* interpreter, Action* action) : Script(interpreter, action), d(new Private(this))
00167 {
00168     //krossdebug( QString("EcmaScript::EcmaScript") );
00169 }
00170 
00171 EcmaScript::~EcmaScript()
00172 {
00173     //krossdebug( QString("EcmaScript::~EcmaScript") );
00174     delete d;
00175 }
00176 
00177 void EcmaScript::execute()
00178 {
00179     if( ! d->init() ) {
00180         d->handleException();
00181         return;
00182     }
00183 
00184     QString scriptCode = action()->code();
00185     if( scriptCode.startsWith("#!") ) // remove optional shebang-line
00186         scriptCode.remove(0, scriptCode.indexOf('\n'));
00187 
00188     const QString fileName = action()->file().isEmpty() ? action()->name() : action()->file();
00189 
00190     //krossdebug( QString("EcmaScript::execute fileName=%1 scriptCode=\n%2").arg(fileName).arg(scriptCode) );
00191 
00192     Q_ASSERT( d->m_engine );
00193 
00194     if( d->m_engine->hasUncaughtException() ) {
00195         d->m_engine->clearExceptions();
00196     }
00197 
00198     d->m_engine->evaluate( scriptCode, fileName );
00199 
00200     if( d->m_engine->hasUncaughtException() ) {
00201         d->handleException();
00202         return;
00203     }
00204 
00205     //d->connectFunctions( &Manager::self() );
00206     d->connectFunctions( action() );
00207 }
00208 
00209 QStringList EcmaScript::functionNames()
00210 {
00211     if( ! d->m_engine && ! d->init() ) {
00212         d->handleException();
00213         return QStringList();
00214     }
00215     QStringList names;
00216     QScriptValueIterator it( d->m_engine->globalObject() );
00217     while( it.hasNext() ) {
00218         it.next();
00219         if( it.value().isFunction() ) {
00220             names << it.name();
00221         }
00222     }
00223     return names;
00224 }
00225 
00226 QVariant EcmaScript::callFunction(const QString& name, const QVariantList& args)
00227 {
00228     if( ! d->m_engine && ! d->init() ) {
00229         d->handleException();
00230         return QVariant();
00231     }
00232 
00233     QScriptValue obj = d->m_engine->globalObject();
00234     QScriptValue function = obj.property(name);
00235     if( ! function.isFunction() ) {
00236         QString err = QString("No such function '%1'").arg(name);
00237         krosswarning( QString("EcmaScript::callFunction %1").arg(err) );
00238         setError(err);
00239         return QVariant();
00240     }
00241 
00242     QScriptValueList arguments;
00243     foreach(const QVariant &v, args)
00244         arguments << d->m_engine->toScriptValue(v);
00245     QScriptValue result = function.call(obj, arguments);
00246     if( d->m_engine->hasUncaughtException() ) {
00247         d->handleException();
00248         return QVariant();
00249     }
00250     return result.toVariant();
00251 }
00252 
00253 QVariant EcmaScript::evaluate(const QByteArray& code)
00254 {
00255     if( ! d->m_engine && ! d->init() ) {
00256         d->handleException();
00257         return QVariant();
00258     }
00259 
00260     QScriptValue result = d->m_engine->evaluate(code);
00261     if( d->m_engine->hasUncaughtException() ) {
00262         d->handleException();
00263         return QVariant();
00264     }
00265     return result.toVariant();
00266 }
00267 
00268 QObject* EcmaScript::engine() const
00269 {
00270     return d->m_engine;
00271 }
00272 
00273 #include "script.moc"

Kross

Skip menu "Kross"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal