summaryrefslogtreecommitdiffstats
path: root/src/H5MF.c
blob: e8665db58fed6e6217cbc930150f50ac1077e091 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
/*-------------------------------------------------------------------------
 * Copyright (C) 1997   National Center for Supercomputing Applications.
 *                      All rights reserved.
 *
 *-------------------------------------------------------------------------
 *
 * Created:             H5MF.c
 *                      Jul 11 1997
 *                      Robb Matzke <matzke@llnl.gov>
 *
 * Purpose:             File memory management functions.
 *
 * Modifications:
 *      Robb Matzke, 5 Aug 1997
 *      Added calls to H5E.
 *
 * 	Robb Matzke, 8 Jun 1998
 *	Implemented a very simple free list which is not persistent and which
 *	is lossy.
 *
 *-------------------------------------------------------------------------
 */
#include <H5private.h>
#include <H5Eprivate.h>
#include <H5Fprivate.h>
#include <H5MFprivate.h>

#define PABLO_MASK      H5MF_mask

/* Is the interface initialized? */
static intn             interface_initialize_g = FALSE;
#define INTERFACE_INIT  NULL


/*-------------------------------------------------------------------------
 * Function:    H5MF_alloc
 *
 * Purpose:     Allocate at least SIZE bytes of file memory and return
 *              the address where that contiguous chunk of file memory
 *              exists. The allocation operation should be either H5MF_META or
 *              H5MF_RAW depending on the purpose for which the storage is
 *              being requested.
 *
 * Return:      Success:        Non-negative.  The file address of new chunk is
 *                              returned through the ADDR argument.
 *
 *              Failure:        Negative
 *
 * Programmer:  Robb Matzke
 *              matzke@llnl.gov
 *              Jul 11 1997
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5MF_alloc(H5F_t *f, intn op, hsize_t size, haddr_t *addr/*out*/)
{
    haddr_t             tmp_addr;
    intn		i, found, status=-1;
    hsize_t		n;
    H5MF_free_t		blk;
    hsize_t		thresh = f->shared->access_parms->threshold;
    hsize_t		align = f->shared->access_parms->alignment;

    FUNC_ENTER(H5MF_alloc, FAIL);

    /* check arguments */
    assert(f);
    assert(H5MF_META == op || H5MF_RAW == op);
    assert(size > 0);
    assert(addr);
    
    /* Fail if we don't have write access */
    if (0==(f->intent & H5F_ACC_RDWR)) {
	HRETURN_ERROR (H5E_RESOURCE, H5E_CANTINIT, FAIL, "file is read-only");
    }

    /*
     * Try to satisfy the request from the free list. We prefer exact matches
     * to partial matches, so if we find an exact match then we break out of
     * the loop immediately, otherwise we keep looking for an exact match.
     */
    for (i=0, found=-1; i<f->shared->fl_nfree; i++) {
	if ((status=H5F_low_alloc(f->shared->lf, op, align, thresh, size,
				  f->shared->fl_free+i, addr/*out*/))>0) {
	    /* Exact match found */
	    found = i;
	    break;
	} else if (0==status) {
	    /* Partial match */
	    found = i;
	}
    }

    if (found>=0 &&
	(status=H5F_low_alloc (f->shared->lf, op, align, thresh, size, 
			       f->shared->fl_free+found, addr/*out*/))>0) {
	/*
	 * We found an exact match.  Remove that block from the free list and
	 * use it to satisfy the request.
	 */
	--(f->shared->fl_nfree);
	HDmemmove (f->shared->fl_free+found, f->shared->fl_free+found+1,
		   (f->shared->fl_nfree-found) * sizeof(H5MF_free_t));
	
    } else if (found>=0 && status==0) {
	/*
	 * We found a free block which is larger than the requested size.
	 * Return the unused parts of the free block to the free list.
	 */
	blk = f->shared->fl_free[found];
	--f->shared->fl_nfree;
	HDmemmove (f->shared->fl_free+found, f->shared->fl_free+found+1,
		   (f->shared->fl_nfree-found) * sizeof(H5MF_free_t));
	if (H5F_addr_gt (addr, &(blk.addr))) {
	    /* Free the first part of the free block */
	    n = addr->offset - blk.addr.offset;
	    H5MF_xfree (f, &(blk.addr), n);
	    blk.addr = *addr;
	    blk.size -= n;
	}
	
	if (blk.size > size) {
	    /* Free the second part of the free block */
	    H5F_addr_inc (&(blk.addr), size);
	    blk.size -= size;
	    H5MF_xfree (f, &(blk.addr), blk.size);
	}
	
    } else {
	/*
	 * No suitable free block was found.  Allocate space from the end of
	 * the file.  We don't know about alignment at this point, so we
	 * allocate enough space to align the data also.
	 */
	if (size>=thresh) {
	    blk.size = size + align - 1;
	} else {
	    blk.size = size;
	}
	if (H5F_low_extend(f->shared->lf, f->shared->access_parms, op,
			   blk.size, &(blk.addr)/*out*/) < 0) {
	    HRETURN_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
			  "low level mem management failed");
	}
	
	/* Convert from absolute to relative */
	blk.addr.offset -= f->shared->base_addr.offset;

	/* Did we extend the size of the hdf5 data? */
	tmp_addr = blk.addr;
	H5F_addr_inc(&tmp_addr, blk.size);
	if (H5F_addr_gt(&tmp_addr, &(f->shared->hdf5_eof))) {
	    f->shared->hdf5_eof = tmp_addr;
	}

	if ((status=H5F_low_alloc (f->shared->lf, op, align, thresh, size,
				   &blk, addr/*out*/))>0) {
	    /* Exact match */
	} else if (0==status) {
	    /* Partial match */
	    if (H5F_addr_gt (addr, &(blk.addr))) {
		n = addr->offset - blk.addr.offset;
		H5MF_xfree (f, &(blk.addr), n);
		blk.addr = *addr;
		blk.size -= n;
	    }
	    if (blk.size > size) {
		H5F_addr_inc (&(blk.addr), size);
		blk.size -= size;
		H5MF_xfree (f, &(blk.addr), blk.size);
	    }
	}
    }
    
    FUNC_LEAVE(SUCCEED);
}

/*-------------------------------------------------------------------------
 * Function:    H5MF_xfree
 *
 * Purpose:     Frees part of a file, making that part of the file
 *              available for reuse.
 *
 * Note:        This version of the function doesn't do anything.
 *
 * Return:      Non-negative on success/Negative on failure
 *
 * Programmer:  Robb Matzke
 *              matzke@llnl.gov
 *              Jul 17 1997
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5MF_xfree(H5F_t *f, const haddr_t *addr, hsize_t size)
{
    int		i;
    
    FUNC_ENTER(H5MF_xfree, FAIL);

    /* check arguments */
    assert(f);
    if (!addr || !H5F_addr_defined(addr) || 0 == size) {
        HRETURN(SUCCEED);
    }
    assert(!H5F_addr_zerop(addr));

    /*
     * Insert this free block into the free list without attempting to
     * combine it with other free blocks.  If the list is overfull then
     * remove the smallest free block.
     */
    if (f->shared->fl_nfree>=H5MF_NFREE) {
	for (i=0; i<H5MF_NFREE; i++) {
	    if (f->shared->fl_free[i].size<size) {
#ifdef H5MF_DEBUG
		if (H5DEBUG(MF)) {
		    fprintf(H5DEBUG(MF),
			    "H5MF_free: lost %lu bytes of file storage\n",
			    (unsigned long) f->shared->fl_free[i].size);
		}
#endif
		f->shared->fl_free[i].addr = *addr;
		f->shared->fl_free[i].size = size;
		break;
	    }
	}
    } else {
	i = f->shared->fl_nfree++;
	f->shared->fl_free[i].addr = *addr;
	f->shared->fl_free[i].size = size;
    }
    FUNC_LEAVE(SUCCEED);
}


/*-------------------------------------------------------------------------
 * Function:	H5MF_realloc
 *
 * Purpose:	Changes the size of an allocated chunk, possibly moving it to
 *		a new address.  The chunk to change is at address ORIG_ADDR
 *		and is exactly ORIG_SIZE bytes (if these are zero and undef
 *		then this function acts like H5MF_alloc).  The new size will
 *		be NEW_SIZE and its address is returned though NEW_ADDR (if
 *		NEW_SIZE is zero then this function acts like H5MF_free and
 *		an undefined address is returned for NEW_ADDR).
 *
 *		If the new size is less than the old size then the new
 *		address will be the same as the old address (except for the
 *		special case where the new size is zero).
 *
 *		If the new size is more than the old size then most likely a
 *		new address will be returned.  However, under certain
 *		circumstances the library may return the same address.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Robb Matzke
 *              Thursday, April 16, 1998
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5MF_realloc (H5F_t *f, intn op, hsize_t orig_size, const haddr_t *orig_addr,
	      hsize_t new_size, haddr_t *new_addr/*out*/)
{
    FUNC_ENTER (H5MF_realloc, FAIL);

    if (0==orig_size) {
	/* Degenerate to H5MF_alloc() */
	assert (!H5F_addr_defined (orig_addr));
	if (new_size>0) {
	    if (H5MF_alloc (f, op, new_size, new_addr/*out*/)<0) {
		HRETURN_ERROR (H5E_RESOURCE, H5E_CANTINIT, FAIL,
			       "unable to allocate new file memory");
	    }
	} else {
	    H5F_addr_undef (new_addr);
	}
	
    } else if (0==new_size) {
	/* Degenerate to H5MF_free() */
	assert (H5F_addr_defined (orig_addr));
	if (H5MF_xfree (f, orig_addr, orig_size)<0) {
	    HRETURN_ERROR (H5E_RESOURCE, H5E_CANTINIT, FAIL,
			   "unable to free old file memory");
	}
	H5F_addr_undef (new_addr);
	
    } else if (new_size > orig_size) {
	/* Size is getting larger */
	if (H5MF_alloc (f, op, new_size, new_addr/*out*/)<0) {
	    HRETURN_ERROR (H5E_RESOURCE, H5E_CANTINIT, FAIL,
			   "unable to allocate new file memory");
	}
	if (H5MF_xfree (f, orig_addr, orig_size)<0) {
	    HRETURN_ERROR (H5E_RESOURCE, H5E_CANTINIT, FAIL,
			   "unable to free old file memory");
	}

    } else {
	/* New size is not larger */
#ifdef H5MF_DEBUG
	if (H5DEBUG(MF) && new_size<orig_size) {
	    HDfprintf (H5DEBUG(MF), "H5MF: realloc lost %Hd bytes\n",
		       orig_size-new_size);
	}
#endif
	*new_addr = *orig_addr;
    }

    FUNC_LEAVE (SUCCEED);
}

	    
	    
'n1382' href='#n1382'>1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the Qt Designer of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qdesigner_propertycommand_p.h"
#include "qdesigner_utils_p.h"
#include "dynamicpropertysheet.h"
#include "qdesigner_propertyeditor_p.h"
#include "qdesigner_integration_p.h"
#include "spacer_widget_p.h"
#include "qdesigner_propertysheet_p.h"

#include <QtDesigner/QDesignerFormEditorInterface>
#include <QtDesigner/QDesignerFormWindowInterface>
#include <QtDesigner/QDesignerFormWindowCursorInterface>
#include <QtDesigner/QDesignerDynamicPropertySheetExtension>
#include <QtDesigner/QDesignerPropertySheetExtension>
#include <QtDesigner/QDesignerPropertyEditorInterface>
#include <QtDesigner/QDesignerObjectInspectorInterface>
#include <QtDesigner/QDesignerIntegrationInterface>
#include <QtDesigner/QDesignerWidgetDataBaseInterface>
#include <QtDesigner/QExtensionManager>

#include <QtCore/QSize>
#include <QtCore/QTextStream>
#include <QtGui/QWidget>
#include <QtGui/QApplication>
#include <QtGui/QAction>
#include <QtGui/QDialog>
#include <QtGui/QPushButton>
#include <QtGui/QLayout>
#include <qdebug.h>

QT_BEGIN_NAMESPACE

namespace  {
enum { debugPropertyCommands = 0 };

// Debug resolve mask of font
QString fontMask(unsigned m)
{
    QString rc;
    if (m & QFont::FamilyResolved)
        rc += QLatin1String("Family");
    if (m & QFont::SizeResolved)
        rc += QLatin1String("Size ");
    if (m & QFont::WeightResolved)
        rc += QLatin1String("Bold ");
    if (m & QFont::StyleResolved)
        rc += QLatin1String("Style ");
    if (m & QFont::UnderlineResolved)
        rc += QLatin1String("Underline ");
    if (m & QFont::StrikeOutResolved)
        rc += QLatin1String("StrikeOut ");
    if (m & QFont::KerningResolved)
        rc += QLatin1String("Kerning ");
    if (m & QFont::StyleStrategyResolved)
        rc += QLatin1String("StyleStrategy");
    return rc;
}

// Debug font
QString fontString(const QFont &f)
{
    QString rc; {
        const QChar comma = QLatin1Char(',');
        QTextStream str(&rc);
        str << QLatin1String("QFont(\"") <<  f.family() << comma <<
            f.pointSize();
        if (f.bold())
            str << comma <<  QLatin1String("bold");
        if (f.italic())
            str << comma <<  QLatin1String("italic");
        if (f.underline())
            str << comma <<  QLatin1String("underline");
        if (f.strikeOut())
            str << comma <<  QLatin1String("strikeOut");
        if (f.kerning())
            str << comma << QLatin1String("kerning");
        str <<  comma << f.styleStrategy() << QLatin1String(" resolve: ")
            << fontMask(f.resolve()) << QLatin1Char(')');
    }
    return rc;
}
QSize checkSize(const QSize &size)
{
    return size.boundedTo(QSize(0xFFFFFF, 0xFFFFFF));
}

QSize diffSize(QDesignerFormWindowInterface *fw)
{
    const QWidget *container = fw->core()->integration()->containerWindow(fw);
    if (!container)
        return QSize();

    const QSize diff = container->size() - fw->size(); // decoration offset of container window
    return diff;
}

void checkSizes(QDesignerFormWindowInterface *fw, const QSize &size, QSize *formSize, QSize *containerSize)
{
    const QWidget *container = fw->core()->integration()->containerWindow(fw);
    if (!container)
        return;

    const  QSize diff = diffSize(fw); // decoration offset of container window

    QSize newFormSize = checkSize(size).expandedTo(fw->mainContainer()->minimumSizeHint()); // don't try to resize to smaller size than minimumSizeHint
    QSize newContainerSize = newFormSize + diff;

    newContainerSize = newContainerSize.expandedTo(container->minimumSizeHint());
    newContainerSize = newContainerSize.expandedTo(container->minimumSize());

    newFormSize = newContainerSize - diff;

    newContainerSize = checkSize(newContainerSize);

    if (formSize)
        *formSize = newFormSize;
    if (containerSize)
        *containerSize = newContainerSize;
}

/* SubProperties: When applying a changed property to a multiselection, it sometimes makes
 * sense to apply only parts (subproperties) of the property.
 * For example, if someone changes the x-value of a geometry in the property editor
 * and applies it to a multi-selection, y should not be applied as this would cause all
 * the widgets to overlap.
 * The following routines can be used to find out the changed subproperties of a property,
 * which are represented as a mask, and to apply them while leaving the others intact. */

enum RectSubPropertyMask {  SubPropertyX=1, SubPropertyY = 2, SubPropertyWidth = 4, SubPropertyHeight = 8 };
enum SizePolicySubPropertyMask { SubPropertyHSizePolicy = 1, SubPropertyHStretch = 2, SubPropertyVSizePolicy = 4, SubPropertyVStretch = 8 };
enum AlignmentSubPropertyMask { SubPropertyHorizontalAlignment = 1, SubPropertyVerticalAlignment = 2 };
enum StringSubPropertyMask { SubPropertyStringValue = 1, SubPropertyStringComment = 2, SubPropertyStringTranslatable = 4, SubPropertyStringDisambiguation = 8 };
enum KeySequenceSubPropertyMask { SubPropertyKeySequenceValue = 1, SubPropertyKeySequenceComment = 2, SubPropertyKeySequenceTranslatable = 4, SubPropertyKeySequenceDisambiguation = 8 };

enum CommonSubPropertyMask { SubPropertyAll = 0xFFFFFFFF };

// Set the mask flag in mask if the properties do not match.
#define COMPARE_SUBPROPERTY(object1, object2, getter, mask, maskFlag) if (object1.getter() != object2.getter()) mask |= maskFlag;

// find changed subproperties of a rectangle
unsigned compareSubProperties(const QRect & r1, const QRect & r2)
{
    unsigned rc = 0;
    COMPARE_SUBPROPERTY(r1, r2, x, rc, SubPropertyX)
    COMPARE_SUBPROPERTY(r1, r2, y, rc, SubPropertyY)
    COMPARE_SUBPROPERTY(r1, r2, width, rc, SubPropertyWidth)
    COMPARE_SUBPROPERTY(r1, r2, height, rc, SubPropertyHeight)
    return rc;
}

// find changed subproperties of a QSize
unsigned compareSubProperties(const QSize & r1, const QSize & r2)
{
    unsigned rc = 0;
    COMPARE_SUBPROPERTY(r1, r2, width,  rc, SubPropertyWidth)
    COMPARE_SUBPROPERTY(r1, r2, height, rc, SubPropertyHeight)
    return rc;
}
// find changed subproperties of a QSizePolicy
unsigned compareSubProperties(const QSizePolicy & sp1, const QSizePolicy & sp2)
{
    unsigned rc = 0;
    COMPARE_SUBPROPERTY(sp1, sp2, horizontalPolicy,  rc, SubPropertyHSizePolicy)
    COMPARE_SUBPROPERTY(sp1, sp2, horizontalStretch, rc, SubPropertyHStretch)
    COMPARE_SUBPROPERTY(sp1, sp2, verticalPolicy,    rc, SubPropertyVSizePolicy)
    COMPARE_SUBPROPERTY(sp1, sp2, verticalStretch,   rc, SubPropertyVStretch)
    return rc;
}
// find changed subproperties of qdesigner_internal::PropertySheetStringValue
unsigned compareSubProperties(const qdesigner_internal::PropertySheetStringValue & str1, const qdesigner_internal::PropertySheetStringValue & str2)
{
    unsigned rc = 0;
    COMPARE_SUBPROPERTY(str1, str2, value,          rc, SubPropertyStringValue)
    COMPARE_SUBPROPERTY(str1, str2, comment,        rc, SubPropertyStringComment)
    COMPARE_SUBPROPERTY(str1, str2, translatable,   rc, SubPropertyStringTranslatable)
    COMPARE_SUBPROPERTY(str1, str2, disambiguation, rc, SubPropertyStringDisambiguation)
    return rc;
}
// find changed subproperties of qdesigner_internal::PropertySheetKeySequenceValue
unsigned compareSubProperties(const qdesigner_internal::PropertySheetKeySequenceValue & str1, const qdesigner_internal::PropertySheetKeySequenceValue & str2)
{
    unsigned rc = 0;
    COMPARE_SUBPROPERTY(str1, str2, value,          rc, SubPropertyKeySequenceValue)
    COMPARE_SUBPROPERTY(str1, str2, comment,        rc, SubPropertyKeySequenceComment)
    COMPARE_SUBPROPERTY(str1, str2, translatable,   rc, SubPropertyKeySequenceTranslatable)
    COMPARE_SUBPROPERTY(str1, str2, disambiguation, rc, SubPropertyKeySequenceDisambiguation)
    return rc;
}

// Compare font-subproperties taking the [undocumented]
// resolve flag into account
template <class Property>
void compareFontSubProperty(const QFont & f1,
                            const QFont & f2,
                            Property (QFont::*getter) () const,
                            unsigned maskBit,
                            unsigned &mask)
{
    const bool f1Changed = f1.resolve() & maskBit;
    const bool f2Changed = f2.resolve() & maskBit;
    // Role has been set/reset in editor
    if (f1Changed != f2Changed) {
        mask |= maskBit;
    } else {
        // Was modified in both palettes: Compare values.
        if (f1Changed && f2Changed && (f1.*getter)() != (f2.*getter)())
            mask |= maskBit;
    }
}
// find changed subproperties of a QFont
unsigned compareSubProperties(const QFont & f1, const QFont & f2)
{
    unsigned rc = 0;
    compareFontSubProperty(f1, f2, &QFont::family,        QFont::FamilyResolved, rc);
    compareFontSubProperty(f1, f2, &QFont::pointSize,     QFont::SizeResolved, rc);
    compareFontSubProperty(f1, f2, &QFont::bold,          QFont::WeightResolved, rc);
    compareFontSubProperty(f1, f2, &QFont::italic,        QFont::StyleResolved, rc);
    compareFontSubProperty(f1, f2, &QFont::underline,     QFont::UnderlineResolved, rc);
    compareFontSubProperty(f1, f2, &QFont::strikeOut,     QFont::StrikeOutResolved, rc);
    compareFontSubProperty(f1, f2, &QFont::kerning,       QFont::KerningResolved, rc);
    compareFontSubProperty(f1, f2, &QFont::styleStrategy, QFont::StyleStrategyResolved, rc);
    if (debugPropertyCommands)
        qDebug() << "compareSubProperties " <<  fontString(f1) << fontString(f2) << "\n\treturns " << fontMask(rc);
    return rc;
}

// Compare colors of a role
bool roleColorChanged(const QPalette & p1, const QPalette & p2, QPalette::ColorRole role)
{
    for (int group = QPalette::Active; group < QPalette::NColorGroups;  group++) {
        const QPalette::ColorGroup pgroup = static_cast<QPalette::ColorGroup>(group);
        if (p1.color(pgroup, role) != p2.color(pgroup, role))
            return true;
    }
    return false;
}
// find changed subproperties of a QPalette taking the [undocumented] resolve flags into account
unsigned compareSubProperties(const QPalette & p1, const QPalette & p2)
{
    unsigned rc = 0;
    unsigned maskBit = 1u;
    // generate a mask for each role
    const unsigned p1Changed = p1.resolve();
    const unsigned p2Changed = p2.resolve();
    for (int role = QPalette::WindowText;  role < QPalette::NColorRoles; role++, maskBit <<= 1u) {
        const bool p1RoleChanged = p1Changed & maskBit;
        const bool p2RoleChanged = p2Changed & maskBit;
        // Role has been set/reset in editor
        if (p1RoleChanged != p2RoleChanged) {
            rc |= maskBit;
        } else {
            // Was modified in both palettes: Compare values.
            if (p1RoleChanged && p2RoleChanged && roleColorChanged(p1, p2, static_cast<QPalette::ColorRole>(role)))
                rc |= maskBit;
        }
    }
    return rc;
}

// find changed subproperties of a QAlignment which is a flag combination of vertical and horizontal

unsigned compareSubProperties(Qt::Alignment a1, Qt::Alignment a2)
{
    unsigned rc = 0;
    if ((a1 & Qt::AlignHorizontal_Mask) != (a2 & Qt::AlignHorizontal_Mask))
        rc |= SubPropertyHorizontalAlignment;
    if ((a1 & Qt::AlignVertical_Mask) != (a2 & Qt::AlignVertical_Mask))
        rc |= SubPropertyVerticalAlignment;
    return rc;
}

Qt::Alignment variantToAlignment(const QVariant & q)
{
    return Qt::Alignment(qdesigner_internal::Utils::valueOf(q));
}
// find changed subproperties of a variant
unsigned compareSubProperties(const QVariant & q1, const QVariant & q2, qdesigner_internal::SpecialProperty specialProperty)
{
    // Do not clobber new value in the comparison function in
    // case someone sets a QString on a PropertySheetStringValue.
    if (q1.type() != q2.type())
        return SubPropertyAll;
    switch (q1.type()) {
    case QVariant::Rect:
        return compareSubProperties(q1.toRect(), q2.toRect());
    case QVariant::Size:
        return compareSubProperties(q1.toSize(), q2.toSize());
    case QVariant::SizePolicy:
        return compareSubProperties(qvariant_cast<QSizePolicy>(q1), qvariant_cast<QSizePolicy>(q2));
    case QVariant::Font:
        return compareSubProperties(qvariant_cast<QFont>(q1), qvariant_cast<QFont>(q2));
    case QVariant::Palette:
        return compareSubProperties(qvariant_cast<QPalette>(q1), qvariant_cast<QPalette>(q2));
    default:
        if (q1.userType() == qMetaTypeId<qdesigner_internal::PropertySheetIconValue>())
            return qvariant_cast<qdesigner_internal::PropertySheetIconValue>(q1).compare(qvariant_cast<qdesigner_internal::PropertySheetIconValue>(q2));
        else if (q1.userType() == qMetaTypeId<qdesigner_internal::PropertySheetStringValue>())
            return compareSubProperties(qvariant_cast<qdesigner_internal::PropertySheetStringValue>(q1), qvariant_cast<qdesigner_internal::PropertySheetStringValue>(q2));
        else if (q1.userType() == qMetaTypeId<qdesigner_internal::PropertySheetKeySequenceValue>())
            return compareSubProperties(qvariant_cast<qdesigner_internal::PropertySheetKeySequenceValue>(q1), qvariant_cast<qdesigner_internal::PropertySheetKeySequenceValue>(q2));
        // Enumerations, flags
        switch (specialProperty) {
        case qdesigner_internal::SP_Alignment:
            return compareSubProperties(variantToAlignment(q1), variantToAlignment(q2));
        default:
        break;
        }
        break;
    }
    return SubPropertyAll;
}

// Apply  the sub property if mask flag is set in mask
#define SET_SUBPROPERTY(rc, newValue, getter, setter, mask, maskFlag) if (mask & maskFlag) rc.setter(newValue.getter());

// apply changed subproperties to a rectangle
QRect applyRectSubProperty(const QRect &oldValue, const QRect &newValue, unsigned mask)
{
    QRect rc = oldValue;
    SET_SUBPROPERTY(rc, newValue, x,      moveLeft,  mask, SubPropertyX)
    SET_SUBPROPERTY(rc, newValue, y,      moveTop,   mask, SubPropertyY)
    SET_SUBPROPERTY(rc, newValue, width,  setWidth,  mask, SubPropertyWidth)
    SET_SUBPROPERTY(rc, newValue, height, setHeight, mask, SubPropertyHeight)
    return rc;
}


// apply changed subproperties to a rectangle QSize
QSize applySizeSubProperty(const QSize &oldValue, const QSize &newValue, unsigned mask)
{
    QSize rc = oldValue;
    SET_SUBPROPERTY(rc, newValue, width,  setWidth,  mask, SubPropertyWidth)
    SET_SUBPROPERTY(rc, newValue, height, setHeight, mask, SubPropertyHeight)
    return rc;
}


// apply changed subproperties to a SizePolicy
QSizePolicy applySizePolicySubProperty(const QSizePolicy &oldValue, const QSizePolicy &newValue, unsigned mask)
{
    QSizePolicy rc = oldValue;
    SET_SUBPROPERTY(rc, newValue, horizontalPolicy,  setHorizontalPolicy,  mask, SubPropertyHSizePolicy)
    SET_SUBPROPERTY(rc, newValue, horizontalStretch, setHorizontalStretch, mask, SubPropertyHStretch)
    SET_SUBPROPERTY(rc, newValue, verticalPolicy,    setVerticalPolicy,    mask, SubPropertyVSizePolicy)
    SET_SUBPROPERTY(rc, newValue, verticalStretch,   setVerticalStretch,   mask, SubPropertyVStretch)
    return rc;
}

// apply changed subproperties to a qdesigner_internal::PropertySheetStringValue
qdesigner_internal::PropertySheetStringValue applyStringSubProperty(const qdesigner_internal::PropertySheetStringValue &oldValue,
            const qdesigner_internal::PropertySheetStringValue &newValue, unsigned mask)
{
    qdesigner_internal::PropertySheetStringValue rc = oldValue;
    SET_SUBPROPERTY(rc, newValue, value, setValue, mask, SubPropertyStringValue)
    SET_SUBPROPERTY(rc, newValue, comment, setComment, mask, SubPropertyStringComment)
    SET_SUBPROPERTY(rc, newValue, translatable, setTranslatable, mask, SubPropertyStringTranslatable)
    SET_SUBPROPERTY(rc, newValue, disambiguation, setDisambiguation, mask, SubPropertyStringDisambiguation)
    return rc;
}

// apply changed subproperties to a qdesigner_internal::PropertySheetKeySequenceValue
qdesigner_internal::PropertySheetKeySequenceValue applyKeySequenceSubProperty(const qdesigner_internal::PropertySheetKeySequenceValue &oldValue,
            const qdesigner_internal::PropertySheetKeySequenceValue &newValue, unsigned mask)
{
    qdesigner_internal::PropertySheetKeySequenceValue rc = oldValue;
    SET_SUBPROPERTY(rc, newValue, value, setValue, mask, SubPropertyKeySequenceValue)
    SET_SUBPROPERTY(rc, newValue, comment, setComment, mask, SubPropertyKeySequenceComment)
    SET_SUBPROPERTY(rc, newValue, translatable, setTranslatable, mask, SubPropertyKeySequenceTranslatable)
    SET_SUBPROPERTY(rc, newValue, disambiguation, setDisambiguation, mask, SubPropertyKeySequenceDisambiguation)
    return rc;
}

// Apply the font-subproperties keeping the [undocumented]
// resolve flag in sync (note that PropertySetterType might be something like const T&).
template <class PropertyReturnType, class PropertySetterType>
inline void setFontSubProperty(unsigned mask,
                               const QFont &newValue,
                               unsigned maskBit,
                               PropertyReturnType (QFont::*getter) () const,
                               void (QFont::*setter) (PropertySetterType),
                               QFont &value)
{
    if (mask & maskBit) {
        (value.*setter)((newValue.*getter)());
        // Set the resolve bit from NewValue in return value
        uint r = value.resolve();
        const bool origFlag = newValue.resolve() & maskBit;
        if (origFlag)
            r |= maskBit;
        else
            r &= ~maskBit;
        value.resolve(r);
        if (debugPropertyCommands)
            qDebug() << "setFontSubProperty " <<  fontMask(maskBit) << " resolve=" << origFlag;
    }
}
// apply changed subproperties to a QFont
QFont applyFontSubProperty(const QFont &oldValue, const QFont &newValue, unsigned mask)
{
    QFont  rc = oldValue;
    setFontSubProperty(mask, newValue, QFont::FamilyResolved,        &QFont::family,        &QFont::setFamily, rc);
    setFontSubProperty(mask, newValue, QFont::SizeResolved,          &QFont::pointSize,     &QFont::setPointSize, rc);
    setFontSubProperty(mask, newValue, QFont::WeightResolved,        &QFont::bold,          &QFont::setBold, rc);
    setFontSubProperty(mask, newValue, QFont::StyleResolved,         &QFont::italic,        &QFont::setItalic, rc);
    setFontSubProperty(mask, newValue, QFont::UnderlineResolved,     &QFont::underline,     &QFont::setUnderline, rc);
    setFontSubProperty(mask, newValue, QFont::StrikeOutResolved,     &QFont::strikeOut,     &QFont::setStrikeOut, rc);
    setFontSubProperty(mask, newValue, QFont::KerningResolved,       &QFont::kerning,       &QFont::setKerning, rc);
    setFontSubProperty(mask, newValue, QFont::StyleStrategyResolved, &QFont::styleStrategy, &QFont::setStyleStrategy, rc);
    if (debugPropertyCommands)
        qDebug() << "applyFontSubProperty old " <<  fontMask(oldValue.resolve()) << " new " << fontMask(newValue.resolve()) << " return: " << fontMask(rc.resolve());
    return rc;
}

// apply changed subproperties to a QPalette
QPalette applyPaletteSubProperty(const QPalette &oldValue, const QPalette &newValue, unsigned mask)
{
    QPalette rc = oldValue;
    // apply a mask for each role
    unsigned maskBit = 1u;
    for (int role = QPalette::WindowText;  role < QPalette::NColorRoles; role++, maskBit <<= 1u) {
        if (mask & maskBit) {
            for (int group = QPalette::Active; group < QPalette::NColorGroups;  group++) {
                const QPalette::ColorGroup pgroup = static_cast<QPalette::ColorGroup>(group);
                const QPalette::ColorRole prole =  static_cast<QPalette::ColorRole>(role);
                rc.setColor(pgroup, prole, newValue.color(pgroup, prole));
            }
            // Set the resolve bit from NewValue in return value
            uint r = rc.resolve();
            const bool origFlag = newValue.resolve() & maskBit;
            if (origFlag)
                r |= maskBit;
            else
                r &= ~maskBit;
            rc.resolve(r);
        }
    }
    return rc;
}

// apply changed subproperties to  a QAlignment which is a flag combination of vertical and horizontal
Qt::Alignment applyAlignmentSubProperty(Qt::Alignment oldValue, Qt::Alignment newValue, unsigned mask)
{
    // easy: both changed.
    if (mask == (SubPropertyHorizontalAlignment|SubPropertyVerticalAlignment))
        return newValue;
    // Change subprop
    const Qt::Alignment changeMask   = (mask & SubPropertyHorizontalAlignment) ? Qt::AlignHorizontal_Mask : Qt::AlignVertical_Mask;
    const Qt::Alignment takeOverMask = (mask & SubPropertyHorizontalAlignment) ? Qt::AlignVertical_Mask   : Qt::AlignHorizontal_Mask;
    return (oldValue & takeOverMask) | (newValue & changeMask);
}

}

namespace qdesigner_internal {

// apply changed subproperties to a variant
PropertyHelper::Value applySubProperty(const QVariant &oldValue, const QVariant &newValue, qdesigner_internal::SpecialProperty specialProperty, unsigned mask, bool changed)
{
    if (mask == SubPropertyAll)
        return PropertyHelper::Value(newValue, changed);

    switch (oldValue.type()) {
    case QVariant::Rect:
        return PropertyHelper::Value(applyRectSubProperty(oldValue.toRect(), newValue.toRect(), mask), changed);
    case QVariant::Size:
        return PropertyHelper::Value(applySizeSubProperty(oldValue.toSize(), newValue.toSize(), mask), changed);
    case QVariant::SizePolicy:
        return PropertyHelper::Value(qVariantFromValue(applySizePolicySubProperty(qvariant_cast<QSizePolicy>(oldValue), qvariant_cast<QSizePolicy>(newValue), mask)), changed);
    case QVariant::Font: {
        // Changed flag in case of font and palette depends on resolve mask only, not on the passed "changed" value.

        // The first case: the user changed bold subproperty and then pressed reset button for this subproperty (not for
        // the whole font property). We instantiate SetPropertyCommand passing changed=true. But in this case no
        // subproperty is changed and the whole property should be marked an unchanged.

        // The second case: there are 2 pushbuttons, for 1st the user set bold and italic subproperties,
        // for the 2nd he set bold only. He does multiselection so that the current widget is the 2nd one.
        // He press reset next to bold subproperty. In result the 2nd widget should have the whole
        // font property marked as unchanged and the 1st widget should have the font property
        // marked as changed and only italic subproperty should be marked as changed (the bold should be reset).

        // The third case: there are 2 pushbuttons, for 1st the user set bold and italic subproperties,
        // for the 2nd he set bold only. He does multiselection so that the current widget is the 2nd one.
        // He press reset button for the whole font property. In result whole font properties for both
        // widgets should be marked as unchanged.
        QFont font = applyFontSubProperty(qvariant_cast<QFont>(oldValue), qvariant_cast<QFont>(newValue), mask);
        return PropertyHelper::Value(qVariantFromValue(font), font.resolve());
        }
    case QVariant::Palette: {
        QPalette palette = applyPaletteSubProperty(qvariant_cast<QPalette>(oldValue), qvariant_cast<QPalette>(newValue), mask);
        return PropertyHelper::Value(qVariantFromValue(palette), palette.resolve());
        }
    default:
        if (oldValue.userType() == qMetaTypeId<qdesigner_internal::PropertySheetIconValue>()) {
            PropertySheetIconValue icon = qvariant_cast<qdesigner_internal::PropertySheetIconValue>(oldValue);
            icon.assign(qvariant_cast<qdesigner_internal::PropertySheetIconValue>(newValue), mask);
            return PropertyHelper::Value(qVariantFromValue(icon), icon.mask());
        } else if (oldValue.userType() == qMetaTypeId<qdesigner_internal::PropertySheetStringValue>()) {
            qdesigner_internal::PropertySheetStringValue str = applyStringSubProperty(
                        qvariant_cast<qdesigner_internal::PropertySheetStringValue>(oldValue),
                        qvariant_cast<qdesigner_internal::PropertySheetStringValue>(newValue), mask);
            return PropertyHelper::Value(qVariantFromValue(str), changed);
        } else if (oldValue.userType() == qMetaTypeId<qdesigner_internal::PropertySheetKeySequenceValue>()) {
            qdesigner_internal::PropertySheetKeySequenceValue key = applyKeySequenceSubProperty(
                        qvariant_cast<qdesigner_internal::PropertySheetKeySequenceValue>(oldValue),
                        qvariant_cast<qdesigner_internal::PropertySheetKeySequenceValue>(newValue), mask);
            return PropertyHelper::Value(qVariantFromValue(key), changed);
        }
        // Enumerations, flags
        switch (specialProperty) {
        case qdesigner_internal::SP_Alignment: {
            qdesigner_internal::PropertySheetFlagValue f = qvariant_cast<qdesigner_internal::PropertySheetFlagValue>(oldValue);
            f.value = applyAlignmentSubProperty(variantToAlignment(oldValue), variantToAlignment(newValue), mask);
            QVariant v;
            qVariantSetValue(v, f);
            return PropertyHelper::Value(v, changed);
                                               }
        default:
        break;
        }
        break;
    }
    return PropertyHelper::Value(newValue, changed);

}
// figure out special property
enum SpecialProperty getSpecialProperty(const QString& propertyName)
{
    if (propertyName == QLatin1String("objectName"))
        return SP_ObjectName;
    if (propertyName == QLatin1String("layoutName"))
        return SP_LayoutName;
    if (propertyName == QLatin1String("spacerName"))
        return SP_SpacerName;
    if (propertyName == QLatin1String("icon"))
        return SP_Icon;
    if (propertyName == QLatin1String("currentTabName"))
        return SP_CurrentTabName;
    if (propertyName == QLatin1String("currentItemName"))
        return SP_CurrentItemName;
    if (propertyName == QLatin1String("currentPageName"))
        return SP_CurrentPageName;
    if (propertyName == QLatin1String("geometry"))
        return SP_Geometry;
    if (propertyName == QLatin1String("windowTitle"))
        return SP_WindowTitle;
    if (propertyName == QLatin1String("minimumSize"))
        return SP_MinimumSize;
    if (propertyName == QLatin1String("maximumSize"))
        return SP_MaximumSize;
    if (propertyName == QLatin1String("alignment"))
        return SP_Alignment;
    if (propertyName == QLatin1String("autoDefault"))
        return SP_AutoDefault;
    if (propertyName == QLatin1String("shortcut"))
        return SP_Shortcut;
    if (propertyName == QLatin1String("orientation"))
        return SP_Orientation;
    return SP_None;
}


PropertyHelper::PropertyHelper(QObject* object,
                               SpecialProperty specialProperty,
                               QDesignerPropertySheetExtension *sheet,
                               int index) :
    m_specialProperty(specialProperty),
    m_object(object),
    m_objectType(OT_Object),
    m_propertySheet(sheet),  m_index(index),
    m_oldValue(m_propertySheet->property(m_index), m_propertySheet->isChanged(m_index))
{
    if (object->isWidgetType()) {
        m_parentWidget = (qobject_cast<QWidget*>(object))->parentWidget();
        m_objectType = OT_Widget;
    } else {
        if (const QAction *action = qobject_cast<const QAction *>(m_object))
            m_objectType = action->associatedWidgets().empty() ? OT_FreeAction : OT_AssociatedAction;
    }

    if(debugPropertyCommands)
        qDebug() << "PropertyHelper on " << m_object->objectName() << " index= " << m_index << " type = " << m_objectType;
}

QDesignerIntegration *PropertyHelper::integration(QDesignerFormWindowInterface *fw) const
{
    return qobject_cast<QDesignerIntegration *>(fw->core()->integration());
}

// Set widget value, apply corrections and checks in case of main window.
void PropertyHelper::checkApplyWidgetValue(QDesignerFormWindowInterface *fw, QWidget* w,
                                      SpecialProperty specialProperty, QVariant &value)
{

    bool isMainContainer = false;
    if (QDesignerFormWindowCursorInterface *cursor = fw->cursor()) {
        if (cursor->isWidgetSelected(w)) {
            if (cursor->isWidgetSelected(fw->mainContainer())) {
                isMainContainer = true;
            }
        }
    }
    if (!isMainContainer)
        return;

    QWidget *container = fw->core()->integration()->containerWindow(fw);
    if (!container)
        return;


    switch (specialProperty) {
    case SP_MinimumSize: {
        const QSize size = checkSize(value.toSize());
        qVariantSetValue(value, size);
    }

        break;
    case SP_MaximumSize: {
        QSize fs, cs;
        checkSizes(fw, value.toSize(), &fs, &cs);
        container->setMaximumSize(cs);
        fw->mainContainer()->setMaximumSize(fs);
        qVariantSetValue(value, fs);

    }
        break;
    case SP_Geometry: {
        QRect r = value.toRect();
        QSize fs, cs;
        checkSizes(fw, r.size(), &fs, &cs);
        container->resize(cs);
        r.setSize(fs);
        qVariantSetValue(value, r);
    }
        break;
    default:
        break;
    }
}

unsigned PropertyHelper::updateMask() const
{
    unsigned rc = 0;
    switch (m_specialProperty) {
    case SP_ObjectName:
    case SP_LayoutName:
    case SP_SpacerName:
    case SP_CurrentTabName:
    case SP_CurrentItemName:
    case SP_CurrentPageName:
        if (m_objectType != OT_FreeAction)
            rc |= UpdateObjectInspector;
        break;
    case SP_Icon:
        if (m_objectType == OT_AssociatedAction)
            rc |= UpdateObjectInspector;
        break;
    case SP_Orientation: // for updating splitter icon
        rc |= UpdateObjectInspector;
        break;
    default:
        break;

    }
    return rc;
}


bool PropertyHelper::canMerge(const PropertyHelper &other) const
{
    return m_object == other.m_object &&  m_index == other.m_index;
}

void PropertyHelper::triggerActionChanged(QAction *a)
{
    a->setData(QVariant(true)); // this triggers signal "changed" in QAction
    a->setData(QVariant(false));
}

// Update the object to reflect the changes
void PropertyHelper::updateObject(QDesignerFormWindowInterface *fw, const QVariant &oldValue, const QVariant &newValue)
{
    if(debugPropertyCommands){
         qDebug() << "PropertyHelper::updateObject(" << m_object->objectName() << ") " << oldValue << " -> " << newValue;
    }
    switch (m_objectType) {
    case OT_Widget: {
        switch (m_specialProperty) {
        case SP_ObjectName: {
            const QString oldName = qVariantValue<PropertySheetStringValue>(oldValue).value();
            const QString newName = qVariantValue<PropertySheetStringValue>(newValue).value();
            QDesignerFormWindowCommand::updateBuddies(fw, oldName, newName);
        }
            break;
        default:
            break;
        }
    } break;
    case OT_AssociatedAction:
    case OT_FreeAction:
        // SP_Shortcut is a fake property, so, QAction::changed does not trigger.
        if (m_specialProperty == SP_ObjectName || m_specialProperty == SP_Shortcut)
            triggerActionChanged(qobject_cast<QAction *>(m_object));
        break;
    default:
        break;
    }

    switch (m_specialProperty) {
    case SP_ObjectName:
    case SP_LayoutName:
    case SP_SpacerName:
        if (QDesignerIntegration *integr = integration(fw)) {
            const QString oldName = qVariantValue<PropertySheetStringValue>(oldValue).value();
            const QString newName = qVariantValue<PropertySheetStringValue>(newValue).value();
            integr->emitObjectNameChanged(fw, m_object, newName, oldName);
        }
        break;
    default:
        break;
    }
}

void PropertyHelper::ensureUniqueObjectName(QDesignerFormWindowInterface *fw, QObject *object) const
{
    switch (m_specialProperty) {
    case SP_SpacerName:
        if (object->isWidgetType()) {
            if (Spacer *sp = qobject_cast<Spacer *>(object)) {
                fw->ensureUniqueObjectName(sp);
                return;
            }
        }
        fw->ensureUniqueObjectName(object);
        break;
    case SP_LayoutName: // Layout name is invoked on the parent widget.
        if (object->isWidgetType()) {
            const QWidget * w = qobject_cast<const QWidget *>(object);
            if (QLayout *wlayout = w->layout()) {
                fw->ensureUniqueObjectName(wlayout);
                return;
            }
        }
        fw->ensureUniqueObjectName(object);
        break;
    case SP_ObjectName:
        fw->ensureUniqueObjectName(object);
        break;
    default:
        break;
    }
}

PropertyHelper::Value PropertyHelper::setValue(QDesignerFormWindowInterface *fw, const QVariant &value, bool changed, unsigned subPropertyMask)
{
    // Set new whole value
    if (subPropertyMask == SubPropertyAll)
        return  applyValue(fw, m_oldValue.first, Value(value, changed));

    // apply subproperties
    const PropertyHelper::Value maskedNewValue = applySubProperty(m_oldValue.first, value, m_specialProperty, subPropertyMask, changed);
    return applyValue(fw, m_oldValue.first, maskedNewValue);
}

// Apply the value and update. Returns corrected value
PropertyHelper::Value PropertyHelper::applyValue(QDesignerFormWindowInterface *fw, const QVariant &oldValue, Value newValue)
{
     if(debugPropertyCommands){
         qDebug() << "PropertyHelper::applyValue(" << m_object << ") " << oldValue << " -> " << newValue.first << " changed=" << newValue.second;
     }

    if (m_objectType ==  OT_Widget) {
        checkApplyWidgetValue(fw, qobject_cast<QWidget *>(m_object), m_specialProperty, newValue.first);
    }

    m_propertySheet->setProperty(m_index, newValue.first);
    m_propertySheet->setChanged(m_index, newValue.second);

    switch (m_specialProperty) {
    case SP_LayoutName:
    case SP_ObjectName:
    case SP_SpacerName:
        ensureUniqueObjectName(fw, m_object);
        newValue.first = m_propertySheet->property(m_index);
        break;
    default:
        break;
    }

    updateObject(fw, oldValue, newValue.first);
    return newValue;
}

PropertyHelper::Value PropertyHelper::restoreOldValue(QDesignerFormWindowInterface *fw)
{
    return applyValue(fw, m_propertySheet->property(m_index), m_oldValue);
}

// find the default value in widget DB in case PropertySheet::reset fails
QVariant PropertyHelper::findDefaultValue(QDesignerFormWindowInterface *fw) const
{
    if (m_specialProperty == SP_AutoDefault && qobject_cast<const QPushButton*>(m_object)) {
        // AutoDefault defaults to true on dialogs
        const bool isDialog = qobject_cast<const QDialog *>(fw->mainContainer());
        return QVariant(isDialog);
    }

    const int item_idx = fw->core()->widgetDataBase()->indexOfObject(m_object);
    if (item_idx == -1)
        return  m_oldValue.first; // We simply don't know the value in this case

    const QDesignerWidgetDataBaseItemInterface *item = fw->core()->widgetDataBase()->item(item_idx);
    const QList<QVariant> default_prop_values = item->defaultPropertyValues();
    if (m_index < default_prop_values.size())
        return default_prop_values.at(m_index);

    if (m_oldValue.first.type() == QVariant::Color)
        return QColor();

    return m_oldValue.first; // Again, we just don't know
}

PropertyHelper::Value PropertyHelper::restoreDefaultValue(QDesignerFormWindowInterface *fw)
{

    Value defaultValue = qMakePair(QVariant(), false);
    const QVariant currentValue = m_propertySheet->property(m_index);
    // try to reset sheet, else try to find default
    if (m_propertySheet->reset(m_index)) {
        defaultValue.first = m_propertySheet->property(m_index);
    } else {
        defaultValue.first = findDefaultValue(fw);
        m_propertySheet->setProperty(m_index, defaultValue.first);
    }

    m_propertySheet->setChanged(m_index, defaultValue.second);

    if (m_objectType == OT_Widget) {
        checkApplyWidgetValue(fw, qobject_cast<QWidget *>(m_object), m_specialProperty, defaultValue.first);
    }

    switch (m_specialProperty) {
    case SP_LayoutName:
    case SP_ObjectName:
    case SP_SpacerName:
        ensureUniqueObjectName(fw, m_object);
        defaultValue.first = m_propertySheet->property(m_index);
        break;
    default:
        break;
    }

    updateObject(fw, currentValue, defaultValue.first);
    return defaultValue;
}

// ---- PropertyListCommand::PropertyDescription(


PropertyListCommand::PropertyDescription::PropertyDescription(const QString &propertyName,
                                                              QDesignerPropertySheetExtension *propertySheet,
                                                              int index) :
    m_propertyName(propertyName),
    m_propertyGroup(propertySheet->propertyGroup(index)),
    m_propertyType(propertySheet->property(index).type()),
    m_specialProperty(getSpecialProperty(propertyName))
{
}

PropertyListCommand::PropertyDescription::PropertyDescription() :
    m_propertyType(QVariant::Invalid),
    m_specialProperty(SP_None)
{
}

void PropertyListCommand::PropertyDescription::debug() const
{
    qDebug() << m_propertyName << m_propertyGroup << m_propertyType << m_specialProperty;
}

bool PropertyListCommand::PropertyDescription::equals(const PropertyDescription &p) const
{
    return m_propertyType == p.m_propertyType && m_specialProperty == p.m_specialProperty &&
           m_propertyName == p.m_propertyName && m_propertyGroup   == p.m_propertyGroup;
}


// ---- PropertyListCommand
PropertyListCommand::PropertyListCommand(QDesignerFormWindowInterface *formWindow) :
    QDesignerFormWindowCommand(QString(), formWindow)
{
}

const QString PropertyListCommand::propertyName() const
{
    return m_propertyDescription.m_propertyName;
}

SpecialProperty PropertyListCommand::specialProperty() const
{
    return m_propertyDescription.m_specialProperty;
}

// add an object
bool PropertyListCommand::add(QObject *object, const QString &propertyName)
{
    QDesignerPropertySheetExtension* sheet = propertySheet(object);
    Q_ASSERT(sheet);

    const int index = sheet->indexOf(propertyName);
    if (index == -1)
        return false;

    if (QDesignerPropertySheet *exSheet = qobject_cast<QDesignerPropertySheet*>(core()->extensionManager()->extension(object, Q_TYPEID(QDesignerPropertySheetExtension))))
        if (!exSheet->isEnabled(index))
            return false;

    const PropertyDescription description(propertyName, sheet, index);

    if (m_propertyHelperList.empty()) {
        // first entry
        m_propertyDescription = description;
    } else {
        // checks: mismatch or only one object in case of name
        const bool match = m_propertyDescription.equals(description);
        if (!match || m_propertyDescription.m_specialProperty == SP_ObjectName)
            return false;
    }
    m_propertyHelperList.push_back(PropertyHelper(object, m_propertyDescription.m_specialProperty, sheet, index));
    return true;
}


// Init from a list and make sure referenceObject is added first to obtain the right property group
bool PropertyListCommand::initList(const ObjectList &list, const QString &apropertyName, QObject *referenceObject)
{
    propertyHelperList().clear();

    // Ensure the referenceObject (property editor) is first, so the right property group is chosen.
    if (referenceObject) {
        if (!add(referenceObject, apropertyName))
            return false;
    }
    foreach (QObject *o, list) {
        if (o != referenceObject)
            add(o, apropertyName);
    }

    return !propertyHelperList().empty();
}


QObject* PropertyListCommand::object(int index) const
{
    Q_ASSERT(index < m_propertyHelperList.size());
    return m_propertyHelperList[index].object();
}

QVariant PropertyListCommand::oldValue(int index) const
{
    Q_ASSERT(index < m_propertyHelperList.size());
    return m_propertyHelperList[index].oldValue();
}

void PropertyListCommand::setOldValue(const QVariant &oldValue, int index)
{
    Q_ASSERT(index < m_propertyHelperList.size());
    m_propertyHelperList[index].setOldValue(oldValue);
}
// ----- SetValueFunction: Set a new value when applied to a PropertyHelper.
class SetValueFunction {
public:
    SetValueFunction(QDesignerFormWindowInterface *formWindow, const PropertyHelper::Value &newValue, unsigned subPropertyMask);

    PropertyHelper::Value operator()(PropertyHelper&);
private:
    QDesignerFormWindowInterface *m_formWindow;
    const PropertyHelper::Value m_newValue;
    const unsigned m_subPropertyMask;
};


SetValueFunction::SetValueFunction(QDesignerFormWindowInterface *formWindow, const PropertyHelper::Value &newValue, unsigned subPropertyMask) :
    m_formWindow(formWindow),
    m_newValue(newValue),
    m_subPropertyMask(subPropertyMask)
{
}

PropertyHelper::Value SetValueFunction::operator()(PropertyHelper &ph) {
        return ph.setValue(m_formWindow, m_newValue.first, m_newValue.second, m_subPropertyMask);
}

// ----- UndoSetValueFunction: Restore old value when applied to a PropertyHelper.
class UndoSetValueFunction {
public:
    UndoSetValueFunction(QDesignerFormWindowInterface *formWindow) : m_formWindow(formWindow) {}
    PropertyHelper::Value operator()(PropertyHelper& ph) { return ph.restoreOldValue(m_formWindow); }
private:
    QDesignerFormWindowInterface *m_formWindow;
};

// ----- RestoreDefaultFunction: Restore default value when applied to a PropertyHelper.
class RestoreDefaultFunction {
public:
    RestoreDefaultFunction(QDesignerFormWindowInterface *formWindow) : m_formWindow(formWindow) {}
    PropertyHelper::Value operator()(PropertyHelper& ph) { return ph.restoreDefaultValue(m_formWindow); }
private:
    QDesignerFormWindowInterface *m_formWindow;
};

// ----- changePropertyList: Iterates over a sequence of PropertyHelpers and
// applies a function to them.
// The function returns the  corrected value which is then set in  the property editor.
// Returns a combination of update flags.
template <class PropertyListIterator, class Function>
        unsigned changePropertyList(QDesignerFormEditorInterface *core,
                                    const QString &propertyName,
                                    PropertyListIterator begin,
                                    PropertyListIterator end,
                                    Function function)
{
    unsigned updateMask = 0;
    QDesignerPropertyEditorInterface *propertyEditor = core->propertyEditor();
    bool updatedPropertyEditor = false;

    for (PropertyListIterator it = begin; it != end; ++it) {
        if (QObject* object = it->object()) { // Might have been deleted in the meantime
            const PropertyHelper::Value newValue = function(*it);
            updateMask |= it->updateMask();
            // Update property editor if it is the current object
            if (!updatedPropertyEditor && propertyEditor && object == propertyEditor->object()) {
                propertyEditor->setPropertyValue(propertyName, newValue.first,  newValue.second);
                updatedPropertyEditor = true;
            }
        }
    }
    if (!updatedPropertyEditor) updateMask |=  PropertyHelper::UpdatePropertyEditor;
    return updateMask;
}


// set a new value, return update mask
unsigned PropertyListCommand::setValue(QVariant value, bool changed, unsigned subPropertyMask)
{
    if(debugPropertyCommands)
        qDebug() << "PropertyListCommand::setValue(" << value <<  changed << subPropertyMask << ')';
    return changePropertyList(formWindow()->core(),
                              m_propertyDescription.m_propertyName, m_propertyHelperList.begin(), m_propertyHelperList.end(),
                              SetValueFunction(formWindow(), PropertyHelper::Value(value, changed), subPropertyMask));
}

// restore old value,  return update mask
unsigned PropertyListCommand::restoreOldValue()
{
    if(debugPropertyCommands)
        qDebug() << "PropertyListCommand::restoreOldValue()";

    return changePropertyList(formWindow()->core(),
                              m_propertyDescription.m_propertyName, m_propertyHelperList.begin(), m_propertyHelperList.end(),
                              UndoSetValueFunction(formWindow()));
}
// set default value,  return update mask
unsigned PropertyListCommand::restoreDefaultValue()
{
    if(debugPropertyCommands)
        qDebug() << "PropertyListCommand::restoreDefaultValue()";

    return changePropertyList(formWindow()->core(),
                              m_propertyDescription.m_propertyName, m_propertyHelperList.begin(), m_propertyHelperList.end(),
                              RestoreDefaultFunction(formWindow()));
}

// update
void PropertyListCommand::update(unsigned updateMask)
{
    if(debugPropertyCommands)
        qDebug() << "PropertyListCommand::update(" << updateMask << ')';

    if (updateMask & PropertyHelper::UpdateObjectInspector) {
        if (QDesignerObjectInspectorInterface *oi = formWindow()->core()->objectInspector())
            oi->setFormWindow(formWindow());
    }

    if (updateMask & PropertyHelper::UpdatePropertyEditor) {
        // this is needed when f.ex. undo, changes parent's palette, but
        // the child is the active widget,
        // TODO: current object?
        if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
            propertyEditor->setObject(propertyEditor->object());
        }
    }
}

void PropertyListCommand::undo()
{
    update(restoreOldValue());
    QDesignerPropertyEditor *designerPropertyEditor = qobject_cast<QDesignerPropertyEditor *>(core()->propertyEditor());
    if (designerPropertyEditor)
        designerPropertyEditor->updatePropertySheet();
}

// check if lists are aequivalent for command merging (same widgets and props)
bool PropertyListCommand::canMergeLists(const PropertyHelperList& other) const
{
    if (m_propertyHelperList.size() !=  other.size())
        return false;
    for (int i = 0; i < m_propertyHelperList.size(); i++) {
        if (!m_propertyHelperList[i].canMerge(other[i]))
            return false;
    }
    return true;
}

// ---- SetPropertyCommand ----
SetPropertyCommand::SetPropertyCommand(QDesignerFormWindowInterface *formWindow)
    :  PropertyListCommand(formWindow),
       m_subPropertyMask(SubPropertyAll)
{
}

bool SetPropertyCommand::init(QObject *object, const QString &apropertyName, const QVariant &newValue)
{
    Q_ASSERT(object);

    m_newValue = newValue;

    propertyHelperList().clear();
    if (!add(object, apropertyName))
        return false;

    setDescription();
    return true;
}

bool SetPropertyCommand::init(const ObjectList &list, const QString &apropertyName, const QVariant &newValue,
                              QObject *referenceObject, bool enableSubPropertyHandling)
{
    if (!initList(list, apropertyName, referenceObject))
        return false;

    m_newValue = newValue;

    if(debugPropertyCommands)
        qDebug() << "SetPropertyCommand::init()" << propertyHelperList().size() << '/' << list.size() << " reference " << referenceObject;

    setDescription();

    if (enableSubPropertyHandling)
        m_subPropertyMask = subPropertyMask(newValue, referenceObject);
    return true;
}

unsigned SetPropertyCommand::subPropertyMask(const QVariant &newValue, QObject *referenceObject)
{
    // figure out the mask of changed sub properties when comparing newValue to the current value of the reference object.
    if (!referenceObject)
        return SubPropertyAll;

    QDesignerPropertySheetExtension* sheet = propertySheet(referenceObject);
    Q_ASSERT(sheet);

    const int index = sheet->indexOf(propertyName());
    if (index == -1 || !sheet->isVisible(index))
        return SubPropertyAll;

    return compareSubProperties(sheet->property(index), newValue, specialProperty());
}

void SetPropertyCommand::setDescription()
{
    if (propertyHelperList().size() == 1) {
        setText(QApplication::translate("Command", "Changed '%1' of '%2'").arg(propertyName()).arg(propertyHelperList()[0].object()->objectName()));
    } else {
        int count = propertyHelperList().size();
        setText(QApplication::translate("Command", "Changed '%1' of %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(propertyName()));
    }
}

void SetPropertyCommand::redo()
{
    update(setValue(m_newValue, true, m_subPropertyMask));
    QDesignerPropertyEditor *designerPropertyEditor = qobject_cast<QDesignerPropertyEditor *>(core()->propertyEditor());
    if (designerPropertyEditor)
        designerPropertyEditor->updatePropertySheet();
}


int SetPropertyCommand::id() const
{
    return 1976;
}

bool SetPropertyCommand::mergeWith(const QUndoCommand *other)
{
    if (id() != other->id() || !formWindow()->isDirty())
        return false;

    // Merging: When  for example when the user types ahead in an inplace-editor,
    // it makes sense to merge all the generated commands containing the one-character changes.
    // In the case of subproperties, if the user changes the font size from 10 to 30 via 20
    // and then changes to bold, it makes sense to merge the font size commands only.
    // This is why the m_subPropertyMask is checked.

    const SetPropertyCommand *cmd = static_cast<const SetPropertyCommand*>(other);
    if (!propertyDescription().equals(cmd->propertyDescription()) ||
        m_subPropertyMask  != cmd->m_subPropertyMask ||
        !canMergeLists(cmd->propertyHelperList()))
        return false;

    m_newValue = cmd->newValue();
    m_subPropertyMask |= cmd->m_subPropertyMask;
    if(debugPropertyCommands)
        qDebug() << "SetPropertyCommand::mergeWith() succeeded " << propertyName();

    return true;
}

// ---- ResetPropertyCommand ----
ResetPropertyCommand::ResetPropertyCommand(QDesignerFormWindowInterface *formWindow)
    : PropertyListCommand(formWindow)
{
}

bool ResetPropertyCommand::init(QObject *object, const QString &apropertyName)
{
    Q_ASSERT(object);

    propertyHelperList().clear();
    if (!add(object, apropertyName))
        return false;

    setDescription();
    return true;
}

bool ResetPropertyCommand::init(const ObjectList &list, const QString &apropertyName, QObject *referenceObject)
{
    if (!initList(list, apropertyName, referenceObject))
        return false;

    if(debugPropertyCommands)
        qDebug() << "ResetPropertyCommand::init()" << propertyHelperList().size() << '/' << list.size();

    setDescription();
    return true;
}

void ResetPropertyCommand::setDescription()
{
    if (propertyHelperList().size() == 1) {
        setText(QApplication::translate("Command", "Reset '%1' of '%2'").arg(propertyName()).arg(propertyHelperList()[0].object()->objectName()));
    } else {
        int count = propertyHelperList().size();
        setText(QApplication::translate("Command", "Reset '%1' of %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(propertyName()));
    }
}

void ResetPropertyCommand::redo()
{
    update(restoreDefaultValue());
    QDesignerPropertyEditor *designerPropertyEditor = qobject_cast<QDesignerPropertyEditor *>(core()->propertyEditor());
    if (designerPropertyEditor)
        designerPropertyEditor->updatePropertySheet();
}

AddDynamicPropertyCommand::AddDynamicPropertyCommand(QDesignerFormWindowInterface *formWindow)
    : QDesignerFormWindowCommand(QString(), formWindow)
{

}

bool AddDynamicPropertyCommand::init(const QList<QObject *> &selection, QObject *current,
            const QString &propertyName, const QVariant &value)
{
    Q_ASSERT(current);
    m_propertyName = propertyName;

    QDesignerFormEditorInterface *core = formWindow()->core();
    QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), current);
    Q_ASSERT(dynamicSheet);

    m_selection.clear();

    if (!value.isValid())
        return false;

    if (!dynamicSheet->canAddDynamicProperty(m_propertyName))
        return false;

    m_selection.append(current);

    m_value = value;

    QListIterator<QObject *> it(selection);
    while (it.hasNext()) {
        QObject *obj = it.next();
        if (m_selection.contains(obj))
            continue;
        dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
        Q_ASSERT(dynamicSheet);
        if (dynamicSheet->canAddDynamicProperty(m_propertyName))
            m_selection.append(obj);
    }

    setDescription();
    return true;
}

void AddDynamicPropertyCommand::redo()
{
    QDesignerFormEditorInterface *core = formWindow()->core();
    QListIterator<QObject *> it(m_selection);
    while (it.hasNext()) {
        QObject *obj = it.next();
        QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
        dynamicSheet->addDynamicProperty(m_propertyName, m_value);
        if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
            if (propertyEditor->object() == obj)
                propertyEditor->setObject(obj);
        }
    }
}

void AddDynamicPropertyCommand::undo()
{
    QDesignerFormEditorInterface *core = formWindow()->core();
    QListIterator<QObject *> it(m_selection);
    while (it.hasNext()) {
        QObject *obj = it.next();
        QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), obj);
        QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
        dynamicSheet->removeDynamicProperty(sheet->indexOf(m_propertyName));
        if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
            if (propertyEditor->object() == obj)
                propertyEditor->setObject(obj);
        }
    }
}

void AddDynamicPropertyCommand::setDescription()
{
    if (m_selection.size() == 1) {
        setText(QApplication::translate("Command", "Add dynamic property '%1' to '%2'").arg(m_propertyName).arg(m_selection.first()->objectName()));
    } else {
        int count = m_selection.size();
        setText(QApplication::translate("Command", "Add dynamic property '%1' to %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(m_propertyName));
    }
}


RemoveDynamicPropertyCommand::RemoveDynamicPropertyCommand(QDesignerFormWindowInterface *formWindow)
    : QDesignerFormWindowCommand(QString(), formWindow)
{

}

bool RemoveDynamicPropertyCommand::init(const QList<QObject *> &selection, QObject *current,
            const QString &propertyName)
{
    Q_ASSERT(current);
    m_propertyName = propertyName;

    QDesignerFormEditorInterface *core = formWindow()->core();
    QDesignerPropertySheetExtension *propertySheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), current);
    Q_ASSERT(propertySheet);
    QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), current);
    Q_ASSERT(dynamicSheet);

    m_objectToValueAndChanged.clear();

    const int index = propertySheet->indexOf(m_propertyName);
    if (!dynamicSheet->isDynamicProperty(index))
        return false;

    m_objectToValueAndChanged[current] = qMakePair(propertySheet->property(index), propertySheet->isChanged(index));

    QListIterator<QObject *> it(selection);
    while (it.hasNext()) {
        QObject *obj = it.next();
        if (m_objectToValueAndChanged.contains(obj))
            continue;

        propertySheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), obj);
        dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
        const int idx = propertySheet->indexOf(m_propertyName);
        if (dynamicSheet->isDynamicProperty(idx))
            m_objectToValueAndChanged[obj] = qMakePair(propertySheet->property(idx), propertySheet->isChanged(idx));
    }

    setDescription();
    return true;
}

void RemoveDynamicPropertyCommand::redo()
{
    QDesignerFormEditorInterface *core = formWindow()->core();
    QMap<QObject *, QPair<QVariant, bool> >::ConstIterator it = m_objectToValueAndChanged.constBegin();
    while (it != m_objectToValueAndChanged.constEnd()) {
        QObject *obj = it.key();
        QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
        QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), obj);
        dynamicSheet->removeDynamicProperty(sheet->indexOf(m_propertyName));
        if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
            if (propertyEditor->object() == obj)
                propertyEditor->setObject(obj);
        }
        ++it;
    }
}

void RemoveDynamicPropertyCommand::undo()
{
    QDesignerFormEditorInterface *core = formWindow()->core();
    QMap<QObject *, QPair<QVariant, bool> >::ConstIterator it = m_objectToValueAndChanged.constBegin();
    while (it != m_objectToValueAndChanged.constEnd()) {
        QObject *obj = it.key();
        QDesignerPropertySheetExtension *propertySheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), obj);
        QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
        const int index = dynamicSheet->addDynamicProperty(m_propertyName, it.value().first);
        propertySheet->setChanged(index, it.value().second);
        if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
            if (propertyEditor->object() == obj)
                propertyEditor->setObject(obj);
        }
        ++it;
    }
}

void RemoveDynamicPropertyCommand::setDescription()
{
    if (m_objectToValueAndChanged.size() == 1) {
        setText(QApplication::translate("Command", "Remove dynamic property '%1' from '%2'").arg(m_propertyName).arg(m_objectToValueAndChanged.constBegin().key()->objectName()));
    } else {
        int count = m_objectToValueAndChanged.size();
        setText(QApplication::translate("Command", "Remove dynamic property '%1' from %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(m_propertyName));
    }
}


} // namespace qdesigner_internal

QT_END_NAMESPACE