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