Kross
manager.cpp
Go to the documentation of this file.
00001 /*************************************************************************** 00002 * manager.cpp 00003 * This file is part of the KDE project 00004 * copyright (C)2004-2007 by Sebastian Sauer (mail@dipe.org) 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Library General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2 of the License, or (at your option) any later version. 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Library General Public License for more details. 00014 * You should have received a copy of the GNU Library General Public License 00015 * along with this program; see the file COPYING. If not, write to 00016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 * Boston, MA 02110-1301, USA. 00018 ***************************************************************************/ 00019 00020 #include "manager.h" 00021 #include "interpreter.h" 00022 #include "action.h" 00023 #include "actioncollection.h" 00024 00025 #include <QtCore/QObject> 00026 #include <QtCore/QArgument> 00027 #include <QtCore/QFile> 00028 #include <QtCore/QRegExp> 00029 #include <QtCore/QFileInfo> 00030 #include <QtCore/QPointer> 00031 #include <QtCore/QLibrary> 00032 #include <QtCore/QCoreApplication> 00033 00034 #include <kstandarddirs.h> 00035 #include <klocale.h> 00036 00037 extern "C" 00038 { 00039 typedef QObject* (*def_module_func)(); 00040 } 00041 00042 using namespace Kross; 00043 00044 namespace Kross { 00045 00047 class Manager::Private 00048 { 00049 public: 00051 QHash< QString, InterpreterInfo* > interpreterinfos; 00052 00054 QStringList interpreters; 00055 00057 QHash< QString, QPointer<QObject> > modules; 00058 00060 ActionCollection* collection; 00061 00063 QHash<QByteArray, MetaTypeHandler*> wrappers; 00064 00066 bool strictTypesEnabled; 00067 }; 00068 00069 } 00070 00071 Q_GLOBAL_STATIC(Manager, _self) 00072 00073 Manager& Manager::self() 00074 { 00075 return *_self(); 00076 } 00077 00078 void* loadLibrary(const char* libname, const char* functionname) 00079 { 00080 QLibrary lib(libname); 00081 lib.setLoadHints( QLibrary::ExportExternalSymbolsHint ); 00082 if( ! lib.load() ) { 00083 const QString err = QString("Error: %1").arg(lib.errorString()); 00084 00085 //TODO move that functionality out of Kross since we like to be Qt-only 00086 foreach(const QString &dir, KStandardDirs().resourceDirs("module")) { 00087 lib.setFileName( QFileInfo(dir, libname).filePath() ); 00088 lib.setLoadHints( QLibrary::ExportExternalSymbolsHint ); 00089 if( lib.load() ) 00090 break; 00091 } 00092 00093 /* 00094 if( ! lib.isLoaded() ) { 00095 foreach(const QString& path, QCoreApplication::instance()->libraryPaths()) { 00096 lib.setFileName( QFileInfo(path, libname).filePath() ); 00097 lib.setLoadHints( QLibrary::ExportExternalSymbolsHint ); 00098 if( lib.load() ) 00099 break; 00100 } 00101 } 00102 */ 00103 00104 if( ! lib.isLoaded() ) { 00105 #ifdef KROSS_INTERPRETER_DEBUG 00106 if( strcmp(functionname, "krossinterpreter") == 0 ) 00107 krossdebug( QString("Kross Interpreter '%1' not available: %2").arg(libname).arg(err) ); 00108 else if( strcmp(functionname, "krossmodule") == 0 ) 00109 krossdebug( QString("Kross Module '%1' not available: %2").arg(libname).arg(err) ); 00110 else 00111 krosswarning( QString("Failed to load unknown type of '%1' library: %2").arg(libname).arg(err) ); 00112 #endif 00113 return 0; 00114 } 00115 } 00116 void* funcPtr = lib.resolve(functionname); 00117 Q_ASSERT(funcPtr); 00118 return funcPtr; 00119 } 00120 00121 Manager::Manager() 00122 : QObject() 00123 , QScriptable() 00124 , ChildrenInterface() 00125 , d( new Private() ) 00126 { 00127 d->strictTypesEnabled = true; 00128 setObjectName("Kross"); 00129 d->collection = new ActionCollection("main"); 00130 00131 #ifdef KROSS_PYTHON_LIBRARY 00132 if( void* funcPtr = loadLibrary(KROSS_PYTHON_LIBRARY, "krossinterpreter") ) { 00133 d->interpreterinfos.insert("python", 00134 new InterpreterInfo("python", 00135 funcPtr, // library 00136 "*.py", // file filter-wildcard 00137 QStringList() << "text/x-python" // mimetypes 00138 ) 00139 ); 00140 } 00141 #endif 00142 00143 #ifdef KROSS_RUBY_LIBRARY 00144 if( void* funcPtr = loadLibrary(KROSS_RUBY_LIBRARY, "krossinterpreter") ) { 00145 InterpreterInfo::Option::Map options; 00146 options.insert("safelevel", new InterpreterInfo::Option( 00147 i18n("Level of safety of the Ruby interpreter"), 00148 QVariant(0) )); // 0 -> unsafe, 4 -> very safe 00149 d->interpreterinfos.insert("ruby", 00150 new InterpreterInfo("ruby", 00151 funcPtr, // library 00152 "*.rb", // file filter-wildcard 00153 QStringList() << /* "text/x-ruby" << */ "application/x-ruby", // mimetypes 00154 options // options 00155 ) 00156 ); 00157 } 00158 #endif 00159 00160 #ifdef KROSS_JAVA_LIBRARY 00161 if( void* funcPtr = loadLibrary(KROSS_JAVA_LIBRARY, "krossinterpreter") ) { 00162 d->interpreterinfos.insert("java", 00163 new InterpreterInfo("java", 00164 funcPtr, // library 00165 "*.java *.class *.jar", // file filter-wildcard 00166 QStringList() << "application/java" // mimetypes 00167 ) 00168 ); 00169 } 00170 #endif 00171 00172 #ifdef KROSS_KJS_LIBRARY 00173 if( void* funcPtr = loadLibrary(KROSS_KJS_LIBRARY, "krossinterpreter") ) { 00174 d->interpreterinfos.insert("javascript", 00175 new InterpreterInfo("javascript", 00176 funcPtr, // library 00177 "*.js", // file filter-wildcard 00178 QStringList() << "application/javascript" // mimetypes 00179 ) 00180 ); 00181 } 00182 #endif 00183 00184 #ifdef KROSS_FALCON_LIBRARY 00185 if( void* funcPtr = loadLibrary(KROSS_FALCON_LIBRARY, "krossinterpreter") ) { 00186 d->interpreterinfos.insert("falcon", 00187 new InterpreterInfo("falcon", 00188 funcPtr, // library 00189 "*.fal", // file filter-wildcard 00190 QStringList() << "application/x-falcon" // mimetypes 00191 ) 00192 ); 00193 } 00194 #endif 00195 00196 #ifdef KROSS_QTSCRIPT_LIBRARY 00197 if( void* funcPtr = loadLibrary(KROSS_QTSCRIPT_LIBRARY, "krossinterpreter") ) { 00198 d->interpreterinfos.insert("qtscript", 00199 new InterpreterInfo("qtscript", 00200 funcPtr, // library 00201 "*.es", // file filter-wildcard 00202 QStringList() << "application/ecmascript" // mimetypes 00203 ) 00204 ); 00205 } 00206 #endif 00207 00208 #ifdef KROSS_LUA_LIBRARY 00209 if( void* funcPtr = loadLibrary(KROSS_LUA_LIBRARY, "krossinterpreter") ) { 00210 d->interpreterinfos.insert("lua", 00211 new InterpreterInfo("lua", 00212 funcPtr, // library 00213 "*.lua *.luac", // file filter-wildcard 00214 QStringList() << "application/x-lua" // mimetypes 00215 ) 00216 ); 00217 } 00218 #endif 00219 00220 // fill the list of supported interpreternames. 00221 QHash<QString, InterpreterInfo*>::Iterator it( d->interpreterinfos.begin() ); 00222 for(; it != d->interpreterinfos.end(); ++it) 00223 if( it.value() ) 00224 d->interpreters << it.key(); 00225 d->interpreters.sort(); 00226 00227 // publish ourself. 00228 ChildrenInterface::addObject(this, "Kross"); 00229 } 00230 00231 Manager::~Manager() 00232 { 00233 qDeleteAll(d->wrappers); 00234 qDeleteAll(d->interpreterinfos); 00235 qDeleteAll(d->modules); 00236 delete d->collection; 00237 delete d; 00238 } 00239 00240 QHash< QString, InterpreterInfo* > Manager::interpreterInfos() const 00241 { 00242 return d->interpreterinfos; 00243 } 00244 00245 bool Manager::hasInterpreterInfo(const QString& interpretername) const 00246 { 00247 return d->interpreterinfos.contains(interpretername) && d->interpreterinfos[interpretername]; 00248 } 00249 00250 InterpreterInfo* Manager::interpreterInfo(const QString& interpretername) const 00251 { 00252 return hasInterpreterInfo(interpretername) ? d->interpreterinfos[interpretername] : 0; 00253 } 00254 00255 const QString Manager::interpreternameForFile(const QString& file) 00256 { 00257 QRegExp rx; 00258 rx.setPatternSyntax(QRegExp::Wildcard); 00259 for(QHash<QString, InterpreterInfo*>::Iterator it = d->interpreterinfos.begin(); it != d->interpreterinfos.end(); ++it) { 00260 if( ! it.value() ) 00261 continue; 00262 foreach(const QString &wildcard, it.value()->wildcard().split(' ', QString::SkipEmptyParts)) { 00263 rx.setPattern( wildcard ); 00264 if( rx.exactMatch(file) ) 00265 return it.value()->interpreterName(); 00266 } 00267 } 00268 return QString(); 00269 } 00270 00271 Interpreter* Manager::interpreter(const QString& interpretername) const 00272 { 00273 if( ! hasInterpreterInfo(interpretername) ) { 00274 krosswarning( QString("No such interpreter '%1'").arg(interpretername) ); 00275 return 0; 00276 } 00277 return d->interpreterinfos[interpretername]->interpreter(); 00278 } 00279 00280 QStringList Manager::interpreters() const 00281 { 00282 return d->interpreters; 00283 } 00284 00285 ActionCollection* Manager::actionCollection() const 00286 { 00287 return d->collection; 00288 } 00289 00290 bool Manager::hasAction(const QString& name) 00291 { 00292 return findChild< Action* >(name) != 0L; 00293 } 00294 00295 QObject* Manager::action(const QString& name) 00296 { 00297 Action* action = findChild< Action* >(name); 00298 if(! action) { 00299 action = new Action(this, name); 00300 #if 0 00301 d->actioncollection->insert(action); //FIXME should we really remember the action? 00302 #endif 00303 } 00304 return action; 00305 } 00306 00307 QObject* Manager::module(const QString& modulename) 00308 { 00309 if( d->modules.contains(modulename) ) { 00310 QObject* obj = d->modules[modulename]; 00311 if( obj ) 00312 return obj; 00313 } 00314 00315 if( modulename.isEmpty() || modulename.contains( QRegExp("[^a-zA-Z0-9]") ) ) { 00316 krosswarning( QString("Invalid module name '%1'").arg(modulename) ); 00317 return 0; 00318 } 00319 00320 QByteArray libraryname = QString("krossmodule%1").arg(modulename).toLower().toLatin1(); 00321 00322 #if 0 00323 KLibLoader* loader = KLibLoader::self(); 00324 KLibrary* lib = loader->library( libraryname, QLibrary::ExportExternalSymbolsHint ); 00325 if( ! lib ) { //FIXME this fallback-code should be in KLibLoader imho. 00326 lib = loader->library( QString("lib%1").arg(libraryname), QLibrary::ExportExternalSymbolsHint ); 00327 if( ! lib ) { 00328 krosswarning( QString("Failed to load module '%1': %2").arg(modulename).arg(loader->lastErrorMessage()) ); 00329 return 0; 00330 } 00331 } 00332 00333 def_module_func func; 00334 func = (def_module_func) lib->resolveFunction("krossmodule"); 00335 if( ! func ) { 00336 krosswarning( QString("Failed to determinate init function in module '%1'").arg(modulename) ); 00337 return 0; 00338 } 00339 00340 QObject* module = (QObject*) (func)(); // call the function 00341 lib->unload(); // unload the library 00342 00343 if( ! module ) { 00344 krosswarning( QString("Failed to load module object '%1'").arg(modulename) ); 00345 return 0; 00346 } 00347 #else 00348 if( void* funcPtr = loadLibrary(libraryname, "krossmodule") ) { 00349 def_module_func func = (def_module_func) funcPtr; 00350 Q_ASSERT( func ); 00351 QObject* module = (QObject*) (func)(); // call the function 00352 Q_ASSERT( module ); 00353 //krossdebug( QString("Manager::module Module successfully loaded: modulename=%1 module.objectName=%2 module.className=%3").arg(modulename).arg(module->objectName()).arg(module->metaObject()->className()) ); 00354 d->modules.insert(modulename, module); 00355 return module; 00356 } 00357 else { 00358 krosswarning( QString("Failed to load module '%1'").arg(modulename) ); 00359 } 00360 #endif 00361 return 0; 00362 } 00363 00364 void Manager::deleteModules() 00365 { 00366 qDeleteAll(d->modules); 00367 d->modules.clear(); 00368 } 00369 00370 bool Manager::executeScriptFile(const QUrl& file) 00371 { 00372 krossdebug( QString("Manager::executeScriptFile() file='%1'").arg(file.toString()) ); 00373 Action* action = new Action(0 /*no parent*/, file); 00374 action->trigger(); 00375 bool ok = ! action->hadError(); 00376 delete action; //action->delayedDestruct(); 00377 return ok; 00378 } 00379 00380 void Manager::addQObject(QObject* obj, const QString &name) 00381 { 00382 this->addObject(obj, name); 00383 } 00384 00385 QObject* Manager::qobject(const QString &name) const 00386 { 00387 return this->object(name); 00388 } 00389 00390 QStringList Manager::qobjectNames() const 00391 { 00392 return this->objects().keys(); 00393 } 00394 00395 MetaTypeHandler* Manager::metaTypeHandler(const QByteArray& typeName) const 00396 { 00397 return d->wrappers.contains(typeName) ? d->wrappers[typeName] : 0; 00398 } 00399 00400 void Manager::registerMetaTypeHandler(const QByteArray& typeName, MetaTypeHandler::FunctionPtr* handler) 00401 { 00402 d->wrappers.insert(typeName, new MetaTypeHandler(handler)); 00403 } 00404 00405 void Manager::registerMetaTypeHandler(const QByteArray& typeName, MetaTypeHandler::FunctionPtr2* handler) 00406 { 00407 d->wrappers.insert(typeName, new MetaTypeHandler(handler)); 00408 } 00409 00410 void Manager::registerMetaTypeHandler(const QByteArray& typeName, MetaTypeHandler* handler) 00411 { 00412 d->wrappers.insert(typeName, handler); 00413 } 00414 00415 bool Manager::strictTypesEnabled() const 00416 { 00417 return d->strictTypesEnabled; 00418 } 00419 00420 void Manager::setStrictTypesEnabled(bool enabled) 00421 { 00422 d->strictTypesEnabled = enabled; 00423 } 00424 00425 bool Manager::hasHandlerAssigned(const QByteArray& typeName) const 00426 { 00427 return d->wrappers.contains(typeName); 00428 } 00429 00430 #include "manager.moc"
KDE 4.6 API Reference