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