You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebindings/kjsembed/jsobjectproxy.cpp

302 lines
11 KiB

/*
* Copyright (C) 2001-2003, Richard J. Moore <rich@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <tqobject.h>
#include <tqobjectlist.h>
#include <tqmetaobject.h>
#include <tqregexp.h>
#include <tqsignal.h>
#include <tqstrlist.h>
#include <tqvariant.h>
#include <private/qucomextra_p.h>
#include <kjs/interpreter.h>
#include <kjs/types.h>
#include <kjs/ustring.h>
#include "kjsembedpart.h"
#include "jssecuritypolicy.h"
#include "jsfactory.h"
#include "global.h"
#include "jsobjectproxy.h"
#include "jsobjectproxy_imp.h"
#include "jsobjecteventproxy.h"
#include "jseventmapper.h"
#include "slotutils.h"
#include "bindings/bindingobject.h"
//#include "kjsembedpart_imp.h"
#include "jsfactory_imp.h"
using namespace KJS;
namespace KJSEmbed {
typedef Bindings::JSObjectProxyImp JSObjectProxyImp;
JSObjectProxy::JSObjectProxy( KJSEmbedPart *part, TQObject *target, TQObject *r, const JSSecurityPolicy *sp )
: JSProxy( JSProxy::ObjectProxy ),
jspart( part ), js( part->interpreter() ), obj( target ), root( r ) {
policy = sp ? sp : JSSecurityPolicy::defaultPolicy();
}
JSObjectProxy::JSObjectProxy( KJSEmbedPart *part, TQObject *target, TQObject *r )
: JSProxy( JSProxy::ObjectProxy ),
jspart( part ), js( part->interpreter() ), obj( target ), root( r ) {
policy = JSSecurityPolicy::defaultPolicy();
}
JSObjectProxy::JSObjectProxy( KJSEmbedPart *part, TQObject *target )
: JSProxy( JSProxy::ObjectProxy ),
jspart( part ), js( part->interpreter() ), obj( target ), root( target ) {
policy = JSSecurityPolicy::defaultPolicy();
}
JSObjectProxy::~JSObjectProxy() {
if ( owner() == JavaScript && obj->parent() == 0 )
delete obj;
}
void JSObjectProxy::setSecurityPolicy( const JSSecurityPolicy *pol ) {
policy = pol ? pol : new JSSecurityPolicy();
}
bool JSObjectProxy::isAllowed( KJS::Interpreter *js ) const {
return policy->isInterpreterAllowed( this, js );
}
KJS::UString JSObjectProxy::toString( KJS::ExecState *exec ) const {
if ( !exec ) {
kdWarning() << "JS toString with null state, ignoring" << endl;
return KJS::UString();
}
if ( !isAllowed( exec->interpreter() ) ) {
kdWarning() << "JS toString request from unknown interpreter, ignoring" << endl;
return KJS::UString();
}
TQString s( "%1 (%2)" );
s = s.arg( obj ? obj->name() : "Dead Object" );
s = s.arg( obj ? obj->className() : "" );
return KJS::UString( s );
}
KJS::Value JSObjectProxy::get( KJS::ExecState *exec, const KJS::Identifier &p ) const {
if ( !isAllowed( exec->interpreter() ) ) {
kdWarning() << "JS get request from unknown interpreter, ignoring" << endl;
return KJS::Null();
}
if ( !policy->isPropertyAllowed( this, obj, p.ascii() ) )
return ObjectImp::get( exec, p );
if ( !obj ) {
kdDebug( 80001 ) << "JS getting '" << p.ustring().qstring() << "' but qobj has died" << endl;
return ObjectImp::get( exec, p );
}
kdDebug( 80001 ) << "JS getting '" << p.ascii() << endl;
// Properties
TQString prop = p.ustring().qstring();
TQMetaObject *meta = obj->metaObject();
if ( meta->findProperty( p.ascii(), true ) != -1 ) {
TQVariant val = obj->property( prop.ascii() );
kdDebug( 80001 ) << "JS getting '" << p.ascii() << "' ( " << val.typeName() << ")" << endl;
return convertToValue( exec, val );
}
return ObjectImp::get
( exec, p );
}
void JSObjectProxy::put( KJS::ExecState *exec,
const KJS::Identifier &p, const KJS::Value &v,
int attr ) {
if ( !isAllowed( exec->interpreter() ) ) {
kdWarning() << "JS put request from unknown interpreter, ignoring" << endl;
return ;
}
if ( !policy->hasCapability( JSSecurityPolicy::CapabilitySetProperties ) ) {
ObjectImp::put( exec, p, v, attr );
return ;
}
if ( !obj ) {
kdDebug( 80001 ) << "JS setting '" << p.ascii() << "' but qobj has died" << endl;
ObjectImp::put( exec, p, v, attr );
return ;
}
// Properties
TQMetaObject *meta = obj->metaObject();
int propIndex = meta->findProperty( p.ascii(), true );
if ( propIndex != -1 ) {
TQVariant val = convertToVariant( exec, v );
if ( meta->property(propIndex, true)->isEnumType() ) {
obj->setProperty( p.ascii(), val.toUInt() );
} else if ( val.isValid() ) {
obj->setProperty( p.ascii(), val );
} else {
kdWarning(80001) << "Error setting value." << endl;
}
} else {
ObjectImp::put( exec, p, v, attr );
}
if ( jspart->factory() ->eventMapper() ->isEventHandler( p ) ) {
if ( evproxy.isNull() )
evproxy = new KJSEmbed::JSObjectEventProxy( this );
evproxy->addFilter( jspart->factory() ->eventMapper() ->findEventType( p ) );
kdDebug( 80001 ) << "Adding event handler " << p.ascii() << endl;
}
}
//
// Implementation of JS Method Bindings
//
void JSObjectProxy::addBindings( KJS::ExecState *exec, KJS::Object &object ) {
kdDebug( 80001 ) << "JSObjectProxy::addBindings() " << ( obj->name() ? obj->name() : "dunno" )
<< ", class " << obj->className() << endl;
if ( policy->hasCapability( JSSecurityPolicy::CapabilityGetProperties | JSSecurityPolicy::CapabilitySetProperties ) ) {
object.put( exec, "properties", KJS::Object( new JSObjectProxyImp( exec, JSObjectProxyImp::MethodProps, this ) ) );
}
if ( policy->hasCapability( JSSecurityPolicy::CapabilityTree ) ) {
JSObjectProxyImp::addBindingsTree( exec, object, this );
JSObjectProxyImp::addBindingsDOM( exec, object, this );
}
if ( policy->hasCapability( JSSecurityPolicy::CapabilitySlots ) ) {
addBindingsSlots( exec, object );
JSObjectProxyImp::addBindingsConnect( exec, object, this );
}
addBindingsClass( exec, object );
}
void JSObjectProxy::addBindingsClass( KJS::ExecState *exec, KJS::Object & /*object*/ ) {
KJS::Identifier clazzid;
TQObject *o = obj;
Bindings::BindingObject *bo = dynamic_cast<Bindings::BindingObject *>( o );
if ( bo ) {
clazzid = KJS::Identifier( bo->jsClassName() ? bo->jsClassName() : obj->className() );
} else {
clazzid = KJS::Identifier( obj->className() );
}
KJS::Object global = js->globalObject();
if ( global.hasProperty( exec, clazzid ) ) {
kdDebug( 80001 ) << "addBindingsClass() " << clazzid.qstring() << " already known" << endl;
KJS::Object clazz = global.get( exec, clazzid ).toObject( exec );
Bindings::JSFactoryImp *imp = dynamic_cast<Bindings::JSFactoryImp *>( clazz.imp() );
if ( !imp ) {
kdWarning() << "addBindingsClass() Class was not created by normal means" << endl;
return ;
}
kdDebug( 80001 ) << "addBindingsClass() Adding enums" << endl;
imp->setDefaultValue( js->builtinObject().construct( exec, KJS::List() ) );
addBindingsEnum( exec, clazz );
} else {
kdWarning() << "addBindingsClass() " << clazzid.qstring() << " not known" << endl;
}
}
void JSObjectProxy::addBindingsEnum( KJS::ExecState *exec, KJS::Object &object ) {
TQMetaObject * mo = obj->metaObject();
TQStrList enumList = mo->enumeratorNames( true );
for ( TQStrListIterator iter( enumList ); iter.current(); ++iter ) {
const TQMetaEnum *me = mo->enumerator( iter.current(), true );
for ( uint i = 0 ; i < me->count ; i++ ) {
TQCString key( ( me->items ) [ i ].key );
int val = ( me->items ) [ i ].value;
object.put( exec, key.data(), KJS::Number( val ), KJS::ReadOnly );
}
}
}
void JSObjectProxy::addBindingsSlots( KJS::ExecState *exec, KJS::Object &object ) {
// Publish slots with supported signatures as methods.
TQMetaObject * mo = obj->metaObject();
TQStrList slotList( mo->slotNames( true ) );
for ( TQStrListIterator iter( slotList ); iter.current(); ++iter ) {
addSlotBinding( iter.current(), exec, object );
}
}
void JSObjectProxy::addSlotBinding( const TQCString &name, KJS::ExecState *exec, KJS::Object &object ) {
// Lookup and bind slot
TQMetaObject * mo = obj->metaObject();
int slotid = mo->findSlot( name.data(), true );
if ( slotid == -1 )
return ;
const TQMetaData *md = mo->slot( slotid, true );
if ( md->access != TQMetaData::Public )
return ;
// Find signature
int id = Bindings::JSSlotUtils::findSignature( name );
// kdDebug( 80001 )<<"JSObjectProxy::addSlotBinding()::slot:"<<name<<" id:"<<id<<endl;
if ( id < 0 )
return ;
TQCString jsname = name;
jsname.detach();
jsname.replace( TQRegExp( "\\([^\\)]*\\)" ), "" );
// Find the return type, we only care if it is a pointer type
const TQUMethod *m = md->method;
const char *retclass = 0;
TQCString ptr( "ptr" );
if ( m->count && ( m->parameters->inOut == TQUParameter::Out )
&& ( ptr == m->parameters->type->desc() ) ) {
retclass = ( const char * ) m->parameters->typeExtra;
// kdDebug(80001) << "Return type is a pointer, type " << retclass << endl;
}
// Create the Imp
JSObjectProxyImp *imp = new JSObjectProxyImp( exec, JSObjectProxyImp::MethodSlot,
retclass ? retclass : "", id, name, this );
if ( !object.hasProperty( exec, KJS::Identifier( jsname ) ) ) {
// The identifier is unused
object.put( exec, KJS::Identifier( jsname.data() ), KJS::Object( imp ) );
} else {
// The identifier has already been used
TQString s( name );
TQCString cs = TQString( "%1%2" ).arg( jsname ).arg( s.contains( ',' ) + 1 ).ascii();
//kdDebug(80001) << "Method " << jsname << " exists, using " << cs << " for " << s << endl;
object.put( exec, KJS::Identifier( cs.data() ), KJS::Object( imp ) );
}
}
} // namespace KJSEmbed