source: trunk/src/script/qscriptclass.cpp@ 447

Last change on this file since 447 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 21.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtScript module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qscriptclass.h"
43
44#ifndef QT_NO_SCRIPT
45
46#include <QtCore/qstringlist.h>
47
48#include "qscriptclasspropertyiterator.h"
49#include "qscriptstring.h"
50#include "qscriptstring_p.h"
51#include "qscriptclass_p.h"
52#include "qscriptclassinfo_p.h"
53#include "qscriptengine_p.h"
54#include "qscriptcontext_p.h"
55#include "qscriptvalueimpl_p.h"
56#include "qscriptmember_p.h"
57#include "qscriptobject_p.h"
58#include "qscriptfunction_p.h"
59
60Q_DECLARE_METATYPE(QScriptContext*)
61Q_DECLARE_METATYPE(QScriptValueList)
62
63QT_BEGIN_NAMESPACE
64
65/*!
66 \since 4.4
67 \class QScriptClass
68
69 \brief The QScriptClass class provides an interface for defining custom behavior of (a class of) Qt Script objects.
70
71 \ingroup script
72 \mainclass
73
74 The QScriptClass class defines an interface for handling various
75 aspects of interaction with the Qt Script objects associated with
76 the class. Such objects are created by calling
77 QScriptEngine::newObject(), passing a pointer to the QScriptClass as
78 argument.
79
80 By subclassing QScriptClass, you can define precisely how access to
81 properties of the objects that use your class is handled. This
82 enables a fully dynamic handling of properties, e.g. it's more
83 powerful than QScriptEngine::newQObject(). For example, you can use
84 QScriptClass to implement array-type objects (i.e. objects that
85 handle the \c{length} property, and properties whose names are valid
86 array indexes, in a special way), or to implement a "live"
87 (runtime-defined) proxy to an underlying object.
88
89 If you just need to handle access to a set of properties that are
90 known at the time an object is created (i.e. "semi-statically"), you
91 might consider using QScriptValue::setProperty() to define
92 getter/setter functions for the relevant properties, rather than
93 subclassing QScriptClass.
94
95 Reimplement queryProperty() to specify which properties are handled
96 in a custom way by your script class (i.e. should be
97 \bold{delegated} to the QScriptClass), and which properties should
98 be handled just like normal Qt Script object properties.
99
100 Reimplement property() and setProperty() to perform the actual
101 access (read or write) to the properties that your class
102 handles. Additionally, you can reimplement propertyFlags() to
103 specify custom flags for your properties.
104
105 Reimplement newIterator() to provide an iterator for objects of your
106 custom class. This is only necessary if objects of your class can
107 have custom properties that you want to be reported when an object
108 is used together with the QScriptValueIterator class, or when an
109 object is used in a for-in enumeration statement in a script.
110
111 When implementing custom classes of objects, you typically use
112 QScriptValue::setData() to store instance-specific data as part of
113 object initialization; the data won't be accessible from scripts
114 directly, but you can access it in e.g. your reimplementations of
115 property() and setProperty() (by calling QScriptValue::data()) to
116 perform custom processing.
117
118 Reimplement prototype() to provide a custom prototype object for
119 your script class.
120
121 Reimplement supportsExtension() and extension() if your custom
122 script class supports one or more of the extensions specified by the
123 Extension enum.
124
125 \sa QScriptClassPropertyIterator, QScriptEngine::newObject(), {Custom Script Class Example}
126*/
127
128/*!
129 \enum QScriptClass::Extension
130
131 This enum specifies the possible extensions to a QScriptClass.
132
133 \value Callable Instances of this class can be called as functions.
134
135 \value HasInstance Instances of this class implement [[HasInstance]].
136
137 \sa extension()
138*/
139
140/*!
141 \enum QScriptClass::QueryFlag
142
143 This enum describes flags that are used to query a QScriptClass
144 regarding how access to a property should be handled.
145
146 \value HandlesReadAccess The QScriptClass handles read access to this property.
147 \value HandlesWriteAccess The QScriptClass handles write access to this property.
148
149 \sa queryProperty()
150*/
151
152class QScriptCustomClassData : public QScriptClassData
153{
154public:
155 QScriptCustomClassData(QScriptClass *klass);
156 ~QScriptCustomClassData();
157
158 virtual void mark(const QScriptValueImpl &object, int generation);
159 virtual bool resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId,
160 QScript::Member *member, QScriptValueImpl *base,
161 QScript::AccessMode access);
162 virtual bool get(const QScriptValueImpl &obj, const QScript::Member &m,
163 QScriptValueImpl *result);
164 virtual bool put(QScriptValueImpl *object, const QScript::Member &member,
165 const QScriptValueImpl &value);
166 virtual bool removeMember(const QScriptValueImpl &object,
167 const QScript::Member &member);
168 virtual bool implementsHasInstance(const QScriptValueImpl &object);
169 virtual bool hasInstance(const QScriptValueImpl &object,
170 const QScriptValueImpl &value);
171 virtual QScriptClassDataIterator *newIterator(const QScriptValueImpl &object);
172
173 QScriptClass *scriptClass() const;
174
175private:
176 QScriptClass *m_class;
177};
178
179class QScriptCustomClassDataIterator : public QScriptClassDataIterator
180{
181public:
182 QScriptCustomClassDataIterator(const QScriptValueImpl &object,
183 QScriptClass *klass);
184 virtual ~QScriptCustomClassDataIterator();
185
186 virtual bool hasNext() const;
187 virtual void next(QScript::Member *member);
188
189 virtual bool hasPrevious() const;
190 virtual void previous(QScript::Member *member);
191
192 virtual void toFront();
193 virtual void toBack();
194
195private:
196 void iteratorToMember(QScript::Member *member);
197
198 QScriptClassPropertyIterator *m_it;
199};
200
201QScriptCustomClassData::QScriptCustomClassData(QScriptClass *klass)
202 : m_class(klass)
203{
204}
205
206QScriptCustomClassData::~QScriptCustomClassData()
207{
208}
209
210void QScriptCustomClassData::mark(const QScriptValueImpl &, int)
211{
212}
213
214bool QScriptCustomClassData::resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId,
215 QScript::Member *member, QScriptValueImpl *base,
216 QScript::AccessMode access)
217{
218 uint id = 0;
219 QScriptClass::QueryFlags queryIn = 0;
220 if (access & QScript::Read)
221 queryIn |= QScriptClass::HandlesReadAccess;
222 if (access & QScript::Write)
223 queryIn |= QScriptClass::HandlesWriteAccess;
224 QScriptEnginePrivate *eng = object.engine();
225 QScriptString str = eng->internedString(nameId);
226 QScriptClass::QueryFlags queryOut;
227 queryOut = m_class->queryProperty(eng->toPublic(object), str, queryIn, &id);
228 if (queryOut & queryIn) {
229 if (base)
230 *base = object;
231 QScriptValue::PropertyFlags flags = m_class->propertyFlags(eng->toPublic(object), str, id);
232 member->native(nameId, id, flags);
233 return true;
234 }
235 return false;
236}
237
238bool QScriptCustomClassData::get(const QScriptValueImpl &object, const QScript::Member &member,
239 QScriptValueImpl *result)
240{
241 QScriptEnginePrivate *eng = object.engine();
242 QScriptString str = eng->internedString(member.nameId());
243 *result = eng->toImpl(m_class->property(eng->toPublic(object), str, member.id()));
244 if (!result->isValid())
245 *result = eng->undefinedValue();
246 return true;
247}
248
249bool QScriptCustomClassData::put(QScriptValueImpl *object, const QScript::Member &member,
250 const QScriptValueImpl &value)
251{
252 QScriptEnginePrivate *eng = object->engine();
253 QScriptString str = eng->internedString(member.nameId());
254 QScriptValue publicObject = eng->toPublic(*object);
255 m_class->setProperty(publicObject, str, member.id(), eng->toPublic(value));
256 return true;
257}
258
259bool QScriptCustomClassData::removeMember(const QScriptValueImpl &object,
260 const QScript::Member &member)
261{
262 QScriptEnginePrivate *eng = object.engine();
263 QScriptString str = eng->internedString(member.nameId());
264 QScriptValue publicObject = eng->toPublic(object);
265 m_class->setProperty(publicObject, str, member.id(), QScriptValue());
266 return true;
267}
268
269bool QScriptCustomClassData::implementsHasInstance(const QScriptValueImpl &object)
270{
271 if (object.classInfo() != QScriptClassPrivate::get(m_class)->classInfo())
272 return false;
273 return m_class->supportsExtension(QScriptClass::HasInstance);
274}
275
276bool QScriptCustomClassData::hasInstance(const QScriptValueImpl &object,
277 const QScriptValueImpl &value)
278{
279 QScriptEnginePrivate *eng = object.engine();
280 QScriptValueList arguments;
281 arguments << eng->toPublic(object) << eng->toPublic(value);
282 QVariant ret = m_class->extension(QScriptClass::HasInstance, qVariantFromValue(arguments));
283 return ret.toBool();
284}
285
286QScriptClassDataIterator *QScriptCustomClassData::newIterator(const QScriptValueImpl &object)
287{
288 return new QScriptCustomClassDataIterator(object, m_class);
289}
290
291QScriptClass *QScriptCustomClassData::scriptClass() const
292{
293 return m_class;
294}
295
296
297
298QScriptCustomClassDataIterator::QScriptCustomClassDataIterator(const QScriptValueImpl &object,
299 QScriptClass *klass)
300{
301 QScriptEnginePrivate *eng = object.engine();
302 m_it = klass->newIterator(eng->toPublic(object));
303}
304
305QScriptCustomClassDataIterator::~QScriptCustomClassDataIterator()
306{
307 if (m_it) {
308 delete m_it;
309 m_it = 0;
310 }
311}
312
313bool QScriptCustomClassDataIterator::hasNext() const
314{
315 return m_it && m_it->hasNext();
316}
317
318void QScriptCustomClassDataIterator::next(QScript::Member *member)
319{
320 if (m_it) {
321 m_it->next();
322 iteratorToMember(member);
323 }
324}
325
326bool QScriptCustomClassDataIterator::hasPrevious() const
327{
328 return m_it && m_it->hasPrevious();
329}
330
331void QScriptCustomClassDataIterator::previous(QScript::Member *member)
332{
333 if (m_it) {
334 m_it->previous();
335 iteratorToMember(member);
336 }
337}
338
339void QScriptCustomClassDataIterator::toFront()
340{
341 if (m_it)
342 m_it->toFront();
343}
344
345void QScriptCustomClassDataIterator::toBack()
346{
347 if (m_it)
348 m_it->toBack();
349}
350
351void QScriptCustomClassDataIterator::iteratorToMember(QScript::Member *member)
352{
353 QScriptString str = m_it->name();
354 QScriptNameIdImpl *nameId = 0;
355 if (str.isValid())
356 nameId = QScriptStringPrivate::get(str)->nameId;
357 member->native(nameId, m_it->id(), m_it->flags());
358}
359
360
361
362QScriptClassPrivate::QScriptClassPrivate(QScriptClass *q)
363 : engine(0), m_classInfo(0), q_ptr(q)
364{
365}
366
367QScriptClassPrivate::~QScriptClassPrivate()
368{
369 if (m_classInfo) {
370 // classInfo is owned by engine