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().constData(), 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,
1646 p->elementSet().toLatin1().constData()));
1647 }
1648}
1649
1650/*!
1651 \internal
1652*/
1653void QAbstractFormBuilder::saveTreeWidgetExtraInfo(QTreeWidget *treeWidget, DomWidget *ui_widget, DomWidget *ui_parentWidget)
1654{
1655 Q_UNUSED(ui_parentWidget);
1656
1657 QList<DomColumn *> columns;
1658
1659 const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
1660 // save the header
1661 for (int c = 0; c<treeWidget->columnCount(); ++c) {
1662 auto *column = new DomColumn;
1663
1664 QList<DomProperty*> properties;
1665
1666 for (const QFormBuilderStrings::TextRoleNName &it : strings.itemTextRoles) {
1667 DomProperty *p = saveText(it.second, treeWidget->headerItem()->data(c, it.first.second));
1668 // Prevent uic 4.4.X from crashing if it cannot find a column text
1669 if (!p && it.first.first == Qt::EditRole && it.second == "text"_L1) {
1670 auto *defaultHeader = new DomString;
1671 defaultHeader->setText(QString::number(c + 1));
1672 defaultHeader->setAttributeNotr(u"true"_s);
1673 p = new DomProperty;
1674 p->setAttributeName(it.second);
1675 p->setElementString(defaultHeader);
1676 }
1677 if (p)
1678 properties.append(p);
1679 }
1680
1681 for (const QFormBuilderStrings::RoleNName &it : strings.itemRoles) {
1682 if (const QVariant v = treeWidget->headerItem()->data(c, it.first); v.isValid()) {
1683 if (DomProperty *p = variantToDomProperty(this, &QAbstractFormBuilderGadget::staticMetaObject, it.second, v))
1684 properties.append(p);
1685 }
1686 }
1687
1688 if (DomProperty *p = saveResource(treeWidget->headerItem()->data(c, Qt::DecorationPropertyRole)))
1689 properties.append(p);
1690
1691 column->setElementProperty(properties);
1692 columns.append(column);
1693 }
1694
1695 ui_widget->setElementColumn(columns);
1696
1697 auto items = ui_widget->elementItem();
1698
1699 QQueue<std::pair<QTreeWidgetItem *, DomItem *> > pendingQueue;
1700 for (int i = 0; i < treeWidget->topLevelItemCount(); i++)
1701 pendingQueue.enqueue(std::make_pair(treeWidget->topLevelItem(i), nullptr));
1702
1703 while (!pendingQueue.isEmpty()) {
1704 const std::pair<QTreeWidgetItem *, DomItem *> pair = pendingQueue.dequeue();
1705 QTreeWidgetItem *item = pair.first;
1706 DomItem *parentDomItem = pair.second;
1707
1708 auto *currentDomItem = new DomItem;
1709
1710 QList<DomProperty*> properties;
1711 for (int c = 0; c < treeWidget->columnCount(); c++) {
1712 for (const QFormBuilderStrings::TextRoleNName &it : strings.itemTextRoles) {
1713 if (DomProperty *p = saveText(it.second, item->data(c, it.first.second)))
1714 properties.append(p);
1715 }
1716
1717 for (const QFormBuilderStrings::RoleNName &it : strings.itemRoles) {
1718 if (const QVariant v = item->data(c, it.first); v.isValid()) {
1719 if (DomProperty *p = variantToDomProperty(this, &QAbstractFormBuilderGadget::staticMetaObject, it.second, v))
1720 properties.append(p);
1721 }
1722 }
1723
1724 if (DomProperty *p = saveResource(item->data(c, Qt::DecorationPropertyRole)))
1725 properties.append(p);
1726 }
1727 storeItemFlags(item, &properties);
1728 currentDomItem->setElementProperty(properties);
1729
1730 if (parentDomItem) {
1731 auto childrenItems = parentDomItem->elementItem();
1732 childrenItems.append(currentDomItem);
1733 parentDomItem->setElementItem(childrenItems);
1734 } else
1735 items.append(currentDomItem);
1736
1737 for (int i = 0; i < item->childCount(); i++)
1738 pendingQueue.enqueue(std::make_pair(item->child(i), currentDomItem));
1739 }
1740
1741 ui_widget->setElementItem(items);
1742}
1743
1744/*!
1745 \internal
1746*/
1747void QAbstractFormBuilder::saveTableWidgetExtraInfo(QTableWidget *tableWidget, DomWidget *ui_widget, DomWidget *ui_parentWidget)
1748{
1749 Q_UNUSED(ui_parentWidget);
1750
1751 // save the horizontal header
1752 QList<DomColumn *> columns;
1753 auto *header = tableWidget->horizontalHeader();
1754 for (int c = 0; c < tableWidget->columnCount(); c++) {
1755 QList<DomProperty*> properties;
1756 QTableWidgetItem *item = tableWidget->horizontalHeaderItem(c);
1757 if (item)
1758 storeItemProps(this, item, &properties, header->defaultAlignment());
1759
1760 auto *column = new DomColumn;
1761 column->setElementProperty(properties);
1762 columns.append(column);
1763 }
1764 ui_widget->setElementColumn(columns);
1765
1766 // save the vertical header
1767 QList<DomRow *> rows;
1768 header = tableWidget->verticalHeader();
1769 for (int r = 0; r < tableWidget->rowCount(); r++) {
1770 QList<DomProperty*> properties;
1771 QTableWidgetItem *item = tableWidget->verticalHeaderItem(r);
1772 if (item)
1773 storeItemProps(this, item, &properties, header->defaultAlignment());
1774
1775 auto *row = new DomRow;
1776 row->setElementProperty(properties);
1777 rows.append(row);
1778 }
1779 ui_widget->setElementRow(rows);
1780
1781 auto items = ui_widget->elementItem();
1782 for (int r = 0; r < tableWidget->rowCount(); r++)
1783 for (int c = 0; c < tableWidget->columnCount(); c++) {
1784 QTableWidgetItem *item = tableWidget->item(r, c);
1785 if (item) {
1786 QList<DomProperty*> properties;
1787 storeItemPropsNFlags(this, item, &properties);
1788
1789 auto *domItem = new DomItem;
1790 domItem->setAttributeRow(r);
1791 domItem->setAttributeColumn(c);
1792 domItem->setElementProperty(properties);
1793 items.append(domItem);
1794 }
1795 }
1796
1797 ui_widget->setElementItem(items);
1798}
1799
1800/*!
1801 \internal
1802*/
1803void QAbstractFormBuilder::saveListWidgetExtraInfo(QListWidget *listWidget, DomWidget *ui_widget, DomWidget *ui_parentWidget)
1804{
1805 Q_UNUSED(ui_parentWidget);
1806
1807 auto ui_items = ui_widget->elementItem();
1808 for (int i=0; i<listWidget->count(); ++i) {
1809 QList<DomProperty*> properties;
1810 storeItemPropsNFlags(this, listWidget->item(i), &properties);
1811
1812 auto *ui_item = new DomItem();
1813 ui_item->setElementProperty(properties);
1814 ui_items.append(ui_item);
1815 }
1816
1817 ui_widget->setElementItem(ui_items);
1818}
1819
1820/*!
1821 \internal
1822*/
1823void QAbstractFormBuilder::saveComboBoxExtraInfo(QComboBox *comboBox, DomWidget *ui_widget, DomWidget *ui_parentWidget)
1824{
1825 Q_UNUSED(ui_parentWidget);
1826 auto ui_items = ui_widget->elementItem();
1827
1828 const int count = comboBox->count();
1829 for (int i=0; i < count; ++i) {
1830 // We might encounter items for which both builders return 0 in Designer
1831 // (indicating a custom combo adding items in the constructor). Ignore those.
1832 DomProperty *textProperty = saveText(QFormBuilderStrings::textAttribute,
1833 comboBox->itemData(i, Qt::DisplayPropertyRole));
1834 DomProperty *iconProperty = saveResource(comboBox->itemData(i, Qt::DecorationPropertyRole));
1835 if (textProperty || iconProperty) {
1836 QList<DomProperty*> properties;
1837 if (textProperty)
1838 properties.push_back(textProperty);
1839 if (iconProperty)
1840 properties.push_back(iconProperty);
1841
1842 auto *ui_item = new DomItem();
1843 ui_item->setElementProperty(properties);
1844 ui_items.push_back(ui_item);
1845 }
1846 }
1847
1848 ui_widget->setElementItem(ui_items);
1849}
1850
1851/*!
1852 \internal
1853 \since 4.5
1854*/
1855
1856void QAbstractFormBuilder::saveButtonExtraInfo(const QAbstractButton *widget, DomWidget *ui_widget, DomWidget *)
1857{
1858 using DomPropertyList = QList<DomProperty *>;
1859 if (const QButtonGroup *buttonGroup = widget->group()) {
1860 DomPropertyList attributes = ui_widget->elementAttribute();
1861 auto *domString = new DomString();
1862 domString->setText(buttonGroup->objectName());
1863 domString->setAttributeNotr(u"true"_s);
1864 auto *domProperty = new DomProperty();
1865 domProperty->setAttributeName(buttonGroupPropertyC);
1866 domProperty->setElementString(domString);
1867 attributes += domProperty;
1868 ui_widget->setElementAttribute(attributes);
1869 }
1870}
1871
1873 "horizontalHeader"_L1,
1874 "verticalHeader"_L1,
1875};
1876
1878{
1879 // Special handling for qtableview/qtreeview fake header attributes
1880 "visible"_L1,
1881 "cascadingSectionResizes"_L1,
1882 "minimumSectionSize"_L1, // before defaultSectionSize
1883 "defaultSectionSize"_L1,
1884 "highlightSections"_L1,
1885 "showSortIndicator"_L1,
1886 "stretchLastSection"_L1
1887};
1888
1889/*!
1890 \internal
1891 \since 4.5
1892*/
1893void QAbstractFormBuilder::saveItemViewExtraInfo(const QAbstractItemView *itemView,
1894 DomWidget *ui_widget, DomWidget *)
1895{
1896 if (const auto *treeView = qobject_cast<const QTreeView*>(itemView)) {
1897 auto viewProperties = ui_widget->elementAttribute();
1898 const auto &headerProperties = computeProperties(treeView->header());
1899 for (const QLatin1StringView realPropertyName : itemViewHeaderRealPropertyNames) {
1900 const QString upperPropertyName = QChar(realPropertyName.at(0)).toUpper()
1901 + realPropertyName.mid(1);
1902 const QString fakePropertyName = "header"_L1 + upperPropertyName;
1903 for (DomProperty *property : headerProperties) {
1904 if (property->attributeName() == realPropertyName) {
1905 property->setAttributeName(fakePropertyName);
1906 viewProperties << property;
1907 }
1908 }
1909 }
1910 ui_widget->setElementAttribute(viewProperties);
1911 } else if (const auto *tableView = qobject_cast<const QTableView*>(itemView)) {
1912 auto viewProperties = ui_widget->elementAttribute();
1913 for (QLatin1StringView headerPrefix : tableHeaderPrefixes) {
1914 const auto &headerProperties = headerPrefix == "horizontalHeader"_L1
1915 ? computeProperties(tableView->horizontalHeader())
1916 : computeProperties(tableView->verticalHeader());
1917 for (const QLatin1StringView realPropertyName : itemViewHeaderRealPropertyNames) {
1918 const QString upperPropertyName = QChar(realPropertyName.at(0)).toUpper()
1919 + realPropertyName.mid(1);
1920 const QString fakePropertyName = headerPrefix + upperPropertyName;
1921 for (DomProperty *property : std::as_const(headerProperties)) {
1922 if (property->attributeName() == realPropertyName) {
1923 property->setAttributeName(fakePropertyName);
1924 viewProperties << property;
1925 }
1926 }
1927 }
1928 }
1929 ui_widget->setElementAttribute(viewProperties);
1930 }
1931}
1932
1933/*!
1934 \internal
1935 \since 4.4
1936*/
1937
1938void QAbstractFormBuilder::setResourceBuilder(QResourceBuilder *builder)
1939{
1940 d->setResourceBuilder(builder);
1941}
1942
1943/*!
1944 \internal
1945 \since 4.4
1946*/
1947
1948QResourceBuilder *QAbstractFormBuilder::resourceBuilder() const
1949{
1950 return d->resourceBuilder();
1951}
1952
1953/*!
1954 \internal
1955 \since 4.5
1956*/
1957
1958void QAbstractFormBuilder::setTextBuilder(QTextBuilder *builder)
1959{
1960 d->setTextBuilder(builder);
1961}
1962
1963/*!
1964 \internal
1965 \since 4.5
1966*/
1967
1968QTextBuilder *QAbstractFormBuilder::textBuilder() const
1969{
1970 return d->textBuilder();
1971}
1972
1973/*!
1974 \internal
1975*/
1976void QAbstractFormBuilder::saveExtraInfo(QWidget *widget, DomWidget *ui_widget,
1977 DomWidget *ui_parentWidget)
1978{
1979 if (false) {
1980#if QT_CONFIG(listwidget)
1981 } else if (auto *listWidget = qobject_cast<QListWidget*>(widget)) {
1982 saveListWidgetExtraInfo(listWidget, ui_widget, ui_parentWidget);
1983#endif
1984#if QT_CONFIG(treewidget)
1985 } else if (auto *treeWidget = qobject_cast<QTreeWidget*>(widget)) {
1986 saveTreeWidgetExtraInfo(treeWidget, ui_widget, ui_parentWidget);
1987#endif
1988#if QT_CONFIG(tablewidget)
1989 } else if (auto *tableWidget = qobject_cast<QTableWidget*>(widget)) {
1990 saveTableWidgetExtraInfo(tableWidget, ui_widget, ui_parentWidget);
1991#endif
1992#if QT_CONFIG(combobox)
1993 } else if (auto *comboBox = qobject_cast<QComboBox*>(widget)) {
1994 if (!QFormBuilderExtra::isQFontComboBox(widget))
1995 saveComboBoxExtraInfo(comboBox, ui_widget, ui_parentWidget);
1996#endif
1997 } else if (auto *ab = qobject_cast<QAbstractButton *>(widget)) {
1998 saveButtonExtraInfo(ab, ui_widget, ui_parentWidget);
1999 }
2000 if (auto *itemView = qobject_cast<QAbstractItemView *>(widget)) {
2001 saveItemViewExtraInfo(itemView, ui_widget, ui_parentWidget);
2002 }
2003}
2004
2005/*!
2006 \internal
2007*/
2008void QAbstractFormBuilder::loadListWidgetExtraInfo(DomWidget *ui_widget, QListWidget *listWidget, QWidget *parentWidget)
2009{
2010 Q_UNUSED(parentWidget);
2011 const auto &elementItem = ui_widget->elementItem();
2012 for (DomItem *ui_item : elementItem) {
2013 const DomPropertyHash properties = propertyMap(ui_item->elementProperty());
2014 auto *item = new QListWidgetItem(listWidget);
2015 loadItemPropsNFlags<QListWidgetItem>(this, item, properties);
2016 }
2017
2018 if (auto *currentRow = QFBE::propertyByName(ui_widget->elementProperty(), "currentRow"))
2019 listWidget->setCurrentRow(currentRow->elementNumber());
2020}
2021
2022/*!
2023 \internal
2024*/
2025void QAbstractFormBuilder::loadTreeWidgetExtraInfo(DomWidget *ui_widget, QTreeWidget *treeWidget, QWidget *parentWidget)
2026{
2027 Q_UNUSED(parentWidget);
2028 const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
2029 const QMetaEnum itemFlags_enum = metaEnum<QAbstractFormBuilderGadget>("itemFlags");
2030 const auto &columns = ui_widget->elementColumn();
2031 if (!columns.isEmpty())
2032 treeWidget->setColumnCount(columns.size());
2033
2034 for (qsizetype i = 0, size = columns.size(); i < size; ++i) {
2035 const DomColumn *c = columns.at(i);
2036 const DomPropertyHash properties = propertyMap(c->elementProperty());
2037
2038 for (const QFormBuilderStrings::RoleNName &it : strings.itemRoles) {
2039 if (DomProperty *p = properties.value(it.second)) {
2040 if (const QVariant v = toVariant(&QAbstractFormBuilderGadget::staticMetaObject, p); v.isValid())
2041 treeWidget->headerItem()->setData(i, it.first, v);
2042 }
2043 }
2044
2045 for (const QFormBuilderStrings::TextRoleNName &it : strings.itemTextRoles) {
2046 if (DomProperty *p = properties.value(it.second)) {
2047 const QVariant v = textBuilder()->loadText(p);
2048 QVariant nativeValue = textBuilder()->toNativeValue(v);
2049 treeWidget->headerItem()->setData(i, it.first.first, qvariant_cast<QString>(nativeValue));
2050 treeWidget->headerItem()->setData(i, it.first.second, v);
2051 }
2052 }
2053
2054 if (DomProperty *p = properties.value(QFormBuilderStrings::iconAttribute)) {
2055 const QVariant v = resourceBuilder()->loadResource(workingDirectory(), p);
2056 QVariant nativeValue = resourceBuilder()->toNativeValue(v);
2057 treeWidget->headerItem()->setIcon(i, qvariant_cast<QIcon>(nativeValue));
2058 treeWidget->headerItem()->setData(i, Qt::DecorationPropertyRole, v);
2059 }
2060 }
2061
2062 QQueue<std::pair<DomItem *, QTreeWidgetItem *> > pendingQueue;
2063 const auto &widgetElementItem = ui_widget->elementItem();
2064 for (DomItem *ui_item : widgetElementItem)
2065 pendingQueue.enqueue(std::make_pair(ui_item, nullptr));
2066
2067 while (!pendingQueue.isEmpty()) {
2068 const std::pair<DomItem *, QTreeWidgetItem *> pair = pendingQueue.dequeue();
2069 const DomItem *domItem = pair.first;
2070 QTreeWidgetItem *parentItem = pair.second;
2071
2072 QTreeWidgetItem *currentItem = nullptr;
2073
2074 if (parentItem)
2075 currentItem = new QTreeWidgetItem(parentItem);
2076 else
2077 currentItem = new QTreeWidgetItem(treeWidget);
2078
2079 const auto &properties = domItem->elementProperty();
2080 int col = -1;
2081 for (DomProperty *property : properties) {
2082 if (property->attributeName() == QFormBuilderStrings::flagsAttribute
2083 && !property->elementSet().isEmpty()) {
2084 currentItem->setFlags(enumKeysToValue<Qt::ItemFlags>(
2085 itemFlags_enum, property->elementSet().toLatin1().constData()));
2086 } else if (property->attributeName() == QFormBuilderStrings::textAttribute
2087 && property->elementString()) {
2088 col++;
2089 QVariant textV = textBuilder()->loadText(property);
2090 QVariant nativeValue = textBuilder()->toNativeValue(textV);
2091 currentItem->setText(col, qvariant_cast<QString>(nativeValue));
2092 currentItem->setData(col, Qt::DisplayPropertyRole, textV);
2093 } else if (col >= 0) {
2094 if (property->attributeName() == QFormBuilderStrings::iconAttribute) {
2095 QVariant v = resourceBuilder()->loadResource(workingDirectory(), property);
2096 if (v.isValid()) {
2097 QVariant nativeValue = resourceBuilder()->toNativeValue(v);
2098 currentItem->setIcon(col, qvariant_cast<QIcon>(nativeValue));
2099 currentItem->setData(col, Qt::DecorationPropertyRole, v);
2100 }
2101 } else {
2102 int role = strings.treeItemRoleHash.value(property->attributeName(), (Qt::ItemDataRole)-1);
2103 if (role >= 0) {
2104 if (const QVariant v = toVariant(&QAbstractFormBuilderGadget::staticMetaObject, property); v.isValid())
2105 currentItem->setData(col, role, v);
2106 } else {
2107 std::pair<Qt::ItemDataRole, Qt::ItemDataRole> rolePair =
2108 strings.treeItemTextRoleHash.value(property->attributeName(),
2109 std::make_pair((Qt::ItemDataRole)-1, (Qt::ItemDataRole)-1));
2110 if (rolePair.first >= 0) {
2111 QVariant textV = textBuilder()->loadText(property);
2112 QVariant nativeValue = textBuilder()->toNativeValue(textV);
2113 currentItem->setData(col, rolePair.first, qvariant_cast<QString>(nativeValue));
2114 currentItem->setData(col, rolePair.second, textV);
2115 }
2116 }
2117 }
2118 }
2119 }
2120
2121 const auto &elementItem = domItem->elementItem();
2122 for (DomItem *childItem : elementItem)
2123 pendingQueue.enqueue(std::make_pair(childItem, currentItem));
2124
2125 }
2126}
2127
2128/*!
2129 \internal
2130*/
2131void QAbstractFormBuilder::loadTableWidgetExtraInfo(DomWidget *ui_widget, QTableWidget *tableWidget, QWidget *parentWidget)
2132{
2133 Q_UNUSED(parentWidget);
2134
2135 const auto &columns = ui_widget->elementColumn();
2136 if (!columns.isEmpty())
2137 tableWidget->setColumnCount(columns.size());
2138 for (qsizetype i = 0, size = columns.size(); i < size; ++i) {
2139 DomColumn *c = columns.at(i);
2140 const DomPropertyHash properties = propertyMap(c->elementProperty());
2141
2142 if (!properties.isEmpty()) {
2143 auto *item = new QTableWidgetItem;
2144 loadItemProps(this, item, properties);
2145 tableWidget->setHorizontalHeaderItem(i, item);
2146 }
2147 }
2148
2149 const auto &rows = ui_widget->elementRow();
2150 if (!rows.isEmpty())
2151 tableWidget->setRowCount(rows.size());
2152 for (qsizetype i = 0, size = rows.size(); i < size; ++i) {
2153 const DomRow *r = rows.at(i);
2154 const DomPropertyHash properties = propertyMap(r->elementProperty());
2155
2156 if (!properties.isEmpty()) {
2157 auto *item = new QTableWidgetItem;
2158 loadItemProps(this, item, properties);
2159 tableWidget->setVerticalHeaderItem(i, item);
2160 }
2161 }
2162
2163 const auto &elementItem = ui_widget->elementItem();
2164 for (DomItem *ui_item : elementItem) {
2165 if (ui_item->hasAttributeRow() && ui_item->hasAttributeColumn()) {
2166 const DomPropertyHash properties = propertyMap(ui_item->elementProperty());
2167 auto *item = new QTableWidgetItem;
2168 loadItemPropsNFlags(this, item, properties);
2169 tableWidget->setItem(ui_item->attributeRow(), ui_item->attributeColumn(), item);
2170 }
2171 }
2172}
2173
2174/*!
2175 \internal
2176*/
2177void QAbstractFormBuilder::loadComboBoxExtraInfo(DomWidget *ui_widget, QComboBox *comboBox, QWidget *parentWidget)
2178{
2179 Q_UNUSED(parentWidget);
2180 const auto &elementItem = ui_widget->elementItem();
2181 for (DomItem *ui_item : elementItem) {
2182 const auto &properties = ui_item->elementProperty();
2183 QString text;
2184 QIcon icon;
2185 QVariant textData;
2186 QVariant iconData;
2187
2188 DomProperty *p = QFBE::propertyByName(properties, QFormBuilderStrings::textAttribute);
2189 if (p && p->elementString()) {
2190 textData = textBuilder()->loadText(p);
2191 text = qvariant_cast<QString>(textBuilder()->toNativeValue(textData));
2192 }
2193
2194 p = QFBE::propertyByName(properties, QFormBuilderStrings::iconAttribute);
2195 if (p) {
2196 iconData = resourceBuilder()->loadResource(workingDirectory(), p);
2197 icon = qvariant_cast<QIcon>(resourceBuilder()->toNativeValue(iconData));
2198 }
2199
2200 comboBox->addItem(icon, text);
2201 comboBox->setItemData((comboBox->count()-1), iconData, Qt::DecorationPropertyRole);
2202 comboBox->setItemData((comboBox->count()-1), textData, Qt::DisplayPropertyRole);
2203 }
2204
2205 if (auto *currentIndex = currentIndexProperty(ui_widget->elementProperty()))
2206 comboBox->setCurrentIndex(currentIndex->elementNumber());
2207}
2208
2209// Get the button group name out of a widget's attribute list
2210static QString buttonGroupName(const DomWidget *ui_widget)
2211{
2212 const auto &attributes = ui_widget->elementAttribute();
2213 if (attributes.isEmpty())
2214 return {};
2215 const QString buttonGroupProperty = buttonGroupPropertyC;
2216 for (const DomProperty *p : attributes) {
2217 if (p->attributeName() == buttonGroupProperty)
2218 return p->elementString()->text();
2219 }
2220 return QString();
2221}
2222
2223/*!
2224 \internal
2225 \since 4.5
2226*/
2227
2228void QAbstractFormBuilder::loadButtonExtraInfo(const DomWidget *ui_widget, QAbstractButton *button, QWidget *)
2229{
2230 using ButtonGroupHash = QFormBuilderExtra::ButtonGroupHash;
2231
2232 const QString groupName = buttonGroupName(ui_widget);
2233 if (groupName.isEmpty())
2234 return;
2235 // Find entry
2236 ButtonGroupHash &buttonGroups = d->buttonGroups();
2237 const auto it = buttonGroups.find(groupName);
2238 if (it == buttonGroups.end()) {
2239#ifdef QFORMINTERNAL_NAMESPACE // Suppress the warning when copying in Designer
2240 uiLibWarning(QCoreApplication::translate("QAbstractFormBuilder", "Invalid QButtonGroup reference '%1' referenced by '%2'.").arg(groupName, button->objectName()));
2241#endif
2242 return;
2243 }
2244 // Create button group on demand?
2245 QButtonGroup *&group = it.value().second;
2246 if (group == nullptr) {
2247 group = new QButtonGroup;
2248 group->setObjectName(groupName);
2249 applyProperties(group, it.value().first->elementProperty());
2250 }
2251 group->addButton(button);
2252}
2253
2254/*!
2255 \internal
2256 \since 4.5
2257*/
2258void QAbstractFormBuilder::loadItemViewExtraInfo(DomWidget *ui_widget, QAbstractItemView *itemView,
2259 QWidget *)
2260{
2261 if (auto *treeView = qobject_cast<QTreeView*>(itemView)) {
2262 const auto &allAttributes = ui_widget->elementAttribute();
2263 QList<DomProperty *> headerProperties;
2264 for (QLatin1StringView realPropertyName : itemViewHeaderRealPropertyNames) {
2265 const QString upperPropertyName = QChar(realPropertyName.at(0)).toUpper()
2266 + realPropertyName.mid(1);
2267 const QString fakePropertyName = "header"_L1 + upperPropertyName;
2268 for (DomProperty *attr : allAttributes) {
2269 if (attr->attributeName() == fakePropertyName) {
2270 attr->setAttributeName(realPropertyName);
2271 headerProperties << attr;
2272 }
2273 }
2274 }
2275 applyProperties(treeView->header(), headerProperties);
2276 } else if (auto *tableView = qobject_cast<QTableView*>(itemView)) {
2277 const auto &allAttributes = ui_widget->elementAttribute();
2278 for (QLatin1StringView headerPrefix : tableHeaderPrefixes) {
2279 QList<DomProperty*> headerProperties;
2280 for (QLatin1StringView realPropertyName : itemViewHeaderRealPropertyNames) {
2281 const QString upperPropertyName = QChar(realPropertyName.at(0)).toUpper()
2282 + realPropertyName.mid(1);
2283 const QString fakePropertyName = headerPrefix + upperPropertyName;
2284 for (DomProperty *attr : allAttributes) {
2285 if (attr->attributeName() == fakePropertyName) {
2286 attr->setAttributeName(realPropertyName);
2287 headerProperties << attr;
2288 }
2289 }
2290 }
2291 if (headerPrefix == "horizontalHeader"_L1)
2292 applyProperties(tableView->horizontalHeader(), headerProperties);
2293 else
2294 applyProperties(tableView->verticalHeader(), headerProperties);
2295 }
2296 }
2297}
2298
2299/*!
2300 \internal
2301*/
2302void QAbstractFormBuilder::loadExtraInfo(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
2303{
2304 if (false) {
2305#if QT_CONFIG(listwidget)
2306 } else if (auto *listWidget = qobject_cast<QListWidget*>(widget)) {
2307 loadListWidgetExtraInfo(ui_widget, listWidget, parentWidget);
2308#endif
2309#if QT_CONFIG(treewidget)
2310 } else if (auto *treeWidget = qobject_cast<QTreeWidget*>(widget)) {
2311 loadTreeWidgetExtraInfo(ui_widget, treeWidget, parentWidget);
2312#endif
2313#if QT_CONFIG(tablewidget)
2314 } else if (auto *tableWidget = qobject_cast<QTableWidget*>(widget)) {
2315 loadTableWidgetExtraInfo(ui_widget, tableWidget, parentWidget);
2316#endif
2317#if QT_CONFIG(combobox)
2318 } else if (auto *comboBox = qobject_cast<QComboBox*>(widget)) {
2319 if (!QFormBuilderExtra::isQFontComboBox(widget))
2320 loadComboBoxExtraInfo(ui_widget, comboBox, parentWidget);
2321#endif
2322#if QT_CONFIG(tabwidget)
2323 } else if (auto *tabWidget = qobject_cast<QTabWidget*>(widget)) {
2324 if (auto *currentIndex = currentIndexProperty(ui_widget->elementProperty()))
2325 tabWidget->setCurrentIndex(currentIndex->elementNumber());
2326#endif
2327#if QT_CONFIG(stackedwidget)
2328 } else if (auto *stackedWidget = qobject_cast<QStackedWidget*>(widget)) {
2329 if (auto *currentIndex = currentIndexProperty(ui_widget->elementProperty()))
2330 stackedWidget->setCurrentIndex(currentIndex->elementNumber());
2331#endif
2332#if QT_CONFIG(toolbox)
2333 } else if (auto *toolBox = qobject_cast<QToolBox*>(widget)) {
2334 if (auto *currentIndex = currentIndexProperty(ui_widget->elementProperty()))
2335 toolBox->setCurrentIndex(currentIndex->elementNumber());
2336 if (auto *tabSpacing = QFBE::propertyByName(ui_widget->elementProperty(), "tabSpacing"))
2337 toolBox->layout()->setSpacing(tabSpacing->elementNumber());
2338#endif
2339 } else if (auto *ab = qobject_cast<QAbstractButton *>(widget)) {
2340 loadButtonExtraInfo(ui_widget, ab, parentWidget);
2341 }
2342 if (auto *itemView = qobject_cast<QAbstractItemView *>(widget)) {
2343 loadItemViewExtraInfo(ui_widget, itemView, parentWidget);
2344 }
2345}
2346
2347/*!
2348 Returns the current working directory of the form builder.
2349
2350 \sa setWorkingDirectory()
2351*/
2352QDir QAbstractFormBuilder::workingDirectory() const
2353{
2354 return d->m_workingDirectory;
2355}
2356
2357/*!
2358 Sets the current working directory of the form builder to the
2359 specified \a directory.
2360
2361 \sa workingDirectory()
2362*/
2363void QAbstractFormBuilder::setWorkingDirectory(const QDir &directory)
2364{
2365 d->m_workingDirectory = directory;
2366}
2367
2368/*!
2369 \internal
2370*/
2371DomAction *QAbstractFormBuilder::createDom(QAction *action)
2372{
2373 if (action->parent() == action->menu() || action->isSeparator())
2374 return nullptr;
2375
2376 auto *ui_action = new DomAction;
2377 ui_action->setAttributeName(action->objectName());
2378
2379 ui_action->setElementProperty(computeProperties(action));
2380
2381 return ui_action;
2382}
2383
2384/*!
2385 \internal
2386 \since 4.5
2387*/
2388
2389DomButtonGroup *QAbstractFormBuilder::createDom(QButtonGroup *buttonGroup)
2390{
2391 if (buttonGroup->buttons().isEmpty()) // Empty group left over on form?
2392 return nullptr;
2393 auto *domButtonGroup = new DomButtonGroup;
2394 domButtonGroup->setAttributeName(buttonGroup->objectName());
2395
2396 domButtonGroup->setElementProperty(computeProperties(buttonGroup));
2397 return domButtonGroup;
2398}
2399
2400/*!
2401 \internal
2402*/
2403DomActionGroup *QAbstractFormBuilder::createDom(QActionGroup *actionGroup)
2404{
2405 auto *ui_action_group = new DomActionGroup;
2406 ui_action_group->setAttributeName(actionGroup->objectName());
2407
2408 ui_action_group->setElementProperty(computeProperties(actionGroup));
2409
2410 QList<DomAction *> ui_actions;
2411
2412 const auto &actions = actionGroup->actions();
2413 ui_actions.reserve(actions.size());
2414 for (QAction *action : actions) {
2415 if (DomAction *ui_action = createDom(action)) {
2416 ui_actions.append(ui_action);
2417 }
2418 }
2419
2420 ui_action_group->setElementAction(ui_actions);
2421
2422 return ui_action_group;
2423}
2424
2425/*!
2426 \internal
2427*/
2428void QAbstractFormBuilder::addMenuAction(QAction *action)
2429{
2430 Q_UNUSED(action);
2431}
2432
2433/*!
2434 \internal
2435*/
2436void QAbstractFormBuilder::reset()
2437{
2438 d->m_laidout.clear();
2439 d->m_actions.clear();
2440 d->m_actionGroups.clear();
2441 d->m_defaultMargin = INT_MIN;
2442 d->m_defaultSpacing = INT_MIN;
2443 d->m_fullyQualifiedEnums = true;
2444}
2445
2446/*!
2447 \internal
2448 Access meta enumeration for Qt::ToolBarArea
2449*/
2450
2451QMetaEnum QAbstractFormBuilder::toolBarAreaMetaEnum()
2452{
2453 return metaEnum<QAbstractFormBuilderGadget>("toolBarArea");
2454}
2455
2456/*!
2457 \internal
2458 Set up a DOM property with icon.
2459*/
2460
2461void QAbstractFormBuilder::setIconProperty(DomProperty &p, const IconPaths &ip) const
2462{
2463 auto *dpi = new DomResourceIcon;
2464
2465 /* TODO
2466 if (!ip.second.isEmpty())
2467 pix->setAttributeResource(ip.second);
2468*/
2469 dpi->setText(ip.first);
2470
2471 p.setAttributeName(QFormBuilderStrings::iconAttribute);
2472 p.setElementIconSet(dpi);
2473}
2474
2475/*!
2476 \internal
2477 Set up a DOM property with pixmap.
2478*/
2479
2480void QAbstractFormBuilder::setPixmapProperty(DomProperty &p, const IconPaths &ip) const
2481{
2482 QFormBuilderExtra::setPixmapProperty(&p, ip);
2483}
2484
2485/*!
2486 \internal
2487 \since 4.4
2488*/
2489
2490DomProperty *QAbstractFormBuilder::saveResource(const QVariant &v) const
2491{
2492 if (v.isNull())
2493 return nullptr;
2494
2495 DomProperty *p = resourceBuilder()->saveResource(workingDirectory(), v);
2496 if (p)
2497 p->setAttributeName(QFormBuilderStrings::iconAttribute);
2498 return p;
2499}
2500
2501/*!
2502 \internal
2503 \since 4.5
2504*/
2505
2506DomProperty *QAbstractFormBuilder::saveText(const QString &attributeName, const QVariant &v) const
2507{
2508 if (v.isNull())
2509 return nullptr;
2510
2511 DomProperty *p = textBuilder()->saveText(v);
2512 if (p)
2513 p->setAttributeName(attributeName);
2514 return p;
2515}
2516
2517/*!
2518 \internal
2519 Return the appropriate DOM pixmap for an image dom property.
2520 From 4.4 - unused
2521*/
2522
2523const DomResourcePixmap *QAbstractFormBuilder::domPixmap(const DomProperty* p) {
2524 switch (p->kind()) {
2525 case DomProperty::IconSet:
2526 qDebug() << "** WARNING QAbstractFormBuilder::domPixmap() called for icon set!";
2527 break;
2528 case DomProperty::Pixmap:
2529 return p->elementPixmap();
2530 default:
2531 break;
2532 }
2533 return nullptr;
2534}
2535
2536/*!
2537 \fn void QAbstractFormBuilder::createConnections ( DomConnections *, QWidget * )
2538 \internal
2539*/
2540
2541/*!
2542 \fn void QAbstractFormBuilder::createCustomWidgets ( DomCustomWidgets * )
2543 \internal
2544*/
2545
2546/*!
2547 \fn void QAbstractFormBuilder::createResources ( DomResources * )
2548 \internal
2549*/
2550
2551/*!
2552 Returns a human-readable description of the last error occurred in load().
2553
2554 \since 5.0
2555 \sa load()
2556*/
2557
2558QString QAbstractFormBuilder::errorString() const
2559{
2560 return d->m_errorString;
2561}
2562
2563QT_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)