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

Kross

  • sources
  • kde-4.12
  • kdelibs
  • kross
  • kjs
kjsscript.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * kjsscript.cpp
3  * This file is part of the KDE project
4  * copyright (C)2004-2006 by Sebastian Sauer (mail@dipe.org)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Library General Public License for more details.
14  * You should have received a copy of the GNU Library General Public License
15  * along with this program; see the file COPYING. If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  ***************************************************************************/
19 
20 #include "kjsscript.h"
21 #include "../core/action.h"
22 #include "../core/manager.h"
23 #include "../core/interpreter.h"
24 
25 // for Kjs
26 #include <kjs/interpreter.h>
27 #include <kjs/ustring.h>
28 #include <kjs/object.h>
29 #include <kjs/PropertyNameArray.h>
30 //#include <kjs/array_instance.h>
31 #include <kjs/function_object.h>
32 
33 // for KjsEmbed
34 #include <kjsembed/kjsembed.h>
35 #include <kjsembed/qobject_binding.h>
36 #include <kjsembed/variant_binding.h>
37 #include <kjsembed/slotproxy.h>
38 
39 #include <QMetaObject>
40 #include <QMetaMethod>
41 #include <QPointer>
42 #include <QTextCodec>
43 
44 using namespace Kross;
45 
46 namespace Kross {
47 
49  static ErrorInterface extractError(const KJS::Completion& completion, KJS::ExecState* exec)
50  {
51  QString type;
52  switch( completion.complType() ) {
53  case KJS::Normal: type = "Normal"; break;
54  case KJS::Break: type = "Break"; break;
55  case KJS::Continue: type = "Continue"; break;
56  case KJS::ReturnValue: type = "ReturnValue"; break;
57  case KJS::Throw: {
58  type = "Throw";
59  } break;
60  case KJS::Interrupted: type = "Interrupted"; break;
61  default: type = "Unknown"; break;
62  }
63 
64  KJS::JSValue* value = completion.value();
65  int lineno = -1;
66  if( value && value->type() == KJS::ObjectType ) {
67  KJS::JSValue* linevalue = value->getObject()->get(exec, "line");
68  if( linevalue && linevalue->type() == KJS::NumberType )
69  lineno = linevalue->toInt32(exec);
70  }
71  const QString message = QString("%1%2: %3").arg( type ).arg((lineno >= 0) ? QString(" line %1").arg(lineno) : "").arg(value ? value->toString(exec).qstring() : "NULL");
72 
73  ErrorInterface err;
74  err.setError(message, QString(), lineno);
75  return err;
76  }
77 
79  class KjsScriptPrivate
80  {
81  public:
85  KJSEmbed::Engine* m_engine;
86 
90  QList< QPair<KJS::JSObject*, QPointer<QObject> > > m_publishedObjects;
91 
97  QList< QObject* > m_autoconnect;
98 
102  QStringList m_defaultFunctionNames;
103 
110  void addFunctions(ChildrenInterface* children)
111  {
112  QHashIterator< QString, ChildrenInterface::Options > it( children->objectOptions() );
113  while(it.hasNext()) {
114  it.next();
115  if( it.value() & ChildrenInterface::AutoConnectSignals ) {
116  QObject* sender = children->object( it.key() );
117  if( sender ) {
118  krossdebug( QString("KjsScript::addFunctions sender name=%1 className=%2").arg(sender->objectName()).arg(sender->metaObject()->className()) );
119  m_autoconnect.append( sender );
120  }
121  }
122  }
123  }
124 
126  bool publishObject(KJS::ExecState* exec, const QString &name, QObject* object)
127  {
128  Q_UNUSED(exec);
129 
130  KJS::JSObject* obj = m_engine->addObject(object, name.isEmpty() ? object->objectName() : name);
131  if( ! obj ) {
132  krosswarning( QString("Failed to publish the QObject name=\"%1\" objectName=\"%2\"").arg(name).arg(object ? object->objectName() : "NULL") );
133  return false;
134  }
135  m_publishedObjects << QPair<KJS::JSObject*, QPointer<QObject> >(obj, object);
136 
137  /*
138  bool restricted = interpreter()->interpreterInfo()->optionValue("restricted", true).toBool();
139  if( restricted ) {
140  KJSEmbed::QObjectBinding* objImp = KJSEmbed::extractBindingImp<KJSEmbed::QObjectBinding>(exec, obj);
141  objImp->setAccess(
142  KJSEmbed::QObjectBinding::ScriptableSlots |
143  KJSEmbed::QObjectBinding::NonScriptableSlots |
144  KJSEmbed::QObjectBinding::PublicSlots |
145  KJSEmbed::QObjectBinding::ScriptableSignals |
146  KJSEmbed::QObjectBinding::NonScriptableSignals |
147  KJSEmbed::QObjectBinding::PublicSignals |
148  KJSEmbed::QObjectBinding::ScriptableProperties |
149  KJSEmbed::QObjectBinding::NonScriptableProperties |
150  KJSEmbed::QObjectBinding::GetParentObject |
151  KJSEmbed::QObjectBinding::ChildObjects
152  );
153  }
154  */
155  return true;
156  }
157 
158  };
159 
160 }
161 
162 KjsScript::KjsScript(Interpreter* interpreter, Action* action)
163  : Script(interpreter, action)
164  , d(new KjsScriptPrivate())
165 {
166  krossdebug( QString("KjsScript::KjsScript") );
167  d->m_engine = 0;
168 
169  d->addFunctions( &Manager::self() );
170  d->addFunctions( action );
171 }
172 
173 KjsScript::~KjsScript()
174 {
175  krossdebug( QString("KjsScript::~KjsScript") );
176  finalize();
177  delete d;
178 }
179 
180 bool KjsScript::initialize()
181 {
182  if( d->m_engine )
183  finalize(); // finalize before initialize
184  clearError(); // clear previous errors.
185 
186  krossdebug( QString("KjsScript::initialize") );
187 
188  d->m_engine = new KJSEmbed::Engine();
189 
190  KJS::Interpreter* kjsinterpreter = d->m_engine->interpreter();
191  kjsinterpreter->setShouldPrintExceptions(true);
192  KJS::ExecState* exec = kjsinterpreter->globalExec();
193 
194  // publish our own action and the manager
195  d->publishObject(exec, "self", action());
196  d->publishObject(exec, "Kross", &Manager::self());
197 
198  d->m_defaultFunctionNames = functionNames();
199  d->m_defaultFunctionNames << "Kross";
200 
201  { // publish the global objects.
202  QHash< QString, QObject* > objects = Manager::self().objects();
203  QHash< QString, QObject* >::Iterator it(objects.begin()), end(objects.end());
204  for(; it != end; ++it)
205  d->publishObject(exec, it.key(), it.value());
206  }
207 
208  { // publish the local objects.
209  QHash< QString, QObject* > objects = action()->objects();
210  QHash< QString, QObject* >::Iterator it(objects.begin()), end(objects.end());
211  for(; it != end; ++it)
212  d->publishObject(exec, it.key(), it.value());
213  }
214 
215  /*
216  { // some debugging
217  krossdebug( QString("Global object") );
218  KJS::JSObject* obj = kjsinterpreter->globalObject();
219  KJS::ExecState* exec = kjsinterpreter->globalExec();
220  KJS::PropertyNameArray props;
221  obj->getPropertyNames(exec, props);
222  for(KJS::PropertyNameArrayIterator it = props.begin(); it != props.end(); ++it)
223  krossdebug( QString(" property name=%1").arg( it->ascii() ) );
224  }
225  */
226 
227  return true;
228 }
229 
230 void KjsScript::finalize()
231 {
232  KJS::Interpreter* kjsinterpreter = d->m_engine->interpreter();
233  KJS::ExecState* exec = kjsinterpreter->globalExec();
234  Q_UNUSED(exec);
235 
236  QList< QPair<KJS::JSObject*, QPointer<QObject> > >::Iterator it( d->m_publishedObjects.begin() );
237  QList< QPair<KJS::JSObject*, QPointer<QObject> > >::Iterator end( d->m_publishedObjects.end() );
238  for(; it != end; ++it) {
239  QObject* obj = (*it).second;
240  if( ! obj )
241  continue;
242  /*
243  KJSEmbed::QObjectBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::QObjectBinding>(exec, kjsobj);
244  Q_ASSERT(imp);
245  QObject* obj = imp->object<QObject>();
246  Q_ASSERT(obj);
247  */
248 
249  // try to remove all pending slotproxy's the dirty way... please note, that we can't
250  // do it using findChildren since the slotproxy's are handcraftet QObject's and don't
251  // implement all of the QObject functionality. Also it seems KjsEmbed does some wired
252  // things with the slotproxy's what prevents us from doing it another more nicer way.
253  foreach( QObject* child, obj->children() )
254  if( KJSEmbed::SlotProxy* proxy = dynamic_cast< KJSEmbed::SlotProxy* >(child) )
255  delete proxy;
256 
257  /* the kjsobj-instance will be or got already deleted by KJS and we don't need to care
258  KJS::JSObject* kjsobj = (*it).first;
259  krossdebug(QString("KjsScript::finalize published object=%1").arg( kjsobj->className().ascii() ));
260  delete kjsobj;
261  */
262  }
263  d->m_publishedObjects.clear();
264 
265  d->m_autoconnect.clear();
266  d->m_defaultFunctionNames.clear();
267 
268  delete d->m_engine;
269  d->m_engine = 0;
270 }
271 
272 void KjsScript::execute()
273 {
274  if(! initialize()) {
275  krosswarning( QString("KjsScript::execute aborted cause initialize failed.") );
276  return;
277  }
278 
279  QByteArray code = action()->code();
280  if(code.startsWith("#!")) // krazy:exclude=strings
281  code.remove(0, code.indexOf('\n')); // remove optional shebang-line
282 
283  QTextCodec *codec = QTextCodec::codecForLocale();
284  KJS::UString c = codec ? KJS::UString(codec->toUnicode(code)) : KJS::UString(code.data(), code.size());
285  //krossdebug( QString("KjsScript::execute code=\n%1").arg(c.qstring()) );
286  KJSEmbed::Engine::ExitStatus exitstatus = d->m_engine->execute(c);
287 
288  KJS::Completion completion = d->m_engine->completion();
289  KJS::Interpreter* kjsinterpreter = d->m_engine->interpreter();
290  KJS::ExecState* exec = kjsinterpreter->globalExec();
291 
292  if(exitstatus != KJSEmbed::Engine::Success) {
293  ErrorInterface error = extractError(completion, exec);
294  setError(&error);
295  return;
296  }
297 
298  KJS::JSObject* kjsglobal = kjsinterpreter->globalObject();
299  if( exec->hadException() ) {
300  ErrorInterface error = extractError(d->m_engine->completion(), exec);
301  krossdebug(QString("KjsScript::execute() failed: %1").arg(error.errorMessage()));
302  setError(&error);
303  //exec->clearException();
304  return;
305  }
306 
307  foreach(QObject* object, d->m_autoconnect) {
308  const QMetaObject* metaobject = object->metaObject();
309  const int count = metaobject->methodCount();
310  for(int i = 0; i < count; ++i) {
311  QMetaMethod metamethod = metaobject->method(i);
312  if( metamethod.methodType() == QMetaMethod::Signal ) {
313  const QString signature = metamethod.signature();
314  const QByteArray name = signature.left(signature.indexOf('(')).toLatin1();
315  krossdebug( QString("KjsScript::execute function=%1").arg(name.data()) );
316 
317  KJS::Identifier id = KJS::Identifier( KJS::UString(name.data()) );
318  KJS::JSValue *functionvalue = kjsglobal->get(exec, id);
319  if( ! functionvalue->isObject() )
320  continue;
321  KJS::JSObject *function = functionvalue->toObject(exec);
322  Q_ASSERT( ! exec->hadException() );
323  if( exec->hadException() )
324  continue;
325  if ( function && function->implementsCall() ) {
326  krossdebug( QString("KjsScript::execute connect function=%1 with signal=%2").arg(name.data()).arg(signature) );
327 
328  QByteArray sendersignal = QString("2%1").arg(signature).toLatin1();
329  QByteArray receiverslot = QString("1%1").arg(signature).toLatin1();
330  KJSEmbed::SlotProxy* receiver = new KJSEmbed::SlotProxy(kjsglobal, exec->dynamicInterpreter(), object, signature.toLatin1());
331 
332  if( connect(object, sendersignal, receiver, receiverslot) ) {
333  krossdebug( QString("KjsScript::execute connected function=%1 with object=%2 signal=%3").arg(name.data()).arg(object->objectName()).arg(signature) );
334  }
335  else {
336  krosswarning( QString("KjsScript::execute failed to connect object=%1 signal=%2").arg(object->objectName()).arg(signature) );
337  }
338 
339  }
340  }
341  }
342 
343  }
344 }
345 
346 QStringList KjsScript::functionNames()
347 {
348  KJS::Interpreter* kjsinterpreter = d->m_engine->interpreter();
349  KJS::ExecState* exec = kjsinterpreter->globalExec();
350  KJS::JSObject* kjsglobal = kjsinterpreter->globalObject();
351  if( exec->hadException() ) {
352  return QStringList();
353  }
354 
355  KJS::PropertyNameArray props;
356  kjsglobal->getPropertyNames(exec, props);
357 
358  QStringList list;
359  for(KJS::PropertyNameArrayIterator it = props.begin(); it != props.end(); ++it) {
360  const char* name = it->ascii();
361  KJS::Identifier id = KJS::Identifier(name);
362  KJS::JSValue *value = kjsglobal->get(exec, id);
363  if( ! value || ! value->isObject() )
364  continue;
365  KJS::JSObject *obj = value->toObject(exec);
366  if( ! obj || ! obj->implementsCall() || ! obj->implementsConstruct() || ! obj->classInfo() )
367  continue;
368  if( d->m_defaultFunctionNames.contains(name) )
369  continue;
370  list << name;
371  }
372 
373  Q_ASSERT( ! exec->hadException() );
374  return list;
375 }
376 
377 QVariant KjsScript::callFunction(const QString& name, const QVariantList& args)
378 {
379  //if( hadError() ) return QVariant(); // check if we had a prev error and abort if that's the case
380 
381  KJS::Interpreter* kjsinterpreter = d->m_engine->interpreter();
382  KJS::ExecState* exec = kjsinterpreter->globalExec();
383  KJS::JSObject* kjsglobal = kjsinterpreter->globalObject();
384  if( exec->hadException() ) {
385  ErrorInterface error = extractError(d->m_engine->completion(), exec);
386  //setError(&error);
387  krossdebug(QString("KjsScript::callFunction(\"%1\") Prev error: %2").arg(name).arg(error.errorMessage()));
388  return QVariant();
389  }
390 
391  KJS::Identifier id = KJS::Identifier( KJS::UString(name.toLatin1().data()) );
392  KJS::JSValue *functionvalue = kjsglobal->get(exec, id);
393  Q_ASSERT( ! exec->hadException() );
394 
395  KJS::JSObject *function = functionvalue->toObject(exec);
396  if ( ! function || ! function->implementsCall() ) {
397  krossdebug(QString("KjsScript::callFunction(\"%1\") No such function").arg(name));
398  setError(QString("No such function \"%1\"").arg(name));
399  return QVariant();
400  }
401 
402  KJS::List kjsargs;
403  foreach(const QVariant &variant, args) {
404  if( qVariantCanConvert< QWidget* >(variant) ) {
405  if( QWidget* widget = qvariant_cast< QWidget* >(variant) ) {
406  kjsargs.append( KJSEmbed::createQObject(exec, widget, KJSEmbed::ObjectBinding::QObjOwned) );
407  Q_ASSERT( ! exec->hadException() );
408  continue;
409  }
410  }
411  if( qVariantCanConvert< QObject* >(variant) ) {
412  if( QObject* obj = qvariant_cast< QObject* >(variant) ) {
413  kjsargs.append( KJSEmbed::createQObject(exec, obj, KJSEmbed::ObjectBinding::QObjOwned) );
414  Q_ASSERT( ! exec->hadException() );
415  continue;
416  }
417  }
418  KJS::JSValue* jsvalue = KJSEmbed::convertToValue(exec, variant);
419  Q_ASSERT( ! exec->hadException() );
420  kjsargs.append( jsvalue );
421  }
422 
423  KJS::JSValue *retValue = function->call(exec, kjsglobal, kjsargs);
424  if( exec->hadException() ) {
425  ErrorInterface error = extractError(d->m_engine->completion(), exec);
426  //exec->clearException();
427  krossdebug(QString("KjsScript::callFunction(\"%1\") Call failed: %2").arg(name).arg(error.errorMessage()));
428  setError(&error);
429  return QVariant();
430  }
431 
432  QVariant result = retValue ? KJSEmbed::convertToVariant(exec, retValue) : QVariant();
433  Q_ASSERT( ! exec->hadException() );
434  return result;
435 }
436 
437 QVariant KjsScript::evaluate(const QByteArray& code)
438 {
439  QTextCodec *codec = QTextCodec::codecForLocale();
440  KJS::UString c = codec ? KJS::UString(codec->toUnicode(code)) : KJS::UString(code.data(), code.size());
441 
442  KJSEmbed::Engine::ExitStatus exitstatus = d->m_engine->execute(c);
443 
444  KJS::Completion completion = d->m_engine->completion();
445  KJS::Interpreter* kjsinterpreter = d->m_engine->interpreter();
446  KJS::ExecState* exec = kjsinterpreter->globalExec();
447 
448  if(exitstatus != KJSEmbed::Engine::Success) {
449  ErrorInterface error = extractError(completion, exec);
450  setError(&error);
451  return QVariant();
452  }
453 
454  KJS::JSValue *retValue = completion.value();
455  QVariant result = retValue ? KJSEmbed::convertToVariant(exec, retValue) : QVariant();
456  Q_ASSERT( ! exec->hadException() );
457  return result;
458 }
QVariant
message
void message(KMessage::MessageType messageType, const QString &text, const QString &caption=QString())
Kross::Script
Base class for interpreter dependent functionality each script provides.
Definition: core/script.h:43
Kross::ErrorInterface
Interface for error-handling.
Definition: errorinterface.h:32
Kross::KjsScript::callFunction
virtual QVariant callFunction(const QString &name, const QVariantList &args=QVariantList())
Call a function in the script.
Definition: kjsscript.cpp:377
Kross::ChildrenInterface::objectOptions
QHash< QString, Options > objectOptions() const
Definition: childreninterface.h:118
QWidget
Kross::KjsScript::functionNames
virtual QStringList functionNames()
Definition: kjsscript.cpp:346
QString
QHash< QString, QObject * >
QObject
Kross::KjsScript::KjsScript
KjsScript(Kross::Interpreter *interpreter, Kross::Action *action)
Constructor.
Definition: kjsscript.cpp:162
Kross::KjsScript::evaluate
virtual QVariant evaluate(const QByteArray &code)
Evaluate some scripting code.
Definition: kjsscript.cpp:437
Kross::ErrorInterface::errorMessage
const QString errorMessage() const
Definition: errorinterface.h:53
Kross::ChildrenInterface::objects
QHash< QString, QObject * > objects() const
Definition: childreninterface.h:104
Kross::ErrorInterface::clearError
void clearError()
Clear the error.
Definition: errorinterface.h:88
QStringList
Kross::ChildrenInterface
Interface for managing Object collections.
Definition: childreninterface.h:38
Kross::Action::code
QByteArray code() const
Definition: action.cpp:318
Kross::KjsScript::~KjsScript
virtual ~KjsScript()
Destructor.
Definition: kjsscript.cpp:173
Kross::Interpreter
Base class for interpreter implementations.
Definition: core/interpreter.h:177
Kross::krosswarning
void krosswarning(const QString &s)
Warning function.
Definition: krossconfig.cpp:34
kjsscript.h
Kross::ChildrenInterface::object
QObject * object(const QString &name) const
Definition: childreninterface.h:97
Kross::ChildrenInterface::AutoConnectSignals
auto connect signals with scripting functions.
Definition: childreninterface.h:47
Kross::Manager::self
static Manager & self()
Return the Manager instance.
Definition: manager.cpp:73
Kross::KjsScript::execute
virtual void execute()
Execute the script.
Definition: kjsscript.cpp:272
Kross::ErrorInterface::setError
void setError(const QString &errormessage, const QString &tracemessage=QString(), long lineno=-1)
Set the error message.
Definition: errorinterface.h:69
Kross::Script::action
Action * action() const
Definition: core/script.cpp:61
Kross::extractError
static ErrorInterface extractError(const KJS::Completion &completion, KJS::ExecState *exec)
Extract an errormessage from a KJS::Completion object.
Definition: kjsscript.cpp:49
Kross::Action
The Action class is an abstract container to deal with scripts like a single standalone script file...
Definition: action.h:94
end
const KShortcut & end()
completion
const KShortcut & completion()
Kross::krossdebug
void krossdebug(const QString &s)
Debugging function.
Definition: krossconfig.cpp:28
QList
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:49:54 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Kross

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

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal