• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • 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         const QString firstPart = i18np("The slot asked for %1 argument", "The slot asked for %1 arguments", idx);
00413         const QString secondPart = i18np("but there is only %1 available", "but there are only %1 available", types.size());
00414         errorText = i18nc("%1 is 'the slot asked for foo arguments', %2 is 'but there are only bar available'", "%1, %2.");
00415 
00416         return 0;
00417     }
00418 
00419     QVariant::Type varianttype = QVariant::nameToType( types[idx].constData() );
00420     //qDebug( QString("type=%1 argtype=%2 variantType=%3 (%4)").arg(types[idx].constData()).arg(args[idx]->type()).arg(varianttype).arg(QVariant::typeToName(varianttype)).toLatin1() );
00421     switch( varianttype ) {
00422         case QVariant::Int:
00423             if( args[idx]->type() == KJS::NumberType )
00424                 return new Value<int>( int( args[idx]->toInteger(exec) ) );
00425             break;
00426         case QVariant::UInt:
00427             if( args[idx]->type() == KJS::NumberType )
00428                 return new Value<uint>( uint( args[idx]->toInteger(exec) ) );
00429             break;
00430         case QVariant::LongLong:
00431             if( args[idx]->type() == KJS::NumberType )
00432                 return new Value<qlonglong>( qlonglong( args[idx]->toInteger(exec) ) );
00433             break;
00434         case QVariant::ULongLong:
00435             if( args[idx]->type() == KJS::NumberType )
00436                 return new Value<qulonglong>( qulonglong( args[idx]->toInteger(exec) ) );
00437             break;
00438         case QVariant::Double:
00439             if( args[idx]->type() == KJS::NumberType )
00440                 return new Value<double>( args[idx]->toNumber(exec) );
00441             //if ( types[idx] == "float" ) return new Value<float>( args[idx]->toNumber(exec) );
00442             //if ( types[idx] == "qreal" ) return new Value<qreal>( args[idx]->toNumber(exec) );
00443             break;
00444         case QVariant::Bool:
00445             if( args[idx]->type() == KJS::BooleanType )
00446                 return new Value<bool>( args[idx]->toBoolean(exec) );
00447             break;
00448         case QVariant::ByteArray:
00449             if( args[idx]->type() == KJS::StringType )
00450                 return new Value<QByteArray>( toQString(args[idx]->toString(exec)).toUtf8() );
00451             break;
00452         case QVariant::String:
00453             if( args[idx]->type() == KJS::StringType )
00454                 return new Value<QString>( toQString(args[idx]->toString(exec)) );
00455             break;
00456         case QVariant::StringList:
00457             if( args[idx]->type() == KJS::ObjectType )
00458                 return new Value<QStringList>( convertArrayToStringList(exec, args[idx]) );
00459             break;
00460         case QVariant::Size:
00461             if( VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]) )
00462                 return new Value<QSize>( valImp->variant().value<QSize>() );
00463             break;
00464         case QVariant::SizeF:
00465             if( VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]) )
00466                 return new Value<QSizeF>( valImp->variant().value<QSizeF>() );
00467             break;
00468         case QVariant::Point:
00469             if( VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]) )
00470                 return new Value<QPoint>( valImp->variant().value<QPoint>() );
00471             break;
00472         case QVariant::PointF:
00473             if( VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]) )
00474                 return new Value<QPointF>( valImp->variant().value<QPointF>() );
00475             break;
00476         case QVariant::Rect:
00477             if( VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]) )
00478                 return new Value<QRect>( valImp->variant().value<QRect>() );
00479             break;
00480         case QVariant::RectF:
00481             if( VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]) )
00482                 return new Value<QRectF>( valImp->variant().value<QRectF>() );
00483             break;
00484         case QVariant::Color:
00485             if( args[idx]->type() == KJS::StringType )
00486                 return new Value<QColor>( QColor(toQString(args[idx]->toString(exec))) );
00487             if( VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]) )
00488                 return new Value<QColor>( valImp->variant().value<QColor>() );
00489             break;
00490         case QVariant::Url:
00491             if( args[idx]->type() == KJS::StringType )
00492                 return new Value<QUrl>( toQString(args[idx]->toString(exec) ));
00493             if( VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]) )
00494                 return new Value<QUrl>( valImp->variant().value<QUrl>() );
00495             break;
00496         case QVariant::List:
00497             if( args[idx]->type() == KJS::ObjectType )
00498                 return new Value<QVariantList>( convertArrayToList(exec, args[idx]) );
00499             break;
00500         case QVariant::Map:
00501             if( args[idx]->type() == KJS::ObjectType )
00502                 return new Value<QVariantMap>( convertArrayToMap(exec, args[idx]) );
00503             break;
00504         case QVariant::UserType: // fall through
00505         default:
00506             if( args[idx]->type() == KJS::NullType )
00507                 return new NullPtr();
00508             if( args[idx]->type() == KJS::StringType )
00509             {
00510                 if( strcmp(types[idx].constData(),"KUrl") == 0 ) //downcast to QUrl
00511                     return new Value<QUrl>( toQString(args[idx]->toString(exec) ));
00512             }
00513             if( args[idx]->type() == KJS::ObjectType )
00514             {
00515                 if(QObjectBinding *objImp = KJSEmbed::extractBindingImp<QObjectBinding>(exec, args[idx]))
00516                 {
00517                     //qDebug("\tQObjectBinding");
00518                     if( QObject* qObj = objImp->qobject<QObject>() )
00519                         return new Value<void*>(qObj);
00520                 }
00521                 else if(ObjectBinding *objImp = KJSEmbed::extractBindingImp<ObjectBinding>(exec, args[idx]))
00522                 {
00523                     //qDebug("\tObjectBinding");
00524                     return new Value<void*>(objImp->voidStar());
00525                 }
00526                 if(VariantBinding *valImp = KJSEmbed::extractBindingImp<VariantBinding>(exec,args[idx]))
00527                 {
00528                     //qDebug() << "\tVariantBinding typeName="  << valImp->variant().typeName() << "type="  << valImp->variant().type() << "userType="  << valImp->variant().userType() << " variant=" << valImp->variant();
00529                     QVariant var = valImp->variant();
00530 
00531                     // if the variant is the appropriate type, return its data
00532                     if ((var.type() == varianttype) ||
00533                         ((var.type() == QVariant::UserType) &&
00534                          (types[idx].constData() == var.typeName())))
00535                         return new Value<void*>(valImp->variant().data());
00536                     else if ((var.type() != QVariant::UserType) && 
00537                            var.canConvert(varianttype))
00538                     {
00539                         // is convertable type, so convert it, and return if successful
00540                         if (var.convert(varianttype))
00541                             return new Value<void*>(valImp->variant().data());
00542                     }
00543                     else if ((var.type() == QVariant::UserType) &&
00544                              var.canConvert<QObject*>())
00545                     {
00546                         QObject* qObj = var.value<QObject*>();
00547                         if (!qObj)
00548                             qObj = reinterpret_cast<QObject*>(var.value<QWidget*>());
00549                         if (qObj) {
00550                             QByteArray typeName = types[idx].constData();
00551                             typeName.replace("*", ""); //krazy:exclude=doublequote_chars
00552                             if (qObj->inherits(typeName))
00553                                 return new Value<void*>(qObj);
00554                         }
00555                     }
00556                 }
00557             }
00558 
00559             QVariant v = KJSEmbed::extractVariant(exec, args[idx]);
00560             if (! v.isNull())
00561                 return new Value<QVariant>(v);
00562 
00563             break;
00564     }
00565 
00566     qDebug("Cast failure %s value Type %d", types[idx].constData(), args[idx]->type() );
00567     // construct a meaningful exception message
00568     QString jsType;
00569     KJS::JSObject* jsObj = args[idx]->getObject();
00570     if (jsObj)
00571     {
00572         const KJS::ClassInfo* ci = jsObj->classInfo();
00573         if (ci && ci->className)
00574             jsType = ci->className;
00575         if (jsType.isEmpty())
00576             jsType = toQString(jsObj->className());
00577     }
00578     
00579     if (jsType.isEmpty())
00580     {
00581         switch(args[idx]->type())
00582         {
00583         case KJS::UnspecifiedType:
00584             jsType = "jsUnspecified";
00585             break;
00586         case KJS::NumberType:
00587             jsType = "jsNumber";
00588             break;
00589         case KJS::BooleanType:
00590             jsType = "jsBoolean";
00591             break;
00592         case KJS::UndefinedType:
00593             jsType = "jsUndefined";
00594             break;
00595         case KJS::NullType:
00596             jsType = "jsNull";
00597             break;
00598         case KJS::StringType:
00599             jsType = "jsString";
00600             break;
00601         case KJS::ObjectType:
00602             jsType = "jsObject";
00603             break;
00604         case KJS::GetterSetterType:
00605             jsType = "jsGetterSetter";
00606             break;
00607         default:
00608             jsType = QString::number(args[idx]->type());
00609             break;
00610         }
00611     }
00612 
00613     errorText = i18n("Failure to cast to %1 value from Type %2 (%3)",
00614                      types[idx].constData(), jsType, toQString(args[idx]->toString(exec)));
00615 
00616     return 0;
00617 }
00618 
00619 KJS::JSValue *SlotBinding::callAsFunction( KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args )
00620 {
00621     QObjectBinding *imp = extractBindingImp<QObjectBinding>(exec,self);
00622     if( imp == 0 )
00623         return KJS::jsNull();
00624 
00625     PointerBase *qtArgs[10];
00626     void *param[11];
00627 
00628     QObject *object = imp->object<QObject>();
00629     int count = object->metaObject()->methodCount();
00630     QMetaMethod metaMember;
00631     int offset = 0;
00632     bool success = false;
00633     for(; offset < count; ++offset)
00634     {
00635         metaMember = object->metaObject()->method(offset);
00636         if( extractMemberName(metaMember) == m_memberName )
00637         {
00638             if( metaMember.parameterTypes().size() == args.size() && validSlot(metaMember, imp->access()) )
00639             {
00640                 success = true;
00641                 break;
00642             }
00643         }
00644     }
00645 
00646     if( !success )
00647     {
00648         return KJS::throwError(exec, KJS::GeneralError, i18n("No such method '%1'.",  m_memberName.constData()));
00649         //return KJSEmbed::throwError(exec, i18n("Call to '%1' failed.").arg(m_memberName.constData()));
00650     }
00651 
00652     QList<QByteArray> types = metaMember.parameterTypes();
00653 
00654     QVariant::Type returnTypeId = QVariant::nameToType( metaMember.typeName() );
00655     int tp = QMetaType::type( metaMember.typeName() );
00656     PointerBase *qtRet = new Value<void*>(0);
00657 
00658     bool returnIsMetaType = (
00659         returnTypeId == QVariant::UserType ||
00660         returnTypeId == QVariant::Size     || returnTypeId == QVariant::SizeF  ||
00661         returnTypeId == QVariant::Point    || returnTypeId == QVariant::PointF ||
00662         returnTypeId == QVariant::Rect     || returnTypeId == QVariant::RectF  ||
00663         returnTypeId == QVariant::Color
00664     );
00665     QVariant returnValue = returnIsMetaType ? QVariant(tp, (void*)0) : QVariant(returnTypeId);
00666     QGenericReturnArgument returnArgument(metaMember.typeName(), &returnValue);
00667     param[0] = returnIsMetaType ? qtRet->voidStar() : returnArgument.data();
00668 
00669     QString errorText;
00670     for( int idx = 0; idx < 10; ++idx)
00671     {
00672         qtArgs[idx] = getArg(exec, types, args, idx, errorText);
00673         if (!qtArgs[idx]) {
00674             for( int i = 0; i < idx; ++i)
00675                 delete qtArgs[i];
00676             delete qtRet;
00677             return KJS::throwError(exec, KJS::GeneralError, i18n("Call to method '%1' failed, unable to get argument %2: %3",  m_memberName.constData(), idx, errorText));
00678         }
00679         param[idx+1] = qtArgs[idx]->voidStar();
00680     }
00681 
00682     success = object->qt_metacall(QMetaObject::InvokeMetaMethod, offset, param) < 0;
00683 
00684     KJS::JSValue *jsReturnValue = 0;
00685     if( success ) {
00686         switch( returnTypeId ) {
00687             case QVariant::Invalid: // fall through
00688             case QVariant::UserType: {
00689                 switch( tp ) {
00690                     case QMetaType::QWidgetStar: {
00691                         QVariant v(tp, param[0]);
00692                         QWidget* widget = v.value< QWidget* >();
00693                         if( widget )
00694                             jsReturnValue = KJSEmbed::createQObject(exec, widget, KJSEmbed::ObjectBinding::CPPOwned);
00695                     } break;
00696                     case QMetaType::QObjectStar: {
00697                         QVariant v(tp,param[0]);
00698                         QObject* obj = v.value< QObject* >();
00699                         if( obj )
00700                             jsReturnValue = KJSEmbed::createQObject(exec, obj, KJSEmbed::ObjectBinding::CPPOwned);
00701                     } break;
00702                     default:
00703                         break;
00704                 }
00705             } break;
00706             default:
00707                 if( returnIsMetaType )
00708                     returnValue = QVariant(tp, param[0]);
00709                 break;
00710         }
00711         if(! jsReturnValue)
00712             jsReturnValue = KJSEmbed::convertToValue(exec, returnValue);
00713     }
00714 
00715     for( int idx = 0; idx < 10; ++idx)
00716         delete qtArgs[idx];
00717     delete qtRet;
00718 
00719     if( !success )
00720         return KJS::throwError(exec, KJS::GeneralError, i18n("Call to '%1' failed.",  m_memberName.constData()));
00721 
00722     return jsReturnValue;
00723 }
00724 
00725 SlotBinding::SlotBinding(KJS::ExecState *exec, const QMetaMethod &member )
00726   : KJS::InternalFunctionImp(static_cast<KJS::FunctionPrototype*>(exec->lexicalInterpreter()->builtinFunctionPrototype()),
00727                              KJS::Identifier(toUString(extractMemberName(member))))
00728 {
00729     m_memberName = extractMemberName(member);
00730     int count = member.parameterNames().count();
00731     putDirect( exec->propertyNames().length, count, LengthFlags );
00732 }
00733 
00734 
00735 KJS::JSObject* KJSEmbed::createQObject(KJS::ExecState *exec, QObject *value, KJSEmbed::ObjectBinding::Ownership owner)
00736 {
00737     if ( 0 == value )
00738         return new KJS::JSObject();
00739 
00740     const QMetaObject *meta = value->metaObject();
00741     KJS::JSObject *parent = exec->dynamicInterpreter()->globalObject();
00742     KJS::JSObject *returnValue;
00743     int pos;
00744     QString clazz;
00745     do
00746     {
00747         clazz = meta->className();
00748 
00749 #ifdef CREATEQOBJ_DIAG
00750         qDebug() << "clazz=" << clazz;
00751 #endif
00752         // strip off namespace since they aren't included
00753         if ((pos = clazz.lastIndexOf("::")) != -1)
00754             clazz.remove(0, pos + 2);
00755 #ifdef CREATEQOBJ_DIAG
00756         qDebug() << "cleaned clazz=" << clazz;
00757 #endif
00758         if ( parent->hasProperty( exec, KJS::Identifier(toUString(clazz)) ) )
00759         {
00760 #ifdef CREATEQOBJ_DIAG
00761             qDebug() << "createQObject(): clazz=" << clazz << " value=" << value;
00762 #endif
00763             Pointer<QObject> pov(value);
00764             returnValue = StaticConstructor::bind(exec, clazz, pov);
00765             if ( returnValue )
00766               return returnValue;
00767 
00768 #ifdef CREATEQOBJ_DIAG
00769             qDebug("\tresort to construct() method.");
00770 #endif
00771             returnValue = StaticConstructor::construct( exec, parent, toUString(clazz) );
00772             if( returnValue )
00773             {
00774                 // If it is a value type setValue
00775                 KJSEmbed::QObjectBinding *imp = extractBindingImp<QObjectBinding>(exec, returnValue );
00776                 if( imp )
00777                 {
00778                     imp->setObject( value );
00779                     imp->watchObject( value );
00780                     imp->setOwnership( owner );
00781                     KJSEmbed::QObjectBinding::publishQObject( exec, returnValue, value);
00782                 }
00783                 else
00784                 {
00785                     KJS::throwError(exec, KJS::TypeError, i18n("%1 is not an Object type",  clazz ));
00786                     return new KJS::JSObject();
00787                 }
00788             }
00789             else
00790             {
00791                 KJS::throwError(exec, KJS::TypeError, i18n("Could not construct value"));
00792                 return new KJS::JSObject();
00793             }
00794             return returnValue;
00795         }
00796         else
00797         {
00798 #ifdef CREATEQOBJ_DIAG
00799             qDebug("%s not a bound type, move up the chain", meta->className() );
00800 #endif
00801             meta = meta->superClass();
00802         }
00803 
00804     }
00805     while( meta );
00806 
00807     KJSEmbed::QObjectBinding *imp = new KJSEmbed::QObjectBinding(exec, value);
00808     imp->setOwnership( owner );
00809 
00810     return imp;
00811 }
00812 
00813 START_QOBJECT_METHOD( callParent, QObject )
00814     //TODO it would be better, if each QObjectBinding remembers it's parent rather then
00815     //creating a new instance each time. That wouldn't only be more logical, but also
00816     //does prevent losing of additional information like e.g. the access-level.
00817     if( imp->access() & QObjectBinding::GetParentObject )
00818     {
00819         QObject *parent = imp->object<QObject>()->parent();
00820         KJS::JSObject *parentObject = KJSEmbed::createQObject(exec, parent);
00821         KJSEmbed::QObjectBinding *parentImp = KJSEmbed::extractBindingImp<KJSEmbed::QObjectBinding>(exec, parentObject);
00822         if( parentImp ) {
00823             parentImp->setAccess( imp->access() ); // inherit access from child since we don't know the access-level of the parent here :-(
00824         }
00825         result = parentObject;
00826     }
00827 END_QOBJECT_METHOD
00828 START_QOBJECT_METHOD( callIsWidgetType, QObject )
00829     result = KJS::jsBoolean(object->isWidgetType());
00830 END_QOBJECT_METHOD
00831 START_QOBJECT_METHOD( callInherits, QObject)
00832     QByteArray className = KJSEmbed::extractQString(exec, args, 0).toLatin1();
00833     result = KJS::jsBoolean(object->inherits(className.constData()));
00834 END_QOBJECT_METHOD
00835 START_QOBJECT_METHOD( callSetParent, QObject )
00836     if( imp->access() & QObjectBinding::SetParentObject )
00837     {
00838         QObject *parent = KJSEmbed::extractObject<QObject>(exec, args, 0, 0);
00839         object->setParent(parent);
00840     }
00841 END_QOBJECT_METHOD
00842 START_QOBJECT_METHOD( callFindChild, QObject )
00843     if( imp->access() & QObjectBinding::ChildObjects )
00844     {
00845         QString childName = KJSEmbed::extractQString(exec, args, 0);
00846         QObject *child = object->findChild<QObject*>(childName);
00847         KJS::JSObject *childObject = KJSEmbed::createQObject(exec, child);
00848         KJSEmbed::QObjectBinding *childImp = KJSEmbed::extractBindingImp<KJSEmbed::QObjectBinding>(exec, childObject);
00849         if( childImp ) {
00850             childImp->setAccess( imp->access() ); // inherit access from parent
00851         }
00852         result = childObject;
00853     }
00854 END_QOBJECT_METHOD
00855 
00856 START_METHOD_LUT(QObjectFactory)
00857     {"connect", 4, KJS::DontDelete|KJS::ReadOnly, &callConnect },
00858     {"parent", 0, KJS::DontDelete|KJS::ReadOnly, &callParent },
00859     {"inherits", 1, KJS::DontDelete|KJS::ReadOnly, &callInherits },
00860     {"isWidgetType", 0, KJS::DontDelete|KJS::ReadOnly, &callIsWidgetType },
00861     {"setParent", 1, KJS::DontDelete|KJS::ReadOnly, &callSetParent },
00862     {"findChild", 1, KJS::DontDelete|KJS::ReadOnly, &callFindChild }
00863 END_METHOD_LUT
00864 
00865 NO_ENUMS( QObjectFactory )
00866 NO_STATICS( QObjectFactory )
00867 
00868 //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
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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