/****************************************************************************
** $Id: qswrapperfactory.cpp  beta1   edited Dec 12 12:04 $
**
** Copyright (C) 2001-2002 Trolltech AS.  All rights reserved.
**
** This file is part of the Qt Script for Applications framework (QSA).
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** Licensees holding a valid QSA Beta Evaluation Version license may use
** this file in accordance with the QSA Beta Evaluation Version License
** Agreement provided with the Software.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
**   information about QSA Commercial License Agreements.
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
*****************************************************************************/

#include "qswrapperfactory.h"
#include "qsinterfacefactory_p.h"

/*!
    \class QSWrapperFactory qswrapperfactory.h
    \brief The QSWrapperFactory class provides a mechanism for Qt Script to
    extend QObject C++ types and to automatically wrap non-QObject C++
    types.

    If a C++ object which is available to Qt Script returns a pointer
    of a non-QObject type, by default Qt Script can't wrap it
    dynamically (it can store the pointer and pass it on, but no
    functions can be called on the object). The QSWrapperFactory class
    provides a means of making non-QObject types properly accessible
    from Qt Script.

    The way QSWrapperFactory achieves this is that when a non-QObject pointer
    is returned the Qt Script interpreter tries to find a wrapper for
    that type. A wrapper is a QObject which can wrap the non-QObject
    type, and which makes the non-QObject type's slots, properties,
    etc. available to Qt Script.

    In some cases even a QObject might need to be wrapped. For
    example, we might want to use a QObject subclass's functions which
    are not declared as slots in Qt Script. Qt Script only makes the
    slots, signals and properties of QObjects available. With
    QSWrapperFactory it is possible to define a QObject which extends another
    QObject with additional slots, properties and signals.

    To make use of this mechanism you wrap the classes you want to
    make available or want to extend (see the example below). You then
    create a QSWrapperFactory subclass: this is a wrapper factory. You
    register your wrapper factory (or factories) with the Qt Script
    interpreter. When the interpreter needs an instance of a class it
    checks the registered wrapper factories to see if the class has a
    suitable wrapper.

    Reimplement classes() to publish the types this instance of
    QSWrapperFactory can wrap. Subclass create(), to create a wrapper for a
    certain type. Finally call QSWrapperFactory::addFactory() to make the
    instance of the wrapper known to the interpreter.

    Below is an example of how to make a non-QObject C++ type known to
    Qt Script. We create a wrapper for a class called Process that
    provides a function called exec(). We then create a wrapper
    factory which we'll register with the interpreter. You can wrap as
    many classes as you like and make them all available through a
    single wrapper factory (although you can use as many wrapper
    factories as you like).

    \code
    class ProcessWrapper : public QObject
    {
	Q_OBJECT
    public:
	ProcessWrapper( Process *p ) : proc( p ) {}
    public slots:
	void exec( const QString &args ) { proc->exec( args ); }
    private:
	Process *proc;
    };

    class WrapperFactory : public QSWrapperFactory
    {
    public:
	WrapperFactory() {}
	QObject *create( const QString &className, void *ptr ) {
	    if ( className == "Process" )
		return ProcessWrapper( (Process*)ptr );
	    return 0;
	}
	QStringList classes() const { return QStringList( "Process" ); }
    };
    \endcode

    Somewhere in your code (before executing any QSA related
    functionality) you must call addFactory() to make your new wrapper
    factory available.

    \code
    QSWrapperFactory::addFactory( new WrapperFactory );
    \endcode

    Now, whenever Qt Script comes across a Process pointer, it will
    look through its wrapper factories to find one that provides a
    wrapper for the Process class and wrap it (e.g. with
    ProcessWrapper). So the script writer will now be able to use all
    the slots, properties and signals that ProcessWrapper provides.

    To \e extend a QObject C++ type, you do exactly the same: i.e.
    wrap the class in a class that exposes the required functionality,
    put the wrapper in a wrapper factory, and register the wrapper
    factory with the interpreter.
*/

/*!
    \fn QObject *QSWrapperFactory::create( const QString &className, void *ptr )

    This function is called by the Qt Script interpreter to request a
    wrapper for the type \a className. \a ptr is a pointer to the
    instance of the type \a className. The \a ptr will be passed to
    its related wrapper function and an instance of the wrapper will
    be returned.

    Reimplement this function to make your wrappers available from
    your wrapper factory.

    If \a ptr is invalid or any other invalid operation occurs, you
    can use throwError() to issue a Qt Script error.
*/

/*!
    \fn QStringList QSWrapperFactory::classes() const

    This function is called by the Qt Script interpreter to find out
    which types this QSWrapperFactory can provide wrappers for.

    Reimplement this function to return the type names this
    QSWrapperFactory can handle.
*/

/*!
    This constructor does nothing.
*/

QSWrapperFactory::QSWrapperFactory()
{
    if ( !QSInterfaceFactory::factory )
	QSInterfaceFactory::factory = new QSInterfaceFactory;
}

/*!
    Registers the QSWrapperFactory \a f , with the Qt Script
    interpreter.
*/

void QSWrapperFactory::addFactory( QSWrapperFactory *f )
{
    QSInterfaceFactory::factory->addWrapper( f );
}

extern void qsa_throw_error( const QString &message ); // in quickinterpreter.cpp

/*!
    Informs the interpreter than an error occured. The error is
    treated like a normal Qt Script error. The error message is passed
    in \a message.
*/

void QSWrapperFactory::throwError( const QString &message )
{
    qsa_throw_error( message );
}
