source: trunk/src/declarative/qml/qdeclarativeproperty.cpp@ 1147

Last change on this file since 1147 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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