src/script/api/qscriptvalueiterator.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "config.h"
       
    43 #include "qscriptvalueiterator.h"
       
    44 
       
    45 #include "qscriptstring.h"
       
    46 #include "qscriptengine.h"
       
    47 #include "qscriptengine_p.h"
       
    48 #include "qscriptvalue_p.h"
       
    49 #include "qlinkedlist.h"
       
    50 
       
    51 
       
    52 #include "JSObject.h"
       
    53 #include "PropertyNameArray.h"
       
    54 #include "JSArray.h"
       
    55 #include "JSFunction.h"
       
    56 
       
    57 QT_BEGIN_NAMESPACE
       
    58 
       
    59 /*!
       
    60   \since 4.3
       
    61   \class QScriptValueIterator
       
    62 
       
    63   \brief The QScriptValueIterator class provides a Java-style iterator for QScriptValue.
       
    64 
       
    65   \ingroup script
       
    66 
       
    67 
       
    68   The QScriptValueIterator constructor takes a QScriptValue as
       
    69   argument.  After construction, the iterator is located at the very
       
    70   beginning of the sequence of properties. Here's how to iterate over
       
    71   all the properties of a QScriptValue:
       
    72 
       
    73   \snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 0
       
    74 
       
    75   The next() advances the iterator. The name(), value() and flags()
       
    76   functions return the name, value and flags of the last item that was
       
    77   jumped over.
       
    78 
       
    79   If you want to remove properties as you iterate over the
       
    80   QScriptValue, use remove(). If you want to modify the value of a
       
    81   property, use setValue().
       
    82 
       
    83   Note that QScriptValueIterator only iterates over the QScriptValue's
       
    84   own properties; i.e. it does not follow the prototype chain. You can
       
    85   use a loop like this to follow the prototype chain:
       
    86 
       
    87   \snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 1
       
    88 
       
    89   Note that QScriptValueIterator will not automatically skip over
       
    90   properties that have the QScriptValue::SkipInEnumeration flag set;
       
    91   that flag only affects iteration in script code.  If you want, you
       
    92   can skip over such properties with code like the following:
       
    93 
       
    94   \snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 2
       
    95 
       
    96   \sa QScriptValue::property()
       
    97 */
       
    98 
       
    99 class QScriptValueIteratorPrivate
       
   100 {
       
   101 public:
       
   102     QScriptValueIteratorPrivate()
       
   103         : initialized(false)
       
   104     {}
       
   105     void ensureInitialized()
       
   106     {
       
   107         if (initialized)
       
   108             return;
       
   109         QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(object.engine());
       
   110         JSC::ExecState *exec = eng_p->globalExec();
       
   111         JSC::PropertyNameArray propertyNamesArray(exec);
       
   112         propertyNamesArray.setShouldCache(false);
       
   113         JSC::asObject(QScriptValuePrivate::get(object)->jscValue)->getOwnPropertyNames(exec, propertyNamesArray, /*includeNonEnumerable=*/true);
       
   114 
       
   115         JSC::PropertyNameArray::const_iterator propertyNamesIt = propertyNamesArray.begin();
       
   116         for(; propertyNamesIt != propertyNamesArray.end(); ++propertyNamesIt) {
       
   117             propertyNames.append(propertyNamesIt->ustring());
       
   118         }
       
   119         it = propertyNames.begin();
       
   120         initialized = true;
       
   121     }
       
   122 
       
   123     QScriptValue object;
       
   124     QLinkedList<JSC::UString> propertyNames;
       
   125     QLinkedList<JSC::UString>::iterator it;
       
   126     QLinkedList<JSC::UString>::iterator current;
       
   127     bool initialized;
       
   128 };
       
   129 
       
   130 /*!
       
   131   Constructs an iterator for traversing \a object. The iterator is
       
   132   set to be at the front of the sequence of properties (before the
       
   133   first property).
       
   134 */
       
   135 QScriptValueIterator::QScriptValueIterator(const QScriptValue &object)
       
   136     : d_ptr(0)
       
   137 {
       
   138     if (object.isObject()) {
       
   139         d_ptr.reset(new QScriptValueIteratorPrivate());
       
   140         d_ptr->object = object;
       
   141     }
       
   142 }
       
   143 
       
   144 /*!
       
   145   Destroys the iterator.
       
   146 */
       
   147 QScriptValueIterator::~QScriptValueIterator()
       
   148 {
       
   149 }
       
   150 
       
   151 /*!
       
   152   Returns true if there is at least one item ahead of the iterator
       
   153   (i.e. the iterator is \e not at the back of the property sequence);
       
   154   otherwise returns false.
       
   155 
       
   156   \sa next(), hasPrevious()
       
   157 */
       
   158 bool QScriptValueIterator::hasNext() const
       
   159 {
       
   160     Q_D(const QScriptValueIterator);
       
   161     if (!d)
       
   162         return false;
       
   163 
       
   164     const_cast<QScriptValueIteratorPrivate*>(d)->ensureInitialized();
       
   165     return d->it != d->propertyNames.end();
       
   166 }
       
   167 
       
   168 /*!
       
   169   Advances the iterator by one position.
       
   170 
       
   171   Calling this function on an iterator located at the back of the
       
   172   container leads to undefined results.
       
   173 
       
   174   \sa hasNext(), previous(), name()
       
   175 */
       
   176 void QScriptValueIterator::next()
       
   177 {
       
   178     Q_D(QScriptValueIterator);
       
   179     if (!d)
       
   180         return;
       
   181     d->ensureInitialized();
       
   182 
       
   183     d->current = d->it;
       
   184     ++(d->it);
       
   185 }
       
   186 
       
   187 /*!
       
   188   Returns true if there is at least one item behind the iterator
       
   189   (i.e. the iterator is \e not at the front of the property sequence);
       
   190   otherwise returns false.
       
   191 
       
   192   \sa previous(), hasNext()
       
   193 */
       
   194 bool QScriptValueIterator::hasPrevious() const
       
   195 {
       
   196     Q_D(const QScriptValueIterator);
       
   197     if (!d)
       
   198         return false;
       
   199 
       
   200     const_cast<QScriptValueIteratorPrivate*>(d)->ensureInitialized();
       
   201     return d->it != d->propertyNames.begin();
       
   202 }
       
   203 
       
   204 /*!
       
   205   Moves the iterator back by one position.
       
   206 
       
   207   Calling this function on an iterator located at the front of the
       
   208   container leads to undefined results.
       
   209 
       
   210   \sa hasPrevious(), next(), name()
       
   211 */
       
   212 void QScriptValueIterator::previous()
       
   213 {
       
   214     Q_D(QScriptValueIterator);
       
   215     if (!d)
       
   216         return;
       
   217     d->ensureInitialized();
       
   218     --(d->it);
       
   219     d->current = d->it;
       
   220 }
       
   221 
       
   222 /*!
       
   223   Moves the iterator to the front of the QScriptValue (before the
       
   224   first property).
       
   225 
       
   226   \sa toBack(), next()
       
   227 */
       
   228 void QScriptValueIterator::toFront()
       
   229 {
       
   230     Q_D(QScriptValueIterator);
       
   231     if (!d)
       
   232         return;
       
   233     d->ensureInitialized();
       
   234     d->it = d->propertyNames.begin();
       
   235 }
       
   236 
       
   237 /*!
       
   238   Moves the iterator to the back of the QScriptValue (after the
       
   239   last property).
       
   240 
       
   241   \sa toFront(), previous()
       
   242 */
       
   243 void QScriptValueIterator::toBack()
       
   244 {
       
   245     Q_D(QScriptValueIterator);
       
   246     if (!d)
       
   247         return;
       
   248     d->ensureInitialized();
       
   249     d->it = d->propertyNames.end();
       
   250 }
       
   251 
       
   252 /*!
       
   253   Returns the name of the last property that was jumped over using
       
   254   next() or previous().
       
   255 
       
   256   \sa value(), flags()
       
   257 */
       
   258 QString QScriptValueIterator::name() const
       
   259 {
       
   260     Q_D(const QScriptValueIterator);
       
   261     if (!d || !d->initialized)
       
   262         return QString();
       
   263     return *d->current;
       
   264 }
       
   265 
       
   266 /*!
       
   267   \since 4.4
       
   268 
       
   269   Returns the name of the last property that was jumped over using
       
   270   next() or previous().
       
   271 */
       
   272 QScriptString QScriptValueIterator::scriptName() const
       
   273 {
       
   274     Q_D(const QScriptValueIterator);
       
   275     if (!d || !d->initialized)
       
   276         return QScriptString();
       
   277     return d->object.engine()->toStringHandle(name());
       
   278 }
       
   279 
       
   280 /*!
       
   281   Returns the value of the last property that was jumped over using
       
   282   next() or previous().
       
   283 
       
   284   \sa setValue(), name()
       
   285 */
       
   286 QScriptValue QScriptValueIterator::value() const
       
   287 {
       
   288     Q_D(const QScriptValueIterator);
       
   289     if (!d || !d->initialized)
       
   290         return QScriptValue();
       
   291     return d->object.property(name());
       
   292 }
       
   293 
       
   294 /*!
       
   295   Sets the \a value of the last property that was jumped over using
       
   296   next() or previous().
       
   297 
       
   298   \sa value(), name()
       
   299 */
       
   300 void QScriptValueIterator::setValue(const QScriptValue &value)
       
   301 {
       
   302     Q_D(QScriptValueIterator);
       
   303     if (!d || !d->initialized)
       
   304         return;
       
   305     d->object.setProperty(name(), value);
       
   306 }
       
   307 
       
   308 /*!
       
   309   Returns the flags of the last property that was jumped over using
       
   310   next() or previous().
       
   311 
       
   312   \sa value()
       
   313 */
       
   314 QScriptValue::PropertyFlags QScriptValueIterator::flags() const
       
   315 {
       
   316     Q_D(const QScriptValueIterator);
       
   317     if (!d || !d->initialized)
       
   318         return 0;
       
   319     return d->object.propertyFlags(name());
       
   320 }
       
   321 
       
   322 /*!
       
   323   Removes the last property that was jumped over using next()
       
   324   or previous().
       
   325 
       
   326   \sa setValue()
       
   327 */
       
   328 void QScriptValueIterator::remove()
       
   329 {
       
   330     Q_D(QScriptValueIterator);
       
   331     if (!d || !d->initialized)
       
   332         return;
       
   333     d->object.setProperty(name(), QScriptValue());
       
   334     d->propertyNames.erase(d->current);
       
   335 }
       
   336 
       
   337 /*!
       
   338   Makes the iterator operate on \a object. The iterator is set to be
       
   339   at the front of the sequence of properties (before the first
       
   340   property).
       
   341 */
       
   342 QScriptValueIterator& QScriptValueIterator::operator=(QScriptValue &object)
       
   343 {
       
   344     d_ptr.reset();
       
   345     if (object.isObject()) {
       
   346         d_ptr.reset(new QScriptValueIteratorPrivate());
       
   347         d_ptr->object = object;
       
   348     }
       
   349     return *this;
       
   350 }
       
   351 
       
   352 QT_END_NAMESPACE