/*
 *  Copyright (C) 2001-2004, 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., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 */

#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <qobject.h>
#include <qcombobox.h>
#include <qdialog.h>
#include <qdir.h>
#include <qfile.h>
#include <qimage.h>
#include <qlistview.h>
#include <qmainwindow.h>
#include <qpainter.h>
#include <qprogressdialog.h>
#include <qtextstream.h>
#include <qtimer.h>
#include <qwidget.h>
#include <qwidgetfactory.h>
#include <qsplitter.h>
#include <qscrollview.h>
#include <qcanvas.h>
#include <qlayout.h>

#ifndef QT_ONLY

#include <dcopref.h>
#include <kaction.h>
#include <klibloader.h>
#include <klocale.h>
#include <kmainwindow.h>
#include <kservice.h>
#include <ktrader.h>

#include <kparts/part.h>
#include <kparts/mainwindow.h>
#include <kparts/componentfactory.h>

#endif // QT_ONLY

#include <kjs/interpreter.h>
#include <kjs/identifier.h>
#include <kjs/types.h>

#include "jsbinding.h"
#include "jsobjectproxy.h"
#include "jsopaqueproxy.h"
#include "jsvalueproxy.h"
#include "jsconsolewidget.h"
#include "jseventmapper.h"
#include "jseventutils.h"
#include "kjsembedpart.h"
#include "customobject_imp.h"

#include "builtins/stddialog_imp.h"
#include "builtins/textstream_imp.h"
#include "builtins/qdir_imp.h"

#ifndef QT_ONLY

#include "builtins/stdaction_imp.h"

#include "bindings/image_imp.h"
#include "bindings/pen_imp.h"
#include "bindings/pixmap_imp.h"
#include "bindings/painter_imp.h"
#include "bindings/dcop_imp.h"
#include "bindings/netaccess_imp.h"
#include "bindings/movie_imp.h"
#include "bindings/sql_imp.h"
#include "bindings/kconfig_imp.h"
#include "bindings/brush_imp.h"
#include "bindings/qlistviewitem_imp.h"
#include "bindings/qcombobox_imp.h"

#endif // QT_ONLY

#include "global.h"
#include "jsbindingplugin.h"
#include "jsfactory_imp.h"
#include "jsfactory.h"

//
// KPart Implementation
//
namespace KJSEmbed {

typedef Bindings::JSFactoryImp JSFactoryImp;
typedef Bindings::CustomObjectImp CustomObjectImp;
typedef BuiltIns::StdDialogImp StdDialogImp;
typedef BuiltIns::TextStreamImp TextStreamImp;

class JSFactoryPrivate
{
public:
    QDict<KJSEmbed::Bindings::JSBindingPlugin> plugins;
};


JSFactory::JSFactory( KJSEmbedPart *part )
    : jspart( part )
{
    evmapper = new JSEventMapper();
    d = new JSFactoryPrivate;
}

JSFactory::~JSFactory()
{
    delete evmapper;
}

void JSFactory::addBindingPluginTypes(KJS::ExecState *exec, KJS::Object &parent)
{
#ifndef QT_ONLY

    // Get list of valid plugin types
    KTrader::OfferList offers = KTrader::self()->query( "JSBindingPlugin/Binding" );
    if ( !offers.count() )
	return;

    KTrader::OfferListIterator itr = offers.begin();
    while( itr != offers.end() ) {
        QString classname = (*itr)->name();
        JSFactoryImp *cons = new JSFactoryImp( exec, this, JSFactoryImp::NewInstance, classname );
        parent.put( exec, KJS::Identifier( cons->parameter() ), KJS::Object( cons ) );
        addType(classname, TypePlugin);
	++itr;
    }
#else
    Q_UNUSED( exec );	
    Q_UNUSED( parent );	
#endif // QT_ONLY
}

bool JSFactory::isBindingPlugin(const QString &classname) const
{
    if ( !isSupported( classname ) )
	return false;
    return (objtypes[classname] & TypePlugin);
}

KJS::Object JSFactory::createBindingPlugin(KJS::ExecState *exec, const QString &classname, const KJS::List &args )
{
#ifndef QT_ONLY

    Bindings::JSBindingPlugin *plugin = d->plugins[classname];
    if ( plugin == 0L ) {
        QString query = "JSBindingPlugin/Binding";
        QString constraint =  "[Name] == '" + classname + "'";
        plugin = KParts::ComponentFactory::createInstanceFromQuery<Bindings::JSBindingPlugin>(query, constraint);
        if (plugin != 0L)
              d->plugins.insert(classname, plugin);
    }

    if (plugin != 0L)
         return plugin->createBinding(jspart, exec, args);

#else
    Q_UNUSED( exec );	
    Q_UNUSED( args );	
#endif // QT_ONLY

    kdWarning( 80001 ) << "Unable to load binding " << classname << "." << endl;

    return KJS::Object();
}

KJS::Object JSFactory::create( KJS::ExecState *exec, const QString &classname, const KJS::List &args )
{
    if ( !isSupported( classname ) ) {
	QString msg = i18n( "Could not create object of type '%1'" ).arg( classname );
	KJS::Object err = KJS::Error::create( exec, KJS::TypeError, msg.utf8() );
	exec->setException( err );
	return err;
    }

    if ( isQObject( classname ) ) {
	// Get parent
	QObject *parent=0;
	if ( args.size() ) {
	    JSObjectProxy *proxy = JSProxy::toObjectProxy( args[0].imp() );
	    if ( proxy )
		parent = proxy->object();
	}

	// Get name
	QCString name;
	QString arg1 = (args.size() > 1) ? args[1].toString(exec).qstring() : QString::null;
	if ( !arg1.isNull() )
	    name = arg1.latin1();

	QObject *obj = create( classname, parent, name.data() );
	if ( obj )
	    return createProxy( exec, obj );
    }
    else if ( isOpaque( classname ) ) {
	KJS::Object opobj = createOpaque( exec, classname, args );
	if ( opobj.isValid() )
	    return opobj;
    }
    else if ( isValue( classname ) ) {
	KJS::Object valobj = createValue( exec, classname, args );
	if ( valobj.isValid() )
	    return valobj;
    }
    else if ( isBindingPlugin( classname ) )
    {
        KJS::Object plugobj = createBindingPlugin(exec, classname, args );
	if ( plugobj.isValid() )
	    return plugobj;
    }

    QString msg = i18n( "Could not create object of type '%1'" ).arg( classname );
    KJS::Object err = KJS::Error::create( exec, KJS::TypeError, msg.utf8() );
    exec->setException( err );

    return err;
}

KJS::Object JSFactory::createProxy( KJS::ExecState *exec,
				    QObject *target, const JSObjectProxy *ctx ) const
{
    kdDebug(80001) << "JSFactory::createProxy: Target '" << target->name()
	      << "' type " << target->className() << endl;

    JSObjectProxy *prx;
    if ( ctx )
	prx = new JSObjectProxy( jspart, target, ctx->rootObject(), ctx->securityPolicy() );
    else
	prx = new JSObjectProxy( jspart, target );

    kdDebug(80001) << "Proxy created" << endl;

    KJS::Object proxyObj( prx );
    prx->addBindings( exec, proxyObj );
    extendProxy( exec, proxyObj );
 
    kdDebug(80001) << "Returning object" << endl;

    return proxyObj;
}

KJS::Object JSFactory::createProxy( KJS::ExecState *exec,
				    QTextStream *target, const JSObjectProxy *context ) const
{
    Q_UNUSED(context)
    kdDebug(80001) << "TextStream proxy created" << endl;

    JSOpaqueProxy *prx = new JSOpaqueProxy( target );
    KJS::Object proxyObj( prx );

    prx->addBindings( exec, proxyObj );
    TextStreamImp::addBindings( exec, proxyObj );

    return proxyObj;
}

KJS::Object JSFactory::createProxy( KJS::ExecState *exec,
				    QEvent *target, const JSObjectProxy *context ) const
{
    switch( target->type() ) {
	case QEvent::MouseButtonPress:
	case QEvent::MouseButtonRelease:
	case QEvent::MouseMove:
	case QEvent::MouseButtonDblClick:
	    return JSEventUtils::convertEvent( exec, (QMouseEvent *) target, context );
            break;
	case QEvent::KeyPress:
	case QEvent::KeyRelease:
	case QEvent::Accel:
	case QEvent::AccelOverride:
	     return JSEventUtils::convertEvent( exec, (QKeyEvent *) target, context );
	     break;
	case QEvent::IMStart:
	case QEvent::IMCompose:
	case QEvent::IMEnd:
	     return JSEventUtils::convertEvent( exec, (QIMEvent *) target, context );
	     break;
	case QEvent::Paint:
	     return JSEventUtils::convertEvent( exec, (QPaintEvent *) target, context );
	     break;
	case QEvent::Resize:
	     return JSEventUtils::convertEvent( exec, (QResizeEvent *) target, context );
	     break;
	case QEvent::FocusIn:
	case QEvent::FocusOut:
	     return JSEventUtils::convertEvent( exec, (QFocusEvent *) target, context );
	     break;
	case QEvent::Close:
	     return JSEventUtils::convertEvent( exec, (QCloseEvent *) target, context );
	     break;
	case QEvent::ChildInserted:
	case QEvent::ChildRemoved:
	     return JSEventUtils::convertEvent( exec, (QChildEvent *) target, context );
	    break;
	case QEvent::Move:
	     return JSEventUtils::convertEvent( exec, (QMoveEvent *) target, context );
	     break;
	case QEvent::Wheel:
	     return JSEventUtils::convertEvent( exec, (QWheelEvent *) target, context );
	     break;
	case QEvent::Show:
	case QEvent::Hide:
	case QEvent::DragLeave:
	     return JSEventUtils::convertEvent( exec, (QEvent *) target, context );
	     break;
	default:
	    break;
    }

    return JSEventUtils::convertEvent( exec, (QEvent *) target, context );
}

KJS::Object JSFactory::extendProxy( KJS::ExecState *exec, KJS::Object &target ) const
{
    CustomObjectImp::addBindings( exec, target );
    addBindingsPlugin( exec, target );
    return target;
}

void JSFactory::addBindingsPlugin(KJS::ExecState *exec, KJS::Object &target) const
{
    kdDebug(800001)<<"JSFactory::addBindingsPlugin"<<endl;
    JSObjectProxy *proxy = JSProxy::toObjectProxy( target.imp() );
    if ( !proxy )
        return;
    if (!isBindingPlugin(proxy->object()->className()))
	return;

#ifndef QT_ONLY
    Bindings::JSBindingPlugin *plugin = d->plugins[proxy->object()->className()];
    if ( plugin == 0L ) {
        QString query = "JSBindingPlugin/Binding";
        QString constraint =  "[Name] == '" + QString::fromUtf8(proxy->object()->className()) + "'";
        plugin = KParts::ComponentFactory::createInstanceFromQuery<Bindings::JSBindingPlugin>(query, constraint);
        if (plugin != 0L)
              d->plugins.insert(proxy->object()->className(), plugin);
    }

    if (plugin != 0L) {
	kdDebug(800001)<<"JSFactory::addBindingsPlugin: calling plugin function"<<endl;
	plugin->addBindings(exec,target);
	return;
    }
#else
    Q_UNUSED( exec );	
#endif // QT_ONLY

    kdWarning( 80001 ) << "Unable to add bindings to " << proxy->object()->className() << "." << endl;
    return;

}


QObject *JSFactory::createBinding( const QString &cname, QObject *parent, const char *name )
{
#ifndef QT_ONLY

    // Bindings
    if ( cname == "DCOPInterface" )
	return new Bindings::JSDCOPInterface( jspart->interpreter(), parent, name );
    else if ( cname == "NetAccess" )
	return new Bindings::NetAccess( parent, name );
    else if ( cname == "Movie" )
	return new Bindings::Movie( parent, name );
    else if ( cname == "SqlDatabase" )
	return new Bindings::SqlDatabase( parent, name );
    else if ( cname == "SqlQuery" )
	return new Bindings::SqlQuery( parent, name );
    else if ( cname == "Config" )
	return new Bindings::Config( parent, name );

#else
    Q_UNUSED( cname );	
    Q_UNUSED( parent );	
    Q_UNUSED( name );	
#endif // QT_ONLY

    return 0;
}

QObject *JSFactory::createObject( const QString &cname, QObject *parent, const char *name )
{
    // QObjects defined by Qt
    if ( cname == "QObject" )
	return new QObject( parent, name );
    else if ( cname == "QTimer" )
	return new QTimer( parent, name );

#ifndef QT_ONLY
    // QObjects defined by KDE
    else if ( cname == "KAction" )
	return new KAction( parent, name );
    else if ( cname == "KToggleAction" )
	return new KToggleAction( parent, name );
#endif // QT_ONLY

#if 0
    QWidget *w = dynamic_cast<QWidget *>( parent );
    if ( !w )
	return 0;

    if ( cname == "QHBoxLayout" )
	return new QHBoxLayout( w, name );
    else if ( cname == "QVBoxLayout" )
	return new QVBoxLayout( w, name );
#endif
    return 0;
}

KJS::Object JSFactory::createOpaque( KJS::ExecState *exec, const QString &cname, const KJS::List &args )
{
#ifndef QT_ONLY

    if ( cname == "DCOPClient" ) {
	JSOpaqueProxy *prx = new JSOpaqueProxy(0, "DCOPClient" );
	KJS::Object proxyObj(prx);
	Bindings::JSDCOPClient::addBindings( exec, proxyObj );
	return proxyObj;
    }
    else if ( cname == "DCOPRef" ) {
	JSOpaqueProxy *prx = new JSOpaqueProxy(new DCOPRef(), "DCOPRef" );
	KJS::Object proxyObj(prx);
	Bindings::JSDCOPRef::addBindings( exec, proxyObj );
	return proxyObj;
    }
#endif // QT_ONLY

    if ( cname == "QDir" ) {
	JSOpaqueProxy *prx;
	if ( args.size() == 0 ) {
	    prx = new JSOpaqueProxy( new QDir( QDir::current() ), "QDir" );
	}
	else {
	    QString arg0 = (args.size() >= 1) ? args[0].toString(exec).qstring() : QString::null;
	    prx = new JSOpaqueProxy( new QDir(arg0), "QDir" );
	}
	KJS::Object proxyObj(prx);
	QDirImp::addBindings( exec, proxyObj );
	return proxyObj;
    }
#ifndef QT_ONLY
	else if ( cname == "Painter" ){
	   Bindings::PainterRef *p = new Bindings::PainterRef();
	   JSOpaqueProxy *prx = new JSOpaqueProxy(p, "Painter" );
	   KJS::Object proxyObj(prx);
	   Bindings::Painter::addBindings( exec, proxyObj );
	   return proxyObj;
	}
        
	else if ( cname == "QListViewItem" ) {

	if ( args.size() == 0 ) {
	    // FALL THRU
	}
	else {
	    JSOpaqueProxy *arg0 = JSProxy::toOpaqueProxy( args[0].imp() );
	    JSOpaqueProxy *prx = 0;

	    if ( arg0 ) {
		if ( arg0->typeName() == "QListViewItem" ) {
		    QListViewItem *parent = (QListViewItem *)( arg0->toVoidStar() );
		    prx = new JSOpaqueProxy( new QListViewItem( parent ), "QListViewItem" );
		}
		else {
		    return KJS::Object();
		}
	    }
	    else {
		JSObjectProxy *arg0 = JSProxy::toObjectProxy( args[0].imp() );
		if ( arg0 ) {
		    QListView *parent = (QListView *)( arg0->widget() );
		    prx = new JSOpaqueProxy( new QListViewItem( parent ), "QListViewItem" );
		}
		else {
		    return KJS::Object();
		}
	    }

	    KJS::Object proxyObj(prx);
	    QListViewItemImp::addBindings( exec, proxyObj );
	    return proxyObj;
	}
    }
#endif // QT_ONLY

    return KJS::Object();
}

KJS::Object JSFactory::createValue( KJS::ExecState *exec, const QString &cname, const KJS::List &/*args*/ )
{
#ifndef QT_ONLY

    if ( cname == "Image" ){
	QImage img = QImage();
    	JSValueProxy *prx = new JSValueProxy( );
	prx->setValue(img);
	KJS::Object proxyObj(prx);
    	Bindings::ImageImp::addBindings( exec, proxyObj);
	return proxyObj;
    }
    if ( cname == "Brush" ){
	QBrush brsh = QBrush();
    	JSValueProxy *prx = new JSValueProxy( );
	prx->setValue(brsh);
	KJS::Object proxyObj(prx);
    	Bindings::BrushImp::addBindings( exec, proxyObj);
	return proxyObj;
    }
    if ( cname == "Pixmap" ){
	QPixmap pix = QPixmap();
    	JSValueProxy *prx = new JSValueProxy( );
	prx->setValue(pix);
	KJS::Object proxyObj(prx);
    	Bindings::Pixmap::addBindings( exec, proxyObj);
	return proxyObj;
    }
    if ( cname == "Pen" ){
	QPen pen = QPen();
    	JSValueProxy *prx = new JSValueProxy( );
	prx->setValue(pen);
	KJS::Object proxyObj(prx);
    	Bindings::Pen::addBindings( exec, proxyObj);
	return proxyObj;
    }
#else
    Q_UNUSED( exec );	
    Q_UNUSED( cname );	
#endif // QT_ONLY
    
    return KJS::Object();
}

QWidget *JSFactory::createWidget( const QString &cname, QWidget *pw, const char *name )
{
    if ( cname == "QSplitter" )
	return new QSplitter( pw, name );
    else if ( cname == "QMainWindow" )
	return new QMainWindow( pw, name );
    else if ( cname == "QProgressDialog" )
	return new QProgressDialog( pw, name );
    else if ( cname == "QScrollView" )
	return new QScrollView( pw, name );
    else if ( cname == "QCanvasView" )
	return new QCanvasView( pw, name );
#ifndef QT_ONLY
    else if ( cname == "KMainWindow" )
	return new KMainWindow( pw, name );
    else if ( cname == "KParts_MainWindow" )
	return new KParts::MainWindow( pw, name );
#endif // QT_ONLY

    return 0;
}

QObject *JSFactory::create( const QString &cname, QObject *parent, const char *name )
{
    kdDebug(80001) << "KJSEmbedPart::create() name " << name << " class " << cname << endl;

    // Factory widgets
    QWidgetFactory wf;
    QWidget *pw = (parent && parent->isWidgetType()) ? static_cast<QWidget *>(parent) : 0;
    QWidget *w = wf.createWidget( cname, pw, name );
    if ( w )
	return w;

    // Custom widgets
    QObject *obj;
    obj = createWidget( cname, pw, name );
    if ( obj ) {
	if ( !isQObject( obj->className() ) )
	    addType( obj->className() );
	return obj;
    }

    // Custom objects
    obj = JSFactory::createObject( cname, parent, name );
    if ( obj ) {
	if ( !isQObject( obj->className() ) )
	    addType( obj->className() );
	return obj;
    }

    // Binding objects
    obj = JSFactory::createBinding( cname, parent, name );
    if ( obj ) {
	if ( !isQObject( obj->className() ) )
	    addType( obj->className() );
	return obj;
    }

    kdDebug(80001) << "Found nothing in :" <<  cname << ":" << endl;
    return 0;
}

KParts::ReadOnlyPart *JSFactory::createROPart( const QString &svc, QObject *parent, const char *name )
{
    kdDebug(80001) << "JSFactory::createROPart svc " << svc << " parent " << (uint)parent << endl;
    return createROPart( svc, "'KParts/ReadOnlyPart' in ServiceTypes", parent, name );
}

KParts::ReadOnlyPart *JSFactory::createROPart( const QString &svc, const QString &con,
					       QObject *parent, const char *name )
{
#ifndef QT_ONLY
    kdDebug(80001) << "JSFactory::createROPart svc " << svc << " con " << con
              << " parent " << (uint)parent << endl;

    KTrader::OfferList offers = KTrader::self()->query( svc, con );
    if ( !offers.count() )
	return 0;

    KService::Ptr ptr = offers.first();
    KLibFactory *fact = KLibLoader::self()->factory( ptr->library().ascii() );
    if ( !fact ) {
	kdDebug(80001) << "Unable to find a matching part" << endl;
	return 0;
    }

    QObject *obj = fact->create( parent, name, "KParts::ReadOnlyPart" );
    addType( obj->className() );
    return static_cast<KParts::ReadOnlyPart *>(obj);
#else // QT_ONLY
    Q_UNUSED( svc );	
    Q_UNUSED( con );	
    Q_UNUSED( parent );	
    Q_UNUSED( name );	
    return 0;
#endif // QT_ONLY
}

KParts::ReadWritePart *JSFactory::createRWPart( const QString &svc, QObject *parent, const char *name )
{
    kdDebug(80001) << "JSFactory::createRWPart svc " << svc << " parent " << (uint)parent << endl;
    return createRWPart( svc, "'KParts/ReadWritePart' in ServiceTypes", parent, name );
}

KParts::ReadWritePart *JSFactory::createRWPart( const QString &svc, const QString &con,
						QObject *parent, const char *name )
{
#ifndef QT_ONLY
    kdDebug(80001) << "JSFactory::createRWPart svc " << svc << " con " << con
              << " parent " << (uint)parent << endl;

    KTrader::OfferList offers = KTrader::self()->query( svc, con );
    if ( !offers.count() )
	return 0;

    KService::Ptr ptr = offers.first();
    KLibFactory *fact = KLibLoader::self()->factory( ptr->library().ascii() );
    if ( !fact ) {
	kdDebug(80001) << "Unable to find a matching part" << endl;
	return 0;
    }

    QObject *obj = fact->create( parent, name, "KParts::ReadWritePart" );
    addType( obj->className() );
    return static_cast<KParts::ReadWritePart *>(obj);
#else // QT_ONLY
    Q_UNUSED( svc );	
    Q_UNUSED( con );	
    Q_UNUSED( parent );	
    Q_UNUSED( name );	
    return 0;
#endif // QT_ONLY
}

QWidget *JSFactory::loadUI( const QString &uiFile, QObject *connector, QWidget *parent, const char *name )
{
    return QWidgetFactory::create( uiFile, connector, parent, name );
}

QStringList JSFactory::listBindingPlugins( KJS::ExecState *exec, KJS::Object &self )
{
    Q_UNUSED(exec)
    Q_UNUSED(self)
    QStringList pluginList;
    QStringList allTypes = objtypes.keys();
    for( uint idx = 0; idx < allTypes.count(); ++idx )
    {
    	if( objtypes[allTypes[idx]] & TypePlugin )
		pluginList.append( allTypes[idx] );
    }
    return pluginList;
}

bool JSFactory::isQObject( const QString &clazz ) const
{
    if ( !isSupported( clazz ) )
	return false;

    return (objtypes[clazz] & TypeQObject);
}

bool JSFactory::isValue( const QString &clazz ) const
{
    if ( !isSupported( clazz ) )
	return false;

    return objtypes[clazz] == TypeValue;
}

bool JSFactory::isOpaque( const QString &clazz ) const
{
    if ( !isSupported( clazz ) )
	return false;

    return objtypes[clazz] == TypeOpaque;
}

void JSFactory::addQObjectPlugin(const QString &classname, KJSEmbed::Bindings::JSBindingPlugin* plugin)
{
    if (plugin) {
	addType(classname, TypeQObjectPlugin);
	d->plugins.insert(classname, plugin);
    }
}

void JSFactory::addType( const QString &clazz, uint prxtype )
{
    if ( prxtype == TypeInvalid ) {
	objtypes.remove( clazz );
	return;
    }

    objtypes[clazz] = prxtype;
}

bool JSFactory::isSupported( const QString &clazz ) const
{
    return objtypes.contains( clazz );
}

uint JSFactory::proxyType( const QString &clazz ) const
{
    if ( !isSupported( clazz ) )
	return TypeInvalid;
    return objtypes[clazz];
}

void JSFactory::addTypes( KJS::ExecState *exec, KJS::Object &parent )
{
    addWidgetFactoryTypes( exec, parent );
    addCustomTypes( exec, parent );
    addBindingTypes( exec, parent );
    addObjectTypes( exec, parent );
    addOpaqueTypes( exec, parent );
    addValueTypes( exec, parent );
    addBindingPluginTypes(exec, parent);
}

QStringList JSFactory::types() const
{
    return objtypes.keys();
}

void JSFactory::addWidgetFactoryTypes( KJS::ExecState *exec, KJS::Object &parent )
{
    QStringList sl = QWidgetFactory::widgets();

    for ( QStringList::Iterator it = sl.begin(); it != sl.end(); ++it ) {
	JSFactoryImp *cons = new JSFactoryImp( exec, this, JSFactoryImp::NewInstance, *it );
	parent.put( exec, KJS::Identifier( KJS::UString(cons->parameter()) ), KJS::Object( cons ) );
	addType( *it );
    }
}

void JSFactory::addCustomTypes( KJS::ExecState *exec, KJS::Object &parent )
{
    const char *classes[] = {

	"QSplitter", "QScrollView", "QCanvasView",
	"QObject", "QTimer",
	"QLayout", "QBoxLayout", "QHBoxLayout", "QVBoxLayout",

#ifndef QT_ONLY
	"KMainWindow", "KXMLGUIClient",
	"KAction", "KToggleAction",

	"KParts_MainWindow",
#endif // QT_ONLY

	0
    };

    for ( int i=0 ; classes[i] ; i++ ) {
	JSFactoryImp *cons = new JSFactoryImp( exec, this, JSFactoryImp::NewInstance, classes[i] );
	parent.put( exec, KJS::Identifier( KJS::UString(cons->parameter()) ), KJS::Object( cons ) );
	addType( classes[i] );
    }
}

void JSFactory::addBindingTypes( KJS::ExecState *exec, KJS::Object &parent )
{
#ifndef QT_ONLY

    const char *bindings[] = {
	"Pixmap", "KJSEmbed::Bindings::Pixmap",
	"NetAccess", "KJSEmbed::Bindings::NetAccess",
	"DCOPInterface", "KJSEmbed::Bindings::JSDCOPInterface",
	"SqlDatabase", "KJSEmbed::Bindings::SqlDatabase",
	"Movie", "KJSEmbed::Bindings::Movie",
	"SqlQuery", "KJSEmbed::Bindings::SqlQuery",
	"Config", "KJSEmbed::Bindings::Config",
	0, 0
    };

    for ( int i=0 ; bindings[i] ; i += 2 ) {
	JSFactoryImp *cons = new JSFactoryImp( exec, this, JSFactoryImp::NewInstance, bindings[i] );
	parent.put( exec, KJS::Identifier( cons->parameter() ), KJS::Object( cons ) );
	addType( bindings[i] );
	addType( bindings[i+1] );
    }

#else
    Q_UNUSED( exec );
    Q_UNUSED( parent );
#endif // QT_ONLY
}

void JSFactory::addOpaqueTypes( KJS::ExecState *exec, KJS::Object &parent )
{
    const char *classes[] = {
	"QTextStream",
	"TextStream",
	"DCOPClient",
	"Painter",
	"QDir",
	"QListViewItem",
	0
    };

    for ( int i=0 ; classes[i] ; i++ ) {
	JSFactoryImp *cons = new JSFactoryImp( exec, this, JSFactoryImp::NewInstance, classes[i] );
	parent.put( exec, KJS::Identifier( KJS::UString(cons->parameter()) ), KJS::Object( cons ) );
	addType( classes[i], TypeOpaque );
    }
}
void JSFactory::addValueTypes( KJS::ExecState *exec, KJS::Object &parent )
{
    const char *classes[] = {
	"Image",
	"Brush",
	"Pixmap",
	"Pen",
	0
    };

    for ( int i=0 ; classes[i] ; i++ ) {
	JSFactoryImp *cons = new JSFactoryImp( exec, this, JSFactoryImp::NewInstance, classes[i] );
	parent.put( exec, KJS::Identifier( KJS::UString(cons->parameter()) ), KJS::Object( cons ) );
	addType( classes[i], TypeValue );
    }
}


void JSFactory::addObjectTypes( KJS::ExecState */*exec*/, KJS::Object &/*parent*/ )
{
    const char *classes[] = {
	"QAccel",
	"QAccessibleObject",
	"QAction",
	"QActionGroup",
	"QApplication",
	"QAquaStyle",
	"QAssistantClient",
	"QAxObject",
	"QAxWidget",
	"QButton",
	"QCDEStyle",
	"QCanvas",
	"QClipboard",
	"QColorDialog",
	"QColorDrag",
	"QCommonStyle",
	"QCopChannel",
	"QDataPump",
	"QDateTimeEditBase",
	"QDesktopWidget",
	"QDns",
	"QDockArea",
	"QDockWindow",
	"QDoubleValidator",
	"QDragObject",
	"QEditorFactory",
	"QErrorMessage",
	"QEventLoop",
	"QFileDialog",
	"QFileIconProvider",
	"QFontDialog",
	"QFtp",
	"QGLWidget",
	"QGridLayout",
	"QGridView",
	"QHButtonGroup",
	"QHGroupBox",
	"QHeader",
	"QHttp",
	"QIconDrag",
	"QImageDrag",
	"QInputDialog",
	"QIntValidator",
	"QLocalFs",
	"QMacStyle",
	"QMenuBar",
	"QMessageBox",
	"QMotif",
	"QMotifDialog",
	"QMotifPlusStyle",
	"QMotifStyle",
	"QMotifWidget",
	"QNPInstance",
	"QNPWidget",
	"QNetworkOperation",
	"QNetworkProtocol",
	"QObjectCleanupHandler",
	"QPlatinumStyle",
	"QProcess",
	"QProgressDialog",
	"QRegExpValidator",
	"QSGIStyle",
	"QServerSocket",
	"QSessionManager",
	"QSignal",
	"QSignalMapper",
	"QSizeGrip",
	"QSocket",
	"QSocketNotifier",
	"QSound",
	"QSplashScreen",
	"QSqlDatabase",
	"QSqlDriver",
	"QSqlEditorFactory",
	"QSqlForm",
	"QStatusBar",
	"QStoredDrag",
	"QStyle",
	"QStyleSheet",
	"QTabBar",
	"QTabDialog",
	"QTextDrag",
	"QToolBar",
	"QToolTipGroup",
	"QTranslator",
	"QUriDrag",
	"QUrlOperator",
	"QVButtonGroup",
	"QVGroupBox",
	"QValidator",
	"QWSKeyboardHandler",
	"QWindowsStyle",
	"QWindowsXPStyle",
	"QWorkspace",
	"QXtWidget",

	0
    };

    for ( int i=0 ; classes[i] ; i++ ) {
	if ( !isSupported(classes[i]) )
	    addType( classes[i] );
    }
}

} // namespace KJSEmbed

// Local Variables:
// c-basic-offset: 4
// End:
