-rw-r--r-- | libopie2/opiecore/opluginloader.cpp | 397 | ||||
-rw-r--r-- | libopie2/opiecore/opluginloader.h | 191 |
2 files changed, 588 insertions, 0 deletions
diff --git a/libopie2/opiecore/opluginloader.cpp b/libopie2/opiecore/opluginloader.cpp new file mode 100644 index 0000000..e5a0903 --- a/dev/null +++ b/libopie2/opiecore/opluginloader.cpp | |||
@@ -0,0 +1,397 @@ | |||
1 | /* | ||
2 | * LGPLv2 or later | ||
3 | * zecke@handhelds.org | ||
4 | */ | ||
5 | |||
6 | #include "opluginloader.h" | ||
7 | |||
8 | #include <stdlib.h> | ||
9 | |||
10 | |||
11 | |||
12 | namespace Opie { | ||
13 | namespace Core { | ||
14 | namespace Internal { | ||
15 | struct OPluginLibraryHolder { | ||
16 | static OPluginLibraryHolder *self(); | ||
17 | QLibrary *getLibrary( const QString& ); | ||
18 | void putLibrary( QLibrary* ); | ||
19 | private: | ||
20 | OPluginLibraryHolder(); | ||
21 | ~OPluginLibraryHolder(); | ||
22 | OPluginLibraryHolder* m_self; | ||
23 | |||
24 | }; | ||
25 | } | ||
26 | |||
27 | }} | ||
28 | /** | ||
29 | * \brief Creates an Empty OPluginItem | ||
30 | * | ||
31 | * create an empty pluginitem. Position is set to -1 and the | ||
32 | * other things are used with the default ctors | ||
33 | */ | ||
34 | OPluginItem::OPluginItem() | ||
35 | : m_pos( -1 ) { | ||
36 | } | ||
37 | |||
38 | /** | ||
39 | * \brief Create an OPluginItem | ||
40 | * | ||
41 | * Create a Plugin Item with all information. | ||
42 | * | ||
43 | * @param name The if available translated Name | ||
44 | * @param conf The name of the config group | ||
45 | * @param path The path to the plugin | ||
46 | * @param pos The position of the plugin if used for sorting | ||
47 | * | ||
48 | */ | ||
49 | OPluginItem::OPluginItem( const QString& name, const QCString& conf, | ||
50 | const QString& path, int pos = -1 ) | ||
51 | : m_name( name ), m_conf( conf ), m_path( path ), m_pos( pos ) { | ||
52 | } | ||
53 | |||
54 | /** | ||
55 | * \brief simple d'tor | ||
56 | */ | ||
57 | OPluginItem::~OPluginItem() { | ||
58 | } | ||
59 | |||
60 | /** | ||
61 | * operator to test equalness of two OPluginItem | ||
62 | */ | ||
63 | bool OPluginItem::operator==( const OPluginItem& r )const{ | ||
64 | if ( m_pos != r.m_pos ) return false; | ||
65 | if ( m_name != r.m_name ) return false; | ||
66 | if ( m_conf != r.m_conf ) return false; | ||
67 | if ( m_path != r.m_path ) return false; | ||
68 | return true; | ||
69 | } | ||
70 | |||
71 | bool OPluginItem::operator!=( const OPluginItem& r ) { | ||
72 | return !( *this == r ); | ||
73 | } | ||
74 | |||
75 | /** | ||
76 | * return the name of this Plugin | ||
77 | */ | ||
78 | QString OPluginItem::name()const { | ||
79 | return m_name; | ||
80 | } | ||
81 | |||
82 | /** | ||
83 | * return the config key | ||
84 | */ | ||
85 | QCString OPluginItem::configKey()const{ | ||
86 | return m_conf; | ||
87 | } | ||
88 | |||
89 | /** | ||
90 | * return the path of the plugin | ||
91 | */ | ||
92 | QString OPluginItem::path()const { | ||
93 | return m_path; | ||
94 | } | ||
95 | |||
96 | int OPluginItem::position()const{ | ||
97 | return m_pos; | ||
98 | } | ||
99 | |||
100 | /** | ||
101 | * Set the name of the Plugin Item | ||
102 | * @param name | ||
103 | */ | ||
104 | void OPluginItem::setName( const QString& name ) { | ||
105 | m_name = name; | ||
106 | } | ||
107 | |||
108 | /** | ||
109 | * Set the config key | ||
110 | * @param key The config key/group of this plugin | ||
111 | */ | ||
112 | void OPluginItem::setConfigKey( const QCString& conf ) { | ||
113 | m_conf = conf; | ||
114 | } | ||
115 | |||
116 | /** | ||
117 | * Set the path of Plugin Item | ||
118 | * @param name The path of the plugin | ||
119 | */ | ||
120 | void OPluginItem::setPath( const QString& name ) { | ||
121 | m_name = name; | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * Set the position | ||
126 | * @param pos The position | ||
127 | */ | ||
128 | void OPluginItem::setPosition( int pos ) { | ||
129 | m_pos = pos; | ||
130 | } | ||
131 | |||
132 | |||
133 | |||
134 | /** | ||
135 | * \brief create a PluginLoader | ||
136 | * | ||
137 | * Create a PluginLoader autoDelete is set to false | ||
138 | * | ||
139 | * \code | ||
140 | * Opie::Core::OGenericPluginLoader loader("myapp-plugin"); | ||
141 | * Opie::Core::OPluginItem::List lst = loader.filtered(); | ||
142 | * for(Opie::Core::OPluginItem::List::Iterator it = lst.begin(); it!=lst.end();++it){ | ||
143 | * MyIface* iface = static_cast<MyIface*>(loader.load(*it,IID_MyIface)); | ||
144 | * } | ||
145 | * \endcode | ||
146 | * | ||
147 | * \code | ||
148 | * Opie::Core::OGenericPluginLoader loader("myapp-plugin"); | ||
149 | * Opie::Core::OPluginItem::List lst = loader.filtered(); | ||
150 | * for(Opie::Core::OPluginItem::List::Iterator it = lst.begin(); it!=lst.end();++it){ | ||
151 | * MyIface* iface = static_cast<MyIface*>(loader.load(*it,IID_MyIface)); | ||
152 | * } | ||
153 | * ... | ||
154 | * loader.clear(); | ||
155 | * | ||
156 | * \endcode | ||
157 | * | ||
158 | * @param name The name of the plugin directory. | ||
159 | * @param isSorted Tell the PluginLoader if your Plugins are sorted | ||
160 | */ | ||
161 | OGenericPluginLoader::OGenericPluginLoader( const QString& name, bool isSorted) | ||
162 | : m_dir( name ), m_autoDelete( false ), m_isSafeMode( false ), | ||
163 | m_isSorted( isSorted ), m_readConfig( false ) | ||
164 | { | ||
165 | setPluginDir( QPEApplication::qpeDir() + "/plugins/"+name ); | ||
166 | } | ||
167 | |||
168 | |||
169 | /** | ||
170 | * calls clear if autoDelete is true. This will release all interfaces | ||
171 | * and remove the library from this process if the refcount falls to zero | ||
172 | */ | ||
173 | OGenericPluginLoader::~OGenericPluginLoader() { | ||
174 | if ( m_autoDelete ) | ||
175 | clear(); | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * enable autoDelete. This will call clear on the d'tor | ||
180 | * | ||
181 | * @see ~OGenericPluginLoader | ||
182 | * @see clear() | ||
183 | */ | ||
184 | void OGenericPluginLoader::setAutoDelete( bool t ) { | ||
185 | m_autoDelete = t; | ||
186 | } | ||
187 | |||
188 | /** | ||
189 | * see if autoDelet is enabled | ||
190 | */ | ||
191 | bool OGenericPluginLoader::autoDelete()const{ | ||
192 | return m_autoDelete; | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * This will unload all returned QUnknownInterfaces by load. Unload | ||
197 | * will be called. | ||
198 | */ | ||
199 | void OGenericPluginLoader::clear() { | ||
200 | QPtrDictIterator<QLibrary> it( m_library ); | ||
201 | for ( ;it.current(); ) | ||
202 | unload( static_cast<QUnknownInterface*>( it.currentKey() ) ); | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * This will take the iface from the internal QPtrDict, Release it, | ||
207 | * and deref the libray used. | ||
208 | * The visibility depends on the QPtrDict. | ||
209 | * @see QPtrDict::insert | ||
210 | */ | ||
211 | void OGenericPluginLoader::unload( QUnknownInterface* iface ) { | ||
212 | if ( !iface ) | ||
213 | return; | ||
214 | |||
215 | iface->release(); | ||
216 | OPluginLibraryHolder::self()->deref( m_library.take( iface ) ); | ||
217 | } | ||
218 | |||
219 | /** | ||
220 | * This tells you | ||
221 | * if by previous tries to load, loading crashed your application. | ||
222 | * If isInSafeMode you can use the GUI to configure the plugins prior to loading | ||
223 | * | ||
224 | * @return true if prior loading failed | ||
225 | */ | ||
226 | bool OGenericPluginLoader::isInSafeMode()const { | ||
227 | if ( !m_readConfig ) | ||
228 | readConfig(); | ||
229 | return m_isSafeMode; | ||
230 | } | ||
231 | |||
232 | /** | ||
233 | * return if the plugin list is sorted. | ||
234 | */ | ||
235 | bool OGenericPluginLoader::isSorted()const { | ||
236 | if ( !m_readConfig ) | ||
237 | readConfig(); | ||
238 | return m_isSorted; | ||
239 | } | ||
240 | |||
241 | /** | ||
242 | * Return the list of all available plugins. This will go through all plugin | ||
243 | * directories and search for your type of plugins ( by subdir ) | ||
244 | * | ||
245 | * @param sorted Tell if you want to have the positions sorted. This only makes sense if you | ||
246 | */ | ||
247 | OPluginItem::List OGenericPluginLoader::allAvailable( bool sorted )const { | ||
248 | OPluginItem::List lst; | ||
249 | for ( QStringList::ConstIterator it = m_plugDirs.begin(); it != m_plugDirs.end(); ++it ) | ||
250 | lst += plugins( *it, sorted, false ); | ||
251 | |||
252 | if ( sorted ) | ||
253 | qHeapSort( lst ); | ||
254 | return lst; | ||
255 | } | ||
256 | |||
257 | /** | ||
258 | * Return only activated plugins. | ||
259 | * | ||
260 | * @param sorted If the list should be sorted | ||
261 | */ | ||
262 | OPluginItem::List OGenericPluginLoader::filtered( bool sorted )const { | ||
263 | OPluginItem::List lst; | ||
264 | for ( QStringList::ConstIterator it = m_plugDirs.begin(); it != m_plugDirs.end(); ++it ) | ||
265 | lst += plugins( *it, sorted, true ); | ||
266 | |||
267 | if ( sorted ) | ||
268 | qHeapSort( lst ); | ||
269 | return lst; | ||
270 | } | ||
271 | |||
272 | |||
273 | /** | ||
274 | * | ||
275 | */ | ||
276 | QUnknownInterface* OGenericPluginLoader::load( const OPluginItem& item, const QUuid& uuid) { | ||
277 | /* | ||
278 | * Check if there could be a library | ||
279 | */ | ||
280 | QString pa = item.path(); | ||
281 | if ( pa.isEmpty() ) | ||
282 | return 0l; | ||
283 | |||
284 | /* | ||
285 | * See if we get a library | ||
286 | * return if we've none | ||
287 | */ | ||
288 | setSafeMode( true ); | ||
289 | QLibrary *lib = OPluginLibraryHolder::self()->getLibrary( pa ); | ||
290 | if ( !lib ) { | ||
291 | setSafeMode(); | ||
292 | return 0l; | ||
293 | } | ||
294 | |||
295 | /** | ||
296 | * try to load the plugin and just in case initialize the pointer to a pointer again | ||
297 | */ | ||
298 | QUnknownInterface** iface = 0; | ||
299 | if ( lib->queryInterface( uuid, iface ) == QS_OK ) { | ||
300 | installTranslators(pa.left( pa.find("."))); | ||
301 | m_library.insert( *iface, lib ); | ||
302 | }else | ||
303 | *iface = 0; | ||
304 | |||
305 | setSafeMode(); | ||
306 | |||
307 | return *iface; | ||
308 | } | ||
309 | |||
310 | void OGenericPluginLoader::readConfig() { | ||
311 | m_readConfig = true; | ||
312 | |||
313 | /* read the config for SafeMode */ | ||
314 | OConfig conf( m_name + "-odpplugins" ); | ||
315 | conf.setGroup( "General" ); | ||
316 | m_isSafeMode = conf.readBoolEntry( "SafeMode", false ); | ||
317 | } | ||
318 | |||
319 | void OGenericPluginLoader::setSafeMode(bool b) { | ||
320 | OConfig conf( m_name + "-odpplugins" ); | ||
321 | conf.setGroup( "General" ); | ||
322 | conf.writeEntry( "SafeMode", b ); | ||
323 | } | ||
324 | |||
325 | void OGenericPluginLoader::setPluginDirs( const QStringList& lst ) { | ||
326 | m_plugDirs = lst; | ||
327 | } | ||
328 | |||
329 | void OGenericPluginLoader::setPluginDir( const QString& str) { | ||
330 | m_plugDirs.clear(); | ||
331 | m_plugDirs.append( str ); | ||
332 | } | ||
333 | |||
334 | bool &OGenericPluginLoader::isSafeMode()const { | ||
335 | return m_isSafeMode; | ||
336 | } | ||
337 | |||
338 | bool &OGenericPluginLoader::isSorted()const { | ||
339 | return m_isSorted; | ||
340 | } | ||
341 | |||
342 | OPluginItem::List OGenericPluginLoader::plugins( const QString& dir, bool sorted, bool disabled ) { | ||
343 | #ifdef Q_OS_MACX | ||
344 | QDir dir( dir, "lib*.dylib" ); | ||
345 | #else | ||
346 | QDir dir( dir, "lib*.so" ); | ||
347 | #endif | ||
348 | /* | ||
349 | * get excluded list and then iterate over them | ||
350 | */ | ||
351 | OConfig cfg( m_name+"odpplugins" ); | ||
352 | cfg.setGroup( dir ); | ||
353 | QStringList excludes = cfg.readListEntry( "Excluded" ); | ||
354 | |||
355 | QStringList list = dir.entryList(); | ||
356 | // for ( | ||
357 | |||
358 | } | ||
359 | |||
360 | |||
361 | QStringList OGenericPluginLoader::languageList() { | ||
362 | if ( languageList.isEmpty() ) { | ||
363 | /* | ||
364 | * be_BY.CP1251 We will add, be_BY.CP1251,be_BY,be | ||
365 | * to our list of languages. | ||
366 | */ | ||
367 | QString str = ::getenv( "LANG" ); | ||
368 | m_languages += str; | ||
369 | int pos = str.find( '.' ); | ||
370 | |||
371 | if ( pos > 0 ) | ||
372 | m_languages += str.left( pos ); | ||
373 | |||
374 | int n_pos = str.find( '_' ); | ||
375 | if ( pos > 0 && n_pos >= pos ) | ||
376 | m_languages += str.left( n_pos ); | ||
377 | |||
378 | } | ||
379 | return m_languages; | ||
380 | } | ||
381 | |||
382 | void OGenericPluginLoader::installTranslators(const QString& type) { | ||
383 | QStringList lst = languageList(); | ||
384 | for ( QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) { | ||
385 | QTranslator* trans = new QTranslator( qApp ); | ||
386 | QString tfn = QPEApplication::qpeDir()+"/i18n/" + lang + "/" + type + ".qm" ; | ||
387 | if ( trans->load( tfn ) ) | ||
388 | qApp->installTranslator( trans ); | ||
389 | else | ||
390 | delete trans; | ||
391 | } | ||
392 | } | ||
393 | |||
394 | |||
395 | |||
396 | } | ||
397 | } | ||
diff --git a/libopie2/opiecore/opluginloader.h b/libopie2/opiecore/opluginloader.h new file mode 100644 index 0000000..a7df4a8 --- a/dev/null +++ b/libopie2/opiecore/opluginloader.h | |||
@@ -0,0 +1,191 @@ | |||
1 | /* | ||
2 | * LGPLv2 or later | ||
3 | * zecke@handhelds.org | ||
4 | */ | ||
5 | #ifndef ODP_CORE_OPLUGIN_LOADER_H | ||
6 | #define ODP_CORE_OPLUGIN_LOADER_H | ||
7 | |||
8 | #include <qpe/qlibrary.h> | ||
9 | |||
10 | #include <qstringlist.h> | ||
11 | |||
12 | namespace Opie { | ||
13 | namespace Core { | ||
14 | class OConfig; | ||
15 | namespace Internal { | ||
16 | class OPluginLibraryHolder; | ||
17 | } | ||
18 | |||
19 | template class QPtrDict<QLibrary>; | ||
20 | |||
21 | /** | ||
22 | * \brief A small item representing the Plugin Information | ||
23 | * This class contains the information about a Plugin. It contains | ||
24 | * a translated name if available to the system, a config key, | ||
25 | * and the path location. | ||
26 | * | ||
27 | * @since 1.2 | ||
28 | * | ||
29 | */ | ||
30 | class OPluginItem { | ||
31 | public: | ||
32 | typedef QValueList<OPluginItem> List; | ||
33 | OPluginItem(); | ||
34 | OPluginItem( const QString& name, const QCString& confopt, const QString& path, int pos = -1 ); | ||
35 | ~OPluginItem(); | ||
36 | |||
37 | bool operator==( const OPluginItem& )const; | ||
38 | bool operator!=( const OPluginItem& )const; | ||
39 | |||
40 | |||
41 | QString name()const; | ||
42 | QCString configKey()const; | ||
43 | QString path()const; | ||
44 | int position()const; | ||
45 | |||
46 | void setName( const QString& ); | ||
47 | void setConfigKey( const QCString& ); | ||
48 | void setPath( const QString& ); | ||
49 | void setPosition( int ); | ||
50 | |||
51 | private: | ||
52 | QString m_name; | ||
53 | QCString m_conf; | ||
54 | QString m_path; | ||
55 | int m_pos; | ||
56 | struct Private; | ||
57 | Private *d; | ||
58 | }; | ||
59 | |||
60 | /** | ||
61 | * \brief A generic class to easily load and manage plugins | ||
62 | * | ||
63 | * This is the generic non sepcialised loader for plugins. Normally | ||
64 | * you would prefer using the OPluginLoader directly. This class | ||
65 | * exists to minimize the application binary size due the usage | ||
66 | * of templates in the specialized API | ||
67 | * | ||
68 | * @since 1.2 | ||
69 | * @see OPluginLoader | ||
70 | */ | ||
71 | class OGenericPluginLoader { | ||
72 | public: | ||
73 | typedef OPluginItem::List List; | ||
74 | OGenericPluginLoader( const QString &name, bool isSorted = false ); | ||
75 | virtual ~OGenericPluginLoader(); | ||
76 | |||
77 | void setAutoDelete( bool ); | ||
78 | bool autoDelete()const; | ||
79 | void clear(); | ||
80 | |||
81 | |||
82 | bool isInSafeMode()const; | ||
83 | |||
84 | |||
85 | List allAvailable(bool sorted = FALSE)const; | ||
86 | List filtered(bool sorted = FALSE)const; | ||
87 | |||
88 | |||
89 | virtual QUnknownInterface* load( const OPluginItem& item, const QUuid& ); | ||
90 | virtual void unload( QUnknownInterface* ); | ||
91 | |||
92 | protected: | ||
93 | virtual void readConfig(); | ||
94 | virtual List plugins( const QString& dir, bool sorted, bool disabled )const; | ||
95 | void setPluginDirs( const QStringList& ); | ||
96 | void setPluginDir( const QString& ); | ||
97 | bool &isSafeMode()const; | ||
98 | bool &isSorted()const; | ||
99 | void readConfig()const; | ||
100 | void setSafeMode(bool b = false); | ||
101 | |||
102 | private: | ||
103 | QString languageList(); | ||
104 | void installTranslators(const QString& type); | ||
105 | QString m_dir; | ||
106 | QStringList m_plugDirs; | ||
107 | QStringList m_languages; | ||
108 | bool m_autoDelete : 1; | ||
109 | bool m_isSafeMode : 1; | ||
110 | bool m_readConfig : 1; | ||
111 | bool m_isSorted : 1; | ||
112 | QPtrDict<QLibrary> m_library; | ||
113 | |||
114 | struct Private; | ||
115 | Private* d; | ||
116 | }; | ||
117 | |||
118 | /** | ||
119 | * \brief The class to load your QCOM+ plugins | ||
120 | * | ||
121 | * This class takes care of activation and even the order | ||
122 | * if you need it. It is normally good to place a .directory file | ||
123 | * into your plugin directory if you need order of activation. | ||
124 | * | ||
125 | * You'll create the OPluginLoader and then use it to load the filtered | ||
126 | * plugins. | ||
127 | * | ||
128 | * There is also a GUI for the configuration and a Manager to write the | ||
129 | * mentioned .directory file | ||
130 | * | ||
131 | * On crash the safe mode is activated for the next run. You can then decide | ||
132 | * if you want to load plugins or come up with the Configuration on | ||
133 | * next start yourself then. | ||
134 | * | ||
135 | * @since 1.2 | ||
136 | */ | ||
137 | class OPluginLoader : public OGenericPluginLoader { | ||
138 | public: | ||
139 | OPluginLoader( const QString& name, bool sorted = false ); | ||
140 | ~OPluginLoader(); | ||
141 | |||
142 | temlate<class IFace> | ||
143 | IFace* load( const QString& name, const QUuid& ); | ||
144 | temlate<class IFace> | ||
145 | IFace* load( const OPluginItem& item, const QUuid& ); | ||
146 | }; | ||
147 | |||
148 | /** | ||
149 | * \brief A class to manager order and activation of plugins | ||
150 | * | ||
151 | * Manage order and activation. This is used by the Opie::Ui::OPluginConfig | ||
152 | * This class controls the activation and order of plugins depending | ||
153 | * on the OPluginLoader you supply. | ||
154 | * | ||
155 | * @see OPluginConfig | ||
156 | * | ||
157 | */ | ||
158 | class OPluginManager { | ||
159 | public: | ||
160 | OPluginManager( OGenericPluginLoader* , const QString& name); | ||
161 | OPluginManager( OConfig* conf, const QString&, | ||
162 | const QCString& group, const OPluginItem::List& ); | ||
163 | ~OPluginManager(); | ||
164 | |||
165 | QString name(); | ||
166 | void setName( const QString& ); | ||
167 | |||
168 | void setPosition( const OPluginItem& ); | ||
169 | void enable( const OPluginItem& ); | ||
170 | void disable( const OPluginItem& ); | ||
171 | void setEnabled( const OPluginItem&, bool = true); | ||
172 | |||
173 | void load(); | ||
174 | void save(); | ||
175 | }; | ||
176 | |||
177 | template<class IFace> | ||
178 | IFace* OPluginLoader::load( const QString& name, const QUuid& uid ) { | ||
179 | return static_cast<IFace*>( OGenericPluginLoader::load( item, uid ) ); | ||
180 | } | ||
181 | |||
182 | template<class IFace> | ||
183 | IFace* OPluginLoader::load( const OPluginItem& item, const QUuid& uid ) { | ||
184 | return static_cast<IFace*>( OGenericPluginLoader::load( item, uid ) ); | ||
185 | } | ||
186 | |||
187 | } | ||
188 | } | ||
189 | |||
190 | |||
191 | #endif | ||