File indexing completed on 2024-07-14 14:35:12

0001 /* This file is part of the KDE libraries
0002     Copyright (C) 2005, 2006 Ian Reinhart Geiser <geiseri@kde.org>
0003     Copyright (C) 2005, 2006 Matt Broadstone <mbroadst@gmail.com>
0004     Copyright (C) 2005, 2006 Richard J. Moore <rich@kde.org>
0005     Copyright (C) 2005, 2006 Erik L. Bunce <kde@bunce.us>
0006 
0007     This library is free software; you can redistribute it and/or
0008     modify it under the terms of the GNU Library General Public
0009     License as published by the Free Software Foundation; either
0010     version 2 of the License, or (at your option) any later version.
0011 
0012     This library is distributed in the hope that it will be useful,
0013     but WITHOUT ANY WARRANTY; without even the implied warranty of
0014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015     Library General Public License for more details.
0016 
0017     You should have received a copy of the GNU Library General Public License
0018     along with this library; see the file COPYING.LIB.  If not, write to
0019     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020     Boston, MA 02110-1301, USA.
0021 */
0022 
0023 #ifndef OBJECT_BINDING_H
0024 #define OBJECT_BINDING_H
0025 
0026 #include "static_binding.h"
0027 #include "variant_binding.h"
0028 #include "pointer.h"
0029 #include "kjseglobal.h"
0030 
0031 /**
0032 * A simple pointer style method.
0033 * This will extract the pointer, cast it to the native type and place it in "value".
0034 * Any data that should be returned from this method should be placed into "result";
0035 *
0036 */
0037 #define START_OBJECT_METHOD( METHODNAME, TYPE) \
0038     KJS::JSValue *METHODNAME( KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args ) \
0039     { \
0040         Q_UNUSED(exec);\
0041         Q_UNUSED(self);\
0042         Q_UNUSED(args);\
0043         KJS::JSValue *result = KJS::jsNull(); \
0044         KJSEmbed::ObjectBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::ObjectBinding>(exec, self ); \
0045         if( imp ) \
0046         { \
0047             TYPE *object = imp->object<TYPE>(); \
0048             if( object ) \
0049             {
0050 
0051 /**
0052 * End a variant method started by START_OBJECT_METHOD
0053 */
0054 #define END_OBJECT_METHOD \
0055     } \
0056     else \
0057         KJS::throwError(exec, KJS::ReferenceError, QString("O: The internal object died."));\
0058     } \
0059     else \
0060         KJS::throwError(exec, KJS::GeneralError, QString("Object cast failed."));\
0061     return result; \
0062     }
0063 
0064 #define START_STATIC_OBJECT_METHOD( METHODNAME ) \
0065     KJS::JSValue *METHODNAME( KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args ) \
0066     {\
0067         Q_UNUSED(exec);\
0068         Q_UNUSED(self);\
0069         Q_UNUSED(args);\
0070         KJS::JSValue *result = KJS::jsNull(); \
0071          
0072 #define END_STATIC_OBJECT_METHOD \
0073     return result; \
0074     }
0075 
0076 namespace KJSEmbed
0077 {
0078 class KJSEMBED_EXPORT ObjectFactory
0079 {
0080 public:
0081     static const Method ObjectMethods[];
0082     static const Method *methods()
0083     {
0084         return ObjectMethods;
0085     }
0086 };
0087 
0088 class KJSEMBED_EXPORT ObjectBinding : public ProxyBinding
0089 {
0090 public:
0091     enum Ownership { CPPOwned, QObjOwned, JSOwned  };
0092     static const KJS::ClassInfo info;
0093 
0094 private:
0095     const char *m_name;
0096     mutable PointerBase *m_value;
0097     Ownership m_owner;
0098 
0099 public:
0100     template <typename T>
0101     ObjectBinding(KJS::ExecState *exec, const char *typeName, T *ptr)
0102         : ProxyBinding(exec),
0103           m_name(typeName)
0104     {
0105         StaticBinding::publish(exec, this, ObjectFactory::methods());
0106 
0107         m_owner = CPPOwned;
0108         m_value = new Pointer<T>(ptr);
0109     }
0110 
0111     ~ObjectBinding() override;
0112 
0113     const char *typeName() const;
0114 
0115     /**
0116      * \return the internal object as a pointer of type T
0117      */
0118     template <typename T>
0119     T *object() const
0120     {
0121         if (m_value) {
0122             return pointer_cast<T>(m_value);
0123         } else {
0124             return nullptr;
0125         }
0126     }
0127 
0128     void *voidStar() const
0129     {
0130         return m_value->voidStar();
0131     }
0132 
0133     template <typename T>
0134     void setObject(T *ptr)
0135     {
0136         if (m_owner == JSOwned) {
0137             //qDebug("object cleans up");
0138             m_value->cleanup();
0139         }
0140         delete m_value;
0141         m_value = new Pointer<T>(ptr);
0142     }
0143 
0144     KJS::UString toString(KJS::ExecState *exec) const override;
0145     KJS::UString className() const override;
0146     KJS::JSType type() const override;
0147 
0148     Ownership ownership() const;
0149     void setOwnership(Ownership owner);
0150 
0151 };
0152 
0153 /**
0154 * Extracts a pointer based type from an ObjectBinding object.  Care should be taken that this method
0155 * is not used with KJSEmbed::ObjectBinding objects because the cast will fail.
0156 */
0157 template< typename T>
0158 T *extractObject(KJS::ExecState *exec, KJS::JSValue *arg, T *defaultValue)
0159 {
0160     if (!arg) {
0161         return defaultValue;
0162     } else {
0163         T *returnValue = nullptr;
0164         KJSEmbed::ObjectBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::ObjectBinding>(exec, arg);
0165         if (imp) {
0166             // GCC 3.3 has problems calling template functions in another class from a template class.
0167             // returnValue = imp->object<T>();
0168 
0169             returnValue = (T *)imp->voidStar();
0170         }
0171         if (returnValue) {
0172             return returnValue;
0173         } else {
0174             return defaultValue;
0175         }
0176     }
0177 }
0178 
0179 /**
0180 * Extracts a pointer from a KJS::List of KJS::JSValues.  If the argument is out of range the default value
0181 * is returned.
0182 */
0183 template< typename T>
0184 T *extractObject(KJS::ExecState *exec, const KJS::List &args, int idx, T *defaultValue = nullptr)
0185 {
0186     if (args.size() > idx) {
0187         return extractObject<T>(exec, args[idx], defaultValue);
0188     } else {
0189         return defaultValue;
0190     }
0191 }
0192 
0193 /**
0194 * Can create any known KJSEmbed::ObjectBinding object and set the value.
0195 * On failure a KJS::jsNull will be returned and the exception set.
0196 */
0197 template< typename T>
0198 KJS::JSValue *createObject(KJS::ExecState *exec, const KJS::UString &className, const T *value, KJSEmbed::ObjectBinding::Ownership owner = KJSEmbed::ObjectBinding::JSOwned)
0199 {
0200     if (nullptr == value) {
0201         return KJS::jsNull();
0202     }
0203 
0204     KJS::JSObject *parent = exec->dynamicInterpreter()->globalObject();
0205     KJS::JSObject *returnValue = StaticConstructor::construct(exec, parent, className);
0206     if (returnValue) {
0207         // If it is a value type setValue
0208         KJSEmbed::ObjectBinding *imp = extractBindingImp<KJSEmbed::ObjectBinding>(exec, returnValue);
0209         if (imp) {
0210             imp->setOwnership(KJSEmbed::ObjectBinding::JSOwned);
0211             imp->setObject(value);
0212             imp->setOwnership(owner);
0213         } else {
0214             throwError(exec, KJS::TypeError, i18n("%1 is not an Object type", className.ascii()));
0215             return KJS::jsNull();
0216         }
0217     } else {
0218         throwError(exec, KJS::GeneralError, "Could not construct value");
0219         //throwError(exec, "Could not construct value" );
0220         return KJS::jsNull();
0221     }
0222 
0223     return returnValue;
0224 }
0225 
0226 template< typename T >
0227 T extractParameter(KJS::ExecState *exec, KJS::JSValue *arg, const T &defaultValue)
0228 {
0229     if (!arg) {
0230         return defaultValue;
0231     } else {
0232         switch (arg->type()) {
0233         case KJS::NumberType:
0234             return extractInt(exec, arg, defaultValue);
0235             break;
0236         case KJS::BooleanType:
0237             return extractBool(exec, arg, 0);
0238             break;
0239         case KJS::UnspecifiedType:
0240         case KJS::UndefinedType:
0241         case KJS::NullType:
0242         case KJS::GetterSetterType:
0243         case KJS::StringType:
0244             return defaultValue;
0245             break;
0246         }
0247 
0248         KJS::JSObject *object = arg->toObject(exec);
0249         if (object->inherits(&VariantBinding::info)) {
0250             return extractVariant<T>(exec, arg, defaultValue);
0251         } else if (object->inherits(&ObjectBinding::info)) {
0252             return extractObject<T>(exec, arg, defaultValue);
0253         } else {
0254             return defaultValue;
0255         }
0256     }
0257 }
0258 }
0259 #endif
0260