1 /* This file is part of the KDE libraries
2     Copyright (C) 2005, 2006 Ian Reinhart Geiser <geiseri@kde.org>
3     Copyright (C) 2005, 2006 Matt Broadstone <mbroadst@gmail.com>
4     Copyright (C) 2005, 2006 Richard J. Moore <rich@kde.org>
5     Copyright (C) 2005, 2006 Erik L. Bunce <kde@bunce.us>
6 
7     This library is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Library General Public
9     License as published by the Free Software Foundation; either
10     version 2 of the License, or (at your option) any later version.
11 
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15     Library General Public License for more details.
16 
17     You should have received a copy of the GNU Library General Public License
18     along with this library; see the file COPYING.LIB.  If not, write to
19     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20     Boston, MA 02110-1301, USA.
21 */
22 
23 #ifndef VALUE_BINDING_H
24 #define VALUE_BINDING_H
25 
26 #include <kjs/object.h>
27 #include <kjs/interpreter.h>
28 
29 #include "static_binding.h"
30 #include "pointer.h"
31 
32 /**
33 * A simple variant style method.
34 * This will extract the value, cast it to the native type and place it in "value".
35 * Any data that should be returned from this method should be placed into "result";
36 *
37 */
38 #define START_VALUE_METHOD( METHODNAME, TYPE) \
39     KJS::JSValue *METHODNAME( KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args ) \
40     { \
41         Q_UNUSED(exec);\
42         Q_UNUSED(self);\
43         Q_UNUSED(args);\
44         KJS::JSValue *result = KJS::jsNull(); \
45         KJSEmbed::ValueBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::ValueBinding>(exec, self ); \
46         if( imp ) \
47         { \
48             TYPE value = imp->value<TYPE>();
49 /**
50 * End a variant method started by START_VALUE_METHOD
51 */
52 #define END_VALUE_METHOD \
53     imp->setValue(value); \
54     } \
55     else { \
56         KJS::throwError(exec, KJS::GeneralError, "Problem in ValueBinding here");\
57     }\
58     return result; \
59     }
60 
61 #define KJSO_VALUE_SIMPLE_BINDING_CTOR( NAME, JSNAME, TYPE, BASENAME )        \
62     NAME::NAME(KJS::ExecState *exec, const char* typeName ) \
63         : BASENAME( exec, typeName )                    \
64     { \
65         StaticBinding::publish( exec, this, NAME::methods() ); \
66     } \
67     NAME::NAME(KJS::ExecState *exec, const TYPE & value) \
68         : BASENAME( exec, #JSNAME , value )                    \
69     { \
70         StaticBinding::publish( exec, this, NAME::methods() ); \
71     }
72 
73 #define KJSO_VALUE_DERIVED_BINDING_CTOR( NAME, JSNAME, TYPE, BASENAME )  \
74     NAME::NAME(KJS::ExecState *exec, const char* typeName ) \
75         : BASENAME( exec, typeName )                    \
76     { \
77         StaticBinding::publish( exec, this, NAME::methods() ); \
78     } \
79     NAME::NAME(KJS::ExecState *exec, const TYPE & value)                \
80         : BASENAME( exec, #JSNAME )                                         \
81     {                                                                   \
82         setValue(value);                                                \
83         StaticBinding::publish( exec, this, NAME::methods() );          \
84     }
85 
86 namespace KJSEmbed
87 {
88 /**
89  * The Bindings for the KJSEmbed::ValueBinding
90  */
91 class ValueFactory
92 {
93 public:
94     static const Method ValueMethods[];
95     static const Method *methods();
96 };
97 
98 /**
99  * Value binding implementation.
100  */
101 class ValueBinding : public ProxyBinding
102 {
103 public:
104     template <typename T>
ValueBinding(KJS::ExecState * exec,const char * typeName,T val)105     ValueBinding(KJS::ExecState *exec, const char *typeName, T val)
106         : ProxyBinding(exec),
107           m_name(typeName)
108     {
109         m_value = new Value<T>(val);
110         StaticBinding::publish(exec, this, ValueFactory::methods());
111     }
112     ValueBinding(KJS::ExecState *exec, const char *typeName);
113     ~ValueBinding() override;
114 
115     KJS::UString toString(KJS::ExecState *exec) const override;
className()116     KJS::UString className() const override
117     {
118         return m_name;
119     }
120 
121     /**
122     * Returns the stored value.
123     */
124     template< typename T>
value()125     T value() const
126     {
127         const T *ptr = reinterpret_cast<const T *>(m_value->voidStar());
128         if (ptr) {
129             return *ptr;
130         } else {
131             return T();
132         }
133     }
134 
135     /**
136     * Set the internal value.
137     */
138     template< typename T>
setValue(const T & val)139     void setValue(const T &val)
140     {
141         delete m_value;
142         m_value = new Value<T>(val);
143     }
144 
145     template< typename T>
castValue(ValueBinding * imp)146     static T castValue(ValueBinding *imp)
147     {
148         const T *ptr = reinterpret_cast<const T *>(imp->m_value->voidStar());
149         if (ptr) {
150             return *ptr;
151         } else {
152             return T();
153         }
154     }
155     static const KJS::ClassInfo info;
156 
157 private:
classInfo()158     const KJS::ClassInfo *classInfo() const override
159     {
160         return &info;
161     }
162 
163     PointerBase *m_value;
164     const char *m_name;
165 
166 };
167 
168 /**
169 * Extracts a pointer based type from an ObjectBinding object.  Care should be taken that this method
170 * is not used with KJSEmbed::ObjectBinding objects because the cast will fail.
171 */
172 template< typename T>
extractValue(KJS::ExecState * exec,KJS::JSValue * arg,const T & defaultValue)173 T extractValue(KJS::ExecState *exec, KJS::JSValue *arg, const T &defaultValue)
174 {
175     if (arg) {
176         KJSEmbed::ValueBinding *imp =
177             KJSEmbed::extractBindingImp<KJSEmbed::ValueBinding>(exec, arg);
178         if (imp) {
179             return ValueBinding::castValue<T>(imp);
180         }
181     }
182     return defaultValue;
183 }
184 
185 /**
186 * Extracts a pointer from a KJS::List of KJS::Values.  If the argument is out of range the default value
187 * is returned.
188 */
189 template< typename T>
190 T extractValue(KJS::ExecState *exec, const KJS::List &args, int idx, const T &defaultValue = T())
191 {
192     if (args.size() > idx) {
193         return extractValue<T>(exec, args[idx], defaultValue);
194     } else {
195         return defaultValue;
196     }
197 }
198 
199 template< typename T>
createValue(KJS::ExecState * exec,const KJS::UString & className,const T & value)200 KJS::JSValue *createValue(KJS::ExecState *exec, const KJS::UString &className, const T &value)
201 {
202     KJS::JSObject *parent = exec->dynamicInterpreter()->globalObject();
203     KJS::JSObject *returnValue = StaticConstructor::construct(exec, parent, className);
204     if (returnValue) {
205         // If it is a value type setValue
206         KJSEmbed::ValueBinding *imp =
207             extractBindingImp<KJSEmbed::ValueBinding>(exec, returnValue);
208         if (imp) {
209             imp->setValue(value);
210         } else {
211             KJS::throwError(exec, KJS::TypeError, toUString(QString("Created failed to cast to %1 failed").arg(toQString(className))));
212             return KJS::jsNull();
213         }
214     } else {
215         KJS::throwError(exec, KJS::TypeError, toUString(QString("Could not construct a %1").arg(toQString(className))));
216         return KJS::jsNull();
217     }
218     return returnValue;
219 }
220 }
221 
222 #endif
223 
224