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