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_imp.cpp

634 lines
19 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 <tqdialog.h>
#include <tqlistbox.h>
#include <tqlistview.h>
#include <tqmetaobject.h>
#include <tqregexp.h>
#include <tqsignal.h>
#include <tqstrlist.h>
#include <tqtabwidget.h>
#include <tqtimer.h>
#include <tqvariant.h>
#include <private/qucom_p.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 "global.h"
#include "jsfactory.h"
#include "slotproxy.h"
#include "slotutils.h"
#include "jsobjectproxy.h"
#include "jsobjectproxy_imp.h"
using namespace KJS;
namespace KJSEmbed {
namespace Bindings {
typedef JSProxy::MethodTable MethodTable;
//
// Factory methods that add the bindings.
//
void JSObjectProxyImp::addBindingsTree( KJS::ExecState *exec, KJS::Object &object, JSObjectProxy *proxy )
{
MethodTable methods[] = {
{ MethodParent, "parent" },
{ MethodChildCount, "childCount" },
{ MethodChild, "child" },
{ MethodChildren, "children" },
{ MethodIsWidgetType, "isWidgetType" },
{ MethodClassName, "className" },
{ MethodSuperClassName, "superClassName" },
{ 0, 0 }
};
int i = 0;
do {
JSObjectProxyImp *obj = new JSObjectProxyImp( exec, methods[i].id, proxy );
obj->setName( KJS::Identifier( methods[i].name ) );
object.put( exec, methods[i].name, KJS::Object(obj) );
i++;
} while( methods[i].id );
}
void JSObjectProxyImp::addBindingsDOM( KJS::ExecState *exec, KJS::Object &object, JSObjectProxy *proxy )
{
MethodTable methods[] = {
{ MethodGetParentNode, "getParentNode" },
{ MethodGetElementById, "getElementById" },
{ MethodHasAttribute, "hasAttribute" },
{ MethodGetAttribute, "getAttribute" },
{ MethodSetAttribute, "setAttribute" },
{ 0, 0 }
};
int i = 0;
do {
JSObjectProxyImp *obj = new JSObjectProxyImp( exec, methods[i].id, proxy );
obj->setName( KJS::Identifier( methods[i].name ) );
object.put( exec, methods[i].name, KJS::Object(obj) );
i++;
} while( methods[i].id );
}
void JSObjectProxyImp::addBindingsConnect( KJS::ExecState *exec, KJS::Object &object, JSObjectProxy *proxy )
{
MethodTable methods[] = {
{ MethodConnect, "connect" },
{ MethodDisconnect, "disconnect" },
{ MethodSignals, "signals" },
{ MethodSlots, "slots" },
{ 0, 0 }
};
int i = 0;
do {
JSObjectProxyImp *obj = new JSObjectProxyImp( exec, methods[i].id, proxy );
obj->setName( KJS::Identifier( methods[i].name ) );
object.put( exec, methods[i].name, KJS::Object(obj) );
i++;
} while( methods[i].id );
}
//
// The real implementation
//
JSObjectProxyImp::JSObjectProxyImp( KJS::ExecState *exec, int mid, JSObjectProxy *parent )
: JSProxyImp(exec), id(mid), proxy(parent), obj(parent->obj)
{
}
JSObjectProxyImp::JSObjectProxyImp( KJS::ExecState *exec,
int mid, const TQCString &name, JSObjectProxy *parent )
: JSProxyImp(exec), id(mid), slotname(name), proxy(parent), obj(parent->obj)
{
}
JSObjectProxyImp::JSObjectProxyImp( KJS::ExecState *exec,
int mid, int sid, const TQCString &name, JSObjectProxy *parent )
: JSProxyImp(exec), id(mid), sigid(sid), slotname(name), proxy(parent), obj(parent->obj)
{
}
JSObjectProxyImp::JSObjectProxyImp( KJS::ExecState *exec,
int mid, const char *ret, int sid, const TQCString &name,
JSObjectProxy *parent )
: JSProxyImp(exec), id(mid), rettype(ret), sigid(sid), slotname(name), proxy(parent), obj(parent->obj)
{
}
//
// Custom methods.
//
KJS::Value JSObjectProxyImp::children( KJS::ExecState *exec, KJS::Object &, const KJS::List & )
{
KJS::List items;
const TQObjectList *kids = obj->children();
if ( kids ) {
TQObjectList l( *kids );
for ( uint i = 0 ; i < l.count() ; i++ ) {
TQObject *child = l.at( i );
TQCString nm = ( child ? child->name() : "<null>" );
items.append( KJS::String( TQString(nm) ) );
}
}
return KJS::Object( proxy->js->builtinArray().construct( exec, items ) );
}
KJS::Value JSObjectProxyImp::properties( KJS::ExecState *exec, KJS::Object &, const KJS::List & )
{
KJS::List items;
TQMetaObject *mo = obj->metaObject();
TQStrList propList( mo->propertyNames( true ) );
for ( TQStrListIterator iter(propList); iter.current(); ++iter ) {
TQCString name = iter.current();
int propid = mo->findProperty( name.data(), true );
if ( propid != -1 ) {
items.append( KJS::String( TQString(name) ) );
}
}
return KJS::Object( proxy->js->builtinArray().construct( exec, items ) );
}
KJS::Value JSObjectProxyImp::callCustomSlot( KJS::ExecState *, KJS::Object &, const KJS::List & )
{
return KJS::Null();
}
//
// Invoke a slot or method.
//
KJS::Value JSObjectProxyImp::callSlot( KJS::ExecState *exec, KJS::Object &self, const KJS::List &args )
{
return JSSlotUtils::invokeSlot( exec, self, args, this );
}
KJS::Value JSObjectProxyImp::call( KJS::ExecState *exec, KJS::Object &self, const KJS::List &args )
{
if ( !proxy->isAllowed(exec->interpreter()) ) {
kdWarning() << "JSObjectProxy::Method call from unknown interpreter!" << endl;
return KJS::Null();
}
if (obj.isNull()) {
kdWarning() << "JSObjectProxy::Method call on null object"<<endl;
return KJS::Null();
}
switch( id ) {
case MethodParent:
{
TQObject *po = obj->parent();
if ( po && proxy->securityPolicy()->isObjectAllowed( proxy, po ) )
return proxy->part()->factory()->createProxy( exec, po, proxy );
return KJS::Null();
}
break;
case MethodChildCount:
{
const TQObjectList *kids = obj->children();
return kids ? KJS::Number( kids->count() ) : KJS::Number(0);
}
break;
case MethodIsWidgetType:
{
return KJS::Boolean( obj->isWidgetType() );
}
break;
case MethodClassName:
{
return KJS::String( obj->className() );
}
break;
case MethodSuperClassName:
{
return KJS::String( obj->metaObject()->superClassName() );
}
break;
case MethodChildren:
return children( exec, self, args );
break;
case MethodProps:
return properties( exec, self, args );
break;
case MethodSlot:
return callSlot( exec, self, args );
break;
case MethodChild:
case MethodGetElementById:
return getElementById( exec, self, args );
break;
case MethodGetParentNode:
return getParentNode( exec, self, args );
break;
case MethodHasAttribute:
return hasAttribute( exec, self, args );
break;
case MethodGetAttribute:
return getAttribute( exec, self, args );
break;
case MethodSetAttribute:
return setAttribute( exec, self, args );
break;
case MethodGetElementsByTagName:
return getElementsByTagName( exec, self, args );
break;
case MethodSignals:
return signalz( exec, self, args );
break;
case MethodSlots:
return slotz( exec, self, args );
break;
case MethodConnect:
return connect( exec, self, args );
case MethodDisconnect:
return disconnect( exec, self, args );
default:
break;
}
return ObjectImp::call( exec, self, args );
}
//
// Connections
//
KJS::Value JSObjectProxyImp::signalz( KJS::ExecState *exec, KJS::Object &, const KJS::List & )
{
KJS::List items;
TQMetaObject *mo = obj->metaObject();
TQStrList signalList( mo->signalNames( true ) );
for ( TQStrListIterator iter(signalList); iter.current(); ++iter ) {
TQCString name = iter.current();
TQString nm( name );
int signalid = mo->findSignal( name.data(), true );
if ( (signalid != -1) && (mo->signal( signalid, true )->access == TQMetaData::Public) )
items.append( KJS::String(nm) );
}
return KJS::Object( proxy->js->builtinArray().construct( exec, items ) );
}
KJS::Value JSObjectProxyImp::slotz( KJS::ExecState *exec, KJS::Object &, const KJS::List & )
{
KJS::List items;
TQMetaObject *mo = obj->metaObject();
TQStrList slotList( mo->slotNames( true ) );
for ( TQStrListIterator iter(slotList); iter.current(); ++iter ) {
TQCString name = iter.current();
TQString nm( name );
int slotid = mo->findSlot( name.data(), true );
if ( (slotid != -1) && (mo->slot( slotid, true )->access == TQMetaData::Public) )
items.append( KJS::String(nm) );
}
return KJS::Object( proxy->js->builtinArray().construct( exec, items ) );
}
KJS::Boolean JSObjectProxyImp::connect( KJS::ExecState *exec,
const KJS::Object &self, const KJS::List &args )
{
// connect sender, sig, slot
// connect sender, sig, recv, method
if ( (args.size() != 3) && (args.size() != 4) )
return KJS::Boolean(false);
// Source object and signal
JSObjectProxy *sendproxy = JSProxy::toObjectProxy( args[0].imp() );
TQObject *sender = sendproxy ? sendproxy->object() : 0;
TQString sig = args[1].toString(exec).qstring();
kdDebug( 80001 ) << "connecting C++ signal" << sig << endl;
// Receiver and slot/signal
KJS::Object recvObj;
TQString dest;
if ( args.size() == 3 ) {
recvObj = self.toObject(exec);
dest = args[2].toString(exec).qstring();
}
else if ( args.size() == 4 ) {
recvObj = args[2].toObject(exec);
dest = args[3].toString(exec).qstring();
}
// Try to connect to C++ slot
JSObjectProxy *recvproxy = JSProxy::toObjectProxy( recvObj.imp() );
if ( recvproxy ) {
TQObject *recv = recvproxy ? recvproxy->object() : 0;
bool ok = JSSlotUtils::connect( sender, sig.ascii(), recv, dest.ascii() );
if ( ok )
return KJS::Boolean(true);
}
return connect( sender, sig.ascii(), recvObj, dest );
}
KJS::Boolean JSObjectProxyImp::connect( TQObject *sender, const char *sig,
const KJS::Object &recv, const TQString &dest )
{
kdDebug(80001) << "Trying signature '" << sig << "'." << endl;
// Try to connect to JS method
JSSlotProxy *slotp = new JSSlotProxy( sender );
slotp->setInterpreter( proxy->interpreter() );
slotp->setProxy( proxy );
slotp->setObject( recv );
slotp->setMethod( dest );
int id = JSSlotUtils::findSignature( sig );
if ( id == JSSlotUtils::SignatureNotSupported ) {
kdWarning(80001) << "Connect with unknown signature '" << sig << "' failed" << endl;
return KJS::Boolean( false );
}
bool ok;
switch ( id ) {
case JSSlotUtils::SignatureNone:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_void()" );
break;
case JSSlotUtils::SignatureInt:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_int(int)" );
break;
case JSSlotUtils::SignatureUInt:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_uint(uint)" );
break;
case JSSlotUtils::SignatureLong:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_long(long)" );
break;
case JSSlotUtils::SignatureULong:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_ulong(ulong)" );
break;
case JSSlotUtils::SignatureBool:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_bool(bool)" );
break;
case JSSlotUtils::SignatureDouble:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_double(double)" );
break;
case JSSlotUtils::SignatureString:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_string(const TQString&)" );
break;
case JSSlotUtils::SignatureCString:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_charstar(const char*)" );
break;
case JSSlotUtils::SignatureColor:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_color(const TQColor&)" );
break;
case JSSlotUtils::SignatureFont:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_font(const TQFont&)" );
break;
case JSSlotUtils::SignaturePoint:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_point(const TQPoint&)" );
break;
case JSSlotUtils::SignatureRect:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_rect(const TQRect&)" );
break;
case JSSlotUtils::SignatureSize:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_size(const TQSize&)" );
break;
case JSSlotUtils::SignaturePixmap:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_pixmap(const TQPixmap&)" );
break;
case JSSlotUtils::SignatureURL:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_url(const KURL&)" );
break;
case JSSlotUtils::SignatureIntInt:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_intint(int, int)" );
break;
case JSSlotUtils::SignatureIntBool:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_intbool(int, bool)" );
break;
case JSSlotUtils::SignatureIntIntIntInt:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_intintint(int, int, int)" );
break;
case JSSlotUtils::SignatureDate:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_date(const TQDate&)" );
break;
case JSSlotUtils::SignatureTime:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_time(const TQTime&)" );
break;
case JSSlotUtils::SignatureDateTime:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_datetime(const TQDateTime&)" );
break;
case JSSlotUtils::SignatureImage:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_image(const TQImage&)" );
break;
case JSSlotUtils::SignatureTQWidget:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_widget(TQWidget*)" );
break;
case JSSlotUtils::SignatureDateDate:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_datedate(const TQDate&, const TQDate& )" );
break;
case JSSlotUtils::SignatureColorString:
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_colorstring(const TQColor&, const TQString&)" );
break;
case JSSlotUtils::SignatureCustom:
{
TQString mangledSig = sig;
mangledSig.remove(' ')
.remove("const")
.remove('&')
.remove('*');
mangledSig = mangledSig.lower();
kdDebug(80001) << "Custom slot signature: " << mangledSig << endl;
break;
}
default:
kdWarning(80001) << "Unsupported signature '" << sig << "' connected with no args" << endl;
ok = JSSlotUtils::connect( sender, sig, slotp, "slot_none()" );
break;
}
if ( !ok ) {
kdDebug(80001) << "Error connecting '" << sig << "'" << endl;
}
return KJS::Boolean(ok);
}
KJS::Boolean JSObjectProxyImp::disconnect( KJS::ExecState *exec, KJS::Object &self, const KJS::List &args )
{
// disconnect sender, sig, slot
// disconnect sender, sig, recv, method
if ( (args.size() != 3) && (args.size() != 4) )
return KJS::Boolean(false);
// Source object and signal
JSObjectProxy *sendproxy = JSProxy::toObjectProxy( args[0].imp() );
TQObject *sender = sendproxy ? sendproxy->object() : 0;
TQString sig = args[1].toString(exec).qstring();
// Receiver and slot/signal
TQObject *recv=0;
TQString dest;
if ( args.size() == 3 ) {
JSObjectProxy *recvproxy = JSProxy::toObjectProxy( self.imp() );
recv = recvproxy ? recvproxy->object() : 0;
dest = args[2].toString(exec).qstring();
}
else if ( args.size() == 4 ) {
JSObjectProxy *recvproxy = JSProxy::toObjectProxy( args[2].imp() );
recv = recvproxy ? recvproxy->object() : 0;
dest = args[3].toString(exec).qstring();
}
return JSSlotUtils::disconnect( exec, self, sender, sig.ascii(), recv, dest.ascii() );
}
//
// DOM methods
//
KJS::Value JSObjectProxyImp::getParentNode( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
if ( args.size())
return KJS::Null();
TQObject *parent = obj->parent();
if ( parent && proxy->securityPolicy()->isObjectAllowed( proxy, parent ) )
return proxy->part()->factory()->createProxy( exec, parent, proxy );
return KJS::Null();
}
KJS::Value JSObjectProxyImp::getElementById( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
if ( !args.size() )
return KJS::Null();
const TQObjectList *kids = obj->children();
if ( !kids )
return KJS::Null();
TQObjectList l( *kids );
TQObject *child = 0;
if ( args[0].isA( KJS::NumberType ) ) {
uint i = args[0].toUInt32( exec );
if ( i >= l.count() )
return KJS::Null();
child = l.at( i );
}
else {
TQString s = args[0].toString( exec ).qstring();
child = obj->child( s.ascii() );
}
if ( child && proxy->securityPolicy()->isObjectAllowed( proxy, child ) ) {
kdDebug(80001) << "Creating subproxy for child " << child->className() << endl;
return proxy->part()->factory()->createProxy( exec, child, proxy );
}
return KJS::Null();
}
KJS::Value JSObjectProxyImp::getElementsByTagName( KJS::ExecState *, KJS::Object &, const KJS::List & )
{
return KJS::Null();
}
KJS::Value JSObjectProxyImp::hasAttribute( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
if ( !args.size() )
return KJS::Null();
TQMetaObject *meta = obj->metaObject();
TQString s = args[0].toString(exec).qstring();
if ( meta->findProperty( s.ascii(), true ) != -1 )
return KJS::Boolean(true);
else
return KJS::Boolean(false);
}
KJS::Value JSObjectProxyImp::getAttribute( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
if ( !args.size() )
{
TQString msg = i18n( "No property was defined." );
return throwError(exec, msg);
}
TQMetaObject *meta = obj->metaObject();
TQString s = args[0].toString(exec).qstring();
kdDebug(80001) << "Get property " << s << " from " << obj->name() << endl;
if ( meta->findProperty( s.ascii(), true ) == -1 )
{
TQString msg = i18n( "Property '%1' could not be found." ).arg( s );
return throwError(exec, msg,KJS::ReferenceError);
}
TQVariant val = obj->property( s.ascii() );
return convertToValue( exec, val );
}
KJS::Value JSObjectProxyImp::setAttribute( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
if ( args.size() != 2 )
return KJS::Boolean(false);
TQMetaObject *meta = obj->metaObject();
TQString s = args[0].toString(exec).qstring();
if ( meta->findProperty( s.ascii(), true ) == -1 )
{
TQString msg = i18n( "Property '%1' could not be found." ).arg( s );
return throwError(exec, msg,KJS::GeneralError);
}
kdDebug(80001) << "Set property " << s << " from " << obj->name() << endl;
TQVariant val = convertToVariant( exec, args[1] );
bool ok = obj->setProperty( s.ascii(), val );
return KJS::Boolean(ok);
}
} // namespace KJSEmbed::Bindings
} // namespace KJSEmbed