1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** 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)
184 u.setEncodedUrl(e->toString(v->ToString()).toUtf8(), QUrl::TolerantMode);
188 static v8::Handle<v8::Value> convertUrlToV8Value(QV8Engine *e, const QUrl &v)
190 return e->toString(v.toEncoded());
193 static QString convertUrlToString(QV8Engine *, const QUrl &v)
201 \class QV8<Type>SequenceResource
202 \brief The external resource used in sequence type objects
204 Every sequence type object returned by QV8SequenceWrapper::newSequence() has
205 a QV8<Type>SequenceResource which contains a property index and a pointer
206 to the object which contains the property.
208 Every sequence type object returned by QV8SequenceWrapper::fromVariant() has
209 a QV8<Type>SequenceResource which contains a copy of the sequence value.
210 Operations on the sequence are implemented directly in terms of that sequence data.
212 There exists one QV8<Type>SequenceResource instance for every JavaScript Object
213 (sequence) instance returned from QV8SequenceWrapper::newSequence() or
214 QV8SequenceWrapper::fromVariant().
217 // F(elementType, elementTypeName, sequenceType, defaultValue)
218 #define FOREACH_QML_SEQUENCE_TYPE(F) \
219 F(int, Int, QList<int>, 0) \
220 F(qreal, Real, QList<qreal>, 0.0) \
221 F(bool, Bool, QList<bool>, false) \
222 F(QString, String, QList<QString>, QString()) \
223 F(QString, QString, QStringList, QString()) \
224 F(QUrl, Url, QList<QUrl>, QUrl())
226 #define QML_SEQUENCE_TYPE_RESOURCE(SequenceElementType, SequenceElementTypeName, SequenceType, DefaultValue, ConversionToV8fn, ConversionFromV8fn, ToStringfn) \
228 Q_DECLARE_METATYPE(SequenceType) \
230 class QV8##SequenceElementTypeName##SequenceResource : public QV8SequenceResource { \
232 QV8##SequenceElementTypeName##SequenceResource(QV8Engine *engine, QObject *obj, int propIdx) \
233 : QV8SequenceResource(engine, QV8SequenceResource::Reference, #SequenceType, qMetaTypeId<SequenceType>(), qMetaTypeId<SequenceElementType>()) \
234 , object(obj), propertyIndex(propIdx) \
237 QV8##SequenceElementTypeName##SequenceResource(QV8Engine *engine, const SequenceType &value) \
238 : QV8SequenceResource(engine, QV8SequenceResource::Copy, #SequenceType, qMetaTypeId<SequenceType>(), qMetaTypeId<SequenceElementType>()) \
239 , object(0), propertyIndex(-1), c(value) \
242 ~QV8##SequenceElementTypeName##SequenceResource() \
245 static QVariant toVariant(QV8Engine *e, v8::Handle<v8::Array> array, uint32_t length, bool *succeeded) \
248 for (uint32_t ii = 0; ii < length; ++ii) { \
249 list.append(ConversionFromV8fn(e, array->Get(ii))); \
252 return QVariant::fromValue<SequenceType>(list); \
254 QVariant toVariant() \
256 if (objectType == QV8SequenceResource::Reference) { \
261 return QVariant::fromValue<SequenceType>(c); \
263 bool isEqual(const QV8SequenceResource *v) \
265 /* Note: two different sequences can never be equal (even if they */ \
266 /* contain the same elements in the same order) in order to */ \
267 /* maintain JavaScript semantics. However, if they both reference */ \
268 /* the same QObject+propertyIndex, they are equal. */ \
269 if (objectType == QV8SequenceResource::Reference && v->objectType == QV8SequenceResource::Reference) { \
270 if (sequenceMetaTypeId == v->sequenceMetaTypeId) { \
271 const QV8##SequenceElementTypeName##SequenceResource *rhs = static_cast<const QV8##SequenceElementTypeName##SequenceResource *>(v); \
272 return (object != 0 && object == rhs->object && propertyIndex == rhs->propertyIndex); \
274 } else if (objectType == QV8SequenceResource::Copy && v->objectType == QV8SequenceResource::Copy) { \
275 if (sequenceMetaTypeId == v->sequenceMetaTypeId) { \
276 const QV8##SequenceElementTypeName##SequenceResource *rhs = static_cast<const QV8##SequenceElementTypeName##SequenceResource *>(v); \
277 return (this == rhs); \
282 quint32 lengthGetter() \
284 if (objectType == QV8SequenceResource::Reference) { \
291 void lengthSetter(v8::Handle<v8::Value> value) \
293 /* Get the new required length */ \
294 if (value.IsEmpty() || !value->IsUint32()) \
296 quint32 newLength = value->Uint32Value(); \
297 /* Read the sequence from the QObject property if we're a reference */ \
298 if (objectType == QV8SequenceResource::Reference) { \
301 void *a[] = { &c, 0 }; \
302 QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \
304 /* Determine whether we need to modify the sequence */ \
305 quint32 count = c.count(); \
306 if (newLength == count) { \
308 } else if (newLength > count) { \
309 /* according to ECMA262r3 we need to insert */ \
310 /* undefined values increasing length to newLength. */ \
311 /* We cannot, so we insert default-values instead. */ \
312 while (newLength > count++) { \
313 c.append(DefaultValue); \
316 /* according to ECMA262r3 we need to remove */ \
317 /* elements until the sequence is the required length. */ \
318 while (newLength < count) { \
323 /* write back if required. */ \
324 if (objectType == QV8SequenceResource::Reference) { \
325 /* write back. already checked that object is non-null, so skip that check here. */ \
327 QDeclarativePropertyPrivate::WriteFlags flags = QDeclarativePropertyPrivate::DontRemoveBinding; \
328 void *a[] = { &c, 0, &status, &flags }; \
329 QMetaObject::metacall(object, QMetaObject::WriteProperty, propertyIndex, a); \
333 v8::Handle<v8::Value> indexedSetter(quint32 index, v8::Handle<v8::Value> value) \
335 if (objectType == QV8SequenceResource::Reference) { \
337 return v8::Undefined(); \
340 /* modify the sequence */ \
341 SequenceElementType elementValue = ConversionFromV8fn(engine, value); \
342 quint32 count = c.count(); \
343 if (index == count) { \
344 c.append(elementValue); \
345 } else if (index < count) { \
346 c[index] = elementValue; \
348 /* according to ECMA262r3 we need to insert */ \
349 /* the value at the given index, increasing length to index+1. */ \
350 while (index > count++) { \
351 c.append(DefaultValue); \
353 c.append(elementValue); \
355 /* write back. already checked that object is non-null, so skip that check here. */ \
356 if (objectType == QV8SequenceResource::Reference) \
360 v8::Handle<v8::Value> indexedGetter(quint32 index) \
362 if (objectType == QV8SequenceResource::Reference) { \
364 return v8::Undefined(); \
367 quint32 count = c.count(); \
369 return ConversionToV8fn(engine, c.at(index)); \
370 return v8::Undefined(); \
372 v8::Handle<v8::Boolean> indexedDeleter(quint32 index) \
374 if (objectType == QV8SequenceResource::Reference) { \
376 return v8::Boolean::New(false); \
377 void *a[] = { &c, 0 }; \
378 QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \
380 if (index < c.count()) { \
381 /* according to ECMA262r3 it should be Undefined, */ \
382 /* but we cannot, so we insert a default-value instead. */ \
383 c.replace(index, DefaultValue); \
384 if (objectType == QV8SequenceResource::Reference) { \
385 /* write back. already checked that object is non-null, so skip that check here. */ \
387 QDeclarativePropertyPrivate::WriteFlags flags = QDeclarativePropertyPrivate::DontRemoveBinding; \
388 void *a[] = { &c, 0, &status, &flags }; \
389 QMetaObject::metacall(object, QMetaObject::WriteProperty, propertyIndex, a); \
391 return v8::Boolean::New(true); \
393 return v8::Boolean::New(false); \
395 v8::Handle<v8::Array> indexedEnumerator() \
397 if (objectType == QV8SequenceResource::Reference) { \
399 return v8::Handle<v8::Array>(); \
402 quint32 count = c.count(); \
403 v8::Local<v8::Array> retn = v8::Array::New(count); \
404 for (quint32 i = 0; i < count; ++i) { \
405 retn->Set(i, v8::Integer::NewFromUnsigned(i)); \
409 v8::Handle<v8::Value> toString() \
411 if (objectType == QV8SequenceResource::Reference) { \
413 return v8::Undefined(); \
417 quint32 count = c.count(); \
418 for (quint32 i = 0; i < count; ++i) { \
419 str += QString(QLatin1String("%1,")).arg(ToStringfn(engine, c[i])); \
422 return engine->toString(str); \
424 void loadReference() \
427 Q_ASSERT(objectType == QV8SequenceResource::Reference); \
428 void *a[] = { &c, 0 }; \
429 QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \
431 void storeReference() \
434 Q_ASSERT(objectType == QV8SequenceResource::Reference); \
436 QDeclarativePropertyPrivate::WriteFlags flags = \
437 QDeclarativePropertyPrivate::DontRemoveBinding; \
438 void *a[] = { &c, 0, &status, &flags }; \
439 QMetaObject::metacall(object, QMetaObject::WriteProperty, propertyIndex, a); \
442 QDeclarativeGuard<QObject> object; \
447 #define GENERATE_QML_SEQUENCE_TYPE_RESOURCE(ElementType, ElementTypeName, SequenceType, DefaultValue) \
448 QML_SEQUENCE_TYPE_RESOURCE(ElementType, ElementTypeName, SequenceType, DefaultValue, convert##ElementTypeName##ToV8Value, convertV8ValueTo##ElementTypeName, convert##ElementTypeName##ToString)
450 FOREACH_QML_SEQUENCE_TYPE(GENERATE_QML_SEQUENCE_TYPE_RESOURCE)
451 #undef GENERATE_QML_SEQUENCE_TYPE_RESOURCE
452 #undef QML_SEQUENCE_TYPE_RESOURCE
456 #endif // QV8SEQUENCEWRAPPER_P_P_H