Merge remote branch 'origin/4.5' into 4.6
[qt:qt.git] / src / script / api / qscriptvalueiterator.cpp
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 QtScript module of the Qt Toolkit.
8 **
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.
17 **
18 ** If you have questions regarding the use of this file, please contact
19 ** Nokia at qt-info@nokia.com.
20 ** $QT_END_LICENSE$
21 **
22 ****************************************************************************/
23
24 #include "config.h"
25 #include "qscriptvalueiterator.h"
26
27 #include "qscriptstring.h"
28 #include "qscriptengine.h"
29 #include "qscriptengine_p.h"
30 #include "qscriptvalue_p.h"
31 #include "qlinkedlist.h"
32
33
34 #include "JSObject.h"
35 #include "PropertyNameArray.h"
36 #include "JSArray.h"
37 #include "JSFunction.h"
38
39 QT_BEGIN_NAMESPACE
40
41 /*!
42   \since 4.3
43   \class QScriptValueIterator
44
45   \brief The QScriptValueIterator class provides a Java-style iterator for QScriptValue.
46
47   \ingroup script
48
49
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:
54
55   \snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 0
56
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
59   jumped over.
60
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().
64
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:
68
69   \snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 1
70
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:
75
76   \snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 2
77
78   \sa QScriptValue::property()
79 */
80
81 class QScriptValueIteratorPrivate
82 {
83 public:
84     QScriptValueIteratorPrivate()
85         : initialized(false)
86     {}
87     void ensureInitialized()
88     {
89         if (initialized)
90             return;
91         QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(object.engine());
92         JSC::ExecState *exec = eng_p->globalExec();
93         JSC::PropertyNameArray propertyNamesArray(exec);
94         propertyNamesArray.setShouldCache(false);
95         JSC::asObject(QScriptValuePrivate::get(object)->jscValue)->getOwnPropertyNames(exec, propertyNamesArray, /*includeNonEnumerable=*/true);
96
97         JSC::PropertyNameArray::const_iterator propertyNamesIt = propertyNamesArray.begin();
98         for(; propertyNamesIt != propertyNamesArray.end(); ++propertyNamesIt) {
99             propertyNames.append(propertyNamesIt->ustring());
100         }
101         it = propertyNames.begin();
102         initialized = true;
103     }
104
105     QScriptValue object;
106     QLinkedList<JSC::UString> propertyNames;
107     QLinkedList<JSC::UString>::iterator it;
108     QLinkedList<JSC::UString>::iterator current;
109     bool initialized;
110 };
111
112 /*!
113   Constructs an iterator for traversing \a object. The iterator is
114   set to be at the front of the sequence of properties (before the
115   first property).
116 */
117 QScriptValueIterator::QScriptValueIterator(const QScriptValue &object)
118     : d_ptr(0)
119 {
120     if (object.isObject()) {
121         d_ptr.reset(new QScriptValueIteratorPrivate());
122         d_ptr->object = object;
123     }
124 }
125
126 /*!
127   Destroys the iterator.
128 */
129 QScriptValueIterator::~QScriptValueIterator()
130 {
131 }
132
133 /*!
134   Returns true if there is at least one item ahead of the iterator
135   (i.e. the iterator is \e not at the back of the property sequence);
136   otherwise returns false.
137
138   \sa next(), hasPrevious()
139 */
140 bool QScriptValueIterator::hasNext() const
141 {
142     Q_D(const QScriptValueIterator);
143     if (!d)
144         return false;
145
146     const_cast<QScriptValueIteratorPrivate*>(d)->ensureInitialized();
147     return d->it != d->propertyNames.end();
148 }
149
150 /*!
151   Advances the iterator by one position.
152
153   Calling this function on an iterator located at the back of the
154   container leads to undefined results.
155
156   \sa hasNext(), previous(), name()
157 */
158 void QScriptValueIterator::next()
159 {
160     Q_D(QScriptValueIterator);
161     if (!d)
162         return;
163     d->ensureInitialized();
164
165     d->current = d->it;
166     ++(d->it);
167 }
168
169 /*!
170   Returns true if there is at least one item behind the iterator
171   (i.e. the iterator is \e not at the front of the property sequence);
172   otherwise returns false.
173
174   \sa previous(), hasNext()
175 */
176 bool QScriptValueIterator::hasPrevious() const
177 {
178     Q_D(const QScriptValueIterator);
179     if (!d)
180         return false;
181
182     const_cast<QScriptValueIteratorPrivate*>(d)->ensureInitialized();
183     return d->it != d->propertyNames.begin();
184 }
185
186 /*!
187   Moves the iterator back by one position.
188
189   Calling this function on an iterator located at the front of the
190   container leads to undefined results.
191
192   \sa hasPrevious(), next(), name()
193 */
194 void QScriptValueIterator::previous()
195 {
196     Q_D(QScriptValueIterator);
197     if (!d)
198         return;
199     d->ensureInitialized();
200     --(d->it);
201     d->current = d->it;
202 }
203
204 /*!
205   Moves the iterator to the front of the QScriptValue (before the
206   first property).
207
208   \sa toBack(), next()
209 */
210 void QScriptValueIterator::toFront()
211 {
212     Q_D(QScriptValueIterator);
213     if (!d)
214         return;
215     d->ensureInitialized();
216     d->it = d->propertyNames.begin();
217 }
218
219 /*!
220   Moves the iterator to the back of the QScriptValue (after the
221   last property).
222
223   \sa toFront(), previous()
224 */
225 void QScriptValueIterator::toBack()
226 {
227     Q_D(QScriptValueIterator);
228     if (!d)
229         return;
230     d->ensureInitialized();
231     d->it = d->propertyNames.end();
232 }
233
234 /*!
235   Returns the name of the last property that was jumped over using
236   next() or previous().
237
238   \sa value(), flags()
239 */
240 QString QScriptValueIterator::name() const
241 {
242     Q_D(const QScriptValueIterator);
243     if (!d || !d->initialized)
244         return QString();
245     return *d->current;
246 }
247
248 /*!
249   \since 4.4
250
251   Returns the name of the last property that was jumped over using
252   next() or previous().
253 */
254 QScriptString QScriptValueIterator::scriptName() const
255 {
256     Q_D(const QScriptValueIterator);
257     if (!d || !d->initialized)
258         return QScriptString();
259     return d->object.engine()->toStringHandle(name());
260 }
261
262 /*!
263   Returns the value of the last property that was jumped over using
264   next() or previous().
265
266   \sa setValue(), name()
267 */
268 QScriptValue QScriptValueIterator::value() const
269 {
270     Q_D(const QScriptValueIterator);
271     if (!d || !d->initialized)
272         return QScriptValue();
273     return d->object.property(name());
274 }
275
276 /*!
277   Sets the \a value of the last property that was jumped over using
278   next() or previous().
279
280   \sa value(), name()
281 */
282 void QScriptValueIterator::setValue(const QScriptValue &value)
283 {
284     Q_D(QScriptValueIterator);
285     if (!d || !d->initialized)
286         return;
287     d->object.setProperty(name(), value);
288 }
289
290 /*!
291   Returns the flags of the last property that was jumped over using
292   next() or previous().
293
294   \sa value()
295 */
296 QScriptValue::PropertyFlags QScriptValueIterator::flags() const
297 {
298     Q_D(const QScriptValueIterator);
299     if (!d || !d->initialized)
300         return 0;
301     return d->object.propertyFlags(name());
302 }
303
304 /*!
305   Removes the last property that was jumped over using next()
306   or previous().
307
308   \sa setValue()
309 */
310 void QScriptValueIterator::remove()
311 {
312     Q_D(QScriptValueIterator);
313     if (!d || !d->initialized)
314         return;
315     d->object.setProperty(name(), QScriptValue());
316     d->propertyNames.erase(d->current);
317 }
318
319 /*!
320   Makes the iterator operate on \a object. The iterator is set to be
321   at the front of the sequence of properties (before the first
322   property).
323 */
324 QScriptValueIterator& QScriptValueIterator::operator=(QScriptValue &object)
325 {
326     d_ptr.reset();
327     if (object.isObject()) {
328         d_ptr.reset(new QScriptValueIteratorPrivate());
329         d_ptr->object = object;
330     }
331     return *this;
332 }
333
334 QT_END_NAMESPACE