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