summaryrefslogtreecommitdiff
path: root/src/shared/scriptwrapper/wrap_helpers.h
blob: 79dc7751d4160c44894df63001bf8d53d6ba1f7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#ifndef WRAP_HELPERS_H
#define WRAP_HELPERS_H

#include <QScriptEngine>
#include <QScriptContext>
#include <QScriptValue>

namespace SharedTools {

// Strip a const ref from a type via template specialization trick.
// Use for determining function call args

template <class T>
    struct RemoveConstRef {
        typedef T Result;
    };

template <class T>
    struct RemoveConstRef<const T &> {
        typedef T Result;
    };

// Template that retrieves a QObject-derived class from a QScriptValue.

template <class QObjectDerived>
    QObjectDerived *qObjectFromScriptValue(const QScriptValue &v)
{
     if (!v.isQObject())
        return 0;
    QObject *o = v.toQObject();
    return qobject_cast<QObjectDerived *>(o);
}

// Template that retrieves a wrapped object from a QScriptValue.
// The wrapped object is accessed through an accessor of
// the  QObject-derived wrapper.

template <class  Wrapper, class Wrapped>
    Wrapped *wrappedFromScriptValue(const QScriptValue &v,
                                    Wrapped * (Wrapper::*wrappedAccessor)  () const)
{
    Wrapper *wrapper = qObjectFromScriptValue<Wrapper>(v);
    if (!wrapper)
        return 0;
    return (wrapper->*wrappedAccessor)();
}

// Template that retrieves a wrapped object from
// a QObject-derived script wrapper object that is set as 'this' in
// a script context via accessor.

template <class  Wrapper, class Wrapped>
    static inline Wrapped *wrappedThisFromContext(QScriptContext *context,
                                                Wrapped * (Wrapper::*wrappedAccessor)  () const)
{
    Wrapped *wrapped = wrappedFromScriptValue(context->thisObject(), wrappedAccessor);
    Q_ASSERT(wrapped);
    return wrapped;
}

// Template that retrieves an object contained in a wrapped object
// in a script getter call (namely the interfaces returned by
// the core interface accessors). Mangles out the wrapper object from
// thisObject(), accesses the wrapped object and returns the contained object.

template <class Contained, class  Wrapper, class Wrapped>
    static inline Contained *containedFromContext(QScriptContext *context,
                                                  Wrapped *   (Wrapper::*wrappedAccessor)  () const,
                                                  Contained * (Wrapped::*containedAccessor)() const)
{
    Wrapped *wrapped = wrappedThisFromContext(context, wrappedAccessor);
    return (wrapped->*containedAccessor)();
}

// Template that retrieves a contained QObject-type object
// in a script getter call and creates a new script-object via engine->newQObject().
// To be called from a script getter callback.

template <class Contained, class  Wrapper, class Wrapped>
    static inline QScriptValue containedQObjectFromContextToScriptValue(QScriptContext *context, QScriptEngine *engine,
                                                                        Wrapped *   (Wrapper::*wrappedAccessor)  () const,
                                                                        Contained * (Wrapped::*containedAccessor)() const)
{
    return engine->newQObject(containedFromContext(context, wrappedAccessor, containedAccessor));
}

// Template that retrieves a contained Non-QObject-type object
// in a script getter call and creates a new script-object by wrapping it into
// a new instance of ContainedWrapper (which casts to QScriptValue).
// To be called from a script getter callback.

template <class ContainedWrapper, class Contained, class  Wrapper, class Wrapped>
    static inline QScriptValue wrapContainedFromContextAsScriptValue(QScriptContext *context, QScriptEngine *engine,
                                                                     Wrapped *   (Wrapper::*wrappedAccessor)  () const,
                                                                     Contained * (Wrapped::*containedAccessor)() const)
{
    Contained *c = containedFromContext(context, wrappedAccessor, containedAccessor);
    if (!c)
        return QScriptValue(engine, QScriptValue::NullValue);

    ContainedWrapper *cw = new ContainedWrapper(*engine, c);
    return *cw; // cast to QScriptValue
}

// Template that retrieves a wrapped object from context (this)
// and calls a const-member function with no parameters.
// To be called from a script getter callback.

template <class Ret, class  Wrapper, class Wrapped>
    static inline QScriptValue scriptCallConstMember_0(QScriptContext *context, QScriptEngine *engine,
                                                       Wrapped *   (Wrapper::*wrappedAccessor)  () const,
                                                       Ret  (Wrapped::*member)() const)
{
    Wrapped *wrapped = wrappedThisFromContext(context, wrappedAccessor);
    return engine->toScriptValue( (wrapped->*member)() );
}

// Ditto for non-const

template <class Ret, class  Wrapper, class Wrapped>
    static inline QScriptValue scriptCallMember_0(QScriptContext *context, QScriptEngine *engine,
                                                       Wrapped *   (Wrapper::*wrappedAccessor)  () const,
                                                       Ret  (Wrapped::*member)())
{
    Wrapped *wrapped = wrappedThisFromContext(context, wrappedAccessor);
    return engine->toScriptValue( (wrapped->*member)() );
}

// Template that retrieves a wrapped object from context (this)
// and calls a const-member function with 1 parameter on it.
// To be called from a script getter callback.

template <class Ret, class Argument, class  Wrapper, class Wrapped>
    static inline QScriptValue scriptCallConstMember_1(QScriptContext *context, QScriptEngine *engine,
                                                       Wrapped *   (Wrapper::*wrappedAccessor)  () const,
                                                       Ret  (Wrapped::*member)(Argument a1) const)
{
    const int argumentCount = context->argumentCount();
    if ( argumentCount != 1)
        return QScriptValue (engine, QScriptValue::NullValue);

    Wrapped *wrapped = wrappedThisFromContext(context, wrappedAccessor);
    // call member. If the argument is a const ref, strip it.
    typedef typename RemoveConstRef<Argument>::Result ArgumentBase;
    ArgumentBase a = qscriptvalue_cast<ArgumentBase>(context->argument(0));
    return engine->toScriptValue( (wrapped->*member)(a) );
}

// Template that retrieves a wrapped object
// and calls a member function with 1 parameter on it.
// To be called from a script getter callback.

template <class Ret, class Argument, class  Wrapper, class Wrapped>
    static inline QScriptValue scriptCallMember_1(QScriptContext *context, QScriptEngine *engine,
                                                  Wrapped *   (Wrapper::*wrappedAccessor)  () const,
                                                  Ret  (Wrapped::*member)(Argument a1))
{
    const int argumentCount = context->argumentCount();
    if ( argumentCount != 1)
        return QScriptValue (engine, QScriptValue::NullValue);

    Wrapped *wrapped = wrappedThisFromContext(context, wrappedAccessor);
    // call member. If the argument is a const ref, strip it.
    typedef typename RemoveConstRef<Argument>::Result ArgumentBase;
    ArgumentBase a = qscriptvalue_cast<ArgumentBase>(context->argument(0));
    return engine->toScriptValue( (wrapped->*member)(a) );
}

// Template that retrieves a wrapped object
// and calls a void member function with 1 parameter that is a wrapper of
// of some interface.
// Typically used for something like 'setCurrentEditor(Editor*)'
// To be called from a script callback.

template <class  ThisWrapper, class ThisWrapped, class ArgumentWrapper, class ArgumentWrapped>
static QScriptValue scriptCallVoidMember_Wrapped1(QScriptContext *context, QScriptEngine *engine,
                                                  ThisWrapped *   (ThisWrapper::*thisWrappedAccessor)  () const,
                                                  ArgumentWrapped *(ArgumentWrapper::*argumentWrappedAccessor)() const,
                                                  void  (ThisWrapped::*member)(ArgumentWrapped *a1),
                                                  bool acceptNullArgument = false)
{
    const QScriptValue voidRC = QScriptValue(engine, QScriptValue::UndefinedValue);
    if (context->argumentCount() < 1)
        return voidRC;

    ThisWrapped *thisWrapped = wrappedThisFromContext(context, thisWrappedAccessor);
    ArgumentWrapped *aw = wrappedFromScriptValue(context->argument(0), argumentWrappedAccessor);
    if (acceptNullArgument || aw)
        (thisWrapped->*member)(aw);
    return voidRC;
}

// Macros that define the static functions to call members

#define SCRIPT_CALL_CONST_MEMBER_0(funcName, accessor, member) \
static QScriptValue funcName(QScriptContext *context, QScriptEngine *engine) \
{   return SharedTools::scriptCallConstMember_0(context, engine, accessor, member); }

#define SCRIPT_CALL_MEMBER_0(funcName, accessor, member) \
static QScriptValue funcName(QScriptContext *context, QScriptEngine *engine) \
{   return SharedTools::scriptCallMember_0(context, engine, accessor, member); }

#define SCRIPT_CALL_CONST_MEMBER_1(funcName, accessor, member) \
static QScriptValue funcName(QScriptContext *context, QScriptEngine *engine) \
{   return SharedTools::scriptCallConstMember_1(context, engine, accessor, member); }

#define SCRIPT_CALL_MEMBER_1(funcName, accessor, member) \
static QScriptValue funcName(QScriptContext *context, QScriptEngine *engine) \
{   return SharedTools::scriptCallMember_1(context, engine, accessor, member); }

// Create a script list of wrapped non-qobjects by wrapping them.
// Wrapper must cast to QScriptValue.

template <class Wrapper, class Iterator>
    static inline QScriptValue wrapObjectList( QScriptEngine *engine, Iterator i1, Iterator i2)
{
    QScriptValue rc = engine->newArray(i2 - i1); // Grrr!
    quint32 i = 0;
    for ( ; i1 != i2 ; ++i1, i++) {
        Wrapper * wrapper =  new Wrapper(*engine, *i1);
        rc.setProperty(i, *wrapper);
    }
    return rc;
}

// Unwrap a list of wrapped objects from a script list.

template <class Wrapper, class Wrapped>
    static inline QList<Wrapped*> unwrapObjectList(const QScriptValue &v,
                                                   Wrapped *(Wrapper::*wrappedAccessor)() const)
{
    QList<Wrapped*> rc;

    if (!v.isArray())
        return rc;

    const  quint32 len = v.property(QLatin1String("length")).toUInt32();
    if (!len)
        return rc;

    for (quint32 i = 0; i < len; i++) {
        const QScriptValue e = v.property(i);
        if (e.isQObject()) {
            QObject *o = e.toQObject();
            if (Wrapper * wrapper = qobject_cast<Wrapper *>(o))
                rc.push_back((wrapper->*wrappedAccessor)());
        }
    }
    return rc;
}

// Traditional registration of a prototype for an interface.
// that can be converted via script value casts via Q_DECLARE_METATYPE.

template <class Interface, class Prototype>
    static void registerInterfaceWithDefaultPrototype(QScriptEngine &engine)
{
    Prototype *protoType = new Prototype(&engine);
    const QScriptValue scriptProtoType = engine.newQObject(protoType);

    engine.setDefaultPrototype(qMetaTypeId<Interface*>(), scriptProtoType);
}

// Convert a class derived from QObject to Scriptvalue via engine->newQObject() to make
// the signals, slots and properties visible.
// To be registered as a magic creation function with qScriptRegisterMetaType().
// (see registerQObject()

template <class SomeQObject>
static QScriptValue qObjectToScriptValue(QScriptEngine *engine, SomeQObject * const &qo)
{
    return engine->newQObject(qo, QScriptEngine::QtOwnership, QScriptEngine::ExcludeChildObjects);
}

// Convert  Scriptvalue back to a class derived from  QObject via QScriptValue::toQObject()
// To be registered as a magic conversion function with  qScriptRegisterMetaType().
// (see registerQObject)

template <class SomeQObject>
static void scriptValueToQObject(const QScriptValue &sv, SomeQObject * &p)
{
    QObject *qObject =  sv.toQObject();
    p = qobject_cast<SomeQObject*>(qObject);
    Q_ASSERT(p);
}

// Register a QObject-derived class which has Q_DECLARE_METATYPE(Ptr*)
// with the engine using qObjectToScriptValue/scriptValueToQObject as
// conversion functions to make it possible to use for example
// Q_PROPERTY(QMainWindow*).

template <class SomeQObject>
static void registerQObject(QScriptEngine *engine)
{
    qScriptRegisterMetaType<SomeQObject*>(engine,
                                          qObjectToScriptValue<SomeQObject>,
                                          scriptValueToQObject<SomeQObject>);
}

} // namespace SharedTools

#endif // WRAP_HELPERS_H