• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

kjsembed

qobject_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 #include "qobject_binding.h"
00024 
00025 #include <QtCore/QObject>
00026 #include <QtCore/QArgument>
00027 #include <QtCore/QMetaEnum>
00028 #include <QtCore/QMetaType>
00029 #include <QtCore/QVariant>
00030 #include <QtCore/QVector>
00031 #include <QtCore/QUrl>
00032 #include <QtCore/QDebug>
00033 #include <QWidget>
00034 
00035 #include "slotproxy.h"
00036 #include "eventproxy.h"
00037 #include "jseventmapper.h"
00038 #include "pointer.h"
00039 #include "variant_binding.h"
00040 
00041 #include <kjs/array_instance.h>
00042 #include <kjs/function_object.h>
00043 
00044 //#define CREATEQOBJ_DIAG
00045 
00046 using namespace KJSEmbed;
00047 
00048 QByteArray createSignal( const QByteArray &sig )
00049 {
00050     return '2' + sig;
00051 }
00052 
00053 QByteArray createSlot( const QByteArray &slt )
00054 {
00055     return '1' + slt;
00056 }
00057 
00058 bool validSlot(const QMetaMethod& method, QObjectBinding::AccessFlags accessflags)
00059 {
00060     switch( method.access() ) {
00061         case QMetaMethod::Private: {
00062             if(! (accessflags & QObjectBinding::PrivateSlots)) return false;
00063         } break;
00064         case QMetaMethod::Protected: {
00065             if(! (accessflags & QObjectBinding::ProtectedSlots)) return false;
00066         } break;
00067         case QMetaMethod::Public: {
00068             if(! (accessflags & QObjectBinding::PublicSlots)) return false;
00069         } break;
00070     }
00071     if(method.attributes() & QMetaMethod::Scriptable) {
00072         if(! (accessflags & QObjectBinding::ScriptableSlots)) return false;
00073     }
00074     else {
00075         if(! (accessflags & QObjectBinding::NonScriptableSlots)) return false;
00076     }
00077     return true;
00078 }
00079 
00080 bool validSignal(const QMetaMethod& method, QObjectBinding::AccessFlags accessflags)
00081 {
00082     switch( method.access() ) {
00083         case QMetaMethod::Private: {
00084             if(! (accessflags & QObjectBinding::PrivateSignals)) return false;
00085         } break;
00086         case QMetaMethod::Protected: {
00087             if(! (accessflags & QObjectBinding::ProtectedSignals)) return false;
00088         } break;
00089         case QMetaMethod::Public: {
00090             if(! (accessflags & QObjectBinding::PublicSignals)) return false;
00091         } break;
00092     }
00093     if(method.attributes() & QMetaMethod::Scriptable) {
00094         if(! (accessflags & QObjectBinding::ScriptableSignals)) return false;
00095     }
00096     else {
00097         if(! (accessflags & QObjectBinding::NonScriptableSignals)) return false;
00098     }
00099     return true;
00100 }
00101 
00102 bool validProperty(const QMetaProperty& property, QObjectBinding::AccessFlags accessflags)
00103 {
00104     if(property.isScriptable()) {
00105         if(! (accessflags & QObjectBinding::ScriptableProperties)) return false;
00106     }
00107     else {
00108         if(! (accessflags & QObjectBinding::NonScriptableProperties)) return false;
00109     }
00110     return true;
00111 }
00112 
00113 KJS::JSValue *callConnect( KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args )
00114 {
00115     KJSEmbed::QObjectBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::QObjectBinding>(exec,  self );
00116     if( !imp ) // No implementation, so we need to use the first argument as we are a global static invocation.
00117         imp = KJSEmbed::extractBindingImp<KJSEmbed::QObjectBinding>(exec, args[0] );
00118     if( !imp )
00119         return KJS::throwError(exec, KJS::GeneralError, i18n("Wrong object type."));
00120         //return KJSEmbed::throwError(exec, i18n("Wrong object type."));
00121 
00122     if( args.size() > 2)
00123     {
00124         KJSEmbed::QObjectBinding *senderImp = KJSEmbed::extractBindingImp<KJSEmbed::QObjectBinding>(exec, args[0] );
00125         if( !senderImp )
00126         {
00127             return KJS::throwError(exec, KJS::GeneralError, i18n("First argument must be a QObject."));
00128             //return KJSEmbed::throwError(exec, i18n("First argument must be a QObject"));
00129         }
00130         QObject* receiver = 0;
00131         QObject* sender = senderImp->object<QObject>();
00132         char *signal = qstrdup( createSignal(args[1]->toString(exec).ascii()).data() );
00133         char *slot = 0;
00134         KJSEmbed::QObjectBinding *receiverImp = 0;
00135         if( args.size() >= 4)
00136         {
00137             slot = qstrdup( createSlot(args[3]->toString(exec).ascii()).data() );
00138             receiverImp = KJSEmbed::extractBindingImp<KJSEmbed::QObjectBinding>(exec, args[2] );
00139             if( !receiverImp )
00140                 receiver = new SlotProxy(args[2]->toObject(exec), exec->dynamicInterpreter(), sender, args[3]->toString(exec).ascii() );
00141             else
00142                 receiver = receiverImp->object<QObject>();
00143         }
00144         else
00145         {
00146             receiverImp = imp;
00147             receiver = imp->object<QObject>();
00148             slot = qstrdup( createSlot(args[2]->toString(exec).ascii()).data() );
00149         }
00150 
00151         const QMetaObject *senderMetaObject = sender->metaObject();
00152         QMetaMethod senderMetaMethod = senderMetaObject->method( senderMetaObject->indexOfSignal(signal) );
00153 
00154         const QMetaObject *receiverMetaObject = receiver->metaObject();
00155         QMetaMethod receiverMetaMethod = receiverMetaObject->method( receiverMetaObject->indexOfSlot(slot) );
00156 
00157         if( validSignal(senderMetaMethod, senderImp->access()) && ( !receiverImp || validSlot(receiverMetaMethod, receiverImp->access()) ) )
00158         {
00159             return KJS::jsBoolean(QObject::connect(sender, signal, receiver, slot));
00160         }
00161 
00162         return KJS::jsBoolean(false);
00163     }
00164     return KJS::throwError(exec, KJS::GeneralError, i18n("Incorrect number of arguments."));
00165     //return KJSEmbed::throwError(exec, i18n("Incorrect number of arguments."));
00166 }
00167 
00168 QByteArray extractMemberName( const QMetaMethod &member )
00169 {
00170     QString sig = member.signature();
00171     return sig.left( sig.indexOf('(') ).toLatin1();
00172 }
00173 
00174 void QObjectBinding::publishQObject( KJS::ExecState *exec, KJS::JSObject *target, QObject *object)
00175 {
00176     KJSEmbed::QObjectBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::QObjectBinding>(exec,  target);
00177     Q_ASSERT(imp);
00178 
00179     // Add the children the QObject has.
00180     if (imp->access() & QObjectBinding::ChildObjects) {
00181         //TODO uh, this one is dirty cause it may eat a lot of time to publish things that may not
00182         //got accessed anyway. Better solution would be to provide access to them on demand only. That
00183         //would also allow to manipulate the QObject-tree at runtime what is currently not possible.
00184         QObjectList children = object->children();
00185         QObjectList::Iterator child = children.begin();
00186         for( ; child != children.end(); ++child)
00187         {
00188             QString objectName = (*child)->objectName();
00189             if( !objectName.isEmpty() )
00190             {
00191                 KJS::JSObject *childObject = KJSEmbed::createQObject(exec, *child);
00192                 KJSEmbed::QObjectBinding *childImp = KJSEmbed::extractBindingImp<KJSEmbed::QObjectBinding>(exec, childObject);
00193                 if(childImp)
00194                 {
00195                     childImp->setAccess( imp->access() ); // inherit access from parent
00196                     target->put(exec, KJS::Identifier(toUString(objectName)), childObject);
00197                 }
00198             }
00199         }
00200     }
00201 
00202     // Add slots of the current object.
00203     const QMetaObject *metaObject = object->metaObject();
00204     int methods = metaObject->methodCount();
00205     for( int idx = 0; idx < methods; ++idx )
00206     {
00207         QMetaMethod member = metaObject->method(idx);
00208         if(validSlot(member, imp->access()))
00209         {
00210             target->put(exec, KJS::Identifier( extractMemberName( member ) ),
00211                         new SlotBinding(exec,member), KJS::DontDelete|KJS::ReadOnly|KJS::Function);
00212         }
00213     }
00214 
00215     // Add enums as read only uints.
00216     int enums = metaObject->enumeratorCount();
00217     for( int idx = 0; idx < enums; ++idx )
00218     {
00219         QMetaEnum enumerator = metaObject->enumerator(idx);
00220         int keys = enumerator.keyCount();
00221         for( int key = 0; key < keys; ++key)
00222         {
00223             target->put(exec, KJS::Identifier( enumerator.key(key) ),
00224                     KJS::jsNumber(enumerator.value(key)), KJS::DontDelete|KJS::ReadOnly);
00225         }
00226     }
00227 }
00228 
00229 QObjectBinding::QObjectBinding( KJS::ExecState *exec, QObject *object )
00230     : ObjectBinding(exec, object->metaObject()->className(), object)
00231     , m_evproxy(0)
00232     , m_access( AllSlots | AllSignals | AllProperties | AllObjects )
00233 {
00234     if( object->parent() != 0 )
00235     {
00236         setOwnership( ObjectBinding::QObjOwned );
00237     }
00238     else
00239     {
00240         setOwnership( ObjectBinding::JSOwned );
00241     }
00242 
00243     m_cleanupHandler = new QObjectCleanupHandler();
00244     watchObject(object);
00245 
00246     StaticBinding::publish( exec, this, QObjectFactory::methods() );
00247     QObjectBinding::publishQObject(exec, this, object);
00248 
00249     // Make "connect" a global static method.
00250     exec->dynamicInterpreter()->globalObject()->put(exec, "connect", new StaticBinding(exec,  &QObjectFactory::methods()[0]) );
00251 }
00252 
00253 QObjectBinding::~QObjectBinding()
00254 {
00255     if( m_cleanupHandler->isEmpty() )
00256     {
00257         setOwnership( ObjectBinding::QObjOwned );
00258     }
00259     else if( object<QObject>()->parent() != 0 )
00260     {
00261         setOwnership( ObjectBinding::QObjOwned );
00262         m_cleanupHandler->remove(object<QObject>());
00263     }
00264     else if( ownership() != ObjectBinding::JSOwned )
00265     {
00266         m_cleanupHandler->remove(object<QObject>());
00267     }
00268     else
00269     {
00270         m_cleanupHandler->remove(object<QObject>());
00271     }
00272 
00273     delete m_cleanupHandler;
00274 }
00275 
00276 void QObjectBinding::watchObject( QObject *object )
00277 {
00278     m_cleanupHandler->add( object );
00279 }
00280 
00281 bool QObjectBinding::getOwnPropertySlot( KJS::ExecState *exec, const KJS::Identifier &propertyName, KJS::PropertySlot &slot )
00282 {
00283     //    qDebug() << "getOwnPropertySlot called";
00284     QObject *obj = object<QObject>();
00285     const QMetaObject *meta = obj->metaObject();
00286     int propIndex = meta->indexOfProperty( propertyName.ascii() );
00287     if ( propIndex != -1 ) {
00288         if(! validProperty(meta->property(propIndex), m_access))
00289             return false;
00290         // qDebug() << "getOwnPropertySlot found the property " << propertyName.ascii();
00291         slot.setCustom( this, propertyGetter );
00292         return true;
00293     }
00294     return ObjectBinding::getOwnPropertySlot( exec, propertyName, slot );
00295 }
00296 
00297 KJS::JSValue *QObjectBinding::propertyGetter( KJS::ExecState *exec, KJS::JSObject*,
00298                                               const KJS::Identifier &propertyName, const KJS::PropertySlot&slot )
00299 {
00300     // qDebug() << "Getter was called";
00301     QObjectBinding *self = static_cast<QObjectBinding *>(slot.slotBase());
00302     QObject *obj =  self->object<QObject>();
00303 
00304     QVariant val = obj->property( propertyName.ascii() );
00305     if ( val.isValid() ) {
00306         return convertToValue( exec, val );
00307     }
00308     qDebug() << QString("propertyGetter called but no property, name was '%1'").arg(propertyName.ascii());
00309     return 0; // ERROR
00310 }
00311 
00312 QObjectBinding::AccessFlags QObjectBinding::access() const
00313 {
00314     return m_access;
00315 }
00316 
00317 void QObjectBinding::setAccess(QObjectBinding::AccessFlags access)
00318 {
00319     m_access = access;
00320 }
00321 
00322 void QObjectBinding::put(KJS::ExecState *exec, const KJS::Identifier &propertyName, KJS::JSValue *value, int attr )
00323 {
00324     QObject *obj = object<QObject>();
00325     if ( obj && !m_cleanupHandler->isEmpty() )
00326     {
00327         // Properties
00328         const QMetaObject *meta = obj->metaObject();
00329 
00330         if ( int propIndex = meta->indexOfProperty( propertyName.ascii() ) != -1 )
00331         {
00332             QMetaProperty prop = meta->property(propIndex);
00333             if(! validProperty(prop, m_access))
00334                 return;
00335 
00336             bool propSet = false;
00337             QVariant val = convertToVariant( exec, value );
00338             if ( prop.isEnumType() )
00339             {
00340                     propSet = obj->setProperty( propertyName.ascii(), val.toUInt() );
00341             }
00342             else if ( val.isValid() /*&& meta->property(propIndex).isWritable() <- wtf?*/ )
00343             {
00344                     propSet = obj->setProperty( propertyName.ascii(), val );
00345             }
00346             /*
00347             if( !propSet )
00348             {
00349                     KJSEmbed::throwError(exec,
00350                             i18n("Setting property %1 failed: property invalid, read-only or does not exist").arg(propertyName.ascii()));
00351             }
00352             */
00353 
00354         }
00355 
00356         if (JSEventMapper::mapper()->isEventHandler(propertyName) )
00357         {
00358             if ( !m_evproxy )
00359                 m_evproxy = new KJSEmbed::EventProxy( this, exec->dynamicInterpreter() );
00360             if( value )
00361                 m_evproxy->addFilter( JSEventMapper::mapper()->findEventType( propertyName ) );
00362             else
00363                 m_evproxy->removeFilter( JSEventMapper::mapper()->findEventType( propertyName ) );
00364         }
00365     }
00366     //qDebug() << "Forward put";
00367     // Set a property value
00368     ObjectBinding::put(exec, propertyName, value, attr);
00369 }
00370 
00371 bool QObjectBinding::canPut(KJS::ExecState *exec, const KJS::Identifier &propertyName) const
00372 {
00373     QObject *obj = object<QObject>();
00374     if ( obj && !m_cleanupHandler->isEmpty() )
00375     {
00376         // Properties
00377         const QMetaObject *meta = obj->metaObject();
00378         if ( int propIndex = meta->indexOfProperty( propertyName.ascii() ) != -1 )
00379         {
00380             QMetaProperty prop = meta->property(propIndex);
00381             return validProperty(prop, m_access) && prop.isWritable();
00382         }
00383     }
00384     return ObjectBinding::canPut(exec,propertyName);
00385 }
00386 
00387 KJS::UString QObjectBinding::className() const
00388 {
00389     return toUString( typeName() );
00390 }
00391 
00392 KJS::UString QObjectBinding::toString(KJS::ExecState *exec) const
00393 {
00394     Q_UNUSED( exec );
00395     QString s( "%1 (%2)" );
00396     s = s.arg( object<QObject>()->objectName() );
00397     s = s.arg( typeName() );
00398     return toUString( s );
00399 }
00400 
00401 PointerBase *getArg( KJS::ExecState *exec, const QList<QByteArray> &types, const KJS::List &args, int idx, QString& errorText)
00402 {
00403     //qDebug("Index %d, args size %d, types size %d", idx, args.size(), types.size() );
00404 
00405     if( types.size() == 0 && idx == 0 )
00406         return new NullPtr();
00407     if ( args.size() <= idx )
00408         return new NullPtr();
00409 
00410     if ( types.size() <= idx )
00411     {
00412         errorText = i18n("The slot asked for %1 arguments but there are only %2 arguments available.", idx, types.size());
00413         return 0;
00414     }
00415 
00416     QVariant::Type varianttype = QVariant::nameToType( types[idx].constData() );
00417     //qDebug( QString("type=%1 argtype=%2 variantType=%3 (%4)").arg(types[idx].constData()).arg(args[idx]->type()).arg(varianttype).arg(QVariant::typeToName(varianttype)).toLatin1() );
00418     switch( varianttype ) {
00419         case QVariant::Int:
00420             if( args[idx]->type() == KJS::NumberType )
00421                 return new Value<int>( int( args[idx]->toInteger(exec) ) );
00422             break;
00423         case QVariant::UInt:
00424             if( args[idx]->type() == KJS::NumberType )
00425                 return new Value<uint>( uint( args[idx]->toInteger(exec) ) );
00426             break;
00427         case QVariant::LongLong:
00428             if( args[idx]->type() == KJS::NumberType )
00429                 return new Value<qlonglong>( qlonglong( args[idx]->toInteger(exec) ) );
00430             break;
00431         case QVariant::ULongLong:
00432             if( args[idx]->type() == KJS::NumberType )
00433                 return new Value<qulonglong>( qulonglong( args[idx]->toInteger(exec) ) );
00434             break;
00435         case QVariant::Double:
00436             if( args[idx]->type() == KJS::NumberType )
00437                 return new Value<double>( args[idx]->toNumber(exec) );
00438             //if ( types[idx] == "float" ) return new Value<float>( args[idx]->toNumber(exec) );
00439             //if ( types[idx] == "qreal" ) return new Value<qreal>( args[idx]->toNumber(exec) );
00440             break;
00441         case QVariant::Bool:
00442             if( args[idx]->type() == KJS::BooleanType )
00443                 return new Value<bool>( args[idx]->toBoolean(exec) );
00444             break;
00445         case QVariant::ByteArray:
00446             if( args[idx]->type() == KJS::StringType )
00447                 return new Value<QByteArray>( toQString(args[idx]->toString(exec)).toUtf8() );
00448             break;
00449         case QVariant::String:
00450             if( args[idx]->type() == KJS::StringType )
00451                 return new Value<QString>( toQString(args[idx]->toString(exec)) );
00452             break;
00453         case QVariant::StringList:
00454             if( args[idx]->type() == KJS::ObjectType )
00455                 return new Value<QStringList>( convertArrayToStringList(exec, args[idx]) );
00456             break;
00457         case QVariant::Size:
00458             if( VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]) )
00459                 return new Value<QSize>( valImp->variant().value<QSize>() );
00460             break;
00461         case QVariant::SizeF:
00462             if( VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]) )
00463                 return new Value<QSizeF>( valImp->variant().value<QSizeF>() );
00464             break;
00465         case QVariant::Point:
00466             if( VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]) )
00467                 return new Value<QPoint>( valImp->variant().value<QPoint>() );
00468             break;
00469         case QVariant::PointF:
00470             if( VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]) )
00471                 return new Value<QPointF>( valImp->variant().value<QPointF>() );
00472             break;
00473         case QVariant::Rect:
00474             if( VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]) )
00475                 return new Value<QRect>( valImp->variant().value<QRect>() );
00476             break;
00477         case QVariant::RectF:
00478             if( VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]) )
00479                 return new Value<QRectF>( valImp->variant().value<QRectF>() );
00480             break;
00481         case QVariant::Color:
00482             if( args[idx]->type() == KJS::StringType )
00483                 return new Value<QColor>( QColor(toQString(args[idx]->toString(exec))) );
00484             if( VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]) )
00485                 return new Value<QColor>( valImp->variant().value<QColor>() );
00486             break;
00487         case QVariant::Url:
00488             if( args[idx]->type() == KJS::StringType )
00489                 return new Value<QUrl>( toQString(args[idx]->toString(exec) ));
00490             if( VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]) )
00491                 return new Value<QUrl>( valImp->variant().value<QUrl>() );
00492             break;
00493         case QVariant::List:
00494             if( args[idx]->type() == KJS::ObjectType )
00495                 return new Value<QVariantList>( convertArrayToList(exec, args[idx]) );
00496             break;
00497         case QVariant::Map:
00498             if( args[idx]->type() == KJS::ObjectType )
00499                 return new Value<QVariantMap>( convertArrayToMap(exec, args[idx]) );
00500             break;
00501         case QVariant::UserType: // fall through
00502         default:
00503             if( args[idx]->type() == KJS::NullType )
00504                 return new NullPtr();
00505             if( args[idx]->type() == KJS::StringType )
00506             {
00507                 if( strcmp(types[idx].constData(),"KUrl") == 0 ) //downcast to QUrl
00508                     return new Value<QUrl>( toQString(args[idx]->toString(exec) ));
00509             }
00510             if( args[idx]->type() == KJS::ObjectType )
00511             {
00512                 if(QObjectBinding *objImp = KJSEmbed::extractBindingImp<QObjectBinding>(exec, args[idx]))
00513                 {
00514                     //qDebug("\tQObjectBinding");
00515                     if( QObject* qObj = objImp->qobject<QObject>() )
00516                         return new Value<void*>(qObj);
00517                 }
00518                 else if(ObjectBinding *objImp = KJSEmbed::extractBindingImp<ObjectBinding>(exec, args[idx]))
00519                 {
00520                     //qDebug("\tObjectBinding");
00521                     return new Value<void*>(objImp->voidStar());
00522                 }
00523                 if(VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]))
00524                 {
00525                     //qDebug() << "\tVariantBinding typeName="  << valImp->variant().typeName() << "type="  << valImp->variant().type() << "userType="  << valImp->variant().userType() << " variant=" << valImp->variant();
00526                     QVariant var = valImp->variant();
00527 
00528                     // if the variant is the appropriate type, return its data
00529                     if ((var.type() == varianttype) ||
00530                         ((var.type() == QVariant::UserType) &&
00531                          (types[idx].constData() == var.typeName())))
00532                         return new Value<void*>(valImp->variant().data());
00533                     else if ((var.type() != QVariant::UserType) && 
00534                            var.canConvert(varianttype))
00535                     {
00536                         // is convertable type, so convert it, and return if successful
00537                         if (var.convert(varianttype))
00538                             return new Value<void*>(valImp->variant().data());
00539                     }
00540                     else if ((var.type() == QVariant::UserType) &&
00541                              var.canConvert<QObject*>())
00542                     {
00543                         QObject* qObj = var.value<QObject*>();
00544                         if (!qObj)
00545                             qObj = reinterpret_cast<QObject*>(var.value<QWidget*>());
00546                         if (qObj) {
00547                             QByteArray typeName = types[idx].constData();
00548                             typeName.replace("*", ""); //krazy:exclude=doublequote_chars
00549                             if (qObj->inherits(typeName))
00550                                 return new Value<void*>(qObj);
00551                         }
00552                     }
00553                 }
00554             }
00555 
00556             QVariant v = KJSEmbed::extractVariant(exec, args[idx]);
00557             if (! v.isNull())
00558                 return new Value<QVariant>(v);
00559 
00560             break;
00561     }
00562 
00563     qDebug("Cast failure %s value Type %d", types[idx].constData(), args[idx]->type() );
00564     // construct a meaningful exception message
00565     QString jsType;
00566     KJS::JSObject* jsObj = args[idx]->getObject();
00567     if (jsObj)
00568     {
00569         const KJS::ClassInfo* ci = jsObj->classInfo();
00570         if (ci && ci->className)
00571             jsType = ci->className;
00572         if (jsType.isEmpty())
00573             jsType = toQString(jsObj->className());
00574     }
00575     
00576     if (jsType.isEmpty())
00577     {
00578         switch(args[idx]->type())
00579         {
00580         case KJS::UnspecifiedType:
00581             jsType = "jsUnspecified";
00582             break;
00583         case KJS::NumberType:
00584             jsType = "jsNumber";
00585             break;
00586         case KJS::BooleanType:
00587             jsType = "jsBoolean";
00588             break;
00589         case KJS::UndefinedType:
00590             jsType = "jsUndefined";
00591             break;
00592         case KJS::NullType:
00593             jsType = "jsNull";
00594             break;
00595         case KJS::StringType:
00596             jsType = "jsString";
00597             break;
00598         case KJS::ObjectType:
00599             jsType = "jsObject";
00600             break;
00601         case KJS::GetterSetterType:
00602             jsType = "jsGetterSetter";
00603             break;
00604         default:
00605             jsType = QString::number(args[idx]->type());
00606             break;
00607         }
00608     }
00609 
00610     errorText = i18n("Failure to cast to %1 value from Type %2 (%3)",
00611                      types[idx].constData(), jsType, toQString(args[idx]->toString(exec)));
00612 
00613     return 0;
00614 }
00615 
00616 KJS::JSValue *SlotBinding::callAsFunction( KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args )
00617 {
00618     QObjectBinding *imp = extractBindingImp<QObjectBinding>(exec,self);
00619     if( imp == 0 )
00620         return KJS::jsNull();
00621 
00622     PointerBase *qtArgs[10];
00623     void *param[11];
00624 
00625     QObject *object = imp->object<QObject>();
00626     int count = object->metaObject()->methodCount();
00627     QMetaMethod metaMember;
00628     int offset = 0;
00629     bool success = false;
00630     for(; offset < count; ++offset)
00631     {
00632         metaMember = object->metaObject()->method(offset);
00633         if( extractMemberName(metaMember) == m_memberName )
00634         {
00635             if( metaMember.parameterTypes().size() == args.size() && validSlot(metaMember, imp->access()) )
00636             {
00637                 success = true;
00638                 break;
00639             }
00640         }
00641     }
00642 
00643     if( !success )
00644     {
00645         return KJS::throwError(exec, KJS::GeneralError, i18n("No such method '%1'.",  m_memberName.constData()));
00646         //return KJSEmbed::throwError(exec, i18n("Call to '%1' failed.").arg(m_memberName.constData()));
00647     }
00648 
00649     QList<QByteArray> types = metaMember.parameterTypes();
00650 
00651     QVariant::Type returnTypeId = QVariant::nameToType( metaMember.typeName() );
00652     int tp = QMetaType::type( metaMember.typeName() );
00653     PointerBase *qtRet = new Value<void*>(0);
00654 
00655     bool returnIsMetaType = (
00656         returnTypeId == QVariant::UserType ||
00657         returnTypeId == QVariant::Size     || returnTypeId == QVariant::SizeF  ||
00658         returnTypeId == QVariant::Point    || returnTypeId == QVariant::PointF ||
00659         returnTypeId == QVariant::Rect     || returnTypeId == QVariant::RectF  ||
00660         returnTypeId == QVariant::Color
00661     );
00662     QVariant returnValue = returnIsMetaType ? QVariant(tp, (void*)0) : QVariant(returnTypeId);
00663     QGenericReturnArgument returnArgument(metaMember.typeName(), &returnValue);
00664     param[0] = returnIsMetaType ? qtRet->voidStar() : returnArgument.data();
00665 
00666     QString errorText;
00667     for( int idx = 0; idx < 10; ++idx)
00668     {
00669         qtArgs[idx] = getArg(exec, types, args, idx, errorText);
00670         if (!qtArgs[idx]) {
00671             for( int i = 0; i < idx; ++i)
00672                 delete qtArgs[i];
00673             delete qtRet;
00674             return KJS::throwError(exec, KJS::GeneralError, i18n("Call to method '%1' failed, unable to get argument %2: %3",  m_memberName.constData(), idx, errorText));
00675         }
00676         param[idx+1] = qtArgs[idx]->voidStar();
00677     }
00678 
00679     success = object->qt_metacall(QMetaObject::InvokeMetaMethod, offset, param) < 0;
00680 
00681     KJS::JSValue *jsReturnValue = 0;
00682     if( success ) {
00683         switch( returnTypeId ) {
00684             case QVariant::Invalid: // fall through
00685             case QVariant::UserType: {
00686                 switch( tp ) {
00687                     case QMetaType::QWidgetStar: {
00688                         QVariant v(tp, param[0]);
00689                         QWidget* widget = v.value< QWidget* >();
00690                         if( widget )
00691                             jsReturnValue = KJSEmbed::createQObject(exec, widget, KJSEmbed::ObjectBinding::CPPOwned);
00692                     } break;
00693                     case QMetaType::QObjectStar: {
00694                         QVariant v(tp,param[0]);
00695                         QObject* obj = v.value< QObject* >();
00696                         if( obj )
00697                             jsReturnValue = KJSEmbed::createQObject(exec, obj, KJSEmbed::ObjectBinding::CPPOwned);
00698                     } break;
00699                     default:
00700                         break;
00701                 }
00702             } break;
00703             default:
00704                 if( returnIsMetaType )
00705                     returnValue = QVariant(tp, param[0]);
00706                 break;
00707         }
00708         if(! jsReturnValue)
00709             jsReturnValue = KJSEmbed::convertToValue(exec, returnValue);
00710     }
00711 
00712     for( int idx = 0; idx < 10; ++idx)
00713         delete qtArgs[idx];
00714     delete qtRet;
00715 
00716     if( !success )
00717         return KJS::throwError(exec, KJS::GeneralError, i18n("Call to '%1' failed.",  m_memberName.constData()));
00718 
00719     return jsReturnValue;
00720 }
00721 
00722 SlotBinding::SlotBinding(KJS::ExecState *exec, const QMetaMethod &member )
00723   : KJS::InternalFunctionImp(static_cast<KJS::FunctionPrototype*>(exec->lexicalInterpreter()->builtinFunctionPrototype()),
00724                              KJS::Identifier(toUString(extractMemberName(member))))
00725 {
00726     m_memberName = extractMemberName(member);
00727     int count = member.parameterNames().count();
00728     putDirect( exec->propertyNames().length, count, LengthFlags );
00729 }
00730 
00731 
00732 KJS::JSObject* KJSEmbed::createQObject(KJS::ExecState *exec, QObject *value, KJSEmbed::ObjectBinding::Ownership owner)
00733 {
00734     if ( 0 == value )
00735         return new KJS::JSObject();
00736 
00737     const QMetaObject *meta = value->metaObject();
00738     KJS::JSObject *parent = exec->dynamicInterpreter()->globalObject();
00739     KJS::JSObject *returnValue;
00740     int pos;
00741     QString clazz;
00742     do
00743     {
00744         clazz = meta->className();
00745 
00746 #ifdef CREATEQOBJ_DIAG
00747         qDebug() << "clazz=" << clazz;
00748 #endif
00749         // strip off namespace since they aren't included
00750         if ((pos = clazz.lastIndexOf("::")) != -1)
00751             clazz.remove(0, pos + 2);
00752 #ifdef CREATEQOBJ_DIAG
00753         qDebug() << "cleaned clazz=" << clazz;
00754 #endif
00755         if ( parent->hasProperty( exec, KJS::Identifier(toUString(clazz)) ) )
00756         {
00757 #ifdef CREATEQOBJ_DIAG
00758             qDebug() << "createQObject(): clazz=" << clazz << " value=" << value;
00759 #endif
00760             Pointer<QObject> pov(value);
00761             returnValue = StaticConstructor::bind(exec, clazz, pov);
00762             if ( returnValue )
00763               return returnValue;
00764 
00765 #ifdef CREATEQOBJ_DIAG
00766             qDebug("\tresort to construct() method.");
00767 #endif
00768             returnValue = StaticConstructor::construct( exec, parent, toUString(clazz) );
00769             if( returnValue )
00770             {
00771                 // If it is a value type setValue
00772                 KJSEmbed::QObjectBinding *imp = extractBindingImp<QObjectBinding>(exec, returnValue );
00773                 if( imp )
00774                 {
00775                     imp->setObject( value );
00776                     imp->watchObject( value );
00777                     imp->setOwnership( owner );
00778                     KJSEmbed::QObjectBinding::publishQObject( exec, returnValue, value);
00779                 }
00780                 else
00781                 {
00782                     KJS::throwError(exec, KJS::TypeError, i18n("%1 is not an Object type",  clazz ));
00783                     return new KJS::JSObject();
00784                 }
00785             }
00786             else
00787             {
00788                 KJS::throwError(exec, KJS::TypeError, i18n("Could not construct value"));
00789                 return new KJS::JSObject();
00790             }
00791             return returnValue;
00792         }
00793         else
00794         {
00795 #ifdef CREATEQOBJ_DIAG
00796             qDebug("%s not a bound type, move up the chain", meta->className() );
00797 #endif
00798             meta = meta->superClass();
00799         }
00800 
00801     }
00802     while( meta );
00803 
00804     KJSEmbed::QObjectBinding *imp = new KJSEmbed::QObjectBinding(exec, value);
00805     imp->setOwnership( owner );
00806 
00807     return imp;
00808 }
00809 
00810 START_QOBJECT_METHOD( callParent, QObject )
00811     //TODO it would be better, if each QObjectBinding remembers it's parent rather then
00812     //creating a new instance each time. That wouldn't only be more logical, but also
00813     //does prevent losing of additional infos like e.g. the access-level.
00814     if( imp->access() & QObjectBinding::GetParentObject )
00815     {
00816         QObject *parent = imp->object<QObject>()->parent();
00817         KJS::JSObject *parentObject = KJSEmbed::createQObject(exec, parent);
00818         KJSEmbed::QObjectBinding *parentImp = KJSEmbed::extractBindingImp<KJSEmbed::QObjectBinding>(exec, parentObject);
00819         if( parentImp ) {
00820             parentImp->setAccess( imp->access() ); // inherit access from child since we don't know the access-level of the parent here :-(
00821         }
00822         result = parentObject;
00823     }
00824 END_QOBJECT_METHOD
00825 START_QOBJECT_METHOD( callIsWidgetType, QObject )
00826     result = KJS::jsBoolean(object->isWidgetType());
00827 END_QOBJECT_METHOD
00828 START_QOBJECT_METHOD( callInherits, QObject)
00829     QByteArray className = KJSEmbed::extractQString(exec, args, 0).toLatin1();
00830     result = KJS::jsBoolean(object->inherits(className.constData()));
00831 END_QOBJECT_METHOD
00832 START_QOBJECT_METHOD( callSetParent, QObject )
00833     if( imp->access() & QObjectBinding::SetParentObject )
00834     {
00835         QObject *parent = KJSEmbed::extractObject<QObject>(exec, args, 0, 0);
00836         object->setParent(parent);
00837     }
00838 END_QOBJECT_METHOD
00839 START_QOBJECT_METHOD( callFindChild, QObject )
00840     if( imp->access() & QObjectBinding::ChildObjects )
00841     {
00842         QString childName = KJSEmbed::extractQString(exec, args, 0);
00843         QObject *child = object->findChild<QObject*>(childName);
00844         KJS::JSObject *childObject = KJSEmbed::createQObject(exec, child);
00845         KJSEmbed::QObjectBinding *childImp = KJSEmbed::extractBindingImp<KJSEmbed::QObjectBinding>(exec, childObject);
00846         if( childImp ) {
00847             childImp->setAccess( imp->access() ); // inherit access from parent
00848         }
00849         result = childObject;
00850     }
00851 END_QOBJECT_METHOD
00852 
00853 START_METHOD_LUT(QObjectFactory)
00854     {"connect", 4, KJS::DontDelete|KJS::ReadOnly, &callConnect },
00855     {"parent", 0, KJS::DontDelete|KJS::ReadOnly, &callParent },
00856     {"inherits", 1, KJS::DontDelete|KJS::ReadOnly, &callInherits },
00857     {"isWidgetType", 0, KJS::DontDelete|KJS::ReadOnly, &callIsWidgetType },
00858     {"setParent", 1, KJS::DontDelete|KJS::ReadOnly, &callSetParent },
00859     {"findChild", 1, KJS::DontDelete|KJS::ReadOnly, &callFindChild }
00860 END_METHOD_LUT
00861 
00862 NO_ENUMS( QObjectFactory )
00863 NO_STATICS( QObjectFactory )
00864 
00865 //kate: indent-spaces on; indent-width 4; replace-tabs on; indent-mode cstyle;

kjsembed

Skip menu "kjsembed"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal