1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml 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 https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://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 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qqmllistwrapper_p.h"
41#include <private/qqmllist_p.h>
42#include <private/qv4objectproto_p.h>
43#include <qv4objectiterator_p.h>
44
45#include <private/qv4functionobject_p.h>
46#include <private/qv4qobjectwrapper_p.h>
47
48QT_BEGIN_NAMESPACE
49
50using namespace QV4;
51
52DEFINE_OBJECT_VTABLE(QmlListWrapper);
53
54void Heap::QmlListWrapper::init()
55{
56 Object::init();
57 object.init();
58 QV4::Scope scope(internalClass->engine);
59 QV4::ScopedObject o(scope, this);
60 o->setArrayType(Heap::ArrayData::Custom);
61}
62
63void Heap::QmlListWrapper::destroy()
64{
65 object.destroy();
66 Object::destroy();
67}
68
69ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, QObject *object, int propId, int propType)
70{
71 if (!object || propId == -1)
72 return Encode::null();
73
74 Scope scope(engine);
75
76 Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocate<QmlListWrapper>());
77 r->d()->object = object;
78 r->d()->propertyType = propType;
79 void *args[] = { &r->d()->property(), nullptr };
80 QMetaObject::metacall(object, QMetaObject::ReadProperty, propId, args);
81 return r.asReturnedValue();
82}
83
84ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, const QQmlListProperty<QObject> &prop, int propType)
85{
86 Scope scope(engine);
87
88 Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocate<QmlListWrapper>());
89 r->d()->object = prop.object;
90 r->d()->property() = prop;
91 r->d()->propertyType = propType;
92 return r.asReturnedValue();
93}
94
95QVariant QmlListWrapper::toVariant() const
96{
97 if (!d()->object)
98 return QVariant();
99
100 return QVariant::fromValue(value: QQmlListReferencePrivate::init(d()->property(), d()->propertyType, engine()->qmlEngine()));
101}
102
103
104ReturnedValue QmlListWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
105{
106 Q_ASSERT(m->as<QmlListWrapper>());
107 const QmlListWrapper *w = static_cast<const QmlListWrapper *>(m);
108 QV4::ExecutionEngine *v4 = w->engine();
109
110 if (id.isArrayIndex()) {
111 uint index = id.asArrayIndex();
112 quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0;
113 if (index < count && w->d()->property().at) {
114 if (hasProperty)
115 *hasProperty = true;
116 return QV4::QObjectWrapper::wrap(engine: v4, object: w->d()->property().at(&w->d()->property(), index));
117 }
118
119 if (hasProperty)
120 *hasProperty = false;
121 return Value::undefinedValue().asReturnedValue();
122 }
123
124 if (id.isString() && id == v4->id_length()->propertyKey()) {
125 if (hasProperty)
126 *hasProperty = true;
127 quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0;
128 return Value::fromUInt32(i: count).asReturnedValue();
129 }
130
131 return Object::virtualGet(m, id, receiver, hasProperty);
132}
133
134bool QmlListWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
135{
136 Q_ASSERT(m->as<QmlListWrapper>());
137
138 const auto *w = static_cast<const QmlListWrapper *>(m);
139 QV4::ExecutionEngine *v4 = w->engine();
140
141 QQmlListProperty<QObject> *prop = &(w->d()->property());
142
143 if (id.isArrayIndex()) {
144 if (!prop->count || !prop->replace)
145 return false;
146
147 const uint index = id.asArrayIndex();
148 const int count = prop->count(prop);
149 if (count < 0 || index >= uint(count))
150 return false;
151
152 QV4::Scope scope(v4);
153 QV4::ScopedObject so(scope, value.toObject(e: scope.engine));
154 if (auto *wrapper = so->as<QV4::QObjectWrapper>()) {
155 prop->replace(prop, index, wrapper->object());
156 return true;
157 }
158
159 return false;
160 }
161
162 if (id.isString() && id == v4->id_length()->propertyKey()) {
163 if (!prop->count)
164 return false;
165
166 const quint32 count = prop->count(prop);
167
168 bool ok = false;
169 const uint newLength = value.asArrayLength(ok: &ok);
170 if (!ok)
171 return false;
172
173 if (newLength == 0) {
174 if (!prop->clear)
175 return false;
176 prop->clear(prop);
177 return true;
178 }
179
180 if (newLength < count) {
181 if (!prop->removeLast)
182 return false;
183
184 for (uint i = newLength; i < count; ++i)
185 prop->removeLast(prop);
186
187 return true;
188 }
189
190 if (!prop->append)
191 return false;
192
193 for (uint i = count; i < newLength; ++i)
194 prop->append(prop, nullptr);
195
196 return true;
197 }
198
199 return Object::virtualPut(m, id, value, receiver);
200}
201
202struct QmlListWrapperOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
203{
204 ~QmlListWrapperOwnPropertyKeyIterator() override = default;
205 PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override;
206
207};
208
209PropertyKey QmlListWrapperOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs)
210{
211 const QmlListWrapper *w = static_cast<const QmlListWrapper *>(o);
212
213 quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0;
214 if (arrayIndex < count) {
215 uint index = arrayIndex;
216 ++arrayIndex;
217 if (attrs)
218 *attrs = QV4::Attr_Data;
219 if (pd)
220 pd->value = QV4::QObjectWrapper::wrap(engine: w->engine(), object: w->d()->property().at(&w->d()->property(), index));
221 return PropertyKey::fromArrayIndex(idx: index);
222 }
223
224 return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
225}
226
227OwnPropertyKeyIterator *QmlListWrapper::virtualOwnPropertyKeys(const Object *m, Value *target)
228{
229 *target = *m;
230 return new QmlListWrapperOwnPropertyKeyIterator;
231}
232
233void PropertyListPrototype::init(ExecutionEngine *)
234{
235 defineDefaultProperty(QStringLiteral("push"), code: method_push, argumentCount: 1);
236}
237
238ReturnedValue PropertyListPrototype::method_push(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
239{
240 Scope scope(b);
241 ScopedObject instance(scope, thisObject->toObject(e: scope.engine));
242 if (!instance)
243 RETURN_UNDEFINED();
244 QmlListWrapper *w = instance->as<QmlListWrapper>();
245 if (!w)
246 RETURN_UNDEFINED();
247 if (!w->d()->property().append)
248 THROW_GENERIC_ERROR("List doesn't define an Append function");
249
250 QV4::ScopedObject so(scope);
251 for (int i = 0, ei = argc; i < ei; ++i)
252 {
253 so = argv[i].toObject(e: scope.engine);
254 if (QV4::QObjectWrapper *wrapper = so->as<QV4::QObjectWrapper>())
255 w->d()->property().append(&w->d()->property(), wrapper->object() );
256 }
257 return Encode::undefined();
258}
259
260QT_END_NAMESPACE
261

source code of qtdeclarative/src/qml/qml/qqmllistwrapper.cpp