-rw-r--r-- | libopie2/opiecore/opluginloader.cpp | 18 | ||||
-rw-r--r-- | libopie2/opiecore/opluginloader.h | 1 |
2 files changed, 16 insertions, 3 deletions
diff --git a/libopie2/opiecore/opluginloader.cpp b/libopie2/opiecore/opluginloader.cpp index 2aca382..87e24d4 100644 --- a/libopie2/opiecore/opluginloader.cpp +++ b/libopie2/opiecore/opluginloader.cpp @@ -312,567 +312,579 @@ void OGenericPluginLoader::setAutoDelete( bool t ) { /** * \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; /* * See if we get a library * return if we've none */ setSafeMode( pa, true ); QLibrary *lib = Internal::OPluginLibraryHolder::self()->ref( pa ); if ( !lib ) { setSafeMode(); return 0l; } /** * try to load the plugin and just in case initialize the pointer to a pointer again */ QUnknownInterface* iface=0; if ( lib->queryInterface( uuid, &iface ) == QS_OK ) { installTranslators(pa.left( pa.find("."))); m_library.insert( iface, lib ); }else iface = 0; setSafeMode(); return iface; } /** * @internal and reads in the safe mode */ void OGenericPluginLoader::readConfig() { /* read the config for SafeMode */ OConfig conf( m_dir + "-odpplugins" ); conf.setGroup( "General" ); m_isSafeMode = conf.readBoolEntry( "SafeMode", false ); } /** * @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 ); } /** * @internal * * Set the List of Plugin Dirs to lst. Currently only QPEApplication::qpeDir()+"/plugins/"+mytype * is used as plugin dir */ void OGenericPluginLoader::setPluginDirs( const QStringList& lst ) { m_plugDirs = lst; } /** * * @internal * Set the Plugin Dir to str. Str will be the only element in the list of plugin dirs */ void OGenericPluginLoader::setPluginDir( const QString& str) { m_plugDirs.clear(); m_plugDirs.append( str ); } /** * @internal */ bool OGenericPluginLoader::isSorted()const{ return m_isSorted; } /* * make libfoo.so.1.0.0 -> foo on UNIX * make libfoo.dylib -> foo on MAC OS X Unix * windows is obviously missing */ /** * @internal */ QString OGenericPluginLoader::unlibify( const QString& str ) { QString st = str.mid( str.find( "lib" )+3 ); #ifdef Q_OS_MACX return st.left( st.findRev( ".dylib" ) ); #else return st.left( st.findRev( ".so" ) ); #endif } /** * @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 QDir dir( _dir, "lib*.dylib" ); #else QDir dir( _dir, "lib*.so" ); #endif OPluginItem::List lst; /* * get excluded list and then iterate over them * Excluded list contains the name * Position is a list with 'name.pos.name.pos.name.pos' * * For the look up we will create two QMap<QString,pos> */ QMap<QString, int> positionMap; QMap<QString, int> excludedMap; OConfig cfg( m_dir+"odpplugins" ); cfg.setGroup( _dir ); QStringList excludes = cfg.readListEntry( "Excluded", ',' ); for ( QStringList::Iterator it = excludes.begin(); it != excludes.end(); ++it ) excludedMap.insert( *it, -2 ); if ( m_isSorted ) { QStringList pos = cfg.readListEntry( "Positions", '.' ); QStringList::Iterator it = pos.begin(); while ( it != pos.end() ) positionMap.insert( *it++, (*it++).toInt() ); } 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 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.setEnabled( false ); else if ( ex && disabled ) continue; else if ( sorted ) item.setPosition( positionMap[str] ); lst.append( item ); } return lst; } /** * @internal generate a list of languages from $LANG */ QStringList OGenericPluginLoader::languageList() { if ( m_languages.isEmpty() ) { /* * be_BY.CP1251 We will add, be_BY.CP1251,be_BY,be * to our list of languages. */ QString str = ::getenv( "LANG" ); m_languages += str; int pos = str.find( '.' ); if ( pos > 0 ) m_languages += str.left( pos ); 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 ) { QTranslator* trans = new QTranslator( qApp ); QString tfn = QPEApplication::qpeDir()+"/i18n/" + *it + "/" + type + ".qm" ; /* * If loaded then install else clean up and don't leak */ 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 ) + : m_loader( loader ), m_isSorted( false ) { } /** * \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 + OPluginItem _item; + + /* for all plugins */ + for ( OPluginItem::List::Iterator it=m_plugins.begin();it != m_plugins.end(); ++it ) { + _item = *it; + /* if path and name are the same we will remove, readd and return */ + if ( _item.path() == item.path() && + _item.name() == item.name() ) { + it = m_plugins.remove( it ); + m_plugins.append( item ); + return; + } + + } } } } diff --git a/libopie2/opiecore/opluginloader.h b/libopie2/opiecore/opluginloader.h index 2f9ec2a..740551c 100644 --- a/libopie2/opiecore/opluginloader.h +++ b/libopie2/opiecore/opluginloader.h @@ -1,206 +1,207 @@ /* * LGPLv2 or later * zecke@handhelds.org */ #ifndef ODP_CORE_OPLUGIN_LOADER_H #define ODP_CORE_OPLUGIN_LOADER_H #include <qpe/qlibrary.h> #include <qptrdict.h> #include <qstringlist.h> namespace Opie { namespace Core { class OConfig; namespace Internal { class OPluginLibraryHolder; } template class QPtrDict<QLibrary>; /** * \brief A small item representing the Plugin Information * This class contains the information about a Plugin. It contains * a translated name if available to the system, a config key, * and the path location. * * @since 1.2 * */ class OPluginItem { public: typedef QValueList<OPluginItem> List; OPluginItem(); 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 * * This is the generic non sepcialised loader for plugins. Normally * you would prefer using the OPluginLoader directly. This class * exists to minimize the application binary size due the usage * of templates in the specialized API * * @since 1.2 * @see OPluginLoader */ class OGenericPluginLoader { 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; 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& ); 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; bool m_isSorted : 1; QPtrDict<QLibrary> m_library; struct Private; Private* d; }; /** * \brief The class to load your QCOM+ plugins * * This class takes care of activation and even the order * if you need it. It is normally good to place a .directory file * into your plugin directory if you need order of activation. * * You'll create the OPluginLoader and then use it to load the filtered * plugins. * * There is also a GUI for the configuration and a Manager to write the * mentioned .directory file * * On crash the safe mode is activated for the next run. You can then decide * 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 ); virtual ~OPluginLoader(); template<class IFace> IFace* load( const OPluginItem& item, const QUuid& ); }; /** * \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 Opie::Ui::OPluginConfig * */ class OPluginManager { public: + typedef QValueList<OPluginManager*> List; OPluginManager( OGenericPluginLoader* ); OPluginManager( const QString& name, const OPluginItem::List&, bool isSorted = false ); virtual ~OPluginManager(); 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); 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 ) ); } } } #endif |