Diffstat (limited to 'qmake/tools/qgpluginmanager.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | qmake/tools/qgpluginmanager.cpp | 544 |
1 files changed, 544 insertions, 0 deletions
diff --git a/qmake/tools/qgpluginmanager.cpp b/qmake/tools/qgpluginmanager.cpp new file mode 100644 index 0000000..46c85f5 --- a/dev/null +++ b/qmake/tools/qgpluginmanager.cpp | |||
@@ -0,0 +1,544 @@ | |||
1 | /**************************************************************************** | ||
2 | ** $Id$ | ||
3 | ** | ||
4 | ** Implementation of QGPluginManager class | ||
5 | ** | ||
6 | ** Copyright (C) 2000-2001 Trolltech AS. All rights reserved. | ||
7 | ** | ||
8 | ** This file is part of the tools module of the Qt GUI Toolkit. | ||
9 | ** | ||
10 | ** This file may be distributed under the terms of the Q Public License | ||
11 | ** as defined by Trolltech AS of Norway and appearing in the file | ||
12 | ** LICENSE.QPL included in the packaging of this file. | ||
13 | ** | ||
14 | ** This file may be distributed and/or modified under the terms of the | ||
15 | ** GNU General Public License version 2 as published by the Free Software | ||
16 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
17 | ** packaging of this file. | ||
18 | ** | ||
19 | ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition | ||
20 | ** licenses may use this file in accordance with the Qt Commercial License | ||
21 | ** Agreement provided with the Software. | ||
22 | ** | ||
23 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
24 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
25 | ** | ||
26 | ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for | ||
27 | ** information about Qt Commercial License Agreements. | ||
28 | ** See http://www.trolltech.com/qpl/ for QPL licensing information. | ||
29 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
30 | ** | ||
31 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
32 | ** not clear to you. | ||
33 | ** | ||
34 | **********************************************************************/ | ||
35 | |||
36 | #include "qgpluginmanager_p.h" | ||
37 | #ifndef QT_NO_COMPONENT | ||
38 | #include "qcomlibrary_p.h" | ||
39 | #include "qmap.h" | ||
40 | #include "qdir.h" | ||
41 | |||
42 | /* | ||
43 | The following co-occurrence code is borrowed from Qt Linguist. | ||
44 | |||
45 | How similar are two texts? The approach used here relies on | ||
46 | co-occurrence matrices and is very efficient. | ||
47 | |||
48 | Let's see with an example: how similar are "here" and "hither"? The | ||
49 | co-occurrence matrix M for "here" is M[h,e] = 1, M[e,r] = 1, | ||
50 | M[r,e] = 1 and 0 elsewhere; the matrix N for "hither" is N[h,i] = 1, | ||
51 | N[i,t] = 1, ..., N[h,e] = 1, N[e,r] = 1 and 0 elsewhere. The union | ||
52 | U of both matrices is the matrix U[i,j] = max { M[i,j], N[i,j] }, | ||
53 | and the intersection V is V[i,j] = min { M[i,j], N[i,j] }. The score | ||
54 | for a pair of texts is | ||
55 | |||
56 | score = (sum of V[i,j] over all i, j) / (sum of U[i,j] over all i, j), | ||
57 | |||
58 | a formula suggested by Arnt Gulbrandsen. Here we have | ||
59 | |||
60 | score = 2 / 6, | ||
61 | |||
62 | or one third. | ||
63 | |||
64 | The implementation differs from this in a few details. Most | ||
65 | importantly, repetitions are ignored; for input "xxx", M[x,x] equals | ||
66 | 1, not 2. | ||
67 | */ | ||
68 | |||
69 | /* | ||
70 | Every character is assigned to one of 20 buckets so that the | ||
71 | co-occurrence matrix requires only 20 * 20 = 400 bits, not | ||
72 | 256 * 256 = 65536 bits or even more if we want the whole Unicode. | ||
73 | Which character falls in which bucket is arbitrary. | ||
74 | |||
75 | The second half of the table is a replica of the first half, because of | ||
76 | laziness. | ||
77 | */ | ||
78 | static const char indexOf[256] = { | ||
79 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
80 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
81 | // ! " # $ % & ' ( ) * + , - . / | ||
82 | 0, 2, 6, 7, 10, 12, 15, 19, 2, 6, 7, 10, 12, 15, 19, 0, | ||
83 | // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? | ||
84 | 1, 3, 4, 5, 8, 9, 11, 13, 14, 16, 2, 6, 7, 10, 12, 15, | ||
85 | // @ A B C D E F G H I J K L M N O | ||
86 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 10, 11, 12, 13, 14, | ||
87 | // P Q R S T U V W X Y Z [ \ ] ^ _ | ||
88 | 15, 12, 16, 17, 18, 19, 2, 10, 15, 7, 19, 2, 6, 7, 10, 0, | ||
89 | // ` a b c d e f g h i j k l m n o | ||
90 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 10, 11, 12, 13, 14, | ||
91 | // p q r s t u v w x y z { | } ~ | ||
92 | 15, 12, 16, 17, 18, 19, 2, 10, 15, 7, 19, 2, 6, 7, 10, 0, | ||
93 | |||
94 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
95 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
96 | 0, 2, 6, 7, 10, 12, 15, 19, 2, 6, 7, 10, 12, 15, 19, 0, | ||
97 | 1, 3, 4, 5, 8, 9, 11, 13, 14, 16, 2, 6, 7, 10, 12, 15, | ||
98 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 10, 11, 12, 13, 14, | ||
99 | 15, 12, 16, 17, 18, 19, 2, 10, 15, 7, 19, 2, 6, 7, 10, 0, | ||
100 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 10, 11, 12, 13, 14, | ||
101 | 15, 12, 16, 17, 18, 19, 2, 10, 15, 7, 19, 2, 6, 7, 10, 0 | ||
102 | }; | ||
103 | |||
104 | /* | ||
105 | The entry bitCount[i] (for i between 0 and 255) is the number of | ||
106 | bits used to represent i in binary. | ||
107 | */ | ||
108 | static const char bitCount[256] = { | ||
109 | 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, | ||
110 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, | ||
111 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, | ||
112 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
113 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, | ||
114 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
115 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
116 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, | ||
117 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, | ||
118 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
119 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
120 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, | ||
121 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
122 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, | ||
123 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, | ||
124 | 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 | ||
125 | }; | ||
126 | |||
127 | class QCoMatrix | ||
128 | { | ||
129 | public: | ||
130 | /* | ||
131 | The matrix has 20 * 20 = 400 entries. This requires 50 bytes, or | ||
132 | 13 words. Some operations are performed on words for more | ||
133 | efficiency. | ||
134 | */ | ||
135 | union { | ||
136 | Q_UINT8 b[52]; | ||
137 | Q_UINT32 w[13]; | ||
138 | }; | ||
139 | |||
140 | QCoMatrix() { memset( b, 0, 52 ); } | ||
141 | QCoMatrix( const char *text ) { | ||
142 | char c = '\0', d; | ||
143 | memset( b, 0, 52 ); | ||
144 | while ( (d = *text) != '\0' ) { | ||
145 | setCoocc( c, d ); | ||
146 | if ( (c = *++text) != '\0' ) { | ||
147 | setCoocc( d, c ); | ||
148 | text++; | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | |||
153 | void setCoocc( char c, char d ) { | ||
154 | int k = indexOf[(uchar) c] + 20 * indexOf[(uchar) d]; | ||
155 | b[k >> 3] |= k & 0x7; | ||
156 | } | ||
157 | |||
158 | int worth() const { | ||
159 | int result = 0; | ||
160 | for ( int i = 0; i < 50; i++ ) | ||
161 | result += bitCount[b[i]]; | ||
162 | return result; | ||
163 | } | ||
164 | |||
165 | static QCoMatrix reunion( const QCoMatrix& m, const QCoMatrix& n ) | ||
166 | { | ||
167 | QCoMatrix p; | ||
168 | for ( int i = 0; i < 13; i++ ) | ||
169 | p.w[i] = m.w[i] | n.w[i]; | ||
170 | return p; | ||
171 | } | ||
172 | static QCoMatrix intersection( const QCoMatrix& m, const QCoMatrix& n ) | ||
173 | { | ||
174 | QCoMatrix p; | ||
175 | for ( int i = 0; i < 13; i++ ) | ||
176 | p.w[i] = m.w[i] & n.w[i]; | ||
177 | return p; | ||
178 | } | ||
179 | }; | ||
180 | |||
181 | /* | ||
182 | Returns an integer between 0 (dissimilar) and 15 (very similar) | ||
183 | depending on how similar the string is to \a target. | ||
184 | |||
185 | This function is efficient, but its results might change in future | ||
186 | versions of Qt as the algorithm evolves. | ||
187 | |||
188 | \code | ||
189 | QString s( "color" ); | ||
190 | a = similarity( s, "color" ); // a == 15 | ||
191 | a = similarity( s, "colour" ); // a == 8 | ||
192 | a = similarity( s, "flavor" ); // a == 4 | ||
193 | a = similarity( s, "dahlia" ); // a == 0 | ||
194 | \endcode | ||
195 | */ | ||
196 | static int similarity( const QString& s1, const QString& s2 ) | ||
197 | { | ||
198 | QCoMatrix m1( s1 ); | ||
199 | QCoMatrix m2( s2 ); | ||
200 | return ( 15 * (QCoMatrix::intersection(m1, m2).worth() + 1) ) / | ||
201 | ( QCoMatrix::reunion(m1, m2).worth() + 1 ); | ||
202 | } | ||
203 | |||
204 | /*! | ||
205 | \class QPluginManager qpluginmanager.h | ||
206 | \reentrant | ||
207 | \brief The QPluginManager class provides basic functions to access a certain kind of functionality in libraries. | ||
208 | \ingroup componentmodel | ||
209 | |||
210 | \internal | ||
211 | |||
212 | A common usage of components is to extend the existing functionality in an application using plugins. The application | ||
213 | defines interfaces that abstract a certain group of functionality, and a plugin provides a specialized implementation | ||
214 | of one or more of those interfaces. | ||
215 | |||
216 | The QPluginManager template has to be instantiated with an interface definition and the IID for this interface. | ||
217 | |||
218 | \code | ||
219 | QPluginManager<MyPluginInterface> *manager = new QPluginManager<MyPluginInterface>( IID_MyPluginInterface ); | ||
220 | \endcode | ||
221 | |||
222 | It searches a specified directory for all shared libraries, queries for components that implement the specific interface and | ||
223 | reads information about the features the plugin wants to add to the application. The component can provide the set of features | ||
224 | provided by implementing either the QFeatureListInterface or the QComponentInformationInterface. The strings returned by the implementations | ||
225 | of | ||
226 | |||
227 | \code | ||
228 | QStringList QFeatureListInterface::featureList() const | ||
229 | \endcode | ||
230 | |||
231 | or | ||
232 | |||
233 | \code | ||
234 | QString QComponentInformationInterface::name() const | ||
235 | \endcode | ||
236 | |||
237 | respectively, can then be used to access the component that provides the requested feature: | ||
238 | |||
239 | \code | ||
240 | MyPluginInterface *iface; | ||
241 | manager->queryInterface( "feature", &iface ); | ||
242 | if ( iface ) | ||
243 | iface->execute( "feature" ); | ||
244 | \endcode | ||
245 | |||
246 | The application can use a QPluginManager instance to create parts of the user interface based on the list of features | ||
247 | found in plugins: | ||
248 | |||
249 | \code | ||
250 | QPluginManager<MyPluginInterface> *manager = new QPluginManager<MyPluginInterface>( IID_ImageFilterInterface ); | ||
251 | manager->addLibraryPath(...); | ||
252 | |||
253 | QStringList features = manager->featureList(); | ||
254 | for ( QStringList::Iterator it = features.begin(); it != features.end(); ++it ) { | ||
255 | MyPluginInterface *iface; | ||
256 | manager->queryInterface( *it, &iface ); | ||
257 | |||
258 | // use QAction to provide toolbuttons and menuitems for each feature... | ||
259 | } | ||
260 | \endcode | ||
261 | */ | ||
262 | |||
263 | /*! | ||
264 | \fn QPluginManager::QPluginManager( const QUuid& id, const QStringList& paths = QString::null, const QString &suffix = QString::null, bool cs = TRUE ) | ||
265 | |||
266 | Creates an QPluginManager for interfaces \a id that will load all shared library files in the \a paths + \a suffix. | ||
267 | If \a cs is FALSE the manager will handle feature strings case insensitive. | ||
268 | |||
269 | \warning | ||
270 | Setting the cs flag to FALSE requires that components also convert to lower case when comparing with passed strings, so this has | ||
271 | to be handled with care and documented very well. | ||
272 | |||
273 | \sa QApplication::libraryPaths() | ||
274 | */ | ||
275 | |||
276 | |||
277 | /*! | ||
278 | \fn QRESULT QPluginManager::queryInterface(const QString& feature, Type** iface) const | ||
279 | |||
280 | Sets \a iface to point to the interface providing \a feature. | ||
281 | |||
282 | \sa featureList(), library() | ||
283 | */ | ||
284 | |||
285 | |||
286 | |||
287 | #include <qptrlist.h> | ||
288 | |||
289 | QGPluginManager::QGPluginManager( const QUuid& id, const QStringList& paths, const QString &suffix, bool cs ) | ||
290 | : interfaceId( id ), plugDict( 17, cs ), casesens( cs ), autounload( TRUE ) | ||
291 | { | ||
292 | // Every QLibrary object is destroyed on destruction of the manager | ||
293 | libDict.setAutoDelete( TRUE ); | ||
294 | for ( QStringList::ConstIterator it = paths.begin(); it != paths.end(); ++it ) { | ||
295 | QString path = *it; | ||
296 | addLibraryPath( path + suffix ); | ||
297 | } | ||
298 | } | ||
299 | |||
300 | QGPluginManager::~QGPluginManager() | ||
301 | { | ||
302 | if ( !autounload ) { | ||
303 | QDictIterator<QLibrary> it( libDict ); | ||
304 | while ( it.current() ) { | ||
305 | QLibrary *lib = it.current(); | ||
306 | ++it; | ||
307 | lib->setAutoUnload( FALSE ); | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | |||
312 | void QGPluginManager::addLibraryPath( const QString& path ) | ||
313 | { | ||
314 | if ( !enabled() || !QDir( path ).exists( ".", TRUE ) ) | ||
315 | return; | ||
316 | |||
317 | #if defined(Q_OS_WIN32) | ||
318 | QString filter = "dll"; | ||
319 | #elif defined(Q_OS_MACX) | ||
320 | QString filter = "dylib"; | ||
321 | #elif defined(Q_OS_UNIX) | ||
322 | QString filter = "so"; | ||
323 | #endif | ||
324 | |||
325 | QStringList plugins = QDir(path).entryList( "*." + filter ); | ||
326 | for ( QStringList::Iterator p = plugins.begin(); p != plugins.end(); ++p ) { | ||
327 | QString lib = QDir::cleanDirPath( path + "/" + *p ); | ||
328 | if ( libList.contains( lib ) ) | ||
329 | continue; | ||
330 | libList.append( lib ); | ||
331 | } | ||
332 | } | ||
333 | |||
334 | const QLibrary* QGPluginManager::library( const QString& feature ) const | ||
335 | { | ||
336 | if ( !enabled() || feature.isEmpty() ) | ||
337 | return 0; | ||
338 | |||
339 | // We already have a QLibrary object for this feature | ||
340 | QLibrary *library = 0; | ||
341 | if ( ( library = plugDict[feature] ) ) | ||
342 | return library; | ||
343 | |||
344 | // Find the filename that matches the feature request best | ||
345 | QMap<int, QStringList> map; | ||
346 | QStringList::ConstIterator it = libList.begin(); | ||
347 | int best = 0; | ||
348 | int worst = 15; | ||
349 | while ( it != libList.end() ) { | ||
350 | if ( (*it).isEmpty() || libDict[*it] ) { | ||
351 | ++it; | ||
352 | continue; | ||
353 | } | ||
354 | QString basename = QFileInfo(*it).baseName(); | ||
355 | int s = similarity( feature, basename ); | ||
356 | if ( s < worst ) | ||
357 | worst = s; | ||
358 | if ( s > best ) | ||
359 | best = s; | ||
360 | map[s].append( basename + QChar(0xfffd) + *it ); | ||
361 | ++it; | ||
362 | } | ||
363 | |||
364 | if ( map.isEmpty() ) | ||
365 | return 0; // no libraries to add | ||
366 | |||
367 | // Start with the best match to get the library object | ||
368 | QGPluginManager *that = (QGPluginManager*)this; | ||
369 | for ( int s = best; s >= worst; --s ) { | ||
370 | QStringList group = map[s]; | ||
371 | group.sort(); // sort according to the base name | ||
372 | QStringList::ConstIterator git = group.begin(); | ||
373 | while ( git != group.end() ) { | ||
374 | QString lib = (*git).mid( (*git).find( QChar(0xfffd) ) + 1 ); | ||
375 | QString basename = (*git).left( (*git).find( QChar(0xfffd) ) ); | ||
376 | ++git; | ||
377 | |||
378 | QStringList sameBasename; | ||
379 | while( git != group.end() && | ||
380 | basename == (*git).left( (*git).find( QChar(0xfffd) ) ) ) { | ||
381 | sameBasename << (*git).mid( (*git).find( QChar(0xfffd) ) + 1 ); | ||
382 | ++git; | ||
383 | } | ||
384 | |||
385 | if ( sameBasename.isEmpty() ) { | ||
386 | that->addLibrary( new QComLibrary( lib ) ); | ||
387 | } else { | ||
388 | QPtrList<QComLibrary> same; | ||
389 | same.setAutoDelete( TRUE ); | ||
390 | for ( QStringList::ConstIterator bit = sameBasename.begin(); | ||
391 | bit != sameBasename.end(); ++bit ) | ||
392 | same.append( new QComLibrary( *bit ) ); | ||
393 | QComLibrary* bestMatch = 0; | ||
394 | for ( QComLibrary* candidate = same.first(); candidate; candidate = same.next() ) | ||
395 | if ( candidate->qtVersion() && candidate->qtVersion() <= QT_VERSION | ||
396 | && ( !bestMatch || candidate->qtVersion() > bestMatch->qtVersion() ) ) | ||
397 | bestMatch = candidate; | ||
398 | if ( bestMatch ) { | ||
399 | same.find( bestMatch ); | ||
400 | that->addLibrary( same.take() ); | ||
401 | } | ||
402 | } | ||
403 | |||
404 | if ( ( library = that->plugDict[feature] ) ) | ||
405 | return library; | ||
406 | } | ||
407 | } | ||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | QStringList QGPluginManager::featureList() const | ||
412 | { | ||
413 | QStringList features; | ||
414 | |||
415 | if ( !enabled() ) | ||
416 | return features; | ||
417 | |||
418 | QGPluginManager *that = (QGPluginManager*)this; | ||
419 | QStringList theLibs = libList; | ||
420 | QStringList phase2Libs; | ||
421 | QStringList phase2Deny; | ||
422 | |||
423 | /* In order to get the feature list we need to add all interesting | ||
424 | libraries. If there are libraries with the same base name, we | ||
425 | prioritze the one that fits our Qt version number and ignore the | ||
426 | others */ | ||
427 | QStringList::Iterator it; | ||
428 | for ( it = theLibs.begin(); it != theLibs.end(); ++it ) { | ||
429 | if ( (*it).isEmpty() || libDict[*it] ) | ||
430 | continue; | ||
431 | QComLibrary* library = new QComLibrary( *it ); | ||
432 | if ( library->qtVersion() == QT_VERSION ) { | ||
433 | that->addLibrary( library ); | ||
434 | phase2Deny << QFileInfo( *it ).baseName(); | ||
435 | } else { | ||
436 | delete library; | ||
437 | phase2Libs << *it; | ||
438 | } | ||
439 | } | ||
440 | for ( it = phase2Libs.begin(); it != phase2Libs.end(); ++it ) | ||
441 | if ( !phase2Deny.contains( QFileInfo( *it ).baseName() ) ) | ||
442 | that->addLibrary( new QComLibrary( *it ) ); | ||
443 | |||
444 | for ( QDictIterator<QLibrary> pit( plugDict ); pit.current(); ++pit ) | ||
445 | features << pit.currentKey(); | ||
446 | |||
447 | return features; | ||
448 | } | ||
449 | |||
450 | bool QGPluginManager::addLibrary( QLibrary* lib ) | ||
451 | { | ||
452 | if ( !enabled() || !lib ) | ||
453 | return FALSE; | ||
454 | |||
455 | QComLibrary* plugin = (QComLibrary*)lib; | ||
456 | bool useful = FALSE; | ||
457 | |||
458 | QUnknownInterface* iFace = 0; | ||
459 | plugin->queryInterface( interfaceId, &iFace ); | ||
460 | if ( iFace ) { | ||
461 | QFeatureListInterface *fliFace = 0; | ||
462 | QComponentInformationInterface *cpiFace = 0; | ||
463 | iFace->queryInterface( IID_QFeatureList, (QUnknownInterface**)&fliFace ); | ||
464 | if ( !fliFace ) | ||
465 | plugin->queryInterface( IID_QFeatureList, (QUnknownInterface**)&fliFace ); | ||
466 | if ( !fliFace ) { | ||
467 | iFace->queryInterface( IID_QComponentInformation, (QUnknownInterface**)&cpiFace ); | ||
468 | if ( !cpiFace ) | ||
469 | plugin->queryInterface( IID_QComponentInformation, (QUnknownInterface**)&cpiFace ); | ||
470 | } | ||
471 | QStringList fl; | ||
472 | if ( fliFace ) | ||
473 | // Map all found features to the library | ||
474 | fl = fliFace->featureList(); | ||
475 | else if ( cpiFace ) | ||
476 | fl << cpiFace->name(); | ||
477 | |||
478 | for ( QStringList::Iterator f = fl.begin(); f != fl.end(); f++ ) { | ||
479 | QLibrary *old = plugDict[*f]; | ||
480 | if ( !old ) { | ||
481 | useful = TRUE; | ||
482 | plugDict.replace( *f, plugin ); | ||
483 | } else { | ||
484 | // we have old *and* plugin, which one to pick? | ||
485 | QComLibrary* first = (QComLibrary*)old; | ||
486 | QComLibrary* second = (QComLibrary*)plugin; | ||
487 | bool takeFirst = TRUE; | ||
488 | if ( first->qtVersion() != QT_VERSION ) { | ||
489 | if ( second->qtVersion() == QT_VERSION ) | ||
490 | takeFirst = FALSE; | ||
491 | else if ( second->qtVersion() < QT_VERSION && | ||
492 | first->qtVersion() > QT_VERSION ) | ||
493 | takeFirst = FALSE; | ||
494 | } | ||
495 | if ( !takeFirst ) { | ||
496 | useful = TRUE; | ||
497 | plugDict.replace( *f, plugin ); | ||
498 | qWarning("%s: Discarding feature %s in %s!", | ||
499 | (const char*) QFile::encodeName( plugin->library()), | ||
500 | (*f).latin1(), | ||
501 | (const char*) QFile::encodeName( old->library() ) ); | ||
502 | } else { | ||
503 | qWarning("%s: Feature %s already defined in %s!", | ||
504 | (const char*) QFile::encodeName( old->library() ), | ||
505 | (*f).latin1(), | ||
506 | (const char*) QFile::encodeName( plugin->library() ) ); | ||
507 | } | ||
508 | } | ||
509 | } | ||
510 | if ( fliFace ) | ||
511 | fliFace->release(); | ||
512 | if ( cpiFace ) | ||
513 | cpiFace->release(); | ||
514 | iFace->release(); | ||
515 | } | ||
516 | |||
517 | if ( useful ) { | ||
518 | libDict.replace( plugin->library(), plugin ); | ||
519 | if ( !libList.contains( plugin->library() ) ) | ||
520 | libList.append( plugin->library() ); | ||
521 | return TRUE; | ||
522 | } | ||
523 | delete plugin; | ||
524 | return FALSE; | ||
525 | } | ||
526 | |||
527 | |||
528 | bool QGPluginManager::enabled() const | ||
529 | { | ||
530 | #ifdef QT_SHARED | ||
531 | return TRUE; | ||
532 | #else | ||
533 | return FALSE; | ||
534 | #endif | ||
535 | } | ||
536 | |||
537 | QRESULT QGPluginManager::queryUnknownInterface(const QString& feature, QUnknownInterface** iface) const | ||
538 | { | ||
539 | QComLibrary* plugin = 0; | ||
540 | plugin = (QComLibrary*)library( feature ); | ||
541 | return plugin ? plugin->queryInterface( interfaceId, (QUnknownInterface**)iface ) : QE_NOINTERFACE; | ||
542 | } | ||
543 | |||
544 | #endif //QT_NO_COMPONENT | ||