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