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

Kross

  • 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
44using namespace Kross;
45
46namespace 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
162KjsScript::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
173KjsScript::~KjsScript()
174{
175 krossdebug( QString("KjsScript::~KjsScript") );
176 finalize();
177 delete d;
178}
179
180bool 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
230void 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
272void 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
346QStringList 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
377QVariant 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
437QVariant 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}
Kross::Action
The Action class is an abstract container to deal with scripts like a single standalone script file.
Definition: action.h:99
Kross::Action::code
QByteArray code() const
Definition: action.cpp:318
Kross::ChildrenInterface
Interface for managing Object collections.
Definition: childreninterface.h:39
Kross::ChildrenInterface::objectOptions
QHash< QString, Options > objectOptions() const
Definition: childreninterface.h:118
Kross::ChildrenInterface::object
QObject * object(const QString &name) const
Definition: childreninterface.h:97
Kross::ChildrenInterface::AutoConnectSignals
@ AutoConnectSignals
auto connect signals with scripting functions.
Definition: childreninterface.h:47
Kross::ChildrenInterface::objects
QHash< QString, QObject * > objects() const
Definition: childreninterface.h:104
Kross::ErrorInterface
Interface for error-handling.
Definition: errorinterface.h:33
Kross::ErrorInterface::errorMessage
const QString errorMessage() const
Definition: errorinterface.h:53
Kross::ErrorInterface::setError
void setError(const QString &errormessage, const QString &tracemessage=QString(), long lineno=-1)
Set the error message.
Definition: errorinterface.h:69
Kross::ErrorInterface::clearError
void clearError()
Clear the error.
Definition: errorinterface.h:88
Kross::Interpreter
Base class for interpreter implementations.
Definition: core/interpreter.h:178
Kross::KjsScript::~KjsScript
virtual ~KjsScript()
Destructor.
Definition: kjsscript.cpp:173
Kross::KjsScript::functionNames
virtual QStringList functionNames()
Definition: kjsscript.cpp:346
Kross::KjsScript::KjsScript
KjsScript(Kross::Interpreter *interpreter, Kross::Action *action)
Constructor.
Definition: kjsscript.cpp:162
Kross::KjsScript::execute
virtual void execute()
Execute the script.
Definition: kjsscript.cpp:272
Kross::Manager::self
static Manager & self()
Return the Manager instance.
Definition: manager.cpp:73
Kross::Script
Base class for interpreter dependent functionality each script provides.
Definition: core/script.h:44
Kross::Script::callFunction
virtual QVariant callFunction(const QString &name, const QVariantList &args=QVariantList())=0
Call a function in the script.
Kross::Script::evaluate
virtual QVariant evaluate(const QByteArray &code)=0
Evaluate some scripting code.
Kross::Script::action
Action * action() const
Definition: core/script.cpp:61
QHash
QList
QObject
QWidget
kjsscript.h
message
void message(KMessage::MessageType messageType, const QString &text, const QString &caption=QString())
name
const char * name(StandardAction id)
completion
const KShortcut & completion()
end
const KShortcut & end()
Kross
Definition: action.cpp:36
Kross::krosswarning
void krosswarning(const QString &s)
Warning function.
Definition: krossconfig.cpp:34
Kross::krossdebug
void krossdebug(const QString &s)
Debugging function.
Definition: krossconfig.cpp:28
Kross::extractError
static ErrorInterface extractError(const KJS::Completion &completion, KJS::ExecState *exec)
Extract an errormessage from a KJS::Completion object.
Definition: kjsscript.cpp:49
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 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-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 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
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
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