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
abstractformbuilder.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
8#include "ui4_p.h"
9#include "properties_p.h"
10
11#include <QtWidgets/qmainwindow.h>
12#include <QtWidgets/qmenu.h>
13#include <QtWidgets/qmenubar.h>
14#include <QtWidgets/qstatusbar.h>
15#include <QtWidgets/qtoolbar.h>
16#if QT_CONFIG(mdiarea)
17# include <QtWidgets/qmdiarea.h>
18#endif
19#include <QtWidgets/qdockwidget.h>
20#include <QtWidgets/qwizard.h>
21#if QT_CONFIG(stackedwidget)
22# include <QtWidgets/qstackedwidget.h>
23#endif
24#if QT_CONFIG(toolbox)
25# include <QtWidgets/qtoolbox.h>
26#endif
27#if QT_CONFIG(tabwidget)
28# include <QtWidgets/qtabwidget.h>
29#endif
30#include <QtWidgets/qsplitter.h>
31#include <QtWidgets/qbuttongroup.h>
32#include <QtWidgets/qboxlayout.h>
33#include <QtWidgets/qformlayout.h>
34#include <QtWidgets/qgridlayout.h>
35#include <QtWidgets/qscrollarea.h>
36#if QT_CONFIG(treewidget)
37# include <QtWidgets/qtreewidget.h>
38#endif
39#if QT_CONFIG(listwidget)
40# include <QtWidgets/qlistwidget.h>
41#endif
42#include <QtWidgets/qheaderview.h>
43#if QT_CONFIG(tablewidget)
44# include <QtWidgets/qtablewidget.h>
45#endif
46#if QT_CONFIG(combobox)
47# include <QtWidgets/qcombobox.h>
48#endif
49#include <QtWidgets/qpushbutton.h>
50#ifndef QFORMINTERNAL_NAMESPACE
51# include <private/qlayout_p.h> // Compiling within Designer
52#endif
53
54#include <QtGui/qaction.h>
55#include <QtGui/qactiongroup.h>
56
57#include <QtCore/qcoreapplication.h>
58#include <QtCore/qdebug.h>
59#include <QtCore/qdir.h>
60#include <QtCore/qfileinfo.h>
61#include <QtCore/qhash.h>
62#include <QtCore/qmetaobject.h>
63#include <QtCore/qpair.h>
64#include <QtCore/qqueue.h>
65#include <QtCore/qvariant.h>
66#include <QtCore/qxmlstream.h>
67
68#include <limits.h>
69
70#include <algorithm>
71#include <iterator>
72
73Q_DECLARE_METATYPE(QWidgetList)
74
75QT_BEGIN_NAMESPACE
76
77using namespace Qt::StringLiterals;
78
79static constexpr auto buttonGroupPropertyC = "buttonGroup"_L1;
80
81#ifdef QFORMINTERNAL_NAMESPACE
82using namespace QFormInternal;
83#endif
84
85using QFBE = QFormBuilderExtra;
86
87static inline DomProperty *currentIndexProperty(const QList<DomProperty*> &properties)
88{
89 return QFBE::propertyByName(properties, "currentIndex");
90}
91
93{
94public:
95 inline QFriendlyLayout() { Q_ASSERT(0); }
96
97#ifdef QFORMINTERNAL_NAMESPACE
99#else
100 friend class QAbstractFormBuilder;
101#endif
102};
103
104/*!
105 \class QAbstractFormBuilder
106
107 \brief The QAbstractFormBuilder class provides a default
108 implementation for classes that create user interfaces at
109 run-time.
110
111 \inmodule QtDesigner
112
113 QAbstractFormBuilder provides a standard interface and a default
114 implementation for constructing forms from user interface
115 files. It is not intended to be instantiated directly. Use the
116 QFormBuilder class to create user interfaces from UI files at
117 run-time. For example:
118
119 \snippet lib/tools_designer_src_lib_uilib_formbuilder.cpp 0
120
121 To override certain aspects of the form builder's behavior,
122 subclass QAbstractFormBuilder and reimplement the relevant virtual
123 functions:
124
125 \list
126 \li load() handles reading of UI format files from arbitrary
127 QIODevices, and construction of widgets from the XML data
128 that they contain.
129 \li save() handles saving of widget details in UI format to
130 arbitrary QIODevices.
131 \li workingDirectory() and setWorkingDirectory() control the
132 directory in which forms are held. The form builder looks for
133 other resources on paths relative to this directory.
134 \endlist
135
136 The QFormBuilder class is typically used by custom components and
137 applications that embed \QD. Standalone applications that need to
138 dynamically generate user interfaces at run-time use the
139 QUiLoader, found in the \l{Qt UI Tools} module.
140
141 \sa {Qt UI Tools}
142*/
143
144/*!
145 Constructs a new form builder.*/
146QAbstractFormBuilder::QAbstractFormBuilder() : d(new QFormBuilderExtra)
147{
148 setResourceBuilder(new QResourceBuilder());
149 setTextBuilder(new QTextBuilder());
150}
151
152/*!
153 Destroys the form builder.*/
154QAbstractFormBuilder::~QAbstractFormBuilder() = default;
155
156/*!
157 \fn QWidget *QAbstractFormBuilder::load(QIODevice *device, QWidget *parent)
158
159 Loads an XML representation of a widget from the given \a device,
160 and constructs a new widget with the specified \a parent.
161
162 \sa save(), errorString()
163*/
164QWidget *QAbstractFormBuilder::load(QIODevice *dev, QWidget *parentWidget)
165{
166 QScopedPointer<DomUI> ui(d->readUi(dev));
167 if (ui.isNull())
168 return nullptr;
169 QWidget *widget = create(ui.data(), parentWidget);
170 if (!widget && d->m_errorString.isEmpty())
171 d->m_errorString = QFormBuilderExtra::msgInvalidUiFile();
172 return widget;
173}
174
175/*!
176 \internal
178QWidget *QAbstractFormBuilder::create(DomUI *ui, QWidget *parentWidget)
179{
180 d->clear();
181 if (const DomLayoutDefault *def = ui->elementLayoutDefault()) {
182 d->m_defaultMargin = def->hasAttributeMargin() ? def->attributeMargin() : INT_MIN;
183 d->m_defaultSpacing = def->hasAttributeSpacing() ? def->attributeSpacing() : INT_MIN;
184 }
185
186 DomWidget *ui_widget = ui->elementWidget();
187 if (!ui_widget)
188 return nullptr;
189
190 initialize(ui);
191
192 if (const DomButtonGroups *domButtonGroups = ui->elementButtonGroups())
193 d->registerButtonGroups(domButtonGroups);
194
195 if (QWidget *widget = create(ui_widget, parentWidget)) {
196 // Reparent button groups that were actually created to main container for them to be found in the signal/slot part
197 for (const auto &bg : std::as_const(d->buttonGroups())) {
198 if (bg.second)
199 bg.second->setParent(widget);
200 }
201 createConnections(ui->elementConnections(), widget);
202 createResources(ui->elementResources()); // maybe this should go first, before create()...
203 applyTabStops(widget, ui->elementTabStops());
204 d->applyInternalProperties();
205 reset();
206 d->clear();
207 return widget;
208 }
209 d->clear();
210 return nullptr;
211}
212
213/*!
214 \internal
215 Retrieve relevant information from the custom widgets section.
216 Called by create(DomUI *, QWidget *); call manually if you
217 just use create(DomWidget *, QWidget *) on some child widget of DomUI.
218 */
219
220void QAbstractFormBuilder::initialize(const DomUI *ui)
221{
222 DomCustomWidgets *domCustomWidgets = ui->elementCustomWidgets();
223 createCustomWidgets(domCustomWidgets);
224
225 if (domCustomWidgets) {
226 const auto &customWidgets = domCustomWidgets->elementCustomWidget();
227 for (const DomCustomWidget *w : customWidgets)
228 d->storeCustomWidgetData(w->elementClass(), w);
229 }
230}
231
232/*!
233 \internal
234*/
235QWidget *QAbstractFormBuilder::create(DomWidget *ui_widget, QWidget *parentWidget)
236{
237 QWidget *w = createWidget(ui_widget->attributeClass(), parentWidget, ui_widget->attributeName());
238 if (!w)
239 return nullptr;
240
241 applyProperties(w, ui_widget->elementProperty());
242
243 const auto &elementAction = ui_widget->elementAction();
244 for (DomAction *ui_action : elementAction) {
245 QAction *child_action = create(ui_action, w);
246 Q_UNUSED( child_action );
247 }
248
249 const auto &elementActionGroup = ui_widget->elementActionGroup();
250 for (DomActionGroup *ui_action_group : elementActionGroup) {
251 QActionGroup *child_action_group = create(ui_action_group, w);
252 Q_UNUSED( child_action_group );
253 }
254
255 QWidgetList children;
256 const auto &elementWidget = ui_widget->elementWidget();
257 for (DomWidget *ui_child : elementWidget) {
258 if (QWidget *child = create(ui_child, w)) {
259 children += child;
260 } else {
261 const QString className = ui_child->elementClass().value(0);
262 uiLibWarning(QCoreApplication::translate("QAbstractFormBuilder", "The creation of a widget of the class '%1' failed.").arg(className));
263 }
264 }
265
266 const auto &elementLayout = ui_widget->elementLayout();
267 for (DomLayout *ui_lay : elementLayout) {
268 QLayout *child_lay = create(ui_lay, nullptr, w);
269 Q_UNUSED( child_lay );
270 }
271
272 const auto &addActions = ui_widget->elementAddAction();
273 if (!addActions.isEmpty()) {
274 for (DomActionRef *ui_action_ref : addActions) {
275 const QString name = ui_action_ref->attributeName();
276 if (name == "separator"_L1) {
277 QAction *sep = new QAction(w);
278 sep->setSeparator(true);
279 w->addAction(sep);
280 addMenuAction(sep);
281 } else if (QAction *a = d->m_actions.value(name)) {
282 w->addAction(a);
283 } else if (QActionGroup *g = d->m_actionGroups.value(name)) {
284 w->addActions(g->actions());
285 } else if (QMenu *menu = w->findChild<QMenu*>(name)) {
286 w->addAction(menu->menuAction());
287 addMenuAction(menu->menuAction());
288 }
289 }
290 }
291
292 loadExtraInfo(ui_widget, w, parentWidget);
293 addItem(ui_widget, w, parentWidget);
294
295 if (qobject_cast<QDialog *>(w) && parentWidget)
296 w->setAttribute(Qt::WA_Moved, false); // So that QDialog::setVisible(true) will center it
297
298 const QStringList zOrderNames = ui_widget->elementZOrder();
299 if (!zOrderNames.isEmpty()) {
300 QWidgetList zOrder = qvariant_cast<QWidgetList>(w->property("_q_zOrder"));
301 for (const QString &widgetName : zOrderNames) {
302 if (QWidget *child = w->findChild<QWidget*>(widgetName)) {
303 if (child->parentWidget() == w) {
304 zOrder.removeAll(child);
305 zOrder.append(child);
306 child->raise();
307 }
308 }
309 }
310 w->setProperty("_q_zOrder", QVariant::fromValue(zOrder));
311 }
312
313 return w;
314}
315
316/*!
317 \internal
318*/
319QAction *QAbstractFormBuilder::create(DomAction *ui_action, QObject *parent)
320{
321 QAction *a = createAction(parent, ui_action->attributeName());
322 if (!a)
323 return nullptr;
324
325 d->m_actions.insert(ui_action->attributeName(), a);
326 applyProperties(a, ui_action->elementProperty());
327 return a;
328}
329
330/*!
331 \internal
332*/
333QActionGroup *QAbstractFormBuilder::create(DomActionGroup *ui_action_group, QObject *parent)
334{
335 QActionGroup *a = createActionGroup(parent, ui_action_group->attributeName());
336 if (!a)
337 return nullptr;
338 d->m_actionGroups.insert(ui_action_group->attributeName(), a);
339 applyProperties(a, ui_action_group->elementProperty());
340
341 const auto &elementAction = ui_action_group->elementAction();
342 for (DomAction *ui_action : elementAction) {
343 QAction *child_action = create(ui_action, a);
344 Q_UNUSED( child_action );
345 }
346
347 const auto &elementActionGroup = ui_action_group->elementActionGroup();
348 for (DomActionGroup *g : elementActionGroup) {
349 QActionGroup *child_action_group = create(g, parent);
350 Q_UNUSED( child_action_group );
351 }
352
353 return a;
354}
355
356// figure out the toolbar area of a DOM attrib list.
357// By legacy, it is stored as an integer. As of 4.3.0, it is the enumeration value.
358Qt::ToolBarArea QAbstractFormBuilder::toolbarAreaFromDOMAttributes(const DomPropertyHash &attributes)
359{
360 const DomProperty *attr = attributes.value("toolBarArea"_L1);
361 if (!attr)
362 return Qt::TopToolBarArea;
363 switch(attr->kind()) {
364 case DomProperty::Number:
365 return static_cast<Qt::ToolBarArea>(attr->elementNumber());
366 case DomProperty::Enum:
367 return enumKeyOfObjectToValue<QAbstractFormBuilderGadget, Qt::ToolBarArea>("toolBarArea",
368 attr->elementEnum().toLatin1().constData());
369 default:
370 break;
371 }
372 return Qt::TopToolBarArea;
373}
374
375/*!
376 \internal
377*/
378bool QAbstractFormBuilder::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
379{
380 const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute());
381
382 if (parentWidget == nullptr)
383 return true;
384 // Check special cases. First: Custom container
385 const QString className = QLatin1StringView(parentWidget->metaObject()->className());
386 const QString addPageMethod = d->customWidgetAddPageMethod(className);
387 if (!addPageMethod.isEmpty()) {
388 // If this fails ( non-existent or non-slot), use ContainerExtension in Designer, else it can't be helped
389 return QMetaObject::invokeMethod(parentWidget, addPageMethod.toUtf8().constData(), Qt::DirectConnection, Q_ARG(QWidget*, widget));
390 }
391
392 if (QMainWindow *mw = qobject_cast<QMainWindow*>(parentWidget)) {
393
394#if QT_CONFIG(menubar)
395 // the menubar
396 if (QMenuBar *menuBar = qobject_cast<QMenuBar*>(widget)) {
397 mw->setMenuBar(menuBar);
398 return true;
399 }
400#endif
401
402#if QT_CONFIG(toolbar)
403 // apply the toolbar's attributes
404 if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) {
405 mw->addToolBar(toolbarAreaFromDOMAttributes(attributes), toolBar);
406 // check break
407 if (const DomProperty *attr = attributes.value("toolBarBreak"_L1))
408 if (attr->elementBool() == "true"_L1)
409 mw->insertToolBarBreak (toolBar);
410
411 return true;
412 }
413#endif
414
415#if QT_CONFIG(statusbar)
416 // statusBar
417 if (QStatusBar *statusBar = qobject_cast<QStatusBar*>(widget)) {
418 mw->setStatusBar(statusBar);
419 return true;
420 }
421#endif
422
423#if QT_CONFIG(dockwidget)
424 // apply the dockwidget's attributes
425 if (QDockWidget *dockWidget = qobject_cast<QDockWidget*>(widget)) {
426 if (const DomProperty *attr = attributes.value("dockWidgetArea"_L1)) {
427 Qt::DockWidgetArea area = static_cast<Qt::DockWidgetArea>(attr->elementNumber());
428 if (!dockWidget->isAreaAllowed(area)) {
429 if (dockWidget->isAreaAllowed(Qt::LeftDockWidgetArea))
430 area = Qt::LeftDockWidgetArea;
431 else if (dockWidget->isAreaAllowed(Qt::RightDockWidgetArea))
432 area = Qt::RightDockWidgetArea;
433 else if (dockWidget->isAreaAllowed(Qt::TopDockWidgetArea))
434 area = Qt::TopDockWidgetArea;
435 else if (dockWidget->isAreaAllowed(Qt::BottomDockWidgetArea))
436 area = Qt::BottomDockWidgetArea;
437 }
438 mw->addDockWidget(area, dockWidget);
439 } else {
440 mw->addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
441 }
442 return true;
443 }
444#endif
445
446 if (!mw->centralWidget()) {
447 mw->setCentralWidget(widget);
448 return true;
449 }
450 }
451
452#if QT_CONFIG(tabwidget)
453 else if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(parentWidget)) {
454 widget->setParent(nullptr);
455
456 const int tabIndex = tabWidget->count();
457 if (auto *titleP = attributes.value(QFormBuilderStrings::titleAttribute))
458 tabWidget->addTab(widget, toString(titleP->elementString()));
459 else
460 tabWidget->addTab(widget, "Page"_L1);
461
462 if (const auto *picon = attributes.value(QFormBuilderStrings::iconAttribute)) {
463 QVariant v = resourceBuilder()->loadResource(workingDirectory(), picon);
464 QVariant nativeValue = resourceBuilder()->toNativeValue(v);
465 tabWidget->setTabIcon(tabIndex, qvariant_cast<QIcon>(nativeValue));
466 }
467
468#if QT_CONFIG(tooltip)
469 if (const auto *ptoolTip = attributes.value(QFormBuilderStrings::toolTipAttribute)) {
470 tabWidget->setTabToolTip(tabIndex, toString(ptoolTip->elementString()));
471 }
472#endif
473
474#if QT_CONFIG(whatsthis)
475 if (const auto *pwhatsThis = attributes.value(QFormBuilderStrings::whatsThisAttribute)) {
476 tabWidget->setTabWhatsThis(tabIndex, toString(pwhatsThis->elementString()));
477 }
478#endif
479
480 return true;
481 }
482#endif
483
484#if QT_CONFIG(toolbox)
485 else if (QToolBox *toolBox = qobject_cast<QToolBox*>(parentWidget)) {
486 const int tabIndex = toolBox->count();
487 if (const auto *labelP = attributes.value(QFormBuilderStrings::labelAttribute))
488 toolBox->addItem(widget, toString(labelP->elementString()));
489 else
490 toolBox->addItem(widget, "Page"_L1);
491
492 if (const auto *picon = attributes.value(QFormBuilderStrings::iconAttribute)) {
493 QVariant v = resourceBuilder()->loadResource(workingDirectory(), picon);
494 QVariant nativeValue = resourceBuilder()->toNativeValue(v);
495 toolBox->setItemIcon(tabIndex, qvariant_cast<QIcon>(nativeValue));
496 }
497
498#if QT_CONFIG(tooltip)
499 if (const auto *ptoolTip = attributes.value(QFormBuilderStrings::toolTipAttribute)) {
500 toolBox->setItemToolTip(tabIndex, toString(ptoolTip->elementString()));
501 }
502#endif
503
504 return true;
505 }
506#endif
507
508#if QT_CONFIG(stackedwidget)
509 else if (QStackedWidget *stackedWidget = qobject_cast<QStackedWidget*>(parentWidget)) {
510 stackedWidget->addWidget(widget);
511 return true;
512 }
513#endif
514
515#if QT_CONFIG(splitter)
516 else if (QSplitter *splitter = qobject_cast<QSplitter*>(parentWidget)) {
517 splitter->addWidget(widget);
518 return true;
519 }
520#endif
521
522#if QT_CONFIG(mdiarea)
523 else if (QMdiArea *mdiArea = qobject_cast<QMdiArea*>(parentWidget)) {
524 mdiArea->addSubWindow(widget);
525 return true;
526 }
527#endif
528
529#if QT_CONFIG(dockwidget)
530 else if (QDockWidget *dockWidget = qobject_cast<QDockWidget*>(parentWidget)) {
531 dockWidget->setWidget(widget);
532 return true;
533 }
534#endif
535
536#if QT_CONFIG(scrollarea)
537 else if (QScrollArea *scrollArea = qobject_cast<QScrollArea*>(parentWidget)) {
538 scrollArea->setWidget(widget);
539 return true;
540 }
541#endif
542
543#if QT_CONFIG(wizard)
544 else if (QWizard *wizard = qobject_cast<QWizard *>(parentWidget)) {
545 QWizardPage *page = qobject_cast<QWizardPage*>(widget);
546 if (!page) {
547 uiLibWarning(QCoreApplication::translate("QAbstractFormBuilder", "Attempt to add child that is not of class QWizardPage to QWizard."));
548 return false;
549 }
550 wizard->addPage(page);
551 return true;
552 }
553#endif
554 return false;
555}
556
557/*!
558 \internal
559*/
560void QAbstractFormBuilder::layoutInfo(DomLayout *ui_layout, QObject *parent, int *margin, int *spacing)
561{
562 Q_UNUSED(parent);
563 auto properties = ui_layout->elementProperty();
564
565 int mar = INT_MIN;
566 int spac = INT_MIN;
567 if (const DomProperty *p = QFBE::propertyByName(properties, "margin"))
568 mar = p->elementNumber();
569 if (const DomProperty *p = QFBE::propertyByName(properties, "spacing"))
570 spac = p->elementNumber();
571
572#ifdef Q_OS_MACOS
573 // here we recognize UI file < 4.3 (no we don't store margin property)
574 if (mar != INT_MIN) {
575 const int defaultMargin = parent->inherits("QLayoutWidget") ? 0 : 9;
576 if (mar == defaultMargin)
577 mar = INT_MIN;
578 if (spac == 6)
579 spac = INT_MIN;
580
581 if (mar == INT_MIN || spac == INT_MIN) {
582 for (auto it = properties.begin(); it != properties.end(); ) {
583 DomProperty *prop = *it;
584 if ((mar == INT_MIN && prop->attributeName() == "margin"_L1)
585 || (spac == INT_MIN && prop->attributeName() == "spacing"_L1)) {
586 delete prop;
587 it = properties.erase(it);
588 } else {
589 ++it;
590 }
591 }
592 ui_layout->setElementProperty(properties);
593 }
594 }
595#endif
596 if (margin)
597 *margin = mar;
598 if (spacing)
599 *spacing = spac;
600}
601
602/*!
603 \internal
604*/
605QLayout *QAbstractFormBuilder::create(DomLayout *ui_layout, QLayout *parentLayout, QWidget *parentWidget)
606{
607 QObject *p = parentLayout;
608
609 if (p == nullptr)
610 p = parentWidget;
611
612 Q_ASSERT(p != nullptr);
613
614 bool tracking = false;
615
616 if (p == parentWidget && parentWidget->layout()) {
617 tracking = true;
618 p = parentWidget->layout();
619 }
620
621 QLayout *layout = createLayout(ui_layout->attributeClass(), p, ui_layout->hasAttributeName() ? ui_layout->attributeName() : QString());
622
623 if (layout == nullptr)
624 return 0;
625
626 if (tracking && layout->parent() == nullptr) {
627 QBoxLayout *box = qobject_cast<QBoxLayout*>(parentWidget->layout());
628 if (!box) { // only QBoxLayout is supported
629 const QString widgetClass = QString::fromUtf8(parentWidget->metaObject()->className());
630 const QString layoutClass = QString::fromUtf8(parentWidget->layout()->metaObject()->className());
631 const QString msg = QCoreApplication::translate("QAbstractFormBuilder", "Attempt to add a layout to a widget '%1' (%2) which already has a layout of non-box type %3.\n"
632 "This indicates an inconsistency in the ui-file.").
633 arg(parentWidget->objectName(), widgetClass, layoutClass);
634 uiLibWarning(msg);
635 return nullptr;
636 }
637 box->addLayout(layout);
638 }
639
640 int margin = INT_MIN, spacing = INT_MIN;
641 layoutInfo(ui_layout, p, &margin, &spacing);
642
643 if (margin != INT_MIN) {
644 layout->setContentsMargins(margin, margin, margin, margin);
645 } else {
646 int left = -1, top = -1, right = -1, bottom = -1;
647 layout->getContentsMargins(&left, &top, &right, &bottom);
648 QFormBuilderExtra::getLayoutMargins(ui_layout->elementProperty(),
649 &left, &top, &right, &bottom);
650 layout->setContentsMargins(left, top, right, bottom);
651 }
652
653 if (spacing != INT_MIN) {
654 layout->setSpacing(spacing);
655 } else {
656 QGridLayout *grid = qobject_cast<QGridLayout *>(layout);
657 if (grid) {
658 const auto &properties = ui_layout->elementProperty();
659 if (const auto *p = QFBE::propertyByName(properties, "horizontalSpacing"))
660 grid->setHorizontalSpacing(p->elementNumber());
661 if (const auto *p = QFBE::propertyByName(properties, "verticalSpacing"))
662 grid->setVerticalSpacing(p->elementNumber());
663 }
664 }
665
666 applyProperties(layout, ui_layout->elementProperty());
667
668 const auto &elementItem = ui_layout->elementItem();
669 for (DomLayoutItem *ui_item : elementItem) {
670 if (QLayoutItem *item = create(ui_item, layout, parentWidget)) {
671 addItem(ui_item, item, layout);
672 }
673 }
674 // Check the box stretch attributes
675 if (QBoxLayout *box = qobject_cast<QBoxLayout*>(layout)) {
676 const QString boxStretch = ui_layout->attributeStretch();
677 if (!boxStretch.isEmpty())
678 QFormBuilderExtra::setBoxLayoutStretch(boxStretch, box);
679 }
680 // Check the grid stretch/minimum size attributes
681 if (QGridLayout *grid = qobject_cast<QGridLayout*>(layout)) {
682 // Stretch
683 const QString gridRowStretch = ui_layout->attributeRowStretch();
684 if (!gridRowStretch.isEmpty())
685 QFormBuilderExtra::setGridLayoutRowStretch(gridRowStretch, grid);
686 const QString gridColumnStretch = ui_layout->attributeColumnStretch();
687 if (!gridColumnStretch.isEmpty())
688 QFormBuilderExtra::setGridLayoutColumnStretch(gridColumnStretch, grid);
689 // Minimum size
690 const QString gridColumnMinimumWidth = ui_layout->attributeColumnMinimumWidth();
691 if (!gridColumnMinimumWidth.isEmpty())
692 QFormBuilderExtra::setGridLayoutColumnMinimumWidth(gridColumnMinimumWidth, grid);
693 const QString gridRowMinimumHeight = ui_layout->attributeRowMinimumHeight();
694 if (!gridRowMinimumHeight.isEmpty())
695 QFormBuilderExtra::setGridLayoutRowMinimumHeight(gridRowMinimumHeight, grid);
696 }
697 return layout;
698}
699
700#if QT_CONFIG(formlayout)
701static inline QFormLayout::ItemRole formLayoutRole(int column, int colspan)
702{
703 if (colspan > 1)
704 return QFormLayout::SpanningRole;
705 return column == 0 ? QFormLayout::LabelRole : QFormLayout::FieldRole;
706}
707#endif
708
709static inline QString alignmentPrefix(bool fullyQualifiedEnums)
710{
711 return fullyQualifiedEnums ? "Qt::AlignmentFlag::"_L1 : "Qt::"_L1;
712}
713
714static inline QString alignmentValue(Qt::Alignment a, bool fullyQualifiedEnums)
715{
716 QLatin1StringView h;
717 QLatin1StringView v;
718 switch (a & Qt::AlignHorizontal_Mask) {
719 case Qt::AlignLeft:
720 h = "AlignLeft"_L1;
721 break;
722 case Qt::AlignRight:
723 h = "AlignRight"_L1;
724 break;
725 case Qt::AlignHCenter:
726 h = "AlignHCenter"_L1;
727 break;
728 case Qt::AlignJustify:
729 h = "AlignJustify"_L1;
730 break;
731 }
732 switch (a & Qt::AlignVertical_Mask) {
733 case Qt::AlignTop:
734 v = "AlignTop"_L1;
735 break;
736 case Qt::AlignBottom:
737 v = "AlignBottom"_L1;
738 break;
739 case Qt::AlignVCenter:
740 v = "AlignVCenter"_L1;
741 break;
742 }
743 QString result;
744 if (!h.isEmpty())
745 result += alignmentPrefix(fullyQualifiedEnums) + h;
746 if (!h.isEmpty() && !v.isEmpty())
747 result += u'|';
748 if (!v.isEmpty())
749 result += alignmentPrefix(fullyQualifiedEnums) + v;
750 return result;
751}
752
753static inline Qt::Alignment alignmentFromDom(const QString &in)
754{
755 Qt::Alignment rc;
756 if (!in.isEmpty()) {
757 for (const auto &f : qTokenize(in, u'|')) {
758 if (f.endsWith("::AlignLeft"_L1)) {
759 rc |= Qt::AlignLeft;
760 } else if (f.endsWith("::AlignRight"_L1)) {
761 rc |= Qt::AlignRight;
762 } else if (f.endsWith("::AlignHCenter"_L1)) {
763 rc |= Qt::AlignHCenter;
764 } else if (f.endsWith("::AlignJustify"_L1)) {
765 rc |= Qt::AlignJustify;
766 } else if (f.endsWith("::AlignTop"_L1)) {
767 rc |= Qt::AlignTop;
768 } else if (f.endsWith("::AlignBottom"_L1)) {
769 rc |= Qt::AlignBottom;
770 } else if (f.endsWith("::AlignVCenter"_L1)) {
771 rc |= Qt::AlignVCenter;
772 }
773 }
774 }
775 return rc;
776}
777
778/*!
779 \internal
780*/
781bool QAbstractFormBuilder::addItem(DomLayoutItem *ui_item, QLayoutItem *item, QLayout *layout)
782{
783 // Calling addChildWidget(), etc. is required to maintain consistency of the layouts,
784 // see documentation of addItem(), which should ideally not be used.
785 if (item->widget()) {
786 static_cast<QFriendlyLayout*>(layout)->addChildWidget(item->widget());
787 } else if (item->layout()) {
788 static_cast<QFriendlyLayout*>(layout)->addChildLayout(item->layout());
789 } else if (item->spacerItem()) {
790 // nothing to do
791 } else {
792 return false;
793 }
794
795 if (QGridLayout *grid = qobject_cast<QGridLayout*>(layout)) {
796 const int rowSpan = ui_item->hasAttributeRowSpan() ? ui_item->attributeRowSpan() : 1;
797 const int colSpan = ui_item->hasAttributeColSpan() ? ui_item->attributeColSpan() : 1;
798 grid->addItem(item, ui_item->attributeRow(), ui_item->attributeColumn(),
799 rowSpan, colSpan, item->alignment());
800 return true;
801 }
802#if QT_CONFIG(formlayout)
803 if (QFormLayout *form = qobject_cast<QFormLayout *>(layout)) {
804 const int row = ui_item->attributeRow();
805 const int colSpan = ui_item->hasAttributeColSpan() ? ui_item->attributeColSpan() : 1;
806 form->setItem(row, formLayoutRole(ui_item->attributeColumn(), colSpan), item);
807 return true;
808 }
809
810#endif
811 layout->addItem(item);
812 return true;
813}
814
815/*!
816 \internal
817*/
818QLayoutItem *QAbstractFormBuilder::create(DomLayoutItem *ui_layoutItem, QLayout *layout, QWidget *parentWidget)
819{
820 switch (ui_layoutItem->kind()) {
821 case DomLayoutItem::Widget: {
822 if (QWidget *w = create(ui_layoutItem->elementWidget(), parentWidget)) {
823#ifdef QFORMINTERNAL_NAMESPACE // uilib
824 QWidgetItem *item = new QWidgetItemV2(w);
825#else // Within Designer: Use factory method that returns special items that refuse to shrink to 0,0
826 QWidgetItem *item = QLayoutPrivate::createWidgetItem(layout, w);
827#endif
828 item->setAlignment(alignmentFromDom(ui_layoutItem->attributeAlignment()));
829 return item;
830 }
831 qWarning() << QCoreApplication::translate("QAbstractFormBuilder", "Empty widget item in %1 '%2'.").arg(QString::fromUtf8(layout->metaObject()->className()), layout->objectName());
832 return nullptr;
833 }
834 case DomLayoutItem::Spacer: {
835 QSize size(0, 0);
836 QSizePolicy::Policy sizeType = QSizePolicy::Expanding;
837 bool isVspacer = false;
838
839 const DomSpacer *ui_spacer = ui_layoutItem->elementSpacer();
840 const auto &spacerProperties = ui_spacer->elementProperty();
841 if (!spacerProperties.isEmpty()) {
842 for (DomProperty *p : spacerProperties) {
843 const QVariant v = toVariant(&QAbstractFormBuilderGadget::staticMetaObject, p); // ### remove me
844 if (v.isNull())
845 continue;
846 if (p->attributeName() == "sizeHint"_L1 && p->kind() == DomProperty::Size) {
847 size = v.toSize(); // ### remove me
848 } else if (p->attributeName() == "sizeType"_L1 && p->kind() == DomProperty::Enum) {
849 sizeType = static_cast<QSizePolicy::Policy>(v.toInt());
850 } else if (p->attributeName() == "orientation"_L1 && p->kind() == DomProperty::Enum) {
851 const Qt::Orientation o = static_cast<Qt::Orientation>(v.toInt());
852 isVspacer = (o == Qt::Vertical);
853 }
854 }
855 }
856
857 QSpacerItem *spacer = nullptr;
858 if (isVspacer)
859 spacer = new QSpacerItem(size.width(), size.height(), QSizePolicy::Minimum, sizeType);
860 else
861 spacer = new QSpacerItem(size.width(), size.height(), sizeType, QSizePolicy::Minimum);
862 return spacer; }
863
864 case DomLayoutItem::Layout:
865 return create(ui_layoutItem->elementLayout(), layout, parentWidget);
866
867 default:
868 break;
869 }
870
871 return nullptr;
872}
873
874/*!
875 \internal
876*/
877void QAbstractFormBuilder::applyProperties(QObject *o, const QList<DomProperty*> &properties)
878{
879 for (DomProperty *p : properties) {
880 const QVariant v = toVariant(o->metaObject(), p);
881 if (!v.isNull()) {
882 QString attributeName = p->attributeName();
883 if (attributeName == "numDigits"_L1 && o->inherits("QLCDNumber")) // Deprecated in Qt 4, removed in Qt 5.
884 attributeName = u"digitCount"_s;
885 if (!d->applyPropertyInternally(o, attributeName, v))
886 o->setProperty(attributeName.toUtf8(), v);
887 }
888 }
889}
890
891
892/*!
893 \internal
894 Check whether a property is applied internally by QAbstractFormBuilder. Call this
895 from overwritten applyProperties().
896*/
897
898bool QAbstractFormBuilder::applyPropertyInternally(QObject *o, const QString &propertyName, const QVariant &value)
899{
900 return d->applyPropertyInternally(o,propertyName, value);
901}
902
903/*!
904 \internal
905*/
906
907QVariant QAbstractFormBuilder::toVariant(const QMetaObject *meta, DomProperty *p)
908{
909 return domPropertyToVariant(this, meta, p);
910}
911
912/*!
913 \internal
914*/
915void QAbstractFormBuilder::setupColorGroup(QPalette &palette, QPalette::ColorGroup colorGroup,
916 DomColorGroup *group)
917{
918 QFormBuilderExtra::setupColorGroup(&palette, colorGroup, group);
919}
920
921/*!
922 \internal
923*/
924DomColorGroup *QAbstractFormBuilder::saveColorGroup(const QPalette &palette)
925{
926 return QFormBuilderExtra::saveColorGroup(palette,
927 palette.currentColorGroup());
928}
929
930/*!
931 \internal
932*/
933QBrush QAbstractFormBuilder::setupBrush(DomBrush *brush)
934{
935 return QFormBuilderExtra::setupBrush(brush);
936}
937
938DomBrush *QAbstractFormBuilder::saveBrush(const QBrush &br)
939{
940 return QFormBuilderExtra::saveBrush(br);
941}
942
943/*!
944 \internal
945*/
946QWidget *QAbstractFormBuilder::createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name)
947{
948 Q_UNUSED(widgetName);
949 Q_UNUSED(parentWidget);
950 Q_UNUSED(name);
951 return nullptr;
952}
953
954/*!
955 \internal
956*/
957QLayout *QAbstractFormBuilder::createLayout(const QString &layoutName, QObject *parent, const QString &name)
958{
959 Q_UNUSED(layoutName);
960 Q_UNUSED(parent);
961 Q_UNUSED(name);
962 return nullptr;
963}
964
965/*!
966 \internal
967*/
968QAction *QAbstractFormBuilder::createAction(QObject *parent, const QString &name)
969{
970 QAction *action = new QAction(parent);
971 action->setObjectName(name);
972 return action;
973}
974
975/*!
976 \internal
977*/
978QActionGroup *QAbstractFormBuilder::createActionGroup(QObject *parent, const QString &name)
979{
980 QActionGroup *g = new QActionGroup(parent);
981 g->setObjectName(name);
982 return g;
983}
984
985/*!
986 \fn void QAbstractFormBuilder::save(QIODevice *device, QWidget *widget)
987
988 Saves an XML representation of the given \a widget to the
989 specified \a device in the standard UI file format.
990
991 \note Unlike when saving a form in \QD, all property values are
992 written. This is because, the state of whether a property value was
993 modified or not isn't stored in the Qt property system. The widget that
994 is being saved, could have been created dynamically, not loaded via
995 \l load(), so in this case the form builder isn't aware of the list of
996 changed properties. Also, there's no generic way to do this for widgets
997 that were created dynamically.
998
999 Therefore, you should remove properties that are not required from your
1000 resulting XML files, before loading them. Alternatively, if you already
1001 know which properties you want to save when you call this method,
1002 you can overload \c computeProperties() and return a filtered list of
1003 required properties. Otherwise, unexpected behavior may occur as some
1004 of these properties may depend on each other.
1005
1006 \sa load()
1007*/
1008void QAbstractFormBuilder::save(QIODevice *dev, QWidget *widget)
1009{
1010 DomWidget *ui_widget = createDom(widget, nullptr);
1011 Q_ASSERT( ui_widget != nullptr );
1012
1013 DomUI *ui = new DomUI();
1014 ui->setAttributeVersion(u"4.0"_s);
1015 ui->setElementWidget(ui_widget);
1016
1017 saveDom(ui, widget);
1018
1019 QXmlStreamWriter writer(dev);
1020 writer.setAutoFormatting(true);
1021 writer.setAutoFormattingIndent(1);
1022 writer.writeStartDocument();
1023 ui->write(writer);
1024 writer.writeEndDocument();
1025
1026 d->m_laidout.clear();
1027
1028 delete ui;
1029}
1030
1031/*!
1032 \internal
1033*/
1034void QAbstractFormBuilder::saveDom(DomUI *ui, QWidget *widget)
1035{
1036 ui->setElementClass(widget->objectName());
1037
1038 if (DomConnections *ui_connections = saveConnections()) {
1039 ui->setElementConnections(ui_connections);
1040 }
1041
1042 if (DomCustomWidgets *ui_customWidgets = saveCustomWidgets()) {
1043 ui->setElementCustomWidgets(ui_customWidgets);
1044 }
1045
1046 if (DomTabStops *ui_tabStops = saveTabStops()) {
1047 ui->setElementTabStops(ui_tabStops);
1048 }
1049
1050 if (DomResources *ui_resources = saveResources()) {
1051 ui->setElementResources(ui_resources);
1052 }
1053 if (DomButtonGroups *ui_buttonGroups = saveButtonGroups(widget))
1054 ui->setElementButtonGroups(ui_buttonGroups);
1055}
1056
1057/*!
1058 \internal
1059*/
1060DomConnections *QAbstractFormBuilder::saveConnections()
1061{
1062 return new DomConnections;
1063}
1064
1065/*!
1066 \internal
1067*/
1068
1069DomWidget *QAbstractFormBuilder::createDom(QWidget *widget, DomWidget *ui_parentWidget, bool recursive)
1070{
1071 DomWidget *ui_widget = new DomWidget();
1072 ui_widget->setAttributeClass(QLatin1StringView(widget->metaObject()->className()));
1073 ui_widget->setAttributeName(widget->objectName());
1074
1075 ui_widget->setElementProperty(computeProperties(widget));
1076
1077 if (recursive) {
1078 if (QLayout *layout = widget->layout()) {
1079 if (DomLayout *ui_layout = createDom(layout, nullptr, ui_parentWidget)) {
1080 QList<DomLayout *> ui_layouts;
1081 ui_layouts.append(ui_layout);
1082
1083 ui_widget->setElementLayout(ui_layouts);
1084 }
1085 }
1086 }
1087
1088 // widgets, actions and action groups
1089 QList<DomWidget *> ui_widgets;
1090 QList<DomAction *> ui_actions;
1091 QList<DomActionGroup *> ui_action_groups;
1092
1093 QObjectList children;
1094
1095 // splitters need to store their children in the order specified by child indexes,
1096 // not the order of the child list.
1097#if QT_CONFIG(splitter)
1098 if (const QSplitter *splitter = qobject_cast<const QSplitter*>(widget)) {
1099 const int count = splitter->count();
1100 for (int i = 0; i < count; ++i)
1101 children.append(splitter->widget(i));
1102 } else
1103#endif
1104 {
1105 QObjectList childObjects = widget->children();
1106
1107 const QWidgetList list = qvariant_cast<QWidgetList>(widget->property("_q_widgetOrder"));
1108 for (QWidget *w : list) {
1109 if (childObjects.contains(w)) {
1110 children.append(w);
1111 childObjects.removeAll(w);
1112 }
1113 }
1114 children += childObjects;
1115
1116 const QWidgetList zOrder = qvariant_cast<QWidgetList>(widget->property("_q_zOrder"));
1117 if (list != zOrder) {
1118 QStringList zOrderList;
1119 zOrderList.reserve(zOrder.size());
1120 std::transform(zOrder.cbegin(), zOrder.cend(),
1121 std::back_inserter(zOrderList),
1122 [] (const QWidget *w) { return w->objectName(); });
1123 ui_widget->setElementZOrder(zOrderList);
1124 }
1125 }
1126
1127 for (QObject *obj : std::as_const(children)) {
1128 if (QWidget *childWidget = qobject_cast<QWidget*>(obj)) {
1129 if (d->m_laidout.contains(childWidget) || !recursive)
1130 continue;
1131
1132 if (QMenu *menu = qobject_cast<QMenu *>(childWidget)) {
1133 const auto actions = menu->parentWidget()->actions();
1134 const bool found =
1135 std::any_of(actions.cbegin(), actions.cend(),
1136 [menu] (const QAction *a) { return a->menu() == menu; });
1137 if (!found)
1138 continue;
1139 }
1140
1141 if (DomWidget *ui_child = createDom(childWidget, ui_widget)) {
1142 ui_widgets.append(ui_child);
1143 }
1144 } else if (QAction *childAction = qobject_cast<QAction*>(obj)) {
1145 if (childAction->actionGroup() != nullptr) {
1146 // it will be added later.
1147 continue;
1148 }
1149
1150 if (DomAction *ui_action = createDom(childAction)) {
1151 ui_actions.append(ui_action);
1152 }
1153 } else if (QActionGroup *childActionGroup = qobject_cast<QActionGroup*>(obj)) {
1154 if (DomActionGroup *ui_action_group = createDom(childActionGroup)) {
1155 ui_action_groups.append(ui_action_group);
1156 }
1157 }
1158 }
1159
1160 // add-action
1161 QList<DomActionRef *> ui_action_refs;
1162 const auto &actions = widget->actions();
1163 ui_action_refs.reserve(actions.size());
1164 for (QAction *action : actions) {
1165 if (DomActionRef *ui_action_ref = createActionRefDom(action)) {
1166 ui_action_refs.append(ui_action_ref);
1167 }
1168 }
1169
1170 if (recursive)
1171 ui_widget->setElementWidget(ui_widgets);
1172
1173 ui_widget->setElementAction(ui_actions);
1174 ui_widget->setElementActionGroup(ui_action_groups);
1175 ui_widget->setElementAddAction(ui_action_refs);
1176
1177 saveExtraInfo(widget, ui_widget, ui_parentWidget);
1178
1179 return ui_widget;
1180}
1181
1182/*!
1183 \internal
1184*/
1185DomActionRef *QAbstractFormBuilder::createActionRefDom(QAction *action)
1186{
1187 DomActionRef *ui_action_ref = new DomActionRef();
1188 if (action->isSeparator()) {
1189 ui_action_ref->setAttributeName("separator"_L1);
1190 } else {
1191 ui_action_ref->setAttributeName(action->menu() != nullptr
1192 ? action->menu()->objectName()
1193 : action->objectName());
1194 }
1195
1196 return ui_action_ref;
1197}
1198
1199// Struct to store layout item parameters for saving layout items
1201 explicit FormBuilderSaveLayoutEntry(QLayoutItem *li = nullptr) :
1202 item(li) {}
1203
1204 void setAlignment(Qt::Alignment al);
1205
1206 QLayoutItem *item;
1207 int row = -1;
1208 int column = -1;
1209 int rowSpan = 0;
1210 int columnSpan = 0;
1212};
1213
1214// filter out the case of "Spacer" and "QLayoutWidget" widgets
1216{
1217 if (const QWidget *widget = item->widget()) {
1218 const char *className = widget->metaObject()->className();
1219 if (qstrcmp(className, "Spacer") && qstrcmp(className, "QLayoutWidget"))
1220 alignment = al;
1221 }
1222}
1223
1224// Create list from standard box layout
1226{
1228 if (const int count = layout->count()) {
1229 rc.reserve(count);
1230 for (int idx = 0; idx < count; ++idx) {
1231 QLayoutItem *item = layout->itemAt(idx);
1233 entry.setAlignment(item->alignment());
1234 rc.append(entry);
1235 }
1236 }
1237 return rc;
1238}
1239
1240// Create list from grid layout
1242{
1244 if (const int count = gridLayout->count()) {
1245 rc.reserve(count);
1246 for (int idx = 0; idx < count; ++idx) {
1247 QLayoutItem *item = gridLayout->itemAt(idx);
1249 gridLayout->getItemPosition(idx, &entry.row, &entry.column, &entry.rowSpan,&entry.columnSpan);
1250 entry.setAlignment(item->alignment());
1251 rc.append(entry);
1252 }
1253 }
1254 return rc;
1255}
1256
1257#if QT_CONFIG(formlayout)
1258// Create list from form layout
1259static QList<FormBuilderSaveLayoutEntry> saveFormLayoutEntries(const QFormLayout *formLayout)
1260{
1261 QList<FormBuilderSaveLayoutEntry> rc;
1262 if (const int count = formLayout->count()) {
1263 rc.reserve(count);
1264 for (int idx = 0; idx < count; ++idx) {
1265 QLayoutItem *item = formLayout->itemAt(idx);
1266 QFormLayout::ItemRole role = QFormLayout::LabelRole;
1267 FormBuilderSaveLayoutEntry entry(item);
1268 formLayout->getItemPosition(idx, &entry.row, &role);
1269 switch (role ) {
1270 case QFormLayout::LabelRole:
1271 entry.column = 0;
1272 break;
1273 case QFormLayout::FieldRole:
1274 entry.column = 1;
1275 break;
1276 case QFormLayout::SpanningRole:
1277 entry.column = 0;
1278 entry.columnSpan = 2;
1279 break;
1280 }
1281 rc.push_back(entry);
1282 }
1283 }
1284 return rc;
1285}
1286#endif
1287
1288/*!
1289 \internal
1290*/
1291
1292DomLayout *QAbstractFormBuilder::createDom(QLayout *layout, DomLayout *ui_layout, DomWidget *ui_parentWidget)
1293{
1294 Q_UNUSED(ui_layout);
1295 DomLayout *lay = new DomLayout();
1296 lay->setAttributeClass(QLatin1StringView(layout->metaObject()->className()));
1297 const QString objectName = layout->objectName();
1298 if (!objectName.isEmpty())
1299 lay->setAttributeName(objectName);
1300 lay->setElementProperty(computeProperties(layout));
1301
1302 QList<FormBuilderSaveLayoutEntry> newList;
1303 if (QGridLayout *gridLayout = qobject_cast<QGridLayout *>(layout)) {
1304 newList = saveGridLayoutEntries(gridLayout);
1305#if QT_CONFIG(formlayout)
1306 } else if (const QFormLayout *formLayout = qobject_cast<const QFormLayout *>(layout)) {
1307 newList = saveFormLayoutEntries(formLayout);
1308#endif
1309 } else {
1310 newList = saveLayoutEntries(layout);
1311 }
1312
1313 QList<DomLayoutItem *> ui_items;
1314 ui_items.reserve(newList.size());
1315 for (const FormBuilderSaveLayoutEntry &item : std::as_const(newList)) {
1316 if (DomLayoutItem *ui_item = createDom(item.item, lay, ui_parentWidget)) {
1317 if (item.row >= 0)
1318 ui_item->setAttributeRow(item.row);
1319 if (item.column >= 0)
1320 ui_item->setAttributeColumn(item.column);
1321 if (item.rowSpan > 1)
1322 ui_item->setAttributeRowSpan(item.rowSpan);
1323 if (item.columnSpan > 1)
1324 ui_item->setAttributeColSpan(item.columnSpan);
1325 if (item.alignment)
1326 ui_item->setAttributeAlignment(alignmentValue(item.alignment,
1327 d->m_fullyQualifiedEnums));
1328 ui_items.append(ui_item);
1329 }
1330 }
1331
1332 lay->setElementItem(ui_items);
1333
1334 return lay;
1335}
1336
1337/*!
1338 \internal
1339*/
1340DomLayoutItem *QAbstractFormBuilder::createDom(QLayoutItem *item, DomLayout *ui_layout, DomWidget *ui_parentWidget)
1341{
1342 DomLayoutItem *ui_item = new DomLayoutItem();
1343
1344 if (item->widget()) {
1345 ui_item->setElementWidget(createDom(item->widget(), ui_parentWidget));
1346 d->m_laidout.insert(item->widget(), true);
1347 } else if (item->layout()) {
1348 ui_item->setElementLayout(createDom(item->layout(), ui_layout, ui_parentWidget));
1349 } else if (item->spacerItem()) {
1350 ui_item->setElementSpacer(createDom(item->spacerItem(), ui_layout, ui_parentWidget));
1351 }
1352
1353 return ui_item;
1354}
1355
1356/*!
1357 \internal
1358*/
1359DomSpacer *QAbstractFormBuilder::createDom(QSpacerItem *spacer, DomLayout *ui_layout, DomWidget *ui_parentWidget)
1360{
1361 Q_UNUSED(ui_layout);
1362 Q_UNUSED(ui_parentWidget);
1363
1364 DomSpacer *ui_spacer = new DomSpacer();
1365 QList<DomProperty*> properties;
1366
1367 DomProperty *prop = nullptr;
1368 // sizeHint property
1369 prop = new DomProperty();
1370 prop->setAttributeName("sizeHint"_L1);
1371 prop->setElementSize(new DomSize());
1372 prop->elementSize()->setElementWidth(spacer->sizeHint().width());
1373 prop->elementSize()->setElementHeight(spacer->sizeHint().height());
1374 properties.append(prop);
1375
1376 // orientation property
1377 prop = new DomProperty(); // ### we don't implemented the case where expandingDirections() is both Vertical and Horizontal
1378 prop->setAttributeName("orientation"_L1);
1379 QString value = d->m_fullyQualifiedEnums ? "Qt::Orientation::"_L1 : "Qt::"_L1;
1380 value += spacer->expandingDirections().testFlag(Qt::Horizontal)
1381 ? "Horizontal"_L1 : "Vertical"_L1;
1382 prop->setElementEnum(value);
1383 properties.append(prop);
1384
1385 ui_spacer->setElementProperty(properties);
1386 return ui_spacer;
1387}
1388
1389/*!
1390 \internal
1391*/
1392DomProperty *QAbstractFormBuilder::createProperty(QObject *obj, const QString &pname, const QVariant &v)
1393{
1394 if (!checkProperty(obj, pname)) {
1395 return nullptr;
1396 }
1397 return variantToDomProperty(this, obj->metaObject(), pname, v);
1398}
1399
1400/*!
1401 \internal
1402*/
1403QList<DomProperty*> QAbstractFormBuilder::computeProperties(QObject *obj)
1404{
1405 QList<DomProperty*> lst;
1406
1407 const QMetaObject *meta = obj->metaObject();
1408
1409 QHash<QByteArray, bool> properties;
1410 const int propertyCount = meta->propertyCount();
1411 for(int i=0; i < propertyCount; ++i)
1412 properties.insert(meta->property(i).name(), true);
1413
1414 const auto propertyNames = properties.keys();
1415
1416 const int propertyNamesCount = propertyNames.size();
1417 for(int i=0; i<propertyNamesCount ; ++i) {
1418 const QString pname = QString::fromUtf8(propertyNames.at(i));
1419 const QMetaProperty prop = meta->property(meta->indexOfProperty(pname.toUtf8()));
1420
1421 if (!prop.isWritable() || !checkProperty(obj, QLatin1StringView(prop.name())))
1422 continue;
1423
1424 const QVariant v = prop.read(obj);
1425
1426 DomProperty *dom_prop = nullptr;
1427 if (v.metaType().id() == QMetaType::Int) {
1428 dom_prop = new DomProperty();
1429
1430 if (prop.isFlagType())
1431 uiLibWarning(QCoreApplication::translate("QAbstractFormBuilder", "Flags property are not supported yet."));
1432
1433 if (prop.isEnumType()) {
1434 QString scope = QString::fromUtf8(prop.enumerator().scope());
1435 if (scope.size())
1436 scope += "::"_L1;
1437 const QString e = QString::fromUtf8(prop.enumerator().valueToKey(v.toInt()));
1438 if (e.size())
1439 dom_prop->setElementEnum(scope + e);
1440 } else
1441 dom_prop->setElementNumber(v.toInt());
1442 dom_prop->setAttributeName(pname);
1443 } else {
1444 dom_prop = createProperty(obj, pname, v);
1445 }
1446
1447 if (!dom_prop || dom_prop->kind() == DomProperty::Unknown)
1448 delete dom_prop;
1449 else
1450 lst.append(dom_prop);
1451 }
1452
1453 return lst;
1454}
1455
1456
1457/*!
1458 \internal
1459 \typedef QAbstractFormBuilder::DomPropertyHash
1460 \typedef QAbstractFormBuilder::IconPaths
1461*/
1462
1463
1464/*!
1465 \internal
1466*/
1467QAbstractFormBuilder::DomPropertyHash QAbstractFormBuilder::propertyMap(const QList<DomProperty*> &properties)
1468{
1469 DomPropertyHash map;
1470
1471 for (DomProperty *p : properties)
1472 map.insert(p->attributeName(), p);
1473
1474 return map;
1475}
1476
1477/*!
1478 \internal
1479*/
1480bool QAbstractFormBuilder::checkProperty(QObject *obj, const QString &prop) const
1481{
1482 Q_UNUSED(obj);
1483 Q_UNUSED(prop);
1484
1485 return true;
1486}
1487
1488/*!
1489 \internal
1490*/
1491QString QAbstractFormBuilder::toString(const DomString *str)
1492{
1493 return str ? str->text() : QString();
1494}
1495
1496/*!
1497 \internal
1498*/
1499void QAbstractFormBuilder::applyTabStops(QWidget *widget, DomTabStops *tabStops)
1500{
1501 if (!tabStops)
1502 return;
1503
1504 const QStringList &names = tabStops->elementTabStop();
1505 QWidgetList widgets;
1506 widgets.reserve(names.size());
1507 for (const QString &name : names) {
1508 if (QWidget *child = widget->findChild<QWidget*>(name)) {
1509 widgets.append(child);
1510 } else {
1511 uiLibWarning(QCoreApplication::translate("QAbstractFormBuilder",
1512 "While applying tab stops: The widget '%1' could not be found.")
1513 .arg(name));
1514 }
1515 }
1516
1517 for (int i = 1, count = widgets.size(); i < count; ++i)
1518 QWidget::setTabOrder(widgets.at(i - 1), widgets.at(i));
1519}
1520
1521/*!
1522 \internal
1523*/
1524DomCustomWidgets *QAbstractFormBuilder::saveCustomWidgets()
1525{
1526 return nullptr;
1527}
1528
1529/*!
1530 \internal
1531*/
1532DomTabStops *QAbstractFormBuilder::saveTabStops()
1533{
1534 return nullptr;
1535}
1536
1537/*!
1538 \internal
1539*/
1540DomResources *QAbstractFormBuilder::saveResources()
1541{
1542 return nullptr;
1543}
1544
1545/*!
1546 \internal
1547 \since 4.5
1548*/
1549
1550DomButtonGroups *QAbstractFormBuilder::saveButtonGroups(const QWidget *mainContainer)
1551{
1552 // Save fst order buttongroup children of maincontainer
1553 const QObjectList &mchildren = mainContainer->children();
1554 if (mchildren.isEmpty())
1555 return nullptr;
1556 QList<DomButtonGroup *> domGroups;
1557 for (QObject *o : mchildren) {
1558 if (auto bg = qobject_cast<QButtonGroup *>(o))
1559 if (DomButtonGroup* dg = createDom(bg))
1560 domGroups.push_back(dg);
1561 }
1562 if (domGroups.isEmpty())
1563 return nullptr;
1564 DomButtonGroups *rc = new DomButtonGroups;
1565 rc->setElementButtonGroup(domGroups);
1566 return rc;
1567}
1568
1569// VC6 would not find templated members, so we use statics and this utter hack.
1571public:
1572 using QAbstractFormBuilder::saveResource;
1573 using QAbstractFormBuilder::saveText;
1574 using QAbstractFormBuilder::resourceBuilder;
1575 using QAbstractFormBuilder::textBuilder;
1576 using QAbstractFormBuilder::toVariant;
1577};
1578
1579template<class T>
1580static void storeItemFlags(const T *item, QList<DomProperty*> *properties)
1581{
1582 static const Qt::ItemFlags defaultFlags = T().flags();
1583 static const QMetaEnum itemFlags_enum = metaEnum<QAbstractFormBuilderGadget>("itemFlags");
1584
1585 if (item->flags() != defaultFlags) {
1586 DomProperty *p = new DomProperty;
1587 p->setAttributeName(QFormBuilderStrings::flagsAttribute);
1588 p->setElementSet(QString::fromLatin1(itemFlags_enum.valueToKeys(item->flags())));
1589 properties->append(p);
1590 }
1591}
1592
1593template<class T>
1594static void storeItemProps(QAbstractFormBuilder *abstractFormBuilder, const T *item,
1595 QList<DomProperty*> *properties,
1596 Qt::Alignment defaultAlign = Qt::AlignLeading | Qt::AlignVCenter)
1597{
1598 static const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
1599 FriendlyFB * const formBuilder = static_cast<FriendlyFB *>(abstractFormBuilder);
1600
1601 DomProperty *p;
1602
1603 for (const QFormBuilderStrings::TextRoleNName &it : strings.itemTextRoles)
1604 if ((p = formBuilder->saveText(it.second, item->data(it.first.second))))
1605 properties->append(p);
1606
1607 auto *mo = static_cast<const QMetaObject *>(&QAbstractFormBuilderGadget::staticMetaObject);
1608 for (const QFormBuilderStrings::RoleNName &it : strings.itemRoles) {
1609 const QVariant v = item->data(it.first);
1610 const bool isModified = v.isValid()
1611 && (it.first != Qt::TextAlignmentRole || v.toUInt() != uint(defaultAlign));
1612 if (isModified &&
1613 (p = variantToDomProperty(abstractFormBuilder, mo, it.second, v))) {
1614 properties->append(p);
1615 }
1616 }
1617
1618 if ((p = formBuilder->saveResource(item->data(Qt::DecorationPropertyRole))))
1619 properties->append(p);
1620}
1621
1622template<class T>
1623static void storeItemPropsNFlags(QAbstractFormBuilder *abstractFormBuilder, const T *item,
1624 QList<DomProperty*> *properties)
1625{
1626 storeItemProps<T>(abstractFormBuilder, item, properties);
1627 storeItemFlags<T>(item, properties);
1628}
1629
1630template<class T>
1631static void loadItemProps(QAbstractFormBuilder *abstractFormBuilder, T *item,
1632 const QHash<QString, DomProperty*> &properties)
1633{
1634 static const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
1635 FriendlyFB * const formBuilder = static_cast<FriendlyFB *>(abstractFormBuilder);
1636
1637 DomProperty *p;
1638 QVariant v;
1639
1640 for (const QFormBuilderStrings::TextRoleNName &it : strings.itemTextRoles)
1641 if ((p = properties.value(it.second))) {
1642 v = formBuilder->textBuilder()->loadText(p);
1643 QVariant nativeValue = formBuilder->textBuilder()->toNativeValue(v);
1644 item->setData(it.first.first, qvariant_cast<QString>(nativeValue));
1645 item->setData(it.first.second, v);
1646 }
1647
1648 for (const QFormBuilderStrings::RoleNName &it : strings.itemRoles)
1649 if ((p = properties.value(it.second)) &&
1650 (v = formBuilder->toVariant(&QAbstractFormBuilderGadget::staticMetaObject, p)).isValid())
1651 item->setData(it.first, v);
1652
1653 if ((p = properties.value(strings.iconAttribute))) {
1654 v = formBuilder->resourceBuilder()->loadResource(formBuilder->workingDirectory(), p);
1655 QVariant nativeValue = formBuilder->resourceBuilder()->toNativeValue(v);
1656 item->setIcon(qvariant_cast<QIcon>(nativeValue));
1657 item->setData(Qt::DecorationPropertyRole, v);
1658 }
1659}
1660
1661template<class T>
1662static void loadItemPropsNFlags(QAbstractFormBuilder *abstractFormBuilder, T *item,
1663 const QHash<QString, DomProperty*> &properties)
1664{
1665 static const QMetaEnum itemFlags_enum = metaEnum<QAbstractFormBuilderGadget>("itemFlags");
1666
1667 loadItemProps<T>(abstractFormBuilder, item, properties);
1668
1669 DomProperty *p = properties.value(QFormBuilderStrings::flagsAttribute);
1670 if (p != nullptr && p->kind() == DomProperty::Set)
1671 item->setFlags(enumKeysToValue<Qt::ItemFlags>(itemFlags_enum, p->elementSet().toLatin1()));
1672}
1673
1674/*!
1675 \internal
1676*/
1677void QAbstractFormBuilder::saveTreeWidgetExtraInfo(QTreeWidget *treeWidget, DomWidget *ui_widget, DomWidget *ui_parentWidget)
1678{
1679 Q_UNUSED(ui_parentWidget);
1680
1681 QList<DomColumn *> columns;
1682 DomProperty *p;
1683 QVariant v;
1684 const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
1685 // save the header
1686 for (int c = 0; c<treeWidget->columnCount(); ++c) {
1687 DomColumn *column = new DomColumn;
1688
1689 QList<DomProperty*> properties;
1690
1691 for (const QFormBuilderStrings::TextRoleNName &it : strings.itemTextRoles) {
1692 p = saveText(it.second, treeWidget->headerItem()->data(c, it.first.second));
1693 // Prevent uic 4.4.X from crashing if it cannot find a column text
1694 if (!p && it.first.first == Qt::EditRole && it.second == "text"_L1) {
1695 DomString *defaultHeader = new DomString;
1696 defaultHeader->setText(QString::number(c + 1));
1697 defaultHeader->setAttributeNotr(u"true"_s);
1698 p = new DomProperty;
1699 p->setAttributeName(it.second);
1700 p->setElementString(defaultHeader);
1701 }
1702 if (p)
1703 properties.append(p);
1704 }
1705
1706 for (const QFormBuilderStrings::RoleNName &it : strings.itemRoles)
1707 if ((v = treeWidget->headerItem()->data(c, it.first)).isValid() &&
1708 (p = variantToDomProperty(this, &QAbstractFormBuilderGadget::staticMetaObject, it.second, v)))
1709 properties.append(p);
1710
1711 if ((p = saveResource(treeWidget->headerItem()->data(c, Qt::DecorationPropertyRole))))
1712 properties.append(p);
1713
1714 column->setElementProperty(properties);
1715 columns.append(column);
1716 }
1717
1718 ui_widget->setElementColumn(columns);
1719
1720 auto items = ui_widget->elementItem();
1721
1722 QQueue<std::pair<QTreeWidgetItem *, DomItem *> > pendingQueue;
1723 for (int i = 0; i < treeWidget->topLevelItemCount(); i++)
1724 pendingQueue.enqueue(std::make_pair(treeWidget->topLevelItem(i), nullptr));
1725
1726 while (!pendingQueue.isEmpty()) {
1727 const std::pair<QTreeWidgetItem *, DomItem *> pair = pendingQueue.dequeue();
1728 QTreeWidgetItem *item = pair.first;
1729 DomItem *parentDomItem = pair.second;
1730
1731 DomItem *currentDomItem = new DomItem;
1732
1733 QList<DomProperty*> properties;
1734 for (int c = 0; c < treeWidget->columnCount(); c++) {
1735 for (const QFormBuilderStrings::TextRoleNName &it : strings.itemTextRoles)
1736 if ((p = saveText(it.second, item->data(c, it.first.second))))
1737 properties.append(p);
1738
1739 for (const QFormBuilderStrings::RoleNName &it : strings.itemRoles)
1740 if ((v = item->data(c, it.first)).isValid() &&
1741 (p = variantToDomProperty(this, &QAbstractFormBuilderGadget::staticMetaObject, it.second, v)))
1742 properties.append(p);
1743
1744 if ((p = saveResource(item->data(c, Qt::DecorationPropertyRole))))
1745 properties.append(p);
1746 }
1747 storeItemFlags(item, &properties);
1748 currentDomItem->setElementProperty(properties);
1749
1750 if (parentDomItem) {
1751 auto childrenItems = parentDomItem->elementItem();
1752 childrenItems.append(currentDomItem);
1753 parentDomItem->setElementItem(childrenItems);
1754 } else
1755 items.append(currentDomItem);
1756
1757 for (int i = 0; i < item->childCount(); i++)
1758 pendingQueue.enqueue(std::make_pair(item->child(i), currentDomItem));
1759 }
1760
1761 ui_widget->setElementItem(items);
1762}
1763
1764/*!
1765 \internal
1766*/
1767void QAbstractFormBuilder::saveTableWidgetExtraInfo(QTableWidget *tableWidget, DomWidget *ui_widget, DomWidget *ui_parentWidget)
1768{
1769 Q_UNUSED(ui_parentWidget);
1770
1771 // save the horizontal header
1772 QList<DomColumn *> columns;
1773 auto *header = tableWidget->horizontalHeader();
1774 for (int c = 0; c < tableWidget->columnCount(); c++) {
1775 QList<DomProperty*> properties;
1776 QTableWidgetItem *item = tableWidget->horizontalHeaderItem(c);
1777 if (item)
1778 storeItemProps(this, item, &properties, header->defaultAlignment());
1779
1780 DomColumn *column = new DomColumn;
1781 column->setElementProperty(properties);
1782 columns.append(column);
1783 }
1784 ui_widget->setElementColumn(columns);
1785
1786 // save the vertical header
1787 QList<DomRow *> rows;
1788 header = tableWidget->verticalHeader();
1789 for (int r = 0; r < tableWidget->rowCount(); r++) {
1790 QList<DomProperty*> properties;
1791 QTableWidgetItem *item = tableWidget->verticalHeaderItem(r);
1792 if (item)
1793 storeItemProps(this, item, &properties, header->defaultAlignment());
1794
1795 DomRow *row = new DomRow;
1796 row->setElementProperty(properties);
1797 rows.append(row);
1798 }
1799 ui_widget->setElementRow(rows);
1800
1801 auto items = ui_widget->elementItem();
1802 for (int r = 0; r < tableWidget->rowCount(); r++)
1803 for (int c = 0; c < tableWidget->columnCount(); c++) {
1804 QTableWidgetItem *item = tableWidget->item(r, c);
1805 if (item) {
1806 QList<DomProperty*> properties;
1807 storeItemPropsNFlags(this, item, &properties);
1808
1809 DomItem *domItem = new DomItem;
1810 domItem->setAttributeRow(r);
1811 domItem->setAttributeColumn(c);
1812 domItem->setElementProperty(properties);
1813 items.append(domItem);
1814 }
1815 }
1816
1817 ui_widget->setElementItem(items);
1818}
1819
1820/*!
1821 \internal
1822*/
1823void QAbstractFormBuilder::saveListWidgetExtraInfo(QListWidget *listWidget, DomWidget *ui_widget, DomWidget *ui_parentWidget)
1824{
1825 Q_UNUSED(ui_parentWidget);
1826
1827 auto ui_items = ui_widget->elementItem();
1828 for (int i=0; i<listWidget->count(); ++i) {
1829 QList<DomProperty*> properties;
1830 storeItemPropsNFlags(this, listWidget->item(i), &properties);
1831
1832 DomItem *ui_item = new DomItem();
1833 ui_item->setElementProperty(properties);
1834 ui_items.append(ui_item);
1835 }
1836
1837 ui_widget->setElementItem(ui_items);
1838}
1839
1840/*!
1841 \internal
1842*/
1843void QAbstractFormBuilder::saveComboBoxExtraInfo(QComboBox *comboBox, DomWidget *ui_widget, DomWidget *ui_parentWidget)
1844{
1845 Q_UNUSED(ui_parentWidget);
1846 auto ui_items = ui_widget->elementItem();
1847
1848 const int count = comboBox->count();
1849 for (int i=0; i < count; ++i) {
1850 // We might encounter items for which both builders return 0 in Designer
1851 // (indicating a custom combo adding items in the constructor). Ignore those.
1852 DomProperty *textProperty = saveText(QFormBuilderStrings::textAttribute,
1853 comboBox->itemData(i, Qt::DisplayPropertyRole));
1854 DomProperty *iconProperty = saveResource(comboBox->itemData(i, Qt::DecorationPropertyRole));
1855 if (textProperty || iconProperty) {
1856 QList<DomProperty*> properties;
1857 if (textProperty)
1858 properties.push_back(textProperty);
1859 if (iconProperty)
1860 properties.push_back(iconProperty);
1861
1862 DomItem *ui_item = new DomItem();
1863 ui_item->setElementProperty(properties);
1864 ui_items.push_back(ui_item);
1865 }
1866 }
1867
1868 ui_widget->setElementItem(ui_items);
1869}
1870
1871/*!
1872 \internal
1873 \since 4.5
1874*/
1875
1876void QAbstractFormBuilder::saveButtonExtraInfo(const QAbstractButton *widget, DomWidget *ui_widget, DomWidget *)
1877{
1878 using DomPropertyList = QList<DomProperty *>;
1879 if (const QButtonGroup *buttonGroup = widget->group()) {
1880 DomPropertyList attributes = ui_widget->elementAttribute();
1881 DomString *domString = new DomString();
1882 domString->setText(buttonGroup->objectName());
1883 domString->setAttributeNotr(u"true"_s);
1884 DomProperty *domProperty = new DomProperty();
1885 domProperty->setAttributeName(buttonGroupPropertyC);
1886 domProperty->setElementString(domString);
1887 attributes += domProperty;
1888 ui_widget->setElementAttribute(attributes);
1889 }
1890}
1891
1893 "horizontalHeader"_L1,
1894 "verticalHeader"_L1,
1895};
1896
1898{
1899 // Special handling for qtableview/qtreeview fake header attributes
1900 "visible"_L1,
1901 "cascadingSectionResizes"_L1,
1902 "minimumSectionSize"_L1, // before defaultSectionSize
1903 "defaultSectionSize"_L1,
1904 "highlightSections"_L1,
1905 "showSortIndicator"_L1,
1906 "stretchLastSection"_L1
1907};
1908
1909/*!
1910 \internal
1911 \since 4.5
1912*/
1913void QAbstractFormBuilder::saveItemViewExtraInfo(const QAbstractItemView *itemView,
1914 DomWidget *ui_widget, DomWidget *)
1915{
1916 if (const QTreeView *treeView = qobject_cast<const QTreeView*>(itemView)) {
1917 auto viewProperties = ui_widget->elementAttribute();
1918 const auto &headerProperties = computeProperties(treeView->header());
1919 for (const QLatin1StringView realPropertyName : itemViewHeaderRealPropertyNames) {
1920 const QString upperPropertyName = QChar(realPropertyName.at(0)).toUpper()
1921 + realPropertyName.mid(1);
1922 const QString fakePropertyName = "header"_L1 + upperPropertyName;
1923 for (DomProperty *property : headerProperties) {
1924 if (property->attributeName() == realPropertyName) {
1925 property->setAttributeName(fakePropertyName);
1926 viewProperties << property;
1927 }
1928 }
1929 }
1930 ui_widget->setElementAttribute(viewProperties);
1931 } else if (const QTableView *tableView = qobject_cast<const QTableView*>(itemView)) {
1932 auto viewProperties = ui_widget->elementAttribute();
1933 for (QLatin1StringView headerPrefix : tableHeaderPrefixes) {
1934 const auto &headerProperties = headerPrefix == "horizontalHeader"_L1
1935 ? computeProperties(tableView->horizontalHeader())
1936 : computeProperties(tableView->verticalHeader());
1937 for (const QLatin1StringView realPropertyName : itemViewHeaderRealPropertyNames) {
1938 const QString upperPropertyName = QChar(realPropertyName.at(0)).toUpper()
1939 + realPropertyName.mid(1);
1940 const QString fakePropertyName = headerPrefix + upperPropertyName;
1941 for (DomProperty *property : std::as_const(headerProperties)) {
1942 if (property->attributeName() == realPropertyName) {
1943 property->setAttributeName(fakePropertyName);
1944 viewProperties << property;
1945 }
1946 }
1947 }
1948 }
1949 ui_widget->setElementAttribute(viewProperties);
1950 }
1951}
1952
1953/*!
1954 \internal
1955 \since 4.4
1956*/
1957
1958void QAbstractFormBuilder::setResourceBuilder(QResourceBuilder *builder)
1959{
1960 d->setResourceBuilder(builder);
1961}
1962
1963/*!
1964 \internal
1965 \since 4.4
1966*/
1967
1968QResourceBuilder *QAbstractFormBuilder::resourceBuilder() const
1969{
1970 return d->resourceBuilder();
1971}
1972
1973/*!
1974 \internal
1975 \since 4.5
1976*/
1977
1978void QAbstractFormBuilder::setTextBuilder(QTextBuilder *builder)
1979{
1980 d->setTextBuilder(builder);
1981}
1982
1983/*!
1984 \internal
1985 \since 4.5
1986*/
1987
1988QTextBuilder *QAbstractFormBuilder::textBuilder() const
1989{
1990 return d->textBuilder();
1991}
1992
1993/*!
1994 \internal
1995*/
1996void QAbstractFormBuilder::saveExtraInfo(QWidget *widget, DomWidget *ui_widget,
1997 DomWidget *ui_parentWidget)
1998{
1999 if (false) {
2000#if QT_CONFIG(listwidget)
2001 } else if (QListWidget *listWidget = qobject_cast<QListWidget*>(widget)) {
2002 saveListWidgetExtraInfo(listWidget, ui_widget, ui_parentWidget);
2003#endif
2004#if QT_CONFIG(treewidget)
2005 } else if (QTreeWidget *treeWidget = qobject_cast<QTreeWidget*>(widget)) {
2006 saveTreeWidgetExtraInfo(treeWidget, ui_widget, ui_parentWidget);
2007#endif
2008#if QT_CONFIG(tablewidget)
2009 } else if (QTableWidget *tableWidget = qobject_cast<QTableWidget*>(widget)) {
2010 saveTableWidgetExtraInfo(tableWidget, ui_widget, ui_parentWidget);
2011#endif
2012#if QT_CONFIG(combobox)
2013 } else if (QComboBox *comboBox = qobject_cast<QComboBox*>(widget)) {
2014 if (!QFormBuilderExtra::isQFontComboBox(widget))
2015 saveComboBoxExtraInfo(comboBox, ui_widget, ui_parentWidget);
2016#endif
2017 } else if(QAbstractButton *ab = qobject_cast<QAbstractButton *>(widget)) {
2018 saveButtonExtraInfo(ab, ui_widget, ui_parentWidget);
2019 }
2020 if (QAbstractItemView *itemView = qobject_cast<QAbstractItemView *>(widget)) {
2021 saveItemViewExtraInfo(itemView, ui_widget, ui_parentWidget);
2022 }
2023}
2024
2025/*!
2026 \internal
2027*/
2028void QAbstractFormBuilder::loadListWidgetExtraInfo(DomWidget *ui_widget, QListWidget *listWidget, QWidget *parentWidget)
2029{
2030 Q_UNUSED(parentWidget);
2031 const auto &elementItem = ui_widget->elementItem();
2032 for (DomItem *ui_item : elementItem) {
2033 const DomPropertyHash properties = propertyMap(ui_item->elementProperty());
2034 QListWidgetItem *item = new QListWidgetItem(listWidget);
2035 loadItemPropsNFlags<QListWidgetItem>(this, item, properties);
2036 }
2037
2038 if (auto *currentRow = QFBE::propertyByName(ui_widget->elementProperty(), "currentRow"))
2039 listWidget->setCurrentRow(currentRow->elementNumber());
2040}
2041
2042/*!
2043 \internal
2044*/
2045void QAbstractFormBuilder::loadTreeWidgetExtraInfo(DomWidget *ui_widget, QTreeWidget *treeWidget, QWidget *parentWidget)
2046{
2047 Q_UNUSED(parentWidget);
2048 const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
2049 const QMetaEnum itemFlags_enum = metaEnum<QAbstractFormBuilderGadget>("itemFlags");
2050 const auto &columns = ui_widget->elementColumn();
2051 if (!columns.isEmpty())
2052 treeWidget->setColumnCount(columns.size());
2053
2054 for (qsizetype i = 0, size = columns.size(); i < size; ++i) {
2055 const DomColumn *c = columns.at(i);
2056 const DomPropertyHash properties = propertyMap(c->elementProperty());
2057
2058 DomProperty *p;
2059 QVariant v;
2060
2061 for (const QFormBuilderStrings::RoleNName &it : strings.itemRoles)
2062 if ((p = properties.value(it.second)) &&
2063 (v = toVariant(&QAbstractFormBuilderGadget::staticMetaObject, p)).isValid())
2064 treeWidget->headerItem()->setData(i, it.first, v);
2065
2066 for (const QFormBuilderStrings::TextRoleNName &it : strings.itemTextRoles)
2067 if ((p = properties.value(it.second))) {
2068 v = textBuilder()->loadText(p);
2069 QVariant nativeValue = textBuilder()->toNativeValue(v);
2070 treeWidget->headerItem()->setData(i, it.first.first, qvariant_cast<QString>(nativeValue));
2071 treeWidget->headerItem()->setData(i, it.first.second, v);
2072 }
2073
2074 if ((p = properties.value(QFormBuilderStrings::iconAttribute))) {
2075 v = resourceBuilder()->loadResource(workingDirectory(), p);
2076 QVariant nativeValue = resourceBuilder()->toNativeValue(v);
2077 treeWidget->headerItem()->setIcon(i, qvariant_cast<QIcon>(nativeValue));
2078 treeWidget->headerItem()->setData(i, Qt::DecorationPropertyRole, v);
2079 }
2080 }
2081
2082 QQueue<std::pair<DomItem *, QTreeWidgetItem *> > pendingQueue;
2083 const auto &widgetElementItem = ui_widget->elementItem();
2084 for (DomItem *ui_item : widgetElementItem)
2085 pendingQueue.enqueue(std::make_pair(ui_item, nullptr));
2086
2087 while (!pendingQueue.isEmpty()) {
2088 const std::pair<DomItem *, QTreeWidgetItem *> pair = pendingQueue.dequeue();
2089 const DomItem *domItem = pair.first;
2090 QTreeWidgetItem *parentItem = pair.second;
2091
2092 QTreeWidgetItem *currentItem = nullptr;
2093
2094 if (parentItem)
2095 currentItem = new QTreeWidgetItem(parentItem);
2096 else
2097 currentItem = new QTreeWidgetItem(treeWidget);
2098
2099 const auto &properties = domItem->elementProperty();
2100 int col = -1;
2101 for (DomProperty *property : properties) {
2102 if (property->attributeName() == QFormBuilderStrings::flagsAttribute
2103 && !property->elementSet().isEmpty()) {
2104 currentItem->setFlags(enumKeysToValue<Qt::ItemFlags>(itemFlags_enum, property->elementSet().toLatin1()));
2105 } else if (property->attributeName() == QFormBuilderStrings::textAttribute
2106 && property->elementString()) {
2107 col++;
2108 QVariant textV = textBuilder()->loadText(property);
2109 QVariant nativeValue = textBuilder()->toNativeValue(textV);
2110 currentItem->setText(col, qvariant_cast<QString>(nativeValue));
2111 currentItem->setData(col, Qt::DisplayPropertyRole, textV);
2112 } else if (col >= 0) {
2113 if (property->attributeName() == QFormBuilderStrings::iconAttribute) {
2114 QVariant v = resourceBuilder()->loadResource(workingDirectory(), property);
2115 if (v.isValid()) {
2116 QVariant nativeValue = resourceBuilder()->toNativeValue(v);
2117 currentItem->setIcon(col, qvariant_cast<QIcon>(nativeValue));
2118 currentItem->setData(col, Qt::DecorationPropertyRole, v);
2119 }
2120 } else {
2121 QVariant v;
2122 int role = strings.treeItemRoleHash.value(property->attributeName(), (Qt::ItemDataRole)-1);
2123 if (role >= 0) {
2124 if ((v = toVariant(&QAbstractFormBuilderGadget::staticMetaObject, property)).isValid())
2125 currentItem->setData(col, role, v);
2126 } else {
2127 std::pair<Qt::ItemDataRole, Qt::ItemDataRole> rolePair =
2128 strings.treeItemTextRoleHash.value(property->attributeName(),
2129 std::make_pair((Qt::ItemDataRole)-1, (Qt::ItemDataRole)-1));
2130 if (rolePair.first >= 0) {
2131 QVariant textV = textBuilder()->loadText(property);
2132 QVariant nativeValue = textBuilder()->toNativeValue(textV);
2133 currentItem->setData(col, rolePair.first, qvariant_cast<QString>(nativeValue));
2134 currentItem->setData(col, rolePair.second, textV);
2135 }
2136 }
2137 }
2138 }
2139 }
2140
2141 const auto &elementItem = domItem->elementItem();
2142 for (DomItem *childItem : elementItem)
2143 pendingQueue.enqueue(std::make_pair(childItem, currentItem));
2144
2145 }
2146}
2147
2148/*!
2149 \internal
2150*/
2151void QAbstractFormBuilder::loadTableWidgetExtraInfo(DomWidget *ui_widget, QTableWidget *tableWidget, QWidget *parentWidget)
2152{
2153 Q_UNUSED(parentWidget);
2154
2155 const auto &columns = ui_widget->elementColumn();
2156 if (!columns.isEmpty())
2157 tableWidget->setColumnCount(columns.size());
2158 for (qsizetype i = 0, size = columns.size(); i < size; ++i) {
2159 DomColumn *c = columns.at(i);
2160 const DomPropertyHash properties = propertyMap(c->elementProperty());
2161
2162 if (!properties.isEmpty()) {
2163 QTableWidgetItem *item = new QTableWidgetItem;
2164 loadItemProps(this, item, properties);
2165 tableWidget->setHorizontalHeaderItem(i, item);
2166 }
2167 }
2168
2169 const auto &rows = ui_widget->elementRow();
2170 if (!rows.isEmpty())
2171 tableWidget->setRowCount(rows.size());
2172 for (qsizetype i = 0, size = rows.size(); i < size; ++i) {
2173 const DomRow *r = rows.at(i);
2174 const DomPropertyHash properties = propertyMap(r->elementProperty());
2175
2176 if (!properties.isEmpty()) {
2177 QTableWidgetItem *item = new QTableWidgetItem;
2178 loadItemProps(this, item, properties);
2179 tableWidget->setVerticalHeaderItem(i, item);
2180 }
2181 }
2182
2183 const auto &elementItem = ui_widget->elementItem();
2184 for (DomItem *ui_item : elementItem) {
2185 if (ui_item->hasAttributeRow() && ui_item->hasAttributeColumn()) {
2186 const DomPropertyHash properties = propertyMap(ui_item->elementProperty());
2187 QTableWidgetItem *item = new QTableWidgetItem;
2188 loadItemPropsNFlags(this, item, properties);
2189 tableWidget->setItem(ui_item->attributeRow(), ui_item->attributeColumn(), item);
2190 }
2191 }
2192}
2193
2194/*!
2195 \internal
2196*/
2197void QAbstractFormBuilder::loadComboBoxExtraInfo(DomWidget *ui_widget, QComboBox *comboBox, QWidget *parentWidget)
2198{
2199 Q_UNUSED(parentWidget);
2200 const auto &elementItem = ui_widget->elementItem();
2201 for (DomItem *ui_item : elementItem) {
2202 const auto &properties = ui_item->elementProperty();
2203 QString text;
2204 QIcon icon;
2205 QVariant textData;
2206 QVariant iconData;
2207
2208 DomProperty *p = QFBE::propertyByName(properties, QFormBuilderStrings::textAttribute);
2209 if (p && p->elementString()) {
2210 textData = textBuilder()->loadText(p);
2211 text = qvariant_cast<QString>(textBuilder()->toNativeValue(textData));
2212 }
2213
2214 p = QFBE::propertyByName(properties, QFormBuilderStrings::iconAttribute);
2215 if (p) {
2216 iconData = resourceBuilder()->loadResource(workingDirectory(), p);
2217 icon = qvariant_cast<QIcon>(resourceBuilder()->toNativeValue(iconData));
2218 }
2219
2220 comboBox->addItem(icon, text);
2221 comboBox->setItemData((comboBox->count()-1), iconData, Qt::DecorationPropertyRole);
2222 comboBox->setItemData((comboBox->count()-1), textData, Qt::DisplayPropertyRole);
2223 }
2224
2225 if (auto *currentIndex = currentIndexProperty(ui_widget->elementProperty()))
2226 comboBox->setCurrentIndex(currentIndex->elementNumber());
2227}
2228
2229// Get the button group name out of a widget's attribute list
2230static QString buttonGroupName(const DomWidget *ui_widget)
2231{
2232 const auto &attributes = ui_widget->elementAttribute();
2233 if (attributes.isEmpty())
2234 return QString();
2235 const QString buttonGroupProperty = buttonGroupPropertyC;
2236 for (const DomProperty *p : attributes) {
2237 if (p->attributeName() == buttonGroupProperty)
2238 return p->elementString()->text();
2239 }
2240 return QString();
2241}
2242
2243/*!
2244 \internal
2245 \since 4.5
2246*/
2247
2248void QAbstractFormBuilder::loadButtonExtraInfo(const DomWidget *ui_widget, QAbstractButton *button, QWidget *)
2249{
2250 using ButtonGroupHash = QFormBuilderExtra::ButtonGroupHash;
2251
2252 const QString groupName = buttonGroupName(ui_widget);
2253 if (groupName.isEmpty())
2254 return;
2255 // Find entry
2256 ButtonGroupHash &buttonGroups = d->buttonGroups();
2257 const auto it = buttonGroups.find(groupName);
2258 if (it == buttonGroups.end()) {
2259#ifdef QFORMINTERNAL_NAMESPACE // Suppress the warning when copying in Designer
2260 uiLibWarning(QCoreApplication::translate("QAbstractFormBuilder", "Invalid QButtonGroup reference '%1' referenced by '%2'.").arg(groupName, button->objectName()));
2261#endif
2262 return;
2263 }
2264 // Create button group on demand?
2265 QButtonGroup *&group = it.value().second;
2266 if (group == nullptr) {
2267 group = new QButtonGroup;
2268 group->setObjectName(groupName);
2269 applyProperties(group, it.value().first->elementProperty());
2270 }
2271 group->addButton(button);
2272}
2273
2274/*!
2275 \internal
2276 \since 4.5
2277*/
2278void QAbstractFormBuilder::loadItemViewExtraInfo(DomWidget *ui_widget, QAbstractItemView *itemView,
2279 QWidget *)
2280{
2281 if (QTreeView *treeView = qobject_cast<QTreeView*>(itemView)) {
2282 const auto &allAttributes = ui_widget->elementAttribute();
2283 QList<DomProperty *> headerProperties;
2284 for (QLatin1StringView realPropertyName : itemViewHeaderRealPropertyNames) {
2285 const QString upperPropertyName = QChar(realPropertyName.at(0)).toUpper()
2286 + realPropertyName.mid(1);
2287 const QString fakePropertyName = "header"_L1 + upperPropertyName;
2288 for (DomProperty *attr : allAttributes) {
2289 if (attr->attributeName() == fakePropertyName) {
2290 attr->setAttributeName(realPropertyName);
2291 headerProperties << attr;
2292 }
2293 }
2294 }
2295 applyProperties(treeView->header(), headerProperties);
2296 } else if (QTableView *tableView = qobject_cast<QTableView*>(itemView)) {
2297 const auto &allAttributes = ui_widget->elementAttribute();
2298 for (QLatin1StringView headerPrefix : tableHeaderPrefixes) {
2299 QList<DomProperty*> headerProperties;
2300 for (QLatin1StringView realPropertyName : itemViewHeaderRealPropertyNames) {
2301 const QString upperPropertyName = QChar(realPropertyName.at(0)).toUpper()
2302 + realPropertyName.mid(1);
2303 const QString fakePropertyName = headerPrefix + upperPropertyName;
2304 for (DomProperty *attr : allAttributes) {
2305 if (attr->attributeName() == fakePropertyName) {
2306 attr->setAttributeName(realPropertyName);
2307 headerProperties << attr;
2308 }
2309 }
2310 }
2311 if (headerPrefix == "horizontalHeader"_L1)
2312 applyProperties(tableView->horizontalHeader(), headerProperties);
2313 else
2314 applyProperties(tableView->verticalHeader(), headerProperties);
2315 }
2316 }
2317}
2318
2319/*!
2320 \internal
2321*/
2322void QAbstractFormBuilder::loadExtraInfo(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
2323{
2324 if (false) {
2325#if QT_CONFIG(listwidget)
2326 } else if (QListWidget *listWidget = qobject_cast<QListWidget*>(widget)) {
2327 loadListWidgetExtraInfo(ui_widget, listWidget, parentWidget);
2328#endif
2329#if QT_CONFIG(treewidget)
2330 } else if (QTreeWidget *treeWidget = qobject_cast<QTreeWidget*>(widget)) {
2331 loadTreeWidgetExtraInfo(ui_widget, treeWidget, parentWidget);
2332#endif
2333#if QT_CONFIG(tablewidget)
2334 } else if (QTableWidget *tableWidget = qobject_cast<QTableWidget*>(widget)) {
2335 loadTableWidgetExtraInfo(ui_widget, tableWidget, parentWidget);
2336#endif
2337#if QT_CONFIG(combobox)
2338 } else if (QComboBox *comboBox = qobject_cast<QComboBox*>(widget)) {
2339 if (!QFormBuilderExtra::isQFontComboBox(widget))
2340 loadComboBoxExtraInfo(ui_widget, comboBox, parentWidget);
2341#endif
2342#if QT_CONFIG(tabwidget)
2343 } else if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(widget)) {
2344 if (auto *currentIndex = currentIndexProperty(ui_widget->elementProperty()))
2345 tabWidget->setCurrentIndex(currentIndex->elementNumber());
2346#endif
2347#if QT_CONFIG(stackedwidget)
2348 } else if (QStackedWidget *stackedWidget = qobject_cast<QStackedWidget*>(widget)) {
2349 if (auto *currentIndex = currentIndexProperty(ui_widget->elementProperty()))
2350 stackedWidget->setCurrentIndex(currentIndex->elementNumber());
2351#endif
2352#if QT_CONFIG(toolbox)
2353 } else if (QToolBox *toolBox = qobject_cast<QToolBox*>(widget)) {
2354 if (auto *currentIndex = currentIndexProperty(ui_widget->elementProperty()))
2355 toolBox->setCurrentIndex(currentIndex->elementNumber());
2356 if (auto *tabSpacing = QFBE::propertyByName(ui_widget->elementProperty(), "tabSpacing"))
2357 toolBox->layout()->setSpacing(tabSpacing->elementNumber());
2358#endif
2359 } else if (QAbstractButton *ab = qobject_cast<QAbstractButton *>(widget)) {
2360 loadButtonExtraInfo(ui_widget, ab, parentWidget);
2361 }
2362 if (QAbstractItemView *itemView = qobject_cast<QAbstractItemView *>(widget)) {
2363 loadItemViewExtraInfo(ui_widget, itemView, parentWidget);
2364 }
2365}
2366
2367/*!
2368 Returns the current working directory of the form builder.
2369
2370 \sa setWorkingDirectory()
2371*/
2372QDir QAbstractFormBuilder::workingDirectory() const
2373{
2374 return d->m_workingDirectory;
2375}
2376
2377/*!
2378 Sets the current working directory of the form builder to the
2379 specified \a directory.
2380
2381 \sa workingDirectory()
2382*/
2383void QAbstractFormBuilder::setWorkingDirectory(const QDir &directory)
2384{
2385 d->m_workingDirectory = directory;
2386}
2387
2388/*!
2389 \internal
2390*/
2391DomAction *QAbstractFormBuilder::createDom(QAction *action)
2392{
2393 if (action->parent() == action->menu() || action->isSeparator())
2394 return nullptr;
2395
2396 DomAction *ui_action = new DomAction;
2397 ui_action->setAttributeName(action->objectName());
2398
2399 ui_action->setElementProperty(computeProperties(action));
2400
2401 return ui_action;
2402}
2403
2404/*!
2405 \internal
2406 \since 4.5
2407*/
2408
2409DomButtonGroup *QAbstractFormBuilder::createDom(QButtonGroup *buttonGroup)
2410{
2411 if (buttonGroup->buttons().isEmpty()) // Empty group left over on form?
2412 return nullptr;
2413 DomButtonGroup *domButtonGroup = new DomButtonGroup;
2414 domButtonGroup->setAttributeName(buttonGroup->objectName());
2415
2416 domButtonGroup->setElementProperty(computeProperties(buttonGroup));
2417 return domButtonGroup;
2418}
2419
2420/*!
2421 \internal
2422*/
2423DomActionGroup *QAbstractFormBuilder::createDom(QActionGroup *actionGroup)
2424{
2425 DomActionGroup *ui_action_group = new DomActionGroup;
2426 ui_action_group->setAttributeName(actionGroup->objectName());
2427
2428 ui_action_group->setElementProperty(computeProperties(actionGroup));
2429
2430 QList<DomAction *> ui_actions;
2431
2432 const auto &actions = actionGroup->actions();
2433 ui_actions.reserve(actions.size());
2434 for (QAction *action : actions) {
2435 if (DomAction *ui_action = createDom(action)) {
2436 ui_actions.append(ui_action);
2437 }
2438 }
2439
2440 ui_action_group->setElementAction(ui_actions);
2441
2442 return ui_action_group;
2443}
2444
2445/*!
2446 \internal
2447*/
2448void QAbstractFormBuilder::addMenuAction(QAction *action)
2449{
2450 Q_UNUSED(action);
2451}
2452
2453/*!
2454 \internal
2455*/
2456void QAbstractFormBuilder::reset()
2457{
2458 d->m_laidout.clear();
2459 d->m_actions.clear();
2460 d->m_actionGroups.clear();
2461 d->m_defaultMargin = INT_MIN;
2462 d->m_defaultSpacing = INT_MIN;
2463 d->m_fullyQualifiedEnums = true;
2464}
2465
2466/*!
2467 \internal
2468 Access meta enumeration for Qt::ToolBarArea
2469*/
2470
2471QMetaEnum QAbstractFormBuilder::toolBarAreaMetaEnum()
2472{
2473 return metaEnum<QAbstractFormBuilderGadget>("toolBarArea");
2474}
2475
2476/*!
2477 \internal
2478 Set up a DOM property with icon.
2479*/
2480
2481void QAbstractFormBuilder::setIconProperty(DomProperty &p, const IconPaths &ip) const
2482{
2483 DomResourceIcon *dpi = new DomResourceIcon;
2484
2485 /* TODO
2486 if (!ip.second.isEmpty())
2487 pix->setAttributeResource(ip.second);
2488*/
2489 dpi->setText(ip.first);
2490
2491 p.setAttributeName(QFormBuilderStrings::iconAttribute);
2492 p.setElementIconSet(dpi);
2493}
2494
2495/*!
2496 \internal
2497 Set up a DOM property with pixmap.
2498*/
2499
2500void QAbstractFormBuilder::setPixmapProperty(DomProperty &p, const IconPaths &ip) const
2501{
2502 QFormBuilderExtra::setPixmapProperty(&p, ip);
2503}
2504
2505/*!
2506 \internal
2507 \since 4.4
2508*/
2509
2510DomProperty *QAbstractFormBuilder::saveResource(const QVariant &v) const
2511{
2512 if (v.isNull())
2513 return nullptr;
2514
2515 DomProperty *p = resourceBuilder()->saveResource(workingDirectory(), v);
2516 if (p)
2517 p->setAttributeName(QFormBuilderStrings::iconAttribute);
2518 return p;
2519}
2520
2521/*!
2522 \internal
2523 \since 4.5
2524*/
2525
2526DomProperty *QAbstractFormBuilder::saveText(const QString &attributeName, const QVariant &v) const
2527{
2528 if (v.isNull())
2529 return nullptr;
2530
2531 DomProperty *p = textBuilder()->saveText(v);
2532 if (p)
2533 p->setAttributeName(attributeName);
2534 return p;
2535}
2536
2537/*!
2538 \internal
2539 Return the appropriate DOM pixmap for an image dom property.
2540 From 4.4 - unused
2541*/
2542
2543const DomResourcePixmap *QAbstractFormBuilder::domPixmap(const DomProperty* p) {
2544 switch (p->kind()) {
2545 case DomProperty::IconSet:
2546 qDebug() << "** WARNING QAbstractFormBuilder::domPixmap() called for icon set!";
2547 break;
2548 case DomProperty::Pixmap:
2549 return p->elementPixmap();
2550 default:
2551 break;
2552 }
2553 return nullptr;
2554}
2555
2556/*!
2557 \fn void QAbstractFormBuilder::createConnections ( DomConnections *, QWidget * )
2558 \internal
2559*/
2560
2561/*!
2562 \fn void QAbstractFormBuilder::createCustomWidgets ( DomCustomWidgets * )
2563 \internal
2564*/
2565
2566/*!
2567 \fn void QAbstractFormBuilder::createResources ( DomResources * )
2568 \internal
2569*/
2570
2571/*!
2572 Returns a human-readable description of the last error occurred in load().
2573
2574 \since 5.0
2575 \sa load()
2576*/
2577
2578QString QAbstractFormBuilder::errorString() const
2579{
2580 return d->m_errorString;
2581}
2582
2583QT_END_NAMESPACE
static QString buttonGroupName(const DomWidget *ui_widget)
static void storeItemProps(QAbstractFormBuilder *abstractFormBuilder, const T *item, QList< DomProperty * > *properties, Qt::Alignment defaultAlign=Qt::AlignLeading|Qt::AlignVCenter)
static Qt::Alignment alignmentFromDom(const QString &in)
static constexpr auto buttonGroupPropertyC
static void storeItemFlags(const T *item, QList< DomProperty * > *properties)
static QList< FormBuilderSaveLayoutEntry > saveGridLayoutEntries(QGridLayout *gridLayout)
static void storeItemPropsNFlags(QAbstractFormBuilder *abstractFormBuilder, const T *item, QList< DomProperty * > *properties)
static QString alignmentPrefix(bool fullyQualifiedEnums)
static void loadItemPropsNFlags(QAbstractFormBuilder *abstractFormBuilder, T *item, const QHash< QString, DomProperty * > &properties)
static DomProperty * currentIndexProperty(const QList< DomProperty * > &properties)
static QString alignmentValue(Qt::Alignment a, bool fullyQualifiedEnums)
static constexpr QLatin1StringView itemViewHeaderRealPropertyNames[]
static void loadItemProps(QAbstractFormBuilder *abstractFormBuilder, T *item, const QHash< QString, DomProperty * > &properties)
static const QLatin1StringView tableHeaderPrefixes[]
static QList< FormBuilderSaveLayoutEntry > saveLayoutEntries(const QLayout *layout)
Definition qlist.h:80
friend class QWidget
Definition qpainter.h:431
QFormBuilderExtra QFBE
FormBuilderSaveLayoutEntry(QLayoutItem *li=nullptr)
void setAlignment(Qt::Alignment al)