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

Kross

  • kross
  • qts
qts/script.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * script.cpp
3  * This file is part of the KDE project
4  * copyright (C)2007-2008 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 "script.h"
21 
22 #include <QMetaObject>
23 #include <QMetaMethod>
24 #include <QScriptEngine>
25 #include <QScriptValueIterator>
26 
27 #include <kapplication.h>
28 
29 using namespace Kross;
30 
31 namespace Kross {
32 
34  class EcmaScript::Private
35  {
36  public:
37  EcmaScript* m_script;
38  QScriptEngine* m_engine;
39  QScriptValue m_kross;
40  QScriptValue m_self;
41 
42  explicit Private(EcmaScript* script) : m_script(script), m_engine(0) {}
43  ~Private() { delete m_engine; }
44 
45  bool init() {
46  if( m_script->action()->hadError() )
47  m_script->action()->clearError();
48 
49  delete m_engine;
50  m_engine = new QScriptEngine();
51 
52  // load the Kross QScriptExtensionPlugin plugin that provides
53  // us a bridge between Kross and QtScript. See here plugin.h
54  m_engine->importExtension("kross");
55  if( m_engine->hasUncaughtException() ) {
56  handleException();
57  delete m_engine;
58  m_engine = 0;
59  return false;
60  }
61 
62  // the Kross QScriptExtensionPlugin exports the "Kross" property.
63  QScriptValue global = m_engine->globalObject();
64  m_kross = global.property("Kross");
65  Q_ASSERT( m_kross.isQObject() );
66  Q_ASSERT( ! m_engine->hasUncaughtException() );
67 
68  // Attach our Kross::Action instance to be able to access it in
69  // scripts. Just like at the Kjs-backend we publish our own
70  // action as "self".
71  m_self = m_engine->newQObject( m_script->action() );
72  global.setProperty("self", m_self, QScriptValue::ReadOnly|QScriptValue::Undeletable);
73 
74  { // publish the global objects.
75  QHash< QString, QObject* > objects = Manager::self().objects();
76  QHash< QString, QObject* >::Iterator it(objects.begin()), end(objects.end());
77  for(; it != end; ++it)
78  global.setProperty(it.key(), m_engine->newQObject( it.value() ) );
79  }
80 
81  { // publish the local objects.
82  QHash< QString, QObject* > objects = m_script->action()->objects();
83  QHash< QString, QObject* >::Iterator it(objects.begin()), end(objects.end());
84  for(; it != end; ++it) {
85  copyEnumsToProperties( it.value() );
86  global.setProperty(it.key(), m_engine->newQObject( it.value() ) );
87  }
88  }
89 
90  return ! m_engine->hasUncaughtException();
91  }
92 
93  void copyEnumsToProperties(QObject* object) {
94  const QMetaObject* meta = object->metaObject();
95  for (int i = 0; i < meta->enumeratorCount(); ++i) {
96  QMetaEnum metaenum = meta->enumerator(i);
97  for (int j = 0; j < metaenum.keyCount(); ++j) {
98  object->setProperty(metaenum.key(j), metaenum.value(j));
99  }
100  }
101  }
102 
103  void handleException() {
104  Q_ASSERT( m_engine );
105  Q_ASSERT( m_engine->hasUncaughtException() );
106  const QString err = m_engine->uncaughtException().toString();
107  const int linenr = m_engine->uncaughtExceptionLineNumber();
108  const QString trace = m_engine->uncaughtExceptionBacktrace().join("\n");
109  krossdebug( QString("%1, line:%2, backtrace:\n%3").arg(err).arg(linenr).arg(trace) );
110  m_script->action()->setError(err, trace, linenr);
111  m_engine->clearExceptions();
112  }
113 
114  void addObject(QObject* object, const QString& name = QString()) {
115  Q_ASSERT( m_engine );
116  Q_ASSERT( ! m_engine->hasUncaughtException() );
117  QScriptValue global = m_engine->globalObject();
118  QScriptValue value = m_engine->newQObject(object);
119  global.setProperty(name.isEmpty() ? object->objectName() : name, value);
120  }
121 
122  void connectFunctions(ChildrenInterface* children) {
123  Q_ASSERT( m_engine );
124  Q_ASSERT( ! m_engine->hasUncaughtException() );
125  QString eval;
126  QScriptValue global = m_engine->globalObject();
127  QHashIterator< QString, ChildrenInterface::Options > it( children->objectOptions() );
128  while(it.hasNext()) {
129  it.next();
130  if( it.value() & ChildrenInterface::AutoConnectSignals ) {
131  QObject* sender = children->object(it.key());
132  if( ! sender )
133  continue;
134  QScriptValue obj = m_engine->globalObject().property(it.key());
135  if( ! obj.isQObject() )
136  continue;
137  const QMetaObject* mo = sender->metaObject();
138  const int count = mo->methodCount();
139  for(int i = 0; i < count; ++i) {
140  QMetaMethod mm = mo->method(i);
141  const QString signature = mm.signature();
142  const QString name = signature.left(signature.indexOf('('));
143  if( mm.methodType() == QMetaMethod::Signal ) {
144  QScriptValue func = global.property(name);
145  if( ! func.isFunction() ) {
146  //krossdebug( QString("EcmaScript::connectFunctions No function to connect with %1.%2").arg(it.key()).arg(name) );
147  continue;
148  }
149  krossdebug( QString("EcmaScript::connectFunctions Connecting with %1.%2").arg(it.key()).arg(name) );
150  eval += QString("try { %1.%2.connect(%3); } catch(e) { print(e); }\n").arg(it.key()).arg(name).arg(name);
151  }
152  }
153  }
154  }
155  Q_ASSERT( ! m_engine->hasUncaughtException() );
156  if( ! eval.isNull() ) {
157  m_engine->evaluate(eval);
158  Q_ASSERT( ! m_engine->hasUncaughtException() );
159  }
160  }
161 
162  };
163 
164 }
165 
166 EcmaScript::EcmaScript(Interpreter* interpreter, Action* action) : Script(interpreter, action), d(new Private(this))
167 {
168  //krossdebug( QString("EcmaScript::EcmaScript") );
169 }
170 
171 EcmaScript::~EcmaScript()
172 {
173  //krossdebug( QString("EcmaScript::~EcmaScript") );
174  delete d;
175 }
176 
177 void EcmaScript::execute()
178 {
179  if( ! d->init() ) {
180  d->handleException();
181  return;
182  }
183 
184  QString scriptCode = action()->code();
185  if( scriptCode.startsWith(QLatin1String("#!")) ) // remove optional shebang-line
186  scriptCode.remove(0, scriptCode.indexOf('\n'));
187 
188  const QString fileName = action()->file().isEmpty() ? action()->name() : action()->file();
189 
190  //krossdebug( QString("EcmaScript::execute fileName=%1 scriptCode=\n%2").arg(fileName).arg(scriptCode) );
191 
192  Q_ASSERT( d->m_engine );
193 
194  if( d->m_engine->hasUncaughtException() ) {
195  d->m_engine->clearExceptions();
196  }
197 
198  d->m_engine->evaluate( scriptCode, fileName );
199 
200  if( d->m_engine->hasUncaughtException() ) {
201  d->handleException();
202  return;
203  }
204 
205  //d->connectFunctions( &Manager::self() );
206  d->connectFunctions( action() );
207 }
208 
209 QStringList EcmaScript::functionNames()
210 {
211  if( ! d->m_engine && ! d->init() ) {
212  d->handleException();
213  return QStringList();
214  }
215  QStringList names;
216  QScriptValueIterator it( d->m_engine->globalObject() );
217  while( it.hasNext() ) {
218  it.next();
219  if( it.value().isFunction() ) {
220  names << it.name();
221  }
222  }
223  return names;
224 }
225 
226 QVariant EcmaScript::callFunction(const QString& name, const QVariantList& args)
227 {
228  if( ! d->m_engine && ! d->init() ) {
229  d->handleException();
230  return QVariant();
231  }
232 
233  QScriptValue obj = d->m_engine->globalObject();
234  QScriptValue function = obj.property(name);
235  if( ! function.isFunction() ) {
236  QString err = QString("No such function '%1'").arg(name);
237  krosswarning( QString("EcmaScript::callFunction %1").arg(err) );
238  setError(err);
239  return QVariant();
240  }
241 
242  QScriptValueList arguments;
243  foreach(const QVariant &v, args)
244  arguments << d->m_engine->toScriptValue(v);
245  QScriptValue result = function.call(obj, arguments);
246  if( d->m_engine->hasUncaughtException() ) {
247  d->handleException();
248  return QVariant();
249  }
250  return result.toVariant();
251 }
252 
253 QVariant EcmaScript::evaluate(const QByteArray& code)
254 {
255  if( ! d->m_engine && ! d->init() ) {
256  d->handleException();
257  return QVariant();
258  }
259 
260  QScriptValue result = d->m_engine->evaluate(code);
261  if( d->m_engine->hasUncaughtException() ) {
262  d->handleException();
263  return QVariant();
264  }
265  return result.toVariant();
266 }
267 
268 QObject* EcmaScript::engine() const
269 {
270  return d->m_engine;
271 }
272 
273 #include "script.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Mon Jul 15 2013 13:05:54 by doxygen 1.8.3.1 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.10.5 API Reference

Skip menu "kdelibs-4.10.5 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