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
104 Q_DECLARE_METATYPE(QWidgetList)
105
106 static const char *buttonGroupPropertyC = "buttonGroup";
107
108 QT_BEGIN_NAMESPACE
109
110 #ifdef QFORMINTERNAL_NAMESPACE
111 using namespace QFormInternal;
112 #endif
113
114 class QFriendlyLayout: public QLayout
115 {
116 public:
QFriendlyLayout()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.*/
QAbstractFormBuilder()168 QAbstractFormBuilder::QAbstractFormBuilder() : d(new QFormBuilderExtra)
169 {
170 setResourceBuilder(new QResourceBuilder());
171 setTextBuilder(new QTextBuilder());
172 }
173
174 /*!
175 Destroys the form builder.*/
176 QAbstractFormBuilder::~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 */
load(QIODevice * dev,QWidget * parentWidget)186 QWidget *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.data(), parentWidget);
192 if (!widget && d->m_errorString.isEmpty())
193 d->m_errorString = QFormBuilderExtra::msgInvalidUiFile();
194 return widget;
195 }
196
197 /*!
198 \internal
199 */
create(DomUI * ui,QWidget * parentWidget)200 QWidget *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(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, 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
initialize(const DomUI * ui)247 void 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(w->elementClass(), w);
256 }
257 }
258
259 /*!
260 \internal
261 */
create(DomWidget * ui_widget,QWidget * parentWidget)262 QWidget *QAbstractFormBuilder::create(DomWidget *ui_widget, QWidget *parentWidget)
263 {
264 QWidget *w = createWidget(ui_widget->attributeClass(), parentWidget, ui_widget->attributeName());
265 if (!w)
266 return nullptr;
267
268 applyProperties(w, ui_widget->elementProperty());
269
270 const auto &elementAction = ui_widget->elementAction();
271 for (DomAction *ui_action : elementAction) {
272 QAction *child_action = create(ui_action, 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, 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_child, w)) {
286 children += child;
287 } else {
288 const QString className = ui_child->elementClass().value(0);
289 uiLibWarning(QCoreApplication::translate("QAbstractFormBuilder", "The creation of a widget of the class '%1' failed.").arg(className));
290 }
291 }
292
293 const auto &elementLayout = ui_widget->elementLayout();
294 for (DomLayout *ui_lay : elementLayout) {
295 QLayout *child_lay = create(ui_lay, nullptr, 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(sep);
308 addMenuAction(sep);
309 } else if (QAction *a = d->m_actions.value(name)) {
310 w->addAction(a);
311 } else if (QActionGroup *g = d->m_actionGroups.value(name)) {
312 w->addActions(g->actions());
313 } else if (QMenu *menu = w->findChild<QMenu*>(name)) {
314 w->addAction(menu->menuAction());
315 addMenuAction(menu->menuAction());
316 }
317 }
318 }
319
320 loadExtraInfo(ui_widget, w, parentWidget);
321 addItem(ui_widget, w, parentWidget);
322
323 if (qobject_cast<QDialog *>(w) && parentWidget)
324 w->setAttribute(Qt::WA_Moved, 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>(w->property("_q_zOrder"));
329 for (const QString &widgetName : zOrderNames) {
330 if (QWidget *child = w->findChild<QWidget*>(widgetName)) {
331 if (child->parentWidget() == w) {
332 zOrder.removeAll(child);
333 zOrder.append(child);
334 child->raise();
335 }
336 }
337 }
338 w->setProperty("_q_zOrder", QVariant::fromValue(zOrder));
339 }
340
341 return w;
342 }
343
344 /*!
345 \internal
346 */
create(DomAction * ui_action,QObject * parent)347 QAction *QAbstractFormBuilder::create(DomAction *ui_action, QObject *parent)
348 {
349 QAction *a = createAction(parent, ui_action->attributeName());
350 if (!a)
351 return nullptr;
352
353 d->m_actions.insert(ui_action->attributeName(), a);
354 applyProperties(a, ui_action->elementProperty());
355 return a;
356 }
357
358 /*!
359 \internal
360 */
create(DomActionGroup * ui_action_group,QObject * parent)361 QActionGroup *QAbstractFormBuilder::create(DomActionGroup *ui_action_group, QObject *parent)
362 {
363 QActionGroup *a = createActionGroup(parent, ui_action_group->attributeName());
364 if (!a)
365 return nullptr;
366 d->m_actionGroups.insert(ui_action_group->attributeName(), a);
367 applyProperties(a, 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, 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(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.
toolbarAreaFromDOMAttributes(const DomPropertyHash & attributes)386 Qt::ToolBarArea QAbstractFormBuilder::toolbarAreaFromDOMAttributes(const DomPropertyHash &attributes) {
387 const DomProperty *attr = attributes.value(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>("toolBarArea",
395 attr->elementEnum().toLatin1().constData());
396 default:
397 break;
398 }
399 return Qt::TopToolBarArea;
400 }
401
402 /*!
403 \internal
404 */
addItem(DomWidget * ui_widget,QWidget * widget,QWidget * parentWidget)405 bool QAbstractFormBuilder::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
406 {
407 const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
408 const DomPropertyHash attributes = propertyMap(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(parentWidget, addPageMethod.toUtf8().constData(), Qt::DirectConnection, Q_ARG(QWidget*, widget));
418 }
419
420 if (QMainWindow *mw = qobject_cast<QMainWindow*>(parentWidget)) {
421
422 #if QT_CONFIG(menubar)
423 // the menubar
424 if (QMenuBar *menuBar = qobject_cast<QMenuBar*>(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*>(widget)) {
433 mw->addToolBar(toolbarAreaFromDOMAttributes(attributes), toolBar);
434 // check break
435 if (const DomProperty *attr = attributes.value(strings.toolBarBreakAttribute))
436 if (attr->elementBool() == strings.trueValue)
437 mw->insertToolBarBreak (toolBar);
438
439 return true;
440 }
441 #endif
442
443 #if QT_CONFIG(statusbar)
444 // statusBar
445 if (QStatusBar *statusBar = qobject_cast<QStatusBar*>(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*>(widget)) {
454 if (const DomProperty *attr = attributes.value(strings.dockWidgetAreaAttribute)) {
455 Qt::DockWidgetArea area = static_cast<Qt::DockWidgetArea>(attr->elementNumber());
456 if (!dockWidget->isAreaAllowed(area)) {
457 if (dockWidget->isAreaAllowed(Qt::LeftDockWidgetArea))
458 area = Qt::LeftDockWidgetArea;
459 else if (dockWidget->isAreaAllowed(Qt::RightDockWidgetArea))
460 area = Qt::RightDockWidgetArea;
461 else if (dockWidget->isAreaAllowed(Qt::TopDockWidgetArea))
462 area = Qt::TopDockWidgetArea;
463 else if (dockWidget->isAreaAllowed(Qt::BottomDockWidgetArea))
464 area = Qt::BottomDockWidgetArea;
465 }
466 mw->addDockWidget(area, dockWidget);
467 } else {
468 mw->addDockWidget(Qt::LeftDockWidgetArea, 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*>(parentWidget)) {
482 widget->setParent(nullptr);
483
484 const int tabIndex = tabWidget->count();
485 if (const DomProperty *titleP = attributes.value(strings.titleAttribute, 0))
486 tabWidget->addTab(widget, toString(titleP->elementString()));
487 else
488 tabWidget->addTab(widget, strings.defaultTitle);
489
490 if (DomProperty *picon = attributes.value(strings.iconAttribute)) {
491 QVariant v = resourceBuilder()->loadResource(workingDirectory(), picon);
492 QVariant nativeValue = resourceBuilder()->toNativeValue(v);
493 tabWidget->setTabIcon(tabIndex, qvariant_cast<QIcon>(nativeValue));
494 }
495
496 #if QT_CONFIG(tooltip)
497 if (const DomProperty *ptoolTip = attributes.value(strings.toolTipAttribute)) {
498 tabWidget->setTabToolTip(tabIndex, toString(ptoolTip->elementString()));
499 }
500 #endif
501
502 #if QT_CONFIG(whatsthis)
503 if (const DomProperty *pwhatsThis = attributes.value(strings.whatsThisAttribute)) {
504 tabWidget->setTabWhatsThis(tabIndex, toString(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*>(parentWidget)) {
514 const int tabIndex = toolBox->count();
515 if (const DomProperty *labelP = attributes.value(strings.labelAttribute, 0))
516 toolBox->addItem(widget, toString(labelP->elementString()));
517 else
518 toolBox->addItem(widget, strings.defaultTitle);
519
520 if (DomProperty *picon = attributes.value(strings.iconAttribute)) {
521 QVariant v = resourceBuilder()->loadResource(workingDirectory(), picon);
522 QVariant nativeValue = resourceBuilder()->toNativeValue(v);
523 toolBox->setItemIcon(tabIndex, qvariant_cast<QIcon>(nativeValue));
524 }
525
526 #if QT_CONFIG(tooltip)
527 if (const DomProperty *ptoolTip = attributes.value(strings.toolTipAttribute)) {
528 toolBox->setItemToolTip(tabIndex, toString(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*>(parentWidget)) {
538 stackedWidget->addWidget(widget);
539 return true;
540 }
541 #endif
542
543 #if QT_CONFIG(splitter)
544 else if (QSplitter *splitter = qobject_cast<QSplitter*>(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*>(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*>(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*>(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 *>(parentWidget)) {
573 QWizardPage *page = qobject_cast<QWizardPage*>(widget);
574 if (!page) {
575 uiLibWarning(QCoreApplication::translate("QAbstractFormBuilder", "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 */
layoutInfo(DomLayout * ui_layout,QObject * parent,int * margin,int * spacing)588 void 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(ui_layout->elementProperty());
593
594 int mar = INT_MIN;
595 int spac = INT_MIN;
596 if (const DomProperty *p = properties.value(strings.marginProperty, 0))
597 mar = p->elementNumber();
598
599 if (const DomProperty *p = properties.value(strings.spacingProperty, 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 */
create(DomLayout * ui_layout,QLayout * parentLayout,QWidget * parentWidget)636 QLayout *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(ui_layout->attributeClass(), p, 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*>(parentWidget->layout());
659 if (!box) { // only QBoxLayout is supported
660 const QString widgetClass = QString::fromUtf8(parentWidget->metaObject()->className());
661 const QString layoutClass = QString::fromUtf8(parentWidget->layout()->metaObject()->className());
662 const QString msg = QCoreApplication::translate("QAbstractFormBuilder", "Attempt to add a layout to a widget '%1' (%2) which already has a layout of non-box type %3.\n"
663 "This indicates an inconsistency in the ui-file.").
664 arg(parentWidget->objectName(), widgetClass, layoutClass);
665 uiLibWarning(msg);
666 return nullptr;
667 }
668 box->addLayout(layout);
669 }
670
671 int margin = INT_MIN, spacing = INT_MIN;
672 layoutInfo(ui_layout, p, &margin, &spacing);
673
674 if (margin != INT_MIN) {
675 layout->setContentsMargins(margin, margin, margin, 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, &top, &right, &bottom);
681
682 const DomPropertyHash properties = propertyMap(ui_layout->elementProperty());
683
684 if (const DomProperty *p = properties.value(strings.leftMarginProperty, 0))
685 left = p->elementNumber();
686
687 if (const DomProperty *p = properties.value(strings.topMarginProperty, 0))
688 top = p->elementNumber();
689
690 if (const DomProperty *p = properties.value(strings.rightMarginProperty, 0))
691 right = p->elementNumber();
692
693 if (const DomProperty *p = properties.value(strings.bottomMarginProperty, 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 *>(layout);
703 if (grid) {
704 const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
705 const DomPropertyHash properties = propertyMap(ui_layout->elementProperty());
706
707 if (const DomProperty *p = properties.value(strings.horizontalSpacingProperty, 0))
708 grid->setHorizontalSpacing(p->elementNumber());
709 if (const DomProperty *p = properties.value(strings.verticalSpacingProperty, 0))
710 grid->setVerticalSpacing(p->elementNumber());
711 }
712 }
713
714 applyProperties(layout, ui_layout->elementProperty());
715
716 const auto &elementItem = ui_layout->elementItem();
717 for (DomLayoutItem *ui_item : elementItem) {
718 if (QLayoutItem *item = create(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*>(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*>(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)
formLayoutRole(int column,int colspan)749 static 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
alignmentValue(Qt::Alignment a)757 static 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
alignmentFromDom(const QString & in)795 static inline Qt::Alignment alignmentFromDom(const QString &in)
796 {
797 Qt::Alignment rc;
798 if (!in.isEmpty()) {
799 const auto flags = in.splitRef(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 */
addItem(DomLayoutItem * ui_item,QLayoutItem * item,QLayout * layout)824 bool 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(item->widget());
830 } else if (item->layout()) {
831 static_cast<QFriendlyLayout*>(layout)->addChildLayout(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*>(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, ui_item->attributeRow(), ui_item->attributeColumn(),
842 rowSpan, colSpan, item->alignment());
843 return true;
844 }
845 #if QT_CONFIG(formlayout)
846 if (QFormLayout *form = qobject_cast<QFormLayout *>(layout)) {
847 const int row = ui_item->attributeRow();
848 const int colSpan = ui_item->hasAttributeColSpan() ? ui_item->attributeColSpan() : 1;
849 form->setItem(row, formLayoutRole(ui_item->attributeColumn(), colSpan), item);
850 return true;
851 }
852
853 #endif
854 layout->addItem(item);
855 return true;
856 }
857
858 /*!
859 \internal
860 */
create(DomLayoutItem * ui_layoutItem,QLayout * layout,QWidget * parentWidget)861 QLayoutItem *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_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(ui_layoutItem->attributeAlignment()));
872 return item;
873 }
874 qWarning() << QCoreApplication::translate("QAbstractFormBuilder", "Empty widget item in %1 '%2'.").arg(QString::fromUtf8(layout->metaObject()->className()), 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(&QAbstractFormBuilderGadget::staticMetaObject, 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_layoutItem->elementLayout(), layout, parentWidget);
910
911 default:
912 break;
913 }
914
915 return nullptr;
916 }
917
918 /*!
919 \internal
920 */
applyProperties(QObject * o,const QList<DomProperty * > & properties)921 void QAbstractFormBuilder::applyProperties(QObject *o, const QList<DomProperty*> &properties)
922 {
923 for (DomProperty *p : properties) {
924 const QVariant v = toVariant(o->metaObject(), p);
925 if (!v.isNull()) {
926 QString attributeName = p->attributeName();
927 if (attributeName == QLatin1String("numDigits") && o->inherits("QLCDNumber")) // Deprecated in Qt 4, removed in Qt 5.
928 attributeName = QLatin1String("digitCount");
929 if (!d->applyPropertyInternally(o, attributeName, v))
930 o->setProperty(attributeName.toUtf8(), 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
applyPropertyInternally(QObject * o,const QString & propertyName,const QVariant & value)942 bool 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
toVariant(const QMetaObject * meta,DomProperty * p)951 QVariant QAbstractFormBuilder::toVariant(const QMetaObject *meta, DomProperty *p)
952 {
953 return domPropertyToVariant(this, meta, p);
954 }
955
956 /*!
957 \internal
958 */
setupColorGroup(QPalette & palette,QPalette::ColorGroup colorGroup,DomColorGroup * group)959 void QAbstractFormBuilder::setupColorGroup(QPalette &palette, QPalette::ColorGroup colorGroup,
960 DomColorGroup *group)
961 {
962 QFormBuilderExtra::setupColorGroup(&palette, colorGroup, group);
963 }
964
965 /*!
966 \internal
967 */
saveColorGroup(const QPalette & palette)968 DomColorGroup *QAbstractFormBuilder::saveColorGroup(const QPalette &palette)
969 {
970 return QFormBuilderExtra::saveColorGroup(palette,
971 palette.currentColorGroup());
972 }
973
974 /*!
975 \internal
976 */
setupBrush(DomBrush * brush)977 QBrush QAbstractFormBuilder::setupBrush(DomBrush *brush)
978 {
979 return QFormBuilderExtra::setupBrush(brush);
980 }
981
saveBrush(const QBrush & br)982 DomBrush *QAbstractFormBuilder::saveBrush(const QBrush &br)
983 {
984 return QFormBuilderExtra::saveBrush(br);
985 }
986
987 /*!
988 \internal
989 */
createWidget(const QString & widgetName,QWidget * parentWidget,const QString & name)990 QWidget *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 */
createLayout(const QString & layoutName,QObject * parent,const QString & name)1001 QLayout *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 */
createAction(QObject * parent,const QString & name)1012 QAction *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 */
createActionGroup(QObject * parent,const QString & name)1022 QActionGroup *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 */
save(QIODevice * dev,QWidget * widget)1052 void QAbstractFormBuilder::save(QIODevice *dev, QWidget *widget)
1053 {
1054 DomWidget *ui_widget = createDom(widget, 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 */
saveDom(DomUI * ui,QWidget * widget)1078 void 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(widget))
1098 ui->setElementButtonGroups(ui_buttonGroups);
1099 }
1100
1101 /*!
1102 \internal
1103 */
saveConnections()1104 DomConnections *QAbstractFormBuilder::saveConnections()
1105 {
1106 return new DomConnections;
1107 }
1108
1109 /*!
1110 \internal
1111 */
1112
createDom(QWidget * widget,DomWidget * ui_parentWidget,bool recursive)1113 DomWidget *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(widget));
1118
1119 if (recursive) {
1120 if (QLayout *layout = widget->layout()) {
1121 if (DomLayout *ui_layout = createDom(layout, nullptr, ui_parentWidget)) {
1122 QVector<DomLayout *> ui_layouts;
1123 ui_layouts.append(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*>(widget)) {
1141 const int count = splitter->count();
1142 for (int i = 0; i < count; ++i)
1143 children.append(splitter->widget(i));
1144 } else
1145 #endif
1146 {
1147 QObjectList childObjects = widget->children();
1148
1149 const QWidgetList list = qvariant_cast<QWidgetList>(widget->property("_q_widgetOrder"));
1150 for (QWidget *w : list) {
1151 if (childObjects.contains(w)) {
1152 children.append(w);
1153 childObjects.removeAll(w);
1154 }
1155 }
1156 children += childObjects;
1157
1158 const QWidgetList zOrder = qvariant_cast<QWidgetList>(widget->property("_q_zOrder"));
1159 if (list != zOrder) {
1160 QStringList zOrderList;
1161 zOrderList.reserve(zOrder.size());
1162 std::transform(zOrder.cbegin(), zOrder.cend(),
1163 std::back_inserter(zOrderList),
1164 [] (const QWidget *w) { return w->objectName(); });
1165 ui_widget->setElementZOrder(zOrderList);
1166 }
1167 }
1168
1169 for (QObject *obj : qAsConst(children)) {
1170 if (QWidget *childWidget = qobject_cast<QWidget*>(obj)) {
1171 if (d->m_laidout.contains(childWidget) || !recursive)
1172 continue;
1173
1174 if (QMenu *menu = qobject_cast<QMenu *>(childWidget)) {
1175 const auto actions = menu->parentWidget()->actions();
1176 const bool found =
1177 std::any_of(actions.cbegin(), actions.cend(),
1178 [menu] (const QAction *a) { return a->menu() == menu; });
1179 if (!found)
1180 continue;
1181 }
1182
1183 if (DomWidget *ui_child = createDom(childWidget, ui_widget)) {
1184 ui_widgets.append(ui_child);
1185 }
1186 } else if (QAction *childAction = qobject_cast<QAction*>(obj)) {
1187 if (childAction->actionGroup() != nullptr) {
1188 // it will be added later.
1189 continue;
1190 }
1191
1192 if (DomAction *ui_action = createDom(childAction)) {
1193 ui_actions.append(ui_action);
1194 }
1195 } else if (QActionGroup *childActionGroup = qobject_cast<QActionGroup*>(obj)) {
1196 if (DomActionGroup *ui_action_group = createDom(childActionGroup)) {
1197 ui_action_groups.append(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(actions.size());
1206 for (QAction *action : actions) {
1207 if (DomActionRef *ui_action_ref = createActionRefDom(action)) {
1208 ui_action_refs.append(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 */
createActionRefDom(QAction * action)1227 DomActionRef *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
1244 struct FormBuilderSaveLayoutEntry {
FormBuilderSaveLayoutEntryFormBuilderSaveLayoutEntry1245 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
setAlignment(Qt::Alignment al)1259 void FormBuilderSaveLayoutEntry::setAlignment(Qt::Alignment al)
1260 {
1261 if (const QWidget *widget = item->widget()) {
1262 const char *className = widget->metaObject()->className();
1263 if (qstrcmp(className, "Spacer") && qstrcmp(className, "QLayoutWidget"))
1264 alignment = al;
1265 }
1266 }
1267
1268 // Create list from standard box layout
saveLayoutEntries(const QLayout * layout)1269 static QList<FormBuilderSaveLayoutEntry> saveLayoutEntries(const QLayout *layout)
1270 {
1271 QList<FormBuilderSaveLayoutEntry> rc;
1272 if (const int count = layout->count()) {
1273 rc.reserve(count);
1274 for (int idx = 0; idx < count; ++idx) {
1275 QLayoutItem *item = layout->itemAt(idx);
1276 FormBuilderSaveLayoutEntry entry(item);
1277 entry.setAlignment(item->alignment());
1278 rc.append(entry);
1279 }
1280 }
1281 return rc;
1282 }
1283
1284 // Create list from grid layout
saveGridLayoutEntries(QGridLayout * gridLayout)1285 static QList<FormBuilderSaveLayoutEntry> saveGridLayoutEntries(QGridLayout *gridLayout)
1286 {
1287 QList<FormBuilderSaveLayoutEntry> rc;
1288 if (const int count = gridLayout->count()) {
1289 rc.reserve(count);
1290 for (int idx = 0; idx < count; ++idx) {
1291 QLayoutItem *item = gridLayout->itemAt(idx);
1292 FormBuilderSaveLayoutEntry entry(item);
1293 gridLayout->getItemPosition(idx, &entry.row, &entry.column, &entry.rowSpan,&entry.columnSpan);
1294 entry.setAlignment(item->alignment());
1295 rc.append(entry);
1296 }
1297 }
1298 return rc;
1299 }
1300
1301 #if QT_CONFIG(formlayout)
1302 // Create list from form layout
saveFormLayoutEntries(const QFormLayout * formLayout)1303 static QList<FormBuilderSaveLayoutEntry> saveFormLayoutEntries(const QFormLayout *formLayout)
1304 {
1305 QList<FormBuilderSaveLayoutEntry> rc;
1306 if (const int count = formLayout->count()) {
1307 rc.reserve(count);
1308 for (int idx = 0; idx < count; ++idx) {
1309 QLayoutItem *item = formLayout->itemAt(idx);
1310 QFormLayout::ItemRole role = QFormLayout::LabelRole;
1311 FormBuilderSaveLayoutEntry entry(item);
1312 formLayout->getItemPosition(idx, &entry.row, &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(entry);
1326 }
1327 }
1328 return rc;
1329 }
1330 #endif
1331
1332 /*!
1333 \internal
1334 */
1335
createDom(QLayout * layout,DomLayout * ui_layout,DomWidget * ui_parentWidget)1336 DomLayout *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(layout));
1345
1346 QList<FormBuilderSaveLayoutEntry> newList;
1347 if (QGridLayout *gridLayout = qobject_cast<QGridLayout *>(layout)) {
1348 newList = saveGridLayoutEntries(gridLayout);
1349 #if QT_CONFIG(formlayout)
1350 } else if (const QFormLayout *formLayout = qobject_cast<const QFormLayout *>(layout)) {
1351 newList = saveFormLayoutEntries(formLayout);
1352 #endif
1353 } else {
1354 newList = saveLayoutEntries(layout);
1355 }
1356
1357 QVector<DomLayoutItem *> ui_items;
1358 ui_items.reserve(newList.size());
1359 for (const FormBuilderSaveLayoutEntry &item : qAsConst(newList)) {
1360 if (DomLayoutItem *ui_item = createDom(item.item, 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(item.alignment));
1371 ui_items.append(ui_item);
1372 }
1373 }
1374
1375 lay->setElementItem(ui_items);
1376
1377 return lay;
1378 }
1379
1380 /*!
1381 \internal
1382 */
createDom(QLayoutItem * item,DomLayout * ui_layout,DomWidget * ui_parentWidget)1383 DomLayoutItem *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(item->widget(), ui_parentWidget));
1389 d->m_laidout.insert(item->widget(), true);
1390 } else if (item->layout()) {
1391 ui_item->setElementLayout(createDom(item->layout(), ui_layout, ui_parentWidget));
1392 } else if (item->spacerItem()) {
1393 ui_item->setElementSpacer(createDom(item->spacerItem(), ui_layout, ui_parentWidget));
1394 }
1395
1396 return ui_item;
1397 }
1398
1399 /*!
1400 \internal
1401 */
createDom(QSpacerItem * spacer,DomLayout * ui_layout,DomWidget * ui_parentWidget)1402 DomSpacer *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(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(prop);
1425
1426 ui_spacer->setElementProperty(properties);
1427 return ui_spacer;
1428 }
1429
1430 /*!
1431 \internal
1432 */
createProperty(QObject * obj,const QString & pname,const QVariant & v)1433 DomProperty *QAbstractFormBuilder::createProperty(QObject *obj, const QString &pname, const QVariant &v)
1434 {
1435 if (!checkProperty(obj, pname)) {
1436 return nullptr;
1437 }
1438 return variantToDomProperty(this, obj->metaObject(), pname, v);
1439 }
1440
1441 /*!
1442 \internal
1443 */
computeProperties(QObject * obj)1444 QList<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(meta->property(i).name(), 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(propertyNames.at(i));
1460 const QMetaProperty prop = meta->property(meta->indexOfProperty(pname.toUtf8()));
1461
1462 if (!prop.isWritable() || !checkProperty(obj, 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(QCoreApplication::translate("QAbstractFormBuilder", "Flags property are not supported yet."));
1473
1474 if (prop.isEnumType()) {
1475 QString scope = QString::fromUtf8(prop.enumerator().scope());
1476 if (scope.size())
1477 scope += QString::fromUtf8("::");
1478 const QString e = QString::fromUtf8(prop.enumerator().valueToKey(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(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 */
propertyMap(const QList<DomProperty * > & properties)1508 QAbstractFormBuilder::DomPropertyHash QAbstractFormBuilder::propertyMap(const QList<DomProperty*> &properties)
1509 {
1510 DomPropertyHash map;
1511
1512 for (DomProperty *p : properties)
1513 map.insert(p->attributeName(), p);
1514
1515 return map;
1516 }
1517
1518 /*!
1519 \internal
1520 */
checkProperty(QObject * obj,const QString & prop) const1521 bool 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 */
toString(const DomString * str)1532 QString QAbstractFormBuilder::toString(const DomString *str)
1533 {
1534 return str ? str->text() : QString();
1535 }
1536
1537 /*!
1538 \internal
1539 */
applyTabStops(QWidget * widget,DomTabStops * tabStops)1540 void 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(names.size());
1548 for (const QString &name : names) {
1549 if (QWidget *child = widget->findChild<QWidget*>(name)) {
1550 widgets.append(child);
1551 } else {
1552 uiLibWarning(QCoreApplication::translate("QAbstractFormBuilder",
1553 "While applying tab stops: The widget '%1' could not be found.")
1554 .arg(name));
1555 }
1556 }
1557
1558 for (int i = 1, count = widgets.size(); i < count; ++i)
1559 QWidget::setTabOrder(widgets.at(i - 1), widgets.at(i));
1560 }
1561
1562 /*!
1563 \internal
1564 */
saveCustomWidgets()1565 DomCustomWidgets *QAbstractFormBuilder::saveCustomWidgets()
1566 {
1567 return nullptr;
1568 }
1569
1570 /*!
1571 \internal
1572 */
saveTabStops()1573 DomTabStops *QAbstractFormBuilder::saveTabStops()
1574 {
1575 return nullptr;
1576 }
1577
1578 /*!
1579 \internal
1580 */
saveResources()1581 DomResources *QAbstractFormBuilder::saveResources()
1582 {
1583 return nullptr;
1584 }
1585
1586 /*!
1587 \internal
1588 \since 4.5
1589 */
1590
saveButtonGroups(const QWidget * mainContainer)1591 DomButtonGroups *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 *>(o))
1600 if (DomButtonGroup* dg = createDom(bg))
1601 domGroups.push_back(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.
1611 class FriendlyFB : public QAbstractFormBuilder {
1612 public:
1613 using QAbstractFormBuilder::saveResource;
1614 using QAbstractFormBuilder::saveText;
1615 using QAbstractFormBuilder::resourceBuilder;
1616 using QAbstractFormBuilder::textBuilder;
1617 using QAbstractFormBuilder::toVariant;
1618 };
1619
1620 template<class T>
storeItemFlags(const T * item,QList<DomProperty * > * properties)1621 static 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>("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(item->flags())));
1631 properties->append(p);
1632 }
1633 }
1634
1635 template<class T>
storeItemProps(QAbstractFormBuilder * abstractFormBuilder,const T * item,QList<DomProperty * > * properties)1636 static void storeItemProps(QAbstractFormBuilder *abstractFormBuilder, const T *item,
1637 QList<DomProperty*> *properties)
1638 {
1639 static const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
1640 FriendlyFB * const formBuilder = static_cast<FriendlyFB *>(abstractFormBuilder);
1641
1642 DomProperty *p;
1643 QVariant v;
1644
1645 for (const QFormBuilderStrings::TextRoleNName &it : strings.itemTextRoles)
1646 if ((p = formBuilder->saveText(it.second, item->data(it.first.second))))
1647 properties->append(p);
1648
1649 for (const QFormBuilderStrings::RoleNName &it : strings.itemRoles)
1650 if ((v = item->data(it.first)).isValid() &&
1651 (p = variantToDomProperty(abstractFormBuilder,
1652 static_cast<const QMetaObject *>(&QAbstractFormBuilderGadget::staticMetaObject),
1653 it.second, v)))
1654 properties->append(p);
1655
1656 if ((p = formBuilder->saveResource(item->data(Qt::DecorationPropertyRole))))
1657 properties->append(p);
1658 }
1659
1660 template<class T>
storeItemPropsNFlags(QAbstractFormBuilder * abstractFormBuilder,const T * item,QList<DomProperty * > * properties)1661 static void storeItemPropsNFlags(QAbstractFormBuilder *abstractFormBuilder, const T *item,
1662 QList<DomProperty*> *properties)
1663 {
1664 storeItemProps<T>(abstractFormBuilder, item, properties);
1665 storeItemFlags<T>(item, properties);
1666 }
1667
1668 template<class T>
loadItemProps(QAbstractFormBuilder * abstractFormBuilder,T * item,const QHash<QString,DomProperty * > & properties)1669 static void loadItemProps(QAbstractFormBuilder *abstractFormBuilder, T *item,
1670 const QHash<QString, DomProperty*> &properties)
1671 {
1672 static const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
1673 FriendlyFB * const formBuilder = static_cast<FriendlyFB *>(abstractFormBuilder);
1674
1675 DomProperty *p;
1676 QVariant v;
1677
1678 for (const QFormBuilderStrings::TextRoleNName &it : strings.itemTextRoles)
1679 if ((p = properties.value(it.second))) {
1680 v = formBuilder->textBuilder()->loadText(p);
1681 QVariant nativeValue = formBuilder->textBuilder()->toNativeValue(v);
1682 item->setData(it.first.first, qvariant_cast<QString>(nativeValue));
1683 item->setData(it.first.second, v);
1684 }
1685
1686 for (const QFormBuilderStrings::RoleNName &it : strings.itemRoles)
1687 if ((p = properties.value(it.second)) &&
1688 (v = formBuilder->toVariant(&QAbstractFormBuilderGadget::staticMetaObject, p)).isValid())
1689 item->setData(it.first, v);
1690
1691 if ((p = properties.value(strings.iconAttribute))) {
1692 v = formBuilder->resourceBuilder()->loadResource(formBuilder->workingDirectory(), p);
1693 QVariant nativeValue = formBuilder->resourceBuilder()->toNativeValue(v);
1694 item->setIcon(qvariant_cast<QIcon>(nativeValue));
1695 item->setData(Qt::DecorationPropertyRole, v);
1696 }
1697 }
1698
1699 template<class T>
loadItemPropsNFlags(QAbstractFormBuilder * abstractFormBuilder,T * item,const QHash<QString,DomProperty * > & properties)1700 static void loadItemPropsNFlags(QAbstractFormBuilder *abstractFormBuilder, T *item,
1701 const QHash<QString, DomProperty*> &properties)
1702 {
1703 static const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
1704 static const QMetaEnum itemFlags_enum = metaEnum<QAbstractFormBuilderGadget>("itemFlags");
1705
1706 loadItemProps<T>(abstractFormBuilder, item, properties);
1707
1708 DomProperty *p;
1709 if ((p = properties.value(strings.flagsAttribute)) && p->kind() == DomProperty::Set)
1710 item->setFlags(enumKeysToValue<Qt::ItemFlags>(itemFlags_enum, p->elementSet().toLatin1()));
1711 }
1712
1713 /*!
1714 \internal
1715 */
saveTreeWidgetExtraInfo(QTreeWidget * treeWidget,DomWidget * ui_widget,DomWidget * ui_parentWidget)1716 void QAbstractFormBuilder::saveTreeWidgetExtraInfo(QTreeWidget *treeWidget, DomWidget *ui_widget, DomWidget *ui_parentWidget)
1717 {
1718 Q_UNUSED(ui_parentWidget);
1719
1720 QVector<DomColumn *> columns;
1721 DomProperty *p;
1722 QVariant v;
1723 const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
1724 // save the header
1725 for (int c = 0; c<treeWidget->columnCount(); ++c) {
1726 DomColumn *column = new DomColumn;
1727
1728 QList<DomProperty*> properties;
1729
1730 for (const QFormBuilderStrings::TextRoleNName &it : strings.itemTextRoles) {
1731 p = saveText(it.second, treeWidget->headerItem()->data(c, it.first.second));
1732 // Prevent uic 4.4.X from crashing if it cannot find a column text
1733 if (!p && it.first.first == Qt::EditRole && it.second == QStringLiteral("text")) {
1734 DomString *defaultHeader = new DomString;
1735 defaultHeader->setText(QString::number(c + 1));
1736 defaultHeader->setAttributeNotr(QStringLiteral("true"));
1737 p = new DomProperty;
1738 p->setAttributeName(it.second);
1739 p->setElementString(defaultHeader);
1740 }
1741 if (p)
1742 properties.append(p);
1743 }
1744
1745 for (const QFormBuilderStrings::RoleNName &it : strings.itemRoles)
1746 if ((v = treeWidget->headerItem()->data(c, it.first)).isValid() &&
1747 (p = variantToDomProperty(this, &QAbstractFormBuilderGadget::staticMetaObject, it.second, v)))
1748 properties.append(p);
1749
1750 if ((p = saveResource(treeWidget->headerItem()->data(c, Qt::DecorationPropertyRole))))
1751 properties.append(p);
1752
1753 column->setElementProperty(properties);
1754 columns.append(column);
1755 }
1756
1757 ui_widget->setElementColumn(columns);
1758
1759 auto items = ui_widget->elementItem();
1760
1761 QQueue<QPair<QTreeWidgetItem *, DomItem *> > pendingQueue;
1762 for (int i = 0; i < treeWidget->topLevelItemCount(); i++)
1763 pendingQueue.enqueue(qMakePair(treeWidget->topLevelItem(i), nullptr));
1764
1765 while (!pendingQueue.isEmpty()) {
1766 const QPair<QTreeWidgetItem *, DomItem *> pair = pendingQueue.dequeue();
1767 QTreeWidgetItem *item = pair.first;
1768 DomItem *parentDomItem = pair.second;
1769
1770 DomItem *currentDomItem = new DomItem;
1771
1772 QList<DomProperty*> properties;
1773 for (int c = 0; c < treeWidget->columnCount(); c++) {
1774 for (const QFormBuilderStrings::TextRoleNName &it : strings.itemTextRoles)
1775 if ((p = saveText(it.second, item->data(c, it.first.second))))
1776 properties.append(p);
1777
1778 for (const QFormBuilderStrings::RoleNName &it : strings.itemRoles)
1779 if ((v = item->data(c, it.first)).isValid() &&
1780 (p = variantToDomProperty(this, &QAbstractFormBuilderGadget::staticMetaObject, it.second, v)))
1781 properties.append(p);
1782
1783 if ((p = saveResource(item->data(c, Qt::DecorationPropertyRole))))
1784 properties.append(p);
1785 }
1786 storeItemFlags(item, &properties);
1787 currentDomItem->setElementProperty(properties);
1788
1789 if (parentDomItem) {
1790 auto childrenItems = parentDomItem->elementItem();
1791 childrenItems.append(currentDomItem);
1792 parentDomItem->setElementItem(childrenItems);
1793 } else
1794 items.append(currentDomItem);
1795
1796 for (int i = 0; i < item->childCount(); i++)
1797 pendingQueue.enqueue(qMakePair(item->child(i), currentDomItem));
1798 }
1799
1800 ui_widget->setElementItem(items);
1801 }
1802
1803 /*!
1804 \internal
1805 */
saveTableWidgetExtraInfo(QTableWidget * tableWidget,DomWidget * ui_widget,DomWidget * ui_parentWidget)1806 void QAbstractFormBuilder::saveTableWidgetExtraInfo(QTableWidget *tableWidget, DomWidget *ui_widget, DomWidget *ui_parentWidget)
1807 {
1808 Q_UNUSED(ui_parentWidget);
1809
1810 // save the horizontal header
1811 QVector<DomColumn *> columns;
1812 for (int c = 0; c < tableWidget->columnCount(); c++) {
1813 QList<DomProperty*> properties;
1814 QTableWidgetItem *item = tableWidget->horizontalHeaderItem(c);
1815 if (item)
1816 storeItemProps(this, item, &properties);
1817
1818 DomColumn *column = new DomColumn;
1819 column->setElementProperty(properties);
1820 columns.append(column);
1821 }
1822 ui_widget->setElementColumn(columns);
1823
1824 // save the vertical header
1825 QVector<DomRow *> rows;
1826 for (int r = 0; r < tableWidget->rowCount(); r++) {
1827 QList<DomProperty*> properties;
1828 QTableWidgetItem *item = tableWidget->verticalHeaderItem(r);
1829 if (item)
1830 storeItemProps(this, item, &properties);
1831
1832 DomRow *row = new DomRow;
1833 row->setElementProperty(properties);
1834 rows.append(row);
1835 }
1836 ui_widget->setElementRow(rows);
1837
1838 auto items = ui_widget->elementItem();
1839 for (int r = 0; r < tableWidget->rowCount(); r++)
1840 for (int c = 0; c < tableWidget->columnCount(); c++) {
1841 QTableWidgetItem *item = tableWidget->item(r, c);
1842 if (item) {
1843 QList<DomProperty*> properties;
1844 storeItemPropsNFlags(this, item, &properties);
1845
1846 DomItem *domItem = new DomItem;
1847 domItem->setAttributeRow(r);
1848 domItem->setAttributeColumn(c);
1849 domItem->setElementProperty(properties);
1850 items.append(domItem);
1851 }
1852 }
1853
1854 ui_widget->setElementItem(items);
1855 }
1856
1857 /*!
1858 \internal
1859 */
saveListWidgetExtraInfo(QListWidget * listWidget,DomWidget * ui_widget,DomWidget * ui_parentWidget)1860 void QAbstractFormBuilder::saveListWidgetExtraInfo(QListWidget *listWidget, DomWidget *ui_widget, DomWidget *ui_parentWidget)
1861 {
1862 Q_UNUSED(ui_parentWidget);
1863
1864 auto ui_items = ui_widget->elementItem();
1865 for (int i=0; i<listWidget->count(); ++i) {
1866 QList<DomProperty*> properties;
1867 storeItemPropsNFlags(this, listWidget->item(i), &properties);
1868
1869 DomItem *ui_item = new DomItem();
1870 ui_item->setElementProperty(properties);
1871 ui_items.append(ui_item);
1872 }
1873
1874 ui_widget->setElementItem(ui_items);
1875 }
1876
1877 /*!
1878 \internal
1879 */
saveComboBoxExtraInfo(QComboBox * comboBox,DomWidget * ui_widget,DomWidget * ui_parentWidget)1880 void QAbstractFormBuilder::saveComboBoxExtraInfo(QComboBox *comboBox, DomWidget *ui_widget, DomWidget *ui_parentWidget)
1881 {
1882 Q_UNUSED(ui_parentWidget);
1883 auto ui_items = ui_widget->elementItem();
1884
1885 const int count = comboBox->count();
1886 for (int i=0; i < count; ++i) {
1887 // We might encounter items for which both builders return 0 in Designer
1888 // (indicating a custom combo adding items in the constructor). Ignore those.
1889 DomProperty *textProperty = saveText(QFormBuilderStrings::instance().textAttribute,
1890 comboBox->itemData(i, Qt::DisplayPropertyRole));
1891 DomProperty *iconProperty = saveResource(comboBox->itemData(i, Qt::DecorationPropertyRole));
1892 if (textProperty || iconProperty) {
1893 QList<DomProperty*> properties;
1894 if (textProperty)
1895 properties.push_back(textProperty);
1896 if (iconProperty)
1897 properties.push_back(iconProperty);
1898
1899 DomItem *ui_item = new DomItem();
1900 ui_item->setElementProperty(properties);
1901 ui_items.push_back(ui_item);
1902 }
1903 }
1904
1905 ui_widget->setElementItem(ui_items);
1906 }
1907
1908 /*!
1909 \internal
1910 \since 4.5
1911 */
1912
saveButtonExtraInfo(const QAbstractButton * widget,DomWidget * ui_widget,DomWidget *)1913 void QAbstractFormBuilder::saveButtonExtraInfo(const QAbstractButton *widget, DomWidget *ui_widget, DomWidget *)
1914 {
1915 using DomPropertyList = QList<DomProperty *>;
1916 if (const QButtonGroup *buttonGroup = widget->group()) {
1917 DomPropertyList attributes = ui_widget->elementAttribute();
1918 DomString *domString = new DomString();
1919 domString->setText(buttonGroup->objectName());
1920 domString->setAttributeNotr(QStringLiteral("true"));
1921 DomProperty *domProperty = new DomProperty();
1922 domProperty->setAttributeName(QLatin1String(buttonGroupPropertyC));
1923 domProperty->setElementString(domString);
1924 attributes += domProperty;
1925 ui_widget->setElementAttribute(attributes);
1926 }
1927 }
1928
1929 /*!
1930 \internal
1931 \since 4.5
1932 */
saveItemViewExtraInfo(const QAbstractItemView * itemView,DomWidget * ui_widget,DomWidget *)1933 void QAbstractFormBuilder::saveItemViewExtraInfo(const QAbstractItemView *itemView,
1934 DomWidget *ui_widget, DomWidget *)
1935 {
1936 //
1937 // Special handling for qtableview/qtreeview fake header attributes
1938 //
1939 static const QLatin1String realPropertyNames[] = {
1940 QLatin1String("visible"),
1941 QLatin1String("cascadingSectionResizes"),
1942 QLatin1String("minimumSectionSize"), // before defaultSectionSize
1943 QLatin1String("defaultSectionSize"),
1944 QLatin1String("highlightSections"),
1945 QLatin1String("showSortIndicator"),
1946 QLatin1String("stretchLastSection"),
1947 };
1948
1949 if (const QTreeView *treeView = qobject_cast<const QTreeView*>(itemView)) {
1950 auto viewProperties = ui_widget->elementAttribute();
1951 const auto &headerProperties = computeProperties(treeView->header());
1952 for (const QString &realPropertyName : realPropertyNames) {
1953 const QString upperPropertyName = realPropertyName.at(0).toUpper()
1954 + realPropertyName.mid(1);
1955 const QString fakePropertyName = QStringLiteral("header") + upperPropertyName;
1956 for (DomProperty *property : headerProperties) {
1957 if (property->attributeName() == realPropertyName) {
1958 property->setAttributeName(fakePropertyName);
1959 viewProperties << property;
1960 }
1961 }
1962 }
1963 ui_widget->setElementAttribute(viewProperties);
1964 } else if (const QTableView *tableView = qobject_cast<const QTableView*>(itemView)) {
1965 static const QStringList headerPrefixes =
1966 (QStringList() << QStringLiteral("horizontalHeader")
1967 << QStringLiteral("verticalHeader"));
1968
1969 auto viewProperties = ui_widget->elementAttribute();
1970 for (const QString &headerPrefix : headerPrefixes) {
1971 const auto &headerProperties = headerPrefix == QStringLiteral("horizontalHeader")
1972 ? computeProperties(tableView->horizontalHeader())
1973 : computeProperties(tableView->verticalHeader());
1974 for (const QString &realPropertyName : realPropertyNames) {
1975 const QString upperPropertyName = realPropertyName.at(0).toUpper()
1976 + realPropertyName.mid(1);
1977 const QString fakePropertyName = headerPrefix + upperPropertyName;
1978 for (DomProperty *property : qAsConst(headerProperties)) {
1979 if (property->attributeName() == realPropertyName) {
1980 property->setAttributeName(fakePropertyName);
1981 viewProperties << property;
1982 }
1983 }
1984 }
1985 }
1986 ui_widget->setElementAttribute(viewProperties);
1987 }
1988 }
1989
1990 /*!
1991 \internal
1992 \since 4.4
1993 */
1994
setResourceBuilder(QResourceBuilder * builder)1995 void QAbstractFormBuilder::setResourceBuilder(QResourceBuilder *builder)
1996 {
1997 d->setResourceBuilder(builder);
1998 }
1999
2000 /*!
2001 \internal
2002 \since 4.4
2003 */
2004
resourceBuilder() const2005 QResourceBuilder *QAbstractFormBuilder::resourceBuilder() const
2006 {
2007 return d->resourceBuilder();
2008 }
2009
2010 /*!
2011 \internal
2012 \since 4.5
2013 */
2014
setTextBuilder(QTextBuilder * builder)2015 void QAbstractFormBuilder::setTextBuilder(QTextBuilder *builder)
2016 {
2017 d->setTextBuilder(builder);
2018 }
2019
2020 /*!
2021 \internal
2022 \since 4.5
2023 */
2024
textBuilder() const2025 QTextBuilder *QAbstractFormBuilder::textBuilder() const
2026 {
2027 return d->textBuilder();
2028 }
2029
2030 /*!
2031 \internal
2032 */
saveExtraInfo(QWidget * widget,DomWidget * ui_widget,DomWidget * ui_parentWidget)2033 void QAbstractFormBuilder::saveExtraInfo(QWidget *widget, DomWidget *ui_widget,
2034 DomWidget *ui_parentWidget)
2035 {
2036 if (QListWidget *listWidget = qobject_cast<QListWidget*>(widget)) {
2037 saveListWidgetExtraInfo(listWidget, ui_widget, ui_parentWidget);
2038 } else if (QTreeWidget *treeWidget = qobject_cast<QTreeWidget*>(widget)) {
2039 saveTreeWidgetExtraInfo(treeWidget, ui_widget, ui_parentWidget);
2040 } else if (QTableWidget *tableWidget = qobject_cast<QTableWidget*>(widget)) {
2041 saveTableWidgetExtraInfo(tableWidget, ui_widget, ui_parentWidget);
2042 } else if (QComboBox *comboBox = qobject_cast<QComboBox*>(widget)) {
2043 if (!qobject_cast<QFontComboBox*>(widget))
2044 saveComboBoxExtraInfo(comboBox, ui_widget, ui_parentWidget);
2045 } else if(QAbstractButton *ab = qobject_cast<QAbstractButton *>(widget)) {
2046 saveButtonExtraInfo(ab, ui_widget, ui_parentWidget);
2047 }
2048 if (QAbstractItemView *itemView = qobject_cast<QAbstractItemView *>(widget)) {
2049 saveItemViewExtraInfo(itemView, ui_widget, ui_parentWidget);
2050 }
2051 }
2052
2053 /*!
2054 \internal
2055 */
loadListWidgetExtraInfo(DomWidget * ui_widget,QListWidget * listWidget,QWidget * parentWidget)2056 void QAbstractFormBuilder::loadListWidgetExtraInfo(DomWidget *ui_widget, QListWidget *listWidget, QWidget *parentWidget)
2057 {
2058 Q_UNUSED(parentWidget);
2059 const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
2060
2061 const auto &elementItem = ui_widget->elementItem();
2062 for (DomItem *ui_item : elementItem) {
2063 const DomPropertyHash properties = propertyMap(ui_item->elementProperty());
2064 QListWidgetItem *item = new QListWidgetItem(listWidget);
2065 loadItemPropsNFlags<QListWidgetItem>(this, item, properties);
2066 }
2067
2068 DomProperty *currentRow = propertyMap(ui_widget->elementProperty()).value(strings.currentRowProperty);
2069 if (currentRow)
2070 listWidget->setCurrentRow(currentRow->elementNumber());
2071 }
2072
2073 /*!
2074 \internal
2075 */
loadTreeWidgetExtraInfo(DomWidget * ui_widget,QTreeWidget * treeWidget,QWidget * parentWidget)2076 void QAbstractFormBuilder::loadTreeWidgetExtraInfo(DomWidget *ui_widget, QTreeWidget *treeWidget, QWidget *parentWidget)
2077 {
2078 Q_UNUSED(parentWidget);
2079 const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
2080 const QMetaEnum itemFlags_enum = metaEnum<QAbstractFormBuilderGadget>("itemFlags");
2081 const auto &columns = ui_widget->elementColumn();
2082 if (columns.count() > 0)
2083 treeWidget->setColumnCount(columns.count());
2084
2085 for (int i = 0; i<columns.count(); ++i) {
2086 const DomColumn *c = columns.at(i);
2087 const DomPropertyHash properties = propertyMap(c->elementProperty());
2088
2089 DomProperty *p;
2090 QVariant v;
2091
2092 for (const QFormBuilderStrings::RoleNName &it : strings.itemRoles)
2093 if ((p = properties.value(it.second)) &&
2094 (v = toVariant(&QAbstractFormBuilderGadget::staticMetaObject, p)).isValid())
2095 treeWidget->headerItem()->setData(i, it.first, v);
2096
2097 for (const QFormBuilderStrings::TextRoleNName &it : strings.itemTextRoles)
2098 if ((p = properties.value(it.second))) {
2099 v = textBuilder()->loadText(p);
2100 QVariant nativeValue = textBuilder()->toNativeValue(v);
2101 treeWidget->headerItem()->setData(i, it.first.first, qvariant_cast<QString>(nativeValue));
2102 treeWidget->headerItem()->setData(i, it.first.second, v);
2103 }
2104
2105 if ((p = properties.value(strings.iconAttribute))) {
2106 v = resourceBuilder()->loadResource(workingDirectory(), p);
2107 QVariant nativeValue = resourceBuilder()->toNativeValue(v);
2108 treeWidget->headerItem()->setIcon(i, qvariant_cast<QIcon>(nativeValue));
2109 treeWidget->headerItem()->setData(i, Qt::DecorationPropertyRole, v);
2110 }
2111 }
2112
2113 QQueue<QPair<DomItem *, QTreeWidgetItem *> > pendingQueue;
2114 const auto &widgetElementItem = ui_widget->elementItem();
2115 for (DomItem *ui_item : widgetElementItem)
2116 pendingQueue.enqueue(qMakePair(ui_item, nullptr));
2117
2118 while (!pendingQueue.isEmpty()) {
2119 const QPair<DomItem *, QTreeWidgetItem *> pair = pendingQueue.dequeue();
2120 const DomItem *domItem = pair.first;
2121 QTreeWidgetItem *parentItem = pair.second;
2122
2123 QTreeWidgetItem *currentItem = nullptr;
2124
2125 if (parentItem)
2126 currentItem = new QTreeWidgetItem(parentItem);
2127 else
2128 currentItem = new QTreeWidgetItem(treeWidget);
2129
2130 const auto &properties = domItem->elementProperty();
2131 int col = -1;
2132 for (DomProperty *property : properties) {
2133 if (property->attributeName() == strings.flagsAttribute && !property->elementSet().isEmpty()) {
2134 currentItem->setFlags(enumKeysToValue<Qt::ItemFlags>(itemFlags_enum, property->elementSet().toLatin1()));
2135 } else if (property->attributeName() == strings.textAttribute && property->elementString()) {
2136 col++;
2137 QVariant textV = textBuilder()->loadText(property);
2138 QVariant nativeValue = textBuilder()->toNativeValue(textV);
2139 currentItem->setText(col, qvariant_cast<QString>(nativeValue));
2140 currentItem->setData(col, Qt::DisplayPropertyRole, textV);
2141 } else if (col >= 0) {
2142 if (property->attributeName() == strings.iconAttribute) {
2143 QVariant v = resourceBuilder()->loadResource(workingDirectory(), property);
2144 if (v.isValid()) {
2145 QVariant nativeValue = resourceBuilder()->toNativeValue(v);
2146 currentItem->setIcon(col, qvariant_cast<QIcon>(nativeValue));
2147 currentItem->setData(col, Qt::DecorationPropertyRole, v);
2148 }
2149 } else {
2150 QVariant v;
2151 int role = strings.treeItemRoleHash.value(property->attributeName(), (Qt::ItemDataRole)-1);
2152 if (role >= 0) {
2153 if ((v = toVariant(&QAbstractFormBuilderGadget::staticMetaObject, property)).isValid())
2154 currentItem->setData(col, role, v);
2155 } else {
2156 QPair<Qt::ItemDataRole, Qt::ItemDataRole> rolePair =
2157 strings.treeItemTextRoleHash.value(property->attributeName(),
2158 qMakePair((Qt::ItemDataRole)-1, (Qt::ItemDataRole)-1));
2159 if (rolePair.first >= 0) {
2160 QVariant textV = textBuilder()->loadText(property);
2161 QVariant nativeValue = textBuilder()->toNativeValue(textV);
2162 currentItem->setData(col, rolePair.first, qvariant_cast<QString>(nativeValue));
2163 currentItem->setData(col, rolePair.second, textV);
2164 }
2165 }
2166 }
2167 }
2168 }
2169
2170 const auto &elementItem = domItem->elementItem();
2171 for (DomItem *childItem : elementItem)
2172 pendingQueue.enqueue(qMakePair(childItem, currentItem));
2173
2174 }
2175 }
2176
2177 /*!
2178 \internal
2179 */
loadTableWidgetExtraInfo(DomWidget * ui_widget,QTableWidget * tableWidget,QWidget * parentWidget)2180 void QAbstractFormBuilder::loadTableWidgetExtraInfo(DomWidget *ui_widget, QTableWidget *tableWidget, QWidget *parentWidget)
2181 {
2182 Q_UNUSED(parentWidget);
2183
2184 const auto &columns = ui_widget->elementColumn();
2185 if (columns.count() > 0)
2186 tableWidget->setColumnCount(columns.count());
2187 for (int i = 0; i< columns.count(); i++) {
2188 DomColumn *c = columns.at(i);
2189 const DomPropertyHash properties = propertyMap(c->elementProperty());
2190
2191 if (!properties.isEmpty()) {
2192 QTableWidgetItem *item = new QTableWidgetItem;
2193 loadItemProps(this, item, properties);
2194 tableWidget->setHorizontalHeaderItem(i, item);
2195 }
2196 }
2197
2198 const auto &rows = ui_widget->elementRow();
2199 if (rows.count() > 0)
2200 tableWidget->setRowCount(rows.count());
2201 for (int i = 0; i< rows.count(); i++) {
2202 const DomRow *r = rows.at(i);
2203 const DomPropertyHash properties = propertyMap(r->elementProperty());
2204
2205 if (!properties.isEmpty()) {
2206 QTableWidgetItem *item = new QTableWidgetItem;
2207 loadItemProps(this, item, properties);
2208 tableWidget->setVerticalHeaderItem(i, item);
2209 }
2210 }
2211
2212 const auto &elementItem = ui_widget->elementItem();
2213 for (DomItem *ui_item : elementItem) {
2214 if (ui_item->hasAttributeRow() && ui_item->hasAttributeColumn()) {
2215 const DomPropertyHash properties = propertyMap(ui_item->elementProperty());
2216 QTableWidgetItem *item = new QTableWidgetItem;
2217 loadItemPropsNFlags(this, item, properties);
2218 tableWidget->setItem(ui_item->attributeRow(), ui_item->attributeColumn(), item);
2219 }
2220 }
2221 }
2222
2223 /*!
2224 \internal
2225 */
loadComboBoxExtraInfo(DomWidget * ui_widget,QComboBox * comboBox,QWidget * parentWidget)2226 void QAbstractFormBuilder::loadComboBoxExtraInfo(DomWidget *ui_widget, QComboBox *comboBox, QWidget *parentWidget)
2227 {
2228 Q_UNUSED(parentWidget);
2229 const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
2230 const auto &elementItem = ui_widget->elementItem();
2231 for (DomItem *ui_item : elementItem) {
2232 const DomPropertyHash properties = propertyMap(ui_item->elementProperty());
2233 QString text;
2234 QIcon icon;
2235 QVariant textData;
2236 QVariant iconData;
2237
2238 DomProperty *p = nullptr;
2239
2240 p = properties.value(strings.textAttribute);
2241 if (p && p->elementString()) {
2242 textData = textBuilder()->loadText(p);
2243 text = qvariant_cast<QString>(textBuilder()->toNativeValue(textData));
2244 }
2245
2246 p = properties.value(strings.iconAttribute);
2247 if (p) {
2248 iconData = resourceBuilder()->loadResource(workingDirectory(), p);
2249 icon = qvariant_cast<QIcon>(resourceBuilder()->toNativeValue(iconData));
2250 }
2251
2252 comboBox->addItem(icon, text);
2253 comboBox->setItemData((comboBox->count()-1), iconData, Qt::DecorationPropertyRole);
2254 comboBox->setItemData((comboBox->count()-1), textData, Qt::DisplayPropertyRole);
2255 }
2256
2257 DomProperty *currentIndex = propertyMap(ui_widget->elementProperty()).value(strings.currentIndexProperty);
2258 if (currentIndex)
2259 comboBox->setCurrentIndex(currentIndex->elementNumber());
2260 }
2261
2262 // Get the button group name out of a widget's attribute list
buttonGroupName(const DomWidget * ui_widget)2263 static QString buttonGroupName(const DomWidget *ui_widget)
2264 {
2265 const auto &attributes = ui_widget->elementAttribute();
2266 if (attributes.isEmpty())
2267 return QString();
2268 const QString buttonGroupProperty = QLatin1String(buttonGroupPropertyC);
2269 for (const DomProperty *p : attributes) {
2270 if (p->attributeName() == buttonGroupProperty)
2271 return p->elementString()->text();
2272 }
2273 return QString();
2274 }
2275
2276 /*!
2277 \internal
2278 \since 4.5
2279 */
2280
loadButtonExtraInfo(const DomWidget * ui_widget,QAbstractButton * button,QWidget *)2281 void QAbstractFormBuilder::loadButtonExtraInfo(const DomWidget *ui_widget, QAbstractButton *button, QWidget *)
2282 {
2283 using ButtonGroupHash = QFormBuilderExtra::ButtonGroupHash;
2284
2285 const QString groupName = buttonGroupName(ui_widget);
2286 if (groupName.isEmpty())
2287 return;
2288 // Find entry
2289 ButtonGroupHash &buttonGroups = d->buttonGroups();
2290 ButtonGroupHash::iterator it = buttonGroups.find(groupName);
2291 if (it == buttonGroups.end()) {
2292 #ifdef QFORMINTERNAL_NAMESPACE // Suppress the warning when copying in Designer
2293 uiLibWarning(QCoreApplication::translate("QAbstractFormBuilder", "Invalid QButtonGroup reference '%1' referenced by '%2'.").arg(groupName, button->objectName()));
2294 #endif
2295 return;
2296 }
2297 // Create button group on demand?
2298 QButtonGroup *&group = it.value().second;
2299 if (group == nullptr) {
2300 group = new QButtonGroup;
2301 group->setObjectName(groupName);
2302 applyProperties(group, it.value().first->elementProperty());
2303 }
2304 group->addButton(button);
2305 }
2306
2307 /*!
2308 \internal
2309 \since 4.5
2310 */
loadItemViewExtraInfo(DomWidget * ui_widget,QAbstractItemView * itemView,QWidget *)2311 void QAbstractFormBuilder::loadItemViewExtraInfo(DomWidget *ui_widget, QAbstractItemView *itemView,
2312 QWidget *)
2313 {
2314 //
2315 // Special handling for qtableview/qtreeview fake header attributes
2316 //
2317 static const QLatin1String realPropertyNames[] = {
2318 QLatin1String("visible"),
2319 QLatin1String("cascadingSectionResizes"),
2320 QLatin1String("minimumSectionSize"), // before defaultSectionSize
2321 QLatin1String("defaultSectionSize"),
2322 QLatin1String("highlightSections"),
2323 QLatin1String("showSortIndicator"),
2324 QLatin1String("stretchLastSection"),
2325 };
2326
2327 if (QTreeView *treeView = qobject_cast<QTreeView*>(itemView)) {
2328 const auto &allAttributes = ui_widget->elementAttribute();
2329 QList<DomProperty *> headerProperties;
2330 for (const QString &realPropertyName : realPropertyNames) {
2331 const QString upperPropertyName = realPropertyName.at(0).toUpper()
2332 + realPropertyName.mid(1);
2333 const QString fakePropertyName = QStringLiteral("header") + upperPropertyName;
2334 for (DomProperty *attr : allAttributes) {
2335 if (attr->attributeName() == fakePropertyName) {
2336 attr->setAttributeName(realPropertyName);
2337 headerProperties << attr;
2338 }
2339 }
2340 }
2341 applyProperties(treeView->header(), headerProperties);
2342 } else if (QTableView *tableView = qobject_cast<QTableView*>(itemView)) {
2343 static const QStringList headerPrefixes =
2344 (QStringList() << QStringLiteral("horizontalHeader")
2345 << QStringLiteral("verticalHeader"));
2346
2347 const auto &allAttributes = ui_widget->elementAttribute();
2348 for (const QString &headerPrefix : headerPrefixes) {
2349 QList<DomProperty*> headerProperties;
2350 for (const QString &realPropertyName : realPropertyNames) {
2351 const QString upperPropertyName = realPropertyName.at(0).toUpper()
2352 + realPropertyName.mid(1);
2353 const QString fakePropertyName = headerPrefix + upperPropertyName;
2354 for (DomProperty *attr : allAttributes) {
2355 if (attr->attributeName() == fakePropertyName) {
2356 attr->setAttributeName(realPropertyName);
2357 headerProperties << attr;
2358 }
2359 }
2360 }
2361 if (headerPrefix == QStringLiteral("horizontalHeader"))
2362 applyProperties(tableView->horizontalHeader(), headerProperties);
2363 else
2364 applyProperties(tableView->verticalHeader(), headerProperties);
2365 }
2366 }
2367 }
2368
2369 /*!
2370 \internal
2371 */
loadExtraInfo(DomWidget * ui_widget,QWidget * widget,QWidget * parentWidget)2372 void QAbstractFormBuilder::loadExtraInfo(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
2373 {
2374 const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
2375 if (false) {
2376 #if QT_CONFIG(listwidget)
2377 } else if (QListWidget *listWidget = qobject_cast<QListWidget*>(widget)) {
2378 loadListWidgetExtraInfo(ui_widget, listWidget, parentWidget);
2379 #endif
2380 #if QT_CONFIG(treewidget)
2381 } else if (QTreeWidget *treeWidget = qobject_cast<QTreeWidget*>(widget)) {
2382 loadTreeWidgetExtraInfo(ui_widget, treeWidget, parentWidget);
2383 #endif
2384 #if QT_CONFIG(tablewidget)
2385 } else if (QTableWidget *tableWidget = qobject_cast<QTableWidget*>(widget)) {
2386 loadTableWidgetExtraInfo(ui_widget, tableWidget, parentWidget);
2387 #endif
2388 #if QT_CONFIG(combobox)
2389 } else if (QComboBox *comboBox = qobject_cast<QComboBox*>(widget)) {
2390 if (!qobject_cast<QFontComboBox *>(widget))
2391 loadComboBoxExtraInfo(ui_widget, comboBox, parentWidget);
2392 #endif
2393 #if QT_CONFIG(tabwidget)
2394 } else if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(widget)) {
2395 const DomProperty *currentIndex = propertyMap(ui_widget->elementProperty()).value(strings.currentIndexProperty);
2396 if (currentIndex)
2397 tabWidget->setCurrentIndex(currentIndex->elementNumber());
2398 #endif
2399 #if QT_CONFIG(stackedwidget)
2400 } else if (QStackedWidget *stackedWidget = qobject_cast<QStackedWidget*>(widget)) {
2401 const DomProperty *currentIndex = propertyMap(ui_widget->elementProperty()).value(strings.currentIndexProperty);
2402 if (currentIndex)
2403 stackedWidget->setCurrentIndex(currentIndex->elementNumber());
2404 #endif
2405 #if QT_CONFIG(toolbox)
2406 } else if (QToolBox *toolBox = qobject_cast<QToolBox*>(widget)) {
2407 const DomProperty *currentIndex = propertyMap(ui_widget->elementProperty()).value(strings.currentIndexProperty);
2408 if (currentIndex)
2409 toolBox->setCurrentIndex(currentIndex->elementNumber());
2410 const DomProperty *tabSpacing = propertyMap(ui_widget->elementProperty()).value(strings.tabSpacingProperty);
2411 if (tabSpacing)
2412 toolBox->layout()->setSpacing(tabSpacing->elementNumber());
2413 #endif
2414 } else if (QAbstractButton *ab = qobject_cast<QAbstractButton *>(widget)) {
2415 loadButtonExtraInfo(ui_widget, ab, parentWidget);
2416 }
2417 if (QAbstractItemView *itemView = qobject_cast<QAbstractItemView *>(widget)) {
2418 loadItemViewExtraInfo(ui_widget, itemView, parentWidget);
2419 }
2420 }
2421
2422 /*!
2423 Returns the current working directory of the form builder.
2424
2425 \sa setWorkingDirectory()
2426 */
workingDirectory() const2427 QDir QAbstractFormBuilder::workingDirectory() const
2428 {
2429 return d->m_workingDirectory;
2430 }
2431
2432 /*!
2433 Sets the current working directory of the form builder to the
2434 specified \a directory.
2435
2436 \sa workingDirectory()
2437 */
setWorkingDirectory(const QDir & directory)2438 void QAbstractFormBuilder::setWorkingDirectory(const QDir &directory)
2439 {
2440 d->m_workingDirectory = directory;
2441 }
2442
2443 /*!
2444 \internal
2445 */
createDom(QAction * action)2446 DomAction *QAbstractFormBuilder::createDom(QAction *action)
2447 {
2448 if (action->parentWidget() == action->menu() || action->isSeparator())
2449 return nullptr;
2450
2451 DomAction *ui_action = new DomAction;
2452 ui_action->setAttributeName(action->objectName());
2453
2454 ui_action->setElementProperty(computeProperties(action));
2455
2456 return ui_action;
2457 }
2458
2459 /*!
2460 \internal
2461 \since 4.5
2462 */
2463
createDom(QButtonGroup * buttonGroup)2464 DomButtonGroup *QAbstractFormBuilder::createDom(QButtonGroup *buttonGroup)
2465 {
2466 if (buttonGroup->buttons().count() == 0) // Empty group left over on form?
2467 return nullptr;
2468 DomButtonGroup *domButtonGroup = new DomButtonGroup;
2469 domButtonGroup->setAttributeName(buttonGroup->objectName());
2470
2471 domButtonGroup->setElementProperty(computeProperties(buttonGroup));
2472 return domButtonGroup;
2473 }
2474
2475 /*!
2476 \internal
2477 */
createDom(QActionGroup * actionGroup)2478 DomActionGroup *QAbstractFormBuilder::createDom(QActionGroup *actionGroup)
2479 {
2480 DomActionGroup *ui_action_group = new DomActionGroup;
2481 ui_action_group->setAttributeName(actionGroup->objectName());
2482
2483 ui_action_group->setElementProperty(computeProperties(actionGroup));
2484
2485 QVector<DomAction *> ui_actions;
2486
2487 const auto &actions = actionGroup->actions();
2488 ui_actions.reserve(actions.size());
2489 for (QAction *action : actions) {
2490 if (DomAction *ui_action = createDom(action)) {
2491 ui_actions.append(ui_action);
2492 }
2493 }
2494
2495 ui_action_group->setElementAction(ui_actions);
2496
2497 return ui_action_group;
2498 }
2499
2500 /*!
2501 \internal
2502 */
addMenuAction(QAction * action)2503 void QAbstractFormBuilder::addMenuAction(QAction *action)
2504 {
2505 Q_UNUSED(action);
2506 }
2507
2508 /*!
2509 \internal
2510 */
reset()2511 void QAbstractFormBuilder::reset()
2512 {
2513 d->m_laidout.clear();
2514 d->m_actions.clear();
2515 d->m_actionGroups.clear();
2516 d->m_defaultMargin = INT_MIN;
2517 d->m_defaultSpacing = INT_MIN;
2518 }
2519
2520 /*!
2521 \internal
2522 Access meta enumeration for Qt::ToolBarArea
2523 */
2524
toolBarAreaMetaEnum()2525 QMetaEnum QAbstractFormBuilder::toolBarAreaMetaEnum()
2526 {
2527 return metaEnum<QAbstractFormBuilderGadget>("toolBarArea");
2528 }
2529
2530 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
2531
2532 /*!
2533 \internal
2534 Return paths of an icon.
2535 */
2536
iconPaths(const QIcon & icon) const2537 QAbstractFormBuilder::IconPaths QAbstractFormBuilder::iconPaths(const QIcon &icon) const
2538 {
2539 Q_UNUSED(icon);
2540 qWarning() << "QAbstractFormBuilder::iconPaths() is obsoleted";
2541 return IconPaths();
2542 }
2543
2544 /*!
2545 \internal
2546 Return paths of a pixmap.
2547 */
2548
pixmapPaths(const QPixmap & pixmap) const2549 QAbstractFormBuilder::IconPaths QAbstractFormBuilder::pixmapPaths(const QPixmap &pixmap) const
2550 {
2551 Q_UNUSED(pixmap);
2552 qWarning() << "QAbstractFormBuilder::pixmapPaths() is obsoleted";
2553 return IconPaths();
2554 }
2555
2556 #endif // < Qt 6
2557
2558 /*!
2559 \internal
2560 Set up a DOM property with icon.
2561 */
2562
setIconProperty(DomProperty & p,const IconPaths & ip) const2563 void QAbstractFormBuilder::setIconProperty(DomProperty &p, const IconPaths &ip) const
2564 {
2565 DomResourceIcon *dpi = new DomResourceIcon;
2566
2567 /* TODO
2568 if (!ip.second.isEmpty())
2569 pix->setAttributeResource(ip.second);
2570 */
2571 dpi->setText(ip.first);
2572
2573 p.setAttributeName(QFormBuilderStrings::instance().iconAttribute);
2574 p.setElementIconSet(dpi);
2575 }
2576
2577 /*!
2578 \internal
2579 Set up a DOM property with pixmap.
2580 */
2581
setPixmapProperty(DomProperty & p,const IconPaths & ip) const2582 void QAbstractFormBuilder::setPixmapProperty(DomProperty &p, const IconPaths &ip) const
2583 {
2584 QFormBuilderExtra::setPixmapProperty(&p, ip);
2585 }
2586
2587 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
2588
2589 /*!
2590 \internal
2591 Convenience. Return DOM property for icon; 0 if icon.isNull().
2592 */
2593
iconToDomProperty(const QIcon & icon) const2594 DomProperty* QAbstractFormBuilder::iconToDomProperty(const QIcon &icon) const
2595 {
2596 Q_UNUSED(icon);
2597 qWarning() << "QAbstractFormBuilder::iconToDomProperty() is obsoleted";
2598 return nullptr;
2599 }
2600
2601 #endif // < Qt 6
2602
2603 /*!
2604 \internal
2605 \since 4.4
2606 */
2607
saveResource(const QVariant & v) const2608 DomProperty *QAbstractFormBuilder::saveResource(const QVariant &v) const
2609 {
2610 if (v.isNull())
2611 return nullptr;
2612
2613 DomProperty *p = resourceBuilder()->saveResource(workingDirectory(), v);
2614 if (p)
2615 p->setAttributeName(QFormBuilderStrings::instance().iconAttribute);
2616 return p;
2617 }
2618
2619 /*!
2620 \internal
2621 \since 4.5
2622 */
2623
saveText(const QString & attributeName,const QVariant & v) const2624 DomProperty *QAbstractFormBuilder::saveText(const QString &attributeName, const QVariant &v) const
2625 {
2626 if (v.isNull())
2627 return nullptr;
2628
2629 DomProperty *p = textBuilder()->saveText(v);
2630 if (p)
2631 p->setAttributeName(attributeName);
2632 return p;
2633 }
2634
2635 /*!
2636 \internal
2637 Return the appropriate DOM pixmap for an image dom property.
2638 From 4.4 - unused
2639 */
2640
domPixmap(const DomProperty * p)2641 const DomResourcePixmap *QAbstractFormBuilder::domPixmap(const DomProperty* p) {
2642 switch (p->kind()) {
2643 case DomProperty::IconSet:
2644 qDebug() << "** WARNING QAbstractFormBuilder::domPixmap() called for icon set!";
2645 break;
2646 case DomProperty::Pixmap:
2647 return p->elementPixmap();
2648 default:
2649 break;
2650 }
2651 return nullptr;
2652 }
2653
2654 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
2655
2656 /*!
2657 \internal
2658 Create icon from DOM.
2659 From 4.4 - unused
2660 */
2661
domPropertyToIcon(const DomResourcePixmap * icon)2662 QIcon QAbstractFormBuilder::domPropertyToIcon(const DomResourcePixmap *icon)
2663 {
2664 Q_UNUSED(icon);
2665 qWarning() << "QAbstractFormBuilder::domPropertyToIcon() is obsoleted";
2666 return QIcon();
2667 }
2668
2669 /*!
2670 \internal
2671 Create icon from DOM. Assert if !domPixmap
2672 From 4.4 - unused
2673 */
2674
domPropertyToIcon(const DomProperty * p)2675 QIcon QAbstractFormBuilder::domPropertyToIcon(const DomProperty* p)
2676 {
2677 Q_UNUSED(p);
2678 qWarning() << "QAbstractFormBuilder::domPropertyToIcon() is obsoleted";
2679 return QIcon();
2680 }
2681
2682
2683 /*!
2684 \internal
2685 Create pixmap from DOM.
2686 From 4.4 - unused
2687 */
2688
domPropertyToPixmap(const DomResourcePixmap * pixmap)2689 QPixmap QAbstractFormBuilder::domPropertyToPixmap(const DomResourcePixmap* pixmap)
2690 {
2691 Q_UNUSED(pixmap);
2692 qWarning() << "QAbstractFormBuilder::domPropertyToPixmap() is obsoleted";
2693 return QPixmap();
2694 }
2695
2696
2697 /*!
2698 \internal
2699 Create pixmap from DOM. Assert if !domPixmap
2700 From 4.4 - unused
2701 */
2702
domPropertyToPixmap(const DomProperty * p)2703 QPixmap QAbstractFormBuilder::domPropertyToPixmap(const DomProperty* p)
2704 {
2705 Q_UNUSED(p);
2706 qWarning() << "QAbstractFormBuilder::domPropertyToPixmap() is obsoleted";
2707 return QPixmap();
2708 }
2709
2710 #endif // < Qt 6
2711
2712 /*!
2713 \fn void QAbstractFormBuilder::createConnections ( DomConnections *, QWidget * )
2714 \internal
2715 */
2716
2717 /*!
2718 \fn void QAbstractFormBuilder::createCustomWidgets ( DomCustomWidgets * )
2719 \internal
2720 */
2721
2722 /*!
2723 \fn void QAbstractFormBuilder::createResources ( DomResources * )
2724 \internal
2725 */
2726
2727 /*!
2728 Returns a human-readable description of the last error occurred in load().
2729
2730 \since 5.0
2731 \sa load()
2732 */
2733
errorString() const2734 QString QAbstractFormBuilder::errorString() const
2735 {
2736 return d->m_errorString;
2737 }
2738
2739 QT_END_NAMESPACE
2740