00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "variant_binding.h"
00025
00026 #include <stdlib.h>
00027
00028 #include <kjs/PropertyNameArray.h>
00029 #include <kjs/array_instance.h>
00030
00031 #include <QtCore/QBitRef>
00032 #include <QtCore/QByteRef>
00033 #include <QtCore/QDebug>
00034 #include <QtCore/QObject>
00035 #include <QtGui/QWidget>
00036
00037 #include "kjseglobal.h"
00038 #include "static_binding.h"
00039 #include "qobject_binding.h"
00040
00041
00042
00043 using namespace KJSEmbed;
00044
00045 const KJS::ClassInfo VariantBinding::info = { "VariantBinding", 0, 0, 0 };
00046
00047 VariantBinding::VariantBinding( KJS::ExecState *exec, const QVariant &value )
00048 : ProxyBinding(exec), m_value(value)
00049 {
00050 StaticBinding::publish( exec, this, VariantFactory::methods() );
00051 }
00052
00053 void *VariantBinding::pointer()
00054 {
00055 return m_value.data();
00056 }
00057
00058 KJS::UString VariantBinding::toString(KJS::ExecState *) const
00059 {
00060 return toUString(m_value.toString());
00061 }
00062
00063 KJS::UString VariantBinding::className() const
00064 {
00065 return m_value.typeName();
00066 }
00067
00068 QVariant VariantBinding::variant() const
00069 {
00070 return m_value;
00071 }
00072
00073 void VariantBinding::setValue( const QVariant &val )
00074 {
00075 m_value = val;
00076 }
00077
00078 QGenericArgument VariantBinding::arg(const char *type) const
00079 {
00080 const void *p = m_value.constData();
00081
00082
00083 return QGenericArgument( type, p );
00084 }
00085
00086 KJS::JSValue *callName( KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args )
00087 {
00088 Q_UNUSED( args );
00089 KJSEmbed::VariantBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::VariantBinding>(exec, self);
00090 return imp ? KJS::jsString( imp->variant().typeName() ) : KJS::jsNull();
00091 }
00092
00093 KJS::JSValue *callCast( KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args )
00094 {
00095 KJSEmbed::VariantBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::VariantBinding>(exec, self );
00096 if( imp )
00097 {
00098 QVariant val = imp->variant();
00099 QVariant::Type type = QVariant::nameToType( args[0]->toString(exec).ascii() );
00100 KJS::JSValue *returnValue = KJS::jsBoolean(val.convert(type));
00101 imp->setValue(val);
00102 return returnValue;
00103 }
00104 return KJS::jsNull();
00105 }
00106
00107 KJS::JSValue *callToString( KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args )
00108 {
00109 Q_UNUSED( args );
00110 KJSEmbed::VariantBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::VariantBinding>(exec, self );
00111 if( imp )
00112 {
00113
00114 QVariant val = imp->variant();
00115 QString stringVal = val.toString();
00116 if( !stringVal.isEmpty() )
00117 return KJS::jsString( val.toString() );
00118 return KJS::jsString( val.typeName() );
00119 }
00120 return KJS::jsNull();
00121 }
00122
00123 const Method VariantFactory::VariantMethods[] =
00124 {
00125 {"cast", 1, KJS::DontDelete|KJS::ReadOnly|KJS::DontEnum, &callCast },
00126 {"toString", 0, KJS::DontDelete|KJS::ReadOnly|KJS::DontEnum, &callToString },
00127 {0, 0, 0, 0 }
00128 };
00129
00130 enum JavaScriptArrayType { None, List, Map };
00131
00132 JavaScriptArrayType checkArray( KJS::ExecState *exec, KJS::JSValue *val )
00133 {
00134 KJS::JSObject *obj = val->toObject( exec );
00135 if ( toQString(obj->className()) == "Array" )
00136 {
00137 if( !obj->hasProperty(exec, KJS::Identifier("length")) )
00138 return Map;
00139 KJS::JSValue *jslen = obj->get(exec, KJS::Identifier("length"));
00140 const int len = jslen->toNumber(exec);
00141 if ( len > 0 ) {
00142 QByteArray buff;
00143 buff.setNum(len-1);
00144 if( !obj->hasProperty(exec, KJS::Identifier( buff.data() ) ) )
00145 return Map;
00146 }
00147 return List;
00148 }
00149 else
00150 return None;
00151 }
00152
00153 QMap<QString, QVariant> KJSEmbed::convertArrayToMap( KJS::ExecState *exec, KJS::JSValue *value )
00154 {
00155 QMap<QString, QVariant> returnMap;
00156 KJS::JSObject *obj = value->toObject(exec);
00157 KJS::PropertyNameArray lst;
00158 obj->getPropertyNames(exec, lst);
00159 KJS::PropertyNameArrayIterator idx = lst.begin();
00160 for( ; idx != lst.end(); idx++ )
00161 {
00162 KJS::Identifier id = *idx;
00163 KJS::JSValue *val = obj->get(exec, id);
00164 returnMap[toQString(id)] = convertToVariant(exec,val);
00165 }
00166 return returnMap;
00167 }
00168
00169 QList<QVariant> KJSEmbed::convertArrayToList( KJS::ExecState *exec, KJS::JSValue *value )
00170 {
00171 QList<QVariant> returnList;
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189 KJS::ArrayInstance* arrayImp = extractBindingImp<KJS::ArrayInstance>(exec, value);
00190 if(arrayImp)
00191 {
00192 const unsigned numItems = arrayImp->getLength();
00193 for ( unsigned i = 0; i < numItems; ++i )
00194 returnList.append( convertToVariant(exec, arrayImp->getItem(i)) );
00195 }
00196 return returnList;
00197 }
00198
00199 QStringList KJSEmbed::convertArrayToStringList( KJS::ExecState *exec, KJS::JSValue *value )
00200 {
00201 QStringList returnList;
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219 KJS::ArrayInstance* arrayImp = extractBindingImp<KJS::ArrayInstance>(exec, value);
00220 if(arrayImp)
00221 {
00222 const unsigned numItems = arrayImp->getLength();
00223 for ( unsigned i = 0; i < numItems; ++i )
00224 returnList.append( convertToVariant(exec, arrayImp->getItem(i)).toString() );
00225 }
00226 return returnList;
00227 }
00228
00229 QDateTime convertDateToDateTime( KJS::ExecState *exec, KJS::JSValue *value )
00230 {
00231 KJS::List args;
00232 QDateTime returnDateTime;
00233 KJS::JSObject *obj = value->toObject( exec );
00234 if ( toQString(obj->className()) == "Date" )
00235 {
00236 int seconds = int( obj->get( exec, KJS::Identifier( "getSeconds" ) )->toObject( exec )->call( exec, obj, args )->toInteger( exec ) );
00237 int minutes = int( obj->get( exec, KJS::Identifier( "getMinutes" ) )->toObject( exec )->call( exec, obj, args )->toInteger( exec ) );
00238 int hours = int( obj->get( exec, KJS::Identifier( "getHours" ) )->toObject( exec )->call( exec, obj, args )->toInteger( exec ) );
00239 int month = int( obj->get( exec, KJS::Identifier( "getMonth" ) )->toObject( exec )->call( exec, obj, args )->toInteger( exec ) );
00240 int day = int( obj->get( exec, KJS::Identifier( "getDate" ) )->toObject( exec )->call( exec, obj, args )->toInteger( exec ) );
00241 int year = int( obj->get( exec, KJS::Identifier( "getFullYear" ) )->toObject( exec )->call( exec, obj, args )->toInteger( exec ) );
00242 returnDateTime.setDate( QDate( year, month + 1, day ) );
00243 returnDateTime.setTime( QTime( hours, minutes, seconds ) );
00244 }
00245 else
00246 {
00247
00248 }
00249
00250 return returnDateTime;
00251 }
00252
00253 QVariant KJSEmbed::convertToVariant( KJS::ExecState *exec, KJS::JSValue *value )
00254 {
00255 #ifdef KJSEMBED_VARIANT_DEBUG
00256 qDebug()<<"KJSEmbed::convertToVariant";
00257 #endif
00258
00259 QVariant returnValue;
00260 switch( value->type() )
00261 {
00262 case KJS::UndefinedType:
00263 case KJS::NullType:
00264 break;
00265 case KJS::StringType:
00266 returnValue = toQString(value->toString(exec));
00267 break;
00268 case KJS::NumberType:
00269 returnValue = value->toNumber(exec);
00270 break;
00271 case KJS::BooleanType:
00272 returnValue = value->toBoolean(exec);
00273 break;
00274 case KJS::ObjectType:
00275 {
00276 KJS::JSObject *obj = value->toObject(exec);
00277
00278 if ( toQString(obj->className()) == "Array" ) {
00279 if (checkArray(exec, value) == List)
00280 returnValue = convertArrayToList(exec, value);
00281 else
00282 returnValue = convertArrayToMap(exec, value);
00283 }
00284 else if ( toQString(obj->className()) == "Date" )
00285 returnValue = convertDateToDateTime( exec, value );
00286 else
00287 returnValue = extractVariant(exec,value);
00288
00289 } break;
00290 default:
00291 returnValue = extractVariant(exec,value);
00292
00293 break;
00294 }
00295 return returnValue;
00296 }
00297
00298 KJS::JSValue *KJSEmbed::convertToValue( KJS::ExecState *exec, const QVariant &value )
00299 {
00300 #ifdef KJSEMBED_VARIANT_DEBUG
00301 qDebug()<<"KJSEmbed::convertToValue typeid="<<value.type()<<"typename="<<value.typeName()<<"toString="<<value.toString();
00302 #endif
00303
00304 KJS::JSValue *returnValue;
00305 switch( value.type() )
00306 {
00307 case QVariant::Invalid:
00308 returnValue = KJS::jsNull();
00309 break;
00310 case QVariant::Int:
00311 returnValue = KJS::jsNumber( value.value<int>() );
00312 break;
00313 case QVariant::UInt:
00314 returnValue = KJS::jsNumber( value.value<unsigned int>() );
00315 break;
00316 case QVariant::LongLong:
00317 returnValue = KJS::jsNumber( value.value<qlonglong>() );
00318 break;
00319 case QVariant::ULongLong:
00320 returnValue = KJS::jsNumber( value.value<qulonglong>() );
00321 break;
00322 case QVariant::Double:
00323 returnValue = KJS::jsNumber( value.value<double>() );
00324 break;
00325 case QVariant::Bool:
00326 returnValue = KJS::jsBoolean( value.value<bool>() );
00327 break;
00328 case QVariant::ByteArray:
00329 returnValue = KJS::jsString( QString(value.value<QByteArray>()) );
00330 break;
00331 case QVariant::String:
00332 returnValue = KJS::jsString( value.value<QString>() );
00333 break;
00334 case QVariant::StringList:
00335 {
00336 KJS::List items;
00337 QStringList lst = value.value<QStringList>();
00338 QStringList::Iterator idx = lst.begin();
00339 for ( ; idx != lst.end(); ++idx )
00340 items.append( KJS::jsString( ( *idx ) ) );
00341 returnValue = exec->lexicalInterpreter()->builtinArray()->construct( exec, items );
00342 break;
00343 }
00344 case QVariant::Date:
00345 case QVariant::DateTime:
00346 case QVariant::Time:
00347 {
00348 QDateTime dt = QDateTime::currentDateTime();
00349 if ( value.type() == QVariant::Date )
00350 dt.setDate( value.toDate() );
00351 else if ( value.type() == QVariant::Time )
00352 dt.setTime( value.toTime() );
00353 else
00354 dt = value.toDateTime();
00355
00356 KJS::List items;
00357 items.append( KJS::jsNumber( dt.date().year() ) );
00358 items.append( KJS::jsNumber( dt.date().month() - 1 ) );
00359 items.append( KJS::jsNumber( dt.date().day() ) );
00360 items.append( KJS::jsNumber( dt.time().hour() ) );
00361 items.append( KJS::jsNumber( dt.time().minute() ) );
00362 items.append( KJS::jsNumber( dt.time().second() ) );
00363 items.append( KJS::jsNumber( dt.time().msec() ) );
00364 returnValue = exec->lexicalInterpreter()->builtinDate()->construct( exec, items );
00365 break;
00366 }
00367 case QVariant::List:
00368 {
00369 KJS::List items;
00370 QList<QVariant> lst = value.toList();
00371 foreach( const QVariant &item, lst)
00372 items.append( convertToValue( exec, item ) );
00373 returnValue = exec->lexicalInterpreter()->builtinArray()->construct( exec, items );
00374 break;
00375 }
00376 case QVariant::Map:
00377 {
00378 QMap<QString,QVariant> map = value.toMap();
00379 QMap<QString,QVariant>::Iterator idx = map.begin();
00380 KJS::JSObject *obj = exec->lexicalInterpreter()->builtinObject()->construct( exec, KJS::List() );
00381 for ( ; idx != map.end(); ++idx )
00382 obj->put(exec, KJS::Identifier( toUString(idx.key()) ), convertToValue( exec, idx.value() ) );
00383 returnValue = obj;
00384 break;
00385 }
00386 default:
00387 {
00388 if( qVariantCanConvert< QWidget* >(value) ) {
00389 QWidget* widget = qvariant_cast< QWidget* >(value);
00390 returnValue = widget ? createQObject(exec, widget, KJSEmbed::ObjectBinding::CPPOwned) : KJS::jsNull();
00391 }
00392 else if( qVariantCanConvert< QObject* >(value) ) {
00393 QObject* object = qvariant_cast< QObject* >(value);
00394 returnValue = object ? createQObject(exec, object, KJSEmbed::ObjectBinding::CPPOwned) : KJS::jsNull();
00395 }
00396 else {
00397 returnValue = createVariant(exec, value.typeName(), value );
00398 if( returnValue->isNull() )
00399 returnValue = KJS::jsString( value.value<QString>() );
00400 }
00401 break;
00402 }
00403 }
00404 return returnValue;
00405 }
00406
00407 QVariant KJSEmbed::extractVariant( KJS::ExecState *exec, KJS::JSValue *value )
00408 {
00409 #ifdef KJSEMBED_VARIANT_DEBUG
00410 qDebug()<<"KJSEmbed::extractVariant";
00411 #endif
00412
00413 KJSEmbed::VariantBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::VariantBinding>(exec, value );
00414 if( imp )
00415 return imp->variant();
00416 if( value->type() == KJS::StringType)
00417 return QVariant(toQString(value->toString(exec)));
00418 if( value->type() == KJS::NumberType)
00419 return QVariant(value->toNumber(exec));
00420 if( value->type() == KJS::BooleanType)
00421 return QVariant(value->toBoolean(exec));
00422
00423 KJS::JSObject *obj = value->toObject( exec );
00424 if ( obj ) {
00425 if(QObjectBinding *objImp = KJSEmbed::extractBindingImp<QObjectBinding>(exec, value)) {
00426 QVariant v;
00427 if( QObject* qobj = objImp->qobject<QObject>() )
00428 v.setValue(qobj);
00429 return v;
00430 }
00431 if( toQString(obj->className()) == "Array" )
00432 return convertArrayToList( exec, value );
00433 }
00434 return QVariant();
00435 }
00436
00437