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 -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