File indexing completed on 2023-12-03 07:47:04
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 #include "variant_binding.h" 0025 0026 #include <stdlib.h> 0027 0028 #include <kjs/PropertyNameArray.h> 0029 #include <kjs/array_instance.h> 0030 0031 #include <QBitRef> 0032 #include <QByteRef> 0033 #include <QDebug> 0034 #include <QObject> 0035 #include <QWidget> 0036 0037 #include "kjseglobal.h" 0038 #include "qobject_binding.h" 0039 0040 //#define KJSEMBED_VARIANT_DEBUG 0041 0042 using namespace KJSEmbed; 0043 0044 const KJS::ClassInfo VariantBinding::info = { "VariantBinding", nullptr, nullptr, nullptr }; 0045 0046 VariantBinding::VariantBinding(KJS::ExecState *exec, const QVariant &value) 0047 : ProxyBinding(exec), m_value(value) 0048 { 0049 StaticBinding::publish(exec, this, VariantFactory::methods()); 0050 } 0051 0052 void *VariantBinding::pointer() 0053 { 0054 return m_value.data(); 0055 } 0056 0057 KJS::UString VariantBinding::toString(KJS::ExecState *) const 0058 { 0059 return toUString(m_value.toString()); 0060 } 0061 0062 KJS::UString VariantBinding::className() const 0063 { 0064 return m_value.typeName(); 0065 } 0066 0067 QVariant VariantBinding::variant() const 0068 { 0069 return m_value; 0070 } 0071 0072 void VariantBinding::setValue(const QVariant &val) 0073 { 0074 m_value = val; 0075 } 0076 0077 QGenericArgument VariantBinding::arg(const char *type) const 0078 { 0079 const void *p = m_value.constData(); 0080 //qDebug("Ptr %0x", p ); 0081 //qDebug() << p; 0082 return QGenericArgument(type, p); 0083 } 0084 0085 KJS::JSValue *callName(KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args) 0086 { 0087 Q_UNUSED(args); 0088 KJSEmbed::VariantBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::VariantBinding>(exec, self); 0089 return imp ? KJS::jsString(imp->variant().typeName()) : KJS::jsNull(); 0090 } 0091 0092 KJS::JSValue *callCast(KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args) 0093 { 0094 KJSEmbed::VariantBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::VariantBinding>(exec, self); 0095 if (imp) { 0096 QVariant val = imp->variant(); 0097 QVariant::Type type = QVariant::nameToType(args[0]->toString(exec).ascii()); 0098 KJS::JSValue *returnValue = KJS::jsBoolean(val.convert(type)); 0099 imp->setValue(val); 0100 return returnValue; 0101 } 0102 return KJS::jsNull(); 0103 } 0104 0105 KJS::JSValue *callToString(KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args) 0106 { 0107 Q_UNUSED(args); 0108 KJSEmbed::VariantBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::VariantBinding>(exec, self); 0109 if (imp) { 0110 //qDebug("Call value to string"); 0111 QVariant val = imp->variant(); 0112 QString stringVal = val.toString(); 0113 if (!stringVal.isEmpty()) { 0114 return KJS::jsString(val.toString()); 0115 } 0116 return KJS::jsString(val.typeName()); 0117 } 0118 return KJS::jsNull(); 0119 } 0120 0121 const Method VariantFactory::VariantMethods[] = { 0122 {"cast", 1, KJS::DontDelete | KJS::ReadOnly | KJS::DontEnum, &callCast }, 0123 {"toString", 0, KJS::DontDelete | KJS::ReadOnly | KJS::DontEnum, &callToString }, 0124 {nullptr, 0, 0, nullptr } 0125 }; 0126 0127 enum JavaScriptArrayType { None, List, Map }; 0128 0129 JavaScriptArrayType checkArray(KJS::ExecState *exec, KJS::JSValue *val) 0130 { 0131 KJS::JSObject *obj = val->toObject(exec); 0132 if (toQString(obj->className()) == "Array") { 0133 if (!obj->hasProperty(exec, KJS::Identifier("length"))) { 0134 return Map; 0135 } 0136 KJS::JSValue *jslen = obj->get(exec, KJS::Identifier("length")); 0137 const int len = jslen->toNumber(exec); 0138 if (len > 0) { 0139 QByteArray buff; 0140 buff.setNum(len - 1); 0141 if (!obj->hasProperty(exec, KJS::Identifier(buff.data()))) { 0142 return Map; 0143 } 0144 } 0145 return List; 0146 } else { 0147 return None; 0148 } 0149 } 0150 0151 QMap<QString, QVariant> KJSEmbed::convertArrayToMap(KJS::ExecState *exec, KJS::JSValue *value) 0152 { 0153 QMap<QString, QVariant> returnMap; 0154 KJS::JSObject *obj = value->toObject(exec); 0155 KJS::PropertyNameArray lst; 0156 obj->getPropertyNames(exec, lst); 0157 KJS::PropertyNameArrayIterator idx = lst.begin(); 0158 for (; idx != lst.end(); idx++) { 0159 KJS::Identifier id = *idx; 0160 KJS::JSValue *val = obj->get(exec, id); 0161 returnMap[toQString(id)] = convertToVariant(exec, val); 0162 } 0163 return returnMap; 0164 } 0165 0166 QList<QVariant> KJSEmbed::convertArrayToList(KJS::ExecState *exec, KJS::JSValue *value) 0167 { 0168 QList<QVariant> returnList; 0169 /* 0170 KJS::JSObject *obj = value->toObject( exec ); 0171 if ( toQString(obj->className() == "Array" ) 0172 { 0173 int length = int(obj->get( exec, KJS::Identifier( "length" ) )->toInteger( exec ) ); 0174 for ( int index = 0; index < length; ++index ) 0175 { 0176 QByteArray buff; 0177 buff.setNum(index); 0178 KJS::JSValue *val = obj->get(exec, KJS::Identifier( buff.data() ) ); 0179 if( val ) 0180 returnList += convertToVariant(exec, val ); 0181 else 0182 returnList += QVariant(); 0183 } 0184 } 0185 */ 0186 KJS::ArrayInstance *arrayImp = extractBindingImp<KJS::ArrayInstance>(exec, value); 0187 if (arrayImp) { 0188 const unsigned numItems = arrayImp->getLength(); 0189 for (unsigned i = 0; i < numItems; ++i) { 0190 returnList.append(convertToVariant(exec, arrayImp->getItem(i))); 0191 } 0192 } 0193 return returnList; 0194 } 0195 0196 QStringList KJSEmbed::convertArrayToStringList(KJS::ExecState *exec, KJS::JSValue *value) 0197 { 0198 QStringList returnList; 0199 /* 0200 KJS::JSObject *obj = value->toObject( exec ); 0201 if ( toQString(obj->className()) == "Array" ) 0202 { 0203 int length = int( obj->get( exec, KJS::Identifier( "length" ) )->toInteger( exec ) ); 0204 for ( int index = 0; index < length; ++index ) 0205 { 0206 QByteArray buff; 0207 buff.setNum(index); 0208 KJS::JSValue *val = obj->get(exec, KJS::Identifier( buff.data() ) ); 0209 if( val ) 0210 returnList += convertToVariant(exec, val ).value<QString>(); 0211 else 0212 returnList += QString(); 0213 } 0214 } 0215 */ 0216 KJS::ArrayInstance *arrayImp = extractBindingImp<KJS::ArrayInstance>(exec, value); 0217 if (arrayImp) { 0218 const unsigned numItems = arrayImp->getLength(); 0219 for (unsigned i = 0; i < numItems; ++i) { 0220 returnList.append(convertToVariant(exec, arrayImp->getItem(i)).toString()); 0221 } 0222 } 0223 return returnList; 0224 } 0225 0226 QDateTime convertDateToDateTime(KJS::ExecState *exec, KJS::JSValue *value) 0227 { 0228 KJS::List args; 0229 QDateTime returnDateTime; 0230 KJS::JSObject *obj = value->toObject(exec); 0231 if (toQString(obj->className()) == "Date") { 0232 int seconds = int(obj->get(exec, KJS::Identifier("getSeconds"))->toObject(exec)->call(exec, obj, args)->toInteger(exec)); 0233 int minutes = int(obj->get(exec, KJS::Identifier("getMinutes"))->toObject(exec)->call(exec, obj, args)->toInteger(exec)); 0234 int hours = int(obj->get(exec, KJS::Identifier("getHours"))->toObject(exec)->call(exec, obj, args)->toInteger(exec)); 0235 int month = int(obj->get(exec, KJS::Identifier("getMonth"))->toObject(exec)->call(exec, obj, args)->toInteger(exec)); 0236 int day = int(obj->get(exec, KJS::Identifier("getDate"))->toObject(exec)->call(exec, obj, args)->toInteger(exec)); 0237 int year = int(obj->get(exec, KJS::Identifier("getFullYear"))->toObject(exec)->call(exec, obj, args)->toInteger(exec)); 0238 returnDateTime.setDate(QDate(year, month + 1, day)); 0239 returnDateTime.setTime(QTime(hours, minutes, seconds)); 0240 } else { 0241 // Throw error 0242 } 0243 0244 return returnDateTime; 0245 } 0246 0247 QVariant KJSEmbed::convertToVariant(KJS::ExecState *exec, KJS::JSValue *value) 0248 { 0249 #ifdef KJSEMBED_VARIANT_DEBUG 0250 qDebug() << "KJSEmbed::convertToVariant"; 0251 #endif 0252 0253 QVariant returnValue; 0254 switch (value->type()) { 0255 case KJS::UndefinedType: 0256 case KJS::NullType: 0257 break; 0258 case KJS::StringType: 0259 returnValue = toQString(value->toString(exec)); 0260 break; 0261 case KJS::NumberType: 0262 returnValue = value->toNumber(exec); 0263 break; 0264 case KJS::BooleanType: 0265 returnValue = value->toBoolean(exec); 0266 break; 0267 case KJS::ObjectType: { 0268 KJS::JSObject *obj = value->toObject(exec); 0269 //qDebug() << "Object type: " << toQString(obj->className()); 0270 if (toQString(obj->className()) == "Array") { 0271 if (checkArray(exec, value) == List) { 0272 returnValue = convertArrayToList(exec, value); 0273 } else { 0274 returnValue = convertArrayToMap(exec, value); 0275 } 0276 } else if (toQString(obj->className()) == "Date") { 0277 returnValue = convertDateToDateTime(exec, value); 0278 } else { 0279 returnValue = extractVariant(exec, value); 0280 } 0281 //if( returnValue.isNull() ) returnValue = toQString(value->toString(exec)); 0282 } break; 0283 default: 0284 returnValue = extractVariant(exec, value); 0285 //if( returnValue.isNull() ) returnValue = toQString(value->toString(exec)); 0286 break; 0287 } 0288 return returnValue; 0289 } 0290 0291 KJS::JSValue *KJSEmbed::convertToValue(KJS::ExecState *exec, const QVariant &value) 0292 { 0293 #ifdef KJSEMBED_VARIANT_DEBUG 0294 qDebug() << "KJSEmbed::convertToValue typeid=" << value.type() << "typename=" << value.typeName() << "toString=" << value.toString(); 0295 #endif 0296 0297 KJS::JSValue *returnValue; 0298 switch (value.type()) { 0299 case QVariant::Invalid: 0300 returnValue = KJS::jsNull(); 0301 break; 0302 case QVariant::Int: 0303 returnValue = KJS::jsNumber(value.value<int>()); 0304 break; 0305 case QVariant::UInt: 0306 returnValue = KJS::jsNumber(value.value<unsigned int>()); 0307 break; 0308 case QVariant::LongLong: 0309 returnValue = KJS::jsNumber(value.value<qlonglong>()); 0310 break; 0311 case QVariant::ULongLong: 0312 returnValue = KJS::jsNumber(value.value<qulonglong>()); 0313 break; 0314 case QVariant::Double: 0315 returnValue = KJS::jsNumber(value.value<double>()); 0316 break; 0317 case QVariant::Bool: 0318 returnValue = KJS::jsBoolean(value.value<bool>()); 0319 break; 0320 case QVariant::ByteArray: 0321 returnValue = KJS::jsString(QString(value.value<QByteArray>())); 0322 break; 0323 case QVariant::String: 0324 returnValue = KJS::jsString(value.value<QString>()); 0325 break; 0326 case QVariant::StringList: { 0327 KJS::List items; 0328 QStringList lst = value.value<QStringList>(); 0329 QStringList::Iterator idx = lst.begin(); 0330 for (; idx != lst.end(); ++idx) { 0331 items.append(KJS::jsString((*idx))); 0332 } 0333 returnValue = exec->lexicalInterpreter()->builtinArray()->construct(exec, items); 0334 break; 0335 } 0336 case QVariant::Date: // fall through 0337 case QVariant::DateTime: // fall through 0338 case QVariant::Time: { 0339 QDateTime dt = QDateTime::currentDateTime(); 0340 if (value.type() == QVariant::Date) { 0341 dt.setDate(value.toDate()); 0342 } else if (value.type() == QVariant::Time) { 0343 dt.setTime(value.toTime()); 0344 } else { 0345 dt = value.toDateTime(); 0346 } 0347 0348 KJS::List items; 0349 items.append(KJS::jsNumber(dt.date().year())); 0350 items.append(KJS::jsNumber(dt.date().month() - 1)); 0351 items.append(KJS::jsNumber(dt.date().day())); 0352 items.append(KJS::jsNumber(dt.time().hour())); 0353 items.append(KJS::jsNumber(dt.time().minute())); 0354 items.append(KJS::jsNumber(dt.time().second())); 0355 items.append(KJS::jsNumber(dt.time().msec())); 0356 returnValue = exec->lexicalInterpreter()->builtinDate()->construct(exec, items); 0357 break; 0358 } 0359 case QVariant::List: { 0360 KJS::List items; 0361 QList<QVariant> lst = value.toList(); 0362 foreach (const QVariant &item, lst) { 0363 items.append(convertToValue(exec, item)); 0364 } 0365 returnValue = exec->lexicalInterpreter()->builtinArray()->construct(exec, items); 0366 break; 0367 } 0368 case QVariant::Map: { 0369 QMap<QString, QVariant> map = value.toMap(); 0370 QMap<QString, QVariant>::Iterator idx = map.begin(); 0371 KJS::JSObject *obj = exec->lexicalInterpreter()->builtinObject()->construct(exec, KJS::List()); 0372 for (; idx != map.end(); ++idx) { 0373 obj->put(exec, KJS::Identifier(toUString(idx.key())), convertToValue(exec, idx.value())); 0374 } 0375 returnValue = obj; 0376 break; 0377 } 0378 default: { 0379 if (value.canConvert< QWidget * >()) { 0380 QWidget *widget = qvariant_cast< QWidget * >(value); 0381 returnValue = widget ? createQObject(exec, widget, KJSEmbed::ObjectBinding::CPPOwned) : KJS::jsNull(); 0382 } else if (value.canConvert< QObject * >()) { 0383 QObject *object = qvariant_cast< QObject * >(value); 0384 returnValue = object ? createQObject(exec, object, KJSEmbed::ObjectBinding::CPPOwned) : KJS::jsNull(); 0385 } else { 0386 returnValue = createVariant(exec, value.typeName(), value); 0387 if (returnValue->isNull()) { 0388 returnValue = KJS::jsString(value.value<QString>()); 0389 } 0390 } 0391 break; 0392 } 0393 } 0394 return returnValue; 0395 } 0396 0397 QVariant KJSEmbed::extractVariant(KJS::ExecState *exec, KJS::JSValue *value) 0398 { 0399 #ifdef KJSEMBED_VARIANT_DEBUG 0400 qDebug() << "KJSEmbed::extractVariant"; 0401 #endif 0402 0403 KJSEmbed::VariantBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::VariantBinding>(exec, value); 0404 if (imp) { 0405 return imp->variant(); 0406 } 0407 if (value->type() == KJS::StringType) { 0408 return QVariant(toQString(value->toString(exec))); 0409 } 0410 if (value->type() == KJS::NumberType) { 0411 return QVariant(value->toNumber(exec)); 0412 } 0413 if (value->type() == KJS::BooleanType) { 0414 return QVariant(value->toBoolean(exec)); 0415 } 0416 0417 KJS::JSObject *obj = value->toObject(exec); 0418 if (obj) { 0419 if (QObjectBinding *objImp = KJSEmbed::extractBindingImp<QObjectBinding>(exec, value)) { 0420 QVariant v; 0421 if (QObject *qobj = objImp->qobject<QObject>()) { 0422 v.setValue(qobj); 0423 } 0424 return v; 0425 } 0426 if (toQString(obj->className()) == "Array") { 0427 return convertArrayToList(exec, value); 0428 } 0429 } 0430 return QVariant(); 0431 } 0432