PythonQt.h
711 lines
| 29.7 KiB
| text/x-c
|
CLexer
/ src / PythonQt.h
ezust
|
r0 | #ifndef _PYTHONQT_H | ||
#define _PYTHONQT_H | ||||
/* | ||||
* | ||||
florianlink
|
r133 | * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved. | ||
ezust
|
r0 | * | ||
* This library is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU Lesser General Public | ||||
* License as published by the Free Software Foundation; either | ||||
* version 2.1 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 | ||||
* Lesser General Public License for more details. | ||||
* | ||||
* Further, this software is distributed without any warranty that it is | ||||
* free of the rightful claim of any third person regarding infringement | ||||
* or the like. Any license provided herein, whether implied or | ||||
* otherwise, applies only to this software file. Patent licenses, if | ||||
* any, provided herein do not apply to combinations of this program with | ||||
* other software, or any other product whatsoever. | ||||
* | ||||
* You should have received a copy of the GNU Lesser General Public | ||||
* License along with this library; if not, write to the Free Software | ||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
* | ||||
florianlink
|
r133 | * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29, | ||
ezust
|
r0 | * 28359 Bremen, Germany or: | ||
* | ||||
* http://www.mevis.de | ||||
* | ||||
*/ | ||||
//---------------------------------------------------------------------------------- | ||||
/*! | ||||
// \file PythonQt.h | ||||
// \author Florian Link | ||||
// \author Last changed by $Author: florian $ | ||||
// \date 2006-05 | ||||
*/ | ||||
//---------------------------------------------------------------------------------- | ||||
#include "PythonQtSystem.h" | ||||
florianlink
|
r16 | #include "PythonQtInstanceWrapper.h" | ||
#include "PythonQtClassWrapper.h" | ||||
ezust
|
r0 | #include "PythonQtSlot.h" | ||
#include "PythonQtObjectPtr.h" | ||||
florianlink
|
r161 | #include "PythonQtStdIn.h" | ||
ezust
|
r0 | #include <QObject> | ||
#include <QVariant> | ||||
#include <QList> | ||||
#include <QHash> | ||||
#include <QByteArray> | ||||
#include <QStringList> | ||||
#include <QtDebug> | ||||
#include <iostream> | ||||
class PythonQtClassInfo; | ||||
class PythonQtPrivate; | ||||
class PythonQtMethodInfo; | ||||
class PythonQtSignalReceiver; | ||||
class PythonQtImportFileInterface; | ||||
class PythonQtCppWrapperFactory; | ||||
florianlink
|
r167 | class PythonQtForeignWrapperFactory; | ||
florianlink
|
r8 | class PythonQtQFileImporter; | ||
ezust
|
r0 | |||
florianlink
|
r26 | typedef void PythonQtQObjectWrappedCB(QObject* object); | ||
typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object); | ||||
florianlink
|
r163 | typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, const char **class_name); | ||
florianlink
|
r4 | |||
florianlink
|
r24 | typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper); | ||
florianlink
|
r161 | template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) { | ||
(reinterpret_cast<T*>(object))->_wrapper = wrapper; | ||||
} | ||||
florianlink
|
r24 | |||
//! returns the offset that needs to be added to upcast an object of type T1 to T2 | ||||
template<class T1, class T2> int PythonQtUpcastingOffset() { | ||||
florianlink
|
r161 | return ((reinterpret_cast<char*>(static_cast<T2*>(reinterpret_cast<T1*>(0x100)))) | ||
- (reinterpret_cast<char*>(reinterpret_cast<T1*>(0x100)))); | ||||
florianlink
|
r24 | } | ||
//! callback to create a QObject lazily | ||||
florianlink
|
r10 | typedef QObject* PythonQtQObjectCreatorFunctionCB(); | ||
//! helper template to create a derived QObject class | ||||
template<class T> QObject* PythonQtCreateObject() { return new T(); }; | ||||
florianlink
|
r144 | //! The main interface to the Python Qt binding, realized as a singleton | ||
/*! | ||||
Use PythonQt::init() to initialize the singleton and PythonQt::self() to access it. | ||||
While there can be only one PythonQt instance, you can have any number of Python context to do scripting in. | ||||
One possibility is to use createModuleFromFile(), createModuleFromScript() or createUniqueModule() to get a context | ||||
that is separated from the other contexts. Alternatively you can use Python dicts as contexts for script evaluation, | ||||
but you will need to populate the dict with the __builtins__ instance to have all Pythons available when running | ||||
code in the scope of a dict. | ||||
*/ | ||||
ezust
|
r0 | class PYTHONQT_EXPORT PythonQt : public QObject { | ||
Q_OBJECT | ||||
public: | ||||
florianlink
|
r144 | |||
//! flags that can be passed to PythonQt::init() | ||||
ezust
|
r0 | enum InitFlags { | ||
RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals | ||||
IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module | ||||
florianlink
|
r144 | ExternalHelp = 4, //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal | ||
PythonAlreadyInitialized = 8 //!<< sets that PythonQt should not can PyInitialize, since it is already done | ||||
ezust
|
r0 | }; | ||
florianlink
|
r119 | //! flags that tell PythonQt which operators to expect on the registered type | ||
enum TypeSlots { | ||||
Type_Add = 1, | ||||
Type_Subtract = 1 << 1, | ||||
Type_Multiply = 1 << 2, | ||||
Type_Divide = 1 << 3, | ||||
Type_Mod = 1 << 4, | ||||
Type_And = 1 << 5, | ||||
Type_Or = 1 << 6, | ||||
Type_Xor = 1 << 7, | ||||
Type_LShift = 1 << 8, | ||||
Type_RShift = 1 << 9, | ||||
Type_InplaceAdd = 1 << 10, | ||||
Type_InplaceSubtract = 1 << 11, | ||||
Type_InplaceMultiply = 1 << 12, | ||||
Type_InplaceDivide = 1 << 13, | ||||
Type_InplaceMod = 1 << 14, | ||||
Type_InplaceAnd = 1 << 15, | ||||
Type_InplaceOr = 1 << 16, | ||||
Type_InplaceXor = 1 << 17, | ||||
Type_InplaceLShift = 1 << 18, | ||||
Type_InplaceRShift = 1 << 19, | ||||
// Not yet needed/nicely mappable/generated... | ||||
//Type_Positive = 1 << 29, | ||||
//Type_Negative = 1 << 29, | ||||
//Type_Abs = 1 << 29, | ||||
//Type_Hash = 1 << 29, | ||||
Type_Invert = 1 << 29, | ||||
Type_RichCompare = 1 << 30, | ||||
Type_NonZero = 1 << 31, | ||||
}; | ||||
florianlink
|
r157 | //! enum for profiling callback | ||
enum ProfilingCallbackState { | ||||
Enter = 1, | ||||
Leave = 2 | ||||
}; | ||||
//! callback for profiling. className and methodName are only passed when state == Enter, otherwise | ||||
//! they are NULL. | ||||
typedef void ProfilingCB(ProfilingCallbackState state, const char* className, const char* methodName); | ||||
florianlink
|
r144 | //--------------------------------------------------------------------------- | ||
//! \name Singleton Initialization | ||||
//@{ | ||||
florianlink
|
r157 | |||
florianlink
|
r144 | //! initialize the python qt binding (flags are a or combination of PythonQt::InitFlags), if \c pythonQtModuleName is given | ||
florianlink
|
r109 | //! it defines the name of the python module that PythonQt will add, otherwise "PythonQt" is used. | ||
//! This can be used to e.g. pass in PySide or PyQt4 to make it more compatible. | ||||
static void init(int flags = IgnoreSiteModule | RedirectStdOut, const QByteArray& pythonQtModuleName = QByteArray()); | ||||
ezust
|
r0 | |||
florianlink
|
r144 | //! cleanup of the singleton | ||
ezust
|
r0 | static void cleanup(); | ||
//! get the singleton instance | ||||
florianlink
|
r161 | static PythonQt* self(); | ||
ezust
|
r0 | |||
florianlink
|
r144 | //@} | ||
florianlink
|
r157 | |||
ezust
|
r0 | //! defines the object types for introspection | ||
enum ObjectType { | ||||
Class, | ||||
Function, | ||||
Variable, | ||||
Module, | ||||
Anything, | ||||
CallOverloads | ||||
}; | ||||
florianlink
|
r161 | |||
//--------------------------------------------------------------------------- | ||||
//! \name Standard input handling | ||||
//@{ | ||||
//! Overwrite default handling of stdin using a custom callback. It internally backup | ||||
//! the original 'sys.stdin' into 'sys.pythonqt_original_stdin' | ||||
void setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData = 0); | ||||
//! Enable or disable stdin custom callback. It resets 'sys.stdin' using either 'sys.pythonqt_stdin' | ||||
//! or 'sys.pythonqt_original_stdin' | ||||
void setRedirectStdInCallbackEnabled(bool enabled); | ||||
//@} | ||||
florianlink
|
r144 | //--------------------------------------------------------------------------- | ||
//! \name Modules | ||||
//@{ | ||||
//! get the __main__ module of python | ||||
PythonQtObjectPtr getMainModule(); | ||||
//! import the given module and return a reference to it (useful to import e.g. "sys" and call something on it) | ||||
//! If a module is already imported, this returns the already imported module. | ||||
PythonQtObjectPtr importModule(const QString& name); | ||||
//! creates the new module \c name and evaluates the given file in the context of that module | ||||
//! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code | ||||
//! to a module later on. | ||||
//! The user needs to make sure that the \c name is unique in the python module dictionary. | ||||
PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename); | ||||
florianlink
|
r157 | |||
florianlink
|
r144 | //! creates the new module \c name and evaluates the given script in the context of that module. | ||
//! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code | ||||
//! to a module later on. | ||||
//! The user needs to make sure that the \c name is unique in the python module dictionary. | ||||
PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString()); | ||||
florianlink
|
r157 | |||
florianlink
|
r144 | //! create a uniquely named module, you can use evalFile or evalScript to populate the module with | ||
//! script code | ||||
PythonQtObjectPtr createUniqueModule(); | ||||
//@} | ||||
//--------------------------------------------------------------------------- | ||||
//! \name Importing/Paths | ||||
//@{ | ||||
ezust
|
r0 | //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path) | ||
void overwriteSysPath(const QStringList& paths); | ||||
florianlink
|
r14 | //! prepend a path to sys.path to allow importing from it | ||
void addSysPath(const QString& path); | ||||
ezust
|
r0 | //! sets the __path__ list of a module to the given list (important for local imports) | ||
void setModuleImportPath(PyObject* module, const QStringList& paths); | ||||
florianlink
|
r144 | //@} | ||
florianlink
|
r157 | |||
florianlink
|
r144 | //--------------------------------------------------------------------------- | ||
//! \name Registering Classes | ||||
//@{ | ||||
florianlink
|
r157 | |||
ezust
|
r0 | //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well) | ||
/* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject, | ||||
florianlink
|
r10 | you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */ | ||
florianlink
|
r24 | void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL); | ||
florianlink
|
r157 | |||
florianlink
|
r10 | //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants | ||
//! (ownership of wrapper is passed to PythonQt) | ||||
/*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type! | ||||
florianlink
|
r157 | |||
florianlink
|
r10 | This will add a wrapper object that is used to make calls to the given classname \c typeName. | ||
All slots that take a pointer to typeName as the first argument will be callable from Python on | ||||
a variant object that contains such a type. | ||||
*/ | ||||
florianlink
|
r24 | void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL); | ||
ezust
|
r0 | |||
//! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes | ||||
//! and it will register the classes when it first sees a pointer to such a derived class | ||||
void registerQObjectClassNames(const QStringList& names); | ||||
florianlink
|
r24 | //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance | ||
//! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that | ||||
//! type is really derived from parentType. | ||||
//! Returns false if the typeName was not yet registered. | ||||
bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0); | ||||
florianlink
|
r26 | //! add a handler for polymorphic downcasting | ||
void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb); | ||||
florianlink
|
r144 | //@} | ||
//--------------------------------------------------------------------------- | ||||
//! \name Script Parsing and Evaluation | ||||
//@{ | ||||
florianlink
|
r157 | |||
ezust
|
r0 | //! parses the given file and returns the python code object, this can then be used to call evalCode() | ||
PythonQtObjectPtr parseFile(const QString& filename); | ||||
//! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string) | ||||
//! If pycode is NULL, a python error is printed. | ||||
florianlink
|
r25 | QVariant evalCode(PyObject* object, PyObject* pycode); | ||
ezust
|
r0 | |||
//! evaluates the given script code and returns the result value | ||||
florianlink
|
r25 | QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input); | ||
ezust
|
r0 | |||
//! evaluates the given script code from file | ||||
florianlink
|
r25 | void evalFile(PyObject* object, const QString& filename); | ||
ezust
|
r0 | |||
florianlink
|
r144 | //@} | ||
florianlink
|
r4 | |||
florianlink
|
r144 | //--------------------------------------------------------------------------- | ||
//! \name Signal Handlers | ||||
//@{ | ||||
ezust
|
r0 | |||
//! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module | ||||
bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname); | ||||
//! remove a signal handler from the given \c signal of \c obj | ||||
bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname); | ||||
//! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver | ||||
bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver); | ||||
//! remove a signal handler from the given \c signal of \c obj | ||||
bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver); | ||||
//@} | ||||
florianlink
|
r144 | //--------------------------------------------------------------------------- | ||
//! \name Variable access | ||||
florianlink
|
r157 | //@{ | ||
ezust
|
r0 | |||
florianlink
|
r25 | //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable) | ||
void addObject(PyObject* object, const QString& name, QObject* qObject); | ||||
ezust
|
r0 | |||
florianlink
|
r25 | //! add the given variable to the object | ||
void addVariable(PyObject* object, const QString& name, const QVariant& v); | ||||
ezust
|
r0 | |||
//! remove the given variable | ||||
void removeVariable(PyObject* module, const QString& name); | ||||
florianlink
|
r25 | //! get the variable with the \c name of the \c object, returns an invalid QVariant on error | ||
QVariant getVariable(PyObject* object, const QString& name); | ||||
ezust
|
r0 | |||
florianlink
|
r25 | //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname | ||
QStringList introspection(PyObject* object, const QString& objectname, ObjectType type); | ||||
florianlink
|
r173 | //! read vars etc. in scope of the given \c object | ||
QStringList introspectObject(PyObject* object, ObjectType type); | ||||
//! read vars etc. in scope of the type object called \c typename. First the typename | ||||
//! of the form module.type is split into module and type. Then the module is looked up | ||||
//! in sys.modules. If the module or type is not found there, then the type is looked up in | ||||
//! the __builtin__ module. | ||||
QStringList introspectType(const QString& typeName, ObjectType type); | ||||
ezust
|
r0 | |||
//! returns the found callable object or NULL | ||||
//! @return new reference | ||||
florianlink
|
r25 | PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name); | ||
florianlink
|
r173 | |||
//! returns the return type of the method of a wrapped c++ object referenced by \c objectname | ||||
QString getReturnTypeOfWrappedMethod(PyObject* module, const QString& objectname); | ||||
//! returns the return type of the method \c methodName of a wrapped c++ type referenced by \c typeName | ||||
QString getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName); | ||||
ezust
|
r0 | //@} | ||
florianlink
|
r144 | //--------------------------------------------------------------------------- | ||
//! \name Calling Python Objects | ||||
florianlink
|
r157 | //@{ | ||
ezust
|
r0 | |||
florianlink
|
r36 | //! call the given python \c callable in the scope of object, returns the result converted to a QVariant | ||
QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList()); | ||||
//! call the given python object, returns the result converted to a QVariant | ||||
QVariant call(PyObject* callable, const QVariantList& args = QVariantList()); | ||||
ezust
|
r0 | |||
florianlink
|
r82 | //! call the given python object, returns the result as new PyObject | ||
PyObject* callAndReturnPyObject(PyObject* callable, const QVariantList& args = QVariantList()); | ||||
ezust
|
r0 | //@} | ||
florianlink
|
r144 | //--------------------------------------------------------------------------- | ||
//! \name Decorations, Constructors, Wrappers... | ||||
//@{ | ||||
ezust
|
r0 | |||
//! add an object whose slots will be used as decorator slots for | ||||
//! other QObjects or CPP classes. The slots need to follow the | ||||
//! convention that the first argument is a pointer to the wrapped object. | ||||
//! (ownership is passed to PythonQt) | ||||
/*! | ||||
Example: | ||||
A slot with the signature | ||||
\code | ||||
bool doSomething(QWidget* w, int a) | ||||
\endcode | ||||
will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot | ||||
that will be called with the concrete instance as first argument. | ||||
So in Python you can now e.g. call | ||||
\code | ||||
someWidget.doSomething(12) | ||||
\endcode | ||||
without QWidget really having this method. This allows to easily make normal methods | ||||
of Qt classes callable by forwarding them with such decorator slots | ||||
or to make CPP classes (which are not derived from QObject) callable from Python. | ||||
*/ | ||||
void addInstanceDecorators(QObject* o); | ||||
//! add an object whose slots will be used as decorator slots for | ||||
//! class objects (ownership is passed to PythonQt) | ||||
/*! | ||||
The slots need to follow the following convention: | ||||
- SomeClass* new_SomeClass(...) | ||||
- QVariant new_SomeClass(...) | ||||
- void delete_SomeClass(SomeClass*) | ||||
- ... static_SomeClass_someName(...) | ||||
This will add: | ||||
- a constructor | ||||
- a constructor which generates a QVariant | ||||
- a destructor (only useful for CPP objects) | ||||
- a static decorator slot which will be available on the MetaObject (visible in PythonQt module) | ||||
*/ | ||||
void addClassDecorators(QObject* o); | ||||
//! this will add the object both as class and instance decorator (ownership is passed to PythonQt) | ||||
void addDecorators(QObject* o); | ||||
//! add the given factory to PythonQt (ownership stays with caller) | ||||
void addWrapperFactory(PythonQtCppWrapperFactory* factory); | ||||
florianlink
|
r167 | //! add the given factory to PythonQt (ownership stays with caller) | ||
void addWrapperFactory(PythonQtForeignWrapperFactory* factory); | ||||
florianlink
|
r168 | //! remove the wrapper factory | ||
void removeWrapperFactory(PythonQtCppWrapperFactory* factory); | ||||
//! remove the wrapper factory | ||||
void removeWrapperFactory(PythonQtForeignWrapperFactory* factory); | ||||
ezust
|
r0 | //@} | ||
florianlink
|
r144 | //--------------------------------------------------------------------------- | ||
//! \name Custom Importer | ||||
//@{ | ||||
florianlink
|
r157 | |||
ezust
|
r0 | //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files) | ||
//! (this method should be called directly after initialization of init() and before calling overwriteSysPath(). | ||||
florianlink
|
r157 | //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks". | ||
florianlink
|
r8 | //! This is not reversible, so even setting setImporter(NULL) afterwards will | ||
//! keep the custom PythonQt importer with a QFile default import interface. | ||||
//! Subsequent python import calls will make use of the passed importInterface | ||||
//! which forwards all import calls to the given \c importInterface. | ||||
//! Passing NULL will install a default QFile importer. | ||||
//! (\c importInterface ownership stays with caller) | ||||
ezust
|
r0 | void setImporter(PythonQtImportFileInterface* importInterface); | ||
florianlink
|
r8 | //! this installs the default QFile importer (which effectively does a setImporter(NULL)) | ||
//! (without calling setImporter or installDefaultImporter at least once, the default python import | ||||
//! mechanism is in place) | ||||
//! the default importer allows to import files from anywhere QFile can read from, | ||||
//! including the Qt resource system using ":". Keep in mind that you need to extend | ||||
//! "sys.path" with ":" to be able to import from the Qt resources. | ||||
void installDefaultImporter() { setImporter(NULL); } | ||||
ezust
|
r0 | //! set paths that the importer should ignore | ||
void setImporterIgnorePaths(const QStringList& paths); | ||||
//! get paths that the importer should ignore | ||||
const QStringList& getImporterIgnorePaths(); | ||||
florianlink
|
r144 | //! get access to the file importer (if set) | ||
static PythonQtImportFileInterface* importInterface(); | ||||
ezust
|
r0 | //@} | ||
florianlink
|
r144 | //--------------------------------------------------------------------------- | ||
//! \name Other Stuff | ||||
//@{ | ||||
ezust
|
r0 | //! get access to internal data (should not be used on the public API, but is used by some C functions) | ||
static PythonQtPrivate* priv() { return _self->_p; } | ||||
//! handle a python error, call this when a python function fails. If no error occurred, it returns false. | ||||
//! The error is currently just output to the python stderr, future version might implement better trace printing | ||||
bool handleError(); | ||||
florianlink
|
r157 | //! clear all NotFound entries on all class infos, to ensure that | ||
//! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded | ||||
void clearNotFoundCachedMembers(); | ||||
florianlink
|
r4 | //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt | ||
void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb); | ||||
//! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt | ||||
void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb); | ||||
//! call the callback if it is set | ||||
static void qObjectNoLongerWrappedCB(QObject* o); | ||||
florianlink
|
r144 | //! called by internal help methods | ||
PyObject* helpCalled(PythonQtClassInfo* info); | ||||
florianlink
|
r157 | |||
florianlink
|
r144 | //! returns the found object or NULL | ||
//! @return new reference | ||||
PythonQtObjectPtr lookupObject(PyObject* module, const QString& name); | ||||
florianlink
|
r157 | //! sets a callback that is called before and after function calls for profiling | ||
void setProfilingCallback(ProfilingCB* cb); | ||||
florianlink
|
r144 | //@} | ||
ezust
|
r0 | signals: | ||
//! emitted when python outputs something to stdout (and redirection is turned on) | ||||
void pythonStdOut(const QString& str); | ||||
//! emitted when python outputs something to stderr (and redirection is turned on) | ||||
void pythonStdErr(const QString& str); | ||||
//! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled | ||||
void pythonHelpRequest(const QByteArray& cppClassName); | ||||
private: | ||||
florianlink
|
r109 | void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName); | ||
florianlink
|
r173 | |||
QString getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context); | ||||
PyObject* getObjectByType(const QString& typeName); | ||||
ezust
|
r0 | |||
//! callback for stdout redirection, emits pythonStdOut signal | ||||
static void stdOutRedirectCB(const QString& str); | ||||
//! callback for stderr redirection, emits pythonStdErr signal | ||||
static void stdErrRedirectCB(const QString& str); | ||||
//! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj | ||||
PythonQtSignalReceiver* getSignalReceiver(QObject* obj); | ||||
florianlink
|
r109 | PythonQt(int flags, const QByteArray& pythonQtModuleName); | ||
ezust
|
r0 | ~PythonQt(); | ||
static PythonQt* _self; | ||||
florianlink
|
r4 | static int _uniqueModuleCount; | ||
ezust
|
r0 | |||
PythonQtPrivate* _p; | ||||
}; | ||||
//! internal PythonQt details | ||||
florianlink
|
r24 | class PYTHONQT_EXPORT PythonQtPrivate : public QObject { | ||
ezust
|
r0 | |||
Q_OBJECT | ||||
public: | ||||
PythonQtPrivate(); | ||||
~PythonQtPrivate(); | ||||
florianlink
|
r10 | enum DecoratorTypes { | ||
StaticDecorator = 1, | ||||
ConstructorDecorator = 2, | ||||
DestructorDecorator = 4, | ||||
InstanceDecorator = 8, | ||||
AllDecorators = 0xffff | ||||
}; | ||||
florianlink
|
r82 | |||
//! get the suffixes that are used for shared libraries | ||||
const QStringList& sharedLibrarySuffixes() { return _sharedLibrarySuffixes; } | ||||
ezust
|
r0 | //! returns if the id is the id for PythonQtObjectPtr | ||
bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; } | ||||
florianlink
|
r18 | //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists) | ||
void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper); | ||||
ezust
|
r0 | //! remove the wrapper ptr again | ||
florianlink
|
r4 | void removeWrapperPointer(void* obj); | ||
florianlink
|
r167 | //! try to unwrap the given object to a C++ pointer using the foreign wrapper factories | ||
void* unwrapForeignWrapper(const QByteArray& classname, PyObject* obj); | ||||
florianlink
|
r24 | //! add parent class relation | ||
bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset); | ||||
florianlink
|
r26 | //! add a handler for polymorphic downcasting | ||
void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb); | ||||
florianlink
|
r157 | |||
florianlink
|
r24 | //! lookup existing classinfo and return new if not yet present | ||
PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName); | ||||
florianlink
|
r4 | //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map | ||
void removeSignalEmitter(QObject* obj); | ||||
ezust
|
r0 | |||
//! wrap the given QObject into a Python object (or return existing wrapper!) | ||||
PyObject* wrapQObject(QObject* obj); | ||||
//! wrap the given ptr into a Python object (or return existing wrapper!) if there is a known QObject of that name or a known wrapper in the factory | ||||
PyObject* wrapPtr(void* ptr, const QByteArray& name); | ||||
//! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well) | ||||
/* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject, | ||||
you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */ | ||||
florianlink
|
r119 | void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0); | ||
ezust
|
r0 | |||
florianlink
|
r10 | //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants | ||
//! (ownership of wrapper is passed to PythonQt) | ||||
/*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type! | ||||
florianlink
|
r157 | |||
florianlink
|
r10 | This will add a wrapper object that is used to make calls to the given classname \c typeName. | ||
All slots that take a pointer to typeName as the first argument will be callable from Python on | ||||
a variant object that contains such a type. | ||||
*/ | ||||
florianlink
|
r119 | void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0); | ||
florianlink
|
r157 | |||
ezust
|
r0 | //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes | ||
//! and it will register the classes when it first sees a pointer to such a derived class | ||||
void registerQObjectClassNames(const QStringList& names); | ||||
//! add a decorator object | ||||
florianlink
|
r10 | void addDecorators(QObject* o, int decoTypes); | ||
ezust
|
r0 | |||
florianlink
|
r56 | //! helper method that creates a PythonQtClassWrapper object (returns a new reference) | ||
florianlink
|
r109 | PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* module); | ||
ezust
|
r0 | |||
florianlink
|
r56 | //! create a new instance of the given enum type with given value (returns a new reference) | ||
static PyObject* createEnumValueInstance(PyObject* enumType, unsigned int enumValue); | ||||
//! helper that creates a new int derived class that represents the enum of the given name (returns a new reference) | ||||
static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject); | ||||
florianlink
|
r51 | |||
florianlink
|
r16 | //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map | ||
PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL); | ||||
ezust
|
r0 | |||
//! get the class info for a meta object (if available) | ||||
florianlink
|
r24 | PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); } | ||
ezust
|
r0 | |||
florianlink
|
r10 | //! get the class info for a meta object (if available) | ||
florianlink
|
r24 | PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); } | ||
ezust
|
r0 | |||
florianlink
|
r4 | //! creates the new module from the given pycode | ||
PythonQtObjectPtr createModule(const QString& name, PyObject* pycode); | ||||
ezust
|
r0 | |||
florianlink
|
r18 | //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again | ||
PythonQtClassInfo* currentClassInfoForClassWrapperCreation(); | ||||
//! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation | ||||
static PyObject* dummyTuple(); | ||||
florianlink
|
r67 | //! called by virtual overloads when a python return value can not be converted to the required Qt type | ||
void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result); | ||||
florianlink
|
r157 | |||
florianlink
|
r101 | //! get access to the PythonQt module | ||
PythonQtObjectPtr pythonQtModule() const { return _pythonQtModule; } | ||||
florianlink
|
r157 | //! returns the profiling callback, which may be NULL | ||
PythonQt::ProfilingCB* profilingCB() const { return _profilingCB; } | ||||
florianlink
|
r173 | |||
//! determines the signature of the given callable object (similar as pydoc) | ||||
QString getSignature(PyObject* object); | ||||
//! returns true if the object is a method descriptor (same as inspect.ismethoddescriptor() in inspect.py) | ||||
bool isMethodDescriptor(PyObject* object) const; | ||||
florianlink
|
r157 | |||
ezust
|
r0 | private: | ||
florianlink
|
r82 | //! Setup the shared library suffixes by getting them from the "imp" module. | ||
void setupSharedLibrarySuffixes(); | ||||
florianlink
|
r18 | |||
florianlink
|
r24 | //! create a new pythonqt class wrapper and place it in the pythonqt module | ||
florianlink
|
r109 | void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module = NULL); | ||
florianlink
|
r18 | |||
florianlink
|
r19 | //! get/create new package module (the returned object is a borrowed reference) | ||
PyObject* packageByName(const char* name); | ||||
ezust
|
r0 | |||
florianlink
|
r4 | //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject) | ||
florianlink
|
r16 | PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj); | ||
florianlink
|
r4 | |||
ezust
|
r0 | //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects | ||
florianlink
|
r24 | QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects; | ||
ezust
|
r0 | |||
//! stores the meta info of known Qt classes | ||||
florianlink
|
r24 | QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos; | ||
ezust
|
r0 | |||
//! names of qobject derived classes that can be casted to qobject savely | ||||
QHash<QByteArray, bool> _knownQObjectClassNames; | ||||
//! stores signal receivers for QObjects | ||||
QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers; | ||||
//! the PythonQt python module | ||||
PythonQtObjectPtr _pythonQtModule; | ||||
florianlink
|
r109 | //! the name of the PythonQt python module | ||
QByteArray _pythonQtModuleName; | ||||
florianlink
|
r157 | |||
ezust
|
r0 | //! the importer interface (if set) | ||
PythonQtImportFileInterface* _importInterface; | ||||
florianlink
|
r8 | //! the default importer | ||
PythonQtQFileImporter* _defaultImporter; | ||||
florianlink
|
r157 | |||
florianlink
|
r4 | PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB; | ||
PythonQtQObjectWrappedCB* _wrappedCB; | ||||
ezust
|
r0 | QStringList _importIgnorePaths; | ||
florianlink
|
r82 | QStringList _sharedLibrarySuffixes; | ||
ezust
|
r0 | |||
//! the cpp object wrapper factories | ||||
QList<PythonQtCppWrapperFactory*> _cppWrapperFactories; | ||||
florianlink
|
r167 | QList<PythonQtForeignWrapperFactory*> _foreignWrapperFactories; | ||
florianlink
|
r19 | QHash<QByteArray, PyObject*> _packages; | ||
ezust
|
r0 | |||
florianlink
|
r18 | PythonQtClassInfo* _currentClassInfoForClassWrapperCreation; | ||
florianlink
|
r157 | PythonQt::ProfilingCB* _profilingCB; | ||
ezust
|
r0 | int _initFlags; | ||
int _PythonQtObjectPtr_metaId; | ||||
friend class PythonQt; | ||||
}; | ||||
#endif | ||||