File indexing completed on 2024-04-21 15:02:58
0001 /*************************************************************************** 0002 * manager.cpp 0003 * This file is part of the KDE project 0004 * copyright (C)2004-2007 by Sebastian Sauer (mail@dipe.org) 0005 * 0006 * This program is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU Library General Public 0008 * License as published by the Free Software Foundation; either 0009 * version 2 of the License, or (at your option) any later version. 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 * Library General Public License for more details. 0014 * You should have received a copy of the GNU Library General Public License 0015 * along with this program; see the file COPYING. If not, write to 0016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 ***************************************************************************/ 0019 0020 #include "manager.h" 0021 #include "interpreter.h" 0022 #include "action.h" 0023 #include "actioncollection.h" 0024 #include "kross_debug.h" 0025 0026 #include <QObject> 0027 #include <QArgument> 0028 #include <QFile> 0029 #include <QRegExp> 0030 #include <QFileInfo> 0031 #include <QPointer> 0032 #include <QLibrary> 0033 #include <QCoreApplication> 0034 0035 #include <klocalizedstring.h> 0036 0037 extern "C" 0038 { 0039 typedef QObject *(*def_module_func)(); 0040 } 0041 0042 using namespace Kross; 0043 0044 namespace Kross 0045 { 0046 0047 /// @internal 0048 class Manager::Private 0049 { 0050 public: 0051 /// List of \a InterpreterInfo instances. 0052 QHash< QString, InterpreterInfo * > interpreterinfos; 0053 0054 /// List of the interpreter names. 0055 QStringList interpreters; 0056 0057 /// Loaded modules. 0058 QHash< QString, QPointer<QObject> > modules; 0059 0060 /// The collection of \a Action instances. 0061 ActionCollection *collection; 0062 0063 /// List with custom handlers for metatypes. 0064 QHash<QByteArray, MetaTypeHandler *> wrappers; 0065 0066 /// Strict type handling enabled or disabled. 0067 bool strictTypesEnabled; 0068 }; 0069 0070 } 0071 0072 Q_GLOBAL_STATIC(Manager, _self) 0073 0074 Manager &Manager::self() 0075 { 0076 return *_self(); 0077 } 0078 0079 enum LibraryFunction 0080 { 0081 LibraryFunctionInterpreter, 0082 LibraryFunctionModule 0083 }; 0084 0085 static QFunctionPointer loadLibrary(const char *libname, enum LibraryFunction function) 0086 { 0087 QLibrary lib; 0088 QString libAbsoluteFilePath; 0089 foreach (const QString &path, QCoreApplication::instance()->libraryPaths()) { 0090 const QFileInfo &fileInfo = QFileInfo(path, libname); 0091 lib.setFileName(fileInfo.filePath()); 0092 lib.setLoadHints(QLibrary::ExportExternalSymbolsHint); 0093 if (lib.load()) { 0094 libAbsoluteFilePath = fileInfo.absoluteFilePath(); 0095 break; 0096 } 0097 } 0098 0099 if (!lib.isLoaded()) { 0100 #ifdef KROSS_INTERPRETER_DEBUG 0101 if (function == LibraryFunctionInterpreter) { 0102 qCDebug(KROSS_LOG) << "Kross Interpreter '" << libname << 0103 "' not available: " << lib.errorString(); 0104 } else if (function == LibraryFunctionModule) { 0105 qCDebug(KROSS_LOG) << "Kross Module '" << libname << 0106 "' not available: " << lib.errorString(); 0107 } else { 0108 qCWarning(KROSS_LOG) << "Failed to load unknown type of '" << 0109 libname << "' library: " << lib.errorString(); 0110 } 0111 #endif 0112 return nullptr; 0113 } 0114 0115 const char* functionName = function == LibraryFunctionInterpreter ? "krossinterpreter" : "krossmodule"; 0116 QFunctionPointer funcPtr = lib.resolve(functionName); 0117 if (!funcPtr) { 0118 qCWarning(KROSS_LOG) << QStringLiteral("Failed to resolve %1 in %2%3") 0119 .arg(functionName) 0120 .arg(lib.fileName()) 0121 .arg(libAbsoluteFilePath.isEmpty() ? "" : QString(" (%1)").arg(libAbsoluteFilePath)); 0122 } 0123 return funcPtr; 0124 } 0125 0126 Manager::Manager() 0127 : QObject() 0128 , QScriptable() 0129 , ChildrenInterface() 0130 , d(new Private()) 0131 { 0132 d->strictTypesEnabled = true; 0133 setObjectName("Kross"); 0134 d->collection = new ActionCollection("main"); 0135 0136 #ifdef KROSS_PYTHON_LIBRARY 0137 if (QFunctionPointer funcPtr = loadLibrary(KROSS_PYTHON_LIBRARY, LibraryFunctionInterpreter)) { 0138 d->interpreterinfos.insert("python", 0139 new InterpreterInfo("python", 0140 funcPtr, // library 0141 "*.py", // file filter-wildcard 0142 QStringList() << "text/x-python" // mimetypes 0143 ) 0144 ); 0145 } 0146 #endif 0147 0148 #ifdef KROSS_RUBY_LIBRARY 0149 if (QFunctionPointer funcPtr = loadLibrary(KROSS_RUBY_LIBRARY, LibraryFunctionInterpreter)) { 0150 InterpreterInfo::Option::Map options; 0151 options.insert("safelevel", new InterpreterInfo::Option( 0152 i18n("Level of safety of the Ruby interpreter"), 0153 QVariant(0))); // 0 -> unsafe, 4 -> very safe 0154 d->interpreterinfos.insert("ruby", 0155 new InterpreterInfo("ruby", 0156 funcPtr, // library 0157 "*.rb", // file filter-wildcard 0158 QStringList() << /* "text/x-ruby" << */ "application/x-ruby", // mimetypes 0159 options // options 0160 ) 0161 ); 0162 } 0163 #endif 0164 0165 #ifdef KROSS_JAVA_LIBRARY 0166 if (QFunctionPointer funcPtr = loadLibrary(KROSS_JAVA_LIBRARY, LibraryFunctionInterpreter)) { 0167 d->interpreterinfos.insert("java", 0168 new InterpreterInfo("java", 0169 funcPtr, // library 0170 "*.java *.class *.jar", // file filter-wildcard 0171 QStringList() << "application/java" // mimetypes 0172 ) 0173 ); 0174 } 0175 #endif 0176 0177 #ifdef KROSS_FALCON_LIBRARY 0178 if (QFunctionPointer funcPtr = loadLibrary(KROSS_FALCON_LIBRARY, LibraryFunctionInterpreter)) { 0179 d->interpreterinfos.insert("falcon", 0180 new InterpreterInfo("falcon", 0181 funcPtr, // library 0182 "*.fal", // file filter-wildcard 0183 QStringList() << "application/x-falcon" // mimetypes 0184 ) 0185 ); 0186 } 0187 #endif 0188 0189 #ifdef KROSS_QTSCRIPT_LIBRARY 0190 if (QFunctionPointer funcPtr = loadLibrary(KROSS_QTSCRIPT_LIBRARY, LibraryFunctionInterpreter)) { 0191 d->interpreterinfos.insert("qtscript", 0192 new InterpreterInfo("qtscript", 0193 funcPtr, // library 0194 "*.es", // file filter-wildcard 0195 QStringList() << "application/ecmascript" // mimetypes 0196 ) 0197 ); 0198 } 0199 #endif 0200 0201 #ifdef KROSS_LUA_LIBRARY 0202 if (QFunctionPointer funcPtr = loadLibrary(KROSS_LUA_LIBRARY, LibraryFunctionInterpreter)) { 0203 d->interpreterinfos.insert("lua", 0204 new InterpreterInfo("lua", 0205 funcPtr, // library 0206 "*.lua *.luac", // file filter-wildcard 0207 QStringList() << "application/x-lua" // mimetypes 0208 ) 0209 ); 0210 } 0211 #endif 0212 0213 // fill the list of supported interpreternames. 0214 QHash<QString, InterpreterInfo *>::Iterator it(d->interpreterinfos.begin()); 0215 for (; it != d->interpreterinfos.end(); ++it) 0216 if (it.value()) { 0217 d->interpreters << it.key(); 0218 } 0219 d->interpreters.sort(); 0220 0221 // publish ourself. 0222 ChildrenInterface::addObject(this, "Kross"); 0223 } 0224 0225 Manager::~Manager() 0226 { 0227 qDeleteAll(d->wrappers); 0228 qDeleteAll(d->interpreterinfos); 0229 qDeleteAll(d->modules); 0230 delete d->collection; 0231 delete d; 0232 } 0233 0234 QHash< QString, InterpreterInfo * > Manager::interpreterInfos() const 0235 { 0236 return d->interpreterinfos; 0237 } 0238 0239 bool Manager::hasInterpreterInfo(const QString &interpretername) const 0240 { 0241 return d->interpreterinfos.contains(interpretername) && d->interpreterinfos[interpretername]; 0242 } 0243 0244 InterpreterInfo *Manager::interpreterInfo(const QString &interpretername) const 0245 { 0246 return hasInterpreterInfo(interpretername) ? d->interpreterinfos[interpretername] : nullptr; 0247 } 0248 0249 const QString Manager::interpreternameForFile(const QString &file) 0250 { 0251 QRegExp rx; 0252 rx.setPatternSyntax(QRegExp::Wildcard); 0253 for (QHash<QString, InterpreterInfo *>::Iterator it = d->interpreterinfos.begin(); it != d->interpreterinfos.end(); ++it) { 0254 if (! it.value()) { 0255 continue; 0256 } 0257 foreach (const QString &wildcard, it.value()->wildcard().split(' ', Qt::SkipEmptyParts)) { 0258 rx.setPattern(wildcard); 0259 if (rx.exactMatch(file)) { 0260 return it.value()->interpreterName(); 0261 } 0262 } 0263 } 0264 return QString(); 0265 } 0266 0267 Interpreter *Manager::interpreter(const QString &interpretername) const 0268 { 0269 if (! hasInterpreterInfo(interpretername)) { 0270 qCWarning(KROSS_LOG) << "No such interpreter " << interpretername; 0271 return nullptr; 0272 } 0273 return d->interpreterinfos[interpretername]->interpreter(); 0274 } 0275 0276 QStringList Manager::interpreters() const 0277 { 0278 return d->interpreters; 0279 } 0280 0281 ActionCollection *Manager::actionCollection() const 0282 { 0283 return d->collection; 0284 } 0285 0286 bool Manager::hasAction(const QString &name) 0287 { 0288 return findChild< Action * >(name) != nullptr; 0289 } 0290 0291 QObject *Manager::action(const QString &name) 0292 { 0293 Action *action = findChild< Action * >(name); 0294 if (! action) { 0295 action = new Action(this, name); 0296 #if 0 0297 d->actioncollection->insert(action); //FIXME should we really remember the action? 0298 #endif 0299 } 0300 return action; 0301 } 0302 0303 QObject *Manager::module(const QString &modulename) 0304 { 0305 if (d->modules.contains(modulename)) { 0306 QObject *obj = d->modules[modulename]; 0307 if (obj) { 0308 return obj; 0309 } 0310 } 0311 0312 if (modulename.isEmpty() || modulename.contains(QRegExp("[^a-zA-Z0-9]"))) { 0313 qCWarning(KROSS_LOG) << "Invalid module name " << modulename; 0314 return nullptr; 0315 } 0316 0317 QByteArray libraryname = QString("krossmodule%1").arg(modulename).toLower().toLatin1(); 0318 0319 if (QFunctionPointer funcPtr = loadLibrary(libraryname.constData(), LibraryFunctionModule)) { 0320 def_module_func func = (def_module_func) funcPtr; 0321 Q_ASSERT(func); 0322 QObject *module = (QObject *)(func)(); // call the function 0323 Q_ASSERT(module); 0324 //krossdebug( QString("Manager::module Module successfully loaded: modulename=%1 module.objectName=%2 module.className=%3").arg(modulename).arg(module->objectName()).arg(module->metaObject()->className()) ); 0325 d->modules.insert(modulename, module); 0326 return module; 0327 } else { 0328 qCWarning(KROSS_LOG) << "Failed to load module " << modulename; 0329 } 0330 return nullptr; 0331 } 0332 0333 void Manager::deleteModules() 0334 { 0335 qDeleteAll(d->modules); 0336 d->modules.clear(); 0337 } 0338 0339 bool Manager::executeScriptFile(const QUrl &file) 0340 { 0341 qCDebug(KROSS_LOG) << "Manager::executeScriptFile() file=" << file.toString(); 0342 Action *action = new Action(nullptr /*no parent*/, file); 0343 action->trigger(); 0344 bool ok = ! action->hadError(); 0345 delete action; //action->delayedDestruct(); 0346 return ok; 0347 } 0348 0349 void Manager::addQObject(QObject *obj, const QString &name) 0350 { 0351 this->addObject(obj, name); 0352 } 0353 0354 QObject *Manager::qobject(const QString &name) const 0355 { 0356 return this->object(name); 0357 } 0358 0359 QStringList Manager::qobjectNames() const 0360 { 0361 return this->objects().keys(); 0362 } 0363 0364 MetaTypeHandler *Manager::metaTypeHandler(const QByteArray &typeName) const 0365 { 0366 return d->wrappers.contains(typeName) ? d->wrappers[typeName] : nullptr; 0367 } 0368 0369 void Manager::registerMetaTypeHandler(const QByteArray &typeName, MetaTypeHandler::FunctionPtr *handler) 0370 { 0371 d->wrappers.insert(typeName, new MetaTypeHandler(handler)); 0372 } 0373 0374 void Manager::registerMetaTypeHandler(const QByteArray &typeName, MetaTypeHandler::FunctionPtr2 *handler) 0375 { 0376 d->wrappers.insert(typeName, new MetaTypeHandler(handler)); 0377 } 0378 0379 void Manager::registerMetaTypeHandler(const QByteArray &typeName, MetaTypeHandler *handler) 0380 { 0381 d->wrappers.insert(typeName, handler); 0382 } 0383 0384 bool Manager::strictTypesEnabled() const 0385 { 0386 return d->strictTypesEnabled; 0387 } 0388 0389 void Manager::setStrictTypesEnabled(bool enabled) 0390 { 0391 d->strictTypesEnabled = enabled; 0392 } 0393 0394 bool Manager::hasHandlerAssigned(const QByteArray &typeName) const 0395 { 0396 return d->wrappers.contains(typeName); 0397 } 0398 0399 #include "moc_manager.cpp"