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 
106 Q_DECLARE_METATYPE(QWidgetList)
107 
108 QT_BEGIN_NAMESPACE
109 
110 namespace {
111     using DomPropertyList = QList<DomProperty *>;
112 }
113 
114 static const char *currentUiVersion = "4.0";
115 static const char *clipboardObjectName = "__qt_fake_top_level";
116 
117 #define OLD_RESOURCE_FORMAT // Support pre 4.4 format.
118 
119 namespace qdesigner_internal {
120 
121 // -------------------- QDesignerResourceBuilder: A resource builder that works on the property sheet icon types.
122 class QDesignerResourceBuilder : public QResourceBuilder
123 {
124 public:
125     QDesignerResourceBuilder(QDesignerFormEditorInterface *core, DesignerPixmapCache *pixmapCache, DesignerIconCache *iconCache);
126 
setPixmapCache(DesignerPixmapCache * pixmapCache)127     void setPixmapCache(DesignerPixmapCache *pixmapCache) { m_pixmapCache = pixmapCache; }
setIconCache(DesignerIconCache * iconCache)128     void setIconCache(DesignerIconCache *iconCache)       { m_iconCache = iconCache; }
isSaveRelative() const129     bool isSaveRelative() const                           { return m_saveRelative; }
setSaveRelative(bool relative)130     void setSaveRelative(bool relative)                   { m_saveRelative = relative; }
usedQrcFiles() const131     QStringList usedQrcFiles() const                      { return m_usedQrcFiles.keys(); }
132 #ifdef OLD_RESOURCE_FORMAT
loadedQrcFiles() const133     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;
143 private:
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 
QDesignerResourceBuilder(QDesignerFormEditorInterface * core,DesignerPixmapCache * pixmapCache,DesignerIconCache * iconCache)154 QDesignerResourceBuilder::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 *>(core->extensionManager(), core)),
159     m_saveRelative(true)
160 {
161 }
162 
setIconPixmap(QIcon::Mode m,QIcon::State s,const QDir & workingDirectory,QString path,PropertySheetIconValue & icon,const QDesignerLanguageExtension * lang=nullptr)163 static 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(m, s, PropertySheetPixmapValue(path));
170 }
171 
loadResource(const QDir & workingDirectory,const DomProperty * property) const172 QVariant 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(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(QFileInfo(workingDirectory, dp->attributeResource()).absoluteFilePath(), false);
187 #endif
188             }
189             return QVariant::fromValue(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(di)) { // new, post 4.4 format
197                 if (flags & NormalOff)
198                     setIconPixmap(QIcon::Normal, QIcon::Off, workingDirectory, di->elementNormalOff()->text(), icon, m_lang);
199                 if (flags & NormalOn)
200                     setIconPixmap(QIcon::Normal, QIcon::On, workingDirectory, di->elementNormalOn()->text(), icon, m_lang);
201                 if (flags & DisabledOff)
202                     setIconPixmap(QIcon::Disabled, QIcon::Off, workingDirectory, di->elementDisabledOff()->text(), icon, m_lang);
203                 if (flags & DisabledOn)
204                     setIconPixmap(QIcon::Disabled, QIcon::On, workingDirectory, di->elementDisabledOn()->text(), icon, m_lang);
205                 if (flags & ActiveOff)
206                     setIconPixmap(QIcon::Active, QIcon::Off, workingDirectory, di->elementActiveOff()->text(), icon, m_lang);
207                 if (flags & ActiveOn)
208                     setIconPixmap(QIcon::Active, QIcon::On, workingDirectory, di->elementActiveOn()->text(), icon, m_lang);
209                 if (flags & SelectedOff)
210                     setIconPixmap(QIcon::Selected, QIcon::Off, workingDirectory, di->elementSelectedOff()->text(), icon, m_lang);
211                 if (flags & SelectedOn)
212                     setIconPixmap(QIcon::Selected, QIcon::On, workingDirectory, di->elementSelectedOn()->text(), icon, m_lang);
213             } else {
214 #ifdef OLD_RESOURCE_FORMAT
215                 setIconPixmap(QIcon::Normal, QIcon::Off, workingDirectory, di->text(), icon, m_lang);
216                 if (di->hasAttributeResource())
217                     m_loadedQrcFiles.insert(QFileInfo(workingDirectory, di->attributeResource()).absoluteFilePath(), false);
218 #endif
219             }
220             return QVariant::fromValue(icon);
221         }
222         default:
223             break;
224     }
225     return QVariant();
226 }
227 
toNativeValue(const QVariant & value) const228 QVariant QDesignerResourceBuilder::toNativeValue(const QVariant &value) const
229 {
230     if (value.canConvert<PropertySheetPixmapValue>()) {
231         if (m_pixmapCache)
232             return m_pixmapCache->pixmap(qvariant_cast<PropertySheetPixmapValue>(value));
233     } else if (value.canConvert<PropertySheetIconValue>()) {
234         if (m_iconCache)
235             return m_iconCache->icon(qvariant_cast<PropertySheetIconValue>(value));
236     }
237     return value;
238 }
239 
saveResource(const QDir & workingDirectory,const QVariant & value) const240 DomProperty *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>(value);
245         DomResourcePixmap *rp = new DomResourcePixmap;
246         const QString pixPath = pix.path();
247         switch (pix.pixmapSource(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(pixPath);
254             if (!qrcFile.isEmpty()) {
255                 m_usedQrcFiles.insert(qrcFile, false);
256 #ifdef OLD_RESOURCE_FORMAT  // Legacy: Add qrc path
257                 rp->setAttributeResource(workingDirectory.relativeFilePath(qrcFile));
258 #endif
259             }
260         }
261             break;
262         case PropertySheetPixmapValue::FilePixmap:
263             rp->setText(m_saveRelative ? workingDirectory.relativeFilePath(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>(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(m_core);
283                 const QString pixPath = pix.path();
284                 rp->setText(ps == PropertySheetPixmapValue::FilePixmap && m_saveRelative ? workingDirectory.relativeFilePath(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(ri->text());
296                                 if (!qrcFile.isEmpty()) {
297                                     m_usedQrcFiles.insert(qrcFile, false);
298 #ifdef OLD_RESOURCE_FORMAT  // Legacy: Set Normal off as text/path in old format.
299                                     ri->setAttributeResource(workingDirectory.relativeFilePath(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 
isResourceType(const QVariant & value) const325 bool QDesignerResourceBuilder::isResourceType(const QVariant &value) const
326 {
327     return value.canConvert<PropertySheetPixmapValue>()
328         || value.canConvert<PropertySheetIconValue>();
329 }
330 // ------------------------- QDesignerTextBuilder
331 
332 template <class DomElement> // for DomString, potentially DomStringList
translationParametersToDom(const PropertySheetTranslatableData & data,DomElement * e)333 inline 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 
348 template <class DomElement> // for DomString, potentially DomStringList
translationParametersFromDom(const DomElement * e,PropertySheetTranslatableData * data)349 inline 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 
364 class QDesignerTextBuilder : public QTextBuilder
365 {
366 public:
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 
loadText(const DomProperty * text) const376 QVariant QDesignerTextBuilder::loadText(const DomProperty *text) const
377 {
378     if (const DomString *domString = text->elementString()) {
379         PropertySheetStringValue stringValue(domString->text());
380         translationParametersFromDom(domString, &stringValue);
381         return QVariant::fromValue(stringValue);
382     }
383     return QVariant(QString());
384 }
385 
toNativeValue(const QVariant & value) const386 QVariant QDesignerTextBuilder::toNativeValue(const QVariant &value) const
387 {
388     if (value.canConvert<PropertySheetStringValue>())
389         return QVariant::fromValue(qvariant_cast<PropertySheetStringValue>(value).value());
390     return value;
391 }
392 
stringToDomProperty(const QString & value)393 static 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 
stringToDomProperty(const QString & value,const PropertySheetTranslatableData & translatableData)402 static inline DomProperty *stringToDomProperty(const QString &value,
403                                                const PropertySheetTranslatableData &translatableData)
404 {
405     DomString *domString = new DomString();
406     domString->setText(value);
407     translationParametersToDom(translatableData, domString);
408     DomProperty *property = new DomProperty();
409     property->setElementString(domString);
410     return property;
411 }
412 
saveText(const QVariant & value) const413 DomProperty *QDesignerTextBuilder::saveText(const QVariant &value) const
414 {
415     if (value.canConvert<PropertySheetStringValue>()) {
416         const PropertySheetStringValue str = qvariant_cast<PropertySheetStringValue>(value);
417         return stringToDomProperty(str.value(), str);
418     }
419     if (value.canConvert<QString>())
420         return stringToDomProperty(value.toString());
421     return nullptr;
422 }
423 
QDesignerResource(FormWindow * formWindow)424 QDesignerResource::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*>(core->extensionManager(), 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(layoutWidget, widget);
445     m_internal_to_qt.insert(designerWidget, 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(it.value(), it.key());
456 
457     }
458 }
459 
460 QDesignerResource::~QDesignerResource() = default;
461 
readUi(QIODevice * dev)462 DomUI *QDesignerResource::readUi(QIODevice *dev)
463 {
464     return d->readUi(dev);
465 }
466 
messageBoxTitle()467 static inline QString messageBoxTitle()
468 {
469     return QApplication::translate("Designer", "Qt Designer");
470 }
471 
save(QIODevice * dev,QWidget * widget)472 void QDesignerResource::save(QIODevice *dev, QWidget *widget)
473 {
474     QAbstractFormBuilder::save(dev, widget);
475 }
476 
saveDom(DomUI * ui,QWidget * widget)477 void QDesignerResource::saveDom(DomUI *ui, QWidget *widget)
478 {
479     QAbstractFormBuilder::saveDom(ui, widget);
480 
481     QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), widget);
482     Q_ASSERT(sheet != nullptr);
483 
484     const QVariant classVar = sheet->property(sheet->indexOf(QStringLiteral("objectName")));
485     QString classStr;
486     if (classVar.canConvert(QVariant::String))
487         classStr = classVar.toString();
488     else
489         classStr = qvariant_cast<PropertySheetStringValue>(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(this, widget->metaObject(), it.key(), 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(includeHints.size());
539         for (QString includeHint : includeHints) {
540             if (includeHint.isEmpty())
541                 continue;
542             DomInclude *incl = new DomInclude;
543             const QString location = includeHint.at(0) == QLatin1Char('<') ? global : local;
544             includeHint.remove(QLatin1Char('"'));
545             includeHint.remove(QLatin1Char('<'));
546             includeHint.remove(QLatin1Char('>'));
547             incl->setAttributeLocation(location);
548             incl->setText(includeHint);
549             ui_includes.append(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(&defaultMargin, &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(&marginFunction, &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*>(core()->extensionManager(), core()))
587         extra->saveUiExtraInfo(ui);
588 
589     if (MetaDataBase *metaDataBase = qobject_cast<MetaDataBase *>(core()->metaDataBase())) {
590         const MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(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 
load(QIODevice * dev,QWidget * parentWidget)602 QWidget *QDesignerResource::load(QIODevice *dev, QWidget *parentWidget)
603 {
604     QScopedPointer<DomUI> ui(readUi(dev));
605     return ui.isNull() ? nullptr : loadUi(ui.data(), parentWidget);
606 }
607 
loadUi(DomUI * ui,QWidget * parentWidget)608 QWidget *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("_q_classname", widget->objectName());
614     else if (d->m_errorString.isEmpty())
615         d->m_errorString = QFormBuilderExtra::msgInvalidUiFile();
616     return widget;
617 }
618 
saveRelative() const619 bool QDesignerResource::saveRelative() const
620 {
621     return m_resourceBuilder->isSaveRelative();
622 }
623 
setSaveRelative(bool relative)624 void QDesignerResource::setSaveRelative(bool relative)
625 {
626     m_resourceBuilder->setSaveRelative(relative);
627 }
628 
create(DomUI * ui,QWidget * parentWidget)629 QWidget *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*>(core()->extensionManager(), core())) {
634         if (!extra->loadUiExtraInfo(ui)) {
635             const QString errorMessage = QApplication::translate("Designer", "This file cannot be read because the extra info extension failed to load.");
636             core()->dialogGui()->message(parentWidget->window(), QDesignerDialogGuiInterface::FormLoadFailureMessage,
637                                          QMessageBox::Warning, messageBoxTitle(), errorMessage, QMessageBox::Ok);
638             return nullptr;
639         }
640     }
641 
642     qdesigner_internal::WidgetFactory *factory = qobject_cast<qdesigner_internal::WidgetFactory*>(core()->widgetFactory());
643     Q_ASSERT(factory != nullptr);
644 
645     QDesignerFormWindowInterface *previousFormWindow = factory->currentFormWindow(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(this, mainWidget->metaObject(), *it);
670                 if (vprop.type() != QVariant::Invalid)
671                     designerFormData.insert((*it)->attributeName(), 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(def->attributeMargin(), def->attributeSpacing());
680         }
681 
682         if (DomLayoutFunction *fun = ui->elementLayoutFunction()) {
683             m_formWindow->setLayoutFunction(fun->attributeMargin(), 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(QLatin1Char('<')).append(QLatin1Char('>'));
698                 } else {
699                     text = text.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
700                 }
701 
702                 includeHints.append(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*>(*it))
716                     mdb->add(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(previousFormWindow);
727 
728     if (const DomSlots *domSlots = ui->elementSlots()) {
729         if (MetaDataBase *metaDataBase = qobject_cast<MetaDataBase *>(core()->metaDataBase())) {
730             QStringList fakeSlots;
731             QStringList fakeSignals;
732             if (addFakeMethods(domSlots, fakeSlots, fakeSignals)) {
733                 MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(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(qSmartMinSize(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(mainWidget);
771         if (wdbIndex != -1) {
772             QDesignerWidgetDataBaseItemInterface *item = wdb->item(wdbIndex);
773             // Promoted main container that is not of container type
774             if (item->isPromoted() && !item->isContainer()) {
775                 item->setContainer(true);
776                 qWarning("** 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 
create(DomWidget * ui_widget,QWidget * parentWidget)785 QWidget *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*>(core()->extensionManager(), 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*>(w);
815     QDesignerMenuBar *menuBar = qobject_cast<QDesignerMenuBar*>(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(sep);
826             addMenuAction(sep);
827         } else if (QAction *a = d->m_actions.value(name)) {
828             w->addAction(a);
829         } else if (QActionGroup *g = d->m_actionGroups.value(name)) {
830             w->addActions(g->actions());
831         } else if (QMenu *menu = w->findChild<QMenu*>(name)) {
832             w->addAction(menu->menuAction());
833             addMenuAction(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(this, core(), ui_widget, w);
844 
845     return w;
846 }
847 
create(DomLayout * ui_layout,QLayout * layout,QWidget * parentWidget)848 QLayout *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*>(l)) {
853         QLayoutSupport::createEmptyCells(gridLayout);
854     } else {
855         if (QFormLayout *formLayout = qobject_cast<QFormLayout*>(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(), l, ui_layout);
861     return l;
862 }
863 
create(DomLayoutItem * ui_layoutItem,QLayout * layout,QWidget * parentWidget)864 QLayoutItem *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(spacer, domSpacer->attributeName());
871         core()->metaDataBase()->add(spacer);
872 
873         spacer->setInteractiveMode(false);
874         applyProperties(spacer, ui_layoutItem->elementSpacer()->elementProperty());
875         spacer->setInteractiveMode(true);
876 
877         if (m_formWindow) {
878             m_formWindow->manageWidget(spacer);
879             if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), spacer))
880                 sheet->setChanged(sheet->indexOf(QStringLiteral("orientation")), 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(layoutWidget);
889         if (m_formWindow)
890             m_formWindow->manageWidget(layoutWidget);
891         (void) create(ui_layout, nullptr, layoutWidget);
892         return new QWidgetItem(layoutWidget);
893     }
894     return QAbstractFormBuilder::create(ui_layoutItem, layout, parentWidget);
895 }
896 
changeObjectName(QObject * o,QString objName)897 void QDesignerResource::changeObjectName(QObject *o, QString objName)
898 {
899     m_formWindow->unify(o, objName, 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 
readDomEnumerationValue(const DomProperty * p,const QDesignerPropertySheetExtension * sheet,int index,QVariant & v)907 static 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>(sheetValue);
916             bool ok = false;
917             v = f.metaFlags.parseFlags(p->elementSet(), &ok);
918             if (!ok)
919                 designerWarning(f.metaFlags.messageParseFailed(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>(sheetValue);
928             bool ok = false;
929             v = e.metaEnum.parseEnum(p->elementEnum(), &ok);
930             if (!ok)
931                 designerWarning(e.metaEnum.messageParseFailed(p->elementEnum()));
932             return true;
933         }
934     }
935         break;
936     default:
937         break;
938     }
939     return false;
940 }
941 
applyProperties(QObject * o,const QList<DomProperty * > & properties)942 void QDesignerResource::applyProperties(QObject *o, const QList<DomProperty*> &properties)
943 {
944     if (properties.isEmpty())
945         return;
946 
947     QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), o);
948     if (!sheet)
949         return;
950 
951     QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core()->extensionManager(), 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("QLCDNumber")) // Deprecated in Qt 4, removed in Qt 5.
958             propertyName = QLatin1String("digitCount");
959         const int index = sheet->indexOf(propertyName);
960         QVariant v;
961         if (!readDomEnumerationValue(p, sheet, index, v))
962             v = toVariant(o->metaObject(), 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(key, &keyVal);
970                 v = QVariant::fromValue(keyVal);
971             } else {
972                 const DomString *str = p->elementString();
973                 PropertySheetStringValue strVal(v.toString());
974                 translationParametersFromDom(str, &strVal);
975                 v = QVariant::fromValue(strVal);
976             }
977             break;
978         case DomProperty::StringList: {
979             const DomStringList *list = p->elementStringList();
980             PropertySheetStringListValue listValue(list->elementString());
981             translationParametersFromDom(list, &listValue);
982             v = QVariant::fromValue(listValue);
983         }
984             break;
985         default:
986             break;
987         }
988 
989         d->applyPropertyInternally(o, propertyName, v);
990         if (index != -1) {
991             sheet->setProperty(index, v);
992             sheet->setChanged(index, 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(p->attributeName(), defaultValue);
1014                 if (idx != -1) {
1015                     sheet->setProperty(idx, v);
1016                     sheet->setChanged(idx, !isDefault);
1017                 }
1018             }
1019         }
1020 
1021         if (propertyName == objectNameProperty)
1022             changeObjectName(o, o->objectName());
1023     }
1024 }
1025 
createWidget(const QString & widgetName,QWidget * parentWidget,const QString & _name)1026 QWidget *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(widgetName, parentWidget);
1033     if (!w)
1034         return nullptr;
1035 
1036     if (name.isEmpty()) {
1037         QDesignerWidgetDataBaseInterface *db = core()->widgetDataBase();
1038         if (QDesignerWidgetDataBaseItemInterface *item = db->item(db->indexOfObject(w)))
1039             name = qtify(item->name());
1040     }
1041 
1042     changeObjectName(w, name);
1043 
1044     QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), parentWidget);
1045     if (!qobject_cast<QMenu*>(w) && (!parentWidget || !container)) {
1046         m_formWindow->manageWidget(w);
1047         if (parentWidget) {
1048             QWidgetList list = qvariant_cast<QWidgetList>(parentWidget->property("_q_widgetOrder"));
1049             list.append(w);
1050             parentWidget->setProperty("_q_widgetOrder", QVariant::fromValue(list));
1051             QWidgetList zOrder = qvariant_cast<QWidgetList>(parentWidget->property("_q_zOrder"));
1052             zOrder.append(w);
1053             parentWidget->setProperty("_q_zOrder", QVariant::fromValue(zOrder));
1054         }
1055     } else {
1056         core()->metaDataBase()->add(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 
createLayout(const QString & layoutName,QObject * parent,const QString & name)1066 QLayout *QDesignerResource::createLayout(const QString &layoutName, QObject *parent, const QString &name)
1067 {
1068     QWidget *layoutBase = nullptr;
1069     QLayout *layout = qobject_cast<QLayout*>(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(layoutName);
1079     if (layoutType == LayoutInfo::NoLayout) {
1080         designerWarning(QCoreApplication::translate("QDesignerResource", "The layout type '%1' is not supported, defaulting to grid.").arg(layoutName));
1081         layoutType = LayoutInfo::Grid;
1082     }
1083     QLayout *lay = core()->widgetFactory()->createLayout(layoutBase, layout, layoutType);
1084     if (lay != nullptr)
1085         changeObjectName(lay, name);
1086 
1087     return lay;
1088 }
1089 
1090 // save
createDom(QWidget * widget,DomWidget * ui_parentWidget,bool recursive)1091 DomWidget *QDesignerResource::createDom(QWidget *widget, DomWidget *ui_parentWidget, bool recursive)
1092 {
1093     QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(widget);
1094     if (!item)
1095         return nullptr;
1096 
1097     if (qobject_cast<Spacer*>(widget) && !m_copyWidget)
1098         return nullptr;
1099 
1100     const QDesignerWidgetDataBaseInterface *wdb = core()->widgetDataBase();
1101     QDesignerWidgetDataBaseItemInterface *widgetInfo =  nullptr;
1102     const int widgetInfoIndex = wdb->indexOfObject(widget, false);
1103     if (widgetInfoIndex != -1) {
1104         widgetInfo = wdb->item(widgetInfoIndex);
1105         // Recursively add all dependent custom widgets
1106         QDesignerWidgetDataBaseItemInterface *customInfo = widgetInfo;
1107         while (customInfo && customInfo->isCustom()) {
1108             m_usedCustomWidgets.insert(customInfo, 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(customInfo->extends());
1113             customInfo = extendsIndex != -1 ?  wdb->item(extendsIndex) : nullptr;
1114         }
1115     }
1116 
1117     DomWidget *w = nullptr;
1118 
1119     if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(widget))
1120         w = saveWidget(tabWidget, ui_parentWidget);
1121     else if (QStackedWidget *stackedWidget = qobject_cast<QStackedWidget*>(widget))
1122         w = saveWidget(stackedWidget, ui_parentWidget);
1123     else if (QToolBox *toolBox = qobject_cast<QToolBox*>(widget))
1124         w = saveWidget(toolBox, ui_parentWidget);
1125     else if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget))
1126         w = saveWidget(toolBar, ui_parentWidget);
1127     else if (QDesignerDockWidget *dockWidget = qobject_cast<QDesignerDockWidget*>(widget))
1128         w = saveWidget(dockWidget, ui_parentWidget);
1129     else if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget))
1130         w = saveWidget(widget, container, ui_parentWidget);
1131     else if (QWizardPage *wizardPage = qobject_cast<QWizardPage*>(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*>(widget) && w->attributeClass() == QStringLiteral("QWidget")) {
1139         w->setAttributeNative(true);
1140     }
1141 
1142     const QString className = w->attributeClass();
1143     if (m_internal_to_qt.contains(className))
1144         w->setAttributeClass(m_internal_to_qt.value(className));
1145 
1146     w->setAttributeName(widget->objectName());
1147 
1148     if (isPromoted( core(), 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(widgetInfo)) {
1165         if (widgetInfo->name() != w->attributeClass())
1166             w->setAttributeClass(widgetInfo->name());
1167     }
1168     addExtensionDataToDOM(this, core(), w, widget);
1169     return w;
1170 }
1171 
createDom(QLayout * layout,DomLayout * ui_parentLayout,DomWidget * ui_parentWidget)1172 DomLayout *QDesignerResource::createDom(QLayout *layout, DomLayout *ui_parentLayout, DomWidget *ui_parentWidget)
1173 {
1174     QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(layout);
1175 
1176     if (item == nullptr) {
1177         layout = layout->findChild<QLayout*>();
1178         // refresh the meta database item
1179         item = core()->metaDataBase()->item(layout);
1180     }
1181 
1182     if (item == nullptr) {
1183         // nothing to do.
1184         return nullptr;
1185     }
1186 
1187     if (qobject_cast<QSplitter*>(layout->parentWidget()) != 0) {
1188         // nothing to do.
1189         return nullptr;
1190     }
1191 
1192     m_chain.push(layout);
1193 
1194     DomLayout *l = QAbstractFormBuilder::createDom(layout, ui_parentLayout, ui_parentWidget);
1195     Q_ASSERT(l != nullptr);
1196     LayoutPropertySheet::stretchAttributesToDom(core(), layout, l);
1197 
1198     m_chain.pop();
1199 
1200     return l;
1201 }
1202 
createDom(QLayoutItem * item,DomLayout * ui_layout,DomWidget * ui_parentWidget)1203 DomLayoutItem *QDesignerResource::createDom(QLayoutItem *item, DomLayout *ui_layout, DomWidget *ui_parentWidget)
1204 {
1205     DomLayoutItem *ui_item = nullptr;
1206 
1207     if (Spacer *s = qobject_cast<Spacer*>(item->widget())) {
1208         if (!core()->metaDataBase()->item(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(item->widget()));
1217 
1218         ui_item = new DomLayoutItem();
1219         ui_item->setElementSpacer(spacer);
1220         d->m_laidout.insert(item->widget(), true);
1221     } else if (QLayoutWidget *layoutWidget = qobject_cast<QLayoutWidget*>(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(layoutWidget->layout(), ui_layout, ui_parentWidget);
1225         ui_item = new DomLayoutItem();
1226         ui_item->setElementLayout(l);
1227         d->m_laidout.insert(item->widget(), true);
1228     } else if (!item->spacerItem()) { // we use spacer as fake item in the Designer
1229         ui_item = QAbstractFormBuilder::createDom(item, ui_layout, ui_parentWidget);
1230     } else {
1231         return nullptr;
1232     }
1233     return ui_item;
1234 }
1235 
createCustomWidgets(DomCustomWidgets * dom_custom_widgets)1236 void QDesignerResource::createCustomWidgets(DomCustomWidgets *dom_custom_widgets)
1237 {
1238     QSimpleResource::handleDomCustomWidgets(core(), dom_custom_widgets);
1239 }
1240 
saveTabStops()1241 DomTabStops *QDesignerResource::saveTabStops()
1242 {
1243     QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(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(widget))
1250             tabStops.append(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 
applyTabStops(QWidget * widget,DomTabStops * tabStops)1262 void 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*>(widgetName)) {
1271             tabOrder.append(w);
1272         }
1273     }
1274 
1275     QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(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. */
msgUnmanagedPage(QDesignerFormEditorInterface * core,QWidget * container,int index,QWidget * page)1283 inline QString msgUnmanagedPage(QDesignerFormEditorInterface *core,
1284                                 QWidget *container, int index, QWidget *page)
1285 {
1286     return QCoreApplication::translate("QDesignerResource",
1287 "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(container->objectName(), WidgetFactory::classNameOf(core, container),
1290                page->objectName(), WidgetFactory::classNameOf(core, page)).
1291            arg(index);
1292 }
1293 
saveWidget(QWidget * widget,QDesignerContainerExtension * container,DomWidget * ui_parentWidget)1294 DomWidget *QDesignerResource::saveWidget(QWidget *widget, QDesignerContainerExtension *container, DomWidget *ui_parentWidget)
1295 {
1296     DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false);
1297     QVector<DomWidget *> ui_widget_list;
1298 
1299     for (int i=0; i<container->count(); ++i) {
1300         QWidget *page = container->widget(i);
1301         Q_ASSERT(page);
1302 
1303         if (DomWidget *ui_page = createDom(page, ui_widget)) {
1304             ui_widget_list.append(ui_page);
1305         } else {
1306             designerWarning(msgUnmanagedPage(core(), widget, i, page));
1307         }
1308     }
1309 
1310     ui_widget->setElementWidget(ui_widget_list);
1311 
1312     return ui_widget;
1313 }
1314 
saveWidget(QStackedWidget * widget,DomWidget * ui_parentWidget)1315 DomWidget *QDesignerResource::saveWidget(QStackedWidget *widget, DomWidget *ui_parentWidget)
1316 {
1317     DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false);
1318     QVector<DomWidget *> ui_widget_list;
1319     if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) {
1320         for (int i=0; i<container->count(); ++i) {
1321             QWidget *page = container->widget(i);
1322             Q_ASSERT(page);
1323             if (DomWidget *ui_page = createDom(page, ui_widget)) {
1324                 ui_widget_list.append(ui_page);
1325             } else {
1326                 designerWarning(msgUnmanagedPage(core(), widget, i, page));
1327             }
1328         }
1329     }
1330 
1331     ui_widget->setElementWidget(ui_widget_list);
1332 
1333     return ui_widget;
1334 }
1335 
saveWidget(QToolBar * toolBar,DomWidget * ui_parentWidget)1336 DomWidget *QDesignerResource::saveWidget(QToolBar *toolBar, DomWidget *ui_parentWidget)
1337 {
1338     DomWidget *ui_widget = QAbstractFormBuilder::createDom(toolBar, ui_parentWidget, false);
1339     if (const QMainWindow *mainWindow = qobject_cast<QMainWindow*>(toolBar->parentWidget())) {
1340         const bool toolBarBreak = mainWindow->toolBarBreak(toolBar);
1341         const Qt::ToolBarArea area = mainWindow->toolBarArea(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(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 
saveWidget(QDesignerDockWidget * dockWidget,DomWidget * ui_parentWidget)1360 DomWidget *QDesignerResource::saveWidget(QDesignerDockWidget *dockWidget, DomWidget *ui_parentWidget)
1361 {
1362     DomWidget *ui_widget = QAbstractFormBuilder::createDom(dockWidget, ui_parentWidget, true);
1363     if (QMainWindow *mainWindow = qobject_cast<QMainWindow*>(dockWidget->parentWidget())) {
1364         const Qt::DockWidgetArea area = mainWindow->dockWidgetArea(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 
saveWidget(QTabWidget * widget,DomWidget * ui_parentWidget)1374 DomWidget *QDesignerResource::saveWidget(QTabWidget *widget, DomWidget *ui_parentWidget)
1375 {
1376     DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false);
1377     QVector<DomWidget *> ui_widget_list;
1378 
1379     if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) {
1380         const int current = widget->currentIndex();
1381         for (int i=0; i<container->count(); ++i) {
1382             QWidget *page = container->widget(i);
1383             Q_ASSERT(page);
1384 
1385             DomWidget *ui_page = createDom(page, ui_widget);
1386             if (!ui_page) {
1387                 designerWarning(msgUnmanagedPage(core(), widget, 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*>(core()->extensionManager(), widget);
1396             PropertySheetIconValue icon = qvariant_cast<PropertySheetIconValue>(sheet->property(sheet->indexOf(QStringLiteral("currentTabIcon"))));
1397             DomProperty *p = resourceBuilder()->saveResource(workingDirectory(), QVariant::fromValue(icon));
1398             if (p) {
1399                 p->setAttributeName(strings.iconAttribute);
1400                 ui_attribute_list.append(p);
1401             }
1402             // attribute `title'
1403             p = textBuilder()->saveText(sheet->property(sheet->indexOf(QStringLiteral("currentTabText"))));
1404             if (p) {
1405                 p->setAttributeName(strings.titleAttribute);
1406                 ui_attribute_list.append(p);
1407             }
1408 
1409             // attribute `toolTip'
1410             QVariant v = sheet->property(sheet->indexOf(QStringLiteral("currentTabToolTip")));
1411             if (!qvariant_cast<PropertySheetStringValue>(v).value().isEmpty()) {
1412                 p = textBuilder()->saveText(v);
1413                 if (p) {
1414                     p->setAttributeName(strings.toolTipAttribute);
1415                 ui_attribute_list.append(p);
1416                 }
1417             }
1418 
1419             // attribute `whatsThis'
1420             v = sheet->property(sheet->indexOf(QStringLiteral("currentTabWhatsThis")));
1421             if (!qvariant_cast<PropertySheetStringValue>(v).value().isEmpty()) {
1422                 p = textBuilder()->saveText(v);
1423                 if (p) {
1424                     p->setAttributeName(strings.whatsThisAttribute);
1425                 ui_attribute_list.append(p);
1426                 }
1427             }
1428 
1429             ui_page->setElementAttribute(ui_attribute_list);
1430 
1431             ui_widget_list.append(ui_page);
1432         }
1433         widget->setCurrentIndex(current);
1434     }
1435 
1436     ui_widget->setElementWidget(ui_widget_list);
1437 
1438     return ui_widget;
1439 }
1440 
saveWidget(QToolBox * widget,DomWidget * ui_parentWidget)1441 DomWidget *QDesignerResource::saveWidget(QToolBox *widget, DomWidget *ui_parentWidget)
1442 {
1443     DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false);
1444     QVector<DomWidget *> ui_widget_list;
1445 
1446     if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) {
1447         const int current = widget->currentIndex();
1448         for (int i=0; i<container->count(); ++i) {
1449             QWidget *page = container->widget(i);
1450             Q_ASSERT(page);
1451 
1452             DomWidget *ui_page = createDom(page, ui_widget);
1453             if (!ui_page) {
1454                 designerWarning(msgUnmanagedPage(core(), widget, i, page));
1455                 continue;
1456             }
1457 
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*>(core()->extensionManager(), widget);
1466             PropertySheetIconValue icon = qvariant_cast<PropertySheetIconValue>(sheet->property(sheet->indexOf(QStringLiteral("currentItemIcon"))));
1467             DomProperty *p = resourceBuilder()->saveResource(workingDirectory(), QVariant::fromValue(icon));
1468             if (p) {
1469                 p->setAttributeName(strings.iconAttribute);
1470                 ui_attribute_list.append(p);
1471             }
1472             p = textBuilder()->saveText(sheet->property(sheet->indexOf(QStringLiteral("currentItemText"))));
1473             if (p) {
1474                 p->setAttributeName(strings.labelAttribute);
1475                 ui_attribute_list.append(p);
1476             }
1477 
1478             // attribute `toolTip'
1479             QVariant v = sheet->property(sheet->indexOf(QStringLiteral("currentItemToolTip")));
1480             if (!qvariant_cast<PropertySheetStringValue>(v).value().isEmpty()) {
1481                 p = textBuilder()->saveText(v);
1482                 if (p) {
1483                     p->setAttributeName(strings.toolTipAttribute);
1484                     ui_attribute_list.append(p);
1485                 }
1486             }
1487 
1488             ui_page->setElementAttribute(ui_attribute_list);
1489 
1490             ui_widget_list.append(ui_page);
1491         }
1492         widget->setCurrentIndex(current);
1493     }
1494 
1495     ui_widget->setElementWidget(ui_widget_list);
1496 
1497     return ui_widget;
1498 }
1499 
saveWidget(QWizardPage * wizardPage,DomWidget * ui_parentWidget)1500 DomWidget *QDesignerResource::saveWidget(QWizardPage *wizardPage, DomWidget *ui_parentWidget)
1501 {
1502     DomWidget *ui_widget = QAbstractFormBuilder::createDom(wizardPage, ui_parentWidget, true);
1503     QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), 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(pageIdPropertyName);
1507     if (pageIdIndex != -1 && sheet->isChanged(pageIdIndex)) {
1508         DomProperty *property = variantToDomProperty(this, wizardPage->metaObject(), pageIdPropertyName, sheet->property(pageIdIndex));
1509         Q_ASSERT(property);
1510         property->elementString()->setAttributeNotr(QStringLiteral("true"));
1511         DomPropertyList attributes = ui_widget->elementAttribute();
1512         attributes.push_back(property);
1513         ui_widget->setElementAttribute(attributes);
1514     }
1515     return ui_widget;
1516 }
1517 
1518 // Do not save the 'currentTabName' properties of containers
checkContainerProperty(const QWidget * w,const QString & propertyName)1519 static inline bool checkContainerProperty(const QWidget *w, const QString &propertyName)
1520 {
1521     if (qobject_cast<const QToolBox *>(w))
1522         return QToolBoxWidgetPropertySheet::checkProperty(propertyName);
1523     if (qobject_cast<const QTabWidget *>(w))
1524         return QTabWidgetPropertySheet::checkProperty(propertyName);
1525     if (qobject_cast<const QStackedWidget *>(w))
1526         return QStackedWidgetPropertySheet::checkProperty(propertyName);
1527     if (qobject_cast<const QMdiArea *>(w))
1528         return QMdiAreaPropertySheet::checkProperty(propertyName);
1529     return true;
1530 }
1531 
checkProperty(QObject * obj,const QString & prop) const1532 bool QDesignerResource::checkProperty(QObject *obj, const QString &prop) const
1533 {
1534     const QDesignerMetaObjectInterface *meta = core()->introspection()->metaObject(obj);
1535 
1536     const int pindex = meta->indexOfProperty(prop);
1537     if (pindex != -1 && !(meta->property(pindex)->attributes(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(), check_widget);
1554     }
1555 
1556     if (check_widget && !checkContainerProperty(check_widget, prop))
1557         return false;
1558 
1559     if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), obj)) {
1560         QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core()->extensionManager(), obj);
1561         const int pindex = sheet->indexOf(prop);
1562         if (sheet->isAttribute(pindex))
1563             return false;
1564 
1565         if (!dynamicSheet || !dynamicSheet->isDynamicProperty(pindex))
1566             return sheet->isChanged(pindex);
1567         if (!sheet->isVisible(pindex))
1568             return false;
1569         return true;
1570     }
1571 
1572     return false;
1573 }
1574 
addItem(DomLayoutItem * ui_item,QLayoutItem * item,QLayout * layout)1575 bool 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*>(layout);
1582     QBoxLayout *box = qobject_cast<QBoxLayout*>(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(), ui_item->attributeRow(), ui_item->attributeColumn(), rowSpan, 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 
addItem(DomWidget * ui_widget,QWidget * widget,QWidget * parentWidget)1598 bool QDesignerResource::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
1599 {
1600     core()->metaDataBase()->add(widget); // ensure the widget is in the meta database
1601 
1602     if (! QAbstractFormBuilder::addItem(ui_widget, widget, parentWidget) || qobject_cast<QMainWindow*> (parentWidget)) {
1603         if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), parentWidget))
1604             container->addWidget(widget);
1605     }
1606 
1607     if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(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(ui_widget->elementAttribute());
1616         QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), parentWidget);
1617         if (DomProperty *picon = attributes.value(strings.iconAttribute)) {
1618             QVariant v = resourceBuilder()->loadResource(workingDirectory(), picon);
1619             sheet->setProperty(sheet->indexOf(QStringLiteral("currentTabIcon")), v);
1620         }
1621         if (DomProperty *ptext = attributes.value(strings.titleAttribute)) {
1622             QVariant v = textBuilder()->loadText(ptext);
1623             sheet->setProperty(sheet->indexOf(QStringLiteral("currentTabText")), v);
1624         }
1625         if (DomProperty *ptext = attributes.value(strings.toolTipAttribute)) {
1626             QVariant v = textBuilder()->loadText(ptext);
1627             sheet->setProperty(sheet->indexOf(QStringLiteral("currentTabToolTip")), v);
1628         }
1629         if (DomProperty *ptext = attributes.value(strings.whatsThisAttribute)) {
1630             QVariant v = textBuilder()->loadText(ptext);
1631             sheet->setProperty(sheet->indexOf(QStringLiteral("currentTabWhatsThis")), v);
1632         }
1633         tabWidget->setCurrentIndex(current);
1634     } else if (QToolBox *toolBox = qobject_cast<QToolBox*>(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(ui_widget->elementAttribute());
1643         QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), parentWidget);
1644         if (DomProperty *picon = attributes.value(strings.iconAttribute)) {
1645             QVariant v = resourceBuilder()->loadResource(workingDirectory(), picon);
1646             sheet->setProperty(sheet->indexOf(QStringLiteral("currentItemIcon")), v);
1647         }
1648         if (DomProperty *ptext = attributes.value(strings.labelAttribute)) {
1649             QVariant v = textBuilder()->loadText(ptext);
1650             sheet->setProperty(sheet->indexOf(QStringLiteral("currentItemText")), v);
1651         }
1652         if (DomProperty *ptext = attributes.value(strings.toolTipAttribute)) {
1653             QVariant v = textBuilder()->loadText(ptext);
1654             sheet->setProperty(sheet->indexOf(QStringLiteral("currentItemToolTip")), v);
1655         }
1656         toolBox->setCurrentIndex(current);
1657     }
1658 
1659     return true;
1660 }
1661 
copy(QIODevice * dev,const FormBuilderClipboard & selection)1662 bool 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 
copy(const FormBuilderClipboard & selection)1684 DomUI *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(w, ui_widget);
1702             m_selected = nullptr;
1703             if (ui_child)
1704                 ui_widget_list.append(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(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(m_resourceBuilder->usedQrcFiles()));
1736     if (DomCustomWidgets *cws = saveCustomWidgets())
1737         ui->setElementCustomWidgets(cws);
1738     return ui;
1739 }
1740 
paste(DomUI * ui,QWidget * widgetParent,QObject * actionParent)1741 FormBuilderClipboard 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(domWidget, widgetParent)) {
1757                 w->move(w->pos() + offset);
1758                 // ### change the init properties of w
1759                 rc.m_widgets.append(w);
1760             }
1761         }
1762     }
1763     const auto domActions = topLevel->elementAction();
1764     for (DomAction *domAction : domActions) {
1765         if (QAction *a = create(domAction, actionParent))
1766             rc.m_actions .append(a);
1767     }
1768 
1769     m_isMainWidget = saved;
1770 
1771     if (QDesignerExtraInfoExtension *extra = qt_extension<QDesignerExtraInfoExtension*>(core()->extensionManager(), core()))
1772         extra->loadUiExtraInfo(ui);
1773 
1774     createResources(ui->elementResources());
1775 
1776     return rc;
1777 }
1778 
paste(QIODevice * dev,QWidget * widgetParent,QObject * actionParent)1779 FormBuilderClipboard 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(uiElement, Qt::CaseInsensitive)) {
1789                 ui.read(reader);
1790                 uiInitialized = true;
1791             } else {
1792                 //: Parsing clipboard contents
1793                 reader.raiseError(QCoreApplication::translate("QDesignerResource", "Unexpected element <%1>").arg(reader.name().toString()));
1794             }
1795         }
1796     }
1797     if (reader.hasError()) {
1798         //: Parsing clipboard contents
1799         designerWarning(QCoreApplication::translate("QDesignerResource", "Error while pasting clipboard contents at line %1, column %2: %3")
1800                                     .arg(reader.lineNumber()).arg(reader.columnNumber())
1801                                     .arg(reader.errorString()));
1802         uiInitialized = false;
1803     } else if (!uiInitialized) {
1804         //: Parsing clipboard contents
1805         designerWarning(QCoreApplication::translate("QDesignerResource", "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, widgetParent, actionParent);
1812 
1813     return clipBoard;
1814 }
1815 
layoutInfo(DomLayout * layout,QObject * parent,int * margin,int * spacing)1816 void QDesignerResource::layoutInfo(DomLayout *layout, QObject *parent, int *margin, int *spacing)
1817 {
1818     QAbstractFormBuilder::layoutInfo(layout, parent, margin, spacing);
1819 }
1820 
saveCustomWidgets()1821 DomCustomWidgets *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 *>(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(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(db->indexOfClassName(name), custom_widget);
1872     }
1873 
1874     DomCustomWidgets *customWidgets = new DomCustomWidgets;
1875     customWidgets->setElementCustomWidget(orderedMap.values().toVector());
1876     return customWidgets;
1877 }
1878 
canCompressSpacings(QObject * object) const1879 bool QDesignerResource::canCompressSpacings(QObject *object) const
1880 {
1881     if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), object)) {
1882         if (qobject_cast<QGridLayout *>(object)) {
1883             const int h = sheet->property(sheet->indexOf(QStringLiteral("horizontalSpacing"))).toInt();
1884             const int v = sheet->property(sheet->indexOf(QStringLiteral("verticalSpacing"))).toInt();
1885             if (h == v)
1886                 return true;
1887         }
1888     }
1889     return false;
1890 }
1891 
computeProperties(QObject * object)1892 QList<DomProperty*> QDesignerResource::computeProperties(QObject *object)
1893 {
1894     QList<DomProperty*> properties;
1895     if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), object)) {
1896         QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(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(p);
1914                 } else {
1915                     properties.append(p);
1916                 }
1917             }
1918         }
1919         if (compressSpacings) {
1920             if (spacingProperties.count() == 2) {
1921                 DomProperty *spacingProperty = spacingProperties.at(0);
1922                 spacingProperty->setAttributeName(QStringLiteral("spacing"));
1923                 properties.append(spacingProperty);
1924                 delete spacingProperties.at(1);
1925             } else {
1926                 properties += spacingProperties;
1927             }
1928         }
1929     }
1930     return properties;
1931 }
1932 
applyProperStdSetAttribute(QObject * object,const QString & propertyName,DomProperty * property)1933 DomProperty *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*>(mgr, object)) {
1940         const QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(mgr, object);
1941         const QDesignerPropertySheet *designerSheet = qobject_cast<QDesignerPropertySheet*>(core()->extensionManager()->extension(object, Q_TYPEID(QDesignerPropertySheetExtension)));
1942         const int index = sheet->indexOf(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
hasSetter(QDesignerFormEditorInterface * core,QObject * object,const QString & propertyName)1950 static 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(propertyName);
1954     if (pindex == -1)
1955         return true;
1956     return  meta->property(pindex)->hasSetter();
1957 }
1958 
createProperty(QObject * object,const QString & propertyName,const QVariant & value)1959 DomProperty *QDesignerResource::createProperty(QObject *object, const QString &propertyName, const QVariant &value)
1960 {
1961     if (!checkProperty(object, propertyName)) {
1962         return nullptr;
1963     }
1964 
1965     if (value.canConvert<PropertySheetFlagValue>()) {
1966         const PropertySheetFlagValue f = qvariant_cast<PropertySheetFlagValue>(value);
1967         const QString flagString = f.metaFlags.toString(f.value, 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(), object, propertyName))
1974             p->setAttributeStdset(0);
1975         p->setAttributeName(propertyName);
1976         p->setElementSet(flagString);
1977         return applyProperStdSetAttribute(object, propertyName, p);
1978     }
1979     if (value.canConvert<PropertySheetEnumValue>()) {
1980         const PropertySheetEnumValue e = qvariant_cast<PropertySheetEnumValue>(value);
1981         bool ok;
1982         const QString id = e.metaEnum.toString(e.value, DesignerMetaEnum::FullyQualified, &ok);
1983         if (!ok)
1984             designerWarning(e.metaEnum.messageToStringFailed(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(), object, propertyName))
1991             p->setAttributeStdset(0);
1992         p->setAttributeName(propertyName);
1993         p->setElementEnum(id);
1994         return applyProperStdSetAttribute(object, propertyName, p);
1995     }
1996     if (value.canConvert<PropertySheetStringValue>()) {
1997         const PropertySheetStringValue strVal = qvariant_cast<PropertySheetStringValue>(value);
1998         DomProperty *p = stringToDomProperty(strVal.value(), strVal);
1999         if (!hasSetter(core(), object, propertyName))
2000             p->setAttributeStdset(0);
2001 
2002         p->setAttributeName(propertyName);
2003 
2004         return applyProperStdSetAttribute(object, propertyName, p);
2005     }
2006     if (value.canConvert<PropertySheetStringListValue>()) {
2007         const PropertySheetStringListValue listValue = qvariant_cast<PropertySheetStringListValue>(value);
2008         DomProperty *p = new DomProperty;
2009         if (!hasSetter(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(listValue, domStringList);
2017         p->setElementStringList(domStringList);
2018         return applyProperStdSetAttribute(object, propertyName, p);
2019     }
2020     if (value.canConvert<PropertySheetKeySequenceValue>()) {
2021         const PropertySheetKeySequenceValue keyVal = qvariant_cast<PropertySheetKeySequenceValue>(value);
2022         DomProperty *p = stringToDomProperty(keyVal.value().toString(), keyVal);
2023         if (!hasSetter(core(), object, propertyName))
2024             p->setAttributeStdset(0);
2025 
2026         p->setAttributeName(propertyName);
2027 
2028         return applyProperStdSetAttribute(object, propertyName, p);
2029     }
2030 
2031     return applyProperStdSetAttribute(object, propertyName, QAbstractFormBuilder::createProperty(object, propertyName, value));
2032 }
2033 
mergeWithLoadedPaths(const QStringList & paths) const2034 QStringList 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(loadedPaths.cbegin(), loadedPaths.cend(),
2040                         std::back_inserter(newPaths),
2041                         [&newPaths] (const QString &path) { return newPaths.contains(path); });
2042 #endif
2043     return newPaths;
2044 }
2045 
2046 
createResources(DomResources * resources)2047 void 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(m_formWindow->absoluteDir().absoluteFilePath(res->attributeLocation()));
2054             while (!QFile::exists(path)) {
2055                 QWidget *dialogParent = m_formWindow->core()->topLevel();
2056                 const QString promptTitle = QCoreApplication::translate("qdesigner_internal::QDesignerResource", "Loading qrc file");
2057                 const QString prompt = QCoreApplication::translate("qdesigner_internal::QDesignerResource", "The specified qrc file <p><b>%1</b></p><p>could not be found. Do you want to update the file location?</p>").arg(path);
2058 
2059                 const QMessageBox::StandardButton answer = core()->dialogGui()->message(dialogParent,  QDesignerDialogGuiInterface::ResourceLoadFailureMessage,
2060                         QMessageBox::Warning, promptTitle,  prompt, QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes);
2061                 if (answer == QMessageBox::Yes) {
2062                     const QFileInfo fi(path);
2063                     const QString fileDialogTitle = QCoreApplication::translate("qdesigner_internal::QDesignerResource", "New location for %1").arg(fi.fileName());
2064                     const QString fileDialogPattern = QCoreApplication::translate("qdesigner_internal::QDesignerResource", "Resource files (*.qrc)");
2065                     path = core()->dialogGui()->getOpenFileName(dialogParent, fileDialogTitle, fi.absolutePath(), fileDialogPattern);
2066                     if (path.isEmpty())
2067                         break;
2068                     m_formWindow->setProperty("_q_resourcepathchanged", 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(paths.cbegin(), paths.cend(),
2088                             std::back_inserter(newPaths),
2089                             [&newPaths] (const QString &path) { return newPaths.contains(path); });
2090         resourceSet->activateResourceFilePaths(newPaths);
2091     } else {
2092         resourceSet = m_formWindow->core()->resourceModel()->addResourceSet(paths);
2093         m_formWindow->setResourceSet(resourceSet);
2094         QObject::connect(m_formWindow->core()->resourceModel(), &QtResourceModel::resourceSetActivated,
2095                 m_formWindow, &FormWindowBase::resourceSetActivated);
2096     }
2097 }
2098 
saveResources()2099 DomResources *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(paths);
2113 }
2114 
saveResources(const QStringList & qrcPaths)2115 DomResources *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(path)) {
2123                 DomResource *dom_res = new DomResource;
2124                 QString conv_path = path;
2125                 if (m_resourceBuilder->isSaveRelative())
2126                     conv_path = m_formWindow->absoluteDir().relativeFilePath(path);
2127                 dom_res->setAttributeLocation(conv_path.replace(QDir::separator(), QLatin1Char('/')));
2128                 dom_include.append(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 
createDom(QAction * action)2139 DomAction *QDesignerResource::createDom(QAction *action)
2140 {
2141     if (!core()->metaDataBase()->item(action) || action->menu())
2142         return nullptr;
2143 
2144     return QAbstractFormBuilder::createDom(action);
2145 }
2146 
createDom(QActionGroup * actionGroup)2147 DomActionGroup *QDesignerResource::createDom(QActionGroup *actionGroup)
2148 {
2149     if (core()->metaDataBase()->item(actionGroup) != nullptr) {
2150         return QAbstractFormBuilder::createDom(actionGroup);
2151     }
2152 
2153     return nullptr;
2154 }
2155 
create(DomAction * ui_action,QObject * parent)2156 QAction *QDesignerResource::create(DomAction *ui_action, QObject *parent)
2157 {
2158     if (QAction *action = QAbstractFormBuilder::create(ui_action, parent)) {
2159         core()->metaDataBase()->add(action);
2160         return action;
2161     }
2162 
2163     return nullptr;
2164 }
2165 
create(DomActionGroup * ui_action_group,QObject * parent)2166 QActionGroup *QDesignerResource::create(DomActionGroup *ui_action_group, QObject *parent)
2167 {
2168     if (QActionGroup *actionGroup = QAbstractFormBuilder::create(ui_action_group, parent)) {
2169         core()->metaDataBase()->add(actionGroup);
2170         return actionGroup;
2171     }
2172 
2173     return nullptr;
2174 }
2175 
createActionRefDom(QAction * action)2176 DomActionRef *QDesignerResource::createActionRefDom(QAction *action)
2177 {
2178     if (!core()->metaDataBase()->item(action)
2179             || (!action->isSeparator() && !action->menu() && action->objectName().isEmpty()))
2180         return nullptr;
2181 
2182     return QAbstractFormBuilder::createActionRefDom(action);
2183 }
2184 
addMenuAction(QAction * action)2185 void QDesignerResource::addMenuAction(QAction *action)
2186 {
2187     core()->metaDataBase()->add(action);
2188 }
2189 
createAction(QObject * parent,const QString & name)2190 QAction *QDesignerResource::createAction(QObject *parent, const QString &name)
2191 {
2192     if (QAction *action = QAbstractFormBuilder::createAction(parent, name)) {
2193         core()->metaDataBase()->add(action);
2194         return action;
2195     }
2196 
2197     return nullptr;
2198 }
2199 
createActionGroup(QObject * parent,const QString & name)2200 QActionGroup *QDesignerResource::createActionGroup(QObject *parent, const QString &name)
2201 {
2202     if (QActionGroup *actionGroup = QAbstractFormBuilder::createActionGroup(parent, name)) {
2203         core()->metaDataBase()->add(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 */
applyAttributesToPropertySheet(const DomWidget * ui_widget,QWidget * widget)2212 void 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*>(m_formWindow->core()->extensionManager(), 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("Unable to apply attributive property '%1' to '%2'. It does not exist.").arg(name, widget->objectName());
2224             designerWarning(msg);
2225         } else {
2226             sheet->setProperty(index, domPropertyToVariant(this, widget->metaObject(), *it));
2227             sheet->setChanged(index, true);
2228         }
2229     }
2230 }
2231 
loadExtraInfo(DomWidget * ui_widget,QWidget * widget,QWidget * parentWidget)2232 void 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*>(widget))
2237         applyAttributesToPropertySheet(ui_widget, widget);
2238 }
2239 
2240 }
2241 
2242 QT_END_NAMESPACE
2243