• Skip to content
  • Skip to link menu
KDE 4.1 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                         global.setProperty(it.key(), m_engine->newQObject( it.value() ) );
00086                 }
00087 
00088                 return ! m_engine->hasUncaughtException();
00089             }
00090 
00091             void handleException() {
00092                 Q_ASSERT( m_engine );
00093                 Q_ASSERT( m_engine->hasUncaughtException() );
00094                 const QString err = m_engine->uncaughtException().toString();
00095                 const int linenr = m_engine->uncaughtExceptionLineNumber();
00096                 const QString trace = m_engine->uncaughtExceptionBacktrace().join("\n");
00097                 krossdebug( QString("%1, line:%2, backtrace:\n%3").arg(err).arg(linenr).arg(trace) );
00098                 m_script->action()->setError(err, trace, linenr);
00099                 m_engine->clearExceptions();
00100             }
00101 
00102             void addObject(QObject* object, const QString& name = QString()) {
00103                 Q_ASSERT( m_engine );
00104                 Q_ASSERT( ! m_engine->hasUncaughtException() );
00105                 QScriptValue global = m_engine->globalObject();
00106                 QScriptValue value = m_engine->newQObject(object);
00107                 global.setProperty(name.isEmpty() ? object->objectName() : name, value);
00108             }
00109 
00110             void connectFunctions(ChildrenInterface* children) {
00111                 Q_ASSERT( m_engine );
00112                 Q_ASSERT( ! m_engine->hasUncaughtException() );
00113                 QString eval;
00114                 QScriptValue global = m_engine->globalObject();
00115                 QHashIterator< QString, ChildrenInterface::Options > it( children->objectOptions() );
00116                 while(it.hasNext()) {
00117                     it.next();
00118                     if( it.value() & ChildrenInterface::AutoConnectSignals ) {
00119                         QObject* sender = children->object(it.key());
00120                         if( ! sender )
00121                             continue;
00122                         QScriptValue obj = m_engine->globalObject().property(it.key());
00123                         if( ! obj.isQObject() )
00124                             continue;
00125                         const QMetaObject* mo = sender->metaObject();
00126                         const int count = mo->methodCount();
00127                         for(int i = 0; i < count; ++i) {
00128                             QMetaMethod mm = mo->method(i);
00129                             const QString signature = mm.signature();
00130                             const QString name = signature.left(signature.indexOf('('));
00131                             if( mm.methodType() == QMetaMethod::Signal ) {
00132                                 QScriptValue func = global.property(name);
00133                                 if( ! func.isFunction() ) {
00134                                     //krossdebug( QString("EcmaScript::connectFunctions No function to connect with %1.%2").arg(it.key()).arg(name) );
00135                                     continue;
00136                                 }
00137                                 krossdebug( QString("EcmaScript::connectFunctions Connecting with %1.%2").arg(it.key()).arg(name) );
00138                                 eval += QString("try { %1.%2.connect(%3); } catch(e) { print(e); }\n").arg(it.key()).arg(name).arg(name);
00139                             }
00140                         }
00141                     }
00142                 }
00143                 Q_ASSERT( ! m_engine->hasUncaughtException() );
00144                 if( ! eval.isNull() ) {
00145                     m_engine->evaluate(eval);
00146                     Q_ASSERT( ! m_engine->hasUncaughtException() );
00147                 }
00148             }
00149 
00150     };
00151 
00152 }
00153 
00154 EcmaScript::EcmaScript(Interpreter* interpreter, Action* action) : Script(interpreter, action), d(new Private(this))
00155 {
00156     //krossdebug( QString("EcmaScript::EcmaScript") );
00157 }
00158 
00159 EcmaScript::~EcmaScript()
00160 {
00161     //krossdebug( QString("EcmaScript::~EcmaScript") );
00162     delete d;
00163 }
00164 
00165 void EcmaScript::execute()
00166 {
00167     if( ! d->init() ) {
00168         d->handleException();
00169         return;
00170     }
00171 
00172     QString scriptCode = action()->code();
00173     if( scriptCode.startsWith("#!") ) // remove optional shebang-line
00174         scriptCode.remove(0, scriptCode.indexOf('\n'));
00175 
00176     const QString fileName = action()->file().isEmpty() ? action()->name() : action()->file();
00177 
00178     //krossdebug( QString("EcmaScript::execute fileName=%1 scriptCode=\n%2").arg(fileName).arg(scriptCode) );
00179 
00180     Q_ASSERT( d->m_engine );
00181 
00182     if( d->m_engine->hasUncaughtException() ) {
00183         d->m_engine->clearExceptions();
00184     }
00185 
00186     d->m_engine->evaluate( scriptCode, fileName );
00187 
00188     if( d->m_engine->hasUncaughtException() ) {
00189         d->handleException();
00190         return;
00191     }
00192 
00193     //d->connectFunctions( &Manager::self() );
00194     d->connectFunctions( action() );
00195 }
00196 
00197 QStringList EcmaScript::functionNames()
00198 {
00199     if( ! d->m_engine && ! d->init() ) {
00200         d->handleException();
00201         return QStringList();
00202     }
00203     QStringList names;
00204     QScriptValueIterator it( d->m_engine->globalObject() );
00205     while( it.hasNext() ) {
00206         it.next();
00207         if( it.value().isFunction() ) {
00208             names << it.name();
00209         }
00210     }
00211     return names;
00212 }
00213 
00214 QVariant EcmaScript::callFunction(const QString& name, const QVariantList& args)
00215 {
00216     if( ! d->m_engine && ! d->init() ) {
00217         d->handleException();
00218         return QVariant();
00219     }
00220 
00221     QScriptValue obj = d->m_engine->globalObject();
00222     QScriptValue function = obj.property(name);
00223     if( ! function.isFunction() ) {
00224         QString err = QString("No such function '%1'").arg(name);
00225         krosswarning( QString("EcmaScript::callFunction %1").arg(err) );
00226         setError(err);
00227         return QVariant();
00228     }
00229 
00230     QScriptValueList arguments;
00231     foreach(const QVariant &v, args)
00232         arguments << d->m_engine->newVariant(v);
00233     QScriptValue result = function.call(obj, arguments);
00234     return result.toVariant();
00235 }
00236 
00237 QObject* EcmaScript::engine() const
00238 {
00239     return d->m_engine;
00240 }
00241 
00242 #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
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
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