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