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

source code of qttools/src/designer/src/components/formeditor/qdesigner_resource.cpp