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, QVariant::fromValue(strVal));
473 anyTrs = trEnabled;
474 }
475 if (p->elementString()->text() != text)
476 o->setProperty(name, 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 \sa createWidget(), errorString()
700*/
701QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget)
702{
703 Q_D(QUiLoader);
704 // QXmlStreamReader will report errors on open failure.
705 if (!device->isOpen())
706 device->open(QIODevice::ReadOnly|QIODevice::Text);
707 return d->builder.load(device, parentWidget);
708}
709
710/*!
711 Returns a list naming the paths in which the loader will search when
712 locating custom widget plugins.
713
714 \sa addPluginPath(), clearPluginPaths()
715*/
716QStringList QUiLoader::pluginPaths() const
717{
718 Q_D(const QUiLoader);
719 return d->builder.pluginPaths();
720}
721
722/*!
723 Clears the list of paths in which the loader will search when locating
724 plugins.
725
726 \sa addPluginPath(), pluginPaths()
727*/
728void QUiLoader::clearPluginPaths()
729{
730 Q_D(QUiLoader);
731 d->builder.clearPluginPaths();
732}
733
734/*!
735 Adds the given \a path to the list of paths in which the loader will search
736 when locating plugins.
737
738 \sa pluginPaths(), clearPluginPaths()
739*/
740void QUiLoader::addPluginPath(const QString &path)
741{
742 Q_D(QUiLoader);
743 d->builder.addPluginPath(path);
744}
745
746/*!
747 Creates a new widget with the given \a parent and \a name using the class
748 specified by \a className. You can use this function to create any of the
749 widgets returned by the availableWidgets() function.
750
751 The function is also used internally by the QUiLoader class whenever it
752 creates a widget. Hence, you can subclass QUiLoader and reimplement this
753 function to intervene process of constructing a user interface or widget.
754 However, in your implementation, ensure that you call QUiLoader's version
755 first.
756
757 \sa availableWidgets(), load()
758*/
759QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name)
760{
761 Q_D(QUiLoader);
762 return d->builder.defaultCreateWidget(className, parent, name);
763}
764
765/*!
766 Creates a new layout with the given \a parent and \a name using the class
767 specified by \a className.
768
769 The function is also used internally by the QUiLoader class whenever it
770 creates a widget. Hence, you can subclass QUiLoader and reimplement this
771 function to intervene process of constructing a user interface or widget.
772 However, in your implementation, ensure that you call QUiLoader's version
773 first.
774
775 \sa createWidget(), load()
776*/
777QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name)
778{
779 Q_D(QUiLoader);
780 return d->builder.defaultCreateLayout(className, parent, name);
781}
782
783/*!
784 Creates a new action group with the given \a parent and \a name.
785
786 The function is also used internally by the QUiLoader class whenever it
787 creates a widget. Hence, you can subclass QUiLoader and reimplement this
788 function to intervene process of constructing a user interface or widget.
789 However, in your implementation, ensure that you call QUiLoader's version
790 first.
791
792 \sa createAction(), createWidget(), load()
793 */
794QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name)
795{
796 Q_D(QUiLoader);
797 return d->builder.defaultCreateActionGroup(parent, name);
798}
799
800/*!
801 Creates a new action with the given \a parent and \a name.
802
803 The function is also used internally by the QUiLoader class whenever it
804 creates a widget. Hence, you can subclass QUiLoader and reimplement this
805 function to intervene process of constructing a user interface or widget.
806 However, in your implementation, ensure that you call QUiLoader's version
807 first.
808
809 \sa createActionGroup(), createWidget(), load()
810*/
811QAction *QUiLoader::createAction(QObject *parent, const QString &name)
812{
813 Q_D(QUiLoader);
814 return d->builder.defaultCreateAction(parent, name);
815}
816
817/*!
818 Returns a list naming all available widgets that can be built using the
819 createWidget() function, i.e all the widgets specified within the given
820 plugin paths.
821
822 \sa pluginPaths(), createWidget()
823
824*/
825QStringList QUiLoader::availableWidgets() const
826{
827 Q_D(const QUiLoader);
828
829 d->setupWidgetMap();
830 widget_map available = *g_widgets();
831
832 const auto &customWidgets = d->builder.customWidgets();
833 for (QDesignerCustomWidgetInterface *plugin : customWidgets)
834 available.insert(plugin->name(), true);
835
836 return available.keys();
837}
838
839
840/*!
841 \since 4.5
842 Returns a list naming all available layouts that can be built using the
843 createLayout() function
844
845 \sa createLayout()
846*/
847
848QStringList QUiLoader::availableLayouts() const
849{
850 QStringList rc;
851#define DECLARE_WIDGET(a, b)
852#define DECLARE_LAYOUT(a, b) rc.push_back(QLatin1String(#a));
853
854#include "widgets.table"
855
856#undef DECLARE_WIDGET
857#undef DECLARE_LAYOUT
858 return rc;
859}
860
861/*!
862 Sets the working directory of the loader to \a dir. The loader will look
863 for other resources, such as icons and resource files, in paths relative to
864 this directory.
865
866 \sa workingDirectory()
867*/
868
869void QUiLoader::setWorkingDirectory(const QDir &dir)
870{
871 Q_D(QUiLoader);
872 d->builder.setWorkingDirectory(dir);
873}
874
875/*!
876 Returns the working directory of the loader.
877
878 \sa setWorkingDirectory()
879*/
880
881QDir QUiLoader::workingDirectory() const
882{
883 Q_D(const QUiLoader);
884 return d->builder.workingDirectory();
885}
886/*!
887 \since 4.5
888
889 If \a enabled is true, user interfaces loaded by this loader will
890 automatically retranslate themselves upon receiving a language change
891 event. Otherwise, the user interfaces will not be retranslated.
892
893 \sa isLanguageChangeEnabled()
894*/
895
896void QUiLoader::setLanguageChangeEnabled(bool enabled)
897{
898 Q_D(QUiLoader);
899 d->builder.dynamicTr = enabled;
900}
901
902/*!
903 \since 4.5
904
905 Returns true if dynamic retranslation on language change is enabled;
906 returns false otherwise.
907
908 \sa setLanguageChangeEnabled()
909*/
910
911bool QUiLoader::isLanguageChangeEnabled() const
912{
913 Q_D(const QUiLoader);
914 return d->builder.dynamicTr;
915}
916
917/*!
918 \internal
919 \since 4.5
920
921 If \a enabled is true, user interfaces loaded by this loader will be
922 translated. Otherwise, the user interfaces will not be translated.
923
924 \note This is orthogonal to languageChangeEnabled.
925
926 \sa isLanguageChangeEnabled(), setLanguageChangeEnabled()
927*/
928
929void QUiLoader::setTranslationEnabled(bool enabled)
930{
931 Q_D(QUiLoader);
932 d->builder.trEnabled = enabled;
933}
934
935/*!
936 \internal
937 \since 4.5
938
939 Returns true if translation is enabled; returns false otherwise.
940
941 \sa setTranslationEnabled()
942*/
943
944bool QUiLoader::isTranslationEnabled() const
945{
946 Q_D(const QUiLoader);
947 return d->builder.trEnabled;
948}
949
950/*!
951 Returns a human-readable description of the last error occurred in load().
952
953 \since 5.0
954 \sa load()
955*/
956
957QString QUiLoader::errorString() const
958{
959 Q_D(const QUiLoader);
960 return d->builder.errorString();
961}
962
963QT_END_NAMESPACE
964
965#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:431
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:4009
QDataStream & operator>>(QDataStream &stream, QImage &image)
Definition qimage.cpp:4035