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