/* * Copyright (C) 2001-2003, Richard J. Moore * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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() : "" ); 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"<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 // Local Variables: // c-basic-offset: 4 // End: