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_propertycommand_p.h"
43 #include "qdesigner_utils_p.h"
44 #include "dynamicpropertysheet.h"
45 #include "qdesigner_propertyeditor_p.h"
46 #include "qdesigner_integration_p.h"
47 #include "spacer_widget_p.h"
48 #include "qdesigner_propertysheet_p.h"
49
50 #include <QtDesigner/QDesignerFormEditorInterface>
51 #include <QtDesigner/QDesignerFormWindowInterface>
52 #include <QtDesigner/QDesignerFormWindowCursorInterface>
53 #include <QtDesigner/QDesignerDynamicPropertySheetExtension>
54 #include <QtDesigner/QDesignerPropertySheetExtension>
55 #include <QtDesigner/QDesignerPropertyEditorInterface>
56 #include <QtDesigner/QDesignerObjectInspectorInterface>
57 #include <QtDesigner/QDesignerIntegrationInterface>
58 #include <QtDesigner/QDesignerWidgetDataBaseInterface>
59 #include <QtDesigner/QExtensionManager>
60
61 #include <QtCore/QSize>
62 #include <QtCore/QTextStream>
63 #include <QtGui/QWidget>
64 #include <QtGui/QApplication>
65 #include <QtGui/QAction>
66 #include <QtGui/QDialog>
67 #include <QtGui/QPushButton>
68 #include <QtGui/QLayout>
69 #include <qdebug.h>
70
71 QT_BEGIN_NAMESPACE
72
73 namespace {
74 enum { debugPropertyCommands = 0 };
75
76 // Debug resolve mask of font
fontMask(unsigned m)77 QString fontMask(unsigned m)
78 {
79 QString rc;
80 if (m & QFont::FamilyResolved)
81 rc += QLatin1String("Family");
82 if (m & QFont::SizeResolved)
83 rc += QLatin1String("Size ");
84 if (m & QFont::WeightResolved)
85 rc += QLatin1String("Bold ");
86 if (m & QFont::StyleResolved)
87 rc += QLatin1String("Style ");
88 if (m & QFont::UnderlineResolved)
89 rc += QLatin1String("Underline ");
90 if (m & QFont::StrikeOutResolved)
91 rc += QLatin1String("StrikeOut ");
92 if (m & QFont::KerningResolved)
93 rc += QLatin1String("Kerning ");
94 if (m & QFont::StyleStrategyResolved)
95 rc += QLatin1String("StyleStrategy");
96 return rc;
97 }
98
99 // Debug font
fontString(const QFont & f)100 QString fontString(const QFont &f)
101 {
102 QString rc; {
103 const QChar comma = QLatin1Char(',');
104 QTextStream str(&rc);
105 str << QLatin1String("QFont(\"") << f.family() << comma <<
106 f.pointSize();
107 if (f.bold())
108 str << comma << QLatin1String("bold");
109 if (f.italic())
110 str << comma << QLatin1String("italic");
111 if (f.underline())
112 str << comma << QLatin1String("underline");
113 if (f.strikeOut())
114 str << comma << QLatin1String("strikeOut");
115 if (f.kerning())
116 str << comma << QLatin1String("kerning");
117 str << comma << f.styleStrategy() << QLatin1String(" resolve: ")
118 << fontMask(f.resolve()) << QLatin1Char(')');
119 }
120 return rc;
121 }
checkSize(const QSize & size)122 QSize checkSize(const QSize &size)
123 {
124 return size.boundedTo(QSize(0xFFFFFF, 0xFFFFFF));
125 }
126
diffSize(QDesignerFormWindowInterface * fw)127 QSize diffSize(QDesignerFormWindowInterface *fw)
128 {
129 const QWidget *container = fw->core()->integration()->containerWindow(fw);
130 if (!container)
131 return QSize();
132
133 const QSize diff = container->size() - fw->size(); // decoration offset of container window
134 return diff;
135 }
136
checkSizes(QDesignerFormWindowInterface * fw,const QSize & size,QSize * formSize,QSize * containerSize)137 void checkSizes(QDesignerFormWindowInterface *fw, const QSize &size, QSize *formSize, QSize *containerSize)
138 {
139 const QWidget *container = fw->core()->integration()->containerWindow(fw);
140 if (!container)
141 return;
142
143 const QSize diff = diffSize(fw); // decoration offset of container window
144
145 QSize newFormSize = checkSize(size).expandedTo(fw->mainContainer()->minimumSizeHint()); // don't try to resize to smaller size than minimumSizeHint
146 QSize newContainerSize = newFormSize + diff;
147
148 newContainerSize = newContainerSize.expandedTo(container->minimumSizeHint());
149 newContainerSize = newContainerSize.expandedTo(container->minimumSize());
150
151 newFormSize = newContainerSize - diff;
152
153 newContainerSize = checkSize(newContainerSize);
154
155 if (formSize)
156 *formSize = newFormSize;
157 if (containerSize)
158 *containerSize = newContainerSize;
159 }
160
161 /* SubProperties: When applying a changed property to a multiselection, it sometimes makes
162 * sense to apply only parts (subproperties) of the property.
163 * For example, if someone changes the x-value of a geometry in the property editor
164 * and applies it to a multi-selection, y should not be applied as this would cause all
165 * the widgets to overlap.
166 * The following routines can be used to find out the changed subproperties of a property,
167 * which are represented as a mask, and to apply them while leaving the others intact. */
168
169 enum RectSubPropertyMask { SubPropertyX=1, SubPropertyY = 2, SubPropertyWidth = 4, SubPropertyHeight = 8 };
170 enum SizePolicySubPropertyMask { SubPropertyHSizePolicy = 1, SubPropertyHStretch = 2, SubPropertyVSizePolicy = 4, SubPropertyVStretch = 8 };
171 enum AlignmentSubPropertyMask { SubPropertyHorizontalAlignment = 1, SubPropertyVerticalAlignment = 2 };
172 enum StringSubPropertyMask { SubPropertyStringValue = 1, SubPropertyStringComment = 2, SubPropertyStringTranslatable = 4, SubPropertyStringDisambiguation = 8 };
173 enum KeySequenceSubPropertyMask { SubPropertyKeySequenceValue = 1, SubPropertyKeySequenceComment = 2, SubPropertyKeySequenceTranslatable = 4, SubPropertyKeySequenceDisambiguation = 8 };
174
175 enum CommonSubPropertyMask { SubPropertyAll = 0xFFFFFFFF };
176
177 // Set the mask flag in mask if the properties do not match.
178 #define COMPARE_SUBPROPERTY(object1, object2, getter, mask, maskFlag) if (object1.getter() != object2.getter()) mask |= maskFlag;
179
180 // find changed subproperties of a rectangle
compareSubProperties(const QRect & r1,const QRect & r2)181 unsigned compareSubProperties(const QRect & r1, const QRect & r2)
182 {
183 unsigned rc = 0;
184 COMPARE_SUBPROPERTY(r1, r2, x, rc, SubPropertyX)
185 COMPARE_SUBPROPERTY(r1, r2, y, rc, SubPropertyY)
186 COMPARE_SUBPROPERTY(r1, r2, width, rc, SubPropertyWidth)
187 COMPARE_SUBPROPERTY(r1, r2, height, rc, SubPropertyHeight)
188 return rc;
189 }
190
191 // find changed subproperties of a QSize
compareSubProperties(const QSize & r1,const QSize & r2)192 unsigned compareSubProperties(const QSize & r1, const QSize & r2)
193 {
194 unsigned rc = 0;
195 COMPARE_SUBPROPERTY(r1, r2, width, rc, SubPropertyWidth)
196 COMPARE_SUBPROPERTY(r1, r2, height, rc, SubPropertyHeight)
197 return rc;
198 }
199 // find changed subproperties of a QSizePolicy
compareSubProperties(const QSizePolicy & sp1,const QSizePolicy & sp2)200 unsigned compareSubProperties(const QSizePolicy & sp1, const QSizePolicy & sp2)
201 {
202 unsigned rc = 0;
203 COMPARE_SUBPROPERTY(sp1, sp2, horizontalPolicy, rc, SubPropertyHSizePolicy)
204 COMPARE_SUBPROPERTY(sp1, sp2, horizontalStretch, rc, SubPropertyHStretch)
205 COMPARE_SUBPROPERTY(sp1, sp2, verticalPolicy, rc, SubPropertyVSizePolicy)
206 COMPARE_SUBPROPERTY(sp1, sp2, verticalStretch, rc, SubPropertyVStretch)
207 return rc;
208 }
209 // find changed subproperties of qdesigner_internal::PropertySheetStringValue
compareSubProperties(const qdesigner_internal::PropertySheetStringValue & str1,const qdesigner_internal::PropertySheetStringValue & str2)210 unsigned compareSubProperties(const qdesigner_internal::PropertySheetStringValue & str1, const qdesigner_internal::PropertySheetStringValue & str2)
211 {
212 unsigned rc = 0;
213 COMPARE_SUBPROPERTY(str1, str2, value, rc, SubPropertyStringValue)
214 COMPARE_SUBPROPERTY(str1, str2, comment, rc, SubPropertyStringComment)
215 COMPARE_SUBPROPERTY(str1, str2, translatable, rc, SubPropertyStringTranslatable)
216 COMPARE_SUBPROPERTY(str1, str2, disambiguation, rc, SubPropertyStringDisambiguation)
217 return rc;
218 }
219 // find changed subproperties of qdesigner_internal::PropertySheetKeySequenceValue
compareSubProperties(const qdesigner_internal::PropertySheetKeySequenceValue & str1,const qdesigner_internal::PropertySheetKeySequenceValue & str2)220 unsigned compareSubProperties(const qdesigner_internal::PropertySheetKeySequenceValue & str1, const qdesigner_internal::PropertySheetKeySequenceValue & str2)
221 {
222 unsigned rc = 0;
223 COMPARE_SUBPROPERTY(str1, str2, value, rc, SubPropertyKeySequenceValue)
224 COMPARE_SUBPROPERTY(str1, str2, comment, rc, SubPropertyKeySequenceComment)
225 COMPARE_SUBPROPERTY(str1, str2, translatable, rc, SubPropertyKeySequenceTranslatable)
226 COMPARE_SUBPROPERTY(str1, str2, disambiguation, rc, SubPropertyKeySequenceDisambiguation)
227 return rc;
228 }
229
230 // Compare font-subproperties taking the [undocumented]
231 // resolve flag into account
232 template <class Property>
compareFontSubProperty(const QFont & f1,const QFont & f2,Property (QFont::* getter)()const,unsigned maskBit,unsigned & mask)233 void compareFontSubProperty(const QFont & f1,
234 const QFont & f2,
235 Property (QFont::*getter) () const,
236 unsigned maskBit,
237 unsigned &mask)
238 {
239 const bool f1Changed = f1.resolve() & maskBit;
240 const bool f2Changed = f2.resolve() & maskBit;
241 // Role has been set/reset in editor
242 if (f1Changed != f2Changed) {
243 mask |= maskBit;
244 } else {
245 // Was modified in both palettes: Compare values.
246 if (f1Changed && f2Changed && (f1.*getter)() != (f2.*getter)())
247 mask |= maskBit;
248 }
249 }
250 // find changed subproperties of a QFont
compareSubProperties(const QFont & f1,const QFont & f2)251 unsigned compareSubProperties(const QFont & f1, const QFont & f2)
252 {
253 unsigned rc = 0;
254 compareFontSubProperty(f1, f2, &QFont::family, QFont::FamilyResolved, rc);
255 compareFontSubProperty(f1, f2, &QFont::pointSize, QFont::SizeResolved, rc);
256 compareFontSubProperty(f1, f2, &QFont::bold, QFont::WeightResolved, rc);
257 compareFontSubProperty(f1, f2, &QFont::italic, QFont::StyleResolved, rc);
258 compareFontSubProperty(f1, f2, &QFont::underline, QFont::UnderlineResolved, rc);
259 compareFontSubProperty(f1, f2, &QFont::strikeOut, QFont::StrikeOutResolved, rc);
260 compareFontSubProperty(f1, f2, &QFont::kerning, QFont::KerningResolved, rc);
261 compareFontSubProperty(f1, f2, &QFont::styleStrategy, QFont::StyleStrategyResolved, rc);
262 if (debugPropertyCommands)
263 qDebug() << "compareSubProperties " << fontString(f1) << fontString(f2) << "\n\treturns " << fontMask(rc);
264 return rc;
265 }
266
267 // Compare colors of a role
roleColorChanged(const QPalette & p1,const QPalette & p2,QPalette::ColorRole role)268 bool roleColorChanged(const QPalette & p1, const QPalette & p2, QPalette::ColorRole role)
269 {
270 for (int group = QPalette::Active; group < QPalette::NColorGroups; group++) {
271 const QPalette::ColorGroup pgroup = static_cast<QPalette::ColorGroup>(group);
272 if (p1.color(pgroup, role) != p2.color(pgroup, role))
273 return true;
274 }
275 return false;
276 }
277 // find changed subproperties of a QPalette taking the [undocumented] resolve flags into account
compareSubProperties(const QPalette & p1,const QPalette & p2)278 unsigned compareSubProperties(const QPalette & p1, const QPalette & p2)
279 {
280 unsigned rc = 0;
281 unsigned maskBit = 1u;
282 // generate a mask for each role
283 const unsigned p1Changed = p1.resolve();
284 const unsigned p2Changed = p2.resolve();
285 for (int role = QPalette::WindowText; role < QPalette::NColorRoles; role++, maskBit <<= 1u) {
286 const bool p1RoleChanged = p1Changed & maskBit;
287 const bool p2RoleChanged = p2Changed & maskBit;
288 // Role has been set/reset in editor
289 if (p1RoleChanged != p2RoleChanged) {
290 rc |= maskBit;
291 } else {
292 // Was modified in both palettes: Compare values.
293 if (p1RoleChanged && p2RoleChanged && roleColorChanged(p1, p2, static_cast<QPalette::ColorRole>(role)))
294 rc |= maskBit;
295 }
296 }
297 return rc;
298 }
299
300 // find changed subproperties of a QAlignment which is a flag combination of vertical and horizontal
301
compareSubProperties(Qt::Alignment a1,Qt::Alignment a2)302 unsigned compareSubProperties(Qt::Alignment a1, Qt::Alignment a2)
303 {
304 unsigned rc = 0;
305 if ((a1 & Qt::AlignHorizontal_Mask) != (a2 & Qt::AlignHorizontal_Mask))
306 rc |= SubPropertyHorizontalAlignment;
307 if ((a1 & Qt::AlignVertical_Mask) != (a2 & Qt::AlignVertical_Mask))
308 rc |= SubPropertyVerticalAlignment;
309 return rc;
310 }
311
variantToAlignment(const QVariant & q)312 Qt::Alignment variantToAlignment(const QVariant & q)
313 {
314 return Qt::Alignment(qdesigner_internal::Utils::valueOf(q));
315 }
316 // find changed subproperties of a variant
compareSubProperties(const QVariant & q1,const QVariant & q2,qdesigner_internal::SpecialProperty specialProperty)317 unsigned compareSubProperties(const QVariant & q1, const QVariant & q2, qdesigner_internal::SpecialProperty specialProperty)
318 {
319 // Do not clobber new value in the comparison function in
320 // case someone sets a QString on a PropertySheetStringValue.
321 if (q1.type() != q2.type())
322 return SubPropertyAll;
323 switch (q1.type()) {
324 case QVariant::Rect:
325 return compareSubProperties(q1.toRect(), q2.toRect());
326 case QVariant::Size:
327 return compareSubProperties(q1.toSize(), q2.toSize());
328 case QVariant::SizePolicy:
329 return compareSubProperties(qvariant_cast<QSizePolicy>(q1), qvariant_cast<QSizePolicy>(q2));
330 case QVariant::Font:
331 return compareSubProperties(qvariant_cast<QFont>(q1), qvariant_cast<QFont>(q2));
332 case QVariant::Palette:
333 return compareSubProperties(qvariant_cast<QPalette>(q1), qvariant_cast<QPalette>(q2));
334 default:
335 if (q1.userType() == qMetaTypeId<qdesigner_internal::PropertySheetIconValue>())
336 return qvariant_cast<qdesigner_internal::PropertySheetIconValue>(q1).compare(qvariant_cast<qdesigner_internal::PropertySheetIconValue>(q2));
337 else if (q1.userType() == qMetaTypeId<qdesigner_internal::PropertySheetStringValue>())
338 return compareSubProperties(qvariant_cast<qdesigner_internal::PropertySheetStringValue>(q1), qvariant_cast<qdesigner_internal::PropertySheetStringValue>(q2));
339 else if (q1.userType() == qMetaTypeId<qdesigner_internal::PropertySheetKeySequenceValue>())
340 return compareSubProperties(qvariant_cast<qdesigner_internal::PropertySheetKeySequenceValue>(q1), qvariant_cast<qdesigner_internal::PropertySheetKeySequenceValue>(q2));
341 // Enumerations, flags
342 switch (specialProperty) {
343 case qdesigner_internal::SP_Alignment:
344 return compareSubProperties(variantToAlignment(q1), variantToAlignment(q2));
345 default:
346 break;
347 }
348 break;
349 }
350 return SubPropertyAll;
351 }
352
353 // Apply the sub property if mask flag is set in mask
354 #define SET_SUBPROPERTY(rc, newValue, getter, setter, mask, maskFlag) if (mask & maskFlag) rc.setter(newValue.getter());
355
356 // apply changed subproperties to a rectangle
applyRectSubProperty(const QRect & oldValue,const QRect & newValue,unsigned mask)357 QRect applyRectSubProperty(const QRect &oldValue, const QRect &newValue, unsigned mask)
358 {
359 QRect rc = oldValue;
360 SET_SUBPROPERTY(rc, newValue, x, moveLeft, mask, SubPropertyX)
361 SET_SUBPROPERTY(rc, newValue, y, moveTop, mask, SubPropertyY)
362 SET_SUBPROPERTY(rc, newValue, width, setWidth, mask, SubPropertyWidth)
363 SET_SUBPROPERTY(rc, newValue, height, setHeight, mask, SubPropertyHeight)
364 return rc;
365 }
366
367
368 // apply changed subproperties to a rectangle QSize
applySizeSubProperty(const QSize & oldValue,const QSize & newValue,unsigned mask)369 QSize applySizeSubProperty(const QSize &oldValue, const QSize &newValue, unsigned mask)
370 {
371 QSize rc = oldValue;
372 SET_SUBPROPERTY(rc, newValue, width, setWidth, mask, SubPropertyWidth)
373 SET_SUBPROPERTY(rc, newValue, height, setHeight, mask, SubPropertyHeight)
374 return rc;
375 }
376
377
378 // apply changed subproperties to a SizePolicy
applySizePolicySubProperty(const QSizePolicy & oldValue,const QSizePolicy & newValue,unsigned mask)379 QSizePolicy applySizePolicySubProperty(const QSizePolicy &oldValue, const QSizePolicy &newValue, unsigned mask)
380 {
381 QSizePolicy rc = oldValue;
382 SET_SUBPROPERTY(rc, newValue, horizontalPolicy, setHorizontalPolicy, mask, SubPropertyHSizePolicy)
383 SET_SUBPROPERTY(rc, newValue, horizontalStretch, setHorizontalStretch, mask, SubPropertyHStretch)
384 SET_SUBPROPERTY(rc, newValue, verticalPolicy, setVerticalPolicy, mask, SubPropertyVSizePolicy)
385 SET_SUBPROPERTY(rc, newValue, verticalStretch, setVerticalStretch, mask, SubPropertyVStretch)
386 return rc;
387 }
388
389 // apply changed subproperties to a qdesigner_internal::PropertySheetStringValue
applyStringSubProperty(const qdesigner_internal::PropertySheetStringValue & oldValue,const qdesigner_internal::PropertySheetStringValue & newValue,unsigned mask)390 qdesigner_internal::PropertySheetStringValue applyStringSubProperty(const qdesigner_internal::PropertySheetStringValue &oldValue,
391 const qdesigner_internal::PropertySheetStringValue &newValue, unsigned mask)
392 {
393 qdesigner_internal::PropertySheetStringValue rc = oldValue;
394 SET_SUBPROPERTY(rc, newValue, value, setValue, mask, SubPropertyStringValue)
395 SET_SUBPROPERTY(rc, newValue, comment, setComment, mask, SubPropertyStringComment)
396 SET_SUBPROPERTY(rc, newValue, translatable, setTranslatable, mask, SubPropertyStringTranslatable)
397 SET_SUBPROPERTY(rc, newValue, disambiguation, setDisambiguation, mask, SubPropertyStringDisambiguation)
398 return rc;
399 }
400
401 // apply changed subproperties to a qdesigner_internal::PropertySheetKeySequenceValue
applyKeySequenceSubProperty(const qdesigner_internal::PropertySheetKeySequenceValue & oldValue,const qdesigner_internal::PropertySheetKeySequenceValue & newValue,unsigned mask)402 qdesigner_internal::PropertySheetKeySequenceValue applyKeySequenceSubProperty(const qdesigner_internal::PropertySheetKeySequenceValue &oldValue,
403 const qdesigner_internal::PropertySheetKeySequenceValue &newValue, unsigned mask)
404 {
405 qdesigner_internal::PropertySheetKeySequenceValue rc = oldValue;
406 SET_SUBPROPERTY(rc, newValue, value, setValue, mask, SubPropertyKeySequenceValue)
407 SET_SUBPROPERTY(rc, newValue, comment, setComment, mask, SubPropertyKeySequenceComment)
408 SET_SUBPROPERTY(rc, newValue, translatable, setTranslatable, mask, SubPropertyKeySequenceTranslatable)
409 SET_SUBPROPERTY(rc, newValue, disambiguation, setDisambiguation, mask, SubPropertyKeySequenceDisambiguation)
410 return rc;
411 }
412
413 // Apply the font-subproperties keeping the [undocumented]
414 // resolve flag in sync (note that PropertySetterType might be something like const T&).
415 template <class PropertyReturnType, class PropertySetterType>
setFontSubProperty(unsigned mask,const QFont & newValue,unsigned maskBit,PropertyReturnType (QFont::* getter)()const,void (QFont::* setter)(PropertySetterType),QFont & value)416 inline void setFontSubProperty(unsigned mask,
417 const QFont &newValue,
418 unsigned maskBit,
419 PropertyReturnType (QFont::*getter) () const,
420 void (QFont::*setter) (PropertySetterType),
421 QFont &value)
422 {
423 if (mask & maskBit) {
424 (value.*setter)((newValue.*getter)());
425 // Set the resolve bit from NewValue in return value
426 uint r = value.resolve();
427 const bool origFlag = newValue.resolve() & maskBit;
428 if (origFlag)
429 r |= maskBit;
430 else
431 r &= ~maskBit;
432 value.resolve(r);
433 if (debugPropertyCommands)
434 qDebug() << "setFontSubProperty " << fontMask(maskBit) << " resolve=" << origFlag;
435 }
436 }
437 // apply changed subproperties to a QFont
applyFontSubProperty(const QFont & oldValue,const QFont & newValue,unsigned mask)438 QFont applyFontSubProperty(const QFont &oldValue, const QFont &newValue, unsigned mask)
439 {
440 QFont rc = oldValue;
441 setFontSubProperty(mask, newValue, QFont::FamilyResolved, &QFont::family, &QFont::setFamily, rc);
442 setFontSubProperty(mask, newValue, QFont::SizeResolved, &QFont::pointSize, &QFont::setPointSize, rc);
443 setFontSubProperty(mask, newValue, QFont::WeightResolved, &QFont::bold, &QFont::setBold, rc);
444 setFontSubProperty(mask, newValue, QFont::StyleResolved, &QFont::italic, &QFont::setItalic, rc);
445 setFontSubProperty(mask, newValue, QFont::UnderlineResolved, &QFont::underline, &QFont::setUnderline, rc);
446 setFontSubProperty(mask, newValue, QFont::StrikeOutResolved, &QFont::strikeOut, &QFont::setStrikeOut, rc);
447 setFontSubProperty(mask, newValue, QFont::KerningResolved, &QFont::kerning, &QFont::setKerning, rc);
448 setFontSubProperty(mask, newValue, QFont::StyleStrategyResolved, &QFont::styleStrategy, &QFont::setStyleStrategy, rc);
449 if (debugPropertyCommands)
450 qDebug() << "applyFontSubProperty old " << fontMask(oldValue.resolve()) << " new " << fontMask(newValue.resolve()) << " return: " << fontMask(rc.resolve());
451 return rc;
452 }
453
454 // apply changed subproperties to a QPalette
applyPaletteSubProperty(const QPalette & oldValue,const QPalette & newValue,unsigned mask)455 QPalette applyPaletteSubProperty(const QPalette &oldValue, const QPalette &newValue, unsigned mask)
456 {
457 QPalette rc = oldValue;
458 // apply a mask for each role
459 unsigned maskBit = 1u;
460 for (int role = QPalette::WindowText; role < QPalette::NColorRoles; role++, maskBit <<= 1u) {
461 if (mask & maskBit) {
462 for (int group = QPalette::Active; group < QPalette::NColorGroups; group++) {
463 const QPalette::ColorGroup pgroup = static_cast<QPalette::ColorGroup>(group);
464 const QPalette::ColorRole prole = static_cast<QPalette::ColorRole>(role);
465 rc.setColor(pgroup, prole, newValue.color(pgroup, prole));
466 }
467 // Set the resolve bit from NewValue in return value
468 uint r = rc.resolve();
469 const bool origFlag = newValue.resolve() & maskBit;
470 if (origFlag)
471 r |= maskBit;
472 else
473 r &= ~maskBit;
474 rc.resolve(r);
475 }
476 }
477 return rc;
478 }
479
480 // apply changed subproperties to a QAlignment which is a flag combination of vertical and horizontal
applyAlignmentSubProperty(Qt::Alignment oldValue,Qt::Alignment newValue,unsigned mask)481 Qt::Alignment applyAlignmentSubProperty(Qt::Alignment oldValue, Qt::Alignment newValue, unsigned mask)
482 {
483 // easy: both changed.
484 if (mask == (SubPropertyHorizontalAlignment|SubPropertyVerticalAlignment))
485 return newValue;
486 // Change subprop
487 const Qt::Alignment changeMask = (mask & SubPropertyHorizontalAlignment) ? Qt::AlignHorizontal_Mask : Qt::AlignVertical_Mask;
488 const Qt::Alignment takeOverMask = (mask & SubPropertyHorizontalAlignment) ? Qt::AlignVertical_Mask : Qt::AlignHorizontal_Mask;
489 return (oldValue & takeOverMask) | (newValue & changeMask);
490 }
491
492 }
493
494 namespace qdesigner_internal {
495
496 // apply changed subproperties to a variant
applySubProperty(const QVariant & oldValue,const QVariant & newValue,qdesigner_internal::SpecialProperty specialProperty,unsigned mask,bool changed)497 PropertyHelper::Value applySubProperty(const QVariant &oldValue, const QVariant &newValue, qdesigner_internal::SpecialProperty specialProperty, unsigned mask, bool changed)
498 {
499 if (mask == SubPropertyAll)
500 return PropertyHelper::Value(newValue, changed);
501
502 switch (oldValue.type()) {
503 case QVariant::Rect:
504 return PropertyHelper::Value(applyRectSubProperty(oldValue.toRect(), newValue.toRect(), mask), changed);
505 case QVariant::Size:
506 return PropertyHelper::Value(applySizeSubProperty(oldValue.toSize(), newValue.toSize(), mask), changed);
507 case QVariant::SizePolicy:
508 return PropertyHelper::Value(QVariant::fromValue(applySizePolicySubProperty(qvariant_cast<QSizePolicy>(oldValue), qvariant_cast<QSizePolicy>(newValue), mask)), changed);
509 case QVariant::Font: {
510 // Changed flag in case of font and palette depends on resolve mask only, not on the passed "changed" value.
511
512 // The first case: the user changed bold subproperty and then pressed reset button for this subproperty (not for
513 // the whole font property). We instantiate SetPropertyCommand passing changed=true. But in this case no
514 // subproperty is changed and the whole property should be marked an unchanged.
515
516 // The second case: there are 2 pushbuttons, for 1st the user set bold and italic subproperties,
517 // for the 2nd he set bold only. He does multiselection so that the current widget is the 2nd one.
518 // He press reset next to bold subproperty. In result the 2nd widget should have the whole
519 // font property marked as unchanged and the 1st widget should have the font property
520 // marked as changed and only italic subproperty should be marked as changed (the bold should be reset).
521
522 // The third case: there are 2 pushbuttons, for 1st the user set bold and italic subproperties,
523 // for the 2nd he set bold only. He does multiselection so that the current widget is the 2nd one.
524 // He press reset button for the whole font property. In result whole font properties for both
525 // widgets should be marked as unchanged.
526 QFont font = applyFontSubProperty(qvariant_cast<QFont>(oldValue), qvariant_cast<QFont>(newValue), mask);
527 return PropertyHelper::Value(QVariant::fromValue(font), font.resolve());
528 }
529 case QVariant::Palette: {
530 QPalette palette = applyPaletteSubProperty(qvariant_cast<QPalette>(oldValue), qvariant_cast<QPalette>(newValue), mask);
531 return PropertyHelper::Value(QVariant::fromValue(palette), palette.resolve());
532 }
533 default:
534 if (oldValue.userType() == qMetaTypeId<qdesigner_internal::PropertySheetIconValue>()) {
535 PropertySheetIconValue icon = qvariant_cast<qdesigner_internal::PropertySheetIconValue>(oldValue);
536 icon.assign(qvariant_cast<qdesigner_internal::PropertySheetIconValue>(newValue), mask);
537 return PropertyHelper::Value(QVariant::fromValue(icon), icon.mask());
538 } else if (oldValue.userType() == qMetaTypeId<qdesigner_internal::PropertySheetStringValue>()) {
539 qdesigner_internal::PropertySheetStringValue str = applyStringSubProperty(
540 qvariant_cast<qdesigner_internal::PropertySheetStringValue>(oldValue),
541 qvariant_cast<qdesigner_internal::PropertySheetStringValue>(newValue), mask);
542 return PropertyHelper::Value(QVariant::fromValue(str), changed);
543 } else if (oldValue.userType() == qMetaTypeId<qdesigner_internal::PropertySheetKeySequenceValue>()) {
544 qdesigner_internal::PropertySheetKeySequenceValue key = applyKeySequenceSubProperty(
545 qvariant_cast<qdesigner_internal::PropertySheetKeySequenceValue>(oldValue),
546 qvariant_cast<qdesigner_internal::PropertySheetKeySequenceValue>(newValue), mask);
547 return PropertyHelper::Value(QVariant::fromValue(key), changed);
548 }
549 // Enumerations, flags
550 switch (specialProperty) {
551 case qdesigner_internal::SP_Alignment: {
552 qdesigner_internal::PropertySheetFlagValue f = qvariant_cast<qdesigner_internal::PropertySheetFlagValue>(oldValue);
553 f.value = applyAlignmentSubProperty(variantToAlignment(oldValue), variantToAlignment(newValue), mask);
554 QVariant v;
555 v.setValue(f);
556 return PropertyHelper::Value(v, changed);
557 }
558 default:
559 break;
560 }
561 break;
562 }
563 return PropertyHelper::Value(newValue, changed);
564
565 }
566 // figure out special property
getSpecialProperty(const QString & propertyName)567 enum SpecialProperty getSpecialProperty(const QString& propertyName)
568 {
569 if (propertyName == QLatin1String("objectName"))
570 return SP_ObjectName;
571 if (propertyName == QLatin1String("layoutName"))
572 return SP_LayoutName;
573 if (propertyName == QLatin1String("spacerName"))
574 return SP_SpacerName;
575 if (propertyName == QLatin1String("icon"))
576 return SP_Icon;
577 if (propertyName == QLatin1String("currentTabName"))
578 return SP_CurrentTabName;
579 if (propertyName == QLatin1String("currentItemName"))
580 return SP_CurrentItemName;
581 if (propertyName == QLatin1String("currentPageName"))
582 return SP_CurrentPageName;
583 if (propertyName == QLatin1String("geometry"))
584 return SP_Geometry;
585 if (propertyName == QLatin1String("windowTitle"))
586 return SP_WindowTitle;
587 if (propertyName == QLatin1String("minimumSize"))
588 return SP_MinimumSize;
589 if (propertyName == QLatin1String("maximumSize"))
590 return SP_MaximumSize;
591 if (propertyName == QLatin1String("alignment"))
592 return SP_Alignment;
593 if (propertyName == QLatin1String("autoDefault"))
594 return SP_AutoDefault;
595 if (propertyName == QLatin1String("shortcut"))
596 return SP_Shortcut;
597 if (propertyName == QLatin1String("orientation"))
598 return SP_Orientation;
599 return SP_None;
600 }
601
602
PropertyHelper(QObject * object,SpecialProperty specialProperty,QDesignerPropertySheetExtension * sheet,int index)603 PropertyHelper::PropertyHelper(QObject* object,
604 SpecialProperty specialProperty,
605 QDesignerPropertySheetExtension *sheet,
606 int index) :
607 m_specialProperty(specialProperty),
608 m_object(object),
609 m_objectType(OT_Object),
610 m_propertySheet(sheet), m_index(index),
611 m_oldValue(m_propertySheet->property(m_index), m_propertySheet->isChanged(m_index))
612 {
613 if (object->isWidgetType()) {
614 m_parentWidget = (qobject_cast<QWidget*>(object))->parentWidget();
615 m_objectType = OT_Widget;
616 } else {
617 if (const QAction *action = qobject_cast<const QAction *>(m_object))
618 m_objectType = action->associatedWidgets().empty() ? OT_FreeAction : OT_AssociatedAction;
619 }
620
621 if(debugPropertyCommands)
622 qDebug() << "PropertyHelper on " << m_object->objectName() << " index= " << m_index << " type = " << m_objectType;
623 }
624
integration(QDesignerFormWindowInterface * fw) const625 QDesignerIntegration *PropertyHelper::integration(QDesignerFormWindowInterface *fw) const
626 {
627 return qobject_cast<QDesignerIntegration *>(fw->core()->integration());
628 }
629
630 // Set widget value, apply corrections and checks in case of main window.
checkApplyWidgetValue(QDesignerFormWindowInterface * fw,QWidget * w,SpecialProperty specialProperty,QVariant & value)631 void PropertyHelper::checkApplyWidgetValue(QDesignerFormWindowInterface *fw, QWidget* w,
632 SpecialProperty specialProperty, QVariant &value)
633 {
634
635 bool isMainContainer = false;
636 if (QDesignerFormWindowCursorInterface *cursor = fw->cursor()) {
637 if (cursor->isWidgetSelected(w)) {
638 if (cursor->isWidgetSelected(fw->mainContainer())) {
639 isMainContainer = true;
640 }
641 }
642 }
643 if (!isMainContainer)
644 return;
645
646 QWidget *container = fw->core()->integration()->containerWindow(fw);
647 if (!container)
648 return;
649
650
651 switch (specialProperty) {
652 case SP_MinimumSize: {
653 const QSize size = checkSize(value.toSize());
654 value.setValue(size);
655 }
656
657 break;
658 case SP_MaximumSize: {
659 QSize fs, cs;
660 checkSizes(fw, value.toSize(), &fs, &cs);
661 container->setMaximumSize(cs);
662 fw->mainContainer()->setMaximumSize(fs);
663 value.setValue(fs);
664
665 }
666 break;
667 case SP_Geometry: {
668 QRect r = value.toRect();
669 QSize fs, cs;
670 checkSizes(fw, r.size(), &fs, &cs);
671 container->resize(cs);
672 r.setSize(fs);
673 value.setValue(r);
674 }
675 break;
676 default:
677 break;
678 }
679 }
680
updateMask() const681 unsigned PropertyHelper::updateMask() const
682 {
683 unsigned rc = 0;
684 switch (m_specialProperty) {
685 case SP_ObjectName:
686 case SP_LayoutName:
687 case SP_SpacerName:
688 case SP_CurrentTabName:
689 case SP_CurrentItemName:
690 case SP_CurrentPageName:
691 if (m_objectType != OT_FreeAction)
692 rc |= UpdateObjectInspector;
693 break;
694 case SP_Icon:
695 if (m_objectType == OT_AssociatedAction)
696 rc |= UpdateObjectInspector;
697 break;
698 case SP_Orientation: // for updating splitter icon
699 rc |= UpdateObjectInspector;
700 break;
701 default:
702 break;
703
704 }
705 return rc;
706 }
707
708
canMerge(const PropertyHelper & other) const709 bool PropertyHelper::canMerge(const PropertyHelper &other) const
710 {
711 return m_object == other.m_object && m_index == other.m_index;
712 }
713
triggerActionChanged(QAction * a)714 void PropertyHelper::triggerActionChanged(QAction *a)
715 {
716 a->setData(QVariant(true)); // this triggers signal "changed" in QAction
717 a->setData(QVariant(false));
718 }
719
720 // Update the object to reflect the changes
updateObject(QDesignerFormWindowInterface * fw,const QVariant & oldValue,const QVariant & newValue)721 void PropertyHelper::updateObject(QDesignerFormWindowInterface *fw, const QVariant &oldValue, const QVariant &newValue)
722 {
723 if(debugPropertyCommands){
724 qDebug() << "PropertyHelper::updateObject(" << m_object->objectName() << ") " << oldValue << " -> " << newValue;
725 }
726 switch (m_objectType) {
727 case OT_Widget: {
728 switch (m_specialProperty) {
729 case SP_ObjectName: {
730 const QString oldName = qvariant_cast<PropertySheetStringValue>(oldValue).value();
731 const QString newName = qvariant_cast<PropertySheetStringValue>(newValue).value();
732 QDesignerFormWindowCommand::updateBuddies(fw, oldName, newName);
733 }
734 break;
735 default:
736 break;
737 }
738 } break;
739 case OT_AssociatedAction:
740 case OT_FreeAction:
741 // SP_Shortcut is a fake property, so, QAction::changed does not trigger.
742 if (m_specialProperty == SP_ObjectName || m_specialProperty == SP_Shortcut)
743 triggerActionChanged(qobject_cast<QAction *>(m_object));
744 break;
745 default:
746 break;
747 }
748
749 switch (m_specialProperty) {
750 case SP_ObjectName:
751 case SP_LayoutName:
752 case SP_SpacerName:
753 if (QDesignerIntegration *integr = integration(fw)) {
754 const QString oldName = qvariant_cast<PropertySheetStringValue>(oldValue).value();
755 const QString newName = qvariant_cast<PropertySheetStringValue>(newValue).value();
756 integr->emitObjectNameChanged(fw, m_object, newName, oldName);
757 }
758 break;
759 default:
760 break;
761 }
762 }
763
ensureUniqueObjectName(QDesignerFormWindowInterface * fw,QObject * object) const764 void PropertyHelper::ensureUniqueObjectName(QDesignerFormWindowInterface *fw, QObject *object) const
765 {
766 switch (m_specialProperty) {
767 case SP_SpacerName:
768 if (object->isWidgetType()) {
769 if (Spacer *sp = qobject_cast<Spacer *>(object)) {
770 fw->ensureUniqueObjectName(sp);
771 return;
772 }
773 }
774 fw->ensureUniqueObjectName(object);
775 break;
776 case SP_LayoutName: // Layout name is invoked on the parent widget.
777 if (object->isWidgetType()) {
778 const QWidget * w = qobject_cast<const QWidget *>(object);
779 if (QLayout *wlayout = w->layout()) {
780 fw->ensureUniqueObjectName(wlayout);
781 return;
782 }
783 }
784 fw->ensureUniqueObjectName(object);
785 break;
786 case SP_ObjectName:
787 fw->ensureUniqueObjectName(object);
788 break;
789 default:
790 break;
791 }
792 }
793
setValue(QDesignerFormWindowInterface * fw,const QVariant & value,bool changed,unsigned subPropertyMask)794 PropertyHelper::Value PropertyHelper::setValue(QDesignerFormWindowInterface *fw, const QVariant &value, bool changed, unsigned subPropertyMask)
795 {
796 // Set new whole value
797 if (subPropertyMask == SubPropertyAll)
798 return applyValue(fw, m_oldValue.first, Value(value, changed));
799
800 // apply subproperties
801 const PropertyHelper::Value maskedNewValue = applySubProperty(m_oldValue.first, value, m_specialProperty, subPropertyMask, changed);
802 return applyValue(fw, m_oldValue.first, maskedNewValue);
803 }
804
805 // Apply the value and update. Returns corrected value
applyValue(QDesignerFormWindowInterface * fw,const QVariant & oldValue,Value newValue)806 PropertyHelper::Value PropertyHelper::applyValue(QDesignerFormWindowInterface *fw, const QVariant &oldValue, Value newValue)
807 {
808 if(debugPropertyCommands){
809 qDebug() << "PropertyHelper::applyValue(" << m_object << ") " << oldValue << " -> " << newValue.first << " changed=" << newValue.second;
810 }
811
812 if (m_objectType == OT_Widget) {
813 checkApplyWidgetValue(fw, qobject_cast<QWidget *>(m_object), m_specialProperty, newValue.first);
814 }
815
816 m_propertySheet->setProperty(m_index, newValue.first);
817 m_propertySheet->setChanged(m_index, newValue.second);
818
819 switch (m_specialProperty) {
820 case SP_LayoutName:
821 case SP_ObjectName:
822 case SP_SpacerName:
823 ensureUniqueObjectName(fw, m_object);
824 newValue.first = m_propertySheet->property(m_index);
825 break;
826 default:
827 break;
828 }
829
830 updateObject(fw, oldValue, newValue.first);
831 return newValue;
832 }
833
restoreOldValue(QDesignerFormWindowInterface * fw)834 PropertyHelper::Value PropertyHelper::restoreOldValue(QDesignerFormWindowInterface *fw)
835 {
836 return applyValue(fw, m_propertySheet->property(m_index), m_oldValue);
837 }
838
839 // find the default value in widget DB in case PropertySheet::reset fails
findDefaultValue(QDesignerFormWindowInterface * fw) const840 QVariant PropertyHelper::findDefaultValue(QDesignerFormWindowInterface *fw) const
841 {
842 if (m_specialProperty == SP_AutoDefault && qobject_cast<const QPushButton*>(m_object)) {
843 // AutoDefault defaults to true on dialogs
844 const bool isDialog = qobject_cast<const QDialog *>(fw->mainContainer());
845 return QVariant(isDialog);
846 }
847
848 const int item_idx = fw->core()->widgetDataBase()->indexOfObject(m_object);
849 if (item_idx == -1)
850 return m_oldValue.first; // We simply don't know the value in this case
851
852 const QDesignerWidgetDataBaseItemInterface *item = fw->core()->widgetDataBase()->item(item_idx);
853 const QList<QVariant> default_prop_values = item->defaultPropertyValues();
854 if (m_index < default_prop_values.size())
855 return default_prop_values.at(m_index);
856
857 if (m_oldValue.first.type() == QVariant::Color)
858 return QColor();
859
860 return m_oldValue.first; // Again, we just don't know
861 }
862
restoreDefaultValue(QDesignerFormWindowInterface * fw)863 PropertyHelper::Value PropertyHelper::restoreDefaultValue(QDesignerFormWindowInterface *fw)
864 {
865
866 Value defaultValue = qMakePair(QVariant(), false);
867 const QVariant currentValue = m_propertySheet->property(m_index);
868 // try to reset sheet, else try to find default
869 if (m_propertySheet->reset(m_index)) {
870 defaultValue.first = m_propertySheet->property(m_index);
871 } else {
872 defaultValue.first = findDefaultValue(fw);
873 m_propertySheet->setProperty(m_index, defaultValue.first);
874 }
875
876 m_propertySheet->setChanged(m_index, defaultValue.second);
877
878 if (m_objectType == OT_Widget) {
879 checkApplyWidgetValue(fw, qobject_cast<QWidget *>(m_object), m_specialProperty, defaultValue.first);
880 }
881
882 switch (m_specialProperty) {
883 case SP_LayoutName:
884 case SP_ObjectName:
885 case SP_SpacerName:
886 ensureUniqueObjectName(fw, m_object);
887 defaultValue.first = m_propertySheet->property(m_index);
888 break;
889 default:
890 break;
891 }
892
893 updateObject(fw, currentValue, defaultValue.first);
894 return defaultValue;
895 }
896
897 // ---- PropertyListCommand::PropertyDescription(
898
899
PropertyDescription(const QString & propertyName,QDesignerPropertySheetExtension * propertySheet,int index)900 PropertyListCommand::PropertyDescription::PropertyDescription(const QString &propertyName,
901 QDesignerPropertySheetExtension *propertySheet,
902 int index) :
903 m_propertyName(propertyName),
904 m_propertyGroup(propertySheet->propertyGroup(index)),
905 m_propertyType(propertySheet->property(index).type()),
906 m_specialProperty(getSpecialProperty(propertyName))
907 {
908 }
909
PropertyDescription()910 PropertyListCommand::PropertyDescription::PropertyDescription() :
911 m_propertyType(QVariant::Invalid),
912 m_specialProperty(SP_None)
913 {
914 }
915
debug() const916 void PropertyListCommand::PropertyDescription::debug() const
917 {
918 qDebug() << m_propertyName << m_propertyGroup << m_propertyType << m_specialProperty;
919 }
920
equals(const PropertyDescription & p) const921 bool PropertyListCommand::PropertyDescription::equals(const PropertyDescription &p) const
922 {
923 return m_propertyType == p.m_propertyType && m_specialProperty == p.m_specialProperty &&
924 m_propertyName == p.m_propertyName && m_propertyGroup == p.m_propertyGroup;
925 }
926
927
928 // ---- PropertyListCommand
PropertyListCommand(QDesignerFormWindowInterface * formWindow,QUndoCommand * parent)929 PropertyListCommand::PropertyListCommand(QDesignerFormWindowInterface *formWindow,
930 QUndoCommand *parent) :
931 QDesignerFormWindowCommand(QString(), formWindow, parent)
932 {
933 }
934
propertyName() const935 const QString PropertyListCommand::propertyName() const
936 {
937 return m_propertyDescription.m_propertyName;
938 }
939
specialProperty() const940 SpecialProperty PropertyListCommand::specialProperty() const
941 {
942 return m_propertyDescription.m_specialProperty;
943 }
944
945 // add an object
add(QObject * object,const QString & propertyName)946 bool PropertyListCommand::add(QObject *object, const QString &propertyName)
947 {
948 QDesignerPropertySheetExtension* sheet = propertySheet(object);
949 Q_ASSERT(sheet);
950
951 const int index = sheet->indexOf(propertyName);
952 if (index == -1)
953 return false;
954
955 if (QDesignerPropertySheet *exSheet = qobject_cast<QDesignerPropertySheet*>(core()->extensionManager()->extension(object, Q_TYPEID(QDesignerPropertySheetExtension))))
956 if (!exSheet->isEnabled(index))
957 return false;
958
959 const PropertyDescription description(propertyName, sheet, index);
960
961 if (m_propertyHelperList.empty()) {
962 // first entry
963 m_propertyDescription = description;
964 } else {
965 // checks: mismatch or only one object in case of name
966 const bool match = m_propertyDescription.equals(description);
967 if (!match || m_propertyDescription.m_specialProperty == SP_ObjectName)
968 return false;
969 }
970
971 const PropertyHelperPtr ph(createPropertyHelper(object, m_propertyDescription.m_specialProperty, sheet, index));
972 m_propertyHelperList.push_back(ph);
973 return true;
974 }
975
createPropertyHelper(QObject * object,SpecialProperty sp,QDesignerPropertySheetExtension * sheet,int sheetIndex) const976 PropertyHelper *PropertyListCommand::createPropertyHelper(QObject *object, SpecialProperty sp,
977 QDesignerPropertySheetExtension *sheet, int sheetIndex) const
978 {
979 return new PropertyHelper(object, sp, sheet, sheetIndex);
980 }
981
982 // Init from a list and make sure referenceObject is added first to obtain the right property group
initList(const ObjectList & list,const QString & apropertyName,QObject * referenceObject)983 bool PropertyListCommand::initList(const ObjectList &list, const QString &apropertyName, QObject *referenceObject)
984 {
985 propertyHelperList().clear();
986
987 // Ensure the referenceObject (property editor) is first, so the right property group is chosen.
988 if (referenceObject) {
989 if (!add(referenceObject, apropertyName))
990 return false;
991 }
992 foreach (QObject *o, list) {
993 if (o != referenceObject)
994 add(o, apropertyName);
995 }
996
997 return !propertyHelperList().empty();
998 }
999
1000
object(int index) const1001 QObject* PropertyListCommand::object(int index) const
1002 {
1003 Q_ASSERT(index < m_propertyHelperList.size());
1004 return m_propertyHelperList.at(index)->object();
1005 }
1006
oldValue(int index) const1007 QVariant PropertyListCommand::oldValue(int index) const
1008 {
1009 Q_ASSERT(index < m_propertyHelperList.size());
1010 return m_propertyHelperList.at(index)->oldValue();
1011 }
1012
setOldValue(const QVariant & oldValue,int index)1013 void PropertyListCommand::setOldValue(const QVariant &oldValue, int index)
1014 {
1015 Q_ASSERT(index < m_propertyHelperList.size());
1016 m_propertyHelperList.at(index)->setOldValue(oldValue);
1017 }
1018 // ----- SetValueFunction: Set a new value when applied to a PropertyHelper.
1019 class SetValueFunction {
1020 public:
1021 SetValueFunction(QDesignerFormWindowInterface *formWindow, const PropertyHelper::Value &newValue, unsigned subPropertyMask);
1022
1023 PropertyHelper::Value operator()(PropertyHelper&);
1024 private:
1025 QDesignerFormWindowInterface *m_formWindow;
1026 const PropertyHelper::Value m_newValue;
1027 const unsigned m_subPropertyMask;
1028 };
1029
1030
SetValueFunction(QDesignerFormWindowInterface * formWindow,const PropertyHelper::Value & newValue,unsigned subPropertyMask)1031 SetValueFunction::SetValueFunction(QDesignerFormWindowInterface *formWindow, const PropertyHelper::Value &newValue, unsigned subPropertyMask) :
1032 m_formWindow(formWindow),
1033 m_newValue(newValue),
1034 m_subPropertyMask(subPropertyMask)
1035 {
1036 }
1037
operator ()(PropertyHelper & ph)1038 PropertyHelper::Value SetValueFunction::operator()(PropertyHelper &ph) {
1039 return ph.setValue(m_formWindow, m_newValue.first, m_newValue.second, m_subPropertyMask);
1040 }
1041
1042 // ----- UndoSetValueFunction: Restore old value when applied to a PropertyHelper.
1043 class UndoSetValueFunction {
1044 public:
UndoSetValueFunction(QDesignerFormWindowInterface * formWindow)1045 UndoSetValueFunction(QDesignerFormWindowInterface *formWindow) : m_formWindow(formWindow) {}
operator ()(PropertyHelper & ph)1046 PropertyHelper::Value operator()(PropertyHelper& ph) { return ph.restoreOldValue(m_formWindow); }
1047 private:
1048 QDesignerFormWindowInterface *m_formWindow;
1049 };
1050
1051 // ----- RestoreDefaultFunction: Restore default value when applied to a PropertyHelper.
1052 class RestoreDefaultFunction {
1053 public:
RestoreDefaultFunction(QDesignerFormWindowInterface * formWindow)1054 RestoreDefaultFunction(QDesignerFormWindowInterface *formWindow) : m_formWindow(formWindow) {}
operator ()(PropertyHelper & ph)1055 PropertyHelper::Value operator()(PropertyHelper& ph) { return ph.restoreDefaultValue(m_formWindow); }
1056 private:
1057 QDesignerFormWindowInterface *m_formWindow;
1058 };
1059
1060 // ----- changePropertyList: Iterates over a sequence of PropertyHelpers and
1061 // applies a function to them.
1062 // The function returns the corrected value which is then set in the property editor.
1063 // Returns a combination of update flags.
1064 template <class PropertyListIterator, class Function>
changePropertyList(QDesignerFormEditorInterface * core,const QString & propertyName,PropertyListIterator begin,PropertyListIterator end,Function function)1065 unsigned changePropertyList(QDesignerFormEditorInterface *core,
1066 const QString &propertyName,
1067 PropertyListIterator begin,
1068 PropertyListIterator end,
1069 Function function)
1070 {
1071 unsigned updateMask = 0;
1072 QDesignerPropertyEditorInterface *propertyEditor = core->propertyEditor();
1073 bool updatedPropertyEditor = false;
1074
1075 for (PropertyListIterator it = begin; it != end; ++it) {
1076 PropertyHelper *ph = it->data();
1077 if (QObject* object = ph->object()) { // Might have been deleted in the meantime
1078 const PropertyHelper::Value newValue = function( *ph );
1079 updateMask |= ph->updateMask();
1080 // Update property editor if it is the current object
1081 if (!updatedPropertyEditor && propertyEditor && object == propertyEditor->object()) {
1082 propertyEditor->setPropertyValue(propertyName, newValue.first, newValue.second);
1083 updatedPropertyEditor = true;
1084 }
1085 }
1086 }
1087 if (!updatedPropertyEditor) updateMask |= PropertyHelper::UpdatePropertyEditor;
1088 return updateMask;
1089 }
1090
1091
1092 // set a new value, return update mask
setValue(QVariant value,bool changed,unsigned subPropertyMask)1093 unsigned PropertyListCommand::setValue(QVariant value, bool changed, unsigned subPropertyMask)
1094 {
1095 if(debugPropertyCommands)
1096 qDebug() << "PropertyListCommand::setValue(" << value
1097 << changed << subPropertyMask << ')';
1098 return changePropertyList(formWindow()->core(),
1099 m_propertyDescription.m_propertyName,
1100 m_propertyHelperList.begin(), m_propertyHelperList.end(),
1101 SetValueFunction(formWindow(), PropertyHelper::Value(value, changed), subPropertyMask));
1102 }
1103
1104 // restore old value, return update mask
restoreOldValue()1105 unsigned PropertyListCommand::restoreOldValue()
1106 {
1107 if(debugPropertyCommands)
1108 qDebug() << "PropertyListCommand::restoreOldValue()";
1109
1110 return changePropertyList(formWindow()->core(),
1111 m_propertyDescription.m_propertyName, m_propertyHelperList.begin(), m_propertyHelperList.end(),
1112 UndoSetValueFunction(formWindow()));
1113 }
1114 // set default value, return update mask
restoreDefaultValue()1115 unsigned PropertyListCommand::restoreDefaultValue()
1116 {
1117 if(debugPropertyCommands)
1118 qDebug() << "PropertyListCommand::restoreDefaultValue()";
1119
1120 return changePropertyList(formWindow()->core(),
1121 m_propertyDescription.m_propertyName, m_propertyHelperList.begin(), m_propertyHelperList.end(),
1122 RestoreDefaultFunction(formWindow()));
1123 }
1124
1125 // update
update(unsigned updateMask)1126 void PropertyListCommand::update(unsigned updateMask)
1127 {
1128 if(debugPropertyCommands)
1129 qDebug() << "PropertyListCommand::update(" << updateMask << ')';
1130
1131 if (updateMask & PropertyHelper::UpdateObjectInspector) {
1132 if (QDesignerObjectInspectorInterface *oi = formWindow()->core()->objectInspector())
1133 oi->setFormWindow(formWindow());
1134 }
1135
1136 if (updateMask & PropertyHelper::UpdatePropertyEditor) {
1137 // this is needed when f.ex. undo, changes parent's palette, but
1138 // the child is the active widget,
1139 // TODO: current object?
1140 if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
1141 propertyEditor->setObject(propertyEditor->object());
1142 }
1143 }
1144 }
1145
undo()1146 void PropertyListCommand::undo()
1147 {
1148 update(restoreOldValue());
1149 QDesignerPropertyEditor *designerPropertyEditor = qobject_cast<QDesignerPropertyEditor *>(core()->propertyEditor());
1150 if (designerPropertyEditor)
1151 designerPropertyEditor->updatePropertySheet();
1152 }
1153
1154 // check if lists are aequivalent for command merging (same widgets and props)
canMergeLists(const PropertyHelperList & other) const1155 bool PropertyListCommand::canMergeLists(const PropertyHelperList& other) const
1156 {
1157 if (m_propertyHelperList.size() != other.size())
1158 return false;
1159 for (int i = 0; i < m_propertyHelperList.size(); i++) {
1160 if (!m_propertyHelperList.at(i)->canMerge(*other.at(i)))
1161 return false;
1162 }
1163 return true;
1164 }
1165
1166 // ---- SetPropertyCommand ----
SetPropertyCommand(QDesignerFormWindowInterface * formWindow,QUndoCommand * parent)1167 SetPropertyCommand::SetPropertyCommand(QDesignerFormWindowInterface *formWindow,
1168 QUndoCommand *parent)
1169 : PropertyListCommand(formWindow, parent),
1170 m_subPropertyMask(SubPropertyAll)
1171 {
1172 }
1173
init(QObject * object,const QString & apropertyName,const QVariant & newValue)1174 bool SetPropertyCommand::init(QObject *object, const QString &apropertyName, const QVariant &newValue)
1175 {
1176 Q_ASSERT(object);
1177
1178 m_newValue = newValue;
1179
1180 propertyHelperList().clear();
1181 if (!add(object, apropertyName))
1182 return false;
1183
1184 setDescription();
1185 return true;
1186 }
1187
init(const ObjectList & list,const QString & apropertyName,const QVariant & newValue,QObject * referenceObject,bool enableSubPropertyHandling)1188 bool SetPropertyCommand::init(const ObjectList &list, const QString &apropertyName, const QVariant &newValue,
1189 QObject *referenceObject, bool enableSubPropertyHandling)
1190 {
1191 if (!initList(list, apropertyName, referenceObject))
1192 return false;
1193
1194 m_newValue = newValue;
1195
1196 if(debugPropertyCommands)
1197 qDebug() << "SetPropertyCommand::init()" << propertyHelperList().size() << '/' << list.size() << " reference " << referenceObject;
1198
1199 setDescription();
1200
1201 if (enableSubPropertyHandling)
1202 m_subPropertyMask = subPropertyMask(newValue, referenceObject);
1203 return true;
1204 }
1205
subPropertyMask(const QVariant & newValue,QObject * referenceObject)1206 unsigned SetPropertyCommand::subPropertyMask(const QVariant &newValue, QObject *referenceObject)
1207 {
1208 // figure out the mask of changed sub properties when comparing newValue to the current value of the reference object.
1209 if (!referenceObject)
1210 return SubPropertyAll;
1211
1212 QDesignerPropertySheetExtension* sheet = propertySheet(referenceObject);
1213 Q_ASSERT(sheet);
1214
1215 const int index = sheet->indexOf(propertyName());
1216 if (index == -1 || !sheet->isVisible(index))
1217 return SubPropertyAll;
1218
1219 return compareSubProperties(sheet->property(index), newValue, specialProperty());
1220 }
1221
setDescription()1222 void SetPropertyCommand::setDescription()
1223 {
1224 if (propertyHelperList().size() == 1) {
1225 setText(QApplication::translate("Command", "Changed '%1' of '%2'").arg(propertyName()).arg(propertyHelperList().at(0)->object()->objectName()));
1226 } else {
1227 int count = propertyHelperList().size();
1228 setText(QApplication::translate("Command", "Changed '%1' of %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(propertyName()));
1229 }
1230 }
1231
redo()1232 void SetPropertyCommand::redo()
1233 {
1234 update(setValue(m_newValue, true, m_subPropertyMask));
1235 QDesignerPropertyEditor *designerPropertyEditor = qobject_cast<QDesignerPropertyEditor *>(core()->propertyEditor());
1236 if (designerPropertyEditor)
1237 designerPropertyEditor->updatePropertySheet();
1238 }
1239
1240
id() const1241 int SetPropertyCommand::id() const
1242 {
1243 return 1976;
1244 }
1245
mergeValue(const QVariant & newValue)1246 QVariant SetPropertyCommand::mergeValue(const QVariant &newValue)
1247 {
1248 return newValue;
1249 }
1250
mergeWith(const QUndoCommand * other)1251 bool SetPropertyCommand::mergeWith(const QUndoCommand *other)
1252 {
1253 if (id() != other->id() || !formWindow()->isDirty())
1254 return false;
1255
1256 // Merging: When for example when the user types ahead in an inplace-editor,
1257 // it makes sense to merge all the generated commands containing the one-character changes.
1258 // In the case of subproperties, if the user changes the font size from 10 to 30 via 20
1259 // and then changes to bold, it makes sense to merge the font size commands only.
1260 // This is why the m_subPropertyMask is checked.
1261
1262 const SetPropertyCommand *cmd = static_cast<const SetPropertyCommand*>(other);
1263 if (!propertyDescription().equals(cmd->propertyDescription()) ||
1264 m_subPropertyMask != cmd->m_subPropertyMask ||
1265 !canMergeLists(cmd->propertyHelperList()))
1266 return false;
1267
1268 const QVariant newValue = mergeValue(cmd->newValue());
1269 if (!newValue.isValid())
1270 return false;
1271 m_newValue = newValue;
1272 m_subPropertyMask |= cmd->m_subPropertyMask;
1273 if(debugPropertyCommands)
1274 qDebug() << "SetPropertyCommand::mergeWith() succeeded " << propertyName();
1275
1276 return true;
1277 }
1278
1279 // ---- ResetPropertyCommand ----
ResetPropertyCommand(QDesignerFormWindowInterface * formWindow)1280 ResetPropertyCommand::ResetPropertyCommand(QDesignerFormWindowInterface *formWindow)
1281 : PropertyListCommand(formWindow)
1282 {
1283 }
1284
init(QObject * object,const QString & apropertyName)1285 bool ResetPropertyCommand::init(QObject *object, const QString &apropertyName)
1286 {
1287 Q_ASSERT(object);
1288
1289 propertyHelperList().clear();
1290 if (!add(object, apropertyName))
1291 return false;
1292
1293 setDescription();
1294 return true;
1295 }
1296
init(const ObjectList & list,const QString & apropertyName,QObject * referenceObject)1297 bool ResetPropertyCommand::init(const ObjectList &list, const QString &apropertyName, QObject *referenceObject)
1298 {
1299 if (!initList(list, apropertyName, referenceObject))
1300 return false;
1301
1302 if(debugPropertyCommands)
1303 qDebug() << "ResetPropertyCommand::init()" << propertyHelperList().size() << '/' << list.size();
1304
1305 setDescription();
1306 return true;
1307 }
1308
setDescription()1309 void ResetPropertyCommand::setDescription()
1310 {
1311 if (propertyHelperList().size() == 1) {
1312 setText(QApplication::translate("Command", "Reset '%1' of '%2'").arg(propertyName()).arg(propertyHelperList().at(0)->object()->objectName()));
1313 } else {
1314 int count = propertyHelperList().size();
1315 setText(QApplication::translate("Command", "Reset '%1' of %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(propertyName()));
1316 }
1317 }
1318
redo()1319 void ResetPropertyCommand::redo()
1320 {
1321 update(restoreDefaultValue());
1322 QDesignerPropertyEditor *designerPropertyEditor = qobject_cast<QDesignerPropertyEditor *>(core()->propertyEditor());
1323 if (designerPropertyEditor)
1324 designerPropertyEditor->updatePropertySheet();
1325 }
1326
AddDynamicPropertyCommand(QDesignerFormWindowInterface * formWindow)1327 AddDynamicPropertyCommand::AddDynamicPropertyCommand(QDesignerFormWindowInterface *formWindow)
1328 : QDesignerFormWindowCommand(QString(), formWindow)
1329 {
1330
1331 }
1332
init(const QList<QObject * > & selection,QObject * current,const QString & propertyName,const QVariant & value)1333 bool AddDynamicPropertyCommand::init(const QList<QObject *> &selection, QObject *current,
1334 const QString &propertyName, const QVariant &value)
1335 {
1336 Q_ASSERT(current);
1337 m_propertyName = propertyName;
1338
1339 QDesignerFormEditorInterface *core = formWindow()->core();
1340 QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), current);
1341 Q_ASSERT(dynamicSheet);
1342
1343 m_selection.clear();
1344
1345 if (!value.isValid())
1346 return false;
1347
1348 if (!dynamicSheet->canAddDynamicProperty(m_propertyName))
1349 return false;
1350
1351 m_selection.append(current);
1352
1353 m_value = value;
1354
1355 QListIterator<QObject *> it(selection);
1356 while (it.hasNext()) {
1357 QObject *obj = it.next();
1358 if (m_selection.contains(obj))
1359 continue;
1360 dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
1361 Q_ASSERT(dynamicSheet);
1362 if (dynamicSheet->canAddDynamicProperty(m_propertyName))
1363 m_selection.append(obj);
1364 }
1365
1366 setDescription();
1367 return true;
1368 }
1369
redo()1370 void AddDynamicPropertyCommand::redo()
1371 {
1372 QDesignerFormEditorInterface *core = formWindow()->core();
1373 QListIterator<QObject *> it(m_selection);
1374 while (it.hasNext()) {
1375 QObject *obj = it.next();
1376 QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
1377 dynamicSheet->addDynamicProperty(m_propertyName, m_value);
1378 if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
1379 if (propertyEditor->object() == obj)
1380 propertyEditor->setObject(obj);
1381 }
1382 }
1383 }
1384
undo()1385 void AddDynamicPropertyCommand::undo()
1386 {
1387 QDesignerFormEditorInterface *core = formWindow()->core();
1388 QListIterator<QObject *> it(m_selection);
1389 while (it.hasNext()) {
1390 QObject *obj = it.next();
1391 QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), obj);
1392 QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
1393 dynamicSheet->removeDynamicProperty(sheet->indexOf(m_propertyName));
1394 if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
1395 if (propertyEditor->object() == obj)
1396 propertyEditor->setObject(obj);
1397 }
1398 }
1399 }
1400
setDescription()1401 void AddDynamicPropertyCommand::setDescription()
1402 {
1403 if (m_selection.size() == 1) {
1404 setText(QApplication::translate("Command", "Add dynamic property '%1' to '%2'").arg(m_propertyName).arg(m_selection.first()->objectName()));
1405 } else {
1406 int count = m_selection.size();
1407 setText(QApplication::translate("Command", "Add dynamic property '%1' to %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(m_propertyName));
1408 }
1409 }
1410
1411
RemoveDynamicPropertyCommand(QDesignerFormWindowInterface * formWindow)1412 RemoveDynamicPropertyCommand::RemoveDynamicPropertyCommand(QDesignerFormWindowInterface *formWindow)
1413 : QDesignerFormWindowCommand(QString(), formWindow)
1414 {
1415
1416 }
1417
init(const QList<QObject * > & selection,QObject * current,const QString & propertyName)1418 bool RemoveDynamicPropertyCommand::init(const QList<QObject *> &selection, QObject *current,
1419 const QString &propertyName)
1420 {
1421 Q_ASSERT(current);
1422 m_propertyName = propertyName;
1423
1424 QDesignerFormEditorInterface *core = formWindow()->core();
1425 QDesignerPropertySheetExtension *propertySheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), current);
1426 Q_ASSERT(propertySheet);
1427 QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), current);
1428 Q_ASSERT(dynamicSheet);
1429
1430 m_objectToValueAndChanged.clear();
1431
1432 const int index = propertySheet->indexOf(m_propertyName);
1433 if (!dynamicSheet->isDynamicProperty(index))
1434 return false;
1435
1436 m_objectToValueAndChanged[current] = qMakePair(propertySheet->property(index), propertySheet->isChanged(index));
1437
1438 QListIterator<QObject *> it(selection);
1439 while (it.hasNext()) {
1440 QObject *obj = it.next();
1441 if (m_objectToValueAndChanged.contains(obj))
1442 continue;
1443
1444 propertySheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), obj);
1445 dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
1446 const int idx = propertySheet->indexOf(m_propertyName);
1447 if (dynamicSheet->isDynamicProperty(idx))
1448 m_objectToValueAndChanged[obj] = qMakePair(propertySheet->property(idx), propertySheet->isChanged(idx));
1449 }
1450
1451 setDescription();
1452 return true;
1453 }
1454
redo()1455 void RemoveDynamicPropertyCommand::redo()
1456 {
1457 QDesignerFormEditorInterface *core = formWindow()->core();
1458 QMap<QObject *, QPair<QVariant, bool> >::ConstIterator it = m_objectToValueAndChanged.constBegin();
1459 while (it != m_objectToValueAndChanged.constEnd()) {
1460 QObject *obj = it.key();
1461 QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
1462 QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), obj);
1463 dynamicSheet->removeDynamicProperty(sheet->indexOf(m_propertyName));
1464 if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
1465 if (propertyEditor->object() == obj)
1466 propertyEditor->setObject(obj);
1467 }
1468 ++it;
1469 }
1470 }
1471
undo()1472 void RemoveDynamicPropertyCommand::undo()
1473 {
1474 QDesignerFormEditorInterface *core = formWindow()->core();
1475 QMap<QObject *, QPair<QVariant, bool> >::ConstIterator it = m_objectToValueAndChanged.constBegin();
1476 while (it != m_objectToValueAndChanged.constEnd()) {
1477 QObject *obj = it.key();
1478 QDesignerPropertySheetExtension *propertySheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), obj);
1479 QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
1480 const int index = dynamicSheet->addDynamicProperty(m_propertyName, it.value().first);
1481 propertySheet->setChanged(index, it.value().second);
1482 if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
1483 if (propertyEditor->object() == obj)
1484 propertyEditor->setObject(obj);
1485 }
1486 ++it;
1487 }
1488 }
1489
setDescription()1490 void RemoveDynamicPropertyCommand::setDescription()
1491 {
1492 if (m_objectToValueAndChanged.size() == 1) {
1493 setText(QApplication::translate("Command", "Remove dynamic property '%1' from '%2'").arg(m_propertyName).arg(m_objectToValueAndChanged.constBegin().key()->objectName()));
1494 } else {
1495 int count = m_objectToValueAndChanged.size();
1496 setText(QApplication::translate("Command", "Remove dynamic property '%1' from %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(m_propertyName));
1497 }
1498 }
1499
1500
1501 } // namespace qdesigner_internal
1502
1503 QT_END_NAMESPACE
1504