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