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 <qfile.h>
00025 #include <qlabel.h>
00026 #include <qlayout.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 QString& msg, const QString& details, QWidget* parent )
00046             : KCModule( parent, "KCMError" )
00047         {
00048             QVBoxLayout* topLayout = new QVBoxLayout( this );
00049             topLayout->addWidget( new QLabel( msg, this ) );
00050             topLayout->addWidget( new QLabel( details, this ) );
00051         }
00052 };
00053 /***************************************************************/
00054 
00055 
00056 
00057 
00058 KCModule* KCModuleLoader::load(const KCModuleInfo &mod, const QString &libname,
00059     KLibLoader *loader, ErrorReporting report, QWidget * parent,
00060     const char * name, const QStringList & 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(QFile::encodeName(libname.arg(mod.library())));
00066   if (lib) {
00067     QString initSym("init_");
00068     initSym += libname.arg(mod.library());
00069 
00070     if ( lib->hasSymbol(QFile::encodeName(initSym)) )
00071     {
00072       KLibFactory *factory = lib->factory();
00073       if ( factory )
00074       {
00075         KCModule *module = KParts::ComponentFactory::createInstanceFromFactory<KCModule>( factory, 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     QString factory("create_%1");
00085     void *create = lib->symbol(QFile::encodeName(factory.arg(mod.handle())));
00086 
00087     if (create)
00088     {
00089       // create the module
00090       KCModule* (*func)(QWidget *, const char *);
00091       func = (KCModule* (*)(QWidget *, const char *)) create;
00092       return  func( parent, name ? name : mod.handle().latin1() );
00093     }
00094     else
00095     {
00096       lib->unload();
00097       return reportError( report, i18n("<qt>There was an error when loading the module '%1'.<br><br>"
00098           "The desktop file (%2) as well as the library (%3) was found but "
00099           "yet the module could not be loaded properly. Most likely "
00100           "the factory declaration was wrong, or the "
00101           "create_* function was missing.</qt>")
00102           .arg( mod.moduleName() )
00103           .arg( mod.fileName() )
00104           .arg( lib->fileName() ),
00105           QString::null, parent );
00106     }
00107 
00108     lib->unload();
00109   }
00110   return reportError( report, i18n("The specified library %1 could not be found.")
00111       .arg( mod.library() ), QString::null, parent );
00112   return 0;
00113 }
00114 
00115 KCModule* KCModuleLoader::loadModule(const KCModuleInfo &mod, bool withfallback, QWidget * parent, const char * name, const QStringList & args )
00116 {
00117   return loadModule( mod, None, withfallback, parent, name, args );
00118 }
00119 
00120 KCModule* KCModuleLoader::loadModule(const KCModuleInfo &mod, ErrorReporting report, bool withfallback, QWidget * parent, const char * name, const QStringList & args )
00121 {
00122   /*
00123    * Simple libraries as modules are the easiest case:
00124    *  We just have to load the library and get the module
00125    *  from the factory.
00126    */
00127 
00128   if ( !mod.service() )
00129   {
00130     if ( mod.moduleName() == "kcmlisa" || mod.moduleName() == "kcmkiolan" )
00131     {
00132       return reportError( report,
00133           i18n("The module %1 could not be found.")
00134           .arg( mod.moduleName() ),
00135           i18n("<qt><p>The Lisa and lan:/ ioslave modules "
00136             "are not installed by default in Kubuntu, because they are obsolete "
00137             "and replaced by zeroconf.<br> If you still wish to use them, you "
00138             "should install the lisa package from the Universe repository.</p></qt>"),
00139           parent );
00140     } else { 
00141       return reportError( report,
00142           i18n("The module %1 could not be found.")
00143           .arg( mod.moduleName() ),
00144           i18n("<qt><p>The diagnostics is:<br>The desktop file %1 could not be found.</p></qt>").arg(mod.fileName()),
00145           parent );
00146     }
00147   }
00148 
00149   if (!mod.library().isEmpty())
00150   {
00151     // get the library loader instance
00152 
00153     KLibLoader *loader = KLibLoader::self();
00154 
00155     KCModule *module = load(mod, "kcm_%1", loader, report, parent, name, args );
00156     /*
00157      * Only try to load libkcm_* if it exists, otherwise KLibLoader::lastErrorMessage would say
00158      * "libkcm_foo not found" instead of the real problem with loading kcm_foo.
00159      */
00160     if (!KLibLoader::findLibrary( QCString( "libkcm_" ) + QFile::encodeName( mod.library() ) ).isEmpty() )
00161       module = load(mod, "libkcm_%1", loader, report, parent, name, args );
00162     if (module)
00163       return module;
00164     return reportError( report,
00165         i18n("The module %1 could not be loaded.")
00166         .arg( mod.moduleName() ), QString::null, parent );
00167   }
00168 
00169   /*
00170    * Ok, we could not load the library.
00171    * Try to run it as an executable.
00172    * This must not be done when calling from kcmshell, or you'll
00173    * have infinite recursion
00174    * (startService calls kcmshell which calls modloader which calls startService...)
00175    *
00176    */
00177   if(withfallback)
00178   {
00179     KApplication::startServiceByDesktopPath(mod.fileName(), QString::null);
00180   }
00181   else
00182   {
00183     return reportError( report,
00184         i18n("The module %1 is not a valid configuration module.")
00185         .arg( mod.moduleName() ), i18n("<qt><p>The diagnostics is:<br>The desktop file %1 does not specify a library.</qt>").arg(mod.fileName()), parent );
00186   }
00187 
00188   return 0;
00189 }
00190 
00191 KCModule* KCModuleLoader::loadModule(const QString &module, QWidget *parent,
00192       const char *name, const QStringList & args)
00193 {
00194   return loadModule(KCModuleInfo(module), None, false, parent, name, args);
00195 }
00196 
00197 KCModule* KCModuleLoader::loadModule(const QString &module, ErrorReporting
00198     report, QWidget *parent, const char *name, const QStringList & args)
00199 {
00200   return loadModule(KCModuleInfo(module), report, false, parent, name, args);
00201 }
00202 
00203 void KCModuleLoader::unloadModule(const KCModuleInfo &mod)
00204 {
00205   // get the library loader instance
00206   KLibLoader *loader = KLibLoader::self();
00207 
00208   // try to unload the library
00209   QString libname("libkcm_%1");
00210   loader->unloadLibrary(QFile::encodeName(libname.arg(mod.library())));
00211 
00212   libname = "kcm_%1";
00213   loader->unloadLibrary(QFile::encodeName(libname.arg(mod.library())));
00214 }
00215 
00216 void KCModuleLoader::showLastLoaderError(QWidget *parent)
00217 {
00218   KMessageBox::detailedError(parent,
00219       i18n("There was an error loading the module."),i18n("<qt><p>The diagnostics is:<br>%1"
00220         "<p>Possible reasons:</p><ul><li>An error occurred during your last "
00221         "KDE upgrade leaving an orphaned control module<li>You have old third party "
00222         "modules lying around.</ul><p>Check these points carefully and try to remove "
00223         "the module mentioned in the error message. If this fails, consider contacting "
00224         "your distributor or packager.</p></qt>")
00225       .arg(KLibLoader::self()->lastErrorMessage()));
00226 
00227 }
00228 
00229 bool KCModuleLoader::testModule( const QString& module )
00230 {
00231   return testModule( KCModuleInfo( module ) );
00232 }
00233 
00234 bool KCModuleLoader::testModule( const KCModuleInfo& module )
00235 {
00236   if (!module.service())
00237   {
00238     kdDebug(1208) << "Module '" << module.fileName() << "' not found." << endl;
00239     return true;
00240   }
00241 
00242   bool doLoad = module.service()->property( "X-KDE-Test-Module", QVariant::Bool ).toBool();
00243   if( !doLoad )
00244   {
00245     return true;
00246   }
00247   else
00248   {
00255     KLibLoader* loader = KLibLoader::self();
00256     KLibrary* library = loader->library( QFile::encodeName((QString("kcm_%1").arg(module.library()))) );
00257     if( library )
00258     {
00259       void *test_func = library->symbol( QString("test_%1").arg(module.factoryName()).utf8() );
00260       if( test_func )
00261       {
00262         bool (*func)() = (bool(*)())test_func;
00263         if( func() )
00264         {
00265           return true;
00266         }
00267         else
00268         {
00269           return false;
00270         }
00271       }
00272       else
00273       {
00274         kdDebug(1208) << "The test function for module '" << module.fileName() << "' could not be found." << endl;
00275         return true;
00276       }
00277     }
00278     kdDebug(1208) << "The library '" << module.library() << "' could not be found." << endl;
00279     return true;
00280   }
00281 }
00282 
00283 KCModule* KCModuleLoader::reportError( ErrorReporting report, const QString & text,
00284         QString details, QWidget * parent )
00285 {
00286   if( details.isNull() )
00287     details = i18n("<qt><p>The diagnostics is:<br>%1"
00288         "<p>Possible reasons:</p><ul><li>An error occurred during your last "
00289         "KDE upgrade leaving an orphaned control module<li>You have old third party "
00290         "modules lying around.</ul><p>Check these points carefully and try to remove "
00291         "the module mentioned in the error message. If this fails, consider contacting "
00292         "your distributor or packager.</p></qt>").arg(KLibLoader::self()->lastErrorMessage());
00293   if( report & Dialog )
00294     KMessageBox::detailedError( parent, text, details );
00295   if( report & Inline )
00296     return new KCMError( text, details, parent );
00297   return 0;
00298 }
00299 
00300 // vim: ts=2 sw=2 et
00301 
KDE Home | KDE Accessibility Home | Description of Access Keys