tools/designer/src/lib/shared/qdesigner_propertycommand.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Designer of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    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
       
    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
       
   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 }
       
   122 QSize checkSize(const QSize &size)
       
   123 {
       
   124     return size.boundedTo(QSize(0xFFFFFF, 0xFFFFFF));
       
   125 }
       
   126 
       
   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 
       
   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
       
   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
       
   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
       
   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
       
   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
       
   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>
       
   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
       
   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
       
   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
       
   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 
       
   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 
       
   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
       
   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
       
   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
       
   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
       
   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
       
   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
       
   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>
       
   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
       
   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
       
   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
       
   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
       
   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(qVariantFromValue(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(qVariantFromValue(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(qVariantFromValue(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(qVariantFromValue(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(qVariantFromValue(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(qVariantFromValue(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             qVariantSetValue(v, 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
       
   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 
       
   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 
       
   625 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.
       
   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         qVariantSetValue(value, 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         qVariantSetValue(value, 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         qVariantSetValue(value, r);
       
   674     }
       
   675         break;
       
   676     default:
       
   677         break;
       
   678     }
       
   679 }
       
   680 
       
   681 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 
       
   709 bool PropertyHelper::canMerge(const PropertyHelper &other) const
       
   710 {
       
   711     return m_object == other.m_object &&  m_index == other.m_index;
       
   712 }
       
   713 
       
   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
       
   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 = qVariantValue<PropertySheetStringValue>(oldValue).value();
       
   731             const QString newName = qVariantValue<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 = qVariantValue<PropertySheetStringValue>(oldValue).value();
       
   755             const QString newName = qVariantValue<PropertySheetStringValue>(newValue).value();
       
   756             integr->emitObjectNameChanged(fw, m_object, newName, oldName);
       
   757         }
       
   758         break;
       
   759     default:
       
   760         break;
       
   761     }
       
   762 }
       
   763 
       
   764 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 
       
   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
       
   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 
       
   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
       
   840 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 
       
   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 
       
   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 
       
   910 PropertyListCommand::PropertyDescription::PropertyDescription() :
       
   911     m_propertyType(QVariant::Invalid),
       
   912     m_specialProperty(SP_None)
       
   913 {
       
   914 }
       
   915 
       
   916 void PropertyListCommand::PropertyDescription::debug() const
       
   917 {
       
   918     qDebug() << m_propertyName << m_propertyGroup << m_propertyType << m_specialProperty;
       
   919 }
       
   920 
       
   921 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
       
   929 PropertyListCommand::PropertyListCommand(QDesignerFormWindowInterface *formWindow) :
       
   930     QDesignerFormWindowCommand(QString(), formWindow)
       
   931 {
       
   932 }
       
   933 
       
   934 const QString PropertyListCommand::propertyName() const
       
   935 {
       
   936     return m_propertyDescription.m_propertyName;
       
   937 }
       
   938 
       
   939 SpecialProperty PropertyListCommand::specialProperty() const
       
   940 {
       
   941     return m_propertyDescription.m_specialProperty;
       
   942 }
       
   943 
       
   944 // add an object
       
   945 bool PropertyListCommand::add(QObject *object, const QString &propertyName)
       
   946 {
       
   947     QDesignerPropertySheetExtension* sheet = propertySheet(object);
       
   948     Q_ASSERT(sheet);
       
   949 
       
   950     const int index = sheet->indexOf(propertyName);
       
   951     if (index == -1)
       
   952         return false;
       
   953 
       
   954     if (QDesignerPropertySheet *exSheet = qobject_cast<QDesignerPropertySheet*>(core()->extensionManager()->extension(object, Q_TYPEID(QDesignerPropertySheetExtension))))
       
   955         if (!exSheet->isEnabled(index))
       
   956             return false;
       
   957 
       
   958     const PropertyDescription description(propertyName, sheet, index);
       
   959 
       
   960     if (m_propertyHelperList.empty()) {
       
   961         // first entry
       
   962         m_propertyDescription = description;
       
   963     } else {
       
   964         // checks: mismatch or only one object in case of name
       
   965         const bool match = m_propertyDescription.equals(description);
       
   966         if (!match || m_propertyDescription.m_specialProperty == SP_ObjectName)
       
   967             return false;
       
   968     }
       
   969     m_propertyHelperList.push_back(PropertyHelper(object, m_propertyDescription.m_specialProperty, sheet, index));
       
   970     return true;
       
   971 }
       
   972 
       
   973 
       
   974 // Init from a list and make sure referenceObject is added first to obtain the right property group
       
   975 bool PropertyListCommand::initList(const ObjectList &list, const QString &apropertyName, QObject *referenceObject)
       
   976 {
       
   977     propertyHelperList().clear();
       
   978 
       
   979     // Ensure the referenceObject (property editor) is first, so the right property group is chosen.
       
   980     if (referenceObject) {
       
   981         if (!add(referenceObject, apropertyName))
       
   982             return false;
       
   983     }
       
   984     foreach (QObject *o, list) {
       
   985         if (o != referenceObject)
       
   986             add(o, apropertyName);
       
   987     }
       
   988 
       
   989     return !propertyHelperList().empty();
       
   990 }
       
   991 
       
   992 
       
   993 QObject* PropertyListCommand::object(int index) const
       
   994 {
       
   995     Q_ASSERT(index < m_propertyHelperList.size());
       
   996     return m_propertyHelperList[index].object();
       
   997 }
       
   998 
       
   999 QVariant PropertyListCommand::oldValue(int index) const
       
  1000 {
       
  1001     Q_ASSERT(index < m_propertyHelperList.size());
       
  1002     return m_propertyHelperList[index].oldValue();
       
  1003 }
       
  1004 
       
  1005 void PropertyListCommand::setOldValue(const QVariant &oldValue, int index)
       
  1006 {
       
  1007     Q_ASSERT(index < m_propertyHelperList.size());
       
  1008     m_propertyHelperList[index].setOldValue(oldValue);
       
  1009 }
       
  1010 // ----- SetValueFunction: Set a new value when applied to a PropertyHelper.
       
  1011 class SetValueFunction {
       
  1012 public:
       
  1013     SetValueFunction(QDesignerFormWindowInterface *formWindow, const PropertyHelper::Value &newValue, unsigned subPropertyMask);
       
  1014 
       
  1015     PropertyHelper::Value operator()(PropertyHelper&);
       
  1016 private:
       
  1017     QDesignerFormWindowInterface *m_formWindow;
       
  1018     const PropertyHelper::Value m_newValue;
       
  1019     const unsigned m_subPropertyMask;
       
  1020 };
       
  1021 
       
  1022 
       
  1023 SetValueFunction::SetValueFunction(QDesignerFormWindowInterface *formWindow, const PropertyHelper::Value &newValue, unsigned subPropertyMask) :
       
  1024     m_formWindow(formWindow),
       
  1025     m_newValue(newValue),
       
  1026     m_subPropertyMask(subPropertyMask)
       
  1027 {
       
  1028 }
       
  1029 
       
  1030 PropertyHelper::Value SetValueFunction::operator()(PropertyHelper &ph) {
       
  1031         return ph.setValue(m_formWindow, m_newValue.first, m_newValue.second, m_subPropertyMask);
       
  1032 }
       
  1033 
       
  1034 // ----- UndoSetValueFunction: Restore old value when applied to a PropertyHelper.
       
  1035 class UndoSetValueFunction {
       
  1036 public:
       
  1037     UndoSetValueFunction(QDesignerFormWindowInterface *formWindow) : m_formWindow(formWindow) {}
       
  1038     PropertyHelper::Value operator()(PropertyHelper& ph) { return ph.restoreOldValue(m_formWindow); }
       
  1039 private:
       
  1040     QDesignerFormWindowInterface *m_formWindow;
       
  1041 };
       
  1042 
       
  1043 // ----- RestoreDefaultFunction: Restore default value when applied to a PropertyHelper.
       
  1044 class RestoreDefaultFunction {
       
  1045 public:
       
  1046     RestoreDefaultFunction(QDesignerFormWindowInterface *formWindow) : m_formWindow(formWindow) {}
       
  1047     PropertyHelper::Value operator()(PropertyHelper& ph) { return ph.restoreDefaultValue(m_formWindow); }
       
  1048 private:
       
  1049     QDesignerFormWindowInterface *m_formWindow;
       
  1050 };
       
  1051 
       
  1052 // ----- changePropertyList: Iterates over a sequence of PropertyHelpers and
       
  1053 // applies a function to them.
       
  1054 // The function returns the  corrected value which is then set in  the property editor.
       
  1055 // Returns a combination of update flags.
       
  1056 template <class PropertyListIterator, class Function>
       
  1057         unsigned changePropertyList(QDesignerFormEditorInterface *core,
       
  1058                                     const QString &propertyName,
       
  1059                                     PropertyListIterator begin,
       
  1060                                     PropertyListIterator end,
       
  1061                                     Function function)
       
  1062 {
       
  1063     unsigned updateMask = 0;
       
  1064     QDesignerPropertyEditorInterface *propertyEditor = core->propertyEditor();
       
  1065     bool updatedPropertyEditor = false;
       
  1066 
       
  1067     for (PropertyListIterator it = begin; it != end; ++it) {
       
  1068         if (QObject* object = it->object()) { // Might have been deleted in the meantime
       
  1069             const PropertyHelper::Value newValue = function(*it);
       
  1070             updateMask |= it->updateMask();
       
  1071             // Update property editor if it is the current object
       
  1072             if (!updatedPropertyEditor && propertyEditor && object == propertyEditor->object()) {
       
  1073                 propertyEditor->setPropertyValue(propertyName, newValue.first,  newValue.second);
       
  1074                 updatedPropertyEditor = true;
       
  1075             }
       
  1076         }
       
  1077     }
       
  1078     if (!updatedPropertyEditor) updateMask |=  PropertyHelper::UpdatePropertyEditor;
       
  1079     return updateMask;
       
  1080 }
       
  1081 
       
  1082 
       
  1083 // set a new value, return update mask
       
  1084 unsigned PropertyListCommand::setValue(QVariant value, bool changed, unsigned subPropertyMask)
       
  1085 {
       
  1086     if(debugPropertyCommands)
       
  1087         qDebug() << "PropertyListCommand::setValue(" << value <<  changed << subPropertyMask << ')';
       
  1088     return changePropertyList(formWindow()->core(),
       
  1089                               m_propertyDescription.m_propertyName, m_propertyHelperList.begin(), m_propertyHelperList.end(),
       
  1090                               SetValueFunction(formWindow(), PropertyHelper::Value(value, changed), subPropertyMask));
       
  1091 }
       
  1092 
       
  1093 // restore old value,  return update mask
       
  1094 unsigned PropertyListCommand::restoreOldValue()
       
  1095 {
       
  1096     if(debugPropertyCommands)
       
  1097         qDebug() << "PropertyListCommand::restoreOldValue()";
       
  1098 
       
  1099     return changePropertyList(formWindow()->core(),
       
  1100                               m_propertyDescription.m_propertyName, m_propertyHelperList.begin(), m_propertyHelperList.end(),
       
  1101                               UndoSetValueFunction(formWindow()));
       
  1102 }
       
  1103 // set default value,  return update mask
       
  1104 unsigned PropertyListCommand::restoreDefaultValue()
       
  1105 {
       
  1106     if(debugPropertyCommands)
       
  1107         qDebug() << "PropertyListCommand::restoreDefaultValue()";
       
  1108 
       
  1109     return changePropertyList(formWindow()->core(),
       
  1110                               m_propertyDescription.m_propertyName, m_propertyHelperList.begin(), m_propertyHelperList.end(),
       
  1111                               RestoreDefaultFunction(formWindow()));
       
  1112 }
       
  1113 
       
  1114 // update
       
  1115 void PropertyListCommand::update(unsigned updateMask)
       
  1116 {
       
  1117     if(debugPropertyCommands)
       
  1118         qDebug() << "PropertyListCommand::update(" << updateMask << ')';
       
  1119 
       
  1120     if (updateMask & PropertyHelper::UpdateObjectInspector) {
       
  1121         if (QDesignerObjectInspectorInterface *oi = formWindow()->core()->objectInspector())
       
  1122             oi->setFormWindow(formWindow());
       
  1123     }
       
  1124 
       
  1125     if (updateMask & PropertyHelper::UpdatePropertyEditor) {
       
  1126         // this is needed when f.ex. undo, changes parent's palette, but
       
  1127         // the child is the active widget,
       
  1128         // TODO: current object?
       
  1129         if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
       
  1130             propertyEditor->setObject(propertyEditor->object());
       
  1131         }
       
  1132     }
       
  1133 }
       
  1134 
       
  1135 void PropertyListCommand::undo()
       
  1136 {
       
  1137     update(restoreOldValue());
       
  1138     QDesignerPropertyEditor *designerPropertyEditor = qobject_cast<QDesignerPropertyEditor *>(core()->propertyEditor());
       
  1139     if (designerPropertyEditor)
       
  1140         designerPropertyEditor->updatePropertySheet();
       
  1141 }
       
  1142 
       
  1143 // check if lists are aequivalent for command merging (same widgets and props)
       
  1144 bool PropertyListCommand::canMergeLists(const PropertyHelperList& other) const
       
  1145 {
       
  1146     if (m_propertyHelperList.size() !=  other.size())
       
  1147         return false;
       
  1148     for (int i = 0; i < m_propertyHelperList.size(); i++) {
       
  1149         if (!m_propertyHelperList[i].canMerge(other[i]))
       
  1150             return false;
       
  1151     }
       
  1152     return true;
       
  1153 }
       
  1154 
       
  1155 // ---- SetPropertyCommand ----
       
  1156 SetPropertyCommand::SetPropertyCommand(QDesignerFormWindowInterface *formWindow)
       
  1157     :  PropertyListCommand(formWindow),
       
  1158        m_subPropertyMask(SubPropertyAll)
       
  1159 {
       
  1160 }
       
  1161 
       
  1162 bool SetPropertyCommand::init(QObject *object, const QString &apropertyName, const QVariant &newValue)
       
  1163 {
       
  1164     Q_ASSERT(object);
       
  1165 
       
  1166     m_newValue = newValue;
       
  1167 
       
  1168     propertyHelperList().clear();
       
  1169     if (!add(object, apropertyName))
       
  1170         return false;
       
  1171 
       
  1172     setDescription();
       
  1173     return true;
       
  1174 }
       
  1175 
       
  1176 bool SetPropertyCommand::init(const ObjectList &list, const QString &apropertyName, const QVariant &newValue,
       
  1177                               QObject *referenceObject, bool enableSubPropertyHandling)
       
  1178 {
       
  1179     if (!initList(list, apropertyName, referenceObject))
       
  1180         return false;
       
  1181 
       
  1182     m_newValue = newValue;
       
  1183 
       
  1184     if(debugPropertyCommands)
       
  1185         qDebug() << "SetPropertyCommand::init()" << propertyHelperList().size() << '/' << list.size() << " reference " << referenceObject;
       
  1186 
       
  1187     setDescription();
       
  1188 
       
  1189     if (enableSubPropertyHandling)
       
  1190         m_subPropertyMask = subPropertyMask(newValue, referenceObject);
       
  1191     return true;
       
  1192 }
       
  1193 
       
  1194 unsigned SetPropertyCommand::subPropertyMask(const QVariant &newValue, QObject *referenceObject)
       
  1195 {
       
  1196     // figure out the mask of changed sub properties when comparing newValue to the current value of the reference object.
       
  1197     if (!referenceObject)
       
  1198         return SubPropertyAll;
       
  1199 
       
  1200     QDesignerPropertySheetExtension* sheet = propertySheet(referenceObject);
       
  1201     Q_ASSERT(sheet);
       
  1202 
       
  1203     const int index = sheet->indexOf(propertyName());
       
  1204     if (index == -1 || !sheet->isVisible(index))
       
  1205         return SubPropertyAll;
       
  1206 
       
  1207     return compareSubProperties(sheet->property(index), newValue, specialProperty());
       
  1208 }
       
  1209 
       
  1210 void SetPropertyCommand::setDescription()
       
  1211 {
       
  1212     if (propertyHelperList().size() == 1) {
       
  1213         setText(QApplication::translate("Command", "Changed '%1' of '%2'").arg(propertyName()).arg(propertyHelperList()[0].object()->objectName()));
       
  1214     } else {
       
  1215         int count = propertyHelperList().size();
       
  1216         setText(QApplication::translate("Command", "Changed '%1' of %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(propertyName()));
       
  1217     }
       
  1218 }
       
  1219 
       
  1220 void SetPropertyCommand::redo()
       
  1221 {
       
  1222     update(setValue(m_newValue, true, m_subPropertyMask));
       
  1223     QDesignerPropertyEditor *designerPropertyEditor = qobject_cast<QDesignerPropertyEditor *>(core()->propertyEditor());
       
  1224     if (designerPropertyEditor)
       
  1225         designerPropertyEditor->updatePropertySheet();
       
  1226 }
       
  1227 
       
  1228 
       
  1229 int SetPropertyCommand::id() const
       
  1230 {
       
  1231     return 1976;
       
  1232 }
       
  1233 
       
  1234 bool SetPropertyCommand::mergeWith(const QUndoCommand *other)
       
  1235 {
       
  1236     if (id() != other->id() || !formWindow()->isDirty())
       
  1237         return false;
       
  1238 
       
  1239     // Merging: When  for example when the user types ahead in an inplace-editor,
       
  1240     // it makes sense to merge all the generated commands containing the one-character changes.
       
  1241     // In the case of subproperties, if the user changes the font size from 10 to 30 via 20
       
  1242     // and then changes to bold, it makes sense to merge the font size commands only.
       
  1243     // This is why the m_subPropertyMask is checked.
       
  1244 
       
  1245     const SetPropertyCommand *cmd = static_cast<const SetPropertyCommand*>(other);
       
  1246     if (!propertyDescription().equals(cmd->propertyDescription()) ||
       
  1247         m_subPropertyMask  != cmd->m_subPropertyMask ||
       
  1248         !canMergeLists(cmd->propertyHelperList()))
       
  1249         return false;
       
  1250 
       
  1251     m_newValue = cmd->newValue();
       
  1252     m_subPropertyMask |= cmd->m_subPropertyMask;
       
  1253     if(debugPropertyCommands)
       
  1254         qDebug() << "SetPropertyCommand::mergeWith() succeeded " << propertyName();
       
  1255 
       
  1256     return true;
       
  1257 }
       
  1258 
       
  1259 // ---- ResetPropertyCommand ----
       
  1260 ResetPropertyCommand::ResetPropertyCommand(QDesignerFormWindowInterface *formWindow)
       
  1261     : PropertyListCommand(formWindow)
       
  1262 {
       
  1263 }
       
  1264 
       
  1265 bool ResetPropertyCommand::init(QObject *object, const QString &apropertyName)
       
  1266 {
       
  1267     Q_ASSERT(object);
       
  1268 
       
  1269     propertyHelperList().clear();
       
  1270     if (!add(object, apropertyName))
       
  1271         return false;
       
  1272 
       
  1273     setDescription();
       
  1274     return true;
       
  1275 }
       
  1276 
       
  1277 bool ResetPropertyCommand::init(const ObjectList &list, const QString &apropertyName, QObject *referenceObject)
       
  1278 {
       
  1279     if (!initList(list, apropertyName, referenceObject))
       
  1280         return false;
       
  1281 
       
  1282     if(debugPropertyCommands)
       
  1283         qDebug() << "ResetPropertyCommand::init()" << propertyHelperList().size() << '/' << list.size();
       
  1284 
       
  1285     setDescription();
       
  1286     return true;
       
  1287 }
       
  1288 
       
  1289 void ResetPropertyCommand::setDescription()
       
  1290 {
       
  1291     if (propertyHelperList().size() == 1) {
       
  1292         setText(QApplication::translate("Command", "Reset '%1' of '%2'").arg(propertyName()).arg(propertyHelperList()[0].object()->objectName()));
       
  1293     } else {
       
  1294         int count = propertyHelperList().size();
       
  1295         setText(QApplication::translate("Command", "Reset '%1' of %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(propertyName()));
       
  1296     }
       
  1297 }
       
  1298 
       
  1299 void ResetPropertyCommand::redo()
       
  1300 {
       
  1301     update(restoreDefaultValue());
       
  1302     QDesignerPropertyEditor *designerPropertyEditor = qobject_cast<QDesignerPropertyEditor *>(core()->propertyEditor());
       
  1303     if (designerPropertyEditor)
       
  1304         designerPropertyEditor->updatePropertySheet();
       
  1305 }
       
  1306 
       
  1307 AddDynamicPropertyCommand::AddDynamicPropertyCommand(QDesignerFormWindowInterface *formWindow)
       
  1308     : QDesignerFormWindowCommand(QString(), formWindow)
       
  1309 {
       
  1310 
       
  1311 }
       
  1312 
       
  1313 bool AddDynamicPropertyCommand::init(const QList<QObject *> &selection, QObject *current,
       
  1314             const QString &propertyName, const QVariant &value)
       
  1315 {
       
  1316     Q_ASSERT(current);
       
  1317     m_propertyName = propertyName;
       
  1318 
       
  1319     QDesignerFormEditorInterface *core = formWindow()->core();
       
  1320     QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), current);
       
  1321     Q_ASSERT(dynamicSheet);
       
  1322 
       
  1323     m_selection.clear();
       
  1324 
       
  1325     if (!value.isValid())
       
  1326         return false;
       
  1327 
       
  1328     if (!dynamicSheet->canAddDynamicProperty(m_propertyName))
       
  1329         return false;
       
  1330 
       
  1331     m_selection.append(current);
       
  1332 
       
  1333     m_value = value;
       
  1334 
       
  1335     QListIterator<QObject *> it(selection);
       
  1336     while (it.hasNext()) {
       
  1337         QObject *obj = it.next();
       
  1338         if (m_selection.contains(obj))
       
  1339             continue;
       
  1340         dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
       
  1341         Q_ASSERT(dynamicSheet);
       
  1342         if (dynamicSheet->canAddDynamicProperty(m_propertyName))
       
  1343             m_selection.append(obj);
       
  1344     }
       
  1345 
       
  1346     setDescription();
       
  1347     return true;
       
  1348 }
       
  1349 
       
  1350 void AddDynamicPropertyCommand::redo()
       
  1351 {
       
  1352     QDesignerFormEditorInterface *core = formWindow()->core();
       
  1353     QListIterator<QObject *> it(m_selection);
       
  1354     while (it.hasNext()) {
       
  1355         QObject *obj = it.next();
       
  1356         QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
       
  1357         dynamicSheet->addDynamicProperty(m_propertyName, m_value);
       
  1358         if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
       
  1359             if (propertyEditor->object() == obj)
       
  1360                 propertyEditor->setObject(obj);
       
  1361         }
       
  1362     }
       
  1363 }
       
  1364 
       
  1365 void AddDynamicPropertyCommand::undo()
       
  1366 {
       
  1367     QDesignerFormEditorInterface *core = formWindow()->core();
       
  1368     QListIterator<QObject *> it(m_selection);
       
  1369     while (it.hasNext()) {
       
  1370         QObject *obj = it.next();
       
  1371         QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), obj);
       
  1372         QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
       
  1373         dynamicSheet->removeDynamicProperty(sheet->indexOf(m_propertyName));
       
  1374         if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
       
  1375             if (propertyEditor->object() == obj)
       
  1376                 propertyEditor->setObject(obj);
       
  1377         }
       
  1378     }
       
  1379 }
       
  1380 
       
  1381 void AddDynamicPropertyCommand::setDescription()
       
  1382 {
       
  1383     if (m_selection.size() == 1) {
       
  1384         setText(QApplication::translate("Command", "Add dynamic property '%1' to '%2'").arg(m_propertyName).arg(m_selection.first()->objectName()));
       
  1385     } else {
       
  1386         int count = m_selection.size();
       
  1387         setText(QApplication::translate("Command", "Add dynamic property '%1' to %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(m_propertyName));
       
  1388     }
       
  1389 }
       
  1390 
       
  1391 
       
  1392 RemoveDynamicPropertyCommand::RemoveDynamicPropertyCommand(QDesignerFormWindowInterface *formWindow)
       
  1393     : QDesignerFormWindowCommand(QString(), formWindow)
       
  1394 {
       
  1395 
       
  1396 }
       
  1397 
       
  1398 bool RemoveDynamicPropertyCommand::init(const QList<QObject *> &selection, QObject *current,
       
  1399             const QString &propertyName)
       
  1400 {
       
  1401     Q_ASSERT(current);
       
  1402     m_propertyName = propertyName;
       
  1403 
       
  1404     QDesignerFormEditorInterface *core = formWindow()->core();
       
  1405     QDesignerPropertySheetExtension *propertySheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), current);
       
  1406     Q_ASSERT(propertySheet);
       
  1407     QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), current);
       
  1408     Q_ASSERT(dynamicSheet);
       
  1409 
       
  1410     m_objectToValueAndChanged.clear();
       
  1411 
       
  1412     const int index = propertySheet->indexOf(m_propertyName);
       
  1413     if (!dynamicSheet->isDynamicProperty(index))
       
  1414         return false;
       
  1415 
       
  1416     m_objectToValueAndChanged[current] = qMakePair(propertySheet->property(index), propertySheet->isChanged(index));
       
  1417 
       
  1418     QListIterator<QObject *> it(selection);
       
  1419     while (it.hasNext()) {
       
  1420         QObject *obj = it.next();
       
  1421         if (m_objectToValueAndChanged.contains(obj))
       
  1422             continue;
       
  1423 
       
  1424         propertySheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), obj);
       
  1425         dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
       
  1426         const int idx = propertySheet->indexOf(m_propertyName);
       
  1427         if (dynamicSheet->isDynamicProperty(idx))
       
  1428             m_objectToValueAndChanged[obj] = qMakePair(propertySheet->property(idx), propertySheet->isChanged(idx));
       
  1429     }
       
  1430 
       
  1431     setDescription();
       
  1432     return true;
       
  1433 }
       
  1434 
       
  1435 void RemoveDynamicPropertyCommand::redo()
       
  1436 {
       
  1437     QDesignerFormEditorInterface *core = formWindow()->core();
       
  1438     QMap<QObject *, QPair<QVariant, bool> >::ConstIterator it = m_objectToValueAndChanged.constBegin();
       
  1439     while (it != m_objectToValueAndChanged.constEnd()) {
       
  1440         QObject *obj = it.key();
       
  1441         QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
       
  1442         QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), obj);
       
  1443         dynamicSheet->removeDynamicProperty(sheet->indexOf(m_propertyName));
       
  1444         if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
       
  1445             if (propertyEditor->object() == obj)
       
  1446                 propertyEditor->setObject(obj);
       
  1447         }
       
  1448         ++it;
       
  1449     }
       
  1450 }
       
  1451 
       
  1452 void RemoveDynamicPropertyCommand::undo()
       
  1453 {
       
  1454     QDesignerFormEditorInterface *core = formWindow()->core();
       
  1455     QMap<QObject *, QPair<QVariant, bool> >::ConstIterator it = m_objectToValueAndChanged.constBegin();
       
  1456     while (it != m_objectToValueAndChanged.constEnd()) {
       
  1457         QObject *obj = it.key();
       
  1458         QDesignerPropertySheetExtension *propertySheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), obj);
       
  1459         QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
       
  1460         const int index = dynamicSheet->addDynamicProperty(m_propertyName, it.value().first);
       
  1461         propertySheet->setChanged(index, it.value().second);
       
  1462         if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
       
  1463             if (propertyEditor->object() == obj)
       
  1464                 propertyEditor->setObject(obj);
       
  1465         }
       
  1466         ++it;
       
  1467     }
       
  1468 }
       
  1469 
       
  1470 void RemoveDynamicPropertyCommand::setDescription()
       
  1471 {
       
  1472     if (m_objectToValueAndChanged.size() == 1) {
       
  1473         setText(QApplication::translate("Command", "Remove dynamic property '%1' from '%2'").arg(m_propertyName).arg(m_objectToValueAndChanged.constBegin().key()->objectName()));
       
  1474     } else {
       
  1475         int count = m_objectToValueAndChanged.size();
       
  1476         setText(QApplication::translate("Command", "Remove dynamic property '%1' from %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(m_propertyName));
       
  1477     }
       
  1478 }
       
  1479 
       
  1480 
       
  1481 } // namespace qdesigner_internal
       
  1482 
       
  1483 QT_END_NAMESPACE