1 /****************************************************************************
3 ** Copyright (C) 2010 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 QtScript module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL-ONLY$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser
12 ** General Public License version 2.1 as published by the Free Software
13 ** Foundation and appearing in the file LICENSE.LGPL included in the
14 ** packaging of this file. Please review the following information to
15 ** ensure the GNU Lesser General Public License version 2.1 requirements
16 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** If you have questions regarding the use of this file, please contact
19 ** Nokia at qt-info@nokia.com.
22 ****************************************************************************/
25 #include "qscriptvalueiterator.h"
27 #include "qscriptstring.h"
28 #include "qscriptengine.h"
29 #include "qscriptengine_p.h"
30 #include "qscriptvalue_p.h"
31 #include "qlinkedlist.h"
35 #include "PropertyNameArray.h"
37 #include "JSFunction.h"
43 \class QScriptValueIterator
45 \brief The QScriptValueIterator class provides a Java-style iterator for QScriptValue.
50 The QScriptValueIterator constructor takes a QScriptValue as
51 argument. After construction, the iterator is located at the very
52 beginning of the sequence of properties. Here's how to iterate over
53 all the properties of a QScriptValue:
55 \snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 0
57 The next() advances the iterator. The name(), value() and flags()
58 functions return the name, value and flags of the last item that was
61 If you want to remove properties as you iterate over the
62 QScriptValue, use remove(). If you want to modify the value of a
63 property, use setValue().
65 Note that QScriptValueIterator only iterates over the QScriptValue's
66 own properties; i.e. it does not follow the prototype chain. You can
67 use a loop like this to follow the prototype chain:
69 \snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 1
71 Note that QScriptValueIterator will not automatically skip over
72 properties that have the QScriptValue::SkipInEnumeration flag set;
73 that flag only affects iteration in script code. If you want, you
74 can skip over such properties with code like the following:
76 \snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 2
78 \sa QScriptValue::property()
81 class QScriptValueIteratorPrivate
84 QScriptValueIteratorPrivate()
88 ~QScriptValueIteratorPrivate()
92 QScriptEnginePrivate *eng_p = engine();
95 QScript::APIShim shim(eng_p);
96 propertyNames.clear(); //destroying the identifiers need to be done under the APIShim guard
99 QScriptValuePrivate *object() const
101 return QScriptValuePrivate::get(objectValue);
104 QScriptEnginePrivate *engine() const
106 return QScriptEnginePrivate::get(objectValue.engine());
109 void ensureInitialized()
113 QScriptEnginePrivate *eng_p = engine();
114 QScript::APIShim shim(eng_p);
115 JSC::ExecState *exec = eng_p->globalExec();
116 JSC::PropertyNameArray propertyNamesArray(exec);
117 JSC::asObject(object()->jscValue)->getOwnPropertyNames(exec, propertyNamesArray, JSC::IncludeDontEnumProperties);
119 JSC::PropertyNameArray::const_iterator propertyNamesIt = propertyNamesArray.begin();
120 for(; propertyNamesIt != propertyNamesArray.end(); ++propertyNamesIt) {
121 propertyNames.append(*propertyNamesIt);
123 it = propertyNames.begin();
127 QScriptValue objectValue;
128 QLinkedList<JSC::Identifier> propertyNames;
129 QLinkedList<JSC::Identifier>::iterator it;
130 QLinkedList<JSC::Identifier>::iterator current;
135 Constructs an iterator for traversing \a object. The iterator is
136 set to be at the front of the sequence of properties (before the
139 QScriptValueIterator::QScriptValueIterator(const QScriptValue &object)
142 if (object.isObject()) {
143 d_ptr.reset(new QScriptValueIteratorPrivate());
144 d_ptr->objectValue = object;
149 Destroys the iterator.
151 QScriptValueIterator::~QScriptValueIterator()
153 Q_D(QScriptValueIterator);
154 if (d && d->engine()) {
155 // Make sure identifiers are removed from the correct engine.
156 QScript::APIShim shim(d->engine());
157 d->propertyNames.clear();
162 Returns true if there is at least one item ahead of the iterator
163 (i.e. the iterator is \e not at the back of the property sequence);
164 otherwise returns false.
166 \sa next(), hasPrevious()
168 bool QScriptValueIterator::hasNext() const
170 Q_D(const QScriptValueIterator);
174 const_cast<QScriptValueIteratorPrivate*>(d)->ensureInitialized();
175 return d->it != d->propertyNames.end();
179 Advances the iterator by one position.
181 Calling this function on an iterator located at the back of the
182 container leads to undefined results.
184 \sa hasNext(), previous(), name()
186 void QScriptValueIterator::next()
188 Q_D(QScriptValueIterator);
191 d->ensureInitialized();
198 Returns true if there is at least one item behind the iterator
199 (i.e. the iterator is \e not at the front of the property sequence);
200 otherwise returns false.
202 \sa previous(), hasNext()
204 bool QScriptValueIterator::hasPrevious() const
206 Q_D(const QScriptValueIterator);
210 const_cast<QScriptValueIteratorPrivate*>(d)->ensureInitialized();
211 return d->it != d->propertyNames.begin();
215 Moves the iterator back by one position.
217 Calling this function on an iterator located at the front of the
218 container leads to undefined results.
220 \sa hasPrevious(), next(), name()
222 void QScriptValueIterator::previous()
224 Q_D(QScriptValueIterator);
227 d->ensureInitialized();
233 Moves the iterator to the front of the QScriptValue (before the
238 void QScriptValueIterator::toFront()
240 Q_D(QScriptValueIterator);
243 d->ensureInitialized();
244 d->it = d->propertyNames.begin();
248 Moves the iterator to the back of the QScriptValue (after the
251 \sa toFront(), previous()
253 void QScriptValueIterator::toBack()
255 Q_D(QScriptValueIterator);
258 d->ensureInitialized();
259 d->it = d->propertyNames.end();
263 Returns the name of the last property that was jumped over using
264 next() or previous().
268 QString QScriptValueIterator::name() const
270 Q_D(const QScriptValueIterator);
271 if (!d || !d->initialized || !d->engine())
273 return d->current->ustring();
279 Returns the name of the last property that was jumped over using
280 next() or previous().
282 QScriptString QScriptValueIterator::scriptName() const
284 Q_D(const QScriptValueIterator);
285 if (!d || !d->initialized || !d->engine())
286 return QScriptString();
287 return d->engine()->toStringHandle(*d->current);
291 Returns the value of the last property that was jumped over using
292 next() or previous().
294 \sa setValue(), name()
296 QScriptValue QScriptValueIterator::value() const
298 Q_D(const QScriptValueIterator);
299 if (!d || !d->initialized || !d->engine())
300 return QScriptValue();
301 QScript::APIShim shim(d->engine());
302 JSC::JSValue jsValue = d->object()->property(*d->current);
303 return d->engine()->scriptValueFromJSCValue(jsValue);
307 Sets the \a value of the last property that was jumped over using
308 next() or previous().
312 void QScriptValueIterator::setValue(const QScriptValue &value)
314 Q_D(QScriptValueIterator);
315 if (!d || !d->initialized || !d->engine())
317 QScript::APIShim shim(d->engine());
318 JSC::JSValue jsValue = d->engine()->scriptValueToJSCValue(value);
319 d->object()->setProperty(*d->current, jsValue);
323 Returns the flags of the last property that was jumped over using
324 next() or previous().
328 QScriptValue::PropertyFlags QScriptValueIterator::flags() const
330 Q_D(const QScriptValueIterator);
331 if (!d || !d->initialized || !d->engine())
333 QScript::APIShim shim(d->engine());
334 return d->object()->propertyFlags(*d->current);
338 Removes the last property that was jumped over using next()
343 void QScriptValueIterator::remove()
345 Q_D(QScriptValueIterator);
346 if (!d || !d->initialized || !d->engine())
348 QScript::APIShim shim(d->engine());
349 d->object()->setProperty(*d->current, JSC::JSValue());
350 d->propertyNames.erase(d->current);
354 Makes the iterator operate on \a object. The iterator is set to be
355 at the front of the sequence of properties (before the first
358 QScriptValueIterator& QScriptValueIterator::operator=(QScriptValue &object)
361 if (object.isObject()) {
362 d_ptr.reset(new QScriptValueIteratorPrivate());
363 d_ptr->objectValue = object;