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