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.
302 lines
11 KiB
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
|