|
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 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 */ |