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