1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #ifndef QV8SEQUENCEWRAPPER_P_P_H
43 #define QV8SEQUENCEWRAPPER_P_P_H
49 // This file is not part of the Qt API. It exists purely as an
50 // implementation detail. This header file may change from version to
51 // version without notice, or even be removed.
56 #include <private/qdeclarativeengine_p.h>
57 #include <private/qdeclarativemetatype_p.h>
63 \class QV8SequenceResource
64 \brief The abstract base class of the external resource used in sequence type objects
66 Every sequence type object returned by QV8SequenceWrapper::fromVariant() or
67 QV8SequenceWrapper::newSequence() has a type-specific QV8SequenceResource which
68 contains the type name, the meta type ids of the sequence and sequence element
69 types, as well as either the sequence data (copy) or object pointer and property
70 index (reference) data associated with the sequence.
72 class QV8SequenceResource : public QV8ObjectResource
74 V8_RESOURCE_TYPE(SequenceType);
77 virtual ~QV8SequenceResource() {}
79 enum ObjectType { Reference, Copy };
81 virtual QVariant toVariant() = 0;
82 virtual bool isEqual(const QV8SequenceResource *v) = 0;
84 virtual quint32 lengthGetter() = 0;
85 virtual void lengthSetter(v8::Handle<v8::Value> value) = 0;
86 virtual v8::Handle<v8::Value> indexedSetter(quint32 index, v8::Handle<v8::Value> value) = 0;
87 virtual v8::Handle<v8::Value> indexedGetter(quint32 index) = 0;
88 virtual v8::Handle<v8::Boolean> indexedDeleter(quint32 index) = 0;
89 virtual v8::Handle<v8::Array> indexedEnumerator() = 0;
90 virtual v8::Handle<v8::Value> toString() = 0;
92 ObjectType objectType;
94 int sequenceMetaTypeId;
95 int elementMetaTypeId;
98 QV8SequenceResource(QV8Engine *engine, ObjectType type, const QByteArray &name, int sequenceId, int elementId)
99 : QV8ObjectResource(engine), objectType(type), typeName(name), sequenceMetaTypeId(sequenceId), elementMetaTypeId(elementId)
104 static int convertV8ValueToInt(QV8Engine *, v8::Handle<v8::Value> v)
106 return v->Int32Value();
109 static v8::Handle<v8::Value> convertIntToV8Value(QV8Engine *, int v)
111 return v8::Integer::New(v);
114 static QString convertIntToString(QV8Engine *, int v)
116 return QString::number(v);
119 static qreal convertV8ValueToReal(QV8Engine *, v8::Handle<v8::Value> v)
121 return v->NumberValue();
124 static v8::Handle<v8::Value> convertRealToV8Value(QV8Engine *, qreal v)
126 return v8::Number::New(v);
129 static QString convertRealToString(QV8Engine *, qreal v)
131 return QString::number(v);
134 static bool convertV8ValueToBool(QV8Engine *, v8::Handle<v8::Value> v)
136 return v->BooleanValue();
139 static v8::Handle<v8::Value> convertBoolToV8Value(QV8Engine *, bool v)
141 return v8::Boolean::New(v);
144 static QString convertBoolToString(QV8Engine *, bool v)
147 return QLatin1String("true");
148 return QLatin1String("false");
151 static QString convertV8ValueToString(QV8Engine *e, v8::Handle<v8::Value> v)
153 return e->toString(v->ToString());
156 static v8::Handle<v8::Value> convertStringToV8Value(QV8Engine *e, const QString &v)
158 return e->toString(v);
161 static QString convertStringToString(QV8Engine *, const QString &v)
166 static QString convertV8ValueToQString(QV8Engine *e, v8::Handle<v8::Value> v)
168 return e->toString(v->ToString());
171 static v8::Handle<v8::Value> convertQStringToV8Value(QV8Engine *e, const QString &v)
173 return e->toString(v);
176 static QString convertQStringToString(QV8Engine *, const QString &v)
181 static QUrl convertV8ValueToUrl(QV8Engine *e, v8::Handle<v8::Value> v)
183 return QUrl(e->toString(v->ToString()));
186 static v8::Handle<v8::Value> convertUrlToV8Value(QV8Engine *e, const QUrl &v)
188 return e->toString(v.toString());
191 static QString convertUrlToString(QV8Engine *, const QUrl &v)
199 \class QV8<Type>SequenceResource
200 \brief The external resource used in sequence type objects
202 Every sequence type object returned by QV8SequenceWrapper::newSequence() has
203 a QV8<Type>SequenceResource which contains a property index and a pointer
204 to the object which contains the property.
206 Every sequence type object returned by QV8SequenceWrapper::fromVariant() has
207 a QV8<Type>SequenceResource which contains a copy of the sequence value.
208 Operations on the sequence are implemented directly in terms of that sequence data.
210 There exists one QV8<Type>SequenceResource instance for every JavaScript Object
211 (sequence) instance returned from QV8SequenceWrapper::newSequence() or
212 QV8SequenceWrapper::fromVariant().
215 // F(elementType, elementTypeName, sequenceType, defaultValue)
216 #define FOREACH_QML_SEQUENCE_TYPE(F) \
217 F(int, Int, QList<int>, 0) \
218 F(qreal, Real, QList<qreal>, 0.0) \
219 F(bool, Bool, QList<bool>, false) \
220 F(QString, String, QList<QString>, QString()) \
221 F(QString, QString, QStringList, QString()) \
222 F(QUrl, Url, QList<QUrl>, QUrl())
224 #define QML_SEQUENCE_TYPE_RESOURCE(SequenceElementType, SequenceElementTypeName, SequenceType, DefaultValue, ConversionToV8fn, ConversionFromV8fn, ToStringfn) \
226 Q_DECLARE_METATYPE(SequenceType) \
228 class QV8##SequenceElementTypeName##SequenceResource : public QV8SequenceResource { \
230 QV8##SequenceElementTypeName##SequenceResource(QV8Engine *engine, QObject *obj, int propIdx) \
231 : QV8SequenceResource(engine, QV8SequenceResource::Reference, #SequenceType, qMetaTypeId<SequenceType>(), qMetaTypeId<SequenceElementType>()) \
232 , object(obj), propertyIndex(propIdx) \
235 QV8##SequenceElementTypeName##SequenceResource(QV8Engine *engine, const SequenceType &value) \
236 : QV8SequenceResource(engine, QV8SequenceResource::Copy, #SequenceType, qMetaTypeId<SequenceType>(), qMetaTypeId<SequenceElementType>()) \
237 , object(0), propertyIndex(-1), c(value) \
240 ~QV8##SequenceElementTypeName##SequenceResource() \
243 static QVariant toVariant(QV8Engine *e, v8::Handle<v8::Array> array, uint32_t length, bool *succeeded) \
246 for (uint32_t ii = 0; ii < length; ++ii) { \
247 list.append(ConversionFromV8fn(e, array->Get(ii))); \
250 return QVariant::fromValue<SequenceType>(list); \
252 QVariant toVariant() \
254 if (objectType == QV8SequenceResource::Reference) { \
259 return QVariant::fromValue<SequenceType>(c); \
261 bool isEqual(const QV8SequenceResource *v) \
263 /* Note: two different sequences can never be equal (even if they */ \
264 /* contain the same elements in the same order) in order to */ \
265 /* maintain JavaScript semantics. However, if they both reference */ \
266 /* the same QObject+propertyIndex, they are equal. */ \
267 if (objectType == QV8SequenceResource::Reference && v->objectType == QV8SequenceResource::Reference) { \
268 if (sequenceMetaTypeId == v->sequenceMetaTypeId) { \
269 const QV8##SequenceElementTypeName##SequenceResource *rhs = static_cast<const QV8##SequenceElementTypeName##SequenceResource *>(v); \
270 return (object != 0 && object == rhs->object && propertyIndex == rhs->propertyIndex); \
272 } else if (objectType == QV8SequenceResource::Copy && v->objectType == QV8SequenceResource::Copy) { \
273 if (sequenceMetaTypeId == v->sequenceMetaTypeId) { \
274 const QV8##SequenceElementTypeName##SequenceResource *rhs = static_cast<const QV8##SequenceElementTypeName##SequenceResource *>(v); \
275 return (this == rhs); \
280 quint32 lengthGetter() \
282 if (objectType == QV8SequenceResource::Reference) { \
289 void lengthSetter(v8::Handle<v8::Value> value) \
291 /* Get the new required length */ \
292 if (value.IsEmpty() || !value->IsUint32()) \
294 quint32 newLength = value->Uint32Value(); \
295 /* Read the sequence from the QObject property if we're a reference */ \
296 if (objectType == QV8SequenceResource::Reference) { \
299 void *a[] = { &c, 0 }; \
300 QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \
302 /* Determine whether we need to modify the sequence */ \
303 quint32 count = c.count(); \
304 if (newLength == count) { \
306 } else if (newLength > count) { \
307 /* according to ECMA262r3 we need to insert */ \
308 /* undefined values increasing length to newLength. */ \
309 /* We cannot, so we insert default-values instead. */ \
310 while (newLength > count++) { \
311 c.append(DefaultValue); \
314 /* according to ECMA262r3 we need to remove */ \
315 /* elements until the sequence is the required length. */ \
316 while (newLength < count) { \
321 /* write back if required. */ \
322 if (objectType == QV8SequenceResource::Reference) { \
323 /* write back. already checked that object is non-null, so skip that check here. */ \
325 QDeclarativePropertyPrivate::WriteFlags flags = QDeclarativePropertyPrivate::DontRemoveBinding; \
326 void *a[] = { &c, 0, &status, &flags }; \
327 QMetaObject::metacall(object, QMetaObject::WriteProperty, propertyIndex, a); \
331 v8::Handle<v8::Value> indexedSetter(quint32 index, v8::Handle<v8::Value> value) \
333 if (objectType == QV8SequenceResource::Reference) { \
335 return v8::Undefined(); \
338 /* modify the sequence */ \
339 SequenceElementType elementValue = ConversionFromV8fn(engine, value); \
340 quint32 count = c.count(); \
341 if (index == count) { \
342 c.append(elementValue); \
343 } else if (index < count) { \
344 c[index] = elementValue; \
346 /* according to ECMA262r3 we need to insert */ \
347 /* the value at the given index, increasing length to index+1. */ \
348 while (index > count++) { \
349 c.append(DefaultValue); \
351 c.append(elementValue); \
353 /* write back. already checked that object is non-null, so skip that check here. */ \
354 if (objectType == QV8SequenceResource::Reference) \
358 v8::Handle<v8::Value> indexedGetter(quint32 index) \
360 if (objectType == QV8SequenceResource::Reference) { \
362 return v8::Undefined(); \
365 quint32 count = c.count(); \
367 return ConversionToV8fn(engine, c.at(index)); \
368 return v8::Undefined(); \
370 v8::Handle<v8::Boolean> indexedDeleter(quint32 index) \
372 if (objectType == QV8SequenceResource::Reference) { \
374 return v8::Boolean::New(false); \
375 void *a[] = { &c, 0 }; \
376 QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \
378 if (index < c.count()) { \
379 /* according to ECMA262r3 it should be Undefined, */ \
380 /* but we cannot, so we insert a default-value instead. */ \
381 c.replace(index, DefaultValue); \
382 if (objectType == QV8SequenceResource::Reference) { \
383 /* write back. already checked that object is non-null, so skip that check here. */ \
385 QDeclarativePropertyPrivate::WriteFlags flags = QDeclarativePropertyPrivate::DontRemoveBinding; \
386 void *a[] = { &c, 0, &status, &flags }; \
387 QMetaObject::metacall(object, QMetaObject::WriteProperty, propertyIndex, a); \
389 return v8::Boolean::New(true); \
391 return v8::Boolean::New(false); \
393 v8::Handle<v8::Array> indexedEnumerator() \
395 if (objectType == QV8SequenceResource::Reference) { \
397 return v8::Handle<v8::Array>(); \
400 quint32 count = c.count(); \
401 v8::Local<v8::Array> retn = v8::Array::New(count); \
402 for (quint32 i = 0; i < count; ++i) { \
403 retn->Set(i, v8::Integer::NewFromUnsigned(i)); \
407 v8::Handle<v8::Value> toString() \
409 if (objectType == QV8SequenceResource::Reference) { \
411 return v8::Undefined(); \
415 quint32 count = c.count(); \
416 for (quint32 i = 0; i < count; ++i) { \
417 str += QString(QLatin1String("%1,")).arg(ToStringfn(engine, c[i])); \
420 return engine->toString(str); \
422 void loadReference() \
425 Q_ASSERT(objectType == QV8SequenceResource::Reference); \
426 void *a[] = { &c, 0 }; \
427 QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \
429 void storeReference() \
432 Q_ASSERT(objectType == QV8SequenceResource::Reference); \
434 QDeclarativePropertyPrivate::WriteFlags flags = \
435 QDeclarativePropertyPrivate::DontRemoveBinding; \
436 void *a[] = { &c, 0, &status, &flags }; \
437 QMetaObject::metacall(object, QMetaObject::WriteProperty, propertyIndex, a); \
440 QDeclarativeGuard<QObject> object; \
445 #define GENERATE_QML_SEQUENCE_TYPE_RESOURCE(ElementType, ElementTypeName, SequenceType, DefaultValue) \
446 QML_SEQUENCE_TYPE_RESOURCE(ElementType, ElementTypeName, SequenceType, DefaultValue, convert##ElementTypeName##ToV8Value, convertV8ValueTo##ElementTypeName, convert##ElementTypeName##ToString)
448 FOREACH_QML_SEQUENCE_TYPE(GENERATE_QML_SEQUENCE_TYPE_RESOURCE)
449 #undef GENERATE_QML_SEQUENCE_TYPE_RESOURCE
450 #undef QML_SEQUENCE_TYPE_RESOURCE
454 #endif // QV8SEQUENCEWRAPPER_P_P_H