Kross

manager.cpp
1 /***************************************************************************
2  * manager.cpp
3  * This file is part of the KDE project
4  * copyright (C)2004-2007 by Sebastian Sauer ([email protected])
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 "manager.h"
21 #include "interpreter.h"
22 #include "action.h"
23 #include "actioncollection.h"
24 #include "kross_debug.h"
25 
26 #include <QObject>
27 #include <QArgument>
28 #include <QFile>
29 #include <QRegExp>
30 #include <QFileInfo>
31 #include <QPointer>
32 #include <QLibrary>
33 #include <QCoreApplication>
34 
35 #include <klocalizedstring.h>
36 
37 extern "C"
38 {
39  typedef QObject *(*def_module_func)();
40 }
41 
42 using namespace Kross;
43 
44 namespace Kross
45 {
46 
47 /// @internal
48 class Manager::Private
49 {
50 public:
51  /// List of \a InterpreterInfo instances.
52  QHash< QString, InterpreterInfo * > interpreterinfos;
53 
54  /// List of the interpreter names.
55  QStringList interpreters;
56 
57  /// Loaded modules.
59 
60  /// The collection of \a Action instances.
61  ActionCollection *collection;
62 
63  /// List with custom handlers for metatypes.
65 
66  /// Strict type handling enabled or disabled.
67  bool strictTypesEnabled;
68 };
69 
70 }
71 
72 Q_GLOBAL_STATIC(Manager, _self)
73 
74 Manager &Manager::self()
75 {
76  return *_self();
77 }
78 
79 enum LibraryFunction
80 {
81  LibraryFunctionInterpreter,
82  LibraryFunctionModule
83 };
84 
85 static QFunctionPointer loadLibrary(const char *libname, enum LibraryFunction function)
86 {
87  QLibrary lib;
88  QString libAbsoluteFilePath;
89  foreach (const QString &path, QCoreApplication::instance()->libraryPaths()) {
90  const QFileInfo &fileInfo = QFileInfo(path, libname);
91  lib.setFileName(fileInfo.filePath());
93  if (lib.load()) {
94  libAbsoluteFilePath = fileInfo.absoluteFilePath();
95  break;
96  }
97  }
98 
99  if (!lib.isLoaded()) {
100 #ifdef KROSS_INTERPRETER_DEBUG
101  if (function == LibraryFunctionInterpreter) {
102  qCDebug(KROSS_LOG) << "Kross Interpreter '" << libname <<
103  "' not available: " << lib.errorString();
104  } else if (function == LibraryFunctionModule) {
105  qCDebug(KROSS_LOG) << "Kross Module '" << libname <<
106  "' not available: " << lib.errorString();
107  } else {
108  qCWarning(KROSS_LOG) << "Failed to load unknown type of '" <<
109  libname << "' library: " << lib.errorString();
110  }
111 #endif
112  return nullptr;
113  }
114 
115  const char* functionName = function == LibraryFunctionInterpreter ? "krossinterpreter" : "krossmodule";
116  QFunctionPointer funcPtr = lib.resolve(functionName);
117  if (!funcPtr) {
118  qCWarning(KROSS_LOG) << QStringLiteral("Failed to resolve %1 in %2%3")
119  .arg(functionName)
120  .arg(lib.fileName())
121  .arg(libAbsoluteFilePath.isEmpty() ? "" : QString(" (%1)").arg(libAbsoluteFilePath));
122  }
123  return funcPtr;
124 }
125 
126 Manager::Manager()
127  : QObject()
128  , QScriptable()
130  , d(new Private())
131 {
132  d->strictTypesEnabled = true;
133  setObjectName("Kross");
134  d->collection = new ActionCollection("main");
135 
136 #ifdef KROSS_PYTHON_LIBRARY
137  if (QFunctionPointer funcPtr = loadLibrary(KROSS_PYTHON_LIBRARY, LibraryFunctionInterpreter)) {
138  d->interpreterinfos.insert("python",
139  new InterpreterInfo("python",
140  funcPtr, // library
141  "*.py", // file filter-wildcard
142  QStringList() << "text/x-python" // mimetypes
143  )
144  );
145  }
146 #endif
147 
148 #ifdef KROSS_RUBY_LIBRARY
149  if (QFunctionPointer funcPtr = loadLibrary(KROSS_RUBY_LIBRARY, LibraryFunctionInterpreter)) {
151  options.insert("safelevel", new InterpreterInfo::Option(
152  i18n("Level of safety of the Ruby interpreter"),
153  QVariant(0))); // 0 -> unsafe, 4 -> very safe
154  d->interpreterinfos.insert("ruby",
155  new InterpreterInfo("ruby",
156  funcPtr, // library
157  "*.rb", // file filter-wildcard
158  QStringList() << /* "text/x-ruby" << */ "application/x-ruby", // mimetypes
159  options // options
160  )
161  );
162  }
163 #endif
164 
165 #ifdef KROSS_JAVA_LIBRARY
166  if (QFunctionPointer funcPtr = loadLibrary(KROSS_JAVA_LIBRARY, LibraryFunctionInterpreter)) {
167  d->interpreterinfos.insert("java",
168  new InterpreterInfo("java",
169  funcPtr, // library
170  "*.java *.class *.jar", // file filter-wildcard
171  QStringList() << "application/java" // mimetypes
172  )
173  );
174  }
175 #endif
176 
177 #ifdef KROSS_FALCON_LIBRARY
178  if (QFunctionPointer funcPtr = loadLibrary(KROSS_FALCON_LIBRARY, LibraryFunctionInterpreter)) {
179  d->interpreterinfos.insert("falcon",
180  new InterpreterInfo("falcon",
181  funcPtr, // library
182  "*.fal", // file filter-wildcard
183  QStringList() << "application/x-falcon" // mimetypes
184  )
185  );
186  }
187 #endif
188 
189 #ifdef KROSS_QTSCRIPT_LIBRARY
190  if (QFunctionPointer funcPtr = loadLibrary(KROSS_QTSCRIPT_LIBRARY, LibraryFunctionInterpreter)) {
191  d->interpreterinfos.insert("qtscript",
192  new InterpreterInfo("qtscript",
193  funcPtr, // library
194  "*.es", // file filter-wildcard
195  QStringList() << "application/ecmascript" // mimetypes
196  )
197  );
198  }
199 #endif
200 
201 #ifdef KROSS_LUA_LIBRARY
202  if (QFunctionPointer funcPtr = loadLibrary(KROSS_LUA_LIBRARY, LibraryFunctionInterpreter)) {
203  d->interpreterinfos.insert("lua",
204  new InterpreterInfo("lua",
205  funcPtr, // library
206  "*.lua *.luac", // file filter-wildcard
207  QStringList() << "application/x-lua" // mimetypes
208  )
209  );
210  }
211 #endif
212 
213  // fill the list of supported interpreternames.
214  QHash<QString, InterpreterInfo *>::Iterator it(d->interpreterinfos.begin());
215  for (; it != d->interpreterinfos.end(); ++it)
216  if (it.value()) {
217  d->interpreters << it.key();
218  }
219  d->interpreters.sort();
220 
221  // publish ourself.
222  ChildrenInterface::addObject(this, "Kross");
223 }
224 
225 Manager::~Manager()
226 {
227  qDeleteAll(d->wrappers);
228  qDeleteAll(d->interpreterinfos);
229  qDeleteAll(d->modules);
230  delete d->collection;
231  delete d;
232 }
233 
234 QHash< QString, InterpreterInfo * > Manager::interpreterInfos() const
235 {
236  return d->interpreterinfos;
237 }
238 
239 bool Manager::hasInterpreterInfo(const QString &interpretername) const
240 {
241  return d->interpreterinfos.contains(interpretername) && d->interpreterinfos[interpretername];
242 }
243 
244 InterpreterInfo *Manager::interpreterInfo(const QString &interpretername) const
245 {
246  return hasInterpreterInfo(interpretername) ? d->interpreterinfos[interpretername] : nullptr;
247 }
248 
249 const QString Manager::interpreternameForFile(const QString &file)
250 {
251  QRegExp rx;
253  for (QHash<QString, InterpreterInfo *>::Iterator it = d->interpreterinfos.begin(); it != d->interpreterinfos.end(); ++it) {
254  if (! it.value()) {
255  continue;
256  }
257  foreach (const QString &wildcard, it.value()->wildcard().split(' ', Qt::SkipEmptyParts)) {
258  rx.setPattern(wildcard);
259  if (rx.exactMatch(file)) {
260  return it.value()->interpreterName();
261  }
262  }
263  }
264  return QString();
265 }
266 
267 Interpreter *Manager::interpreter(const QString &interpretername) const
268 {
269  if (! hasInterpreterInfo(interpretername)) {
270  qCWarning(KROSS_LOG) << "No such interpreter " << interpretername;
271  return nullptr;
272  }
273  return d->interpreterinfos[interpretername]->interpreter();
274 }
275 
276 QStringList Manager::interpreters() const
277 {
278  return d->interpreters;
279 }
280 
281 ActionCollection *Manager::actionCollection() const
282 {
283  return d->collection;
284 }
285 
286 bool Manager::hasAction(const QString &name)
287 {
288  return findChild< Action * >(name) != nullptr;
289 }
290 
291 QObject *Manager::action(const QString &name)
292 {
293  Action *action = findChild< Action * >(name);
294  if (! action) {
295  action = new Action(this, name);
296 #if 0
297  d->actioncollection->insert(action); //FIXME should we really remember the action?
298 #endif
299  }
300  return action;
301 }
302 
303 QObject *Manager::module(const QString &modulename)
304 {
305  if (d->modules.contains(modulename)) {
306  QObject *obj = d->modules[modulename];
307  if (obj) {
308  return obj;
309  }
310  }
311 
312  if (modulename.isEmpty() || modulename.contains(QRegExp("[^a-zA-Z0-9]"))) {
313  qCWarning(KROSS_LOG) << "Invalid module name " << modulename;
314  return nullptr;
315  }
316 
317  QByteArray libraryname = QString("krossmodule%1").arg(modulename).toLower().toLatin1();
318 
319  if (QFunctionPointer funcPtr = loadLibrary(libraryname.constData(), LibraryFunctionModule)) {
320  def_module_func func = (def_module_func) funcPtr;
321  Q_ASSERT(func);
322  QObject *module = (QObject *)(func)(); // call the function
323  Q_ASSERT(module);
324  //krossdebug( QString("Manager::module Module successfully loaded: modulename=%1 module.objectName=%2 module.className=%3").arg(modulename).arg(module->objectName()).arg(module->metaObject()->className()) );
325  d->modules.insert(modulename, module);
326  return module;
327  } else {
328  qCWarning(KROSS_LOG) << "Failed to load module " << modulename;
329  }
330  return nullptr;
331 }
332 
333 void Manager::deleteModules()
334 {
335  qDeleteAll(d->modules);
336  d->modules.clear();
337 }
338 
339 bool Manager::executeScriptFile(const QUrl &file)
340 {
341  qCDebug(KROSS_LOG) << "Manager::executeScriptFile() file=" << file.toString();
342  Action *action = new Action(nullptr /*no parent*/, file);
343  action->trigger();
344  bool ok = ! action->hadError();
345  delete action; //action->delayedDestruct();
346  return ok;
347 }
348 
349 void Manager::addQObject(QObject *obj, const QString &name)
350 {
351  this->addObject(obj, name);
352 }
353 
354 QObject *Manager::qobject(const QString &name) const
355 {
356  return this->object(name);
357 }
358 
359 QStringList Manager::qobjectNames() const
360 {
361  return this->objects().keys();
362 }
363 
364 MetaTypeHandler *Manager::metaTypeHandler(const QByteArray &typeName) const
365 {
366  return d->wrappers.contains(typeName) ? d->wrappers[typeName] : nullptr;
367 }
368 
369 void Manager::registerMetaTypeHandler(const QByteArray &typeName, MetaTypeHandler::FunctionPtr *handler)
370 {
371  d->wrappers.insert(typeName, new MetaTypeHandler(handler));
372 }
373 
374 void Manager::registerMetaTypeHandler(const QByteArray &typeName, MetaTypeHandler::FunctionPtr2 *handler)
375 {
376  d->wrappers.insert(typeName, new MetaTypeHandler(handler));
377 }
378 
379 void Manager::registerMetaTypeHandler(const QByteArray &typeName, MetaTypeHandler *handler)
380 {
381  d->wrappers.insert(typeName, handler);
382 }
383 
384 bool Manager::strictTypesEnabled() const
385 {
386  return d->strictTypesEnabled;
387 }
388 
389 void Manager::setStrictTypesEnabled(bool enabled)
390 {
391  d->strictTypesEnabled = enabled;
392 }
393 
394 bool Manager::hasHandlerAssigned(const QByteArray &typeName) const
395 {
396  return d->wrappers.contains(typeName);
397 }
398 
void setPatternSyntax(QRegExp::PatternSyntax syntax)
bool hadError() const
void addObject(QObject *object, const QString &name=QString(), Options options=NoOption)
Add a QObject to the list of children.
Definition: action.cpp:36
void setLoadHints(QLibrary::LoadHints hints)
Each interpreter is able to define options we could use to manipulate the interpreter behaviour...
Q_GLOBAL_STATIC(Internal::StaticControl, s_instance) class ControlPrivate
KDB_EXPORT QStringList libraryPaths()
QString toString(QUrl::FormattingOptions options) const const
void trigger()
The InterpreterInfo class provides abstract information about a Interpreter before the interpreter-ba...
QString filePath() const const
void setPattern(const QString &pattern)
void setObjectName(const QString &name)
QString absoluteFilePath() const const
bool isEmpty() const const
const char * constData() const const
Interface for managing Object collections.
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QCoreApplication * instance()
ExportExternalSymbolsHint
Base class for interpreter implementations.
bool isLoaded() const const
QString toLower() const const
bool load()
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
SkipEmptyParts
QString i18n(const char *text, const TYPE &arg...)
void setFileName(const QString &fileName)
QByteArray toLatin1() const const
QFunctionPointer resolve(const char *symbol)
Base class for metatype-handlers as used returned by the Kross::Manager::metaTypeHandler() method...
Definition: metatype.h:195
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QMap::iterator insert(const Key &key, const T &value)
The Action class is an abstract container to deal with scripts like a single standalone script file...
Definition: action.h:95
The ActionCollection class manages collections of Action instances.
bool exactMatch(const QString &str) const const
QString errorString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sun Oct 24 2021 22:59:02 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.