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