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
quiloader.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4
5#include "quiloader.h"
6#include "quiloader_p.h"
7
8#include <QtUiPlugin/customwidget.h>
9
10#include <formbuilder.h>
11#include <formbuilderextra_p.h>
12#include <objectutils_p.h>
13#include <textbuilder_p.h>
14#include <ui4_p.h>
15
16#include <QtWidgets/qapplication.h>
17#include <QtWidgets/qlayout.h>
18#include <QtWidgets/qwidget.h>
19#if QT_CONFIG(tabwidget)
20# include <QtWidgets/qtabwidget.h>
21#endif
22#if QT_CONFIG(treewidget)
23# include <QtWidgets/qtreewidget.h>
24#endif
25#if QT_CONFIG(listwidget)
26# include <QtWidgets/qlistwidget.h>
27#endif
28#if QT_CONFIG(tablewidget)
29# include <QtWidgets/qtablewidget.h>
30#endif
31#if QT_CONFIG(toolbox)
32# include <QtWidgets/qtoolbox.h>
33#endif
34#if QT_CONFIG(combobox)
35# include <QtWidgets/qcombobox.h>
36#endif
37
38#include <QtGui/qaction.h>
39#include <QtGui/qactiongroup.h>
40
41#include <QtCore/qdebug.h>
42#include <QtCore/qdatastream.h>
43#include <QtCore/qmap.h>
44#include <QtCore/qdir.h>
45#include <QtCore/qlibraryinfo.h>
46
47#include <algorithm>
48
49QT_BEGIN_NAMESPACE
50
51using widget_map = QMap<QString, bool>;
53
54class QUiLoader;
56
57#ifndef QT_NO_DATASTREAM
58// QUiTranslatableStringValue must be streamable since they become part of the QVariant-based
59// mime data when dragging items in views with QAbstractItemView::InternalMove.
60QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s)
61{
62 out << s.qualifier() << s.value();
63 return out;
64}
65
66QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s)
67{
68 QByteArray qualifier, value;
69 in >> qualifier >> value;
70 s.setQualifier(qualifier);
71 s.setValue(value);
72 return in;
73}
74#endif // QT_NO_DATASTREAM
75
76QString QUiTranslatableStringValue::translate(const QByteArray &className, bool idBased) const
77{
78 return idBased
79 ? qtTrId(m_qualifier.constData())
80 : QCoreApplication::translate(className.constData(), m_value.constData(), m_qualifier.constData());
81}
82
83#ifdef QFORMINTERNAL_NAMESPACE
84namespace QFormInternal
85{
86#endif
87
89{
90public:
91 explicit TranslatingTextBuilder(bool idBased, bool trEnabled, const QByteArray &className) :
92 m_idBased(idBased), m_trEnabled(trEnabled), m_className(className) {}
93
94 QVariant loadText(const DomProperty *icon) const override;
95
96 QVariant toNativeValue(const QVariant &value) const override;
97
98 bool idBased() const { return m_idBased; }
99
100private:
101 bool m_idBased;
102 bool m_trEnabled;
103 QByteArray m_className;
104};
105
106QVariant TranslatingTextBuilder::loadText(const DomProperty *text) const
107{
108 const DomString *str = text->elementString();
109 if (!str)
110 return {};
111 if (str->hasAttributeNotr()) {
112 const QString notr = str->attributeNotr();
113 if (notr == QStringLiteral("true") || notr == QStringLiteral("yes"))
114 return QVariant::fromValue(str->text());
115 }
117 strVal.setValue(str->text().toUtf8());
118 if (m_idBased)
119 strVal.setQualifier(str->attributeId().toUtf8());
120 else if (str->hasAttributeComment())
121 strVal.setQualifier(str->attributeComment().toUtf8());
122 return QVariant::fromValue(strVal);
123}
124
125QVariant TranslatingTextBuilder::toNativeValue(const QVariant &value) const
126{
127 if (value.canConvert<QUiTranslatableStringValue>()) {
128 auto tsv = qvariant_cast<QUiTranslatableStringValue>(value);
129 if (!m_trEnabled)
130 return QString::fromUtf8(tsv.value().constData());
131 return QVariant::fromValue(tsv.translate(m_className, m_idBased));
132 }
133 if (value.canConvert<QString>())
134 return QVariant::fromValue(qvariant_cast<QString>(value));
135 return value;
136}
137
138// This is "exported" to linguist
140 { Qt::DisplayRole, Qt::DisplayPropertyRole },
141#if QT_CONFIG(tooltip)
142 { Qt::ToolTipRole, Qt::ToolTipPropertyRole },
143#endif
144#if QT_CONFIG(statustip)
145 { Qt::StatusTipRole, Qt::StatusTipPropertyRole },
146#endif
147#if QT_CONFIG(whatsthis)
148 { Qt::WhatsThisRole, Qt::WhatsThisPropertyRole },
149#endif
150 { -1 , -1 }
151};
152
153#if QT_CONFIG(treewidget)
154static void recursiveReTranslate(QTreeWidgetItem *item, const QByteArray &class_name, bool idBased)
155{
156 const QUiItemRolePair *irs = qUiItemRoles;
157
158 int cnt = item->columnCount();
159 for (int i = 0; i < cnt; ++i) {
160 for (unsigned j = 0; irs[j].shadowRole >= 0; j++) {
161 QVariant v = item->data(i, irs[j].shadowRole);
162 if (v.isValid()) {
163 auto tsv = qvariant_cast<QUiTranslatableStringValue>(v);
164 item->setData(i, irs[j].realRole, tsv.translate(class_name, idBased));
165 }
166 }
167 }
168
169 cnt = item->childCount();
170 for (int i = 0; i < cnt; ++i)
171 recursiveReTranslate(item->child(i), class_name, idBased);
172}
173#endif
174
175template<typename T>
176static void reTranslateWidgetItem(T *item, const QByteArray &class_name, bool idBased)
177{
178 const QUiItemRolePair *irs = qUiItemRoles;
179
180 for (unsigned j = 0; irs[j].shadowRole >= 0; j++) {
181 QVariant v = item->data(irs[j].shadowRole);
182 if (v.isValid()) {
183 auto tsv = qvariant_cast<QUiTranslatableStringValue>(v);
184 item->setData(irs[j].realRole, tsv.translate(class_name, idBased));
185 }
186 }
187}
188
189#if QT_CONFIG(tablewidget)
190static void reTranslateTableItem(QTableWidgetItem *item, const QByteArray &class_name, bool idBased)
191{
192 if (item)
193 reTranslateWidgetItem(item, class_name, idBased);
194}
195#endif
196
198{
200
201public:
208
210 {
211 if (event->type() == QEvent::LanguageChange) {
213 for (const QByteArray &prop : dynamicPropertyNames) {
215 const QByteArray propName = prop.mid(sizeof(PROP_GENERIC_PREFIX) - 1);
216 const auto tsv =
219 }
220 }
221 if (0) {
222#if QT_CONFIG(tabwidget)
223 } else if (auto *tabw = qobject_cast<QTabWidget*>(o)) {
224 const int cnt = tabw->count();
225 for (int i = 0; i < cnt; ++i) {
227#if QT_CONFIG(tooltip)
229# endif
230#if QT_CONFIG(whatsthis)
232# endif
233 }
234#endif
235#if QT_CONFIG(listwidget)
236 } else if (auto *listw = qobject_cast<QListWidget*>(o)) {
237 const int cnt = listw->count();
238 for (int i = 0; i < cnt; ++i)
240#endif
241#if QT_CONFIG(treewidget)
242 } else if (auto *treew = qobject_cast<QTreeWidget*>(o)) {
245 const int cnt = treew->topLevelItemCount();
246 for (int i = 0; i < cnt; ++i) {
249 }
250#endif
251#if QT_CONFIG(tablewidget)
252 } else if (auto *tablew = qobject_cast<QTableWidget*>(o)) {
253 const int row_cnt = tablew->rowCount();
254 const int col_cnt = tablew->columnCount();
255 for (int j = 0; j < col_cnt; ++j)
257 for (int i = 0; i < row_cnt; ++i) {
259 for (int j = 0; j < col_cnt; ++j)
261 }
262#endif
263#if QT_CONFIG(combobox)
264 } else if (auto *combow = qobject_cast<QComboBox*>(o)) {
266 const int cnt = combow->count();
267 for (int i = 0; i < cnt; ++i) {
269 if (v.isValid()) {
272 }
273 }
274 }
275#endif
276#if QT_CONFIG(toolbox)
277 } else if (auto *toolw = qobject_cast<QToolBox*>(o)) {
278 const int cnt = toolw->count();
279 for (int i = 0; i < cnt; ++i) {
281#if QT_CONFIG(tooltip)
283# endif
284 }
285#endif
286 }
287 }
288 return false;
289 }
290
291 template <class Widget>
293 void (Widget::*setter)(int, const QString &),
294 int i,
295 const char *propName) const
296 {
298 if (v.isValid()) {
301 }
302 }
303
304private:
306 bool m_idBased;
307};
308
310{
314
315public:
316 QUiLoader *loader = nullptr;
317
318 bool dynamicTr = false;
319 bool trEnabled = true;
320
322
323 QWidget *defaultCreateWidget(const QString &className, QWidget *parent, const QString &name)
324 {
325 return ParentClass::createWidget(className, parent, name);
326 }
327
328 QLayout *defaultCreateLayout(const QString &className, QObject *parent, const QString &name)
329 {
330 return ParentClass::createLayout(className, parent, name);
331 }
332
333 QAction *defaultCreateAction(QObject *parent, const QString &name)
334 {
335 return ParentClass::createAction(parent, name);
336 }
337
338 QActionGroup *defaultCreateActionGroup(QObject *parent, const QString &name)
339 {
340 return ParentClass::createActionGroup(parent, name);
341 }
342
343 QWidget *createWidget(const QString &className, QWidget *parent, const QString &name) override
344 {
345 if (QWidget *widget = loader->createWidget(className, parent, name)) {
346 widget->setObjectName(name);
347 return widget;
348 }
349
350 return nullptr;
351 }
352
353 QLayout *createLayout(const QString &className, QObject *parent, const QString &name) override
354 {
355 if (QLayout *layout = loader->createLayout(className, parent, name)) {
356 layout->setObjectName(name);
357 return layout;
358 }
359
360 return nullptr;
361 }
362
363 QActionGroup *createActionGroup(QObject *parent, const QString &name) override
364 {
365 if (QActionGroup *actionGroup = loader->createActionGroup(parent, name)) {
366 actionGroup->setObjectName(name);
367 return actionGroup;
368 }
369
370 return nullptr;
371 }
372
373 QAction *createAction(QObject *parent, const QString &name) override
374 {
375 if (QAction *action = loader->createAction(parent, name)) {
376 action->setObjectName(name);
377 return action;
378 }
379
380 return nullptr;
381 }
382
383 void applyProperties(QObject *o, const QList<DomProperty*> &properties) override;
384 QWidget *create(DomUI *ui, QWidget *parentWidget) override;
385 QWidget *create(DomWidget *ui_widget, QWidget *parentWidget) override;
386 bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) override;
387
388 template <class Widget>
389 void translateSubwidgetProperty(const QList<DomProperty*> &attributes,
390 Widget *mainWidget,
391 const QString &attribute,
392 int i,
393 void (Widget::*setter)(int, const QString &),
394 const char *propName) const;
395
396private:
397 QByteArray m_class;
398 TranslationWatcher *m_trwatch = nullptr;
399 bool m_idBased = false;
400};
401
402static QString convertTranslatable(const DomProperty *p, const QByteArray &className,
403 bool idBased, QUiTranslatableStringValue *strVal)
404{
405 if (p->kind() != DomProperty::String)
406 return {};
407 const DomString *dom_str = p->elementString();
408 if (!dom_str)
409 return {};
410 if (dom_str->hasAttributeNotr()) {
411 const QString notr = dom_str->attributeNotr();
412 if (notr == QStringLiteral("yes") || notr == QStringLiteral("true"))
413 return {};
414 }
415 strVal->setValue(dom_str->text().toUtf8());
416 strVal->setQualifier(idBased ? dom_str->attributeId().toUtf8() : dom_str->attributeComment().toUtf8());
417 if (strVal->value().isEmpty() && strVal->qualifier().isEmpty())
418 return {};
419 return strVal->translate(className, idBased);
420}
421
422static DomProperty *attributeByName(const QList<DomProperty*> &attributes,
423 const QString &attribute)
424{
425 auto pred = [&attribute](const DomProperty *prop) {
426 return prop->attributeName() == attribute;
427 };
428 auto it = std::find_if(attributes.cbegin(), attributes.cend(), pred);
429 return it != attributes.cend() ? *it : nullptr;
430}
431
432template <class Widget>
433void FormBuilderPrivate::translateSubwidgetProperty(const QList<DomProperty*> &attributes,
434 Widget *mainWidget,
435 const QString &attribute,
436 int i,
437 void (Widget::*setter)(int, const QString &),
438 const char *propName) const
439{
440 if (const auto *p = attributeByName(attributes, attribute)) {
442 const QString text = convertTranslatable(p, m_class, m_idBased, &strVal);
443 if (!text.isEmpty()) {
444 if (dynamicTr)
445 mainWidget->widget(i)->setProperty(propName, QVariant::fromValue(strVal));
446 (mainWidget->*setter)(i, text);
447 }
448 }
449}
450
451void FormBuilderPrivate::applyProperties(QObject *o, const QList<DomProperty*> &properties)
452{
453 QFormBuilder::applyProperties(o, properties);
454
455 if (!m_trwatch)
456 m_trwatch = new TranslationWatcher(o, m_class, m_idBased);
457
458 if (properties.isEmpty())
459 return;
460
461 // Unlike string item roles, string properties are not loaded via the textBuilder
462 // (as they are "shadowed" by the property sheets in designer). So do the initial
463 // translation here.
464 bool anyTrs = false;
465 for (const DomProperty *p : properties) {
466 QUiTranslatableStringValue strVal;
467 const QString text = convertTranslatable(p, m_class, m_idBased, &strVal);
468 if (text.isEmpty())
469 continue;
470 const QByteArray name = p->attributeName().toUtf8();
471 if (dynamicTr) {
472 const QByteArray dynname = QByteArray(PROP_GENERIC_PREFIX + name);
473 o->setProperty(dynname.constData(), QVariant::fromValue(strVal));
474 anyTrs = trEnabled;
475 }
476 if (p->elementString()->text() != text)
477 o->setProperty(name.constData(), text);
478 }
479 if (anyTrs)
480 o->installEventFilter(m_trwatch);
481}
482
483QWidget *FormBuilderPrivate::create(DomUI *ui, QWidget *parentWidget)
484{
485 m_class = ui->elementClass().toUtf8();
486 m_trwatch = nullptr;
487 m_idBased = ui->attributeIdbasedtr();
488 setTextBuilder(new TranslatingTextBuilder(m_idBased, trEnabled, m_class));
489 return QFormBuilder::create(ui, parentWidget);
490}
491
492QWidget *FormBuilderPrivate::create(DomWidget *ui_widget, QWidget *parentWidget)
493{
494 QWidget *w = QFormBuilder::create(ui_widget, parentWidget);
495 if (w == nullptr)
496 return nullptr;
497
498 if (0) {
499#if QT_CONFIG(tabwidget)
500 } else if (qobject_cast<QTabWidget*>(w)) {
501#endif
502#if QT_CONFIG(listwidget)
503 } else if (qobject_cast<QListWidget*>(w)) {
504#endif
505#if QT_CONFIG(treewidget)
506 } else if (qobject_cast<QTreeWidget*>(w)) {
507#endif
508#if QT_CONFIG(tablewidget)
509 } else if (qobject_cast<QTableWidget*>(w)) {
510#endif
511#if QT_CONFIG(combobox)
512 } else if (qobject_cast<QComboBox*>(w)) {
513 if (QFormBuilderExtra::isQFontComboBox(w))
514 return w;
515#endif
516#if QT_CONFIG(toolbox)
517 } else if (qobject_cast<QToolBox*>(w)) {
518#endif
519 } else {
520 return w;
521 }
522 if (dynamicTr && trEnabled)
523 w->installEventFilter(m_trwatch);
524 return w;
525}
526
527bool FormBuilderPrivate::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
528{
529 if (parentWidget == nullptr)
530 return true;
531
532 if (!ParentClass::addItem(ui_widget, widget, parentWidget))
533 return false;
534
535 // Check special cases. First: Custom container
536 const QString className = QLatin1String(parentWidget->metaObject()->className());
537 if (!d->customWidgetAddPageMethod(className).isEmpty())
538 return true;
539
540 if (0) {
541#if QT_CONFIG(tabwidget)
542 } else if (auto *tabWidget = qobject_cast<QTabWidget*>(parentWidget)) {
543 const int i = tabWidget->count() - 1;
544 translateSubwidgetProperty(ui_widget->elementAttribute(), tabWidget,
545 QFormBuilderStrings::titleAttribute,
546 i, &QTabWidget::setTabText, PROP_TABPAGETEXT);
547#if QT_CONFIG(tooltip)
548 translateSubwidgetProperty(ui_widget->elementAttribute(), tabWidget,
549 QFormBuilderStrings::toolTipAttribute,
550 i, &QTabWidget::setTabToolTip, PROP_TABPAGETOOLTIP);
551# endif
552#if QT_CONFIG(whatsthis)
553 translateSubwidgetProperty(ui_widget->elementAttribute(), tabWidget,
554 QFormBuilderStrings::whatsThisAttribute,
555 i, &QTabWidget::setTabWhatsThis, PROP_TABPAGEWHATSTHIS);
556# endif
557#endif
558#if QT_CONFIG(toolbox)
559 } else if (auto *toolBox = qobject_cast<QToolBox*>(parentWidget)) {
560 const int i = toolBox->count() - 1;
561 translateSubwidgetProperty(ui_widget->elementAttribute(), toolBox,
562 QFormBuilderStrings::labelAttribute,
563 i, &QToolBox::setItemText, PROP_TOOLITEMTEXT);
564#if QT_CONFIG(tooltip)
565 translateSubwidgetProperty(ui_widget->elementAttribute(), toolBox,
566 QFormBuilderStrings::toolTipAttribute,
567 i, &QToolBox::setItemToolTip, PROP_TOOLITEMTOOLTIP);
568# endif
569#endif
570 }
571
572 return true;
573}
574
575#ifdef QFORMINTERNAL_NAMESPACE
576}
577#endif
578
580{
581public:
582#ifdef QFORMINTERNAL_NAMESPACE
584#else
586#endif
587
588 void setupWidgetMap() const;
589};
590
592{
593 if (!g_widgets()->isEmpty())
594 return;
595
596#ifdef QFORMINTERNAL_NAMESPACE
597 const QStringList names = QFormInternal::widgetNames();
598#else
599 const QStringList names = widgetNames();
600#endif
601 for (const QString &name : names)
602 g_widgets()->insert(name, true);
603}
604
605/*!
606 \class QUiLoader
607 \inmodule QtUiTools
608
609 \brief Loads and instantiates \QD forms at runtime.
610
611 Use QUiLoader to dynamically create QWidget-based user interfaces
612 based on the information stored in UI files (created with \QD).
613
614 The \l load() function reads the content of a UI file, instantiates
615 the widgets described in the file, and returns a pointer to the
616 top-level \l QWidget. This widget can then be shown:
617
618 \snippet quiloader/mywidget.cpp 0
619
620 If the instantiation fails, the function returns
621 a \c nullptr; use the \l errorString() function to retrieve a human-readable
622 description of the error that occurred.
623
624 \section2 Loading forms with custom widgets
625
626 If the UI file contains custom widgets implemented in a \QD plugin, loading
627 will fail by default. To work around this, you can subclass \l QUiLoader and
628 override the \l createWidget() function. If this is not possible, you can also
629 let the module load \QD plugins by adding their locations via
630 \l addPluginPath() or the \c QT_PLUGIN_PATH environment variable.
631 See the \l{Creating Custom Widgets for Qt Widgets Designer}
632 page for more details.
633
634 \section2 Loading a particular widget from a UI file
635
636 You can load a specific widget from a UI file, instead of a
637 complete UI file. Use the \l availableWidgets() function to
638 retrieve the names of the available widgets, and the
639 \l createWidget() function to instantiate a specific one. For example:
640
641 \snippet quiloader/main.cpp 0
642
643 \section2 Customizing the widget creation
644
645 The \l createAction(), \l createActionGroup(), \l createLayout(), and
646 \l createWidget() functions are used internally by the QUiLoader class whenever
647 it has to create an action, action group, layout, or widget respectively.
648 You can subclass QUiLoader and reimplement these functions to
649 customize the UI creation workflow. For example, you
650 might want to have a list of the actions created when loading a form or
651 creating a custom widget.
652
653 \section2 Example
654
655 For a complete example using the QUiLoader class, see the
656 \l{Calculator Builder}.
657
658 \sa {Qt UI Tools}, QFormBuilder
659*/
660
661/*!
662 Creates a form loader with the given \a parent.
663*/
664QUiLoader::QUiLoader(QObject *parent)
665 : QObject(parent), d_ptr(new QUiLoaderPrivate)
666{
667 Q_D(QUiLoader);
668
669#ifndef QT_NO_DATASTREAM
670 static int metaTypeId = 0;
671 if (!metaTypeId) {
672 metaTypeId = qRegisterMetaType<QUiTranslatableStringValue>("QUiTranslatableStringValue");
673 }
674#endif // QT_NO_DATASTREAM
675 d->builder.loader = this;
676
677#if QT_CONFIG(library)
678 QStringList paths;
679 const QStringList &libraryPaths = QApplication::libraryPaths();
680 for (const QString &path : libraryPaths) {
681 QString libPath = path;
682 libPath += QDir::separator();
683 libPath += QStringLiteral("designer");
684 paths.append(libPath);
685 }
686
687 d->builder.setPluginPath(paths);
688#endif // QT_CONFIG(library)
689}
690
691/*!
692 Destroys the loader.
693*/
694QUiLoader::~QUiLoader() = default;
695
696/*!
697 Instantiates a form from the given \a device. Returns a new QWidget with the
698 given \a parentWidget if successful. Returns \c nullptr otherwise.
699
700 \warning
701 \include security_considerations.qdocinc
702
703 \sa createWidget(), errorString()
704*/
705QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget)
706{
707 Q_D(QUiLoader);
708 // QXmlStreamReader will report errors on open failure.
709 if (!device->isOpen())
710 device->open(QIODevice::ReadOnly|QIODevice::Text);
711 return d->builder.load(device, parentWidget);
712}
713
714/*!
715 Returns a list naming the paths in which the loader will search when
716 locating custom widget plugins.
717
718 \sa addPluginPath(), clearPluginPaths()
719*/
720QStringList QUiLoader::pluginPaths() const
721{
722 Q_D(const QUiLoader);
723 return d->builder.pluginPaths();
724}
725
726/*!
727 Clears the list of paths in which the loader will search when locating
728 plugins.
729
730 \sa addPluginPath(), pluginPaths()
731*/
732void QUiLoader::clearPluginPaths()
733{
734 Q_D(QUiLoader);
735 d->builder.clearPluginPaths();
736}
737
738/*!
739 Adds the given \a path to the list of paths in which the loader will search
740 when locating plugins.
741
742 \warning Only set paths that you trust. Allowing untrusted users to create
743 or add content in a specified path may lead to security vulnerabilities.
744
745 \sa pluginPaths(), clearPluginPaths()
746*/
747void QUiLoader::addPluginPath(const QString &path)
748{
749 Q_D(QUiLoader);
750 d->builder.addPluginPath(path);
751}
752
753/*!
754 Creates a new widget with the given \a parent and \a name using the class
755 specified by \a className. You can use this function to create any of the
756 widgets returned by the availableWidgets() function.
757
758 The function is also used internally by the QUiLoader class whenever it
759 creates a widget. Therefore, you can subclass QUiLoader and reimplement this
760 function to intervene in the process of constructing a user interface or widget.
761 However, in your implementation, ensure that you call QUiLoader's version
762 first.
763
764 \sa availableWidgets(), load()
765*/
766QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name)
767{
768 Q_D(QUiLoader);
769 return d->builder.defaultCreateWidget(className, parent, name);
770}
771
772/*!
773 Creates a new layout with the given \a parent and \a name using the class
774 specified by \a className.
775
776 The function is also used internally by the QUiLoader class whenever it
777 creates a layout. Therefore, you can subclass QUiLoader and reimplement this
778 function to intervene in the process of constructing a user interface or widget.
779 However, in your implementation, ensure that you call QUiLoader's version
780 first.
781
782 \sa createWidget(), load()
783*/
784QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name)
785{
786 Q_D(QUiLoader);
787 return d->builder.defaultCreateLayout(className, parent, name);
788}
789
790/*!
791 Creates a new action group with the given \a parent and \a name.
792
793 The function is also used internally by the QUiLoader class whenever it
794 creates an action group. Therefore, you can subclass QUiLoader and reimplement
795 this function to intervene in the process of constructing a user interface or
796 widget. However, in your implementation, ensure that you call QUiLoader's
797 version first.
798
799 \sa createAction(), createWidget(), load()
800 */
801QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name)
802{
803 Q_D(QUiLoader);
804 return d->builder.defaultCreateActionGroup(parent, name);
805}
806
807/*!
808 Creates a new action with the given \a parent and \a name.
809
810 The function is also used internally by the QUiLoader class whenever it
811 creates an action. Therefore, you can subclass QUiLoader and reimplement this
812 function to intervene in the process of constructing a user interface or widget.
813 However, in your implementation, ensure that you call QUiLoader's version
814 first.
815
816 \sa createActionGroup(), createWidget(), load()
817*/
818QAction *QUiLoader::createAction(QObject *parent, const QString &name)
819{
820 Q_D(QUiLoader);
821 return d->builder.defaultCreateAction(parent, name);
822}
823
824/*!
825 Returns a list of all available widgets that can be built using the
826 createWidget() function, that is, all the widgets specified within the given
827 plugin paths.
828
829 \sa pluginPaths(), createWidget()
830
831*/
832QStringList QUiLoader::availableWidgets() const
833{
834 Q_D(const QUiLoader);
835
836 d->setupWidgetMap();
837 widget_map available = *g_widgets();
838
839 const auto &customWidgets = d->builder.customWidgets();
840 for (QDesignerCustomWidgetInterface *plugin : customWidgets)
841 available.insert(plugin->name(), true);
842
843 return available.keys();
844}
845
846
847/*!
848 \since 4.5
849 Returns a list of all available layouts that can be built using the
850 createLayout() function.
851
852 \sa createLayout()
853*/
854
855QStringList QUiLoader::availableLayouts() const
856{
857#ifdef QFORMINTERNAL_NAMESPACE
858 return QFormInternal::layoutNames();
859#else
860 return layoutNames();
861#endif
862}
863
864/*!
865 Sets the working directory of the loader to \a dir. The loader will look
866 for other resources, such as icons and resource files, in paths relative to
867 this directory.
868
869 \warning Only set a directory that you trust. Allowing untrusted users to
870 create or add content in the working directory may lead to security
871 vulnerabilities.
872
873 \sa workingDirectory()
874*/
875
876void QUiLoader::setWorkingDirectory(const QDir &dir)
877{
878 Q_D(QUiLoader);
879 d->builder.setWorkingDirectory(dir);
880}
881
882/*!
883 Returns the working directory of the loader.
884
885 \sa setWorkingDirectory()
886*/
887
888QDir QUiLoader::workingDirectory() const
889{
890 Q_D(const QUiLoader);
891 return d->builder.workingDirectory();
892}
893/*!
894 \since 4.5
895
896 If \a enabled is true, user interfaces loaded by this loader will
897 automatically retranslate themselves upon receiving a language change
898 event. Otherwise, the user interfaces will not be retranslated.
899
900 \sa isLanguageChangeEnabled()
901*/
902
903void QUiLoader::setLanguageChangeEnabled(bool enabled)
904{
905 Q_D(QUiLoader);
906 d->builder.dynamicTr = enabled;
907}
908
909/*!
910 \since 4.5
911
912 Returns \c true if dynamic retranslation on language change is enabled;
913 returns \c false otherwise.
914
915 The default is \c false.
916
917 \sa setLanguageChangeEnabled()
918*/
919
920bool QUiLoader::isLanguageChangeEnabled() const
921{
922 Q_D(const QUiLoader);
923 return d->builder.dynamicTr;
924}
925
926/*!
927 \internal
928 \since 4.5
929
930 If \a enabled is true, user interfaces loaded by this loader will be
931 translated. Otherwise, the user interfaces will not be translated.
932
933 \note This is orthogonal to languageChangeEnabled.
934
935 \sa isLanguageChangeEnabled(), setLanguageChangeEnabled()
936*/
937
938void QUiLoader::setTranslationEnabled(bool enabled)
939{
940 Q_D(QUiLoader);
941 d->builder.trEnabled = enabled;
942}
943
944/*!
945 \internal
946 \since 4.5
947
948 Returns \c true if translation is enabled; returns \c false otherwise.
949
950 The default is \c true.
951
952 \sa setTranslationEnabled()
953*/
954
955bool QUiLoader::isTranslationEnabled() const
956{
957 Q_D(const QUiLoader);
958 return d->builder.trEnabled;
959}
960
961/*!
962 Returns a human-readable description of the last error that occurred in load().
963
964 \since 5.0
965 \sa load()
966*/
967
968QString QUiLoader::errorString() const
969{
970 Q_D(const QUiLoader);
971 return d->builder.errorString();
972}
973
974QT_END_NAMESPACE
975
976#include "quiloader.moc"
void applyProperties(QObject *o, const QList< DomProperty * > &properties) override
friend class QT_PREPEND_NAMESPACE(QUiLoader)
QLayout * defaultCreateLayout(const QString &className, QObject *parent, const QString &name)
QAction * createAction(QObject *parent, const QString &name) override
QLayout * createLayout(const QString &className, QObject *parent, const QString &name) override
FormBuilderPrivate()=default
QActionGroup * defaultCreateActionGroup(QObject *parent, const QString &name)
QActionGroup * createActionGroup(QObject *parent, const QString &name) override
void translateSubwidgetProperty(const QList< DomProperty * > &attributes, Widget *mainWidget, const QString &attribute, int i, void(Widget::*setter)(int, const QString &), const char *propName) const
QWidget * create(DomWidget *ui_widget, QWidget *parentWidget) override
QAction * defaultCreateAction(QObject *parent, const QString &name)
QWidget * create(DomUI *ui, QWidget *parentWidget) override
QUiLoader * loader
QWidget * defaultCreateWidget(const QString &className, QWidget *parent, const QString &name)
bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) override
QWidget * createWidget(const QString &className, QWidget *parent, const QString &name) override
Definition qlist.h:81
friend class QWidget
Definition qpainter.h:432
void setupWidgetMap() const
FormBuilderPrivate builder
QVariant toNativeValue(const QVariant &value) const override
QVariant loadText(const DomProperty *icon) const override
TranslatingTextBuilder(bool idBased, bool trEnabled, const QByteArray &className)
Definition quiloader.cpp:91
Q_GLOBAL_STATIC(QReadWriteLock, g_updateMutex)
#define QStringLiteral(str)
Definition qstring.h:1825
const QUiItemRolePair qUiItemRoles[]
static void reTranslateWidgetItem(T *item, const QByteArray &class_name, bool idBased)
static QString convertTranslatable(const DomProperty *p, const QByteArray &className, bool idBased, QUiTranslatableStringValue *strVal)
static DomProperty * attributeByName(const QList< DomProperty * > &attributes, const QString &attribute)
QDataStream & operator<<(QDataStream &stream, const QImage &image)
[0]
Definition qimage.cpp:4012
QDataStream & operator>>(QDataStream &stream, QImage &image)
Definition qimage.cpp:4038