kjsembed
variant_binding.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2005, 2006 Ian Reinhart Geiser <geiseri@kde.org> 00003 Copyright (C) 2005, 2006 Matt Broadstone <mbroadst@gmail.com> 00004 Copyright (C) 2005, 2006 Richard J. Moore <rich@kde.org> 00005 Copyright (C) 2005, 2006 Erik L. Bunce <kde@bunce.us> 00006 Copyright (C) 2007, 2008 Sebastian Sauer <mail@dipe.org> 00007 00008 This library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Library General Public 00010 License as published by the Free Software Foundation; either 00011 version 2 of the License, or (at your option) any later version. 00012 00013 This library is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Library General Public License for more details. 00017 00018 You should have received a copy of the GNU Library General Public License 00019 along with this library; see the file COPYING.LIB. If not, write to 00020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00021 Boston, MA 02110-1301, USA. 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 //#define KJSEMBED_VARIANT_DEBUG 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 //qDebug("Ptr %0x", p ); 00082 //qDebug() << p; 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 //qDebug("Call value to string"); 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 KJS::JSObject *obj = value->toObject( exec ); 00174 if ( toQString(obj->className() == "Array" ) 00175 { 00176 int length = int(obj->get( exec, KJS::Identifier( "length" ) )->toInteger( exec ) ); 00177 for ( int index = 0; index < length; ++index ) 00178 { 00179 QByteArray buff; 00180 buff.setNum(index); 00181 KJS::JSValue *val = obj->get(exec, KJS::Identifier( buff.data() ) ); 00182 if( val ) 00183 returnList += convertToVariant(exec, val ); 00184 else 00185 returnList += QVariant(); 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 KJS::JSObject *obj = value->toObject( exec ); 00204 if ( toQString(obj->className()) == "Array" ) 00205 { 00206 int length = int( obj->get( exec, KJS::Identifier( "length" ) )->toInteger( exec ) ); 00207 for ( int index = 0; index < length; ++index ) 00208 { 00209 QByteArray buff; 00210 buff.setNum(index); 00211 KJS::JSValue *val = obj->get(exec, KJS::Identifier( buff.data() ) ); 00212 if( val ) 00213 returnList += convertToVariant(exec, val ).value<QString>(); 00214 else 00215 returnList += QString(); 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 // Throw error 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 //qDebug() << "Object type: " << toQString(obj->className()); 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 //if( returnValue.isNull() ) returnValue = toQString(value->toString(exec)); 00289 } break; 00290 default: 00291 returnValue = extractVariant(exec,value); 00292 //if( returnValue.isNull() ) returnValue = toQString(value->toString(exec)); 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: // fall through 00345 case QVariant::DateTime: // fall through 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 //kate: indent-spaces on; indent-width 4; replace-tabs on; indent-mode cstyle;
KDE 4.6 API Reference