Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdesigner_resource.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
5#include "formwindow.h"
8#include "iconloader_p.h"
20
21#include <QtDesigner/abstractformeditor.h>
22#include <QtDesigner/abstractintegration.h>
23#include <QtDesigner/private/ui4_p.h>
24#include <QtDesigner/private/formbuilderextra_p.h>
25#include <QtDesigner/private/resourcebuilder_p.h>
26#include <QtDesigner/private/textbuilder_p.h>
27#include <qdesigner_widgetitem_p.h>
28
29// shared
30#include <widgetdatabase_p.h>
31#include <metadatabase_p.h>
32#include <layout_p.h>
33#include <layoutinfo_p.h>
34#include <spacer_widget_p.h>
35#include <pluginmanager_p.h>
36#include <widgetfactory_p.h>
37#include <abstractlanguage.h>
38#include <abstractintrospection_p.h>
39
40#include <qlayout_widget_p.h>
41#include <qdesigner_utils_p.h>
42#include <QtDesigner/private/ui4_p.h>
43
44// sdk
45#include <QtDesigner/propertysheet.h>
46#include <QtDesigner/abstractformeditor.h>
47#include <QtDesigner/extrainfo.h>
48#include <QtDesigner/abstractformwindowtool.h>
49#include <QtDesigner/qextensionmanager.h>
50#include <QtDesigner/container.h>
51#include <abstractdialoggui_p.h>
52
53#include <QtWidgets/qmenu.h>
54#include <QtWidgets/qmessagebox.h>
55#include <QtWidgets/qlayout.h>
56#include <QtWidgets/qformlayout.h>
57#include <QtWidgets/qtabwidget.h>
58#include <QtWidgets/qtoolbox.h>
59#include <QtWidgets/qstackedwidget.h>
60#include <QtWidgets/qtoolbar.h>
61#include <QtWidgets/qtabbar.h>
62#include <QtWidgets/qbuttongroup.h>
63#include <QtWidgets/qapplication.h>
64#include <QtWidgets/qmainwindow.h>
65#include <QtWidgets/qsplitter.h>
66#include <QtWidgets/qmdiarea.h>
67#include <QtWidgets/qmenubar.h>
68#include <QtWidgets/qfiledialog.h>
69#include <QtWidgets/qheaderview.h>
70#include <QtWidgets/qwizard.h>
71#include <private/qlayoutengine_p.h>
72
73#include <QtGui/qaction.h>
74#include <QtGui/qactiongroup.h>
75
76#include <QtCore/qbuffer.h>
77#include <QtCore/qdir.h>
78#include <QtCore/qmetaobject.h>
79#include <QtCore/qdebug.h>
80#include <QtCore/qversionnumber.h>
81#include <QtCore/qxmlstream.h>
82
83#include <algorithm>
84#include <iterator>
85#include <memory>
86
87Q_DECLARE_METATYPE(QWidgetList)
88
89QT_BEGIN_NAMESPACE
90
91using namespace Qt::StringLiterals;
92
93using QFBE = QFormBuilderExtra;
94
95namespace {
96 using DomPropertyList = QList<DomProperty *>;
97}
98
99static constexpr auto currentUiVersion = "4.0"_L1;
100static constexpr auto clipboardObjectName = "__qt_fake_top_level"_L1;
101
102#define OLD_RESOURCE_FORMAT // Support pre 4.4 format.
103
104namespace qdesigner_internal {
105
106// PYSIDE-2492 (since 6.7): Write fully qualified enums for Python
107static bool supportsQualifiedEnums(const QVersionNumber &qtVersion)
108{
109 if (qtVersion >= QVersionNumber{6, 6, 2})
110 return true;
111
112 switch (qtVersion.majorVersion()) {
113 case 6: // Qt 6
114 switch (qtVersion.minorVersion()) {
115 case 5: // 6.5 LTS
116 if (qtVersion.microVersion() >= 4)
117 return true;
118 break;
119 case 2: // 6.2 LTS
120 if (qtVersion.microVersion() >= 13)
121 return true;
122 break;
123 }
124 break;
125
126 case 5: // Qt 5 LTS
127 if (qtVersion >= QVersionNumber{5, 15, 18})
128 return true;
129 break;
130 }
131 return false;
132}
133
134// Separate horizontal/vertical size constraints since Qt 7 (QTBUG-17730).
135static bool supportsSeparateSizeConstraints(const QVersionNumber &qtVersion)
136{
137 return qtVersion >= QVersionNumber{7, 0, 0};
138}
139
140// -------------------- QDesignerResourceBuilder: A resource builder that works on the property sheet icon types.
142{
143public:
144 QDesignerResourceBuilder(QDesignerFormEditorInterface *core, DesignerPixmapCache *pixmapCache, DesignerIconCache *iconCache);
145
146 void setPixmapCache(DesignerPixmapCache *pixmapCache) { m_pixmapCache = pixmapCache; }
147 void setIconCache(DesignerIconCache *iconCache) { m_iconCache = iconCache; }
148 bool isSaveRelative() const { return m_saveRelative; }
149 void setSaveRelative(bool relative) { m_saveRelative = relative; }
150 QStringList usedQrcFiles() const { return m_usedQrcFiles.keys(); }
152 QStringList loadedQrcFiles() const { return m_loadedQrcFiles.keys(); } // needed only for loading old resource attribute of <iconset> tag.
153#endif
154
155 QVariant loadResource(const QDir &workingDirectory, const DomProperty *icon) const override;
156
157 QVariant toNativeValue(const QVariant &value) const override;
158
159 DomProperty *saveResource(const QDir &workingDirectory, const QVariant &value) const override;
160
161 bool isResourceType(const QVariant &value) const override;
162private:
163
164 QDesignerFormEditorInterface *m_core;
165 DesignerPixmapCache *m_pixmapCache;
166 DesignerIconCache *m_iconCache;
167 const QDesignerLanguageExtension *m_lang;
168 bool m_saveRelative;
169 mutable QMap<QString, bool> m_usedQrcFiles;
170 mutable QMap<QString, bool> m_loadedQrcFiles;
171};
172
173QDesignerResourceBuilder::QDesignerResourceBuilder(QDesignerFormEditorInterface *core, DesignerPixmapCache *pixmapCache, DesignerIconCache *iconCache) :
174 m_core(core),
175 m_pixmapCache(pixmapCache),
176 m_iconCache(iconCache),
177 m_lang(qt_extension<QDesignerLanguageExtension *>(core->extensionManager(), core)),
178 m_saveRelative(true)
179{
180}
181
182static inline void setIconPixmap(QIcon::Mode m, QIcon::State s, const QDir &workingDirectory,
183 QString path, PropertySheetIconValue &icon,
184 const QDesignerLanguageExtension *lang = nullptr)
185{
186 if (lang == nullptr || !lang->isLanguageResource(path))
187 path = QFileInfo(workingDirectory, path).absoluteFilePath();
188 icon.setPixmap(m, s, PropertySheetPixmapValue(path));
189}
190
191QVariant QDesignerResourceBuilder::loadResource(const QDir &workingDirectory, const DomProperty *property) const
192{
193 switch (property->kind()) {
194 case DomProperty::Pixmap: {
196 DomResourcePixmap *dp = property->elementPixmap();
197 if (!dp->text().isEmpty()) {
198 if (m_lang != nullptr && m_lang->isLanguageResource(dp->text())) {
199 pixmap.setPath(dp->text());
200 } else {
201 pixmap.setPath(QFileInfo(workingDirectory, dp->text()).absoluteFilePath());
202 }
204 if (dp->hasAttributeResource())
205 m_loadedQrcFiles.insert(QFileInfo(workingDirectory, dp->attributeResource()).absoluteFilePath(), false);
206#endif
207 }
208 return QVariant::fromValue(pixmap);
209 }
210
211 case DomProperty::IconSet: {
213 DomResourceIcon *di = property->elementIconSet();
214 const bool hasTheme = di->hasAttributeTheme();
215 if (hasTheme) {
216 const QString &theme = di->attributeTheme();
217 const qsizetype themeEnum = theme.startsWith("QIcon::"_L1)
218 ? QDesignerResourceBuilder::themeIconIndex(theme) : -1;
219 if (themeEnum != -1)
220 icon.setThemeEnum(themeEnum);
221 else
222 icon.setTheme(theme);
223 }
224 if (const int flags = iconStateFlags(di)) { // new, post 4.4 format
225 if (flags & NormalOff)
226 setIconPixmap(QIcon::Normal, QIcon::Off, workingDirectory, di->elementNormalOff()->text(), icon, m_lang);
227 if (flags & NormalOn)
228 setIconPixmap(QIcon::Normal, QIcon::On, workingDirectory, di->elementNormalOn()->text(), icon, m_lang);
229 if (flags & DisabledOff)
230 setIconPixmap(QIcon::Disabled, QIcon::Off, workingDirectory, di->elementDisabledOff()->text(), icon, m_lang);
231 if (flags & DisabledOn)
232 setIconPixmap(QIcon::Disabled, QIcon::On, workingDirectory, di->elementDisabledOn()->text(), icon, m_lang);
233 if (flags & ActiveOff)
234 setIconPixmap(QIcon::Active, QIcon::Off, workingDirectory, di->elementActiveOff()->text(), icon, m_lang);
235 if (flags & ActiveOn)
236 setIconPixmap(QIcon::Active, QIcon::On, workingDirectory, di->elementActiveOn()->text(), icon, m_lang);
237 if (flags & SelectedOff)
238 setIconPixmap(QIcon::Selected, QIcon::Off, workingDirectory, di->elementSelectedOff()->text(), icon, m_lang);
239 if (flags & SelectedOn)
240 setIconPixmap(QIcon::Selected, QIcon::On, workingDirectory, di->elementSelectedOn()->text(), icon, m_lang);
241 } else if (!hasTheme) {
243 setIconPixmap(QIcon::Normal, QIcon::Off, workingDirectory, di->text(), icon, m_lang);
244 if (di->hasAttributeResource())
245 m_loadedQrcFiles.insert(QFileInfo(workingDirectory, di->attributeResource()).absoluteFilePath(), false);
246#endif
247 }
248 return QVariant::fromValue(icon);
249 }
250 default:
251 break;
252 }
253 return QVariant();
254}
255
256QVariant QDesignerResourceBuilder::toNativeValue(const QVariant &value) const
257{
258 if (value.canConvert<PropertySheetPixmapValue>()) {
259 if (m_pixmapCache)
260 return m_pixmapCache->pixmap(qvariant_cast<PropertySheetPixmapValue>(value));
261 } else if (value.canConvert<PropertySheetIconValue>()) {
262 if (m_iconCache)
263 return m_iconCache->icon(qvariant_cast<PropertySheetIconValue>(value));
264 }
265 return value;
266}
267
268DomProperty *QDesignerResourceBuilder::saveResource(const QDir &workingDirectory, const QVariant &value) const
269{
270 DomProperty *p = new DomProperty;
271 if (value.canConvert<PropertySheetPixmapValue>()) {
272 const PropertySheetPixmapValue pix = qvariant_cast<PropertySheetPixmapValue>(value);
273 DomResourcePixmap *rp = new DomResourcePixmap;
274 const QString pixPath = pix.path();
275 switch (pix.pixmapSource(m_core)) {
276 case PropertySheetPixmapValue::LanguageResourcePixmap:
277 rp->setText(pixPath);
278 break;
279 case PropertySheetPixmapValue::ResourcePixmap: {
280 rp->setText(pixPath);
281 const QString qrcFile = m_core->resourceModel()->qrcPath(pixPath);
282 if (!qrcFile.isEmpty()) {
283 m_usedQrcFiles.insert(qrcFile, false);
284#ifdef OLD_RESOURCE_FORMAT // Legacy: Add qrc path
285 rp->setAttributeResource(workingDirectory.relativeFilePath(qrcFile));
286#endif
287 }
288 }
289 break;
290 case PropertySheetPixmapValue::FilePixmap:
291 rp->setText(m_saveRelative ? workingDirectory.relativeFilePath(pixPath) : pixPath);
292 break;
293 }
294 p->setElementPixmap(rp);
295 return p;
296 }
297 if (value.canConvert<PropertySheetIconValue>()) {
298 const PropertySheetIconValue icon = qvariant_cast<PropertySheetIconValue>(value);
299 const auto &pixmaps = icon.paths();
300 const int themeEnum = icon.themeEnum();
301 const QString theme = themeEnum != -1
302 ? QDesignerResourceBuilder::fullyQualifiedThemeIconName(themeEnum) : icon.theme();
303 if (!pixmaps.isEmpty() || !theme.isEmpty()) {
304 DomResourceIcon *ri = new DomResourceIcon;
305 if (!theme.isEmpty())
306 ri->setAttributeTheme(theme);
307 for (auto itPix = pixmaps.cbegin(), end = pixmaps.cend(); itPix != end; ++itPix) {
308 const QIcon::Mode mode = itPix.key().first;
309 const QIcon::State state = itPix.key().second;
310 DomResourcePixmap *rp = new DomResourcePixmap;
311 const PropertySheetPixmapValue &pix = itPix.value();
312 const PropertySheetPixmapValue::PixmapSource ps = pix.pixmapSource(m_core);
313 const QString pixPath = pix.path();
314 rp->setText(ps == PropertySheetPixmapValue::FilePixmap && m_saveRelative ? workingDirectory.relativeFilePath(pixPath) : pixPath);
315 if (state == QIcon::Off) {
316 switch (mode) {
317 case QIcon::Normal:
318 ri->setElementNormalOff(rp);
319#ifdef OLD_RESOURCE_FORMAT // Legacy: Set Normal off as text/path in old format.
320 ri->setText(rp->text());
321#endif
322 if (ps == PropertySheetPixmapValue::ResourcePixmap) {
323 // Be sure that ri->text() file comes from active resourceSet (i.e. make appropriate
324 // resourceSet active before calling this method).
325 const QString qrcFile = m_core->resourceModel()->qrcPath(ri->text());
326 if (!qrcFile.isEmpty()) {
327 m_usedQrcFiles.insert(qrcFile, false);
328#ifdef OLD_RESOURCE_FORMAT // Legacy: Set Normal off as text/path in old format.
329 ri->setAttributeResource(workingDirectory.relativeFilePath(qrcFile));
330#endif
331 }
332 }
333 break;
334 case QIcon::Disabled: ri->setElementDisabledOff(rp); break;
335 case QIcon::Active: ri->setElementActiveOff(rp); break;
336 case QIcon::Selected: ri->setElementSelectedOff(rp); break;
337 }
338 } else {
339 switch (mode) {
340 case QIcon::Normal: ri->setElementNormalOn(rp); break;
341 case QIcon::Disabled: ri->setElementDisabledOn(rp); break;
342 case QIcon::Active: ri->setElementActiveOn(rp); break;
343 case QIcon::Selected: ri->setElementSelectedOn(rp); break;
344 }
345 }
346 }
347 p->setElementIconSet(ri);
348 return p;
349 }
350 }
351 delete p;
352 return nullptr;
353}
354
355bool QDesignerResourceBuilder::isResourceType(const QVariant &value) const
356{
357 return value.canConvert<PropertySheetPixmapValue>()
358 || value.canConvert<PropertySheetIconValue>();
359}
360// ------------------------- QDesignerTextBuilder
361
362template <class DomElement> // for DomString, potentially DomStringList
363inline void translationParametersToDom(const PropertySheetTranslatableData &data, DomElement *e)
364{
365 const QString propertyComment = data.disambiguation();
366 if (!propertyComment.isEmpty())
367 e->setAttributeComment(propertyComment);
368 const QString propertyExtracomment = data.comment();
369 if (!propertyExtracomment.isEmpty())
370 e->setAttributeExtraComment(propertyExtracomment);
371 const QString &id = data.id();
372 if (!id.isEmpty())
373 e->setAttributeId(id);
374 if (!data.translatable())
375 e->setAttributeNotr(u"true"_s);
376}
377
378template <class DomElement> // for DomString, potentially DomStringList
379inline void translationParametersFromDom(const DomElement *e, PropertySheetTranslatableData *data)
380{
381 if (e->hasAttributeComment())
382 data->setDisambiguation(e->attributeComment());
383 if (e->hasAttributeExtraComment())
384 data->setComment(e->attributeExtraComment());
385 if (e->hasAttributeId())
386 data->setId(e->attributeId());
387 if (e->hasAttributeNotr()) {
388 const QString notr = e->attributeNotr();
389 const bool translatable = !(notr == "true"_L1 || notr == "yes"_L1);
390 data->setTranslatable(translatable);
391 }
392}
393
395{
396public:
398
399 QVariant loadText(const DomProperty *icon) const override;
400
401 QVariant toNativeValue(const QVariant &value) const override;
402
403 DomProperty *saveText(const QVariant &value) const override;
404};
405
406QVariant QDesignerTextBuilder::loadText(const DomProperty *text) const
407{
408 if (const DomString *domString = text->elementString()) {
409 PropertySheetStringValue stringValue(domString->text());
410 translationParametersFromDom(domString, &stringValue);
411 return QVariant::fromValue(stringValue);
412 }
413 return QVariant(QString());
414}
415
416QVariant QDesignerTextBuilder::toNativeValue(const QVariant &value) const
417{
418 if (value.canConvert<PropertySheetStringValue>())
419 return QVariant::fromValue(qvariant_cast<PropertySheetStringValue>(value).value());
420 return value;
421}
422
423static inline DomProperty *stringToDomProperty(const QString &value)
424{
425 DomString *domString = new DomString();
426 domString->setText(value);
427 DomProperty *property = new DomProperty();
428 property->setElementString(domString);
429 return property;
430}
431
432static inline DomProperty *stringToDomProperty(const QString &value,
433 const PropertySheetTranslatableData &translatableData)
434{
435 DomString *domString = new DomString();
436 domString->setText(value);
437 translationParametersToDom(translatableData, domString);
438 DomProperty *property = new DomProperty();
439 property->setElementString(domString);
440 return property;
441}
442
443DomProperty *QDesignerTextBuilder::saveText(const QVariant &value) const
444{
445 if (value.canConvert<PropertySheetStringValue>()) {
446 const PropertySheetStringValue str = qvariant_cast<PropertySheetStringValue>(value);
447 return stringToDomProperty(str.value(), str);
448 }
449 if (value.canConvert<QString>())
450 return stringToDomProperty(value.toString());
451 return nullptr;
452}
453
456 m_formWindow(formWindow),
457 m_copyWidget(false),
458 m_selected(nullptr),
459 m_resourceBuilder(new QDesignerResourceBuilder(m_formWindow->core(), m_formWindow->pixmapCache(), m_formWindow->iconCache()))
460{
461 // Check language unless extension present (Jambi)
462 QDesignerFormEditorInterface *core = m_formWindow->core();
463 if (const QDesignerLanguageExtension *le = qt_extension<QDesignerLanguageExtension*>(core->extensionManager(), core))
464 d->m_language = le->name();
465
466 setWorkingDirectory(formWindow->absoluteDir());
467 setResourceBuilder(m_resourceBuilder);
468 setTextBuilder(new QDesignerTextBuilder());
469
470 // ### generalise
471 const QString designerWidget = u"QDesignerWidget"_s;
472 const QString layoutWidget = u"QLayoutWidget"_s;
473 const QString widget = u"QWidget"_s;
474 m_internal_to_qt.insert(layoutWidget, widget);
475 m_internal_to_qt.insert(designerWidget, widget);
476 m_internal_to_qt.insert(u"QDesignerDialog"_s, u"QDialog"_s);
477 m_internal_to_qt.insert(u"QDesignerMenuBar"_s, u"QMenuBar"_s);
478 m_internal_to_qt.insert(u"QDesignerMenu"_s, u"QMenu"_s);
479 m_internal_to_qt.insert(u"QDesignerDockWidget"_s, u"QDockWidget"_s);
480
481 // invert
482 for (auto it = m_internal_to_qt.cbegin(), cend = m_internal_to_qt.cend(); it != cend; ++it ) {
483 if (it.value() != designerWidget && it.value() != layoutWidget)
484 m_qt_to_internal.insert(it.value(), it.key());
485
486 }
487}
488
490
491DomUI *QDesignerResource::readUi(QIODevice *dev)
492{
493 return d->readUi(dev);
494}
495
496static inline QString messageBoxTitle()
497{
498 return QApplication::translate("Designer", "Qt Widgets Designer");
499}
500
501void QDesignerResource::save(QIODevice *dev, QWidget *widget)
502{
503 // Do not write fully qualified enumerations for spacer/line orientations
504 // and other enum/flag properties for older Qt versions since that breaks
505 // older uic.
506 const auto qtVersion = m_formWindow->core()->integration()->qtVersion();
507 d->m_fullyQualifiedEnums = supportsQualifiedEnums(qtVersion);
508 d->m_saveVersion = qtVersion;
509 QAbstractFormBuilder::save(dev, widget);
510}
511
512void QDesignerResource::saveDom(DomUI *ui, QWidget *widget)
513{
514 QAbstractFormBuilder::saveDom(ui, widget);
515
516 QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), widget);
517 Q_ASSERT(sheet != nullptr);
518
519 const QVariant classVar = sheet->property(sheet->indexOf(u"objectName"_s));
520 QString classStr;
521 if (classVar.canConvert<QString>())
522 classStr = classVar.toString();
523 else
524 classStr = qvariant_cast<PropertySheetStringValue>(classVar).value();
525 ui->setElementClass(classStr);
526
527 for (int index = 0; index < m_formWindow->toolCount(); ++index) {
528 QDesignerFormWindowToolInterface *tool = m_formWindow->tool(index);
529 Q_ASSERT(tool != nullptr);
530 tool->saveToDom(ui, widget);
531 }
532
533 const QString author = m_formWindow->author();
534 if (!author.isEmpty()) {
535 ui->setElementAuthor(author);
536 }
537
538 const QString comment = m_formWindow->comment();
539 if (!comment.isEmpty()) {
540 ui->setElementComment(comment);
541 }
542
543 const QString exportMacro = m_formWindow->exportMacro();
544 if (!exportMacro.isEmpty()) {
545 ui->setElementExportMacro(exportMacro);
546 }
547
548 if (m_formWindow->useIdBasedTranslations())
549 ui->setAttributeIdbasedtr(true);
550
551 if (core()->integration()->qtVersion() >= QVersionNumber(6, 10, 0)) {
552 const QString label = m_formWindow->idBasedTranslationLabel();
553 if (!label.isEmpty())
554 ui->setAttributeLabel(label);
555 }
556
557 if (!m_formWindow->connectSlotsByName()) // Don't write out if true (default)
558 ui->setAttributeConnectslotsbyname(false);
559
560 const QVariantMap designerFormData = m_formWindow->formData();
561 if (!designerFormData.isEmpty()) {
562 DomPropertyList domPropertyList;
563 for (auto it = designerFormData.cbegin(), cend = designerFormData.cend(); it != cend; ++it) {
564 if (DomProperty *prop = variantToDomProperty(this, widget->metaObject(), it.key(), it.value()))
565 domPropertyList += prop;
566 }
567 if (!domPropertyList.isEmpty()) {
568 DomDesignerData* domDesignerFormData = new DomDesignerData;
569 domDesignerFormData->setElementProperty(domPropertyList);
570 ui->setElementDesignerdata(domDesignerFormData);
571 }
572 }
573
574 if (!m_formWindow->includeHints().isEmpty()) {
575 const QString local = u"local"_s;
576 const QString global = u"global"_s;
577 QList<DomInclude *> ui_includes;
578 const QStringList &includeHints = m_formWindow->includeHints();
579 ui_includes.reserve(includeHints.size());
580 for (QString includeHint : includeHints) {
581 if (includeHint.isEmpty())
582 continue;
583 DomInclude *incl = new DomInclude;
584 const QString location = includeHint.at(0) == u'<' ? global : local;
585 includeHint.remove(u'"');
586 includeHint.remove(u'<');
587 includeHint.remove(u'>');
588 incl->setAttributeLocation(location);
589 incl->setText(includeHint);
590 ui_includes.append(incl);
591 }
592
593 DomIncludes *includes = new DomIncludes;
594 includes->setElementInclude(ui_includes);
595 ui->setElementIncludes(includes);
596 }
597
598 int defaultMargin = INT_MIN, defaultSpacing = INT_MIN;
599 m_formWindow->layoutDefault(&defaultMargin, &defaultSpacing);
600
601 if (defaultMargin != INT_MIN || defaultSpacing != INT_MIN) {
602 DomLayoutDefault *def = new DomLayoutDefault;
603 if (defaultMargin != INT_MIN)
604 def->setAttributeMargin(defaultMargin);
605 if (defaultSpacing != INT_MIN)
606 def->setAttributeSpacing(defaultSpacing);
607 ui->setElementLayoutDefault(def);
608 }
609
610 QString marginFunction, spacingFunction;
611 m_formWindow->layoutFunction(&marginFunction, &spacingFunction);
612 if (!marginFunction.isEmpty() || !spacingFunction.isEmpty()) {
613 DomLayoutFunction *def = new DomLayoutFunction;
614
615 if (!marginFunction.isEmpty())
616 def->setAttributeMargin(marginFunction);
617 if (!spacingFunction.isEmpty())
618 def->setAttributeSpacing(spacingFunction);
619 ui->setElementLayoutFunction(def);
620 }
621
622 QString pixFunction = m_formWindow->pixmapFunction();
623 if (!pixFunction.isEmpty()) {
624 ui->setElementPixmapFunction(pixFunction);
625 }
626
627 if (QDesignerExtraInfoExtension *extra = qt_extension<QDesignerExtraInfoExtension*>(core()->extensionManager(), core()))
628 extra->saveUiExtraInfo(ui);
629
630 if (MetaDataBase *metaDataBase = qobject_cast<MetaDataBase *>(core()->metaDataBase())) {
631 const MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(m_formWindow->mainContainer());
632 const QStringList fakeSlots = item->fakeSlots();
633 const QStringList fakeSignals =item->fakeSignals();
634 if (!fakeSlots.isEmpty() || !fakeSignals.isEmpty()) {
635 DomSlots *domSlots = new DomSlots();
636 domSlots->setElementSlot(fakeSlots);
637 domSlots->setElementSignal(fakeSignals);
638 ui->setElementSlots(domSlots);
639 }
640 }
641}
642
643QWidget *QDesignerResource::load(QIODevice *dev, QWidget *parentWidget)
644{
645 std::unique_ptr<DomUI> ui(readUi(dev));
646 return ui ? loadUi(ui.get(), parentWidget) : nullptr;
647}
648
649QWidget *QDesignerResource::loadUi(DomUI *ui, QWidget *parentWidget)
650{
651 QWidget *widget = create(ui, parentWidget);
652 // Store the class name as 'reset' value for the main container's object name.
653 if (widget)
654 widget->setProperty("_q_classname", widget->objectName());
655 else if (d->m_errorString.isEmpty())
656 d->m_errorString = QFormBuilderExtra::msgInvalidUiFile();
657 return widget;
658}
659
661{
662 return m_resourceBuilder->isSaveRelative();
663}
664
666{
667 m_resourceBuilder->setSaveRelative(relative);
668}
669
670QWidget *QDesignerResource::create(DomUI *ui, QWidget *parentWidget)
671{
672 // Load extra info extension. This is used by Jambi for preventing
673 // C++ UI files from being loaded
674 if (QDesignerExtraInfoExtension *extra = qt_extension<QDesignerExtraInfoExtension*>(core()->extensionManager(), core())) {
675 if (!extra->loadUiExtraInfo(ui)) {
676 const QString errorMessage = QApplication::translate("Designer", "This file cannot be read because the extra info extension failed to load.");
677 core()->dialogGui()->message(parentWidget->window(), QDesignerDialogGuiInterface::FormLoadFailureMessage,
678 QMessageBox::Warning, messageBoxTitle(), errorMessage, QMessageBox::Ok);
679 return nullptr;
680 }
681 }
682
683 qdesigner_internal::WidgetFactory *factory = qobject_cast<qdesigner_internal::WidgetFactory*>(core()->widgetFactory());
684 Q_ASSERT(factory != nullptr);
685
686 QDesignerFormWindowInterface *previousFormWindow = factory->currentFormWindow(m_formWindow);
687
688 m_isMainWidget = true;
689 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
690 QWidget *mainWidget = QAbstractFormBuilder::create(ui, parentWidget);
691
692 if (m_formWindow) {
693 m_formWindow->setUseIdBasedTranslations(ui->attributeIdbasedtr());
694 m_formWindow->setIdBasedTranslationLabel(ui->attributeLabel());
695 // Default to true unless set.
696 const bool connectSlotsByName = !ui->hasAttributeConnectslotsbyname() || ui->attributeConnectslotsbyname();
697 m_formWindow->setConnectSlotsByName(connectSlotsByName);
698 }
699
700 if (mainWidget && m_formWindow) {
701 m_formWindow->setAuthor(ui->elementAuthor());
702 m_formWindow->setComment(ui->elementComment());
703 m_formWindow->setExportMacro(ui->elementExportMacro());
704
705 // Designer data
706 QVariantMap designerFormData;
707 if (ui->hasElementDesignerdata()) {
708 const DomPropertyList domPropertyList = ui->elementDesignerdata()->elementProperty();
709 for (auto *prop : domPropertyList) {
710 const QVariant vprop = domPropertyToVariant(this, mainWidget->metaObject(), prop);
711 if (vprop.metaType().id() != QMetaType::UnknownType)
712 designerFormData.insert(prop->attributeName(), vprop);
713 }
714 }
715 m_formWindow->setFormData(designerFormData);
716
717 m_formWindow->setPixmapFunction(ui->elementPixmapFunction());
718
719 if (DomLayoutDefault *def = ui->elementLayoutDefault()) {
720 m_formWindow->setLayoutDefault(def->attributeMargin(), def->attributeSpacing());
721 }
722
723 if (DomLayoutFunction *fun = ui->elementLayoutFunction()) {
724 m_formWindow->setLayoutFunction(fun->attributeMargin(), fun->attributeSpacing());
725 }
726
727 if (DomIncludes *includes = ui->elementIncludes()) {
728 const auto global = "global"_L1;
729 QStringList includeHints;
730 const auto &elementInclude = includes->elementInclude();
731 for (DomInclude *incl : elementInclude) {
732 QString text = incl->text();
733
734 if (text.isEmpty())
735 continue;
736
737 if (incl->hasAttributeLocation() && incl->attributeLocation() == global ) {
738 text.prepend(u'<');
739 text.append(u'>');
740 } else {
741 text.prepend(u'"');
742 text.append(u'"');
743 }
744
745 includeHints.append(text);
746 }
747
748 m_formWindow->setIncludeHints(includeHints);
749 }
750
751 // Register all button groups the form builder adds as children of the main container for them to be found
752 // in the signal slot editor
753 auto *mdb = core()->metaDataBase();
754 for (auto *child : mainWidget->children()) {
755 if (QButtonGroup *bg = qobject_cast<QButtonGroup*>(child))
756 mdb->add(bg);
757 }
758 // Load tools
759 for (int index = 0; index < m_formWindow->toolCount(); ++index) {
760 QDesignerFormWindowToolInterface *tool = m_formWindow->tool(index);
761 Q_ASSERT(tool != nullptr);
762 tool->loadFromDom(ui, mainWidget);
763 }
764 }
765
766 factory->currentFormWindow(previousFormWindow);
767
768 if (const DomSlots *domSlots = ui->elementSlots()) {
769 if (MetaDataBase *metaDataBase = qobject_cast<MetaDataBase *>(core()->metaDataBase())) {
770 QStringList fakeSlots;
771 QStringList fakeSignals;
772 if (addFakeMethods(domSlots, fakeSlots, fakeSignals)) {
773 MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(mainWidget);
774 item->setFakeSlots(fakeSlots);
775 item->setFakeSignals(fakeSignals);
776 }
777 }
778 }
779 if (mainWidget) {
780 // Initialize the mainwindow geometry. Has it been explicitly specified?
781 bool hasExplicitGeometry = false;
782 const auto &properties = ui->elementWidget()->elementProperty();
783 if (!properties.isEmpty()) {
784 for (const DomProperty *p : properties) {
785 if (p->attributeName() == "geometry"_L1) {
786 hasExplicitGeometry = true;
787 break;
788 }
789 }
790 }
791 if (hasExplicitGeometry) {
792 // Geometry was specified explicitly: Verify that smartMinSize is respected
793 // (changed fonts, label wrapping policies, etc). This does not happen automatically in docked mode.
794 const QSize size = mainWidget->size();
795 const QSize minSize = size.expandedTo(qSmartMinSize(mainWidget));
796 if (minSize != size)
797 mainWidget->resize(minSize);
798 } else {
799 // No explicit Geometry: perform an adjustSize() to resize the form correctly before embedding it into a container
800 // (which might otherwise squeeze the form)
801 mainWidget->adjustSize();
802 }
803 // Some integration wizards create forms with main containers
804 // based on derived classes of QWidget and load them into Designer
805 // without the plugin existing. This will trigger the auto-promotion
806 // mechanism of Designer, which will set container=false for
807 // QWidgets. For the main container, force container=true and warn.
808 const QDesignerWidgetDataBaseInterface *wdb = core()->widgetDataBase();
809 const int wdbIndex = wdb->indexOfObject(mainWidget);
810 if (wdbIndex != -1) {
811 QDesignerWidgetDataBaseItemInterface *item = wdb->item(wdbIndex);
812 // Promoted main container that is not of container type
813 if (item->isPromoted() && !item->isContainer()) {
814 item->setContainer(true);
815 qWarning("** WARNING The form's main container is an unknown custom widget '%s'."
816 " Defaulting to a promoted instance of '%s', assuming container.",
817 item->name().toUtf8().constData(), item->extends().toUtf8().constData());
818 }
819 }
820 }
821 return mainWidget;
822}
823
824QWidget *QDesignerResource::create(DomWidget *ui_widget, QWidget *parentWidget)
825{
826 const QString className = ui_widget->attributeClass();
827 if (!m_isMainWidget && className == "QWidget"_L1
828 && !ui_widget->elementLayout().isEmpty()
829 && !ui_widget->hasAttributeNative()) {
830 // ### check if elementLayout.size() == 1
831
832 QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), parentWidget);
833
834 if (container == nullptr) {
835 // generate a QLayoutWidget iff the parent is not an QDesignerContainerExtension.
836 ui_widget->setAttributeClass(u"QLayoutWidget"_s);
837 }
838 }
839
840 // save the actions
841 const auto &actionRefs = ui_widget->elementAddAction();
842 ui_widget->setElementAddAction(QList<DomActionRef *>());
843
844 QWidget *w = QAbstractFormBuilder::create(ui_widget, parentWidget);
845
846 // restore the actions
847 ui_widget->setElementAddAction(actionRefs);
848
849 if (w == nullptr)
850 return nullptr;
851
852 // ### generalize using the extension manager
853 QDesignerMenu *menu = qobject_cast<QDesignerMenu*>(w);
854 QDesignerMenuBar *menuBar = qobject_cast<QDesignerMenuBar*>(w);
855
856 if (menu)
857 menu->hide();
858
859 for (DomActionRef *ui_action_ref : actionRefs) {
860 const QString name = ui_action_ref->attributeName();
861 if (name == "separator"_L1) {
862 QAction *sep = new QAction(w);
863 sep->setSeparator(true);
864 w->addAction(sep);
865 addMenuAction(sep);
866 } else if (QAction *a = d->m_actions.value(name)) {
867 w->addAction(a);
868 } else if (QActionGroup *g = d->m_actionGroups.value(name)) {
869 w->addActions(g->actions());
870 } else if (QMenu *menu = w->findChild<QMenu*>(name)) {
871 w->addAction(menu->menuAction());
872 addMenuAction(menu->menuAction());
873 }
874 }
875
876 if (menu)
877 menu->adjustSpecialActions();
878 else if (menuBar)
879 menuBar->adjustSpecialActions();
880
881 ui_widget->setAttributeClass(className); // fix the class name
882 applyExtensionDataFromDOM(this, core(), ui_widget, w);
883
884 return w;
885}
886
887QLayout *QDesignerResource::create(DomLayout *ui_layout, QLayout *layout, QWidget *parentWidget)
888{
889 QLayout *l = QAbstractFormBuilder::create(ui_layout, layout, parentWidget);
890
891 if (QGridLayout *gridLayout = qobject_cast<QGridLayout*>(l)) {
892 QLayoutSupport::createEmptyCells(gridLayout);
893 } else {
894 if (QFormLayout *formLayout = qobject_cast<QFormLayout*>(l))
895 QLayoutSupport::createEmptyCells(formLayout);
896 }
897 // While the actual values are applied by the form builder, we still need
898 // to mark them as 'changed'.
899 LayoutPropertySheet::markChangedStretchProperties(core(), l, ui_layout);
900 return l;
901}
902
903QLayoutItem *QDesignerResource::create(DomLayoutItem *ui_layoutItem, QLayout *layout, QWidget *parentWidget)
904{
905 if (ui_layoutItem->kind() == DomLayoutItem::Spacer) {
906 const DomSpacer *domSpacer = ui_layoutItem->elementSpacer();
907 Spacer *spacer = static_cast<Spacer*>(core()->widgetFactory()->createWidget(u"Spacer"_s, parentWidget));
908 if (domSpacer->hasAttributeName())
909 changeObjectName(spacer, domSpacer->attributeName());
910 core()->metaDataBase()->add(spacer);
911
912 spacer->setInteractiveMode(false);
913 applyProperties(spacer, ui_layoutItem->elementSpacer()->elementProperty());
914 spacer->setInteractiveMode(true);
915
916 if (m_formWindow) {
917 m_formWindow->manageWidget(spacer);
918 if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), spacer))
919 sheet->setChanged(sheet->indexOf(u"orientation"_s), true);
920 }
921
922 return new QWidgetItem(spacer);
923 }
924 if (ui_layoutItem->kind() == DomLayoutItem::Layout && parentWidget) {
925 DomLayout *ui_layout = ui_layoutItem->elementLayout();
926 QLayoutWidget *layoutWidget = new QLayoutWidget(m_formWindow, parentWidget);
927 core()->metaDataBase()->add(layoutWidget);
928 if (m_formWindow)
929 m_formWindow->manageWidget(layoutWidget);
930 (void) create(ui_layout, nullptr, layoutWidget);
931 return new QWidgetItem(layoutWidget);
932 }
933 return QAbstractFormBuilder::create(ui_layoutItem, layout, parentWidget);
934}
935
936void QDesignerResource::changeObjectName(QObject *o, QString objName)
937{
938 m_formWindow->unify(o, objName, true);
939 o->setObjectName(objName);
940
941}
942
943/* If the property is a enum or flag value, retrieve
944 * the existing enum/flag via property sheet and use it to convert */
945
946static bool readDomEnumerationValue(const DomProperty *p,
947 const QDesignerPropertySheetExtension* sheet, int index,
948 QVariant &v)
949{
950 switch (p->kind()) {
951 case DomProperty::Set: {
952 const QVariant sheetValue = sheet->property(index);
953 if (sheetValue.canConvert<PropertySheetFlagValue>()) {
954 const PropertySheetFlagValue f = qvariant_cast<PropertySheetFlagValue>(sheetValue);
955 bool ok = false;
956 v = f.metaFlags.parseFlags(p->elementSet(), &ok);
957 if (!ok)
958 designerWarning(f.metaFlags.messageParseFailed(p->elementSet()));
959 return true;
960 }
961 }
962 break;
963 case DomProperty::Enum: {
964 const QVariant sheetValue = sheet->property(index);
965 if (sheetValue.canConvert<PropertySheetEnumValue>()) {
966 const PropertySheetEnumValue e = qvariant_cast<PropertySheetEnumValue>(sheetValue);
967 bool ok = false;
968 v = e.metaEnum.parseEnum(p->elementEnum(), &ok);
969 if (!ok)
970 designerWarning(e.metaEnum.messageParseFailed(p->elementEnum()));
971 return true;
972 }
973 }
974 break;
975 default:
976 break;
977 }
978 return false;
979}
980
981// ### fixme Qt 7 remove this: Exclude deprecated properties of Qt 5.
982static bool isDeprecatedQt5Property(const QObject *o, const DomProperty *p)
983{
984 const QString &propertyName = p->attributeName();
985 switch (p->kind()) {
986 case DomProperty::Set:
987 if (propertyName == u"features" && o->inherits("QDockWidget")
988 && p->elementSet() == u"QDockWidget::AllDockWidgetFeatures") {
989 return true;
990 }
991 break;
992 case DomProperty::Enum:
993 if (propertyName == u"sizeAdjustPolicy" && o->inherits("QComboBox")
994 && p->elementEnum() == u"QComboBox::AdjustToMinimumContentsLength") {
995 return true;
996 }
997 break;
998 default:
999 break;
1000 }
1001 return false;
1002}
1003
1004void QDesignerResource::applyProperties(QObject *o, const QList<DomProperty*> &properties)
1005{
1006 if (properties.isEmpty())
1007 return;
1008
1009 auto *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), o);
1010 if (!sheet)
1011 return;
1012
1013 auto *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core()->extensionManager(), o);
1014 if (dynamicSheet != nullptr && !dynamicSheet->dynamicPropertiesAllowed())
1015 dynamicSheet = nullptr;
1016
1017 for (DomProperty *p : properties) {
1018 if (isDeprecatedQt5Property(o, p)) // ### fixme Qt 7 remove this
1019 continue; // ### fixme Qt 7 remove this: Exclude deprecated value of Qt 5.
1020 const QString &propertyName = p->attributeName();
1021 if (propertyName == "numDigits"_L1 && o->inherits("QLCDNumber")) { // Deprecated in Qt 4, removed in Qt 5.
1022 applyProperty(o, p, u"digitCount"_s, sheet, dynamicSheet);
1023#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) // Qt 6 reading Qt 7 forms
1024 } else if (propertyName == "horizontalSizeConstraint"_L1 && o->inherits("QLayout")) {
1025 applyProperty(o, p, u"sizeConstraint"_s, sheet, dynamicSheet);
1026#else // Qt 7 reading pre Qt 7 forms
1027 } else if (propertyName == "sizeConstraint"_L1 && o->inherits("QLayout")) {
1028 applyProperty(o, p, u"horizontalSizeConstraint"_s, sheet, dynamicSheet);
1029 applyProperty(o, p, u"verticalSizeConstraint"_s, sheet, dynamicSheet);
1030#endif
1031 } else {
1032 applyProperty(o, p, propertyName, sheet, dynamicSheet);
1033 }
1034 }
1035}
1036
1037void QDesignerResource::applyProperty(QObject *o, DomProperty* p, const QString &propertyName,
1040{
1041 const int index = sheet->indexOf(propertyName);
1042 QVariant v;
1043 if (!readDomEnumerationValue(p, sheet, index, v))
1044 v = toVariant(o->metaObject(), p);
1045 switch (p->kind()) {
1046 case DomProperty::String:
1047 if (index != -1 && sheet->property(index).userType() == qMetaTypeId<PropertySheetKeySequenceValue>()) {
1048 const DomString *key = p->elementString();
1049 PropertySheetKeySequenceValue keyVal(QKeySequence(key->text()));
1050 translationParametersFromDom(key, &keyVal);
1051 v = QVariant::fromValue(keyVal);
1052 } else {
1053 const DomString *str = p->elementString();
1054 PropertySheetStringValue strVal(v.toString());
1055 translationParametersFromDom(str, &strVal);
1056 v = QVariant::fromValue(strVal);
1057 }
1058 break;
1059 case DomProperty::StringList: {
1060 const DomStringList *list = p->elementStringList();
1061 PropertySheetStringListValue listValue(list->elementString());
1062 translationParametersFromDom(list, &listValue);
1063 v = QVariant::fromValue(listValue);
1064 }
1065 break;
1066 default:
1067 break;
1068 }
1069 d->applyPropertyInternally(o, propertyName, v);
1070 if (index != -1) {
1071 sheet->setProperty(index, v);
1072 sheet->setChanged(index, true);
1073 } else if (dynamicSheet != nullptr) {
1074 QVariant defaultValue = QVariant(v.metaType());
1075 bool isDefault = (v == defaultValue);
1076 if (v.canConvert<PropertySheetIconValue>()) {
1077 defaultValue = QVariant(QMetaType(QMetaType::QIcon));
1078 isDefault = (qvariant_cast<PropertySheetIconValue>(v) == PropertySheetIconValue());
1079 } else if (v.canConvert<PropertySheetPixmapValue>()) {
1080 defaultValue = QVariant(QMetaType(QMetaType::QPixmap));
1081 isDefault = (qvariant_cast<PropertySheetPixmapValue>(v) == PropertySheetPixmapValue());
1082 } else if (v.canConvert<PropertySheetStringValue>()) {
1083 defaultValue = QVariant(QMetaType(QMetaType::QString));
1084 isDefault = (qvariant_cast<PropertySheetStringValue>(v) == PropertySheetStringValue());
1085 } else if (v.canConvert<PropertySheetStringListValue>()) {
1086 defaultValue = QVariant(QMetaType(QMetaType::QStringList));
1087 isDefault = (qvariant_cast<PropertySheetStringListValue>(v) == PropertySheetStringListValue());
1088 } else if (v.canConvert<PropertySheetKeySequenceValue>()) {
1089 defaultValue = QVariant(QMetaType(QMetaType::QKeySequence));
1090 isDefault = (qvariant_cast<PropertySheetKeySequenceValue>(v) == PropertySheetKeySequenceValue());
1091 }
1092 if (defaultValue.metaType().id() != QMetaType::User) {
1093 const int idx = dynamicSheet->addDynamicProperty(p->attributeName(), defaultValue);
1094 if (idx != -1) {
1095 sheet->setProperty(idx, v);
1096 sheet->setChanged(idx, !isDefault);
1097 }
1098 }
1099 }
1100
1101 if (propertyName == "objectName"_L1)
1102 changeObjectName(o, o->objectName());
1103}
1104
1105QWidget *QDesignerResource::createWidget(const QString &widgetName, QWidget *parentWidget, const QString &_name)
1106{
1107 QString name = _name;
1108 if (m_isMainWidget)
1109 m_isMainWidget = false;
1110
1111 QWidget *w = core()->widgetFactory()->createWidget(widgetName, parentWidget);
1112 if (!w)
1113 return nullptr;
1114
1115 if (name.isEmpty()) {
1116 QDesignerWidgetDataBaseInterface *db = core()->widgetDataBase();
1117 if (QDesignerWidgetDataBaseItemInterface *item = db->item(db->indexOfObject(w)))
1118 name = qtify(item->name());
1119 }
1120
1121 changeObjectName(w, name);
1122
1123 QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), parentWidget);
1124 if (!qobject_cast<QMenu*>(w) && (!parentWidget || !container)) {
1125 m_formWindow->manageWidget(w);
1126 if (parentWidget) {
1127 QWidgetList list = qvariant_cast<QWidgetList>(parentWidget->property("_q_widgetOrder"));
1128 list.append(w);
1129 parentWidget->setProperty("_q_widgetOrder", QVariant::fromValue(list));
1130 QWidgetList zOrder = qvariant_cast<QWidgetList>(parentWidget->property("_q_zOrder"));
1131 zOrder.append(w);
1132 parentWidget->setProperty("_q_zOrder", QVariant::fromValue(zOrder));
1133 }
1134 } else {
1135 core()->metaDataBase()->add(w);
1136 }
1137
1138 w->setWindowFlags(w->windowFlags() & ~Qt::Window);
1139 // Make sure it is non-modal (for example, KDialog calls setModal(true) in the constructor).
1140 w->setWindowModality(Qt::NonModal);
1141
1142 return w;
1143}
1144
1145QLayout *QDesignerResource::createLayout(const QString &layoutName, QObject *parent, const QString &name)
1146{
1147 QWidget *layoutBase = nullptr;
1148 QLayout *layout = qobject_cast<QLayout*>(parent);
1149
1150 if (parent->isWidgetType())
1151 layoutBase = static_cast<QWidget*>(parent);
1152 else {
1153 Q_ASSERT( layout != nullptr );
1154 layoutBase = layout->parentWidget();
1155 }
1156
1157 LayoutInfo::Type layoutType = LayoutInfo::layoutType(layoutName);
1158 if (layoutType == LayoutInfo::NoLayout) {
1159 designerWarning(QCoreApplication::translate("QDesignerResource", "The layout type '%1' is not supported, defaulting to grid.").arg(layoutName));
1160 layoutType = LayoutInfo::Grid;
1161 }
1162 QLayout *lay = core()->widgetFactory()->createLayout(layoutBase, layout, layoutType);
1163 if (lay != nullptr)
1164 changeObjectName(lay, name);
1165
1166 return lay;
1167}
1168
1169// save
1170DomWidget *QDesignerResource::createDom(QWidget *widget, DomWidget *ui_parentWidget, bool recursive)
1171{
1172 QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(widget);
1173 if (!item)
1174 return nullptr;
1175
1176 if (qobject_cast<Spacer*>(widget) && !m_copyWidget)
1177 return nullptr;
1178
1179 const QDesignerWidgetDataBaseInterface *wdb = core()->widgetDataBase();
1180 QDesignerWidgetDataBaseItemInterface *widgetInfo = nullptr;
1181 const int widgetInfoIndex = wdb->indexOfObject(widget, false);
1182 if (widgetInfoIndex != -1) {
1183 widgetInfo = wdb->item(widgetInfoIndex);
1184 // Recursively add all dependent custom widgets
1185 QDesignerWidgetDataBaseItemInterface *customInfo = widgetInfo;
1186 while (customInfo && customInfo->isCustom()) {
1187 m_usedCustomWidgets.insert(customInfo, true);
1188 const QString extends = customInfo->extends();
1189 if (extends == customInfo->name())
1190 break; // There are faulty files around that have name==extends
1191 const int extendsIndex = wdb->indexOfClassName(customInfo->extends());
1192 customInfo = extendsIndex != -1 ? wdb->item(extendsIndex) : nullptr;
1193 }
1194 }
1195
1196 DomWidget *w = nullptr;
1197
1198 if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(widget))
1199 w = saveWidget(tabWidget, ui_parentWidget);
1200 else if (QStackedWidget *stackedWidget = qobject_cast<QStackedWidget*>(widget))
1201 w = saveWidget(stackedWidget, ui_parentWidget);
1202 else if (QToolBox *toolBox = qobject_cast<QToolBox*>(widget))
1203 w = saveWidget(toolBox, ui_parentWidget);
1204 else if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget))
1205 w = saveWidget(toolBar, ui_parentWidget);
1206 else if (QDesignerDockWidget *dockWidget = qobject_cast<QDesignerDockWidget*>(widget))
1207 w = saveWidget(dockWidget, ui_parentWidget);
1208 else if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget))
1209 w = saveWidget(widget, container, ui_parentWidget);
1210 else if (QWizardPage *wizardPage = qobject_cast<QWizardPage*>(widget))
1211 w = saveWidget(wizardPage, ui_parentWidget);
1212 else
1213 w = QAbstractFormBuilder::createDom(widget, ui_parentWidget, recursive);
1214
1215 Q_ASSERT( w != nullptr );
1216
1217 if (!qobject_cast<QLayoutWidget*>(widget) && w->attributeClass() == "QWidget"_L1)
1218 w->setAttributeNative(true);
1219
1220 const QString className = w->attributeClass();
1221 if (m_internal_to_qt.contains(className))
1222 w->setAttributeClass(m_internal_to_qt.value(className));
1223
1224 if (isPromoted( core(), widget)) { // is promoted?
1225 Q_ASSERT(widgetInfo != nullptr);
1226
1227 w->setAttributeClass(widgetInfo->name());
1228
1229 const auto &prop_list = w->elementProperty();
1230 for (DomProperty *prop : prop_list) {
1231 if (prop->attributeName() == "geometry"_L1) {
1232 if (DomRect *rect = prop->elementRect()) {
1233 rect->setElementX(widget->x());
1234 rect->setElementY(widget->y());
1235 }
1236 break;
1237 }
1238 }
1239 } else if (widgetInfo != nullptr && m_usedCustomWidgets.contains(widgetInfo)) {
1240 if (widgetInfo->name() != w->attributeClass())
1241 w->setAttributeClass(widgetInfo->name());
1242 }
1243 addExtensionDataToDOM(this, core(), w, widget);
1244 return w;
1245}
1246
1247DomLayout *QDesignerResource::createDom(QLayout *layout, DomLayout *ui_parentLayout, DomWidget *ui_parentWidget)
1248{
1249 QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(layout);
1250
1251 if (item == nullptr) {
1252 layout = layout->findChild<QLayout*>();
1253 // refresh the meta database item
1254 item = core()->metaDataBase()->item(layout);
1255 }
1256
1257 if (item == nullptr) {
1258 // nothing to do.
1259 return nullptr;
1260 }
1261
1262 if (qobject_cast<QSplitter*>(layout->parentWidget()) != 0) {
1263 // nothing to do.
1264 return nullptr;
1265 }
1266
1267 m_chain.push(layout);
1268
1269 DomLayout *l = QAbstractFormBuilder::createDom(layout, ui_parentLayout, ui_parentWidget);
1270 Q_ASSERT(l != nullptr);
1271 LayoutPropertySheet::stretchAttributesToDom(core(), layout, l);
1272
1273 m_chain.pop();
1274
1275 return l;
1276}
1277
1278DomLayoutItem *QDesignerResource::createDom(QLayoutItem *item, DomLayout *ui_layout, DomWidget *ui_parentWidget)
1279{
1280 DomLayoutItem *ui_item = nullptr;
1281
1282 if (Spacer *s = qobject_cast<Spacer*>(item->widget())) {
1283 if (!core()->metaDataBase()->item(s))
1284 return nullptr;
1285
1286 DomSpacer *spacer = new DomSpacer();
1287 const QString objectName = s->objectName();
1288 if (!objectName.isEmpty())
1289 spacer->setAttributeName(objectName);
1290 // ### filter the properties
1291 spacer->setElementProperty(computeProperties(item->widget()));
1292
1293 ui_item = new DomLayoutItem();
1294 ui_item->setElementSpacer(spacer);
1295 d->m_laidout.insert(item->widget(), true);
1296 } else if (QLayoutWidget *layoutWidget = qobject_cast<QLayoutWidget*>(item->widget())) {
1297 // Do not save a QLayoutWidget if it is within a layout (else it is saved as "QWidget"
1298 Q_ASSERT(layoutWidget->layout());
1299 DomLayout *l = createDom(layoutWidget->layout(), ui_layout, ui_parentWidget);
1300 ui_item = new DomLayoutItem();
1301 ui_item->setElementLayout(l);
1302 d->m_laidout.insert(item->widget(), true);
1303 } else if (!item->spacerItem()) { // we use spacer as fake item in the Designer
1304 ui_item = QAbstractFormBuilder::createDom(item, ui_layout, ui_parentWidget);
1305 } else {
1306 return nullptr;
1307 }
1308 return ui_item;
1309}
1310
1311void QDesignerResource::createCustomWidgets(DomCustomWidgets *dom_custom_widgets)
1312{
1313 QSimpleResource::handleDomCustomWidgets(core(), dom_custom_widgets);
1314}
1315
1317{
1318 QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(m_formWindow);
1319 Q_ASSERT(item);
1320
1321 QStringList tabStops;
1322 const QWidgetList &tabOrder = item->tabOrder();
1323 for (QWidget *widget : tabOrder) {
1324 if (m_formWindow->mainContainer()->isAncestorOf(widget))
1325 tabStops.append(widget->objectName());
1326 }
1327
1328 if (!tabStops.isEmpty()) {
1329 DomTabStops *dom = new DomTabStops;
1330 dom->setElementTabStop(tabStops);
1331 return dom;
1332 }
1333
1334 return nullptr;
1335}
1336
1337void QDesignerResource::applyTabStops(QWidget *widget, DomTabStops *tabStops)
1338{
1339 if (tabStops == nullptr || widget == nullptr)
1340 return;
1341
1342 QWidgetList tabOrder;
1343 const QStringList &elementTabStop = tabStops->elementTabStop();
1344 for (const QString &widgetName : elementTabStop) {
1345 if (QWidget *w = widget->findChild<QWidget*>(widgetName)) {
1346 tabOrder.append(w);
1347 }
1348 }
1349
1350 QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(m_formWindow);
1351 Q_ASSERT(item);
1352 item->setTabOrder(tabOrder);
1353}
1354
1355/* Unmanaged container pages occur when someone adds a page in a custom widget
1356 * constructor. They don't have a meta DB entry which causes createDom
1357 * to return 0. */
1358inline QString msgUnmanagedPage(QDesignerFormEditorInterface *core,
1359 QWidget *container, int index, QWidget *page)
1360{
1361 return QCoreApplication::translate("QDesignerResource",
1362"The container extension of the widget '%1' (%2) returned a widget not managed by Designer '%3' (%4) when queried for page #%5.\n"
1363"Container pages should only be added by specifying them in XML returned by the domXml() method of the custom widget.").
1364 arg(container->objectName(), WidgetFactory::classNameOf(core, container),
1365 page->objectName(), WidgetFactory::classNameOf(core, page)).
1366 arg(index);
1367}
1368
1369DomWidget *QDesignerResource::saveWidget(QWidget *widget, QDesignerContainerExtension *container, DomWidget *ui_parentWidget)
1370{
1371 DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false);
1372 QList<DomWidget *> ui_widget_list;
1373
1374 for (int i=0; i<container->count(); ++i) {
1375 QWidget *page = container->widget(i);
1376 Q_ASSERT(page);
1377
1378 if (DomWidget *ui_page = createDom(page, ui_widget)) {
1379 ui_widget_list.append(ui_page);
1380 } else {
1381 designerWarning(msgUnmanagedPage(core(), widget, i, page));
1382 }
1383 }
1384
1385 ui_widget->setElementWidget(ui_widget_list);
1386
1387 return ui_widget;
1388}
1389
1390DomWidget *QDesignerResource::saveWidget(QStackedWidget *widget, DomWidget *ui_parentWidget)
1391{
1392 DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false);
1393 QList<DomWidget *> ui_widget_list;
1394 if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) {
1395 for (int i=0; i<container->count(); ++i) {
1396 QWidget *page = container->widget(i);
1397 Q_ASSERT(page);
1398 if (DomWidget *ui_page = createDom(page, ui_widget)) {
1399 ui_widget_list.append(ui_page);
1400 } else {
1401 designerWarning(msgUnmanagedPage(core(), widget, i, page));
1402 }
1403 }
1404 }
1405
1406 ui_widget->setElementWidget(ui_widget_list);
1407
1408 return ui_widget;
1409}
1410
1411DomWidget *QDesignerResource::saveWidget(QToolBar *toolBar, DomWidget *ui_parentWidget)
1412{
1413 DomWidget *ui_widget = QAbstractFormBuilder::createDom(toolBar, ui_parentWidget, false);
1414 if (const QMainWindow *mainWindow = qobject_cast<QMainWindow*>(toolBar->parentWidget())) {
1415 const bool toolBarBreak = mainWindow->toolBarBreak(toolBar);
1416 const Qt::ToolBarArea area = mainWindow->toolBarArea(toolBar);
1417
1418 auto attributes = ui_widget->elementAttribute();
1419
1420 DomProperty *attr = new DomProperty();
1421 attr->setAttributeName(u"toolBarArea"_s);
1422 attr->setElementEnum(QLatin1StringView(toolBarAreaMetaEnum().valueToKey(area)));
1423 attributes << attr;
1424
1425 attr = new DomProperty();
1426 attr->setAttributeName(u"toolBarBreak"_s);
1427 attr->setElementBool(toolBarBreak ? u"true"_s : u"false"_s);
1428 attributes << attr;
1429 ui_widget->setElementAttribute(attributes);
1430 }
1431
1432 return ui_widget;
1433}
1434
1435DomWidget *QDesignerResource::saveWidget(QDesignerDockWidget *dockWidget, DomWidget *ui_parentWidget)
1436{
1437 DomWidget *ui_widget = QAbstractFormBuilder::createDom(dockWidget, ui_parentWidget, true);
1438 if (QMainWindow *mainWindow = qobject_cast<QMainWindow*>(dockWidget->parentWidget())) {
1439 const Qt::DockWidgetArea area = mainWindow->dockWidgetArea(dockWidget);
1440 DomProperty *attr = new DomProperty();
1441 attr->setAttributeName(u"dockWidgetArea"_s);
1442 attr->setElementNumber(int(area));
1443 ui_widget->setElementAttribute(ui_widget->elementAttribute() << attr);
1444 }
1445
1446 return ui_widget;
1447}
1448
1449DomWidget *QDesignerResource::saveWidget(QTabWidget *widget, DomWidget *ui_parentWidget)
1450{
1451 DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false);
1452 QList<DomWidget *> ui_widget_list;
1453
1454 if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) {
1455 const int current = widget->currentIndex();
1456 for (int i=0; i<container->count(); ++i) {
1457 QWidget *page = container->widget(i);
1458 Q_ASSERT(page);
1459
1460 DomWidget *ui_page = createDom(page, ui_widget);
1461 if (!ui_page) {
1462 designerWarning(msgUnmanagedPage(core(), widget, i, page));
1463 continue;
1464 }
1465 QList<DomProperty*> ui_attribute_list;
1466
1467 // attribute `icon'
1468 widget->setCurrentIndex(i);
1469 QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), widget);
1470 PropertySheetIconValue icon = qvariant_cast<PropertySheetIconValue>(sheet->property(sheet->indexOf(u"currentTabIcon"_s)));
1471 DomProperty *p = resourceBuilder()->saveResource(workingDirectory(), QVariant::fromValue(icon));
1472 if (p) {
1473 p->setAttributeName(QFormBuilderStrings::iconAttribute);
1474 ui_attribute_list.append(p);
1475 }
1476 // attribute `title'
1477 p = textBuilder()->saveText(sheet->property(sheet->indexOf(u"currentTabText"_s)));
1478 if (p) {
1479 p->setAttributeName(QFormBuilderStrings::titleAttribute);
1480 ui_attribute_list.append(p);
1481 }
1482
1483 // attribute `toolTip'
1484 QVariant v = sheet->property(sheet->indexOf(u"currentTabToolTip"_s));
1485 if (!qvariant_cast<PropertySheetStringValue>(v).value().isEmpty()) {
1486 p = textBuilder()->saveText(v);
1487 if (p) {
1488 p->setAttributeName(QFormBuilderStrings::toolTipAttribute);
1489 ui_attribute_list.append(p);
1490 }
1491 }
1492
1493 // attribute `whatsThis'
1494 v = sheet->property(sheet->indexOf(u"currentTabWhatsThis"_s));
1495 if (!qvariant_cast<PropertySheetStringValue>(v).value().isEmpty()) {
1496 p = textBuilder()->saveText(v);
1497 if (p) {
1498 p->setAttributeName(QFormBuilderStrings::whatsThisAttribute);
1499 ui_attribute_list.append(p);
1500 }
1501 }
1502
1503 ui_page->setElementAttribute(ui_attribute_list);
1504
1505 ui_widget_list.append(ui_page);
1506 }
1507 widget->setCurrentIndex(current);
1508 }
1509
1510 ui_widget->setElementWidget(ui_widget_list);
1511
1512 return ui_widget;
1513}
1514
1515DomWidget *QDesignerResource::saveWidget(QToolBox *widget, DomWidget *ui_parentWidget)
1516{
1517 DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false);
1518 QList<DomWidget *> ui_widget_list;
1519
1520 if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) {
1521 const int current = widget->currentIndex();
1522 for (int i=0; i<container->count(); ++i) {
1523 QWidget *page = container->widget(i);
1524 Q_ASSERT(page);
1525
1526 DomWidget *ui_page = createDom(page, ui_widget);
1527 if (!ui_page) {
1528 designerWarning(msgUnmanagedPage(core(), widget, i, page));
1529 continue;
1530 }
1531
1532 // attribute `label'
1533 QList<DomProperty*> ui_attribute_list;
1534
1535 // attribute `icon'
1536 widget->setCurrentIndex(i);
1537 QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), widget);
1538 PropertySheetIconValue icon = qvariant_cast<PropertySheetIconValue>(sheet->property(sheet->indexOf(u"currentItemIcon"_s)));
1539 DomProperty *p = resourceBuilder()->saveResource(workingDirectory(), QVariant::fromValue(icon));
1540 if (p) {
1541 p->setAttributeName(QFormBuilderStrings::iconAttribute);
1542 ui_attribute_list.append(p);
1543 }
1544 p = textBuilder()->saveText(sheet->property(sheet->indexOf(u"currentItemText"_s)));
1545 if (p) {
1546 p->setAttributeName(QFormBuilderStrings::labelAttribute);
1547 ui_attribute_list.append(p);
1548 }
1549
1550 // attribute `toolTip'
1551 QVariant v = sheet->property(sheet->indexOf(u"currentItemToolTip"_s));
1552 if (!qvariant_cast<PropertySheetStringValue>(v).value().isEmpty()) {
1553 p = textBuilder()->saveText(v);
1554 if (p) {
1555 p->setAttributeName(QFormBuilderStrings::toolTipAttribute);
1556 ui_attribute_list.append(p);
1557 }
1558 }
1559
1560 ui_page->setElementAttribute(ui_attribute_list);
1561
1562 ui_widget_list.append(ui_page);
1563 }
1564 widget->setCurrentIndex(current);
1565 }
1566
1567 ui_widget->setElementWidget(ui_widget_list);
1568
1569 return ui_widget;
1570}
1571
1572DomWidget *QDesignerResource::saveWidget(QWizardPage *wizardPage, DomWidget *ui_parentWidget)
1573{
1574 DomWidget *ui_widget = QAbstractFormBuilder::createDom(wizardPage, ui_parentWidget, true);
1575 QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), wizardPage);
1576 // Save the page id (string) attribute, append to existing attributes
1577 const QString pageIdPropertyName = QLatin1StringView(QWizardPagePropertySheet::pageIdProperty);
1578 const int pageIdIndex = sheet->indexOf(pageIdPropertyName);
1579 if (pageIdIndex != -1 && sheet->isChanged(pageIdIndex)) {
1580 DomProperty *property = variantToDomProperty(this, wizardPage->metaObject(), pageIdPropertyName, sheet->property(pageIdIndex));
1581 Q_ASSERT(property);
1582 property->elementString()->setAttributeNotr(u"true"_s);
1583 DomPropertyList attributes = ui_widget->elementAttribute();
1584 attributes.push_back(property);
1585 ui_widget->setElementAttribute(attributes);
1586 }
1587 return ui_widget;
1588}
1589
1590// Do not save the 'currentTabName' properties of containers
1591static inline bool checkContainerProperty(const QWidget *w, const QString &propertyName)
1592{
1593 if (qobject_cast<const QToolBox *>(w))
1594 return QToolBoxWidgetPropertySheet::checkProperty(propertyName);
1595 if (qobject_cast<const QTabWidget *>(w))
1596 return QTabWidgetPropertySheet::checkProperty(propertyName);
1597 if (qobject_cast<const QStackedWidget *>(w))
1598 return QStackedWidgetPropertySheet::checkProperty(propertyName);
1599 if (qobject_cast<const QMdiArea *>(w))
1600 return QMdiAreaPropertySheet::checkProperty(propertyName);
1601 return true;
1602}
1603
1604bool QDesignerResource::checkProperty(QObject *obj, const QString &prop) const
1605{
1606 const QDesignerMetaObjectInterface *meta = core()->introspection()->metaObject(obj);
1607
1608 const int pindex = meta->indexOfProperty(prop);
1609 if (pindex != -1 && !meta->property(pindex)->attributes().testFlag(QDesignerMetaPropertyInterface::StoredAttribute))
1610 return false;
1611
1612 if (prop == "objectName"_L1 || prop == "spacerName"_L1) // ### don't store the property objectName
1613 return false;
1614
1615 if (!supportsSeparateSizeConstraints(d->m_saveVersion)
1616 && prop == "verticalSizeConstraint"_L1) { // 7.0
1617 return false;
1618 }
1619
1620 QWidget *check_widget = nullptr;
1621 if (obj->isWidgetType())
1622 check_widget = static_cast<QWidget*>(obj);
1623
1624 if (check_widget && prop == "geometry"_L1) {
1625 if (check_widget == m_formWindow->mainContainer())
1626 return true; // Save although maincontainer is technically laid-out by embedding container
1627 if (m_selected && m_selected == check_widget)
1628 return true;
1629
1630 return !LayoutInfo::isWidgetLaidout(core(), check_widget);
1631 }
1632
1633 if (check_widget && !checkContainerProperty(check_widget, prop))
1634 return false;
1635
1636 if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), obj)) {
1637 QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core()->extensionManager(), obj);
1638 const int pindex = sheet->indexOf(prop);
1639 if (sheet->isAttribute(pindex))
1640 return false;
1641
1642 if (!dynamicSheet || !dynamicSheet->isDynamicProperty(pindex))
1643 return sheet->isChanged(pindex);
1644 if (!sheet->isVisible(pindex))
1645 return false;
1646 return true;
1647 }
1648
1649 return false;
1650}
1651
1652bool QDesignerResource::addItem(DomLayoutItem *ui_item, QLayoutItem *item, QLayout *layout)
1653{
1654 if (item->widget() == nullptr) {
1655 return false;
1656 }
1657
1658 QGridLayout *grid = qobject_cast<QGridLayout*>(layout);
1659 QBoxLayout *box = qobject_cast<QBoxLayout*>(layout);
1660
1661 if (grid != nullptr) {
1662 const int rowSpan = ui_item->hasAttributeRowSpan() ? ui_item->attributeRowSpan() : 1;
1663 const int colSpan = ui_item->hasAttributeColSpan() ? ui_item->attributeColSpan() : 1;
1664 grid->addWidget(item->widget(), ui_item->attributeRow(), ui_item->attributeColumn(), rowSpan, colSpan, item->alignment());
1665 return true;
1666 }
1667 if (box != nullptr) {
1668 box->addItem(item);
1669 return true;
1670 }
1671
1672 return QAbstractFormBuilder::addItem(ui_item, item, layout);
1673}
1674
1675bool QDesignerResource::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
1676{
1677 core()->metaDataBase()->add(widget); // ensure the widget is in the meta database
1678
1679 if (! QAbstractFormBuilder::addItem(ui_widget, widget, parentWidget) || qobject_cast<QMainWindow*> (parentWidget)) {
1680 if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), parentWidget))
1681 container->addWidget(widget);
1682 }
1683
1684 if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(parentWidget)) {
1685 const int tabIndex = tabWidget->count() - 1;
1686 const int current = tabWidget->currentIndex();
1687
1688 tabWidget->setCurrentIndex(tabIndex);
1689
1690 const auto &attributes = ui_widget->elementAttribute();
1691 QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), parentWidget);
1692 if (auto *picon = QFBE::propertyByName(attributes, QFormBuilderStrings::iconAttribute)) {
1693 QVariant v = resourceBuilder()->loadResource(workingDirectory(), picon);
1694 sheet->setProperty(sheet->indexOf(u"currentTabIcon"_s), v);
1695 }
1696 if (auto *ptext = QFBE::propertyByName(attributes, QFormBuilderStrings::titleAttribute)) {
1697 QVariant v = textBuilder()->loadText(ptext);
1698 sheet->setProperty(sheet->indexOf(u"currentTabText"_s), v);
1699 }
1700 if (auto *ptext = QFBE::propertyByName(attributes, QFormBuilderStrings::toolTipAttribute)) {
1701 QVariant v = textBuilder()->loadText(ptext);
1702 sheet->setProperty(sheet->indexOf(u"currentTabToolTip"_s), v);
1703 }
1704 if (auto *ptext = QFBE::propertyByName(attributes, QFormBuilderStrings::whatsThisAttribute)) {
1705 QVariant v = textBuilder()->loadText(ptext);
1706 sheet->setProperty(sheet->indexOf(u"currentTabWhatsThis"_s), v);
1707 }
1708 tabWidget->setCurrentIndex(current);
1709 } else if (QToolBox *toolBox = qobject_cast<QToolBox*>(parentWidget)) {
1710 const int itemIndex = toolBox->count() - 1;
1711 const int current = toolBox->currentIndex();
1712
1713 toolBox->setCurrentIndex(itemIndex);
1714
1715 const auto &attributes = ui_widget->elementAttribute();
1716 QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), parentWidget);
1717 if (auto *picon = QFBE::propertyByName(attributes, QFormBuilderStrings::iconAttribute)) {
1718 QVariant v = resourceBuilder()->loadResource(workingDirectory(), picon);
1719 sheet->setProperty(sheet->indexOf(u"currentItemIcon"_s), v);
1720 }
1721 if (auto *ptext = QFBE::propertyByName(attributes, QFormBuilderStrings::labelAttribute)) {
1722 QVariant v = textBuilder()->loadText(ptext);
1723 sheet->setProperty(sheet->indexOf(u"currentItemText"_s), v);
1724 }
1725 if (auto *ptext = QFBE::propertyByName(attributes, QFormBuilderStrings::toolTipAttribute)) {
1726 QVariant v = textBuilder()->loadText(ptext);
1727 sheet->setProperty(sheet->indexOf(u"currentItemToolTip"_s), v);
1728 }
1729 toolBox->setCurrentIndex(current);
1730 }
1731
1732 return true;
1733}
1734
1735bool QDesignerResource::copy(QIODevice *dev, const FormBuilderClipboard &selection)
1736{
1737 m_copyWidget = true;
1738
1739 DomUI *ui = copy(selection);
1740
1741 d->m_laidout.clear();
1742 m_copyWidget = false;
1743
1744 if (!ui)
1745 return false;
1746
1747 QXmlStreamWriter writer(dev);
1748 writer.setAutoFormatting(true);
1749 writer.setAutoFormattingIndent(1);
1750 writer.writeStartDocument();
1751 ui->write(writer);
1752 writer.writeEndDocument();
1753 delete ui;
1754 return true;
1755}
1756
1757DomUI *QDesignerResource::copy(const FormBuilderClipboard &selection)
1758{
1759 if (selection.empty())
1760 return nullptr;
1761
1762 m_copyWidget = true;
1763
1764 DomWidget *ui_widget = new DomWidget();
1765 ui_widget->setAttributeName(clipboardObjectName);
1766 bool hasItems = false;
1767 // Widgets
1768 if (!selection.m_widgets.isEmpty()) {
1769 QList<DomWidget *> ui_widget_list;
1770 for (auto *w : selection.m_widgets) {
1771 m_selected = w;
1772 DomWidget *ui_child = createDom(w, ui_widget);
1773 m_selected = nullptr;
1774 if (ui_child)
1775 ui_widget_list.append(ui_child);
1776 }
1777 if (!ui_widget_list.isEmpty()) {
1778 ui_widget->setElementWidget(ui_widget_list);
1779 hasItems = true;
1780 }
1781 }
1782 // actions
1783 if (!selection.m_actions.isEmpty()) {
1784 QList<DomAction *> domActions;
1785 for (QAction* action : std::as_const(selection.m_actions)) {
1786 if (DomAction *domAction = createDom(action))
1787 domActions += domAction;
1788 }
1789 if (!domActions.isEmpty()) {
1790 ui_widget-> setElementAction(domActions);
1791 hasItems = true;
1792 }
1793 }
1794
1795 d->m_laidout.clear();
1796 m_copyWidget = false;
1797
1798 if (!hasItems) {
1799 delete ui_widget;
1800 return nullptr;
1801 }
1802 // UI
1803 DomUI *ui = new DomUI();
1804 ui->setAttributeVersion(currentUiVersion);
1805 ui->setElementWidget(ui_widget);
1806 ui->setElementResources(saveResources(m_resourceBuilder->usedQrcFiles()));
1807 if (DomCustomWidgets *cws = saveCustomWidgets())
1808 ui->setElementCustomWidgets(cws);
1809 return ui;
1810}
1811
1812FormBuilderClipboard QDesignerResource::paste(DomUI *ui, QWidget *widgetParent, QObject *actionParent)
1813{
1814 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
1815 const int saved = m_isMainWidget;
1816 m_isMainWidget = false;
1817
1819
1820 // Widgets
1821 const DomWidget *topLevel = ui->elementWidget();
1822 initialize(ui);
1823 const auto &domWidgets = topLevel->elementWidget();
1824 if (!domWidgets.isEmpty()) {
1825 const QPoint offset = m_formWindow->grid();
1826 for (DomWidget* domWidget : domWidgets) {
1827 if (QWidget *w = create(domWidget, widgetParent)) {
1828 w->move(w->pos() + offset);
1829 // ### change the init properties of w
1830 rc.m_widgets.append(w);
1831 }
1832 }
1833 }
1834 const auto domActions = topLevel->elementAction();
1835 for (DomAction *domAction : domActions) {
1836 if (QAction *a = create(domAction, actionParent))
1837 rc.m_actions .append(a);
1838 }
1839
1840 m_isMainWidget = saved;
1841
1842 if (QDesignerExtraInfoExtension *extra = qt_extension<QDesignerExtraInfoExtension*>(core()->extensionManager(), core()))
1843 extra->loadUiExtraInfo(ui);
1844
1845 createResources(ui->elementResources());
1846
1847 return rc;
1848}
1849
1850FormBuilderClipboard QDesignerResource::paste(QIODevice *dev, QWidget *widgetParent, QObject *actionParent)
1851{
1852 DomUI ui;
1853 QXmlStreamReader reader(dev);
1854 bool uiInitialized = false;
1855
1856 while (!reader.atEnd()) {
1857 if (reader.readNext() == QXmlStreamReader::StartElement) {
1858 if (reader.name().compare("ui"_L1, Qt::CaseInsensitive)) {
1859 ui.read(reader);
1860 uiInitialized = true;
1861 } else {
1862 //: Parsing clipboard contents
1863 reader.raiseError(QCoreApplication::translate("QDesignerResource", "Unexpected element <%1>").arg(reader.name().toString()));
1864 }
1865 }
1866 }
1867 if (reader.hasError()) {
1868 //: Parsing clipboard contents
1869 designerWarning(QCoreApplication::translate("QDesignerResource", "Error while pasting clipboard contents at line %1, column %2: %3")
1870 .arg(reader.lineNumber()).arg(reader.columnNumber())
1871 .arg(reader.errorString()));
1872 uiInitialized = false;
1873 } else if (!uiInitialized) {
1874 //: Parsing clipboard contents
1875 designerWarning(QCoreApplication::translate("QDesignerResource", "Error while pasting clipboard contents: The root element <ui> is missing."));
1876 }
1877
1878 if (!uiInitialized)
1879 return FormBuilderClipboard();
1880
1881 FormBuilderClipboard clipBoard = paste(&ui, widgetParent, actionParent);
1882
1883 return clipBoard;
1884}
1885
1886void QDesignerResource::layoutInfo(DomLayout *layout, QObject *parent, int *margin, int *spacing)
1887{
1888 QAbstractFormBuilder::layoutInfo(layout, parent, margin, spacing);
1889}
1890
1892{
1893 if (m_usedCustomWidgets.isEmpty())
1894 return nullptr;
1895
1896 // We would like the list to be in order of the widget database indexes
1897 // to ensure that base classes come first (nice optics)
1898 QDesignerFormEditorInterface *core = m_formWindow->core();
1899 QDesignerWidgetDataBaseInterface *db = core->widgetDataBase();
1900 const bool isInternalWidgetDataBase = qobject_cast<const WidgetDataBase *>(db);
1901 QMap<int, DomCustomWidget *> orderedMap;
1902
1903 for (auto it = m_usedCustomWidgets.cbegin(), end = m_usedCustomWidgets.cend(); it != end; ++it) {
1904 QDesignerWidgetDataBaseItemInterface *item = it.key();
1905 const QString name = item->name();
1906 DomCustomWidget *custom_widget = new DomCustomWidget;
1907
1908 custom_widget->setElementClass(name);
1909 if (item->isContainer())
1910 custom_widget->setElementContainer(item->isContainer());
1911
1912 if (!item->includeFile().isEmpty()) {
1913 DomHeader *header = new DomHeader;
1914 const IncludeSpecification spec = includeSpecification(item->includeFile());
1915 header->setText(spec.first);
1916 if (spec.second == IncludeGlobal) {
1917 header->setAttributeLocation(u"global"_s);
1918 }
1919 custom_widget->setElementHeader(header);
1920 custom_widget->setElementExtends(item->extends());
1921 }
1922
1923 if (isInternalWidgetDataBase) {
1924 WidgetDataBaseItem *internalItem = static_cast<WidgetDataBaseItem *>(item);
1925 const QStringList fakeSlots = internalItem->fakeSlots();
1926 const QStringList fakeSignals = internalItem->fakeSignals();
1927 if (!fakeSlots.isEmpty() || !fakeSignals.isEmpty()) {
1928 DomSlots *domSlots = new DomSlots();
1929 domSlots->setElementSlot(fakeSlots);
1930 domSlots->setElementSignal(fakeSignals);
1931 custom_widget->setElementSlots(domSlots);
1932 }
1933 const QString addPageMethod = internalItem->addPageMethod();
1934 if (!addPageMethod.isEmpty())
1935 custom_widget->setElementAddPageMethod(addPageMethod);
1936 }
1937
1938 orderedMap.insert(db->indexOfClassName(name), custom_widget);
1939 }
1940
1941 DomCustomWidgets *customWidgets = new DomCustomWidgets;
1942 customWidgets->setElementCustomWidget(orderedMap.values().toVector());
1943 return customWidgets;
1944}
1945
1946bool QDesignerResource::canCompressSpacings(QObject *object) const
1947{
1948 if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), object)) {
1949 if (qobject_cast<QGridLayout *>(object)) {
1950 const int h = sheet->property(sheet->indexOf(u"horizontalSpacing"_s)).toInt();
1951 const int v = sheet->property(sheet->indexOf(u"verticalSpacing"_s)).toInt();
1952 if (h == v)
1953 return true;
1954 }
1955 }
1956 return false;
1957}
1958
1960{
1961 QList<DomProperty*> properties;
1962 if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), object)) {
1963 QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core()->extensionManager(), object);
1964 const int count = sheet->count();
1965 QList<DomProperty *> spacingProperties;
1966 const bool compressSpacings = canCompressSpacings(object);
1967 for (int index = 0; index < count; ++index) {
1968 if (!sheet->isChanged(index) && (!dynamicSheet || !dynamicSheet->isDynamicProperty(index)))
1969 continue;
1970
1971 const QString propertyName = sheet->propertyName(index);
1972 // Suppress windowModality in legacy forms that have it set on child widgets
1973 if (propertyName == "windowModality"_L1 && !sheet->isVisible(index))
1974 continue;
1975
1976 const QVariant value = sheet->property(index);
1977 if (DomProperty *p = createProperty(object, propertyName, value)) {
1978 if (compressSpacings && (propertyName == "horizontalSpacing"_L1
1979 || propertyName == "verticalSpacing"_L1)) {
1980 spacingProperties.append(p);
1981 } else {
1982 properties.append(p);
1983 }
1984 }
1985 }
1986 if (compressSpacings) {
1987 if (spacingProperties.size() == 2) {
1988 DomProperty *spacingProperty = spacingProperties.at(0);
1989 spacingProperty->setAttributeName(u"spacing"_s);
1990 properties.append(spacingProperty);
1991 delete spacingProperties.at(1);
1992 } else {
1993 properties += spacingProperties;
1994 }
1995 }
1996 }
1997 return properties;
1998}
1999
2000DomProperty *QDesignerResource::applyProperStdSetAttribute(QObject *object, const QString &propertyName, DomProperty *property)
2001{
2002 if (!property)
2003 return nullptr;
2004
2005 QExtensionManager *mgr = core()->extensionManager();
2006 if (const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(mgr, object)) {
2007 const QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(mgr, object);
2008 const QDesignerPropertySheet *designerSheet = qobject_cast<QDesignerPropertySheet*>(core()->extensionManager()->extension(object, Q_TYPEID(QDesignerPropertySheetExtension)));
2009 const int index = sheet->indexOf(propertyName);
2010 if ((dynamicSheet && dynamicSheet->isDynamicProperty(index)) || (designerSheet && designerSheet->isDefaultDynamicProperty(index)))
2011 property->setAttributeStdset(0);
2012 }
2013 return property;
2014}
2015
2016// Optimistic check for a standard setter function
2017static inline bool hasSetter(QDesignerFormEditorInterface *core, QObject *object, const QString &propertyName)
2018{
2019 const QDesignerMetaObjectInterface *meta = core->introspection()->metaObject(object);
2020 const int pindex = meta->indexOfProperty(propertyName);
2021 if (pindex == -1)
2022 return true;
2023 return meta->property(pindex)->hasSetter();
2024}
2025
2026DomProperty *QDesignerResource::createProperty(QObject *object, const QString &propertyName, const QVariant &value)
2027{
2028 if (!checkProperty(object, propertyName)) {
2029 return nullptr;
2030 }
2031
2032 if (value.canConvert<PropertySheetFlagValue>()) {
2033 const PropertySheetFlagValue f = qvariant_cast<PropertySheetFlagValue>(value);
2034 const auto mode = d->m_fullyQualifiedEnums
2035 ? DesignerMetaFlags::FullyQualified : DesignerMetaFlags::Qualified;
2036 const QString flagString = f.metaFlags.toString(f.value, mode);
2037 if (flagString.isEmpty())
2038 return nullptr;
2039
2040 DomProperty *p = new DomProperty;
2041 // check if we have a standard cpp set function
2042 if (!hasSetter(core(), object, propertyName))
2043 p->setAttributeStdset(0);
2044 p->setAttributeName(propertyName);
2045 p->setElementSet(flagString);
2046 return applyProperStdSetAttribute(object, propertyName, p);
2047 }
2048 if (value.canConvert<PropertySheetEnumValue>()) {
2049 const PropertySheetEnumValue e = qvariant_cast<PropertySheetEnumValue>(value);
2050 const auto mode = d->m_fullyQualifiedEnums
2051 ? DesignerMetaEnum::FullyQualified : DesignerMetaEnum::Qualified;
2052 bool ok;
2053 const QString id = e.metaEnum.toString(e.value, mode, &ok);
2054 if (!ok)
2055 designerWarning(e.metaEnum.messageToStringFailed(e.value));
2056 if (id.isEmpty())
2057 return nullptr;
2058
2059 DomProperty *p = new DomProperty;
2060 // check if we have a standard cpp set function
2061 if (!hasSetter(core(), object, propertyName))
2062 p->setAttributeStdset(0);
2063 // Map "horizontalSizeConstraint" to "sizeConstraint" for Qt 6
2064 if (!supportsSeparateSizeConstraints(d->m_saveVersion)
2065 && propertyName == "horizontalSizeConstraint"_L1
2066 && object->inherits("QLayout")) {
2067 p->setAttributeName("sizeConstraint"_L1);
2068 } else {
2069 p->setAttributeName(propertyName);
2070 }
2071 p->setElementEnum(id);
2072 return applyProperStdSetAttribute(object, propertyName, p);
2073 }
2074 if (value.canConvert<PropertySheetStringValue>()) {
2075 const PropertySheetStringValue strVal = qvariant_cast<PropertySheetStringValue>(value);
2076 DomProperty *p = stringToDomProperty(strVal.value(), strVal);
2077 if (!hasSetter(core(), object, propertyName))
2078 p->setAttributeStdset(0);
2079
2080 p->setAttributeName(propertyName);
2081
2082 return applyProperStdSetAttribute(object, propertyName, p);
2083 }
2084 if (value.canConvert<PropertySheetStringListValue>()) {
2085 const PropertySheetStringListValue listValue = qvariant_cast<PropertySheetStringListValue>(value);
2086 DomProperty *p = new DomProperty;
2087 if (!hasSetter(core(), object, propertyName))
2088 p->setAttributeStdset(0);
2089
2090 p->setAttributeName(propertyName);
2091
2092 DomStringList *domStringList = new DomStringList();
2093 domStringList->setElementString(listValue.value());
2094 translationParametersToDom(listValue, domStringList);
2095 p->setElementStringList(domStringList);
2096 return applyProperStdSetAttribute(object, propertyName, p);
2097 }
2098 if (value.canConvert<PropertySheetKeySequenceValue>()) {
2099 const PropertySheetKeySequenceValue keyVal = qvariant_cast<PropertySheetKeySequenceValue>(value);
2100 DomProperty *p = stringToDomProperty(keyVal.value().toString(), keyVal);
2101 if (!hasSetter(core(), object, propertyName))
2102 p->setAttributeStdset(0);
2103
2104 p->setAttributeName(propertyName);
2105
2106 return applyProperStdSetAttribute(object, propertyName, p);
2107 }
2108
2109 return applyProperStdSetAttribute(object, propertyName, QAbstractFormBuilder::createProperty(object, propertyName, value));
2110}
2111
2112QStringList QDesignerResource::mergeWithLoadedPaths(const QStringList &paths) const
2113{
2114 QStringList newPaths = paths;
2116 const QStringList loadedPaths = m_resourceBuilder->loadedQrcFiles();
2117 std::remove_copy_if(loadedPaths.cbegin(), loadedPaths.cend(),
2118 std::back_inserter(newPaths),
2119 [&newPaths] (const QString &path) { return newPaths.contains(path); });
2120#endif
2121 return newPaths;
2122}
2123
2124
2125void QDesignerResource::createResources(DomResources *resources)
2126{
2127 QStringList paths;
2128 if (resources != nullptr) {
2129 const auto &dom_include = resources->elementInclude();
2130 for (DomResource *res : dom_include) {
2131 QString path = QDir::cleanPath(m_formWindow->absoluteDir().absoluteFilePath(res->attributeLocation()));
2132 while (!QFile::exists(path)) {
2133 QWidget *dialogParent = m_formWindow->core()->topLevel();
2134 const QString promptTitle = QCoreApplication::translate("qdesigner_internal::QDesignerResource", "Loading qrc file");
2135 const QString prompt = QCoreApplication::translate("qdesigner_internal::QDesignerResource", "The specified qrc file <p><b>%1</b></p><p>could not be found. Do you want to update the file location?</p>").arg(path);
2136
2137 const QMessageBox::StandardButton answer = core()->dialogGui()->message(dialogParent, QDesignerDialogGuiInterface::ResourceLoadFailureMessage,
2138 QMessageBox::Warning, promptTitle, prompt, QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes);
2139 if (answer == QMessageBox::Yes) {
2140 const QFileInfo fi(path);
2141 const QString fileDialogTitle = QCoreApplication::translate("qdesigner_internal::QDesignerResource", "New location for %1").arg(fi.fileName());
2142 const QString fileDialogPattern = QCoreApplication::translate("qdesigner_internal::QDesignerResource", "Resource files (*.qrc)");
2143 path = core()->dialogGui()->getOpenFileName(dialogParent, fileDialogTitle, fi.absolutePath(), fileDialogPattern);
2144 if (path.isEmpty())
2145 break;
2146 m_formWindow->setProperty("_q_resourcepathchanged", QVariant(true));
2147 } else {
2148 break;
2149 }
2150 }
2151 if (!path.isEmpty()) {
2152 paths << path;
2153 m_formWindow->addResourceFile(path);
2154 }
2155 }
2156 }
2157
2159 paths = mergeWithLoadedPaths(paths);
2160#endif
2161
2162 QtResourceSet *resourceSet = m_formWindow->resourceSet();
2163 if (resourceSet) {
2164 QStringList newPaths = resourceSet->activeResourceFilePaths();
2165 std::remove_copy_if(paths.cbegin(), paths.cend(),
2166 std::back_inserter(newPaths),
2167 [&newPaths] (const QString &path) { return newPaths.contains(path); });
2168 resourceSet->activateResourceFilePaths(newPaths);
2169 } else {
2170 resourceSet = m_formWindow->core()->resourceModel()->addResourceSet(paths);
2171 m_formWindow->setResourceSet(resourceSet);
2172 QObject::connect(m_formWindow->core()->resourceModel(), &QtResourceModel::resourceSetActivated,
2173 m_formWindow, &FormWindowBase::resourceSetActivated);
2174 }
2175}
2176
2178{
2179 QStringList paths;
2180 switch (m_formWindow->resourceFileSaveMode()) {
2181 case QDesignerFormWindowInterface::SaveAllResourceFiles:
2182 paths = m_formWindow->activeResourceFilePaths();
2183 break;
2184 case QDesignerFormWindowInterface::SaveOnlyUsedResourceFiles:
2185 paths = m_resourceBuilder->usedQrcFiles();
2186 break;
2187 case QDesignerFormWindowInterface::DontSaveResourceFiles:
2188 break;
2189 }
2190 return saveResources(paths);
2191}
2192
2193DomResources *QDesignerResource::saveResources(const QStringList &qrcPaths)
2194{
2195 QtResourceSet *resourceSet = m_formWindow->resourceSet();
2196 QList<DomResource *> dom_include;
2197 if (resourceSet) {
2198 const QStringList activePaths = resourceSet->activeResourceFilePaths();
2199 for (const QString &path : activePaths) {
2200 if (qrcPaths.contains(path)) {
2201 DomResource *dom_res = new DomResource;
2202 QString conv_path = path;
2203 if (m_resourceBuilder->isSaveRelative())
2204 conv_path = m_formWindow->absoluteDir().relativeFilePath(path);
2205 conv_path.replace(QDir::separator(), u'/');
2206 dom_res->setAttributeLocation(conv_path);
2207 dom_include.append(dom_res);
2208 }
2209 }
2210 }
2211
2212 DomResources *dom_resources = new DomResources;
2213 dom_resources->setElementInclude(dom_include);
2214
2215 return dom_resources;
2216}
2217
2218DomAction *QDesignerResource::createDom(QAction *action)
2219{
2220 if (!core()->metaDataBase()->item(action) || action->menu())
2221 return nullptr;
2222
2224}
2225
2226DomActionGroup *QDesignerResource::createDom(QActionGroup *actionGroup)
2227{
2228 if (core()->metaDataBase()->item(actionGroup) != nullptr) {
2229 return QAbstractFormBuilder::createDom(actionGroup);
2230 }
2231
2232 return nullptr;
2233}
2234
2235QAction *QDesignerResource::create(DomAction *ui_action, QObject *parent)
2236{
2237 if (QAction *action = QAbstractFormBuilder::create(ui_action, parent)) {
2238 core()->metaDataBase()->add(action);
2239 return action;
2240 }
2241
2242 return nullptr;
2243}
2244
2245QActionGroup *QDesignerResource::create(DomActionGroup *ui_action_group, QObject *parent)
2246{
2247 if (QActionGroup *actionGroup = QAbstractFormBuilder::create(ui_action_group, parent)) {
2248 core()->metaDataBase()->add(actionGroup);
2249 return actionGroup;
2250 }
2251
2252 return nullptr;
2253}
2254
2255DomActionRef *QDesignerResource::createActionRefDom(QAction *action)
2256{
2257 if (!core()->metaDataBase()->item(action)
2258 || (!action->isSeparator() && !action->menu() && action->objectName().isEmpty()))
2259 return nullptr;
2260
2262}
2263
2264void QDesignerResource::addMenuAction(QAction *action)
2265{
2266 core()->metaDataBase()->add(action);
2267}
2268
2269QAction *QDesignerResource::createAction(QObject *parent, const QString &name)
2270{
2271 if (QAction *action = QAbstractFormBuilder::createAction(parent, name)) {
2272 core()->metaDataBase()->add(action);
2273 return action;
2274 }
2275
2276 return nullptr;
2277}
2278
2279QActionGroup *QDesignerResource::createActionGroup(QObject *parent, const QString &name)
2280{
2281 if (QActionGroup *actionGroup = QAbstractFormBuilder::createActionGroup(parent, name)) {
2282 core()->metaDataBase()->add(actionGroup);
2283 return actionGroup;
2284 }
2285
2286 return nullptr;
2287}
2288
2289/* Apply the attributes to a widget via property sheet where appropriate,
2290 * that is, the sheet handles attributive fake properties */
2291void QDesignerResource::applyAttributesToPropertySheet(const DomWidget *ui_widget, QWidget *widget)
2292{
2293 const DomPropertyList attributes = ui_widget->elementAttribute();
2294 if (attributes.isEmpty())
2295 return;
2296 QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(m_formWindow->core()->extensionManager(), widget);
2297 for (auto *prop : attributes) {
2298 const QString name = prop->attributeName();
2299 const int index = sheet->indexOf(name);
2300 if (index == -1) {
2301 const QString msg = "Unable to apply attributive property '%1' to '%2'. It does not exist."_L1.arg(name, widget->objectName());
2302 designerWarning(msg);
2303 } else {
2304 sheet->setProperty(index, domPropertyToVariant(this, widget->metaObject(), prop));
2305 sheet->setChanged(index, true);
2306 }
2307 }
2308}
2309
2310void QDesignerResource::loadExtraInfo(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
2311{
2312 QAbstractFormBuilder::loadExtraInfo(ui_widget, widget, parentWidget);
2313 // Apply the page id attribute of a QWizardPage (which is an attributive fake property)
2314 if (qobject_cast<const QWizardPage*>(widget))
2315 applyAttributesToPropertySheet(ui_widget, widget);
2316}
2317
2318}
2319
2320QT_END_NAMESPACE
virtual bool isDynamicProperty(int index) const =0
virtual bool isLanguageResource(const QString &path) const =0
friend class QWidget
Definition qpainter.h:432
QDesignerFormEditorInterface * core() const override
Returns a pointer to \QD's current QDesignerFormEditorInterface object.
void setLayoutDefault(int margin, int spacing) override
Sets the default margin and spacing for the form's layout.
void layoutDefault(int *margin, int *spacing) override
Fills in the default margin and spacing for the form's default layout in the margin and spacing varia...
QWidget * mainContainer() const override
Returns the main container widget for the form window.
void manageWidget(QWidget *w) override
Instructs the form window to manage the specified widget.
int toolCount() const override
Returns the number of tools available.
QVariant toNativeValue(const QVariant &value) const override
bool isResourceType(const QVariant &value) const override
QVariant loadResource(const QDir &workingDirectory, const DomProperty *icon) const override
QDesignerResourceBuilder(QDesignerFormEditorInterface *core, DesignerPixmapCache *pixmapCache, DesignerIconCache *iconCache)
DomProperty * saveResource(const QDir &workingDirectory, const QVariant &value) const override
void setIconCache(DesignerIconCache *iconCache)
void setPixmapCache(DesignerPixmapCache *pixmapCache)
DomActionGroup * createDom(QActionGroup *actionGroup) override
QWidget * load(QIODevice *dev, QWidget *parentWidget) override
Loads an XML representation of a widget from the given device, and constructs a new widget with the s...
bool addItem(DomLayoutItem *ui_item, QLayoutItem *item, QLayout *layout) override
DomLayoutItem * createDom(QLayoutItem *item, DomLayout *ui_layout, DomWidget *ui_parentWidget) override
DomLayout * createDom(QLayout *layout, DomLayout *ui_layout, DomWidget *ui_parentWidget) override
void applyProperties(QObject *o, const QList< DomProperty * > &properties) override
void createCustomWidgets(DomCustomWidgets *) override
QLayout * create(DomLayout *ui_layout, QLayout *layout, QWidget *parentWidget) override
void applyTabStops(QWidget *widget, DomTabStops *tabStops) override
DomWidget * saveWidget(QToolBar *toolBar, DomWidget *ui_parentWidget)
DomCustomWidgets * saveCustomWidgets() override
DomWidget * saveWidget(QDesignerDockWidget *dockWidget, DomWidget *ui_parentWidget)
DomUI * copy(const FormBuilderClipboard &selection) override
QAction * create(DomAction *ui_action, QObject *parent) override
QActionGroup * create(DomActionGroup *ui_action_group, QObject *parent) override
DomWidget * saveWidget(QWizardPage *wizardPage, DomWidget *ui_parentWidget)
void saveDom(DomUI *ui, QWidget *widget) override
void createResources(DomResources *) override
void save(QIODevice *dev, QWidget *widget) override
Saves an XML representation of the given widget to the specified device in the standard UI file forma...
QLayoutItem * create(DomLayoutItem *ui_layoutItem, QLayout *layout, QWidget *parentWidget) override
QWidget * create(DomUI *ui, QWidget *parentWidget) override
QWidget * loadUi(DomUI *ui, QWidget *parentWidget)
void loadExtraInfo(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) override
DomWidget * createDom(QWidget *widget, DomWidget *ui_parentWidget, bool recursive=true) override
DomWidget * saveWidget(QTabWidget *widget, DomWidget *ui_parentWidget)
DomWidget * saveWidget(QToolBox *widget, DomWidget *ui_parentWidget)
FormBuilderClipboard paste(DomUI *ui, QWidget *widgetParent, QObject *actionParent=nullptr) override
DomWidget * saveWidget(QWidget *widget, QDesignerContainerExtension *container, DomWidget *ui_parentWidget)
bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) override
void layoutInfo(DomLayout *layout, QObject *parent, int *margin, int *spacing) override
FormBuilderClipboard paste(QIODevice *dev, QWidget *widgetParent, QObject *actionParent=nullptr) override
QList< DomProperty * > computeProperties(QObject *obj) override
DomWidget * saveWidget(QStackedWidget *widget, DomWidget *ui_parentWidget)
QWidget * create(DomWidget *ui_widget, QWidget *parentWidget) override
bool copy(QIODevice *dev, const FormBuilderClipboard &selection) override
QVariant toNativeValue(const QVariant &value) const override
DomProperty * saveText(const QVariant &value) const override
QVariant loadText(const DomProperty *icon) const override
static bool checkProperty(const QString &propertyName)
Auxiliary methods to store/retrieve settings.
static QString messageBoxTitle()
static void setIconPixmap(QIcon::Mode m, QIcon::State s, const QDir &workingDirectory, QString path, PropertySheetIconValue &icon, const QDesignerLanguageExtension *lang=nullptr)
static DomProperty * stringToDomProperty(const QString &value, const PropertySheetTranslatableData &translatableData)
QString msgUnmanagedPage(QDesignerFormEditorInterface *core, QWidget *container, int index, QWidget *page)
static DomProperty * stringToDomProperty(const QString &value)
void translationParametersToDom(const PropertySheetTranslatableData &data, DomElement *e)
static bool supportsQualifiedEnums(const QVersionNumber &qtVersion)
static bool hasSetter(QDesignerFormEditorInterface *core, QObject *object, const QString &propertyName)
static bool isDeprecatedQt5Property(const QObject *o, const DomProperty *p)
static bool readDomEnumerationValue(const DomProperty *p, const QDesignerPropertySheetExtension *sheet, int index, QVariant &v)
static bool checkContainerProperty(const QWidget *w, const QString &propertyName)
void translationParametersFromDom(const DomElement *e, PropertySheetTranslatableData *data)
static bool supportsSeparateSizeConstraints(const QVersionNumber &qtVersion)
#define OLD_RESOURCE_FORMAT
static constexpr auto clipboardObjectName
QFormBuilderExtra QFBE
static constexpr auto currentUiVersion