File indexing completed on 2024-12-01 09:54:45
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 Copyright (C) 2007, 2008 Sebastian Sauer <mail@dipe.org> 0007 0008 This library is free software; you can redistribute it and/or 0009 modify it under the terms of the GNU Library General Public 0010 License as published by the Free Software Foundation; either 0011 version 2 of the License, or (at your option) any later version. 0012 0013 This library is distributed in the hope that it will be useful, 0014 but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0016 Library General Public License for more details. 0017 0018 You should have received a copy of the GNU Library General Public License 0019 along with this library; see the file COPYING.LIB. If not, write to 0020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0021 Boston, MA 02110-1301, USA. 0022 */ 0023 0024 #ifndef VARIANT_BINDING_H 0025 #define VARIANT_BINDING_H 0026 0027 #include <QVariant> 0028 0029 #include <kjs/object.h> 0030 #include <kjs/interpreter.h> 0031 0032 #include "static_binding.h" 0033 0034 /** 0035 * A simple variant style method. 0036 * This will extract the QVariant, cast it to the native type and place it in "value". 0037 * Any data that should be returned from this method should be placed into "result"; 0038 * 0039 */ 0040 #define START_VARIANT_METHOD( METHODNAME, TYPE) \ 0041 KJS::JSValue *METHODNAME( KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args ) \ 0042 { \ 0043 Q_UNUSED(exec);\ 0044 Q_UNUSED(self);\ 0045 Q_UNUSED(args);\ 0046 KJS::JSValue *result = KJS::jsNull(); \ 0047 KJSEmbed::VariantBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::VariantBinding>(exec, self ); \ 0048 if( imp ) \ 0049 { \ 0050 TYPE value = imp->value<TYPE>(); 0051 /** 0052 * End a variant method started by START_VARIANT_METHOD 0053 */ 0054 #define END_VARIANT_METHOD \ 0055 imp->setValue(QVariant::fromValue(value)); \ 0056 } \ 0057 else \ 0058 {\ 0059 KJS::throwError(exec, KJS::GeneralError, "We have a problem baby");\ 0060 }\ 0061 return result; \ 0062 } 0063 0064 #define KJSO_VARIANT_SIMPLE_BINDING_CTOR( NAME, JSNAME, TYPE, BASENAME ) \ 0065 NAME::NAME(KJS::ExecState *exec, const char* typeName ) \ 0066 : BASENAME( exec, typeName ) \ 0067 { \ 0068 StaticBinding::publish( exec, this, NAME::methods() ); \ 0069 } \ 0070 NAME::NAME(KJS::ExecState *exec, const TYPE & value) \ 0071 : BASENAME( exec, QVariant::fromValue(value)) \ 0072 { \ 0073 StaticBinding::publish( exec, this, NAME::methods() ); \ 0074 } 0075 0076 namespace KJSEmbed 0077 { 0078 /** 0079 * QVariant based binding. This class wraps the implementation. 0080 * You should never have to use this class directly instead use KJSEmbed::createVariant. 0081 */ 0082 0083 /** 0084 * QVariant bindinging implementation. 0085 */ 0086 class KJSEMBED_EXPORT VariantBinding : public ProxyBinding 0087 { 0088 public: 0089 /** 0090 * Create a new binding implementation with a QVariant to wrap 0091 */ 0092 VariantBinding(KJS::ExecState *exec, const QVariant &value); 0093 ~VariantBinding() override {} 0094 0095 void *pointer(); 0096 0097 KJS::UString toString(KJS::ExecState *) const override; 0098 KJS::UString className() const override; 0099 0100 /** 0101 * Return the wrapped QVariant 0102 */ 0103 QVariant variant() const; 0104 0105 /** 0106 * Extract the actual value from the wrapper. This method wraps QVariant::value, so it will support 0107 * some aspects of casting. If the cast fails a default value of T will be returned. 0108 */ 0109 template<typename T> 0110 T value() const 0111 { 0112 return m_value.value<T>(); 0113 } 0114 /** 0115 * Set the internal value of the QVariant. 0116 */ 0117 void setValue(const QVariant &val); 0118 0119 /** 0120 * Constructs a QGenericArgument that is used with QMetaObject::invokeMember 0121 */ 0122 QGenericArgument arg(const char *type) const; 0123 0124 static const KJS::ClassInfo info; 0125 0126 private: 0127 const KJS::ClassInfo *classInfo() const override 0128 { 0129 return &info; 0130 } 0131 QVariant m_value; 0132 0133 }; 0134 0135 /** 0136 * Extracts a QVariant from a KJS::JSValue if the conversion fails a QVariant::Null is returned. 0137 */ 0138 QVariant KJSEMBED_EXPORT extractVariant(KJS::ExecState *exec, KJS::JSValue *value); 0139 0140 /** 0141 * Extracts a value based type from a VariantBinding object. This method calls @ref extractVariant so if 0142 * the conversions fails then the default value will be returned. Care should be taken that this method 0143 * is not used with KJSEmbed::ObjectBinding objects because the cast will fail. 0144 */ 0145 template< typename T> 0146 T extractVariant(KJS::ExecState *exec, KJS::JSValue *arg, const T &defaultValue) 0147 { 0148 if (!arg) { 0149 return defaultValue; 0150 } else { 0151 QVariant variant = extractVariant(exec, arg); 0152 if (!variant.isNull()) { 0153 if (variant.canConvert<T>()) { 0154 return variant.value<T>(); 0155 } else { 0156 throwError(exec, KJS::TypeError, "Cast failed"); 0157 return defaultValue; 0158 } 0159 } else { 0160 return defaultValue; 0161 } 0162 } 0163 } 0164 0165 /** 0166 * Extracts a value from a KJS::List of KJS::JSValues. If the argument is out of range the default value 0167 * is returned. 0168 */ 0169 template< typename T> 0170 T extractVariant(KJS::ExecState *exec, const KJS::List &args, int idx, const T &defaultValue = T()) 0171 { 0172 if (args.size() >= idx) { 0173 return extractVariant<T>(exec, args[idx], defaultValue); 0174 } else { 0175 return defaultValue; 0176 } 0177 } 0178 0179 /** 0180 * Can create any known KJSEmbed::VariantBinding object and set the value. 0181 * On failure a KJS::jsNull will be returned and the exception set. Only values 0182 * that are supported by QVariant will work. 0183 */ 0184 template< typename T> 0185 KJS::JSValue *createVariant(KJS::ExecState *exec, const KJS::UString &className, const T &value) 0186 { 0187 KJS::JSObject *parent; 0188 parent = exec->dynamicInterpreter()->globalObject(); 0189 KJS::JSObject *returnValue = StaticConstructor::construct(exec, parent, className); 0190 if (returnValue) { 0191 // If it is a value type setValue 0192 KJSEmbed::VariantBinding *imp = extractBindingImp<KJSEmbed::VariantBinding>(exec, returnValue); 0193 if (imp) { 0194 imp->setValue(QVariant::fromValue(value)); 0195 } else { 0196 throwError(exec, KJS::TypeError, toUString(QString("Created failed to cast to %1 failed").arg(toQString(className)))); 0197 return KJS::jsNull(); 0198 } 0199 } else { 0200 throwError(exec, KJS::TypeError, toUString(QString("Could not construct a %1").arg(toQString(className)))); 0201 return KJS::jsNull(); 0202 } 0203 return returnValue; 0204 } 0205 0206 /** 0207 * Convert a KJS::JSValue that contains an associative array into a QMap. If you call 0208 * this on a normal Javascript object you will get each property as the key and its 0209 * data as the value. A normal array will give you a QMap with each key being the 0210 * index. 0211 */ 0212 QMap<QString, QVariant> KJSEMBED_EXPORT convertArrayToMap(KJS::ExecState *exec, KJS::JSValue *value); 0213 0214 /** 0215 * Convert a KJS::JSValue into a QList. If the list contains only strings, or objects that can be 0216 * converted to strings you can call to @ref convertArrayToStringList. If you call this on an 0217 * associative array or a javascript object the list will return empty. Unless there happens to be 0218 * a property with a numeric index present, then all bets are off. 0219 */ 0220 QList<QVariant> KJSEMBED_EXPORT convertArrayToList(KJS::ExecState *exec, KJS::JSValue *value); 0221 0222 /** 0223 * Convert a KJS::JSValue into a QStringList. @see convertArrayToList. 0224 */ 0225 QStringList KJSEMBED_EXPORT convertArrayToStringList(KJS::ExecState *exec, KJS::JSValue *value); 0226 0227 /** 0228 * Convert a KJS::JSValue into a QVariant object 0229 */ 0230 QVariant KJSEMBED_EXPORT convertToVariant(KJS::ExecState *exec, KJS::JSValue *value); 0231 0232 /** 0233 * Convert a QVariant to a KJS::JSValue. If the type is a known type the bindings will be added. 0234 * If the type is supported by QVariant, but is not supported by KJSEmbed then it will just be wrapped. 0235 * This wrapped value can be used just like normal value bindings, save for the lack of methods available to the object. 0236 */ 0237 KJSEMBED_EXPORT KJS::JSValue *convertToValue(KJS::ExecState *exec, const QVariant &value); 0238 0239 /** 0240 * The Bindings for the KJSEmbed::VariantBinding 0241 */ 0242 struct Method; 0243 class KJSEMBED_EXPORT VariantFactory 0244 { 0245 public: 0246 static const Method VariantMethods[]; 0247 static const Method *methods() 0248 { 0249 return VariantMethods; 0250 } 0251 }; 0252 0253 } 0254 #endif 0255