1
0
mirror of https://github.com/thp/pyotherside.git synced 2025-01-17 23:22:53 +08:00

Add API documentation using Doxygen

This commit is contained in:
Thomas Perl 2013-08-08 17:55:38 +02:00
parent 0c8bd9e07a
commit ad62b4dc2b
5 changed files with 2098 additions and 45 deletions

1869
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@ -17,12 +17,12 @@
**/
#include "pyotherside_plugin.h"
#include "qpython.h"
#include "qpython_priv.h"
static void
pyotherside_atexit()
{
QPython::closing();
QPythonPriv::closing();
}
PyOtherSideExtensionPlugin::PyOtherSideExtensionPlugin()

View File

@ -26,6 +26,25 @@
#include <QJSEngine>
class QPythonWorker : public QObject {
Q_OBJECT
public:
QPythonWorker(QPython *qpython);
~QPythonWorker();
public slots:
void process(QString func, QVariant args, QJSValue callback);
void import(QString func, QJSValue callback);
signals:
void finished(QVariant result, QJSValue callback);
void imported(bool result, QJSValue callback);
private:
QPython *qpython;
};
QPythonWorker::QPythonWorker(QPython *qpython)
: QObject()
, qpython(qpython)
@ -55,7 +74,7 @@ QPython::priv = NULL;
QPython::QPython(QObject *parent)
: QObject(parent)
, worker(this)
, worker(new QPythonWorker(this))
, thread()
, handlers()
{
@ -63,20 +82,20 @@ QPython::QPython(QObject *parent)
priv = new QPythonPriv;
}
worker.moveToThread(&thread);
worker->moveToThread(&thread);
QObject::connect(priv, SIGNAL(receive(QVariant)),
this, SLOT(receive(QVariant)));
QObject::connect(this, SIGNAL(process(QString,QVariant,QJSValue)),
&worker, SLOT(process(QString,QVariant,QJSValue)));
QObject::connect(&worker, SIGNAL(finished(QVariant,QJSValue)),
this, SLOT(finished(QVariant,QJSValue)));
worker, SLOT(process(QString,QVariant,QJSValue)));
QObject::connect(worker, SIGNAL(finished(QVariant,QJSValue)),
this, SLOT(finished(QVariant,QJSValue)));
QObject::connect(this, SIGNAL(import(QString,QJSValue)),
&worker, SLOT(import(QString,QJSValue)));
QObject::connect(&worker, SIGNAL(imported(bool,QJSValue)),
this, SLOT(imported(bool,QJSValue)));
worker, SLOT(import(QString,QJSValue)));
QObject::connect(worker, SIGNAL(imported(bool,QJSValue)),
this, SLOT(imported(bool,QJSValue)));
thread.start();
}
@ -85,6 +104,8 @@ QPython::~QPython()
{
thread.quit();
thread.wait();
delete worker;
}
void
@ -242,12 +263,3 @@ QPython::imported(bool result, QJSValue callback)
callback.call(args);
}
}
void
QPython::closing()
{
priv->enter();
priv->closing();
priv->leave();
}

View File

@ -30,68 +30,238 @@
class QPython;
class QPythonPriv;
class QPythonWorker : public QObject {
Q_OBJECT
public:
QPythonWorker(QPython *qpython);
~QPythonWorker();
public slots:
void process(QString func, QVariant args, QJSValue callback);
void import(QString func, QJSValue callback);
signals:
void finished(QVariant result, QJSValue callback);
void imported(bool result, QJSValue callback);
private:
QPython *qpython;
};
class QPythonWorker;
class QPython : public QObject {
Q_OBJECT
public:
/**
* \brief Create a new Python instance
*
* A new Python instance can be created in QML as follows:
*
* \code
* import io.thp.pyotherside 1.0
*
* Python {
* id: py
* }
* \endcode
*
* \arg parent The parent QObject
**/
QPython(QObject *parent=NULL);
virtual ~QPython();
/**
* \brief Add a local filesystem path to Python's sys.path.
*
* The import path will be added synchronously. After the call
* returns, the new import path will already be in effect.
*
* \arg path Directory that will be added to the search path
**/
Q_INVOKABLE void
addImportPath(QString path);
/**
* \brief Add a handler for events sent with \c pyotherside.send()
*
* The provided \a callback will be called whenever the first argument
* to \c pyotherside.send() matches the \a event argument.
*
* For example, when the Python code contains a call like this:
*
* \code
* import pyotherside
*
* pyotherside.call('new-entries', 100, 123)
* \endcode
*
* The event can be captured in QML like this:
*
* \code
* Python {
* id: py
*
* Component.onCompleted: {
* py.setHandler('new-entries', function(first, last) {
* console.log('New entries from ' + first + ' to ' + last);
* });
* }
* }
* \endcode
*
* All events for which no handler was set will be sent to the
* received() signal.
*
* If a handler for that specific \a event already exist, the
* new \a callback will replace the old one.
*
* \arg event The event name (first argument to pyotherside.send())
* \arg callback The JS callback to be called when the event occurs
**/
Q_INVOKABLE void
setHandler(QString event, QJSValue callback);
/**
* \brief Evaluate a Python expression synchronously
*
* Evaluate the string \a expr as Python expression and return the
* result as Qt data type. The evaluation happens synchronously.
*
* \code
* Python {
* Component.onCompleted: {
* console.log('Squares: ' + evaluate('[x for x in range(10)]'));
* }
* }
* \endcode
*
* \arg expr Python expression to be evaluated
* \result The result of the expression as Qt data type
**/
Q_INVOKABLE QVariant
evaluate(QString expr);
/* Need a callback, as the module can only be used after import */
/**
* \brief Asynchronously import a Python module
*
* Imports a Python module by name asynchronously. The function
* will return immediately. If the module is successfully imported,
* the supplied \a callback will be called. Only then will the
* imported module be available:
*
* \code
* Python {
* Component.onCompleted: {
* importModule('os', function() {
* // You can use the "os" module here
* });
* }
* }
* \endcode
*
* If an error occurs while trying to import, the signal error()
* will be emitted with detailed information about the error.
*
* \arg name The name of the Python module to import
* \arg callback The JS callback to be called when the module is
* successfully imported
**/
Q_INVOKABLE void
importModule(QString name, QJSValue callback);
/**
* \brief Synchronously import a Python module
*
* Imports a Python module by name synchronously. This function
* will block until the module is imported and available. In
* general, you should use importModule() instead of this function
* to avoid blocking the QML UI thread. Example use:
*
* \code
* Python {
* Component.onCompleted: {
* var success = importModule_sync('os');
* if (success) {
* // You can use the "os" module here
* }
* }
* }
* \endcode
*
* \arg name The name of the Python module to import
* \result \c true if the import was successful, \c false otherwise
**/
Q_INVOKABLE bool
importModule_sync(QString name);
/**
* \brief Asynchronously call a Python function
*
* Call a Python function asynchronously and call back into QML
* when the result is available:
*
* \code
* Python {
* Component.onCompleted: {
* importModule('os', function() {
* call('os.getcwd', [], function (result) {
* console.log('Working directory: ' + result);
* call('os.chdir', ['/'], function (result) {
* console.log('Working directory changed.');
* }););
* });
* });
* }
* }
* \endcode
*
* \arg func The Python function to call
* \arg args A list of arguments, or \c [] for no arguments
* \arg callback A callback that receives the function call result
**/
Q_INVOKABLE void
call(QString func,
QVariant args=QVariantList(),
QJSValue callback=QJSValue());
/**
* \brief Synchronously call a Python function
*
* This is the synchronous variant of call(). In general, you should
* use call() instead of this function to avoid blocking the QML UI
* thread. Example usage:
*
* \code
* Python {
* Component.onCompleted: {
* importModule_sync('os');
* var cwd = call_sync('os.getcwd', []);
* console.log('Working directory: ' + cwd);
* call_sync('os.chdir', ['/']);
* console.log('Working directory changed.');
* }
* }
* \endcode
*
* \arg func The Python function to call
* \arg args A list of arguments, or \c [] for no arguments
* \result The return value of the Python call as Qt data type
**/
Q_INVOKABLE QVariant
call_sync(QString func, QVariant args=QVariantList());
static void
closing();
signals:
/**
* \brief Default event handler for \c pyotherside.send()
*
* This signal will be emitted for all events from Python for
* which no specific handler (see setHandler()) is configured.
*
* \arg data The argument list of \c pyotherside.send()
**/
void received(QVariant data);
/**
* \brief Error handler for errors from Python
*
* This signal will be emitted when an error happens in the
* Python interpreter that isn't caught. For example, errors
* in evaluate(), importModule() and call() will be reported
* with this signal.
*
* \arg traceback A string describing the error
**/
void error(QString traceback);
private slots:
void process(QString func, QVariant args, QJSValue callback);
void import(QString name, QJSValue callback);
private slots:
void receive(QVariant data);
void finished(QVariant result, QJSValue callback);
@ -100,7 +270,7 @@ class QPython : public QObject {
private:
static QPythonPriv *priv;
QPythonWorker worker;
QPythonWorker *worker;
QThread thread;
QMap<QString,QJSValue> handlers;
};

View File

@ -192,6 +192,7 @@ QPythonPriv::eval(QString expr)
void
QPythonPriv::closing()
{
enter();
if (priv->atexit_callback != NULL) {
PyObject *args = PyTuple_New(0);
PyObject *result = PyObject_Call(priv->atexit_callback, args, NULL);
@ -201,5 +202,6 @@ QPythonPriv::closing()
Py_DECREF(priv->atexit_callback);
priv->atexit_callback = NULL;
}
leave();
}