summaryrefslogtreecommitdiffstats
path: root/src/uitools/quiloader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/uitools/quiloader.cpp')
-rw-r--r--src/uitools/quiloader.cpp917
1 files changed, 917 insertions, 0 deletions
diff --git a/src/uitools/quiloader.cpp b/src/uitools/quiloader.cpp
new file mode 100644
index 000000000..2621ace1c
--- /dev/null
+++ b/src/uitools/quiloader.cpp
@@ -0,0 +1,917 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+
+#include "quiloader.h"
+#include "quiloader_p.h"
+
+#include <QtUiPlugin/customwidget.h>
+
+#include <formbuilder.h>
+#include <formbuilderextra_p.h>
+#include <textbuilder_p.h>
+#include <ui4_p.h>
+
+#include <QtWidgets/qapplication.h>
+#include <QtWidgets/qlayout.h>
+#include <QtWidgets/qwidget.h>
+#include <QtWidgets/qtabwidget.h>
+#include <QtWidgets/qtreewidget.h>
+#include <QtWidgets/qlistwidget.h>
+#include <QtWidgets/qtablewidget.h>
+#include <QtWidgets/qtoolbox.h>
+#include <QtWidgets/qcombobox.h>
+#include <QtWidgets/qfontcombobox.h>
+
+#include <QtGui/qaction.h>
+#include <QtGui/qactiongroup.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qlibraryinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+typedef QMap<QString, bool> widget_map;
+Q_GLOBAL_STATIC(widget_map, g_widgets)
+
+class QUiLoader;
+class QUiLoaderPrivate;
+
+#ifndef QT_NO_DATASTREAM
+// QUiTranslatableStringValue must be streamable since they become part of the QVariant-based
+// mime data when dragging items in views with QAbstractItemView::InternalMove.
+QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s)
+{
+ out << s.qualifier() << s.value();
+ return out;
+}
+
+QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s)
+{
+ QByteArray qualifier, value;
+ in >> qualifier >> value;
+ s.setQualifier(qualifier);
+ s.setValue(value);
+ return in;
+}
+#endif // QT_NO_DATASTREAM
+
+QString QUiTranslatableStringValue::translate(const QByteArray &className, bool idBased) const
+{
+ return idBased
+ ? qtTrId(m_qualifier.constData())
+ : QCoreApplication::translate(className.constData(), m_value.constData(), m_qualifier.constData());
+}
+
+#ifdef QFORMINTERNAL_NAMESPACE
+namespace QFormInternal
+{
+#endif
+
+class TranslatingTextBuilder : public QTextBuilder
+{
+public:
+ explicit TranslatingTextBuilder(bool idBased, bool trEnabled, const QByteArray &className) :
+ m_idBased(idBased), m_trEnabled(trEnabled), m_className(className) {}
+
+ QVariant loadText(const DomProperty *icon) const override;
+
+ QVariant toNativeValue(const QVariant &value) const override;
+
+ bool idBased() const { return m_idBased; }
+
+private:
+ bool m_idBased;
+ bool m_trEnabled;
+ QByteArray m_className;
+};
+
+QVariant TranslatingTextBuilder::loadText(const DomProperty *text) const
+{
+ const DomString *str = text->elementString();
+ if (!str)
+ return QVariant();
+ if (str->hasAttributeNotr()) {
+ const QString notr = str->attributeNotr();
+ if (notr == QStringLiteral("true") || notr == QStringLiteral("yes"))
+ return QVariant::fromValue(str->text());
+ }
+ QUiTranslatableStringValue strVal;
+ strVal.setValue(str->text().toUtf8());
+ if (m_idBased)
+ strVal.setQualifier(str->attributeId().toUtf8());
+ else if (str->hasAttributeComment())
+ strVal.setQualifier(str->attributeComment().toUtf8());
+ return QVariant::fromValue(strVal);
+}
+
+QVariant TranslatingTextBuilder::toNativeValue(const QVariant &value) const
+{
+ if (value.canConvert<QUiTranslatableStringValue>()) {
+ QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(value);
+ if (!m_trEnabled)
+ return QString::fromUtf8(tsv.value().constData());
+ return QVariant::fromValue(tsv.translate(m_className, m_idBased));
+ }
+ if (value.canConvert<QString>())
+ return QVariant::fromValue(qvariant_cast<QString>(value));
+ return value;
+}
+
+// This is "exported" to linguist
+const QUiItemRolePair qUiItemRoles[] = {
+ { Qt::DisplayRole, Qt::DisplayPropertyRole },
+#if QT_CONFIG(tooltip)
+ { Qt::ToolTipRole, Qt::ToolTipPropertyRole },
+#endif
+#if QT_CONFIG(statustip)
+ { Qt::StatusTipRole, Qt::StatusTipPropertyRole },
+#endif
+#if QT_CONFIG(whatsthis)
+ { Qt::WhatsThisRole, Qt::WhatsThisPropertyRole },
+#endif
+ { -1 , -1 }
+};
+
+static void recursiveReTranslate(QTreeWidgetItem *item, const QByteArray &class_name, bool idBased)
+{
+ const QUiItemRolePair *irs = qUiItemRoles;
+
+ int cnt = item->columnCount();
+ for (int i = 0; i < cnt; ++i) {
+ for (unsigned j = 0; irs[j].shadowRole >= 0; j++) {
+ QVariant v = item->data(i, irs[j].shadowRole);
+ if (v.isValid()) {
+ QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v);
+ item->setData(i, irs[j].realRole, tsv.translate(class_name, idBased));
+ }
+ }
+ }
+
+ cnt = item->childCount();
+ for (int i = 0; i < cnt; ++i)
+ recursiveReTranslate(item->child(i), class_name, idBased);
+}
+
+template<typename T>
+static void reTranslateWidgetItem(T *item, const QByteArray &class_name, bool idBased)
+{
+ const QUiItemRolePair *irs = qUiItemRoles;
+
+ for (unsigned j = 0; irs[j].shadowRole >= 0; j++) {
+ QVariant v = item->data(irs[j].shadowRole);
+ if (v.isValid()) {
+ QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v);
+ item->setData(irs[j].realRole, tsv.translate(class_name, idBased));
+ }
+ }
+}
+
+static void reTranslateTableItem(QTableWidgetItem *item, const QByteArray &class_name, bool idBased)
+{
+ if (item)
+ reTranslateWidgetItem(item, class_name, idBased);
+}
+
+#define RETRANSLATE_SUBWIDGET_PROP(mainWidget, setter, propName) \
+ do { \
+ QVariant v = mainWidget->widget(i)->property(propName); \
+ if (v.isValid()) { \
+ QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v); \
+ mainWidget->setter(i, tsv.translate(m_className, m_idBased)); \
+ } \
+ } while (0)
+
+class TranslationWatcher: public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit TranslationWatcher(QObject *parent, const QByteArray &className, bool idBased):
+ QObject(parent),
+ m_className(className),
+ m_idBased(idBased)
+ {
+ }
+
+ bool eventFilter(QObject *o, QEvent *event) override
+ {
+ if (event->type() == QEvent::LanguageChange) {
+ const auto &dynamicPropertyNames = o->dynamicPropertyNames();
+ for (const QByteArray &prop : dynamicPropertyNames) {
+ if (prop.startsWith(PROP_GENERIC_PREFIX)) {
+ const QByteArray propName = prop.mid(sizeof(PROP_GENERIC_PREFIX) - 1);
+ const QUiTranslatableStringValue tsv =
+ qvariant_cast<QUiTranslatableStringValue>(o->property(prop));
+ o->setProperty(propName, tsv.translate(m_className, m_idBased));
+ }
+ }
+ if (0) {
+#if QT_CONFIG(tabwidget)
+ } else if (QTabWidget *tabw = qobject_cast<QTabWidget*>(o)) {
+ const int cnt = tabw->count();
+ for (int i = 0; i < cnt; ++i) {
+ RETRANSLATE_SUBWIDGET_PROP(tabw, setTabText, PROP_TABPAGETEXT);
+#if QT_CONFIG(tooltip)
+ RETRANSLATE_SUBWIDGET_PROP(tabw, setTabToolTip, PROP_TABPAGETOOLTIP);
+# endif
+#if QT_CONFIG(whatsthis)
+ RETRANSLATE_SUBWIDGET_PROP(tabw, setTabWhatsThis, PROP_TABPAGEWHATSTHIS);
+# endif
+ }
+#endif
+#if QT_CONFIG(listwidget)
+ } else if (QListWidget *listw = qobject_cast<QListWidget*>(o)) {
+ const int cnt = listw->count();
+ for (int i = 0; i < cnt; ++i)
+ reTranslateWidgetItem(listw->item(i), m_className, m_idBased);
+#endif
+#if QT_CONFIG(treewidget)
+ } else if (QTreeWidget *treew = qobject_cast<QTreeWidget*>(o)) {
+ if (QTreeWidgetItem *item = treew->headerItem())
+ recursiveReTranslate(item, m_className, m_idBased);
+ const int cnt = treew->topLevelItemCount();
+ for (int i = 0; i < cnt; ++i) {
+ QTreeWidgetItem *item = treew->topLevelItem(i);
+ recursiveReTranslate(item, m_className, m_idBased);
+ }
+#endif
+#if QT_CONFIG(tablewidget)
+ } else if (QTableWidget *tablew = qobject_cast<QTableWidget*>(o)) {
+ const int row_cnt = tablew->rowCount();
+ const int col_cnt = tablew->columnCount();
+ for (int j = 0; j < col_cnt; ++j)
+ reTranslateTableItem(tablew->horizontalHeaderItem(j), m_className, m_idBased);
+ for (int i = 0; i < row_cnt; ++i) {
+ reTranslateTableItem(tablew->verticalHeaderItem(i), m_className, m_idBased);
+ for (int j = 0; j < col_cnt; ++j)
+ reTranslateTableItem(tablew->item(i, j), m_className, m_idBased);
+ }
+#endif
+#if QT_CONFIG(combobox)
+ } else if (QComboBox *combow = qobject_cast<QComboBox*>(o)) {
+ if (!qobject_cast<QFontComboBox*>(o)) {
+ const int cnt = combow->count();
+ for (int i = 0; i < cnt; ++i) {
+ const QVariant v = combow->itemData(i, Qt::DisplayPropertyRole);
+ if (v.isValid()) {
+ QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v);
+ combow->setItemText(i, tsv.translate(m_className, m_idBased));
+ }
+ }
+ }
+#endif
+#if QT_CONFIG(toolbox)
+ } else if (QToolBox *toolw = qobject_cast<QToolBox*>(o)) {
+ const int cnt = toolw->count();
+ for (int i = 0; i < cnt; ++i) {
+ RETRANSLATE_SUBWIDGET_PROP(toolw, setItemText, PROP_TOOLITEMTEXT);
+#if QT_CONFIG(tooltip)
+ RETRANSLATE_SUBWIDGET_PROP(toolw, setItemToolTip, PROP_TOOLITEMTOOLTIP);
+# endif
+ }
+#endif
+ }
+ }
+ return false;
+ }
+
+private:
+ QByteArray m_className;
+ bool m_idBased;
+};
+
+class FormBuilderPrivate: public QFormBuilder
+{
+ friend class QT_PREPEND_NAMESPACE(QUiLoader);
+ friend class QT_PREPEND_NAMESPACE(QUiLoaderPrivate);
+ using ParentClass = QFormBuilder;
+
+public:
+ QUiLoader *loader = nullptr;
+
+ bool dynamicTr = false;
+ bool trEnabled = true;
+
+ FormBuilderPrivate() = default;
+
+ QWidget *defaultCreateWidget(const QString &className, QWidget *parent, const QString &name)
+ {
+ return ParentClass::createWidget(className, parent, name);
+ }
+
+ QLayout *defaultCreateLayout(const QString &className, QObject *parent, const QString &name)
+ {
+ return ParentClass::createLayout(className, parent, name);
+ }
+
+ QAction *defaultCreateAction(QObject *parent, const QString &name)
+ {
+ return ParentClass::createAction(parent, name);
+ }
+
+ QActionGroup *defaultCreateActionGroup(QObject *parent, const QString &name)
+ {
+ return ParentClass::createActionGroup(parent, name);
+ }
+
+ QWidget *createWidget(const QString &className, QWidget *parent, const QString &name) override
+ {
+ if (QWidget *widget = loader->createWidget(className, parent, name)) {
+ widget->setObjectName(name);
+ return widget;
+ }
+
+ return nullptr;
+ }
+
+ QLayout *createLayout(const QString &className, QObject *parent, const QString &name) override
+ {
+ if (QLayout *layout = loader->createLayout(className, parent, name)) {
+ layout->setObjectName(name);
+ return layout;
+ }
+
+ return nullptr;
+ }
+
+ QActionGroup *createActionGroup(QObject *parent, const QString &name) override
+ {
+ if (QActionGroup *actionGroup = loader->createActionGroup(parent, name)) {
+ actionGroup->setObjectName(name);
+ return actionGroup;
+ }
+
+ return nullptr;
+ }
+
+ QAction *createAction(QObject *parent, const QString &name) override
+ {
+ if (QAction *action = loader->createAction(parent, name)) {
+ action->setObjectName(name);
+ return action;
+ }
+
+ return nullptr;
+ }
+
+ void applyProperties(QObject *o, const QList<DomProperty*> &properties) override;
+ QWidget *create(DomUI *ui, QWidget *parentWidget) override;
+ QWidget *create(DomWidget *ui_widget, QWidget *parentWidget) override;
+ bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) override;
+
+private:
+ QByteArray m_class;
+ TranslationWatcher *m_trwatch = nullptr;
+ bool m_idBased = false;
+};
+
+static QString convertTranslatable(const DomProperty *p, const QByteArray &className,
+ bool idBased, QUiTranslatableStringValue *strVal)
+{
+ if (p->kind() != DomProperty::String)
+ return QString();
+ const DomString *dom_str = p->elementString();
+ if (!dom_str)
+ return QString();
+ if (dom_str->hasAttributeNotr()) {
+ const QString notr = dom_str->attributeNotr();
+ if (notr == QStringLiteral("yes") || notr == QStringLiteral("true"))
+ return QString();
+ }
+ strVal->setValue(dom_str->text().toUtf8());
+ strVal->setQualifier(idBased ? dom_str->attributeId().toUtf8() : dom_str->attributeComment().toUtf8());
+ if (strVal->value().isEmpty() && strVal->qualifier().isEmpty())
+ return QString();
+ return strVal->translate(className, idBased);
+}
+
+void FormBuilderPrivate::applyProperties(QObject *o, const QList<DomProperty*> &properties)
+{
+ QFormBuilder::applyProperties(o, properties);
+
+ if (!m_trwatch)
+ m_trwatch = new TranslationWatcher(o, m_class, m_idBased);
+
+ if (properties.isEmpty())
+ return;
+
+ // Unlike string item roles, string properties are not loaded via the textBuilder
+ // (as they are "shadowed" by the property sheets in designer). So do the initial
+ // translation here.
+ bool anyTrs = false;
+ for (const DomProperty *p : properties) {
+ QUiTranslatableStringValue strVal;
+ const QString text = convertTranslatable(p, m_class, m_idBased, &strVal);
+ if (text.isEmpty())
+ continue;
+ const QByteArray name = p->attributeName().toUtf8();
+ if (dynamicTr) {
+ const QByteArray dynname = QByteArray(PROP_GENERIC_PREFIX + name);
+ o->setProperty(dynname, QVariant::fromValue(strVal));
+ anyTrs = trEnabled;
+ }
+ if (p->elementString()->text() != text)
+ o->setProperty(name, text);
+ }
+ if (anyTrs)
+ o->installEventFilter(m_trwatch);
+}
+
+QWidget *FormBuilderPrivate::create(DomUI *ui, QWidget *parentWidget)
+{
+ m_class = ui->elementClass().toUtf8();
+ m_trwatch = nullptr;
+ m_idBased = ui->attributeIdbasedtr();
+ setTextBuilder(new TranslatingTextBuilder(m_idBased, trEnabled, m_class));
+ return QFormBuilder::create(ui, parentWidget);
+}
+
+QWidget *FormBuilderPrivate::create(DomWidget *ui_widget, QWidget *parentWidget)
+{
+ QWidget *w = QFormBuilder::create(ui_widget, parentWidget);
+ if (w == nullptr)
+ return nullptr;
+
+ if (0) {
+#if QT_CONFIG(tabwidget)
+ } else if (qobject_cast<QTabWidget*>(w)) {
+#endif
+#if QT_CONFIG(listwidget)
+ } else if (qobject_cast<QListWidget*>(w)) {
+#endif
+#if QT_CONFIG(treewidget)
+ } else if (qobject_cast<QTreeWidget*>(w)) {
+#endif
+#if QT_CONFIG(tablewidget)
+ } else if (qobject_cast<QTableWidget*>(w)) {
+#endif
+#if QT_CONFIG(combobox)
+ } else if (qobject_cast<QComboBox*>(w)) {
+ if (qobject_cast<QFontComboBox*>(w))
+ return w;
+#endif
+#if QT_CONFIG(toolbox)
+ } else if (qobject_cast<QToolBox*>(w)) {
+#endif
+ } else {
+ return w;
+ }
+ if (dynamicTr && trEnabled)
+ w->installEventFilter(m_trwatch);
+ return w;
+}
+
+#define TRANSLATE_SUBWIDGET_PROP(mainWidget, attribute, setter, propName) \
+ do { \
+ if (const auto *p = attributes.value(attribute)) { \
+ QUiTranslatableStringValue strVal; \
+ const QString text = convertTranslatable(p, m_class, m_idBased, &strVal); \
+ if (!text.isEmpty()) { \
+ if (dynamicTr) \
+ mainWidget->widget(i)->setProperty(propName, QVariant::fromValue(strVal)); \
+ mainWidget->setter(i, text); \
+ } \
+ } \
+ } while (0)
+
+bool FormBuilderPrivate::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
+{
+ if (parentWidget == nullptr)
+ return true;
+
+ if (!ParentClass::addItem(ui_widget, widget, parentWidget))
+ return false;
+
+ // Check special cases. First: Custom container
+ const QString className = QLatin1String(parentWidget->metaObject()->className());
+ if (!d->customWidgetAddPageMethod(className).isEmpty())
+ return true;
+
+ if (0) {
+#if QT_CONFIG(tabwidget)
+ } else if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(parentWidget)) {
+ const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute());
+ const int i = tabWidget->count() - 1;
+ TRANSLATE_SUBWIDGET_PROP(tabWidget, QFormBuilderStrings::titleAttribute,
+ setTabText, PROP_TABPAGETEXT);
+#if QT_CONFIG(tooltip)
+ TRANSLATE_SUBWIDGET_PROP(tabWidget, QFormBuilderStrings::toolTipAttribute,
+ setTabToolTip, PROP_TABPAGETOOLTIP);
+# endif
+#if QT_CONFIG(whatsthis)
+ TRANSLATE_SUBWIDGET_PROP(tabWidget, QFormBuilderStrings::whatsThisAttribute,
+ setTabWhatsThis, PROP_TABPAGEWHATSTHIS);
+# endif
+#endif
+#if QT_CONFIG(toolbox)
+ } else if (QToolBox *toolBox = qobject_cast<QToolBox*>(parentWidget)) {
+ const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute());
+ const int i = toolBox->count() - 1;
+ TRANSLATE_SUBWIDGET_PROP(toolBox, QFormBuilderStrings::labelAttribute,
+ setItemText, PROP_TOOLITEMTEXT);
+#if QT_CONFIG(tooltip)
+ TRANSLATE_SUBWIDGET_PROP(toolBox, QFormBuilderStrings::toolTipAttribute,
+ setItemToolTip, PROP_TOOLITEMTOOLTIP);
+# endif
+#endif
+ }
+
+ return true;
+}
+
+#ifdef QFORMINTERNAL_NAMESPACE
+}
+#endif
+
+class QUiLoaderPrivate
+{
+public:
+#ifdef QFORMINTERNAL_NAMESPACE
+ QFormInternal::FormBuilderPrivate builder;
+#else
+ FormBuilderPrivate builder;
+#endif
+
+ void setupWidgetMap() const;
+};
+
+void QUiLoaderPrivate::setupWidgetMap() const
+{
+ if (!g_widgets()->isEmpty())
+ return;
+
+#define DECLARE_WIDGET(a, b) g_widgets()->insert(QLatin1String(#a), true);
+#define DECLARE_LAYOUT(a, b)
+
+#include "widgets.table"
+
+#undef DECLARE_WIDGET
+#undef DECLARE_WIDGET_1
+#undef DECLARE_LAYOUT
+}
+
+/*!
+ \class QUiLoader
+ \inmodule QtUiTools
+
+ \brief The QUiLoader class enables standalone applications to
+ dynamically create user interfaces at run-time using the
+ information stored in UI files or specified in plugin paths.
+
+ In addition, you can customize or create your own user interface by
+ deriving your own loader class.
+
+ If you have a custom component or an application that embeds \QD, you can
+ also use the QFormBuilder class provided by the QtDesigner module to create
+ user interfaces from UI files.
+
+ The QUiLoader class provides a collection of functions allowing you to
+ create widgets based on the information stored in UI files (created
+ with \QD) or available in the specified plugin paths. The specified plugin
+ paths can be retrieved using the pluginPaths() function. Similarly, the
+ contents of a UI file can be retrieved using the load() function. For
+ example:
+
+ \snippet quiloader/mywidget.cpp 0
+
+ \if !defined(qtforpython)
+ By including the user interface in the form's resources (\c myform.qrc), we
+ ensure that it will be present at run-time:
+
+ \quotefile quiloader/mywidget.qrc
+ \endif
+
+ The availableWidgets() function returns a QStringList with the class names
+ of the widgets available in the specified plugin paths. To create these
+ widgets, simply use the createWidget() function. For example:
+
+ \snippet quiloader/main.cpp 0
+
+ To make a custom widget available to the loader, you can use the
+ addPluginPath() function; to remove all available widgets, you can call
+ the clearPluginPaths() function.
+
+ The createAction(), createActionGroup(), createLayout(), and createWidget()
+ functions are used internally by the QUiLoader class whenever it has to
+ create an action, action group, layout, or widget respectively. For that
+ reason, you can subclass the QUiLoader class and reimplement these
+ functions to intervene the process of constructing a user interface. For
+ example, you might want to have a list of the actions created when loading
+ a form or creating a custom widget.
+
+ For a complete example using the QUiLoader class, see the
+ \l{Calculator Builder}.
+
+ \sa {Qt UI Tools}, QFormBuilder
+*/
+
+/*!
+ Creates a form loader with the given \a parent.
+*/
+QUiLoader::QUiLoader(QObject *parent)
+ : QObject(parent), d_ptr(new QUiLoaderPrivate)
+{
+ Q_D(QUiLoader);
+
+#ifndef QT_NO_DATASTREAM
+ static int metaTypeId = 0;
+ if (!metaTypeId) {
+ metaTypeId = qRegisterMetaType<QUiTranslatableStringValue>("QUiTranslatableStringValue");
+ }
+#endif // QT_NO_DATASTREAM
+ d->builder.loader = this;
+
+#if QT_CONFIG(library)
+ QStringList paths;
+ const QStringList &libraryPaths = QApplication::libraryPaths();
+ for (const QString &path : libraryPaths) {
+ QString libPath = path;
+ libPath += QDir::separator();
+ libPath += QStringLiteral("designer");
+ paths.append(libPath);
+ }
+
+ d->builder.setPluginPath(paths);
+#endif // QT_CONFIG(library)
+}
+
+/*!
+ Destroys the loader.
+*/
+QUiLoader::~QUiLoader() = default;
+
+/*!
+ Loads a form from the given \a device and creates a new widget with the
+ given \a parentWidget to hold its contents.
+
+ \sa createWidget(), errorString()
+*/
+QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget)
+{
+ Q_D(QUiLoader);
+ // QXmlStreamReader will report errors on open failure.
+ if (!device->isOpen())
+ device->open(QIODevice::ReadOnly|QIODevice::Text);
+ return d->builder.load(device, parentWidget);
+}
+
+/*!
+ Returns a list naming the paths in which the loader will search when
+ locating custom widget plugins.
+
+ \sa addPluginPath(), clearPluginPaths()
+*/
+QStringList QUiLoader::pluginPaths() const
+{
+ Q_D(const QUiLoader);
+ return d->builder.pluginPaths();
+}
+
+/*!
+ Clears the list of paths in which the loader will search when locating
+ plugins.
+
+ \sa addPluginPath(), pluginPaths()
+*/
+void QUiLoader::clearPluginPaths()
+{
+ Q_D(QUiLoader);
+ d->builder.clearPluginPaths();
+}
+
+/*!
+ Adds the given \a path to the list of paths in which the loader will search
+ when locating plugins.
+
+ \sa pluginPaths(), clearPluginPaths()
+*/
+void QUiLoader::addPluginPath(const QString &path)
+{
+ Q_D(QUiLoader);
+ d->builder.addPluginPath(path);
+}
+
+/*!
+ Creates a new widget with the given \a parent and \a name using the class
+ specified by \a className. You can use this function to create any of the
+ widgets returned by the availableWidgets() function.
+
+ The function is also used internally by the QUiLoader class whenever it
+ creates a widget. Hence, you can subclass QUiLoader and reimplement this
+ function to intervene process of constructing a user interface or widget.
+ However, in your implementation, ensure that you call QUiLoader's version
+ first.
+
+ \sa availableWidgets(), load()
+*/
+QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name)
+{
+ Q_D(QUiLoader);
+ return d->builder.defaultCreateWidget(className, parent, name);
+}
+
+/*!
+ Creates a new layout with the given \a parent and \a name using the class
+ specified by \a className.
+
+ The function is also used internally by the QUiLoader class whenever it
+ creates a widget. Hence, you can subclass QUiLoader and reimplement this
+ function to intervene process of constructing a user interface or widget.
+ However, in your implementation, ensure that you call QUiLoader's version
+ first.
+
+ \sa createWidget(), load()
+*/
+QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name)
+{
+ Q_D(QUiLoader);
+ return d->builder.defaultCreateLayout(className, parent, name);
+}
+
+/*!
+ Creates a new action group with the given \a parent and \a name.
+
+ The function is also used internally by the QUiLoader class whenever it
+ creates a widget. Hence, you can subclass QUiLoader and reimplement this
+ function to intervene process of constructing a user interface or widget.
+ However, in your implementation, ensure that you call QUiLoader's version
+ first.
+
+ \sa createAction(), createWidget(), load()
+ */
+QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name)
+{
+ Q_D(QUiLoader);
+ return d->builder.defaultCreateActionGroup(parent, name);
+}
+
+/*!
+ Creates a new action with the given \a parent and \a name.
+
+ The function is also used internally by the QUiLoader class whenever it
+ creates a widget. Hence, you can subclass QUiLoader and reimplement this
+ function to intervene process of constructing a user interface or widget.
+ However, in your implementation, ensure that you call QUiLoader's version
+ first.
+
+ \sa createActionGroup(), createWidget(), load()
+*/
+QAction *QUiLoader::createAction(QObject *parent, const QString &name)
+{
+ Q_D(QUiLoader);
+ return d->builder.defaultCreateAction(parent, name);
+}
+
+/*!
+ Returns a list naming all available widgets that can be built using the
+ createWidget() function, i.e all the widgets specified within the given
+ plugin paths.
+
+ \sa pluginPaths(), createWidget()
+
+*/
+QStringList QUiLoader::availableWidgets() const
+{
+ Q_D(const QUiLoader);
+
+ d->setupWidgetMap();
+ widget_map available = *g_widgets();
+
+ const auto &customWidgets = d->builder.customWidgets();
+ for (QDesignerCustomWidgetInterface *plugin : customWidgets)
+ available.insert(plugin->name(), true);
+
+ return available.keys();
+}
+
+
+/*!
+ \since 4.5
+ Returns a list naming all available layouts that can be built using the
+ createLayout() function
+
+ \sa createLayout()
+*/
+
+QStringList QUiLoader::availableLayouts() const
+{
+ QStringList rc;
+#define DECLARE_WIDGET(a, b)
+#define DECLARE_LAYOUT(a, b) rc.push_back(QLatin1String(#a));
+
+#include "widgets.table"
+
+#undef DECLARE_WIDGET
+#undef DECLARE_LAYOUT
+ return rc;
+}
+
+/*!
+ Sets the working directory of the loader to \a dir. The loader will look
+ for other resources, such as icons and resource files, in paths relative to
+ this directory.
+
+ \sa workingDirectory()
+*/
+
+void QUiLoader::setWorkingDirectory(const QDir &dir)
+{
+ Q_D(QUiLoader);
+ d->builder.setWorkingDirectory(dir);
+}
+
+/*!
+ Returns the working directory of the loader.
+
+ \sa setWorkingDirectory()
+*/
+
+QDir QUiLoader::workingDirectory() const
+{
+ Q_D(const QUiLoader);
+ return d->builder.workingDirectory();
+}
+/*!
+ \since 4.5
+
+ If \a enabled is true, user interfaces loaded by this loader will
+ automatically retranslate themselves upon receiving a language change
+ event. Otherwise, the user interfaces will not be retranslated.
+
+ \sa isLanguageChangeEnabled()
+*/
+
+void QUiLoader::setLanguageChangeEnabled(bool enabled)
+{
+ Q_D(QUiLoader);
+ d->builder.dynamicTr = enabled;
+}
+
+/*!
+ \since 4.5
+
+ Returns true if dynamic retranslation on language change is enabled;
+ returns false otherwise.
+
+ \sa setLanguageChangeEnabled()
+*/
+
+bool QUiLoader::isLanguageChangeEnabled() const
+{
+ Q_D(const QUiLoader);
+ return d->builder.dynamicTr;
+}
+
+/*!
+ \internal
+ \since 4.5
+
+ If \a enabled is true, user interfaces loaded by this loader will be
+ translated. Otherwise, the user interfaces will not be translated.
+
+ \note This is orthogonal to languageChangeEnabled.
+
+ \sa isLanguageChangeEnabled(), setLanguageChangeEnabled()
+*/
+
+void QUiLoader::setTranslationEnabled(bool enabled)
+{
+ Q_D(QUiLoader);
+ d->builder.trEnabled = enabled;
+}
+
+/*!
+ \internal
+ \since 4.5
+
+ Returns true if translation is enabled; returns false otherwise.
+
+ \sa setTranslationEnabled()
+*/
+
+bool QUiLoader::isTranslationEnabled() const
+{
+ Q_D(const QUiLoader);
+ return d->builder.trEnabled;
+}
+
+/*!
+ Returns a human-readable description of the last error occurred in load().
+
+ \since 5.0
+ \sa load()
+*/
+
+QString QUiLoader::errorString() const
+{
+ Q_D(const QUiLoader);
+ return d->builder.errorString();
+}
+
+QT_END_NAMESPACE
+
+#include "quiloader.moc"