kcmoduleloader.cpp
00001 /* 00002 Copyright (c) 1999 Matthias Hoelzer-Kluepfel <hoelzer@kde.org> 00003 Copyright (c) 2000 Matthias Elter <elter@kde.org> 00004 Copyright (c) 2003,2004 Matthias Kretz <kretz@kde.org> 00005 Copyright (c) 2004 Frans Englich <frans.englich@telia.com> 00006 00007 This file is part of the KDE project 00008 00009 This library is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU Library General Public 00011 License version 2, as published by the Free Software Foundation. 00012 00013 This library is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Library General Public License for more details. 00017 00018 You should have received a copy of the GNU Library General Public License 00019 along with this library; see the file COPYING.LIB. If not, write to 00020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00021 Boston, MA 02110-1301, USA. 00022 */ 00023 00024 #include <tqfile.h> 00025 #include <tqlabel.h> 00026 #include <tqlayout.h> 00027 00028 #include <kapplication.h> 00029 #include <kdebug.h> 00030 #include <klocale.h> 00031 #include <kmessagebox.h> 00032 #include <kparts/componentfactory.h> 00033 00034 #include "kcmoduleloader.h" 00035 00036 00037 /***************************************************************/ 00042 class KCMError : public KCModule 00043 { 00044 public: 00045 KCMError( const TQString& msg, const TQString& details, TQWidget* parent ) 00046 : KCModule( parent, "KCMError" ) 00047 { 00048 TQVBoxLayout* topLayout = new TQVBoxLayout( this ); 00049 topLayout->addWidget( new TQLabel( msg, this ) ); 00050 topLayout->addWidget( new TQLabel( details, this ) ); 00051 } 00052 }; 00053 /***************************************************************/ 00054 00055 00056 00057 00058 KCModule* KCModuleLoader::load(const KCModuleInfo &mod, const TQString &libname, 00059 KLibLoader *loader, ErrorReporting report, TQWidget * parent, 00060 const char * name, const TQStringList & args ) 00061 { 00062 // attempt to load modules with ComponentFactory, only if the symbol init_<lib> exists 00063 // (this is because some modules, e.g. kcmkio with multiple modules in the library, 00064 // cannot be ported to KGenericFactory) 00065 KLibrary *lib = loader->library(TQFile::encodeName(libname.arg(mod.library()))); 00066 if (lib) { 00067 TQString initSym("init_"); 00068 initSym += libname.arg(mod.library()); 00069 00070 if ( lib->hasSymbol(TQFile::encodeName(initSym)) ) 00071 { 00072 KLibFactory *factory = lib->factory(); 00073 if ( factory ) 00074 { 00075 KCModule *module = KParts::ComponentFactory::createInstanceFromFactory<KCModule>( factory, TQT_TQOBJECT(parent), name ? name : mod.handle().latin1(), args ); 00076 if (module) 00077 return module; 00078 } 00079 // else do a fallback 00080 kdDebug(1208) << "Unable to load module using ComponentFactory. Falling back to old loader." << endl; 00081 } 00082 00083 // get the create_ function 00084 TQString factory("create_%1"); 00085 void *create = lib->symbol(TQFile::encodeName(factory.arg(mod.handle()))); 00086 00087 if (create) 00088 { 00089 // create the module 00090 KCModule* (*func)(TQWidget *, const char *); 00091 func = (KCModule* (*)(TQWidget *, const char *)) create; 00092 return func( parent, name ? name : mod.handle().latin1() ); 00093 } 00094 else 00095 { 00096 TQString libFileName = lib->fileName(); 00097 lib->unload(); 00098 return reportError( report, i18n("<qt>There was an error when loading the module '%1'.<br><br>" 00099 "The desktop file (%2) as well as the library (%3) was found but " 00100 "yet the module could not be loaded properly. Most likely " 00101 "the factory declaration was wrong, or the " 00102 "create_* function was missing.</qt>") 00103 .arg( mod.moduleName() ) 00104 .arg( mod.fileName() ) 00105 .arg( libFileName ), 00106 TQString::null, parent ); 00107 } 00108 00109 lib->unload(); 00110 } 00111 return reportError( report, i18n("The specified library %1 could not be found.") 00112 .arg( mod.library() ), TQString::null, parent ); 00113 return 0; 00114 } 00115 00116 KCModule* KCModuleLoader::loadModule(const KCModuleInfo &mod, bool withfallback, TQWidget * parent, const char * name, const TQStringList & args ) 00117 { 00118 return loadModule( mod, None, withfallback, parent, name, args ); 00119 } 00120 00121 KCModule* KCModuleLoader::loadModule(const KCModuleInfo &mod, ErrorReporting report, bool withfallback, TQWidget * parent, const char * name, const TQStringList & args ) 00122 { 00123 /* 00124 * Simple libraries as modules are the easiest case: 00125 * We just have to load the library and get the module 00126 * from the factory. 00127 */ 00128 00129 if ( !mod.service() ) 00130 { 00131 if ( mod.moduleName() == "kcmlisa" || mod.moduleName() == "kcmkiolan" ) 00132 { 00133 return reportError( report, 00134 i18n("The module %1 could not be found.") 00135 .arg( mod.moduleName() ), 00136 i18n("<qt><p>The Lisa and lan:/ ioslave modules " 00137 "are not installed by default in Kubuntu, because they are obsolete " 00138 "and replaced by zeroconf.<br> If you still wish to use them, you " 00139 "should install the lisa package from the Universe repository.</p></qt>"), 00140 parent ); 00141 } else { 00142 return reportError( report, 00143 i18n("The module %1 could not be found.") 00144 .arg( mod.moduleName() ), 00145 i18n("<qt><p>The diagnostics is:<br>The desktop file %1 could not be found.</p></qt>").arg(mod.fileName()), 00146 parent ); 00147 } 00148 } 00149 00150 if (!mod.library().isEmpty()) 00151 { 00152 // get the library loader instance 00153 00154 KLibLoader *loader = KLibLoader::self(); 00155 00156 KCModule *module = load(mod, "kcm_%1", loader, report, parent, name, args ); 00157 /* 00158 * Only try to load libkcm_* if it exists, otherwise KLibLoader::lastErrorMessage would say 00159 * "libkcm_foo not found" instead of the real problem with loading kcm_foo. 00160 */ 00161 if (!KLibLoader::findLibrary( TQCString( "libkcm_" ) + TQFile::encodeName( mod.library() ) ).isEmpty() ) 00162 module = load(mod, "libkcm_%1", loader, report, parent, name, args ); 00163 if (module) 00164 return module; 00165 return reportError( report, 00166 i18n("The module %1 could not be loaded.") 00167 .arg( mod.moduleName() ), TQString::null, parent ); 00168 } 00169 00170 /* 00171 * Ok, we could not load the library. 00172 * Try to run it as an executable. 00173 * This must not be done when calling from kcmshell, or you'll 00174 * have infinite recursion 00175 * (startService calls kcmshell which calls modloader which calls startService...) 00176 * 00177 */ 00178 if(withfallback) 00179 { 00180 KApplication::startServiceByDesktopPath(mod.fileName(), TQString::null); 00181 } 00182 else 00183 { 00184 return reportError( report, 00185 i18n("The module %1 is not a valid configuration module.") 00186 .arg( mod.moduleName() ), i18n("<qt><p>The diagnostics is:<br>The desktop file %1 does not specify a library.</qt>").arg(mod.fileName()), parent ); 00187 } 00188 00189 return 0; 00190 } 00191 00192 KCModule* KCModuleLoader::loadModule(const TQString &module, TQWidget *parent, 00193 const char *name, const TQStringList & args) 00194 { 00195 return loadModule(KCModuleInfo(module), None, false, parent, name, args); 00196 } 00197 00198 KCModule* KCModuleLoader::loadModule(const TQString &module, ErrorReporting 00199 report, TQWidget *parent, const char *name, const TQStringList & args) 00200 { 00201 return loadModule(KCModuleInfo(module), report, false, parent, name, args); 00202 } 00203 00204 void KCModuleLoader::unloadModule(const KCModuleInfo &mod) 00205 { 00206 // get the library loader instance 00207 KLibLoader *loader = KLibLoader::self(); 00208 00209 // try to unload the library 00210 TQString libname("libkcm_%1"); 00211 loader->unloadLibrary(TQFile::encodeName(libname.arg(mod.library()))); 00212 00213 libname = "kcm_%1"; 00214 loader->unloadLibrary(TQFile::encodeName(libname.arg(mod.library()))); 00215 } 00216 00217 void KCModuleLoader::showLastLoaderError(TQWidget *parent) 00218 { 00219 KMessageBox::detailedError(parent, 00220 i18n("There was an error loading the module."),i18n("<qt><p>The diagnostics is:<br>%1" 00221 "<p>Possible reasons:</p><ul><li>An error occurred during your last " 00222 "KDE upgrade leaving an orphaned control module<li>You have old third party " 00223 "modules lying around.</ul><p>Check these points carefully and try to remove " 00224 "the module mentioned in the error message. If this fails, consider contacting " 00225 "your distributor or packager.</p></qt>") 00226 .arg(KLibLoader::self()->lastErrorMessage())); 00227 00228 } 00229 00230 bool KCModuleLoader::testModule( const TQString& module ) 00231 { 00232 return testModule( KCModuleInfo( module ) ); 00233 } 00234 00235 bool KCModuleLoader::testModule( const KCModuleInfo& module ) 00236 { 00237 if (!module.service()) 00238 { 00239 kdDebug(1208) << "Module '" << module.fileName() << "' not found." << endl; 00240 return true; 00241 } 00242 00243 bool doLoad = module.service()->property( "X-KDE-Test-Module", TQVariant::Bool ).toBool(); 00244 if( !doLoad ) 00245 { 00246 return true; 00247 } 00248 else 00249 { 00256 KLibLoader* loader = KLibLoader::self(); 00257 KLibrary* library = loader->library( TQFile::encodeName((TQString("kcm_%1").arg(module.library()))) ); 00258 if( library ) 00259 { 00260 void *test_func = library->symbol( TQString(TQString("test_%1").arg(module.factoryName())).utf8() ); 00261 if( test_func ) 00262 { 00263 bool (*func)() = (bool(*)())test_func; 00264 if( func() ) 00265 { 00266 return true; 00267 } 00268 else 00269 { 00270 return false; 00271 } 00272 } 00273 else 00274 { 00275 kdDebug(1208) << "The test function for module '" << module.fileName() << "' could not be found." << endl; 00276 return true; 00277 } 00278 } 00279 kdDebug(1208) << "The library '" << module.library() << "' could not be found." << endl; 00280 return true; 00281 } 00282 } 00283 00284 KCModule* KCModuleLoader::reportError( ErrorReporting report, const TQString & text, 00285 TQString details, TQWidget * parent ) 00286 { 00287 if( details.isNull() ) 00288 details = i18n("<qt><p>The diagnostics is:<br>%1" 00289 "<p>Possible reasons:</p><ul><li>An error occurred during your last " 00290 "KDE upgrade leaving an orphaned control module<li>You have old third party " 00291 "modules lying around.</ul><p>Check these points carefully and try to remove " 00292 "the module mentioned in the error message. If this fails, consider contacting " 00293 "your distributor or packager.</p></qt>").arg(KLibLoader::self()->lastErrorMessage()); 00294 if( report & Dialog ) 00295 KMessageBox::detailedError( parent, text, details ); 00296 if( report & Inline ) 00297 return new KCMError( text, details, parent ); 00298 return 0; 00299 } 00300 00301 // vim: ts=2 sw=2 et 00302