-rw-r--r-- | libopie2/opiecore/opluginloader.cpp | 369 | ||||
-rw-r--r-- | libopie2/opiecore/opluginloader.h | 59 |
2 files changed, 395 insertions, 33 deletions
diff --git a/libopie2/opiecore/opluginloader.cpp b/libopie2/opiecore/opluginloader.cpp index b473cd7..2aca382 100644 --- a/libopie2/opiecore/opluginloader.cpp +++ b/libopie2/opiecore/opluginloader.cpp @@ -6,16 +6,17 @@ #include "opluginloader.h" #include "oconfig.h" #include <qpe/qpeapplication.h> #include <qdir.h> #include <qdict.h> #include <qtl.h> +#include <qfile.h> #include <stdlib.h> namespace Opie { namespace Core { namespace Internal { @@ -105,86 +106,148 @@ bool operator<=( const OPluginItem& l, const OPluginItem& r ) { * create an empty pluginitem. Position is set to -1 and the * other things are used with the default ctors */ OPluginItem::OPluginItem() : m_pos( -1 ) { } /** + * @todo Create Internal name so we can have the plugin names translated. Or only for the gui? I'm not yet sure * \brief Create an OPluginItem * - * Create a Plugin Item with all information. + * Create a Plugin Item with all information. If you for some reasons + * need to create your own OPluginItems make sure that 'name' is always the same + * as it if used for positions and exclude list. * * @param name The if available translated Name - * @param path The path to the plugin + * @param path The path to the plugin must be absolute. + * @param b If the OPluginItem is enabled or not * @param pos The position of the plugin if used for sorting * */ -OPluginItem::OPluginItem( const QString& name, const QString& path, int pos ) - : m_name( name ), m_path( path ), m_pos( pos ) { -} +OPluginItem::OPluginItem( const QString& name, const QString& path, bool b, int pos ) + : m_name( name ), m_path( path ), m_enabled( b ), m_pos( pos ) +{} /** * \brief simple d'tor */ OPluginItem::~OPluginItem() { } /** + * \brief Test if this Item is Empty and does not represent a loadable plugin + * Test if a OPluginItem is empty. A OPluginItem is empty if name and path are empty + * ,pos equals -1 and the item is disabled + * + * @see QString::isEmpty() + * + */ +bool OPluginItem::isEmpty()const { + if ( m_pos != -1 ) return false; + if ( m_enabled ) return false; + if ( !m_name.isEmpty() ) return false; + if ( !m_path.isEmpty() ) return false; + + return true; +} + +/** + * \brief test equality * operator to test equalness of two OPluginItem */ bool OPluginItem::operator==( const OPluginItem& r )const{ - if ( m_pos != r.m_pos ) return false; - if ( m_name != r.m_name ) return false; - if ( m_path != r.m_path ) return false; + if ( m_pos != r.m_pos ) return false; + if ( m_enabled != r.m_enabled) return false; + if ( m_name != r.m_name ) return false; + if ( m_path != r.m_path ) return false; return true; } +/** + * \brief test non equality + * operator to test non-equalness of two OPluginItem + */ bool OPluginItem::operator!=( const OPluginItem& r )const{ return !( *this == r ); } /** + * \brief returns the name of the plugin * return the name of this Plugin */ QString OPluginItem::name()const { return m_name; } /** - * return the path of the plugin + * \brief return the path of the plugin */ QString OPluginItem::path()const { return m_path; } +/** + * \brief Return if this item is enabled. + */ +bool OPluginItem::isEnabled()const { + return m_enabled; +} + +/** + * \brief return the position of a plugin. + * return the position of the item + * -1 is the default value and means normally that the whole items are unsorted. + * Higher numbers belong to an upper position. With plugins with the postions 20,19,5,3 + * the item with pos 20 would be the first in the list returned by the OGenericPluginLoader + * + * @see OGenericPluginLoader::allAvailable + * @see OGenericPluginLoader::filtered + */ int OPluginItem::position()const{ return m_pos; } /** + * \brief set the name of a plugin * Set the name of the Plugin Item * @param name */ void OPluginItem::setName( const QString& name ) { m_name = name; } /** - * Set the path of Plugin Item + * \brief set the path of a plugin + * Set the path of Plugin Item. The path must be absolute. * @param name The path of the plugin */ void OPluginItem::setPath( const QString& name ) { m_name = name; } /** + * \brief enable or disable the to load attribute + * Set the Enabled attribute. Such changes won't be saved. If you want to save it + * use a OPluginManager to configure your plugins manually or Opie::Ui::OPluginConfig + * for a graphical frontend. + * + * @param enabled Enable or Disable the Enabled Attribute + */ +void OPluginItem::setEnabled( bool enabled ) { + m_enabled = enabled; +} + +/** + * \brief Set the position. * Set the position * @param pos The position + * + * @see position() */ void OPluginItem::setPosition( int pos ) { m_pos = pos; } /** @@ -219,111 +282,141 @@ OGenericPluginLoader::OGenericPluginLoader( const QString& name, bool isSorted) m_isSorted( isSorted ) { setPluginDir( QPEApplication::qpeDir() + "/plugins/"+name ); readConfig(); } /** + * \brief simple d'tor that cleans up depending on autoDelete + * * calls clear if autoDelete is true. This will release all interfaces * and remove the library from this process if the refcount falls to zero */ OGenericPluginLoader::~OGenericPluginLoader() { if ( m_autoDelete ) clear(); } /** + * \brief Enable or disable autoDelete on destruction + * * enable autoDelete. This will call clear on the d'tor * * @see ~OGenericPluginLoader * @see clear() */ void OGenericPluginLoader::setAutoDelete( bool t ) { m_autoDelete = t; } /** - * see if autoDelet is enabled + * \brief See if autoDelete is enabled. */ bool OGenericPluginLoader::autoDelete()const{ return m_autoDelete; } /** + * \brief unload all loaded Plugins + * * This will unload all returned QUnknownInterfaces by load. Unload * will be called. */ void OGenericPluginLoader::clear() { QPtrDictIterator<QLibrary> it( m_library ); for ( ;it.current(); ) unload( static_cast<QUnknownInterface*>( it.currentKey() ) ); } /** + * \brief unload the Plugin and the accompanied Resources. + * * This will take the iface from the internal QPtrDict, Release it, * and deref the libray used. * The visibility depends on the QPtrDict. * @see QPtrDict::insert */ void OGenericPluginLoader::unload( QUnknownInterface* iface ) { if ( !iface ) return; iface->release(); Internal::OPluginLibraryHolder::self()->deref( m_library.take( iface ) ); } /** + * \brief The name of the plugins. + * + * Return the name/type you specified in the constructor. + * This is at least used by the OPluginManager to find the right config + */ +QString OGenericPluginLoader::name()const { + return m_dir; +} + + +/** + * \brief See if loading of a plugin segfaulted * This tells you * if by previous tries to load, loading crashed your application. * If isInSafeMode you can use the GUI to configure the plugins prior to loading * * @return true if prior loading failed */ bool OGenericPluginLoader::isInSafeMode()const { return m_isSafeMode; } /** + * \brief Return all Plugins found in the plugins dirs. * Return the list of all available plugins. This will go through all plugin * directories and search for your type of plugins ( by subdir ) * * @param sorted Tell if you want to have the positions sorted. This only makes sense if you */ OPluginItem::List OGenericPluginLoader::allAvailable( bool sorted )const { OPluginItem::List lst; for ( QStringList::ConstIterator it = m_plugDirs.begin(); it != m_plugDirs.end(); ++it ) lst += plugins( *it, sorted, false ); if ( sorted ) qHeapSort( lst ); return lst; } /** + * \brief Return only the enabled plugins * Return only activated plugins. * * @param sorted If the list should be sorted */ OPluginItem::List OGenericPluginLoader::filtered( bool sorted )const { OPluginItem::List lst; for ( QStringList::ConstIterator it = m_plugDirs.begin(); it != m_plugDirs.end(); ++it ) lst += plugins( *it, sorted, true ); if ( sorted ) qHeapSort( lst ); return lst; } /** + * \brief Load a OPluginItem for the specified interface + * This will open the resource of the OPluginItem::path() and then will query + * if the Interface specified in the uuid is available and then will manage the + * resource and Interface. + * + * @param item The OPluginItem that should be loaded + * @param uuid The Interface to query for * + * @return Either 0 in case of failure or the Plugin as QUnknownInterface* */ QUnknownInterface* OGenericPluginLoader::load( const OPluginItem& item, const QUuid& uuid) { /* * Check if there could be a library */ QString pa = item.path(); if ( pa.isEmpty() ) return 0l; @@ -353,24 +446,26 @@ QUnknownInterface* OGenericPluginLoader::load( const OPluginItem& item, const QU return iface; } /** * @internal and reads in the safe mode */ void OGenericPluginLoader::readConfig() { - /* read the config for SafeMode */ + + +/* read the config for SafeMode */ OConfig conf( m_dir + "-odpplugins" ); conf.setGroup( "General" ); m_isSafeMode = conf.readBoolEntry( "SafeMode", false ); } /** - * Enter or leave SafeMode + * @internal Enter or leave SafeMode */ void OGenericPluginLoader::setSafeMode(const QString& str, bool b) { OConfig conf( m_dir + "-odpplugins" ); conf.setGroup( "General" ); conf.writeEntry( "SafeMode", b ); conf.writeEntry( "CrashedPlugin", str ); } @@ -415,17 +510,21 @@ QString OGenericPluginLoader::unlibify( const QString& str ) { #ifdef Q_OS_MACX return st.left( st.findRev( ".dylib" ) ); #else return st.left( st.findRev( ".so" ) ); #endif } /** - * Return a List of Plugins for a dir and add positions and remove disabled. + * @internal + * + * \brief method to return available plugins. Internal and for reeimplementations + * + *Return a List of Plugins for a dir and add positions and remove disabled. * If a plugin is on the excluded list assign position -2 * * @param dir The dir to look in * @param sorted Should positions be read? * @param disabled Remove excluded from the list */ OPluginItem::List OGenericPluginLoader::plugins( const QString& _dir, bool sorted, bool disabled )const { #ifdef Q_OS_MACX @@ -468,22 +567,22 @@ OPluginItem::List OGenericPluginLoader::plugins( const QString& _dir, bool sorte QStringList list = dir.entryList(); QStringList::Iterator it; for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { QString str = unlibify( *it ); OPluginItem item( str, _dir + "/" + *it ); bool ex = excludedMap.contains( str ); /* - * if disabled but we should show all assign a -2 + * if disabled but we should show all mark it as disabled * else continue because we don't want to add the item * else if sorted we assign the right position */ if ( ex && !disabled) - item.setPosition( -2 ); + item.setEnabled( false ); else if ( ex && disabled ) continue; else if ( sorted ) item.setPosition( positionMap[str] ); lst.append( item ); } @@ -509,16 +608,20 @@ QStringList OGenericPluginLoader::languageList() { int n_pos = str.find( '_' ); if ( pos > 0 && n_pos >= pos ) m_languages += str.left( n_pos ); } return m_languages; } +/** + * @internal + * Tries to install languages using the languageList for the type + */ void OGenericPluginLoader::installTranslators(const QString& type) { QStringList lst = languageList(); /* * for each language and maybe later for each language dir... * try to load a Translator */ for ( QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) { @@ -530,12 +633,246 @@ void OGenericPluginLoader::installTranslators(const QString& type) { */ if ( trans->load( tfn ) ) qApp->installTranslator( trans ); else delete trans; } } +/** + * \brief Simple c'tor. + * + * Simple C'tor same as the one of the base class. Additional this + * class can cast for you if you nee it. + * + * + * @param name The name of your plugin class + * @param sorted If plugins are sorted + * + * @see OGenericPluginLoader + */ +OPluginLoader::OPluginLoader( const QString& name, bool sorted ) + : OGenericPluginLoader( name, sorted ) +{ +} + +/** + * d'tor + * @see OGenericPluginLoader::~OGenericPluginLoader + */ +OPluginLoader::~OPluginLoader() { +} + +/** + * \brief C'Tor using a OGenericPluginLoader + * The C'tor. Pass your OGenericPluginLoader to manage + * OGenericPluginLoader::allAvailable plugins. + * + * + * @param loader A Pointer to your OGenericPluginLoader + * @param name The name + */ +OPluginManager::OPluginManager( OGenericPluginLoader* loader) + : m_loader( loader ) +{ +} + +/** + * \brief Overloaded c'tor using a List of Plugins and a type name + * Overloaded Constructor to work with a 'Type' of plugins + * and a correspending list of those. In this case calling load + * is a no operation. + * + * @param name The name of your plugin ('today','inputmethods','applets') + * @param lst A List with plugins of your type to manage + * @param isSorted If the List should be treated sorted + */ +OPluginManager::OPluginManager( const QString& name, const OPluginItem::List& lst, bool isSorted) + : m_loader( 0l ), m_cfgName( name ), m_plugins( lst ), m_isSorted( isSorted ) +{ +} + +/** + * \brief A simple d'tor + */ +OPluginManager::~OPluginManager() { +} + +/** + * \brief Return the OPluginItem where loading is likely to have crashed on. + * Return the Item that made the OGenericPluginLoader crash + * the returned OPluginItem could be empty if no crash occured + * which should apply most of the time. It could also be empty if the crashed + * plugin is not in the current list of available/managed plugins + * + * @see OPluginItem::isEmpty + * @return OPluginItem that crashed the loader + */ +OPluginItem OPluginManager::crashedPlugin()const { + return m_crashed; +} + +/** + * \brief Return a list of plugins that are managed by this OPluginManager + * + * Return the list of managed plugins. This could either result + * from passing a OGenericPluginLoader and calling load or by + * giving name and a list of plugins. + */ +OPluginItem::List OPluginManager::managedPlugins()const { + return m_plugins; +} + +/** + * \brief Set the position of the items + * + * Replace the OPluginItem with the name and path and this way + * apply the new position. The search is linear and this way O(n/2) + * You still need to call save() to make your changes effective. After saving + * a call to OGenericPluginLoader::filtered() returns the newly configured order and items + * + * @param item The OPluginItem to be replaced internall + * + */ +void OPluginManager::setPosition( const OPluginItem& item) { + replace( item ); +} + +/** + * \brief Enable the item specified as argument + * + * This will make sure that OPluginItem::setEnabled is called and then will replace + * the item with one that matches name and path internally. + * @see setPosition + * + * @param the Item to enable + */ +void OPluginManager::enable( const OPluginItem& item ) { + setEnabled( item, true ); +} + +/** + * \brief disable the Item. + * + * Disable the OPluginItem. Same applies as in + * @see setPosition and @see enable + * + * @param item Item to disable + */ +void OPluginManager::disable( const OPluginItem& item) { + setEnabled( item, false ); +} + +/** + * \brief Enable or disable the OPluginItem. + * Depending on the value of the parameter this will either disable + * or enable the pluginitem. + * Beside that same as in @see disable, @see enable, @see setPosition + * applies. + * + * @param _item The OPluginItem to enable or to disable. + * @param b Enable or disable the plugin. + * + */ +void OPluginManager::setEnabled( const OPluginItem& _item, bool b ) { + OPluginItem item = _item; + item.setEnabled( b ); + replace( item ); +} + +/** + * \brief Load necessary information after constructing the object + * If you speified a OGenericPluginLoader you need to call this method + * so that this manager knows what to manage and have a right value for \sa crashedPlugin + * For the name and the list of plugins this does only try to find out the crashed plugin + */ +void OPluginManager::load() { + OConfig cfg( configName() ); + cfg.setGroup( "General" ); + QString crashedPath = cfg.readEntry( "CrashedPlugin" ); + + /* if we've a loader this applies if we were called from the first part */ + if ( m_loader ) + m_plugins = m_loader->allAvailable( m_loader->isSorted() ); + + /* fast and normal route if we did not crash... */ + if ( crashedPath.isEmpty() ) + return; + + /* lets try to find the plugin path and this way the associated item */ + for ( OPluginItem::List::Iterator it = m_plugins.begin(); it != m_plugins.end(); ++it ) + if ( (*it).path() == crashedPath ) { + m_crashed = *it; + break; + } +} + + +/** + * \brief Save the values and this way make it available. + * + * Save the current set of data. A call to @see OGenericPluginLoader::filtered + * now would return your saved changes. + */ +void OPluginManager::save() { + QMap<QString, QStringList> excluded; // map for path to excluded name + QMap<QString, QStringList> positions; // if positions matter contains splitted up by dirs + bool sorted = m_loader ? m_loader->isSorted() : m_isSorted; + + /* + * We will create some maps for the groups to include positions a + */ + for ( OPluginItem::List::Iterator it = m_plugins.begin(); it != m_plugins.end(); ++it ) { + OPluginItem item = *it; + QString path = QFileInfo( item.path() ).filePath(); + if ( sorted ) { + positions[path].append( item.name() ); + positions[path].append( QString::number( item.position() ) ); + } + + if ( !item.isEnabled() ) + excluded[path].append( item.name() ); + } + +/* + * The code below wouldn't work because we can't delete groups/keys from the config + * ### for ODP make Config right! + */ +// if ( excluded.isEmpty() && positions.isEmpty() ) return; + /* + * Now safe for each path + */ + OConfig cfg( configName() ); + + /* safe excluded items */ + for ( QMap<QString, QStringList>::Iterator it = excluded.begin(); it != excluded.end(); ++it ) { + OConfigGroupSaver saver( &cfg, it.key() ); + cfg.writeEntry("Excluded", it.data(), ',' ); + } + + /* safe positions we could also see if positions.contains(path) and remove/write in the above loop + * ### Write a Test Suite that can profile these runs... + */ + for ( QMap<QString, QStringList>::Iterator it = positions.begin(); it != positions.end(); ++it ) { + OConfigGroupSaver saver( &cfg, it.key() ); + cfg.writeEntry("Positions", it.data(), '.' ); + } +} + +/** + * @internal + */ +QString OPluginManager::configName()const { + QString str = m_loader ? m_loader->name() : m_cfgName; + return str + "odpplugins"; +} + +/** + * @internal.. replace in m_plugins by path... this is linear search O(n/2) + */ +void OPluginManager::replace( const OPluginItem& item ) { +// ### fixme +} } } diff --git a/libopie2/opiecore/opluginloader.h b/libopie2/opiecore/opluginloader.h index 6166b75..2f9ec2a 100644 --- a/libopie2/opiecore/opluginloader.h +++ b/libopie2/opiecore/opluginloader.h @@ -27,34 +27,39 @@ template class QPtrDict<QLibrary>; * * @since 1.2 * */ class OPluginItem { public: typedef QValueList<OPluginItem> List; OPluginItem(); - OPluginItem( const QString& name, const QString& path, int pos = -1 ); + OPluginItem( const QString& name, const QString& path, bool enabled = true, int pos = -1 ); ~OPluginItem(); + bool isEmpty()const; + bool operator==( const OPluginItem& )const; bool operator!=( const OPluginItem& )const; QString name()const; QString path()const; + bool isEnabled()const; int position()const; void setName( const QString& ); void setPath( const QString& ); + void setEnabled( bool ); void setPosition( int ); private: QString m_name; QString m_path; + bool m_enabled : 1; int m_pos; struct Private; Private *d; }; /** * \brief A generic class to easily load and manage plugins * @@ -71,36 +76,36 @@ public: typedef OPluginItem::List List; OGenericPluginLoader( const QString &name, bool isSorted = false ); virtual ~OGenericPluginLoader(); void setAutoDelete( bool ); bool autoDelete()const; void clear(); - + QString name()const; + bool isSorted()const; bool isInSafeMode()const; - List allAvailable(bool sorted = FALSE)const; - List filtered(bool sorted = FALSE)const; + List allAvailable(bool sorted = false )const; + List filtered(bool sorted = false )const; virtual QUnknownInterface* load( const OPluginItem& item, const QUuid& ); virtual void unload( QUnknownInterface* ); protected: + friend class OPluginManager; // we need the static unlibify void readConfig(); virtual List plugins( const QString& dir, bool sorted, bool disabled )const; void setPluginDirs( const QStringList& ); void setPluginDir( const QString& ); - bool isSorted()const; void setSafeMode(const QString& app = QString::null, bool b = false); static QString unlibify( const QString& str ); - private: QStringList languageList(); void installTranslators(const QString& type); QString m_dir; QStringList m_plugDirs; QStringList m_languages; bool m_autoDelete : 1; bool m_isSafeMode : 1; @@ -128,52 +133,72 @@ private: * if you want to load plugins or come up with the Configuration on * next start yourself then. * * @since 1.2 */ class OPluginLoader : public OGenericPluginLoader { public: OPluginLoader( const QString& name, bool sorted = false ); - ~OPluginLoader(); + virtual ~OPluginLoader(); template<class IFace> IFace* load( const OPluginItem& item, const QUuid& ); }; /** - * \brief A class to manager order and activation of plugins + * \brief A class to manage order and activation of plugins * * Manage order and activation. This is used by the Opie::Ui::OPluginConfig * This class controls the activation and order of plugins depending * on the OPluginLoader you supply. + * You must call load() and save after construnction an instance * - * @see OPluginConfig + * @see Opie::Ui::OPluginConfig * */ class OPluginManager { public: - OPluginManager( OGenericPluginLoader* , const QString& name); - OPluginManager( OConfig* conf, const QString&, - const QCString& group, const OPluginItem::List& ); - ~OPluginManager(); + OPluginManager( OGenericPluginLoader* ); + OPluginManager( const QString& name, const OPluginItem::List&, bool isSorted = false ); + virtual ~OPluginManager(); - QString name(); - void setName( const QString& ); + OPluginItem crashedPlugin()const; + + OPluginItem::List managedPlugins()const; void setPosition( const OPluginItem& ); void enable( const OPluginItem& ); void disable( const OPluginItem& ); void setEnabled( const OPluginItem&, bool = true); - void load(); - void save(); + virtual void load(); + virtual void save(); + +protected: + QString configName()const; + void replace( const OPluginItem& ); +private: + OGenericPluginLoader *m_loader; + QString m_cfgName; + OPluginItem::List m_plugins; + OPluginItem m_crashed; + bool m_isSorted : 1; }; +/** + * This is a template method allowing you to safely cast + * your load function + * + * \code + * MyTypePlugin *plug = load->load<MyTypePlugin>( item, IID_MyPlugin ); + * \endcode + * + */ template<class IFace> IFace* OPluginLoader::load( const OPluginItem& item, const QUuid& uid ) { return static_cast<IFace*>( OGenericPluginLoader::load( item, uid ) ); } } } |