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

source code of qttools/src/designer/src/lib/uilib/abstractformbuilder.cpp