0
|
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 documentation 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 |
/*!
|
|
43 |
\example script/customclass
|
|
44 |
\title Custom Script Class Example
|
|
45 |
|
|
46 |
The Custom Script Class example shows how to use QScriptClass and QScriptClassPropertyIterator
|
|
47 |
to implement a custom script class.
|
|
48 |
|
|
49 |
The script class we are going to implement is called \c{ByteArray}. It provides a wrapper around
|
|
50 |
the QByteArray class in Qt, with a simplified API. Why do we need such a class? Well, neither the
|
|
51 |
ECMAScript \c{Array} class or \c{String} class is appropriate to use when working with arrays of
|
|
52 |
bytes. Our \c{ByteArray} class will have the right semantics; objects will use only the amount of
|
|
53 |
memory that is really needed (a byte is stored as a byte, not as a floating-point number or a
|
|
54 |
Unicode character) and can be passed directly to C++ slots taking QByteArray arguments (no costly
|
|
55 |
conversion necessary).
|
|
56 |
|
|
57 |
\section1 ByteArray Class In Use
|
|
58 |
|
|
59 |
When the \c{ByteArray} class has been made available to the
|
|
60 |
scripting environment, \c{ByteArray} objects can be constructed like
|
|
61 |
so:
|
|
62 |
|
|
63 |
\snippet doc/src/snippets/code/doc_src_examples_qtscriptcustomclass.qdoc 0
|
|
64 |
|
|
65 |
\c{ByteArray} objects behave similar to normal \c{Array} objects. Every \c{ByteArray} object has
|
|
66 |
a \c{length} property, that holds the length of the array. If a new value is assigned to the \c{length}
|
|
67 |
property, the array is resized. If the array is enlarged, the new bytes are initialized to 0.
|
|
68 |
(This is a difference from normal \c{Array} objects; \c{ByteArray} objects are always dense arrays.)
|
|
69 |
Use normal array operations to read or write bytes in the array. The following code sets all the
|
|
70 |
bytes of an array to a certain value:
|
|
71 |
|
|
72 |
\snippet doc/src/snippets/code/doc_src_examples_qtscriptcustomclass.qdoc 1
|
|
73 |
|
|
74 |
When assigning a value to an array element, the value is truncated to eight bits:
|
|
75 |
|
|
76 |
\snippet doc/src/snippets/code/doc_src_examples_qtscriptcustomclass.qdoc 2
|
|
77 |
|
|
78 |
Like normal \c{Array} objects, if the array index is greater than the current length
|
|
79 |
of the array, the array is resized accordingly:
|
|
80 |
|
|
81 |
\snippet doc/src/snippets/code/doc_src_examples_qtscriptcustomclass.qdoc 3
|
|
82 |
|
|
83 |
Property names that aren't valid array indexes are treated
|
|
84 |
like normal object properties (again, the same is the case for normal \c{Array} objects);
|
|
85 |
in other words, it's perfectly fine to do something like this:
|
|
86 |
|
|
87 |
\snippet doc/src/snippets/code/doc_src_examples_qtscriptcustomclass.qdoc 4
|
|
88 |
|
|
89 |
The above assignment won't affect the contents of the array, but will rather assign a value
|
|
90 |
to the object property named "foo".
|
|
91 |
|
|
92 |
\c{ByteArray} objects have a set of methods: chop(), equals(), left(), mid(), toBase64() and so on.
|
|
93 |
These map directly onto the corresponding methods in QByteArray.
|
|
94 |
|
|
95 |
\snippet doc/src/snippets/code/doc_src_examples_qtscriptcustomclass.qdoc 5
|
|
96 |
|
|
97 |
\section1 ByteArray Class Implementation
|
|
98 |
|
|
99 |
To implement the \c{ByteArray} script class in C++, we create a subclass of QScriptClass,
|
|
100 |
called ByteArrayClass, and reimplement the virtual functions from QScriptClass. We also provide
|
|
101 |
a Qt Script constructor function suitable for being added to a QScriptEngine's environment.
|
|
102 |
|
|
103 |
The ByteArrayClass constructor prepares the script class:
|
|
104 |
|
|
105 |
\snippet examples/script/customclass/bytearrayclass.cpp 0
|
|
106 |
|
|
107 |
First, the constructor registers a pair of conversion functions, so that C++ QByteArray objects
|
|
108 |
and Qt Script \c{ByteArray} objects can move seamlessly between the C++ side and the script side.
|
|
109 |
For example, if a \c{ByteArray} object is passed to a C++ slot that takes a QByteArray
|
|
110 |
argument, the actual QByteArray that the \c{ByteArray} object wraps will be passed correctly.
|
|
111 |
|
|
112 |
Second, we store a handle to the string "length", so that we can quickly compare a given property name
|
|
113 |
to "length" later on.
|
|
114 |
|
|
115 |
Third, we initialize the standard \c{ByteArray} prototype, to be returned by our prototype()
|
|
116 |
reimplementation later on. (The implementation of the prototype is discussed later.)
|
|
117 |
|
|
118 |
Fourth, we initialize a constructor function for \c{ByteArray}, to be returned by the
|
|
119 |
constructor() function. We set the internal data of the constructor to be a pointer to
|
|
120 |
this ByteArrayClass object, so that the constructor, when it is invoked, can extract the
|
|
121 |
pointer and use it to create a new \c{ByteArray} object.
|
|
122 |
|
|
123 |
\snippet examples/script/customclass/bytearrayclass.cpp 1
|
|
124 |
|
|
125 |
The newInstance() function isn't part of the QScriptClass API; its purpose is to offer
|
|
126 |
a convenient way to construct a \c{ByteArray} object from an existing QByteArray. We store the
|
|
127 |
QByteArray as the internal data of the new object, and return the new object.
|
|
128 |
QScriptEngine::newObject() will call the prototype() function of our class, ensuring that
|
|
129 |
the prototype of the new object will be the standard \c{ByteArray} prototype.
|
|
130 |
|
|
131 |
\snippet examples/script/customclass/bytearrayclass.cpp 2
|
|
132 |
|
|
133 |
construct() is the native function that will act as a constructor for \c{ByteArray}
|
|
134 |
in scripts. We extract the pointer to the class, then call a newInstance() overload
|
|
135 |
that takes an initial size as argument, and return the new script object.
|
|
136 |
|
|
137 |
\snippet examples/script/customclass/bytearrayclass.cpp 3
|
|
138 |
|
|
139 |
queryProperty() is the function that Qt Script will call whenever someone tries to access
|
|
140 |
a property of a \c{ByteArray} object. We first get a pointer to the underlying QByteArray.
|
|
141 |
We check if the property being accessed is the special \c{length} property; if so, we
|
|
142 |
return, indicating that we will handle every kind of access to this property (e.g. both
|
|
143 |
read and write). Otherwise, we attempt to convert the property name to an array index. If
|
|
144 |
this fails, we return, indicating that we don't want to handle this property. Otherwise, we
|
|
145 |
have a valid array index, and store it in the \c{id} argument, so that we don't have to
|
|
146 |
recompute it in e.g. property() or setProperty(). If the index is greater than or equal to
|
|
147 |
the QByteArray's size, we indicate that we don't want to handle read access (but we still want
|
|
148 |
to handle writes, if requested).
|
|
149 |
|
|
150 |
\snippet examples/script/customclass/bytearrayclass.cpp 4
|
|
151 |
|
|
152 |
In the property() reimplementation, we do similar checks as in queryProperty() to find out
|
|
153 |
which property is being requested, and then return the value of that property.
|
|
154 |
|
|
155 |
\snippet examples/script/customclass/bytearrayclass.cpp 5
|
|
156 |
|
|
157 |
The setProperty() reimplementation has a structure that is similar to property(). If the \c{length} property
|
|
158 |
is being set, we resize the underlying QByteArray to the given length. Otherwise, we grab the
|
|
159 |
array index that was calculated in the queryProperty() function, enlarge the array if necessary,
|
|
160 |
and write the given value to the array.
|
|
161 |
|
|
162 |
\snippet examples/script/customclass/bytearrayclass.cpp 6
|
|
163 |
|
|
164 |
The propertyFlags() reimplementation specifies that the \c{length} property can't be deleted,
|
|
165 |
and that it is not enumerable. Array elements can't be deleted.
|
|
166 |
|
|
167 |
\snippet examples/script/customclass/bytearrayclass.cpp 7
|
|
168 |
|
|
169 |
We want the array elements to show up when a \c{ByteArray} object is used in for-in
|
|
170 |
statements and together with QScriptValueIterator. Therefore, we reimplement the
|
|
171 |
newIterator() function and have it return a new iterator for a given \c{ByteArray}.
|
|
172 |
|
|
173 |
\section1 ByteArray Iterator Implementation
|
|
174 |
|
|
175 |
\snippet examples/script/customclass/bytearrayclass.cpp 8
|
|
176 |
|
|
177 |
The \c{ByteArrayClassPropertyIterator} class is simple. It maintains an index into the
|
|
178 |
underlying QByteArray, and checks and updates the index in hasNext(), next() and so on.
|
|
179 |
|
|
180 |
\section1 ByteArray Prototype Implementation
|
|
181 |
|
|
182 |
The prototype class, ByteArrayPrototype, implements the \c{ByteArray} functions as slots.
|
|
183 |
|
|
184 |
\snippet examples/script/customclass/bytearrayprototype.h 0
|
|
185 |
|
|
186 |
There is a small helper function, thisByteArray(), that returns a pointer to the QByteArray
|
|
187 |
being operated upon:
|
|
188 |
|
|
189 |
\snippet examples/script/customclass/bytearrayprototype.cpp 0
|
|
190 |
|
|
191 |
The slots simply forward the calls to the QByteArray. Examples:
|
|
192 |
|
|
193 |
\snippet examples/script/customclass/bytearrayprototype.cpp 1
|
|
194 |
|
|
195 |
The remove() function is noteworthy; if we look at QByteArray::remove(), we see that it
|
|
196 |
should return a reference to the QByteArray itself (i.e. not a copy). To get the same
|
|
197 |
behavior in scripts, we return the script object (thisObject()).
|
|
198 |
*/
|