src/declarative/qml/qdeclarativeproperty.cpp
changeset 30 5dc02b23752f
child 37 758a864f9613
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 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 QtDeclarative module 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 "qdeclarativeproperty.h"
       
    43 #include "private/qdeclarativeproperty_p.h"
       
    44 
       
    45 #include "private/qdeclarativecompositetypedata_p.h"
       
    46 #include "qdeclarative.h"
       
    47 #include "private/qdeclarativebinding_p.h"
       
    48 #include "qdeclarativecontext.h"
       
    49 #include "private/qdeclarativecontext_p.h"
       
    50 #include "private/qdeclarativeboundsignal_p.h"
       
    51 #include "qdeclarativeengine.h"
       
    52 #include "private/qdeclarativeengine_p.h"
       
    53 #include "private/qdeclarativedata_p.h"
       
    54 #include "private/qdeclarativestringconverters_p.h"
       
    55 #include "private/qdeclarativelist_p.h"
       
    56 #include "private/qdeclarativecompiler_p.h"
       
    57 
       
    58 #include <QStringList>
       
    59 #include <QtCore/qdebug.h>
       
    60 
       
    61 #include <math.h>
       
    62 
       
    63 QT_BEGIN_NAMESPACE
       
    64 
       
    65 /*!
       
    66 \class QDeclarativeProperty
       
    67 \since 4.7
       
    68 \brief The QDeclarativeProperty class abstracts accessing properties on objects created from  QML.
       
    69 
       
    70 As QML uses Qt's meta-type system all of the existing QMetaObject classes can be used to introspect
       
    71 and interact with objects created by QML.  However, some of the new features provided by QML - such 
       
    72 as type safety and attached properties - are most easily used through the QDeclarativeProperty class 
       
    73 that simplifies some of their natural complexity.
       
    74 
       
    75 Unlike QMetaProperty which represents a property on a class type, QDeclarativeProperty encapsulates 
       
    76 a property on a specific object instance.  To read a property's value, programmers create a 
       
    77 QDeclarativeProperty instance and call the read() method.  Likewise to write a property value the
       
    78 write() method is used.
       
    79 
       
    80 \code
       
    81 
       
    82 QObject *object = declarativeComponent.create();
       
    83 
       
    84 QDeclarativeProperty property(object, "font.pixelSize");
       
    85 qWarning() << "Current pixel size:" << property.read().toInt();
       
    86 property.write(24);
       
    87 qWarning() << "Pixel size should now be 24:" << property.read().toInt();
       
    88 
       
    89 \endcode
       
    90 */
       
    91 
       
    92 /*!
       
    93     Create an invalid QDeclarativeProperty.
       
    94 */
       
    95 QDeclarativeProperty::QDeclarativeProperty()
       
    96 : d(new QDeclarativePropertyPrivate)
       
    97 {
       
    98     d->q = this;
       
    99 }
       
   100 
       
   101 /*!  \internal */
       
   102 QDeclarativeProperty::~QDeclarativeProperty()
       
   103 {
       
   104     delete d; d = 0;
       
   105 }
       
   106 
       
   107 /*!
       
   108     Creates a QDeclarativeProperty for the default property of \a obj. If there is no
       
   109     default property, an invalid QDeclarativeProperty will be created.
       
   110  */
       
   111 QDeclarativeProperty::QDeclarativeProperty(QObject *obj)
       
   112 : d(new QDeclarativePropertyPrivate)
       
   113 {
       
   114     d->q = this;
       
   115     d->initDefault(obj);
       
   116 }
       
   117 
       
   118 /*!
       
   119     Creates a QDeclarativeProperty for the default property of \a obj
       
   120     using the \l{QDeclarativeContext} {context} \a ctxt. If there is
       
   121     no default property, an invalid QDeclarativeProperty will be
       
   122     created.
       
   123  */
       
   124 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, QDeclarativeContext *ctxt)
       
   125 : d(new QDeclarativePropertyPrivate)
       
   126 {
       
   127     d->q = this;
       
   128     d->context = ctxt?QDeclarativeContextData::get(ctxt):0;
       
   129     d->engine = ctxt?ctxt->engine():0;
       
   130     d->initDefault(obj);
       
   131 }
       
   132 
       
   133 /*!
       
   134     Creates a QDeclarativeProperty for the default property of \a obj
       
   135     using the environment for instantiating QML components that is
       
   136     provided by \a engine.  If there is no default property, an
       
   137     invalid QDeclarativeProperty will be created.
       
   138  */
       
   139 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, QDeclarativeEngine *engine)
       
   140   : d(new QDeclarativePropertyPrivate)
       
   141 {
       
   142     d->q = this;
       
   143     d->context = 0;
       
   144     d->engine = engine;
       
   145     d->initDefault(obj);
       
   146 }
       
   147 
       
   148 /*!
       
   149     Initialize from the default property of \a obj
       
   150 */
       
   151 void QDeclarativePropertyPrivate::initDefault(QObject *obj)
       
   152 {
       
   153     if (!obj)
       
   154         return;
       
   155 
       
   156     QMetaProperty p = QDeclarativeMetaType::defaultProperty(obj);
       
   157     core.load(p);
       
   158     if (core.isValid()) 
       
   159         object = obj;
       
   160 }
       
   161 
       
   162 /*!
       
   163     Creates a QDeclarativeProperty for the property \a name of \a obj.
       
   164  */
       
   165 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name)
       
   166 : d(new QDeclarativePropertyPrivate)
       
   167 {
       
   168     d->q = this;
       
   169     d->initProperty(obj, name);
       
   170     if (!isValid()) d->object = 0;
       
   171 }
       
   172 
       
   173 /*!
       
   174     Creates a QDeclarativeProperty for the property \a name of \a obj
       
   175     using the \l{QDeclarativeContext} {context} \a ctxt.
       
   176 */
       
   177 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeContext *ctxt)
       
   178 : d(new QDeclarativePropertyPrivate)
       
   179 {
       
   180     d->q = this;
       
   181     d->context = ctxt?QDeclarativeContextData::get(ctxt):0;
       
   182     d->engine = ctxt?ctxt->engine():0;
       
   183     d->initProperty(obj, name);
       
   184     if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
       
   185 }
       
   186 
       
   187 /*!
       
   188     Creates a QDeclarativeProperty for the property \a name of \a obj
       
   189     using the environment for instantiating QML components that is
       
   190     provided by \a engine.
       
   191  */
       
   192 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeEngine *engine)
       
   193 : d(new QDeclarativePropertyPrivate)
       
   194 {
       
   195     d->q = this;
       
   196     d->context = 0;
       
   197     d->engine = engine;
       
   198     d->initProperty(obj, name);
       
   199     if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
       
   200 }
       
   201 
       
   202 Q_GLOBAL_STATIC(QDeclarativeValueTypeFactory, qmlValueTypes);
       
   203 
       
   204 void QDeclarativePropertyPrivate::initProperty(QObject *obj, const QString &name)
       
   205 {
       
   206     if (!obj) return;
       
   207 
       
   208     QDeclarativeTypeNameCache *typeNameCache = context?context->imports:0;
       
   209 
       
   210     QStringList path = name.split(QLatin1Char('.'));
       
   211     if (path.isEmpty()) return;
       
   212 
       
   213     QObject *currentObject = obj;
       
   214 
       
   215     // Everything up to the last property must be an "object type" property
       
   216     for (int ii = 0; ii < path.count() - 1; ++ii) {
       
   217         const QString &pathName = path.at(ii);
       
   218 
       
   219         if (QDeclarativeTypeNameCache::Data *data = typeNameCache?typeNameCache->data(pathName):0) {
       
   220             if (data->type) {
       
   221                 QDeclarativeAttachedPropertiesFunc func = data->type->attachedPropertiesFunction();
       
   222                 if (!func) return; // Not an attachable type
       
   223 
       
   224                 currentObject = qmlAttachedPropertiesObjectById(data->type->index(), currentObject);
       
   225                 if (!currentObject) return; // Something is broken with the attachable type
       
   226             } else {
       
   227                 Q_ASSERT(data->typeNamespace);
       
   228                 if ((ii + 1) == path.count()) return; // No type following the namespace
       
   229                 
       
   230                 ++ii; data = data->typeNamespace->data(path.at(ii));
       
   231                 if (!data || !data->type) return; // Invalid type in namespace 
       
   232 
       
   233                 QDeclarativeAttachedPropertiesFunc func = data->type->attachedPropertiesFunction();
       
   234                 if (!func) return; // Not an attachable type
       
   235 
       
   236                 currentObject = qmlAttachedPropertiesObjectById(data->type->index(), currentObject);
       
   237                 if (!currentObject) return; // Something is broken with the attachable type
       
   238             }
       
   239         } else {
       
   240 
       
   241             QDeclarativePropertyCache::Data local;
       
   242             QDeclarativePropertyCache::Data *property = 
       
   243                 QDeclarativePropertyCache::property(engine, obj, pathName, local);
       
   244 
       
   245             if (!property) return; // Not a property
       
   246             if (property->flags & QDeclarativePropertyCache::Data::IsFunction) 
       
   247                 return; // Not an object property 
       
   248 
       
   249             if (ii == (path.count() - 2) && QDeclarativeValueTypeFactory::isValueType(property->propType)) {
       
   250                 // We're now at a value type property.  We can use a global valuetypes array as we 
       
   251                 // never actually use the objects, just look up their properties.
       
   252                 QObject *typeObject = (*qmlValueTypes())[property->propType];
       
   253                 if (!typeObject) return; // Not a value type
       
   254 
       
   255                 int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData());
       
   256                 if (idx == -1) return; // Value type property does not exist
       
   257 
       
   258                 QMetaProperty vtProp = typeObject->metaObject()->property(idx);
       
   259 
       
   260                 object = currentObject;
       
   261                 core = *property;
       
   262                 valueType.flags = QDeclarativePropertyCache::Data::flagsForProperty(vtProp);
       
   263                 valueType.valueTypeCoreIdx = idx;
       
   264                 valueType.valueTypePropType = vtProp.userType();
       
   265 
       
   266                 return; 
       
   267             } else {
       
   268                 if (!(property->flags & QDeclarativePropertyCache::Data::IsQObjectDerived)) 
       
   269                     return; // Not an object property
       
   270 
       
   271                 void *args[] = { &currentObject, 0 };
       
   272                 QMetaObject::metacall(currentObject, QMetaObject::ReadProperty, property->coreIndex, args);
       
   273                 if (!currentObject) return; // No value
       
   274 
       
   275             }
       
   276         }
       
   277 
       
   278     }
       
   279 
       
   280     const QString &terminal = path.last();
       
   281 
       
   282     if (terminal.count() >= 3 &&
       
   283         terminal.at(0) == QLatin1Char('o') &&
       
   284         terminal.at(1) == QLatin1Char('n') &&
       
   285         terminal.at(2).isUpper()) {
       
   286 
       
   287         QString signalName = terminal.mid(2);
       
   288         signalName[0] = signalName.at(0).toLower();
       
   289 
       
   290         QMetaMethod method = findSignalByName(currentObject->metaObject(), signalName.toLatin1().constData());
       
   291         if (method.signature()) {
       
   292             object = currentObject;
       
   293             core.load(method);
       
   294             return;
       
   295         }
       
   296     }
       
   297 
       
   298     // Property
       
   299     QDeclarativePropertyCache::Data local;
       
   300     QDeclarativePropertyCache::Data *property = 
       
   301         QDeclarativePropertyCache::property(engine, currentObject, terminal, local);
       
   302     if (property && !(property->flags & QDeclarativePropertyCache::Data::IsFunction)) {
       
   303         object = currentObject;
       
   304         core = *property;
       
   305     }
       
   306 }
       
   307 
       
   308 /*!
       
   309     Create a copy of \a other.
       
   310 */
       
   311 QDeclarativeProperty::QDeclarativeProperty(const QDeclarativeProperty &other)
       
   312 : d(new QDeclarativePropertyPrivate(*other.d))
       
   313 {
       
   314     d->q = this;
       
   315 }
       
   316 
       
   317 /*!
       
   318   \enum QDeclarativeProperty::PropertyTypeCategory
       
   319 
       
   320   This enum specifies a category of QML property.
       
   321 
       
   322   \value InvalidCategory The property is invalid, or is a signal property.
       
   323   \value List The property is a QDeclarativeListProperty list property
       
   324   \value Object The property is a QObject derived type pointer
       
   325   \value Normal The property is a normal value property.
       
   326  */
       
   327 
       
   328 /*!
       
   329   \enum QDeclarativeProperty::Type
       
   330 
       
   331   This enum specifies a type of QML property.
       
   332 
       
   333   \value Invalid The property is invalid.
       
   334   \value Property The property is a regular Qt property.
       
   335   \value SignalProperty The property is a signal property.
       
   336 */
       
   337 
       
   338 /*!
       
   339     Returns the property category.
       
   340 */
       
   341 QDeclarativeProperty::PropertyTypeCategory QDeclarativeProperty::propertyTypeCategory() const
       
   342 {
       
   343     return d->propertyTypeCategory();
       
   344 }
       
   345 
       
   346 QDeclarativeProperty::PropertyTypeCategory 
       
   347 QDeclarativePropertyPrivate::propertyTypeCategory() const
       
   348 {
       
   349     uint type = q->type();
       
   350 
       
   351     if (isValueType()) {
       
   352         return QDeclarativeProperty::Normal;
       
   353     } else if (type & QDeclarativeProperty::Property) {
       
   354         int type = propertyType();
       
   355         if (type == QVariant::Invalid)
       
   356             return QDeclarativeProperty::InvalidCategory;
       
   357         else if (QDeclarativeValueTypeFactory::isValueType((uint)type))
       
   358             return QDeclarativeProperty::Normal;
       
   359         else if (core.flags & QDeclarativePropertyCache::Data::IsQObjectDerived)
       
   360             return QDeclarativeProperty::Object;
       
   361         else if (core.flags & QDeclarativePropertyCache::Data::IsQList)
       
   362             return QDeclarativeProperty::List;
       
   363         else 
       
   364             return QDeclarativeProperty::Normal;
       
   365     } else {
       
   366         return QDeclarativeProperty::InvalidCategory;
       
   367     }
       
   368 }
       
   369 
       
   370 /*!
       
   371     Returns the type name of the property, or 0 if the property has no type
       
   372     name.
       
   373 */
       
   374 const char *QDeclarativeProperty::propertyTypeName() const
       
   375 {
       
   376     if (d->isValueType()) {
       
   377 
       
   378         QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context);
       
   379         QDeclarativeValueType *valueType = 0;
       
   380         if (ep) valueType = ep->valueTypes[d->core.propType];
       
   381         else valueType = QDeclarativeValueTypeFactory::valueType(d->core.propType);
       
   382         Q_ASSERT(valueType);
       
   383 
       
   384         const char *rv = valueType->metaObject()->property(d->valueType.valueTypeCoreIdx).typeName();
       
   385 
       
   386         if (!ep) delete valueType;
       
   387 
       
   388         return rv;
       
   389     } else if (d->object && type() & Property && d->core.isValid()) {
       
   390         return d->object->metaObject()->property(d->core.coreIndex).typeName();
       
   391     } else {
       
   392         return 0;
       
   393     }
       
   394 }
       
   395 
       
   396 /*!
       
   397     Returns true if \a other and this QDeclarativeProperty represent the same 
       
   398     property.
       
   399 */
       
   400 bool QDeclarativeProperty::operator==(const QDeclarativeProperty &other) const
       
   401 {
       
   402     // category is intentially omitted here as it is generated 
       
   403     // from the other members
       
   404     return d->object == other.d->object &&
       
   405            d->core == other.d->core &&
       
   406            d->valueType == other.d->valueType;
       
   407 }
       
   408 
       
   409 /*!
       
   410     Returns the QVariant type of the property, or QVariant::Invalid if the 
       
   411     property has no QVariant type.
       
   412 */
       
   413 int QDeclarativeProperty::propertyType() const
       
   414 {
       
   415     return d->propertyType();
       
   416 }
       
   417 
       
   418 bool QDeclarativePropertyPrivate::isValueType() const
       
   419 {
       
   420     return valueType.valueTypeCoreIdx != -1;
       
   421 }
       
   422 
       
   423 int QDeclarativePropertyPrivate::propertyType() const
       
   424 {
       
   425     uint type = q->type();
       
   426     if (isValueType()) {
       
   427         return valueType.valueTypePropType;
       
   428     } else if (type & QDeclarativeProperty::Property) {
       
   429         if (core.propType == (int)QVariant::LastType)
       
   430             return qMetaTypeId<QVariant>();
       
   431         else
       
   432             return core.propType;
       
   433     } else {
       
   434         return QVariant::Invalid;
       
   435     }
       
   436 }
       
   437 
       
   438 /*!
       
   439     Returns the type of the property.
       
   440 */
       
   441 QDeclarativeProperty::Type QDeclarativeProperty::type() const
       
   442 {
       
   443     if (d->core.flags & QDeclarativePropertyCache::Data::IsFunction)
       
   444         return SignalProperty;
       
   445     else if (d->core.isValid())
       
   446         return Property;
       
   447     else
       
   448         return Invalid;
       
   449 }
       
   450 
       
   451 /*!
       
   452     Returns true if this QDeclarativeProperty represents a regular Qt property.
       
   453 */
       
   454 bool QDeclarativeProperty::isProperty() const
       
   455 {
       
   456     return type() & Property;
       
   457 }
       
   458 
       
   459 /*!
       
   460     Returns true if this QDeclarativeProperty represents a QML signal property.
       
   461 */
       
   462 bool QDeclarativeProperty::isSignalProperty() const
       
   463 {
       
   464     return type() & SignalProperty;
       
   465 }
       
   466 
       
   467 /*!
       
   468     Returns the QDeclarativeProperty's QObject.
       
   469 */
       
   470 QObject *QDeclarativeProperty::object() const
       
   471 {
       
   472     return d->object;
       
   473 }
       
   474 
       
   475 /*!
       
   476     Assign \a other to this QDeclarativeProperty.
       
   477 */
       
   478 QDeclarativeProperty &QDeclarativeProperty::operator=(const QDeclarativeProperty &other)
       
   479 {
       
   480     d->context = other.d->context;
       
   481     d->engine = other.d->engine;
       
   482     d->object = other.d->object;
       
   483 
       
   484     d->isNameCached = other.d->isNameCached;
       
   485     d->core = other.d->core;
       
   486     d->nameCache = other.d->nameCache;
       
   487 
       
   488     d->valueType = other.d->valueType;
       
   489 
       
   490     return *this;
       
   491 }
       
   492 
       
   493 /*!
       
   494     Returns true if the property is writable, otherwise false.
       
   495 */
       
   496 bool QDeclarativeProperty::isWritable() const
       
   497 {
       
   498     if (!d->object)
       
   499         return false;
       
   500     if (d->core.flags & QDeclarativePropertyCache::Data::IsQList)           //list
       
   501         return true;
       
   502     else if (d->core.flags & QDeclarativePropertyCache::Data::IsFunction)   //signal handler
       
   503         return false;
       
   504     else if (d->core.isValid())                                             //normal property
       
   505         return d->core.flags & QDeclarativePropertyCache::Data::IsWritable;
       
   506     else
       
   507         return false;
       
   508 }
       
   509 
       
   510 /*!
       
   511     Returns true if the property is designable, otherwise false.
       
   512 */
       
   513 bool QDeclarativeProperty::isDesignable() const
       
   514 {
       
   515     if (type() & Property && d->core.isValid() && d->object)
       
   516         return d->object->metaObject()->property(d->core.coreIndex).isDesignable();
       
   517     else
       
   518         return false;
       
   519 }
       
   520 
       
   521 /*!
       
   522     Returns true if the property is resettable, otherwise false.
       
   523 */
       
   524 bool QDeclarativeProperty::isResettable() const
       
   525 {
       
   526     if (type() & Property && d->core.isValid() && d->object)
       
   527         return d->core.flags & QDeclarativePropertyCache::Data::IsResettable;
       
   528     else
       
   529         return false;
       
   530 }
       
   531 
       
   532 /*!
       
   533     Returns true if the QDeclarativeProperty refers to a valid property, otherwise
       
   534     false.
       
   535 */
       
   536 bool QDeclarativeProperty::isValid() const
       
   537 {
       
   538     return type() != Invalid;
       
   539 }
       
   540 
       
   541 /*!
       
   542     Return the name of this QML property.
       
   543 */
       
   544 QString QDeclarativeProperty::name() const
       
   545 {
       
   546     if (!d->isNameCached) {
       
   547         // ###
       
   548         if (!d->object) {
       
   549         } else if (d->isValueType()) {
       
   550             QString rv = d->core.name(d->object) + QLatin1Char('.');
       
   551 
       
   552             QDeclarativeEnginePrivate *ep = d->engine?QDeclarativeEnginePrivate::get(d->engine):0;
       
   553             QDeclarativeValueType *valueType = 0;
       
   554             if (ep) valueType = ep->valueTypes[d->core.propType];
       
   555             else valueType = QDeclarativeValueTypeFactory::valueType(d->core.propType);
       
   556             Q_ASSERT(valueType);
       
   557 
       
   558             rv += QString::fromUtf8(valueType->metaObject()->property(d->valueType.valueTypeCoreIdx).name());
       
   559 
       
   560             if (!ep) delete valueType;
       
   561 
       
   562             d->nameCache = rv;
       
   563         } else if (type() & SignalProperty) {
       
   564             QString name = QLatin1String("on") + d->core.name(d->object);
       
   565             name[2] = name.at(2).toUpper();
       
   566             d->nameCache = name;
       
   567         } else {
       
   568             d->nameCache = d->core.name(d->object);
       
   569         }
       
   570         d->isNameCached = true;
       
   571     }
       
   572 
       
   573     return d->nameCache;
       
   574 }
       
   575 
       
   576 /*!
       
   577   Returns the \l{QMetaProperty} {Qt property} associated with
       
   578   this QML property.
       
   579  */
       
   580 QMetaProperty QDeclarativeProperty::property() const
       
   581 {
       
   582     if (type() & Property && d->core.isValid() && d->object)
       
   583         return d->object->metaObject()->property(d->core.coreIndex);
       
   584     else
       
   585         return QMetaProperty();
       
   586 }
       
   587 
       
   588 /*!
       
   589     Return the QMetaMethod for this property if it is a SignalProperty, 
       
   590     otherwise returns an invalid QMetaMethod.
       
   591 */
       
   592 QMetaMethod QDeclarativeProperty::method() const
       
   593 {
       
   594     if (type() & SignalProperty && d->object)
       
   595         return d->object->metaObject()->method(d->core.coreIndex);
       
   596     else
       
   597         return QMetaMethod();
       
   598 }
       
   599 
       
   600 /*!
       
   601     Returns the binding associated with this property, or 0 if no binding 
       
   602     exists.
       
   603 */
       
   604 QDeclarativeAbstractBinding *
       
   605 QDeclarativePropertyPrivate::binding(const QDeclarativeProperty &that) 
       
   606 {
       
   607     if (!that.isProperty() || !that.d->object)
       
   608         return 0;
       
   609 
       
   610     QDeclarativeData *data = QDeclarativeData::get(that.d->object);
       
   611     if (!data) 
       
   612         return 0;
       
   613 
       
   614     if (!data->hasBindingBit(that.d->core.coreIndex))
       
   615         return 0;
       
   616 
       
   617     QDeclarativeAbstractBinding *binding = data->bindings;
       
   618     while (binding && binding->propertyIndex() != that.d->core.coreIndex) 
       
   619         binding = binding->m_nextBinding;
       
   620 
       
   621     if (binding && that.d->valueType.valueTypeCoreIdx != -1) {
       
   622         if (binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy) {
       
   623             QDeclarativeValueTypeProxyBinding *proxy = static_cast<QDeclarativeValueTypeProxyBinding *>(binding);
       
   624 
       
   625             binding = proxy->binding(bindingIndex(that));
       
   626         }
       
   627     }
       
   628 
       
   629     return binding;
       
   630 }
       
   631 
       
   632 /*!
       
   633     Set the binding associated with this property to \a newBinding.  Returns
       
   634     the existing binding (if any), otherwise 0.
       
   635 
       
   636     \a newBinding will be enabled, and the returned binding (if any) will be
       
   637     disabled.
       
   638 
       
   639     Ownership of \a newBinding transfers to QML.  Ownership of the return value
       
   640     is assumed by the caller.
       
   641 
       
   642     \a flags is passed through to the binding and is used for the initial update (when
       
   643     the binding sets the intial value, it will use these flags for the write).
       
   644 */
       
   645 QDeclarativeAbstractBinding *
       
   646 QDeclarativePropertyPrivate::setBinding(const QDeclarativeProperty &that,
       
   647                                             QDeclarativeAbstractBinding *newBinding, 
       
   648                                             WriteFlags flags) 
       
   649 {
       
   650     if (!that.isProperty() || !that.d->object) {
       
   651         if (newBinding)
       
   652             newBinding->destroy();
       
   653         return 0;
       
   654     }
       
   655 
       
   656     return that.d->setBinding(that.d->object, that.d->core.coreIndex, 
       
   657                               that.d->valueType.valueTypeCoreIdx, newBinding, flags);
       
   658 }
       
   659 
       
   660 QDeclarativeAbstractBinding *
       
   661 QDeclarativePropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex,
       
   662                                         QDeclarativeAbstractBinding *newBinding, WriteFlags flags)
       
   663 {
       
   664     QDeclarativeData *data = QDeclarativeData::get(object, 0 != newBinding);
       
   665     QDeclarativeAbstractBinding *binding = 0;
       
   666 
       
   667     if (data && data->hasBindingBit(coreIndex)) {
       
   668         binding = data->bindings;
       
   669 
       
   670         while (binding && binding->propertyIndex() != coreIndex) 
       
   671             binding = binding->m_nextBinding;
       
   672     }
       
   673 
       
   674     if (binding && valueTypeIndex != -1 && binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy) {
       
   675         int index = coreIndex | (valueTypeIndex << 24);
       
   676         binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
       
   677     }
       
   678 
       
   679     if (binding) 
       
   680         binding->setEnabled(false);
       
   681 
       
   682     if (newBinding) 
       
   683         newBinding->setEnabled(true, flags);
       
   684 
       
   685     return binding;
       
   686 }
       
   687 
       
   688 /*!
       
   689     Returns the expression associated with this signal property, or 0 if no 
       
   690     signal expression exists.
       
   691 */
       
   692 QDeclarativeExpression *
       
   693 QDeclarativePropertyPrivate::signalExpression(const QDeclarativeProperty &that)
       
   694 {
       
   695     if (!(that.type() & QDeclarativeProperty::SignalProperty))
       
   696         return 0;
       
   697 
       
   698     const QObjectList &children = that.d->object->children();
       
   699     
       
   700     for (int ii = 0; ii < children.count(); ++ii) {
       
   701         QObject *child = children.at(ii);
       
   702 
       
   703         QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
       
   704         if (signal && signal->index() == that.index()) 
       
   705             return signal->expression();
       
   706     }
       
   707 
       
   708     return 0;
       
   709 }
       
   710 
       
   711 /*!
       
   712     Set the signal expression associated with this signal property to \a expr.
       
   713     Returns the existing signal expression (if any), otherwise 0.
       
   714 
       
   715     Ownership of \a expr transfers to QML.  Ownership of the return value is
       
   716     assumed by the caller.
       
   717 */
       
   718 QDeclarativeExpression *
       
   719 QDeclarativePropertyPrivate::setSignalExpression(const QDeclarativeProperty &that,
       
   720                                                      QDeclarativeExpression *expr) 
       
   721 {
       
   722     if (!(that.type() & QDeclarativeProperty::SignalProperty)) {
       
   723         delete expr;
       
   724         return 0;
       
   725     }
       
   726 
       
   727     const QObjectList &children = that.d->object->children();
       
   728     
       
   729     for (int ii = 0; ii < children.count(); ++ii) {
       
   730         QObject *child = children.at(ii);
       
   731 
       
   732         QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
       
   733         if (signal && signal->index() == that.index()) 
       
   734             return signal->setExpression(expr);
       
   735     }
       
   736 
       
   737     if (expr) {
       
   738         QDeclarativeBoundSignal *signal = new QDeclarativeBoundSignal(that.d->object, that.method(), that.d->object);
       
   739         return signal->setExpression(expr);
       
   740     } else {
       
   741         return 0;
       
   742     }
       
   743 }
       
   744 
       
   745 /*!
       
   746     Returns the property value.
       
   747 */
       
   748 QVariant QDeclarativeProperty::read() const
       
   749 {
       
   750     if (!d->object)
       
   751         return QVariant();
       
   752 
       
   753     if (type() & SignalProperty) {
       
   754 
       
   755         return QVariant();
       
   756 
       
   757     } else if (type() & Property) {
       
   758 
       
   759         return d->readValueProperty();
       
   760 
       
   761     }
       
   762     return QVariant();
       
   763 }
       
   764 
       
   765 /*!
       
   766 Return the \a name property value of \a object.  This method is equivalent to:
       
   767 \code
       
   768     QDeclarativeProperty p(object, name);
       
   769     p.read();
       
   770 \endcode
       
   771 */
       
   772 QVariant QDeclarativeProperty::read(QObject *object, const QString &name)
       
   773 {
       
   774     QDeclarativeProperty p(object, name);
       
   775     return p.read();
       
   776 }
       
   777 
       
   778 /*!
       
   779   Return the \a name property value of \a object using the
       
   780   \l{QDeclarativeContext} {context} \a ctxt.  This method is
       
   781   equivalent to:
       
   782 
       
   783   \code
       
   784     QDeclarativeProperty p(object, name, context);
       
   785     p.read();
       
   786   \endcode
       
   787 */
       
   788 QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeContext *ctxt)
       
   789 {
       
   790     QDeclarativeProperty p(object, name, ctxt);
       
   791     return p.read();
       
   792 }
       
   793 
       
   794 /*!
       
   795   
       
   796   Return the \a name property value of \a object using the environment
       
   797   for instantiating QML components that is provided by \a engine. .
       
   798   This method is equivalent to:
       
   799 
       
   800   \code
       
   801     QDeclarativeProperty p(object, name, engine);
       
   802     p.read();
       
   803   \endcode
       
   804 */
       
   805 QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeEngine *engine)
       
   806 {
       
   807     QDeclarativeProperty p(object, name, engine);
       
   808     return p.read();
       
   809 }
       
   810 
       
   811 QVariant QDeclarativePropertyPrivate::readValueProperty()
       
   812 {
       
   813     if (isValueType()) {
       
   814 
       
   815         QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context);
       
   816         QDeclarativeValueType *valueType = 0;
       
   817         if (ep) valueType = ep->valueTypes[core.propType];
       
   818         else valueType = QDeclarativeValueTypeFactory::valueType(core.propType);
       
   819         Q_ASSERT(valueType);
       
   820 
       
   821         valueType->read(object, core.coreIndex);
       
   822 
       
   823         QVariant rv =
       
   824             valueType->metaObject()->property(this->valueType.valueTypeCoreIdx).read(valueType);
       
   825 
       
   826         if (!ep) delete valueType;
       
   827         return rv;
       
   828 
       
   829     } else if (core.flags & QDeclarativePropertyCache::Data::IsQList) {
       
   830 
       
   831         QDeclarativeListProperty<QObject> prop;
       
   832         void *args[] = { &prop, 0 };
       
   833         QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
       
   834         return QVariant::fromValue(QDeclarativeListReferencePrivate::init(prop, core.propType, engine)); 
       
   835 
       
   836     } else if (core.flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
       
   837 
       
   838         QObject *rv = 0;
       
   839         void *args[] = { &rv, 0 };
       
   840         QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
       
   841         return QVariant::fromValue(rv);
       
   842 
       
   843     } else {
       
   844 
       
   845         return object->metaObject()->property(core.coreIndex).read(object.data());
       
   846 
       
   847     }
       
   848 }
       
   849 
       
   850 //writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
       
   851 bool QDeclarativePropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
       
   852 {
       
   853     if (!object || !prop.isWritable())
       
   854         return false;
       
   855 
       
   856     QVariant v = value;
       
   857     if (prop.isEnumType()) {
       
   858         QMetaEnum menum = prop.enumerator();
       
   859         if (v.userType() == QVariant::String
       
   860 #ifdef QT3_SUPPORT
       
   861             || v.userType() == QVariant::CString
       
   862 #endif
       
   863             ) {
       
   864             if (prop.isFlagType())
       
   865                 v = QVariant(menum.keysToValue(value.toByteArray()));
       
   866             else
       
   867                 v = QVariant(menum.keyToValue(value.toByteArray()));
       
   868         } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) {
       
   869             int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope()) + "::" + menum.name());
       
   870             if ((enumMetaTypeId == 0) || (v.userType() != enumMetaTypeId) || !v.constData())
       
   871                 return false;
       
   872             v = QVariant(*reinterpret_cast<const int *>(v.constData()));
       
   873         }
       
   874         v.convert(QVariant::Int);
       
   875     }
       
   876 
       
   877     // the status variable is changed by qt_metacall to indicate what it did
       
   878     // this feature is currently only used by QtDBus and should not be depended
       
   879     // upon. Don't change it without looking into QDBusAbstractInterface first
       
   880     // -1 (unchanged): normal qt_metacall, result stored in argv[0]
       
   881     // changed: result stored directly in value, return the value of status
       
   882     int status = -1;
       
   883     void *argv[] = { v.data(), &v, &status, &flags };
       
   884     QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv);
       
   885     return status;
       
   886 }
       
   887 
       
   888 bool QDeclarativePropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags)
       
   889 {
       
   890     // Remove any existing bindings on this property
       
   891     if (!(flags & DontRemoveBinding)) {
       
   892         QDeclarativeAbstractBinding *binding = setBinding(*q, 0);
       
   893         if (binding) binding->destroy();
       
   894     }
       
   895 
       
   896     bool rv = false;
       
   897     if (isValueType()) {
       
   898         QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context);
       
   899 
       
   900         QDeclarativeValueType *writeBack = 0;
       
   901         if (ep) {
       
   902             writeBack = ep->valueTypes[core.propType];
       
   903         } else {
       
   904             writeBack = QDeclarativeValueTypeFactory::valueType(core.propType);
       
   905         }
       
   906 
       
   907         writeBack->read(object, core.coreIndex);
       
   908 
       
   909         QDeclarativePropertyCache::Data data = core;
       
   910         data.flags = valueType.flags;
       
   911         data.coreIndex = valueType.valueTypeCoreIdx;
       
   912         data.propType = valueType.valueTypePropType;
       
   913         rv = write(writeBack, data, value, context, flags);
       
   914 
       
   915         writeBack->write(object, core.coreIndex, flags);
       
   916         if (!ep) delete writeBack;
       
   917 
       
   918     } else {
       
   919 
       
   920         rv = write(object, core, value, context, flags);
       
   921 
       
   922     }
       
   923 
       
   924     return rv;
       
   925 }
       
   926 
       
   927 bool QDeclarativePropertyPrivate::write(QObject *object, const QDeclarativePropertyCache::Data &property, 
       
   928                                             const QVariant &value, QDeclarativeContextData *context, 
       
   929                                             WriteFlags flags)
       
   930 {
       
   931     int coreIdx = property.coreIndex;
       
   932     int status = -1;    //for dbus
       
   933 
       
   934     if (property.flags & QDeclarativePropertyCache::Data::IsEnumType) {
       
   935         QMetaProperty prop = object->metaObject()->property(property.coreIndex);
       
   936         QVariant v = value;
       
   937         // Enum values come through the script engine as doubles
       
   938         if (value.userType() == QVariant::Double) { 
       
   939             double integral;
       
   940             double fractional = modf(value.toDouble(), &integral);
       
   941             if (qFuzzyIsNull(fractional))
       
   942                 v.convert(QVariant::Int);
       
   943         }
       
   944         return writeEnumProperty(prop, coreIdx, object, v, flags);
       
   945     }
       
   946 
       
   947     int propertyType = property.propType;
       
   948     int variantType = value.userType();
       
   949 
       
   950     QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context);
       
   951 
       
   952     if (propertyType == QVariant::Url) {
       
   953 
       
   954         QUrl u;
       
   955         bool found = false;
       
   956         if (variantType == QVariant::Url) {
       
   957             u = value.toUrl();
       
   958             found = true;
       
   959         } else if (variantType == QVariant::ByteArray) {
       
   960             u = QUrl(QString::fromUtf8(value.toByteArray()));
       
   961             found = true;
       
   962         } else if (variantType == QVariant::String) {
       
   963             u = QUrl(value.toString());
       
   964             found = true;
       
   965         }
       
   966 
       
   967         if (!found)
       
   968             return false;
       
   969 
       
   970         if (context && u.isRelative() && !u.isEmpty())
       
   971             u = context->resolvedUrl(u);
       
   972         int status = -1;
       
   973         void *argv[] = { &u, 0, &status, &flags };
       
   974         QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
       
   975 
       
   976     } else if (variantType == propertyType) {
       
   977 
       
   978         void *a[] = { (void *)value.constData(), 0, &status, &flags };
       
   979         QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
       
   980 
       
   981     } else if (qMetaTypeId<QVariant>() == propertyType) {
       
   982 
       
   983         void *a[] = { (void *)&value, 0, &status, &flags };
       
   984         QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
       
   985 
       
   986     } else if (property.flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
       
   987 
       
   988         const QMetaObject *valMo = rawMetaObjectForType(enginePriv, value.userType());
       
   989         
       
   990         if (!valMo)
       
   991             return false;
       
   992 
       
   993         QObject *o = *(QObject **)value.constData();
       
   994         const QMetaObject *propMo = rawMetaObjectForType(enginePriv, propertyType);
       
   995 
       
   996         if (o) valMo = o->metaObject();
       
   997 
       
   998         if (canConvert(valMo, propMo)) {
       
   999             void *args[] = { &o, 0, &status, &flags };
       
  1000             QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, 
       
  1001                                   args);
       
  1002         } else if (!o && canConvert(propMo, valMo)) {
       
  1003             // In the case of a null QObject, we assign the null if there is 
       
  1004             // any change that the null variant type could be up or down cast to 
       
  1005             // the property type.
       
  1006             void *args[] = { &o, 0, &status, &flags };
       
  1007             QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, 
       
  1008                                   args);
       
  1009         } else {
       
  1010             return false;
       
  1011         }
       
  1012 
       
  1013     } else if (property.flags & QDeclarativePropertyCache::Data::IsQList) {
       
  1014 
       
  1015         const QMetaObject *listType = 0;
       
  1016         if (enginePriv) {
       
  1017             listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType));
       
  1018         } else {
       
  1019             QDeclarativeType *type = QDeclarativeMetaType::qmlType(QDeclarativeMetaType::listType(property.propType));
       
  1020             if (!type) return false;
       
  1021             listType = type->baseMetaObject();
       
  1022         }
       
  1023         if (!listType) return false;
       
  1024 
       
  1025         QDeclarativeListProperty<void> prop;
       
  1026         void *args[] = { &prop, 0 };
       
  1027         QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args);
       
  1028 
       
  1029         if (!prop.clear) return false;
       
  1030 
       
  1031         prop.clear(&prop);
       
  1032 
       
  1033         if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
       
  1034             const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
       
  1035 
       
  1036             for (int ii = 0; ii < list.count(); ++ii) {
       
  1037                 QObject *o = list.at(ii);
       
  1038                 if (o && !canConvert(o->metaObject(), listType))
       
  1039                     o = 0;
       
  1040                 prop.append(&prop, (void *)o);
       
  1041             }
       
  1042         } else {
       
  1043             QObject *o = enginePriv?enginePriv->toQObject(value):QDeclarativeMetaType::toQObject(value);
       
  1044             if (o && !canConvert(o->metaObject(), listType))
       
  1045                 o = 0;
       
  1046             prop.append(&prop, (void *)o);
       
  1047         }
       
  1048 
       
  1049     } else {
       
  1050         Q_ASSERT(variantType != propertyType);
       
  1051 
       
  1052         bool ok = false;
       
  1053         QVariant v;
       
  1054         if (variantType == QVariant::String)
       
  1055             v = QDeclarativeStringConverters::variantFromString(value.toString(), propertyType, &ok);
       
  1056         if (!ok) {
       
  1057             v = value;
       
  1058             if (v.convert((QVariant::Type)propertyType)) {
       
  1059                 ok = true;
       
  1060             } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
       
  1061                 QDeclarativeMetaType::StringConverter con = QDeclarativeMetaType::customStringConverter(propertyType);
       
  1062                 if (con) {
       
  1063                     v = con(value.toString());
       
  1064                     if (v.userType() == propertyType)
       
  1065                         ok = true;
       
  1066                 }
       
  1067             }
       
  1068         }
       
  1069         if (ok) {
       
  1070             void *a[] = { (void *)v.constData(), 0, &status, &flags};
       
  1071             QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
       
  1072         } else {
       
  1073             return false;
       
  1074         }
       
  1075     }
       
  1076 
       
  1077     return true;
       
  1078 }
       
  1079 
       
  1080 const QMetaObject *QDeclarativePropertyPrivate::rawMetaObjectForType(QDeclarativeEnginePrivate *engine, int userType)
       
  1081 {
       
  1082     if (engine) {
       
  1083         return engine->rawMetaObjectForType(userType);
       
  1084     } else {
       
  1085         QDeclarativeType *type = QDeclarativeMetaType::qmlType(userType);
       
  1086         return type?type->baseMetaObject():0;
       
  1087     }
       
  1088 }
       
  1089 
       
  1090 /*!
       
  1091     Sets the property value to \a value and returns true.
       
  1092     Returns false if the property can't be set because the
       
  1093     \a value is the wrong type, for example.
       
  1094  */
       
  1095 bool QDeclarativeProperty::write(const QVariant &value) const
       
  1096 {
       
  1097     return QDeclarativePropertyPrivate::write(*this, value, 0);
       
  1098 }
       
  1099 
       
  1100 /*!
       
  1101   Writes \a value to the \a name property of \a object.  This method
       
  1102   is equivalent to:
       
  1103 
       
  1104   \code
       
  1105     QDeclarativeProperty p(object, name);
       
  1106     p.write(value);
       
  1107   \endcode
       
  1108 */
       
  1109 bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value)
       
  1110 {
       
  1111     QDeclarativeProperty p(object, name);
       
  1112     return p.write(value);
       
  1113 }
       
  1114 
       
  1115 /*!
       
  1116   Writes \a value to the \a name property of \a object using the
       
  1117   \l{QDeclarativeContext} {context} \a ctxt.  This method is
       
  1118   equivalent to:
       
  1119 
       
  1120   \code
       
  1121     QDeclarativeProperty p(object, name, ctxt);
       
  1122     p.write(value);
       
  1123   \endcode
       
  1124 */
       
  1125 bool QDeclarativeProperty::write(QObject *object,
       
  1126                                  const QString &name,
       
  1127                                  const QVariant &value, 
       
  1128                                  QDeclarativeContext *ctxt)
       
  1129 {
       
  1130     QDeclarativeProperty p(object, name, ctxt);
       
  1131     return p.write(value);
       
  1132 }
       
  1133 
       
  1134 /*!
       
  1135   
       
  1136   Writes \a value to the \a name property of \a object using the
       
  1137   environment for instantiating QML components that is provided by
       
  1138   \a engine.  This method is equivalent to:
       
  1139 
       
  1140   \code
       
  1141     QDeclarativeProperty p(object, name, engine);
       
  1142     p.write(value);
       
  1143   \endcode
       
  1144 */
       
  1145 bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value, 
       
  1146                                  QDeclarativeEngine *engine)
       
  1147 {
       
  1148     QDeclarativeProperty p(object, name, engine);
       
  1149     return p.write(value);
       
  1150 }
       
  1151 
       
  1152 /*!
       
  1153     Resets the property and returns true if the property is
       
  1154     resettable.  If the property is not resettable, nothing happens
       
  1155     and false is returned.
       
  1156 */
       
  1157 bool QDeclarativeProperty::reset() const
       
  1158 {
       
  1159     if (isResettable()) {
       
  1160         void *args[] = { 0 };
       
  1161         QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
       
  1162         return true;
       
  1163     } else {
       
  1164         return false;
       
  1165     }
       
  1166 }
       
  1167 
       
  1168 bool QDeclarativePropertyPrivate::write(const QDeclarativeProperty &that,
       
  1169                                             const QVariant &value, WriteFlags flags) 
       
  1170 {
       
  1171     if (that.d->object && that.type() & QDeclarativeProperty::Property && 
       
  1172         that.d->core.isValid() && that.isWritable()) 
       
  1173         return that.d->writeValueProperty(value, flags);
       
  1174     else 
       
  1175         return false;
       
  1176 }
       
  1177 
       
  1178 /*!
       
  1179     Returns true if the property has a change notifier signal, otherwise false.
       
  1180 */
       
  1181 bool QDeclarativeProperty::hasNotifySignal() const
       
  1182 {
       
  1183     if (type() & Property && d->object) {
       
  1184         return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
       
  1185     }
       
  1186     return false;
       
  1187 }
       
  1188 
       
  1189 /*!
       
  1190     Returns true if the property needs a change notifier signal for bindings
       
  1191     to remain upto date, false otherwise.
       
  1192 
       
  1193     Some properties, such as attached properties or those whose value never 
       
  1194     changes, do not require a change notifier.
       
  1195 */
       
  1196 bool QDeclarativeProperty::needsNotifySignal() const
       
  1197 {
       
  1198     return type() & Property && !property().isConstant();
       
  1199 }
       
  1200 
       
  1201 /*!
       
  1202     Connects the property's change notifier signal to the
       
  1203     specified \a method of the \a dest object and returns
       
  1204     true. Returns false if this metaproperty does not
       
  1205     represent a regular Qt property or if it has no
       
  1206     change notifier signal, or if the \a dest object does
       
  1207     not have the specified \a method.
       
  1208 */
       
  1209 bool QDeclarativeProperty::connectNotifySignal(QObject *dest, int method) const
       
  1210 {
       
  1211     if (!(type() & Property) || !d->object)
       
  1212         return false;
       
  1213 
       
  1214     QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
       
  1215     if (prop.hasNotifySignal()) {
       
  1216         return QMetaObject::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
       
  1217     } else {
       
  1218         return false;
       
  1219     }
       
  1220 }
       
  1221 
       
  1222 /*!
       
  1223     Connects the property's change notifier signal to the
       
  1224     specified \a slot of the \a dest object and returns
       
  1225     true. Returns false if this metaproperty does not
       
  1226     represent a regular Qt property or if it has no
       
  1227     change notifier signal, or if the \a dest object does
       
  1228     not have the specified \a slot.
       
  1229 */
       
  1230 bool QDeclarativeProperty::connectNotifySignal(QObject *dest, const char *slot) const
       
  1231 {
       
  1232     if (!(type() & Property) || !d->object)
       
  1233         return false;
       
  1234 
       
  1235     QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
       
  1236     if (prop.hasNotifySignal()) {
       
  1237         QByteArray signal(QByteArray("2") + prop.notifySignal().signature());
       
  1238         return QObject::connect(d->object, signal.constData(), dest, slot);
       
  1239     } else  {
       
  1240         return false;
       
  1241     }
       
  1242 }
       
  1243 
       
  1244 /*!
       
  1245     Return the Qt metaobject index of the property.
       
  1246 */
       
  1247 int QDeclarativeProperty::index() const
       
  1248 {
       
  1249     return d->core.coreIndex;
       
  1250 }
       
  1251 
       
  1252 int QDeclarativePropertyPrivate::valueTypeCoreIndex(const QDeclarativeProperty &that)
       
  1253 {
       
  1254     return that.d->valueType.valueTypeCoreIdx;
       
  1255 }
       
  1256 
       
  1257 /*!
       
  1258     Returns the "property index" for use in bindings.  The top 8 bits are the value type
       
  1259     offset, and 0 otherwise.  The bottom 24-bits are the regular property index.
       
  1260 */
       
  1261 int QDeclarativePropertyPrivate::bindingIndex(const QDeclarativeProperty &that)
       
  1262 {
       
  1263     int rv = that.d->core.coreIndex;
       
  1264     if (rv != -1 && that.d->valueType.valueTypeCoreIdx != -1)
       
  1265         rv = rv | (that.d->valueType.valueTypeCoreIdx << 24);
       
  1266     return rv;
       
  1267 }
       
  1268 
       
  1269 struct SerializedData {
       
  1270     bool isValueType;
       
  1271     QDeclarativePropertyCache::Data core;
       
  1272 };
       
  1273 
       
  1274 struct ValueTypeSerializedData : public SerializedData {
       
  1275     QDeclarativePropertyCache::ValueTypeData valueType;
       
  1276 };
       
  1277 
       
  1278 QByteArray QDeclarativePropertyPrivate::saveValueType(const QMetaObject *metaObject, int index, 
       
  1279                                                  const QMetaObject *subObject, int subIndex)
       
  1280 {
       
  1281     QMetaProperty prop = metaObject->property(index);
       
  1282     QMetaProperty subProp = subObject->property(subIndex);
       
  1283 
       
  1284     ValueTypeSerializedData sd;
       
  1285     sd.isValueType = true;
       
  1286     sd.core.load(metaObject->property(index));
       
  1287     sd.valueType.flags = QDeclarativePropertyCache::Data::flagsForProperty(subProp);
       
  1288     sd.valueType.valueTypeCoreIdx = subIndex;
       
  1289     sd.valueType.valueTypePropType = subProp.userType();
       
  1290 
       
  1291     QByteArray rv((const char *)&sd, sizeof(sd));
       
  1292 
       
  1293     return rv;
       
  1294 }
       
  1295 
       
  1296 QByteArray QDeclarativePropertyPrivate::saveProperty(const QMetaObject *metaObject, int index)
       
  1297 {
       
  1298     SerializedData sd;
       
  1299     sd.isValueType = false;
       
  1300     sd.core.load(metaObject->property(index));
       
  1301 
       
  1302     QByteArray rv((const char *)&sd, sizeof(sd));
       
  1303     return rv;
       
  1304 }
       
  1305 
       
  1306 QDeclarativeProperty 
       
  1307 QDeclarativePropertyPrivate::restore(const QByteArray &data, QObject *object, QDeclarativeContextData *ctxt)
       
  1308 {
       
  1309     QDeclarativeProperty prop;
       
  1310 
       
  1311     if (data.isEmpty())
       
  1312         return prop;
       
  1313 
       
  1314     prop.d->object = object;
       
  1315     prop.d->context = ctxt;
       
  1316     prop.d->engine = ctxt->engine;
       
  1317 
       
  1318     const SerializedData *sd = (const SerializedData *)data.constData();
       
  1319     if (sd->isValueType) {
       
  1320         const ValueTypeSerializedData *vt = (const ValueTypeSerializedData *)sd;
       
  1321         prop.d->core = vt->core;
       
  1322         prop.d->valueType = vt->valueType;
       
  1323     } else {
       
  1324         prop.d->core = sd->core;
       
  1325     }
       
  1326 
       
  1327     return prop;
       
  1328 }
       
  1329 
       
  1330 /*!
       
  1331     Returns true if lhs and rhs refer to the same metaobject data
       
  1332 */
       
  1333 bool QDeclarativePropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs)
       
  1334 {
       
  1335     return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
       
  1336 }
       
  1337 
       
  1338 /*!
       
  1339     Returns true if from inherits to.
       
  1340 */
       
  1341 bool QDeclarativePropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to)
       
  1342 {
       
  1343     if (from && to == &QObject::staticMetaObject)
       
  1344         return true;
       
  1345 
       
  1346     while (from) {
       
  1347         if (equal(from, to))
       
  1348             return true;
       
  1349         from = from->superClass();
       
  1350     }
       
  1351     
       
  1352     return false;
       
  1353 }
       
  1354 
       
  1355 /*!
       
  1356     Return the signal corresponding to \a name
       
  1357 */
       
  1358 QMetaMethod QDeclarativePropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
       
  1359 {
       
  1360     Q_ASSERT(mo);
       
  1361     int methods = mo->methodCount();
       
  1362     for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
       
  1363         QMetaMethod method = mo->method(ii);
       
  1364         QByteArray methodName = method.signature();
       
  1365         int idx = methodName.indexOf('(');
       
  1366         methodName = methodName.left(idx);
       
  1367 
       
  1368         if (methodName == name)
       
  1369             return method;
       
  1370     }
       
  1371 
       
  1372     // If no signal is found, but the signal is of the form "onBlahChanged",
       
  1373     // return the notify signal for the property "Blah"
       
  1374     if (name.endsWith("Changed")) {
       
  1375         QByteArray propName = name.mid(0, name.length() - 7);
       
  1376         int propIdx = mo->indexOfProperty(propName.constData());
       
  1377         if (propIdx >= 0) {
       
  1378             QMetaProperty prop = mo->property(propIdx);
       
  1379             if (prop.hasNotifySignal())
       
  1380                 return prop.notifySignal();
       
  1381         }
       
  1382     }
       
  1383 
       
  1384     return QMetaMethod();
       
  1385 }
       
  1386 
       
  1387 QT_END_NAMESPACE