source: trunk/tools/designer/src/lib/shared/pluginmanager.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 27.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the Qt Designer of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "pluginmanager_p.h"
43#include "qdesigner_utils_p.h"
44#include "qdesigner_qsettings_p.h"
45
46#include <QtDesigner/QDesignerFormEditorInterface>
47#include <QtDesigner/QDesignerCustomWidgetInterface>
48#include <QtDesigner/QExtensionManager>
49#include <QtDesigner/QDesignerLanguageExtension>
50
51#include <QtCore/QDir>
52#include <QtCore/QFile>
53#include <QtCore/QFileInfo>
54#include <QtCore/QSet>
55#include <QtCore/QPluginLoader>
56#include <QtCore/QLibrary>
57#include <QtCore/QLibraryInfo>
58#include <QtCore/qdebug.h>
59#include <QtCore/QMap>
60#include <QtCore/QSettings>
61#include <QtCore/QCoreApplication>
62
63#include <QtCore/QXmlStreamReader>
64#include <QtCore/QXmlStreamAttributes>
65#include <QtCore/QXmlStreamAttribute>
66
67static const char *uiElementC = "ui";
68static const char *languageAttributeC = "language";
69static const char *widgetElementC = "widget";
70static const char *displayNameAttributeC = "displayname";
71static const char *classAttributeC = "class";
72static const char *customwidgetElementC = "customwidget";
73static const char *extendsElementC = "extends";
74static const char *addPageMethodC = "addpagemethod";
75static const char *propertySpecsC = "propertyspecifications";
76static const char *stringPropertySpecC = "stringpropertyspecification";
77static const char *stringPropertyNameAttrC = "name";
78static const char *stringPropertyTypeAttrC = "type";
79static const char *stringPropertyNoTrAttrC = "notr";
80static const char *jambiLanguageC = "jambi";
81
82enum { debugPluginManager = 0 };
83
84/* Custom widgets: Loading custom widgets is a 2-step process: PluginManager
85 * scans for its plugins in the constructor. At this point, it might not be safe
86 * to immediately initialize the custom widgets it finds, because the rest of
87 * Designer is not initialized yet.
88 * Later on, in ensureInitialized(), the plugin instances (including static ones)
89 * are iterated and the custom widget plugins are initialized and added to internal
90 * list of custom widgets and parsed data. Should there be a parse error or a language
91 * mismatch, it kicks out the respective custom widget. The m_initialized flag
92 * is used to indicate the state.
93 * Later, someone might call registerNewPlugins(), which agains clears the flag via
94 * registerPlugin() and triggers the process again.
95 * Also note that Jambi fakes a custom widget collection that changes its contents
96 * every time the project is switched. So, custom widget plugins can actually
97 * disappear, and the custom widget list must be cleared and refilled in
98 * ensureInitialized() after registerNewPlugins. */
99
100QT_BEGIN_NAMESPACE
101
102static QStringList unique(const QStringList &lst)
103{
104 const QSet<QString> s = QSet<QString>::fromList(lst);
105 return s.toList();
106}
107
108QStringList QDesignerPluginManager::defaultPluginPaths()
109{
110 QStringList result;
111
112 const QStringList path_list = QCoreApplication::libraryPaths();
113
114 const QString designer = QLatin1String("designer");
115 foreach (const QString &path, path_list) {
116 QString libPath = path;
117 libPath += QDir::separator();
118 libPath += designer;
119 result.append(libPath);
120 }
121
122 QString homeLibPath = QDir::homePath();
123 homeLibPath += QDir::separator();
124 homeLibPath += QLatin1String(".designer");
125 homeLibPath += QDir::separator();
126 homeLibPath += QLatin1String("plugins");
127
128 result.append(homeLibPath);
129 return result;
130}
131
132// Figure out the language designer is running. ToDo: Introduce some
133// Language name API to QDesignerLanguageExtension?
134
135static inline QString getDesignerLanguage(QDesignerFormEditorInterface *core)
136{
137 if (QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension *>(core->extensionManager(), core)) {
138 if (lang->uiExtension() == QLatin1String("jui"))
139 return QLatin1String(jambiLanguageC);
140 return QLatin1String("unknown");
141 }
142 return QLatin1String("c++");
143}
144
145// ---------------- QDesignerCustomWidgetSharedData
146
147class QDesignerCustomWidgetSharedData : public QSharedData {
148public:
149 // Type of a string property
150 typedef QPair<qdesigner_internal::TextPropertyValidationMode, bool> StringPropertyType;
151 typedef QHash<QString, StringPropertyType> StringPropertyTypeMap;
152
153 explicit QDesignerCustomWidgetSharedData(const QString &thePluginPath) : pluginPath(thePluginPath) {}
154 void clearXML();
155
156 QString pluginPath;
157
158 QString xmlClassName;
159 QString xmlDisplayName;
160 QString xmlLanguage;
161 QString xmlAddPageMethod;
162 QString xmlExtends;
163
164 StringPropertyTypeMap xmlStringPropertyTypeMap;
165};
166
167void QDesignerCustomWidgetSharedData::clearXML()
168{
169 xmlClassName.clear();
170 xmlDisplayName.clear();
171 xmlLanguage.clear();
172 xmlAddPageMethod.clear();
173 xmlExtends.clear();
174 xmlStringPropertyTypeMap.clear();
175}
176
177// ---------------- QDesignerCustomWidgetData
178
179QDesignerCustomWidgetData::QDesignerCustomWidgetData(const QString &pluginPath) :
180 m_d(new QDesignerCustomWidgetSharedData(pluginPath))
181{
182}
183
184QDesignerCustomWidgetData::QDesignerCustomWidgetData(const QDesignerCustomWidgetData &o) :
185 m_d(o.m_d)
186{
187}
188
189QDesignerCustomWidgetData& QDesignerCustomWidgetData::operator=(const QDesignerCustomWidgetData &o)
190{
191 m_d.operator=(o.m_d);
192 return *this;
193}
194
195QDesignerCustomWidgetData::~QDesignerCustomWidgetData()
196{
197}
198
199bool QDesignerCustomWidgetData::isNull() const
200{
201 return m_d->xmlClassName.isEmpty() || m_d->pluginPath.isEmpty();
202}
203
204QString QDesignerCustomWidgetData::xmlClassName() const
205{
206 return m_d->xmlClassName;
207}
208
209QString QDesignerCustomWidgetData::xmlLanguage() const
210{
211 return m_d->xmlLanguage;
212}
213
214QString QDesignerCustomWidgetData::xmlAddPageMethod() const
215{
216 return m_d->xmlAddPageMethod;
217}
218
219QString QDesignerCustomWidgetData::xmlExtends() const
220{
221 return m_d->xmlExtends;
222}
223
224QString QDesignerCustomWidgetData::xmlDisplayName() const
225{
226 return m_d->xmlDisplayName;
227}
228
229QString QDesignerCustomWidgetData::pluginPath() const
230{
231 return m_d->pluginPath;
232}
233
234bool QDesignerCustomWidgetData::xmlStringPropertyType(const QString &name, StringPropertyType *type) const
235{
236 QDesignerCustomWidgetSharedData::StringPropertyTypeMap::const_iterator it = m_d->xmlStringPropertyTypeMap.constFind(name);
237 if (it == m_d->xmlStringPropertyTypeMap.constEnd()) {
238 *type = StringPropertyType(qdesigner_internal::ValidationRichText, true);
239 return false;
240 }
241 *type = it.value();
242 return true;
243}
244
245// Wind a QXmlStreamReader until it finds an element. Returns index or one of FindResult
246enum FindResult { FindError = -2, ElementNotFound = -1 };
247
248static int findElement(const QStringList &desiredElts, QXmlStreamReader &sr)
249{
250 while (true) {
251 switch(sr.readNext()) {
252 case QXmlStreamReader::EndDocument:
253 return ElementNotFound;
254 case QXmlStreamReader::Invalid:
255 return FindError;
256 case QXmlStreamReader::StartElement: {
257 const int index = desiredElts.indexOf(sr.name().toString().toLower());
258 if (index >= 0)
259 return index;
260 }
261 break;
262 default:
263 break;
264 }
265 }
266 return FindError;
267}
268
269static inline QString msgXmlError(const QString &name, const QString &errorMessage)
270{
271 return QDesignerPluginManager::tr("An XML error was encountered when parsing the XML of the custom widget %1: %2").arg(name, errorMessage);
272}
273
274static inline QString msgAttributeMissing(const QString &name)
275{
276 return QDesignerPluginManager::tr("A required attribute ('%1') is missing.").arg(name);
277}
278
279static qdesigner_internal::TextPropertyValidationMode typeStringToType(const QString &v, bool *ok)
280{
281 *ok = true;
282 if (v == QLatin1String("multiline"))
283 return qdesigner_internal::ValidationMultiLine;
284 if (v == QLatin1String("richtext"))
285 return qdesigner_internal::ValidationRichText;
286 if (v == QLatin1String("stylesheet"))
287 return qdesigner_internal::ValidationStyleSheet;
288 if (v == QLatin1String("singleline"))
289 return qdesigner_internal::ValidationSingleLine;
290 if (v == QLatin1String("objectname"))
291 return qdesigner_internal::ValidationObjectName;
292 if (v == QLatin1String("objectnamescope"))
293 return qdesigner_internal::ValidationObjectNameScope;
294 if (v == QLatin1String("url"))
295 return qdesigner_internal::ValidationURL;
296 *ok = false;
297 return qdesigner_internal::ValidationRichText;
298}
299
300static bool parsePropertySpecs(QXmlStreamReader &sr,
301 QDesignerCustomWidgetSharedData::StringPropertyTypeMap *rc,
302 QString *errorMessage)
303{
304 const QString propertySpecs = QLatin1String(propertySpecsC);
305 const QString stringPropertySpec = QLatin1String(stringPropertySpecC);
306 const QString stringPropertyTypeAttr = QLatin1String(stringPropertyTypeAttrC);
307 const QString stringPropertyNoTrAttr = QLatin1String(stringPropertyNoTrAttrC);
308 const QString stringPropertyNameAttr = QLatin1String(stringPropertyNameAttrC);
309
310 while (!sr.atEnd()) {
311 switch(sr.readNext()) {
312 case QXmlStreamReader::StartElement: {
313 if (sr.name() != stringPropertySpec) {
314 *errorMessage = QDesignerPluginManager::tr("An invalid property specification ('%1') was encountered. Supported types: %2").arg(sr.name().toString(), stringPropertySpec);
315 return false;
316 }
317 const QXmlStreamAttributes atts = sr.attributes();
318 const QString name = atts.value(stringPropertyNameAttr).toString();
319 const QString type = atts.value(stringPropertyTypeAttr).toString();
320 const QString notrS = atts.value(stringPropertyNoTrAttr).toString(); //Optional
321
322 if (type.isEmpty()) {
323 *errorMessage = msgAttributeMissing(stringPropertyTypeAttr);
324 return false;
325 }
326 if (name.isEmpty()) {
327 *errorMessage = msgAttributeMissing(stringPropertyNameAttr);
328 return false;
329 }
330 bool typeOk;
331 const bool noTr = notrS == QLatin1String("true") || notrS == QLatin1String("1");
332 QDesignerCustomWidgetSharedData::StringPropertyType v(typeStringToType(type, &typeOk), !noTr);
333 if (!typeOk) {
334 *errorMessage = QDesignerPluginManager::tr("'%1' is not a valid string property specification.").arg(type);
335 return false;
336 }
337 rc->insert(name, v);
338 }
339 break;
340 case QXmlStreamReader::EndElement: // Outer </stringproperties>
341 if (sr.name() == propertySpecs)
342 return true;
343 default:
344 break;
345 }
346 }
347 return true;
348}
349
350QDesignerCustomWidgetData::ParseResult
351 QDesignerCustomWidgetData::parseXml(const QString &xml, const QString &name, QString *errorMessage)
352{
353 if (debugPluginManager)
354 qDebug() << Q_FUNC_INFO << name;
355
356 QDesignerCustomWidgetSharedData &data = *m_d;
357 data.clearXML();
358
359 QXmlStreamReader sr(xml);
360
361 bool foundUI = false;
362 bool foundWidget = false;
363 ParseResult rc = ParseOk;
364 // Parse for the (optional) <ui> or the first <widget> element
365 QStringList elements;
366 elements.push_back(QLatin1String(uiElementC));
367 elements.push_back(QLatin1String(widgetElementC));
368 for (int i = 0; i < 2 && !foundWidget; i++) {
369 switch (findElement(elements, sr)) {
370 case FindError:
371 *errorMessage = msgXmlError(name, sr.errorString());
372 return ParseError;
373 case ElementNotFound:
374 *errorMessage = QDesignerPluginManager::tr("The XML of the custom widget %1 does not contain any of the elements <widget> or <ui>.").arg(name);
375 return ParseError;
376 case 0: { // <ui>
377 const QXmlStreamAttributes attributes = sr.attributes();
378 data.xmlLanguage = attributes.value(QLatin1String(languageAttributeC)).toString();
379 data.xmlDisplayName = attributes.value(QLatin1String(displayNameAttributeC)).toString();
380 foundUI = true;
381 }
382 break;
383 case 1: // <widget>: Do some sanity checks
384 data.xmlClassName = sr.attributes().value(QLatin1String(classAttributeC)).toString();
385 if (data.xmlClassName.isEmpty()) {
386 *errorMessage = QDesignerPluginManager::tr("The class attribute for the class %1 is missing.").arg(name);
387 rc = ParseWarning;
388 } else {
389 if (data.xmlClassName != name) {
390 *errorMessage = QDesignerPluginManager::tr("The class attribute for the class %1 does not match the class name %2.").arg(data.xmlClassName, name);
391 rc = ParseWarning;
392 }
393 }
394 foundWidget = true;
395 break;
396 }
397 }
398 // Parse out the <customwidget> element which might be present if <ui> was there
399 if (!foundUI)
400 return rc;
401 elements.clear();
402 elements.push_back(QLatin1String(customwidgetElementC));
403 switch (findElement(elements, sr)) {
404 case FindError:
405 *errorMessage = msgXmlError(name, sr.errorString());
406 return ParseError;
407 case ElementNotFound:
408 return rc;
409 default:
410 break;
411 }
412 // Find <extends>, <addPageMethod>, <stringproperties>
413 elements.clear();
414 elements.push_back(QLatin1String(extendsElementC));
415 elements.push_back(QLatin1String(addPageMethodC));
416 elements.push_back(QLatin1String(propertySpecsC));
417 while (true) {
418 switch (findElement(elements, sr)) {
419 case FindError:
420 *errorMessage = msgXmlError(name, sr.errorString());
421 return ParseError;
422 case ElementNotFound:
423 return rc;
424 case 0: // <extends>
425 data.xmlExtends = sr.readElementText();
426 if (sr.tokenType() != QXmlStreamReader::EndElement) {
427 *errorMessage = msgXmlError(name, sr.errorString());
428 return ParseError;
429 }
430 break;
431 case 1: // <addPageMethod>
432 data.xmlAddPageMethod = sr.readElementText();
433 if (sr.tokenType() != QXmlStreamReader::EndElement) {
434 *errorMessage = msgXmlError(name, sr.errorString());
435 return ParseError;
436 }
437 break;
438 case 2: // <stringproperties>
439 if (!parsePropertySpecs(sr, &m_d->xmlStringPropertyTypeMap, errorMessage)) {
440 *errorMessage = msgXmlError(name, *errorMessage);
441 return ParseError;
442 }
443 break;
444 }
445 }
446 return rc;
447}
448
449// ---------------- QDesignerPluginManagerPrivate
450
451class QDesignerPluginManagerPrivate {
452 public:
453 typedef QPair<QString, QString> ClassNamePropertyNameKey;
454
455 QDesignerPluginManagerPrivate(QDesignerFormEditorInterface *core);
456
457 void clearCustomWidgets();
458 bool addCustomWidget(QDesignerCustomWidgetInterface *c,
459 const QString &pluginPath,
460 const QString &designerLanguage);
461 void addCustomWidgets(const QObject *o,
462 const QString &pluginPath,
463 const QString &designerLanguage);
464
465 QDesignerFormEditorInterface *m_core;
466 QStringList m_pluginPaths;
467 QStringList m_registeredPlugins;
468 // TODO: QPluginLoader also caches invalid plugins -> This seems to be dead code
469 QStringList m_disabledPlugins;
470
471 typedef QMap<QString, QString> FailedPluginMap;
472 FailedPluginMap m_failedPlugins;
473
474 // Synced lists of custom widgets and their data. Note that the list
475 // must be ordered for collections to appear in order.
476 QList<QDesignerCustomWidgetInterface *> m_customWidgets;
477 QList<QDesignerCustomWidgetData> m_customWidgetData;
478
479 QStringList defaultPluginPaths() const;
480
481 bool m_initialized;
482};
483
484QDesignerPluginManagerPrivate::QDesignerPluginManagerPrivate(QDesignerFormEditorInterface *core) :
485 m_core(core),
486 m_initialized(false)
487{
488}
489
490void QDesignerPluginManagerPrivate::clearCustomWidgets()
491{
492 m_customWidgets.clear();
493 m_customWidgetData.clear();
494}
495
496// Add a custom widget to the list if it parses correctly
497// and is of the right language
498bool QDesignerPluginManagerPrivate::addCustomWidget(QDesignerCustomWidgetInterface *c,
499 const QString &pluginPath,
500 const QString &designerLanguage)
501{
502 if (debugPluginManager)
503 qDebug() << Q_FUNC_INFO << c->name();
504
505 if (!c->isInitialized())
506 c->initialize(m_core);
507 // Parse the XML even if the plugin is initialized as Jambi might play tricks here
508 QDesignerCustomWidgetData data(pluginPath);
509 const QString domXml = c->domXml();
510 if (!domXml.isEmpty()) { // Legacy: Empty XML means: Do not show up in widget box.
511 QString errorMessage;
512 const QDesignerCustomWidgetData::ParseResult pr = data.parseXml(domXml, c->name(), &errorMessage);
513 switch (pr) {
514 case QDesignerCustomWidgetData::ParseOk:
515 break;
516 case QDesignerCustomWidgetData::ParseWarning:
517 qdesigner_internal::designerWarning(errorMessage);
518 break;
519 case QDesignerCustomWidgetData::ParseError:
520 qdesigner_internal::designerWarning(errorMessage);
521 return false;
522 }
523 // Does the language match?
524 const QString pluginLanguage = data.xmlLanguage();
525 if (!pluginLanguage.isEmpty() && pluginLanguage.compare(designerLanguage, Qt::CaseInsensitive))
526 return false;
527 }
528 m_customWidgets.push_back(c);
529 m_customWidgetData.push_back(data);
530 return true;
531}
532
533// Check the plugin interface for either a custom widget or a collection and
534// add all contained custom widgets.
535void QDesignerPluginManagerPrivate::addCustomWidgets(const QObject *o,
536 const QString &pluginPath,
537 const QString &designerLanguage)
538{
539 if (QDesignerCustomWidgetInterface *c = qobject_cast<QDesignerCustomWidgetInterface*>(o)) {
540 addCustomWidget(c, pluginPath, designerLanguage);
541 return;
542 }
543 if (const QDesignerCustomWidgetCollectionInterface *coll = qobject_cast<QDesignerCustomWidgetCollectionInterface*>(o)) {
544 foreach(QDesignerCustomWidgetInterface *c, coll->customWidgets())
545 addCustomWidget(c, pluginPath, designerLanguage);
546 }
547}
548
549
550// ---------------- QDesignerPluginManager
551// As of 4.4, the header will be distributed with the Eclipse plugin.
552
553QDesignerPluginManager::QDesignerPluginManager(QDesignerFormEditorInterface *core) :
554 QObject(core),
555 m_d(new QDesignerPluginManagerPrivate(core))
556{
557 m_d->m_pluginPaths = defaultPluginPaths();
558 const QSettings settings(qApp->organizationName(), QDesignerQSettings::settingsApplicationName());
559 m_d->m_disabledPlugins = unique(settings.value(QLatin1String("PluginManager/DisabledPlugins")).toStringList());
560
561 // Register plugins
562 updateRegisteredPlugins();
563
564 if (debugPluginManager)
565 qDebug() << "QDesignerPluginManager::disabled: " << m_d->m_disabledPlugins << " static " << m_d->m_customWidgets.size();
566}
567
568QDesignerPluginManager::~QDesignerPluginManager()
569{
570 syncSettings();
571 delete m_d;
572}
573
574QDesignerFormEditorInterface *QDesignerPluginManager::core() const
575{
576 return m_d->m_core;
577}
578
579QStringList QDesignerPluginManager::findPlugins(const QString &path)
580{
581 if (debugPluginManager)
582 qDebug() << Q_FUNC_INFO << path;
583 const QDir dir(path);
584 if (!dir.exists())
585 return QStringList();
586
587 const QFileInfoList infoList = dir.entryInfoList(QDir::Files);
588 if (infoList.empty())
589 return QStringList();
590
591 // Load symbolic links but make sure all file names are unique as not
592 // to fall for something like 'libplugin.so.1 -> libplugin.so'
593 QStringList result;
594 const QFileInfoList::const_iterator icend = infoList.constEnd();
595 for (QFileInfoList::const_iterator it = infoList.constBegin(); it != icend; ++it) {
596 QString fileName;
597 if (it->isSymLink()) {
598 const QFileInfo linkTarget = QFileInfo(it->symLinkTarget());
599 if (linkTarget.exists() && linkTarget.isFile())
600 fileName = linkTarget.absoluteFilePath();
601 } else {
602 fileName = it->absoluteFilePath();
603 }
604 if (!fileName.isEmpty() && QLibrary::isLibrary(fileName) && !result.contains(fileName))
605 result += fileName;
606 }
607 return result;
608}
609
610void QDesignerPluginManager::setDisabledPlugins(const QStringList &disabled_plugins)
611{
612 m_d->m_disabledPlugins = disabled_plugins;
613 updateRegisteredPlugins();
614}
615
616void QDesignerPluginManager::setPluginPaths(const QStringList &plugin_paths)
617{
618 m_d->m_pluginPaths = plugin_paths;
619 updateRegisteredPlugins();
620}
621
622QStringList QDesignerPluginManager::disabledPlugins() const
623{
624 return m_d->m_disabledPlugins;
625}
626
627QStringList QDesignerPluginManager::failedPlugins() const
628{
629 return m_d->m_failedPlugins.keys();
630}
631
632QString QDesignerPluginManager::failureReason(const QString &pluginName) const
633{
634 return m_d->m_failedPlugins.value(pluginName);
635}
636
637QStringList QDesignerPluginManager::registeredPlugins() const
638{
639 return m_d->m_registeredPlugins;
640}
641
642QStringList QDesignerPluginManager::pluginPaths() const
643{
644 return m_d->m_pluginPaths;
645}
646
647QObject *QDesignerPluginManager::instance(const QString &plugin) const
648{
649 if (m_d->m_disabledPlugins.contains(plugin))
650 return 0;
651
652 QPluginLoader loader(plugin);
653 return loader.instance();
654}
655
656void QDesignerPluginManager::updateRegisteredPlugins()
657{
658 if (debugPluginManager)
659 qDebug() << Q_FUNC_INFO;
660 m_d->m_registeredPlugins.clear();
661 foreach (const QString &path, m_d->m_pluginPaths)
662 registerPath(path);
663}
664
665bool QDesignerPluginManager::registerNewPlugins()
666{
667 if (debugPluginManager)
668 qDebug() << Q_FUNC_INFO;
669
670 const int before = m_d->m_registeredPlugins.size();
671 foreach (const QString &path, m_d->m_pluginPaths)
672 registerPath(path);
673 const bool newPluginsFound = m_d->m_registeredPlugins.size() > before;
674 // We force a re-initialize as Jambi collection might return
675 // different widget lists when switching projects.
676 m_d->m_initialized = false;
677 ensureInitialized();
678
679 return newPluginsFound;
680}
681
682void QDesignerPluginManager::registerPath(const QString &path)
683{
684 if (debugPluginManager)
685 qDebug() << Q_FUNC_INFO << path;
686 QStringList candidates = findPlugins(path);
687
688 foreach (const QString &plugin, candidates)
689 registerPlugin(plugin);
690}
691
692void QDesignerPluginManager::registerPlugin(const QString &plugin)
693{
694 if (debugPluginManager)
695 qDebug() << Q_FUNC_INFO << plugin;
696 if (m_d->m_disabledPlugins.contains(plugin))
697 return;
698 if (m_d->m_registeredPlugins.contains(plugin))
699 return;
700
701 QPluginLoader loader(plugin);
702 if (loader.isLoaded() || loader.load()) {
703 m_d->m_registeredPlugins += plugin;
704 QDesignerPluginManagerPrivate::FailedPluginMap::iterator fit = m_d->m_failedPlugins.find(plugin);
705 if (fit != m_d->m_failedPlugins.end())
706 m_d->m_failedPlugins.erase(fit);
707 return;
708 }
709
710 const QString errorMessage = loader.errorString();
711 m_d->m_failedPlugins.insert(plugin, errorMessage);
712}
713
714
715
716bool QDesignerPluginManager::syncSettings()
717{
718 QSettings settings(qApp->organizationName(), QDesignerQSettings::settingsApplicationName());
719 settings.beginGroup(QLatin1String("PluginManager"));
720 settings.setValue(QLatin1String("DisabledPlugins"), m_d->m_disabledPlugins);
721 settings.endGroup();
722 return settings.status() == QSettings::NoError;
723}
724
725void QDesignerPluginManager::ensureInitialized()
726{
727 if (debugPluginManager)
728 qDebug() << Q_FUNC_INFO << m_d->m_initialized << m_d->m_customWidgets.size();
729
730 if (m_d->m_initialized)
731 return;
732
733 const QString designerLanguage = getDesignerLanguage(m_d->m_core);
734
735 m_d->clearCustomWidgets();
736 // Add the static custom widgets
737 const QObjectList staticPluginObjects = QPluginLoader::staticInstances();
738 if (!staticPluginObjects.empty()) {
739 const QString staticPluginPath = QCoreApplication::applicationFilePath();
740 foreach(QObject *o, staticPluginObjects)
741 m_d->addCustomWidgets(o, staticPluginPath, designerLanguage);
742 }
743 foreach (const QString &plugin, m_d->m_registeredPlugins)
744 if (QObject *o = instance(plugin))
745 m_d->addCustomWidgets(o, plugin, designerLanguage);
746
747 m_d->m_initialized = true;
748}
749
750QDesignerPluginManager::CustomWidgetList QDesignerPluginManager::registeredCustomWidgets() const
751{
752 const_cast<QDesignerPluginManager*>(this)->ensureInitialized();
753 return m_d->m_customWidgets;
754}
755
756QDesignerCustomWidgetData QDesignerPluginManager::customWidgetData(QDesignerCustomWidgetInterface *w) const
757{
758 const int index = m_d->m_customWidgets.indexOf(w);
759 if (index == -1)
760 return QDesignerCustomWidgetData();
761 return m_d->m_customWidgetData.at(index);
762}
763
764QDesignerCustomWidgetData QDesignerPluginManager::customWidgetData(const QString &name) const
765{
766 const int count = m_d->m_customWidgets.size();
767 for (int i = 0; i < count; i++)
768 if (m_d->m_customWidgets.at(i)->name() == name)
769 return m_d->m_customWidgetData.at(i);
770 return QDesignerCustomWidgetData();
771}
772
773QObjectList QDesignerPluginManager::instances() const
774{
775 QStringList plugins = registeredPlugins();
776
777 QObjectList lst;
778 foreach (const QString &plugin, plugins) {
779 if (QObject *o = instance(plugin))
780 lst.append(o);
781 }
782
783 return lst;
784}
785
786QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.