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