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 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#ifdef QFORMINTERNAL_NAMESPACE
857 return QFormInternal::layoutNames();
858#else
859 return layoutNames();
860#endif
861}
862
863/*!
864 Sets the working directory of the loader to \a dir. The loader will look
865 for other resources, such as icons and resource files, in paths relative to
866 this directory.
867
868 \warning Only set a directory that you trust. Allowing untrusted users to
869 create or add content in the working directory may lead to security
870 vulnerabilities.
871
872 \sa workingDirectory()
873*/
874
875void QUiLoader::setWorkingDirectory(const QDir &dir)
876{
877 Q_D(QUiLoader);
878 d->builder.setWorkingDirectory(dir);
879}
880
881/*!
882 Returns the working directory of the loader.
883
884 \sa setWorkingDirectory()
885*/
886
887QDir QUiLoader::workingDirectory() const
888{
889 Q_D(const QUiLoader);
890 return d->builder.workingDirectory();
891}
892/*!
893 \since 4.5
894
895 If \a enabled is true, user interfaces loaded by this loader will
896 automatically retranslate themselves upon receiving a language change
897 event. Otherwise, the user interfaces will not be retranslated.
898
899 \sa isLanguageChangeEnabled()
900*/
901
902void QUiLoader::setLanguageChangeEnabled(bool enabled)
903{
904 Q_D(QUiLoader);
905 d->builder.dynamicTr = enabled;
906}
907
908/*!
909 \since 4.5
910
911 Returns true if dynamic retranslation on language change is enabled;
912 returns false otherwise.
913
914 \sa setLanguageChangeEnabled()
915*/
916
917bool QUiLoader::isLanguageChangeEnabled() const
918{
919 Q_D(const QUiLoader);
920 return d->builder.dynamicTr;
921}
922
923/*!
924 \internal
925 \since 4.5
926
927 If \a enabled is true, user interfaces loaded by this loader will be
928 translated. Otherwise, the user interfaces will not be translated.
929
930 \note This is orthogonal to languageChangeEnabled.
931
932 \sa isLanguageChangeEnabled(), setLanguageChangeEnabled()
933*/
934
935void QUiLoader::setTranslationEnabled(bool enabled)
936{
937 Q_D(QUiLoader);
938 d->builder.trEnabled = enabled;
939}
940
941/*!
942 \internal
943 \since 4.5
944
945 Returns true if translation is enabled; returns false otherwise.
946
947 \sa setTranslationEnabled()
948*/
949
950bool QUiLoader::isTranslationEnabled() const
951{
952 Q_D(const QUiLoader);
953 return d->builder.trEnabled;
954}
955
956/*!
957 Returns a human-readable description of the last error occurred in load().
958
959 \since 5.0
960 \sa load()
961*/
962
963QString QUiLoader::errorString() const
964{
965 Q_D(const QUiLoader);
966 return d->builder.errorString();
967}
968
969QT_END_NAMESPACE
970
971#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