/****************************************************************************
** $Id: qsinterpreter.cpp  beta1   edited Dec 17 00:50 $
**
** Implementation of the QSInterpreter class.
**
** 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 "qsinterpreter.h"
#include "qsa.h"

class QSInterpreterPrivate
{
public:
};

/*!
  \class QSInterpreter qsinterpreter.h

  \brief The QSInterpreter class provides the public API for Qt Script
  for Applications script engine.

  This class (implemented in \c libqsa) provides the functionality
  required to make Qt/C++ applications scriptable with Qt Script.

  For convience reasons, a single instance of the QSInterpreter class
  exists in an application; it is available as
  QSInterpreter::defaultInterpreter().

  Use addObject() to make application objects available to the
  interpreter for use by scripts. Such objects can be removed from the
  interpreter's view with removeObject().

  A global function can be executed using call(). Any string
  containing valid Qt Script code can be executed using evaluate().
  These two functions do not require a project to be open, but most
  other functions only work if there is a current project. Even if you
  don't use the QSA Developer, it is suggested to use a scripting
  project, only for very simple cases, where nothing more than
  evaluating a simple piece of code is needed, it makes sense to work
  without a project.

  If an error occurs, e.g. during the execution of a script, the
  error() signal is emitted. The error behavior depends on the
  errorMode() which is set with setErrorMode().

  The list of functions available in a particular class is available
  from functionsOf(), and the list of global functions is returned by
  globalFunctions(). To introspect variables and classes in a context,
  use classesOf() and variablesOf().

  \omit
  The Qt Script package paths can be modified and retrieved using
  addPackagePath(), removePackagePath() and packagePaths(). These
  paths are used by Qt Script to locate packages which can be imported
  using the \c import statement.
  \endomit

  See the \link qsa.book Manual\endlink for more explanation and
  examples.

*/

/*!
  Constructs a QSInterpreter.

  Currently, only one instance of the class QSInterpreter may exist at
  any one time. You can access this instance with
  QSInterpreter::defaultInterpreter().
*/

QSInterpreter::QSInterpreter()
    : em( AskForDebug )
{
    if ( QtApplicationScript::selfPtr && QtApplicationScript::selfPtr->qsip )
	qFatal( "Multiple QSInterpreter instances are not supported, yet.\n"
		"Use QSInterpreter::defaultInterpreter()." );
    qas = QtApplicationScript::self();
    QtApplicationScript::selfPtr->qsip = this;
    d = new QSInterpreterPrivate;

    // ### temp kludge
    connect( qas, SIGNAL( error( const QString &, const QString &, int ) ),
	     this, SIGNAL(  error( const QString &, const QString &, int ) ) );
}

/*! Destructor
  \internal
*/

QSInterpreter::~QSInterpreter()
{
    if ( QtApplicationScript::selfPtr )
	QtApplicationScript::selfPtr->qsip = 0;
    delete d;
}

/*!
  Returns the application-wide default interpreter.

  (This function will automatically create the interpreter if it
  doesn't already exist.)
 */

QSInterpreter* QSInterpreter::defaultInterpreter()
{
    return QtApplicationScript::self()->interpreter();
}

/*! \property QSInterpreter::errorMode
  \brief what should happen when an error occurs

*/

/*! \enum QSInterpreter::ErrorMode

  The ErrorMode describes what should happen when an error occurs
  while parsing or executing script code.

  \value Notify Notifies the user that an error occurred via a message
  box.

  \value AskForDebug Notifies the user that an error occurred via a
  message box and offers them the option of opening QSA Developer to
  debug the problem. QSA Developer can be only opened if a scripting
  project is open.<sup>*</sup>

  \value Debug Opens QSA Developer to debug the problem. QSA Developer
  can be only opened if a scripting project is open.<sup>*</sup>

  \value Nothing Nothing happens.

  <sup>*</sup> If there is no project open, QSA Developer can and will
  not be invoked, so you will need to handle the error() signal
  yourself or only get a notification message box, if the errorMode()
  is something else than Nothing.
*/

void QSInterpreter::setErrorMode( ErrorMode m )
{ qas->setErrorMode( (QtApplicationScript::ErrorMode)m); }

QSInterpreter::ErrorMode QSInterpreter::errorMode() const
{ return (ErrorMode)qas->errorMode(); }

/*! \fn void QSInterpreter::error( const QString &message,
  const QString &file, int lineNumber )

  This signal is emitted if an error occurs when running or parsing a
  script. \a message contains the error message from the interpreter,
  \a file the filename (if known) where the error occured, and \a
  lineNumber the line number at which the error occured..
*/

/*!
  Executes the string of Qt Script in \a code and returns any value
  produced by that \a code.

  This function executes the code passed in as \a code. The code can
  use and reference code (functions, classes, variables, etc.) which
  have been passed to this function previously or which are defined in
  the current project. Also application objects, which have been added
  via addObject() can be accessed.

  If \a context is 0 (default), the code is executed as global
  code. If a \a context is given, the code is executed in the context
  of that object.

  The functions openDeveloper() and closeDeveloper() clear the
  interpreter and re-evaluate the current project, meaning the code
  which has been passed previously into evaluate gets lost when
  calling one of these functions.

*/

QVariant QSInterpreter::evaluate( const QString &code, QObject *context )
{
    return qas->evaluate( code, context );
}

/*!
  Calls the function \a function with the given \a arguments. The
  arguments are converted into Qt Script datatypes first.

  Functions which were passed to evaluate() in previous calls or which
  are defined in the current project, can be called from this
  function.

  If \a context is 0 (default), the function is called in the global
  scope. If a \a context is given, the function is called in the scope
  of that object.

  The functions openDeveloper() and closeDeveloper() clear the
  interpreter and re-evaluate the current project, meaning the code
  which has been passed previously into evaluate() gets lost when
  calling one of these functions.

*/

QVariant QSInterpreter::call( const QString &function,
				    const QValueList<QVariant> &arguments,
				    QObject *context )
{
    return qas->call( function, arguments, context );
}

/*!  Checks if the script code \a code is free of syntax errors or
  not. Returns TRUE if the code is free of syntax errors, otherwise
  FALSE.
*/

bool QSInterpreter::checkSyntax( const QString &code )
{
    return qas->checkSyntax( code );
}

/*! Returns the current execution context of the interpreter. This is
  either a QObject pointer or 0.
*/

QObject *QSInterpreter::currentContext() const
{
    return qas->currentContext();
}

/*! Returns the current project of the interpreter or 0 if there is
  no project.
*/

QSProject *QSInterpreter::currentProject() const
{
    return qas->currentProject();
}

/*!

  Makes the QObject \a o available to the scripting engine. All child
  objects of \a o are made available too.

  If no object in the parent hierarchy of \a o has been added via
  addObject() yet, \a o will be made available as a toplevel object to
  the programmer and will be accessible via \c Application.object_name
  (where \c object_name is the value of \e o's QObject::name()
  property).

  If an object in the parent hierarchy of \a o has been made available
  via addObject() already, \a o will not be made available as a
  toplevel object. It is accessible then through \c
  parent1.parent2.object_name in the scripting language, given that \c
  parent1 has been made available via addObject() previously. The
  reason to make an object available like this, even though it is not
  made available as a toplevel object, is so that code can be added in
  in the context of that object. See setObjectSource().

  \warning Every object passed to this function must have a name.
*/

void QSInterpreter::addObject( QObject *o )
{
    qas->addObject( o );
}

/*! Removes the QObject \a o from the list of available objects for
  scripting.

  \sa clearObjects()
*/

void QSInterpreter::removeObject( QObject *o )
{
    qas->removeObject( o );
}

/*!
  Returns the list of available objects for scripting.
*/

const QObjectList* QSInterpreter::objects() const
{
    return qas->objects();
}

/*! Removes all application objects from the list of available
  objects. Note that this deosn't delete the application objects!

  \sa removeObject()
*/

void QSInterpreter::clearObjects()
{
    qas->clearObjects();
}

/*! Clears the interpreter and closes the currently opened Qt Script
  for Applications project, if one is open.

  This function does not clear the application objects. Use
  clearObjects() to do that.
*/

void QSInterpreter::clear()
{
    qas->clear();
}

/*! Returns the code of the object \a object */

QString QSInterpreter::objectSource( QObject *object ) const
{
    return qas->objectSource( object );
}

/*! Adds the script code \a code in the context of \a object. \a
  object must have been available to the scripting language via
  addObject() before.

  If there has been set code already for that object \a object, \a
  code is appended to this code if \a append is TRUE, otherwise the
  currently set code is replaced with \a code.
*/

void QSInterpreter::setObjectSource( QObject *object, const QString &code,
				     bool append )
{
    qas->setObjectSource( object, code, append );
}


/*! Adds the Qt Script function \a qtscriptFunction in the context of
  \a receiver as signal handler for the C++ signal \a signal of the
  object \a sender.

  Example:
  \code
  QSInterpreter::defaultInterpreter()->addSignalHandler( Form1.okButton, SIGNAL( clicked() ), document, "startCalculation" );
  \endcode

  \sa removeSignalHandler()
*/

void QSInterpreter::addSignalHandler( QObject *sender, const char *signal,
				      QObject *receiver,
				      const char *qtscriptFunction )
{
    qas->addSignalHandler( sender, signal, receiver, qtscriptFunction );
}

/*! Adds the Qt Script function \a qtscriptFunction (fully qualified)
  as signal handler for the C++ signal \a signal of the object \a
  sender.

  Example:
  \code
  QSInterpreter::defaultInterpreter()->addSignalHandler( Form1.okButton, SIGNAL( clicked() ), "classA.obj.calculate" );
  \endcode

  \sa removeSignalHandler()
*/

void QSInterpreter::addSignalHandler( QObject *sender, const char *signal,
				      const char *qtscriptFunction )
{
    qas->addSignalHandler( sender, signal, qtscriptFunction );
}

/*! Removes the connection between the signal \a signal of the object
  \a sender and the the signal handler \a qtscriptFunction in the
  context \a receiver.

  \sa addSignalHandler()
*/

void QSInterpreter::removeSignalHandler( QObject *sender, const char *signal,
					 QObject *receiver,
					 const char *qtscriptFunction )
{
    qas->removeSignalHandler( sender, signal, receiver, qtscriptFunction );
}

/*! Removes the connection between the signal \a signal of the object
  \a sender and the the fully qualified signal handler \a
  qtscriptFunction.

  \sa addSignalHandler()
*/

void QSInterpreter::removeSignalHandler( QObject *sender, const char *signal,
					       const char *qtscriptFunction )
{
    qas->removeSignalHandler( sender, signal, qtscriptFunction );
}

/*!
  If a project is open, then all the names of all the global functions
  in that project are returned. If no project is open, then all the
  names of all the global functions created with evaluate() are
  returned.

 If \a includeSignature is FALSE (the default), no signature is
 appended to the function name. If \a includeSignature is TRUE then
 each name returned will be of the form:
 \code
 functionName( typeOfArg1, typeOfArg2, ... )
 \endcode

 \sa functionsOf(), classes(), classesOf(), variablesOf()
*/

QStringList QSInterpreter::globalFunctions( bool includeSignature ) const
{
    return functionsOf( QString::null, includeSignature );
}

/*!  Returns all script functions in the context \a context (this can
  be e.g. a class or form). If \a context is empty, the functions of
  the global context (global functions) are returned.

  \a context can be fully qualified.

  If \a includeSignature is FALSE (the default), no signature is
  appended to the function name. If \a includeSignature is TRUE then
  each name returned will be of the form:
  \code
  functionName( typeOfArg1, typeOfArg2, ... )
  \endcode

  \sa globalFunctions(), classes(), classesOf(), variablesOf()
*/

QStringList QSInterpreter::functionsOf( const QString &context,
					bool includeSignature ) const
{
    return qas->functionsOf( context, includeSignature );
}

/*! Returns all script functions which have been defined in the
  context \a context.

  If \a includeSignature is FALSE (the default), no signature is
  appended to the function name. If \a includeSignature is TRUE then
  each name returned will be of the form:
  \code
  functionName( typeOfArg1, typeOfArg2, ... )
  \endcode

  \sa globalFunctions(), classes(), classesOf(), variablesOf()
*/

QStringList QSInterpreter::functionsOf( QObject *context,
					bool includeSignature ) const
{
    return qas->functionsOf( context, includeSignature );
}

/*!
  Returns all currently declared classes.

  \sa functionsOf(), classesOf(), variablesOf()
*/

QStringList QSInterpreter::classes() const
{
    return qas->classes();
}

/*! Returns all currently declared classes in the fully qualified
  context \a context

  \sa functionsOf(), classes(), globalClasses(), variablesOf()
*/

QStringList QSInterpreter::classesOf( const QString &context ) const
{
    return qas->classesOf( context );
}

/*! Returns all currently declared classes in the context \a context

  \sa functionsOf(), classes(), globalClasses(), variablesOf()
*/

QStringList QSInterpreter::classesOf( QObject *context ) const
{
    return qas->classesOf( context );
}

/*! Returns all currently declared classes in the global context

  \sa functionsOf(), classes(), classesOf(), variablesOf()
*/

QStringList QSInterpreter::globalClasses() const
{
    return classesOf( QString::null );
}

/*! Returns all currently declared variables in the fully qualified
  context \a context

  \sa functionsOf(), classes(), classesOf(), globalFunctions()
*/

QStringList QSInterpreter::variablesOf( const QString &context ) const
{
    return qas->variablesOf( context );
}

/*! Returns all currently declared variables in the contenxt \a context

  \sa functionsOf(), classes(), classesOf(), globalFunctions()
*/

QStringList QSInterpreter::variablesOf( QObject *context ) const
{
    return qas->variablesOf( context );
}

/*! Returns all currently declared variables in the global context

  \sa functionsOf(), classes(), classesOf(), variablesOf()
*/

QStringList QSInterpreter::globalVariables() const
{
    return qas->globalVariables();
}
