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