SourceForge.net Logo
PythonQt
PythonQt.h
Go to the documentation of this file.
00001 #ifndef _PYTHONQT_H
00002 #define _PYTHONQT_H
00003 
00004 /*
00005  *
00006  *  Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
00007  *
00008  *  This library is free software; you can redistribute it and/or
00009  *  modify it under the terms of the GNU Lesser General Public
00010  *  License as published by the Free Software Foundation; either
00011  *  version 2.1 of the License, or (at your option) any later version.
00012  *
00013  *  This library is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  *  Lesser General Public License for more details.
00017  *
00018  *  Further, this software is distributed without any warranty that it is
00019  *  free of the rightful claim of any third person regarding infringement
00020  *  or the like.  Any license provided herein, whether implied or
00021  *  otherwise, applies only to this software file.  Patent licenses, if
00022  *  any, provided herein do not apply to combinations of this program with
00023  *  other software, or any other product whatsoever.
00024  *
00025  *  You should have received a copy of the GNU Lesser General Public
00026  *  License along with this library; if not, write to the Free Software
00027  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00028  *
00029  *  Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
00030  *  28359 Bremen, Germany or:
00031  *
00032  *  http://www.mevis.de
00033  *
00034  */
00035 
00036 //----------------------------------------------------------------------------------
00043 //----------------------------------------------------------------------------------
00044 
00045 #include "PythonQtSystem.h"
00046 #include "PythonQtInstanceWrapper.h"
00047 #include "PythonQtClassWrapper.h"
00048 #include "PythonQtSlot.h"
00049 #include "PythonQtObjectPtr.h"
00050 #include "PythonQtStdIn.h"
00051 #include <QObject>
00052 #include <QVariant>
00053 #include <QList>
00054 #include <QHash>
00055 #include <QByteArray>
00056 #include <QStringList>
00057 #include <QtDebug>
00058 #include <iostream>
00059 
00060 
00061 class PythonQtClassInfo;
00062 class PythonQtPrivate;
00063 class PythonQtMethodInfo;
00064 class PythonQtSignalReceiver;
00065 class PythonQtImportFileInterface;
00066 class PythonQtCppWrapperFactory;
00067 class PythonQtForeignWrapperFactory;
00068 class PythonQtQFileImporter;
00069 
00070 typedef void  PythonQtQObjectWrappedCB(QObject* object);
00071 typedef void  PythonQtQObjectNoLongerWrappedCB(QObject* object);
00072 typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, const char **class_name);
00073 
00074 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
00075 
00076 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) { 
00077   (reinterpret_cast<T*>(object))->_wrapper = wrapper;
00078 }
00079 
00081 template<class T1, class T2> int PythonQtUpcastingOffset() {
00082   return ((reinterpret_cast<char*>(static_cast<T2*>(reinterpret_cast<T1*>(0x100)))) 
00083           - (reinterpret_cast<char*>(reinterpret_cast<T1*>(0x100))));
00084 }
00085 
00087 typedef QObject* PythonQtQObjectCreatorFunctionCB();
00088 
00090 template<class T> QObject* PythonQtCreateObject() { return new T(); };
00091 
00093 
00101 class PYTHONQT_EXPORT PythonQt : public QObject {
00102 
00103   Q_OBJECT
00104 
00105 public:
00106 
00108   enum InitFlags {
00109     RedirectStdOut = 1,   
00110     IgnoreSiteModule = 2, 
00111     ExternalHelp = 4,     
00112     PythonAlreadyInitialized = 8 
00113   };
00114 
00116   enum TypeSlots {
00117     Type_Add = 1,
00118     Type_Subtract = 1 << 1,
00119     Type_Multiply = 1 << 2,
00120     Type_Divide = 1 << 3,
00121     Type_Mod = 1 << 4,
00122     Type_And = 1 << 5,
00123     Type_Or = 1 << 6,
00124     Type_Xor = 1 << 7,
00125     Type_LShift = 1 << 8,
00126     Type_RShift = 1 << 9,
00127 
00128     Type_InplaceAdd = 1 << 10,
00129     Type_InplaceSubtract = 1 << 11,
00130     Type_InplaceMultiply = 1 << 12,
00131     Type_InplaceDivide = 1 << 13,
00132     Type_InplaceMod = 1 << 14,
00133     Type_InplaceAnd = 1 << 15,
00134     Type_InplaceOr = 1 << 16,
00135     Type_InplaceXor = 1 << 17,
00136     Type_InplaceLShift = 1 << 18,
00137     Type_InplaceRShift = 1 << 19,
00138 
00139     // Not yet needed/nicely mappable/generated...
00140     //Type_Positive = 1 << 29,
00141     //Type_Negative = 1 << 29,
00142     //Type_Abs = 1 << 29,
00143     //Type_Hash = 1 << 29,
00144 
00145     Type_Invert = 1 << 29,
00146     Type_RichCompare = 1 << 30,
00147     Type_NonZero     = 1 << 31,
00148 
00149   };
00150 
00152   enum ProfilingCallbackState {
00153     Enter = 1,
00154     Leave = 2
00155   };
00156 
00159   typedef void ProfilingCB(ProfilingCallbackState state, const char* className, const char* methodName);
00160 
00161   //---------------------------------------------------------------------------
00163 
00164 
00168   static void init(int flags = IgnoreSiteModule | RedirectStdOut, const QByteArray& pythonQtModuleName = QByteArray());
00169 
00171   static void cleanup();
00172 
00174   static PythonQt* self();
00175 
00177 
00179   enum ObjectType {
00180     Class,
00181     Function,
00182     Variable,
00183     Module,
00184     Anything,
00185     CallOverloads
00186   };
00187 
00188 
00189   //---------------------------------------------------------------------------
00191 
00192 
00195   void setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData = 0);
00196 
00199   void setRedirectStdInCallbackEnabled(bool enabled);
00200 
00202 
00203   //---------------------------------------------------------------------------
00205 
00206 
00208   PythonQtObjectPtr getMainModule();
00209 
00212   PythonQtObjectPtr importModule(const QString& name);
00213 
00218   PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
00219 
00224   PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
00225 
00228   PythonQtObjectPtr createUniqueModule();
00229 
00231 
00232   //---------------------------------------------------------------------------
00234 
00235 
00237   void overwriteSysPath(const QStringList& paths);
00238 
00240   void addSysPath(const QString& path);
00241 
00243   void setModuleImportPath(PyObject* module, const QStringList& paths);
00244 
00246 
00247   //---------------------------------------------------------------------------
00249 
00250 
00252   /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
00253    you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
00254   void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
00255 
00258 
00264   void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
00265 
00268   void registerQObjectClassNames(const QStringList& names);
00269 
00274   bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
00275 
00277   void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
00278 
00280 
00281   //---------------------------------------------------------------------------
00283 
00284 
00286   PythonQtObjectPtr parseFile(const QString& filename);
00287 
00290   QVariant evalCode(PyObject* object, PyObject* pycode);
00291 
00293   QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input);
00294 
00296   void evalFile(PyObject* object, const QString& filename);
00297 
00299 
00300   //---------------------------------------------------------------------------
00302 
00303 
00305   bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
00306 
00308   bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
00309 
00311   bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
00312 
00314   bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
00315 
00317 
00318   //---------------------------------------------------------------------------
00320 
00321 
00323   void addObject(PyObject* object, const QString& name, QObject* qObject);
00324 
00326   void addVariable(PyObject* object, const QString& name, const QVariant& v);
00327 
00329   void removeVariable(PyObject* module, const QString& name);
00330 
00332   QVariant getVariable(PyObject* object, const QString& name);
00333 
00335   QStringList introspection(PyObject* object, const QString& objectname, ObjectType type);
00337   QStringList introspectObject(PyObject* object, ObjectType type);
00342   QStringList introspectType(const QString& typeName, ObjectType type);
00343 
00346   PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
00347   
00349   QString getReturnTypeOfWrappedMethod(PyObject* module, const QString& objectname);  
00351   QString getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName);
00353 
00354   //---------------------------------------------------------------------------
00356 
00357 
00359   QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList());
00360 
00362   QVariant call(PyObject* callable, const QVariantList& args = QVariantList());
00363 
00365   PyObject* callAndReturnPyObject(PyObject* callable, const QVariantList& args = QVariantList());
00366 
00368 
00369   //---------------------------------------------------------------------------
00371 
00372 
00377 
00398   void addInstanceDecorators(QObject* o);
00399 
00402 
00416   void addClassDecorators(QObject* o);
00417 
00419   void addDecorators(QObject* o);
00420 
00422   void addWrapperFactory(PythonQtCppWrapperFactory* factory);
00423 
00425   void addWrapperFactory(PythonQtForeignWrapperFactory* factory);
00426 
00428   void removeWrapperFactory(PythonQtCppWrapperFactory* factory);
00429 
00431   void removeWrapperFactory(PythonQtForeignWrapperFactory* factory);
00432 
00434 
00435   //---------------------------------------------------------------------------
00437 
00438 
00448   void setImporter(PythonQtImportFileInterface* importInterface);
00449 
00456   void installDefaultImporter() { setImporter(NULL); }
00457 
00459   void setImporterIgnorePaths(const QStringList& paths);
00460 
00462   const QStringList& getImporterIgnorePaths();
00463 
00465   static PythonQtImportFileInterface* importInterface();
00466 
00468 
00469   //---------------------------------------------------------------------------
00471 
00472 
00474   static PythonQtPrivate* priv() { return _self->_p; }
00475 
00478   bool handleError();
00479 
00482   void clearNotFoundCachedMembers();
00483 
00485   void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
00487   void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
00488 
00490   static void qObjectNoLongerWrappedCB(QObject* o);
00491 
00493   PyObject* helpCalled(PythonQtClassInfo* info);
00494 
00497   PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
00498 
00500   void setProfilingCallback(ProfilingCB* cb);
00501 
00503 
00504 signals:
00506   void pythonStdOut(const QString& str);
00508   void pythonStdErr(const QString& str);
00509 
00511   void pythonHelpRequest(const QByteArray& cppClassName);
00512 
00513 private:
00514   void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName);
00515   
00516   QString getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context);
00517   
00518   PyObject* getObjectByType(const QString& typeName);
00519 
00521   static void stdOutRedirectCB(const QString& str);
00523   static void stdErrRedirectCB(const QString& str);
00524 
00526   PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
00527 
00528   PythonQt(int flags, const QByteArray& pythonQtModuleName);
00529   ~PythonQt();
00530 
00531   static PythonQt* _self;
00532   static int _uniqueModuleCount;
00533 
00534   PythonQtPrivate* _p;
00535 
00536 };
00537 
00539 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
00540 
00541   Q_OBJECT
00542 
00543 public:
00544   PythonQtPrivate();
00545   ~PythonQtPrivate();
00546 
00547   enum DecoratorTypes {
00548     StaticDecorator = 1,
00549     ConstructorDecorator = 2,
00550     DestructorDecorator = 4,
00551     InstanceDecorator = 8,
00552     AllDecorators = 0xffff
00553   };
00554 
00556   const QStringList& sharedLibrarySuffixes() { return _sharedLibrarySuffixes; }
00557 
00559   bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
00560 
00562   void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
00564   void removeWrapperPointer(void* obj);
00565 
00567   void shellClassDeleted(void* shellClass);
00568 
00570   void* unwrapForeignWrapper(const QByteArray& classname, PyObject* obj);
00571 
00573   bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
00574 
00576   void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
00577 
00579   PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
00580 
00582   void removeSignalEmitter(QObject* obj);
00583 
00585   PyObject* wrapQObject(QObject* obj);
00586 
00588   PyObject* wrapPtr(void* ptr, const QByteArray& name);
00589 
00591   /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
00592      you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
00593   void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
00594 
00597 
00603   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);
00604 
00607   void registerQObjectClassNames(const QStringList& names);
00608 
00610   void addDecorators(QObject* o, int decoTypes);
00611 
00613   PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* module);
00614 
00616   static PyObject*  createEnumValueInstance(PyObject* enumType, unsigned int enumValue);
00617 
00619   static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
00620 
00622   PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
00623 
00625   PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
00626 
00628   PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
00629 
00631   PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
00632 
00634   PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
00635 
00637   static PyObject* dummyTuple();
00638 
00640   void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result);
00641 
00643   PythonQtObjectPtr pythonQtModule() const { return _pythonQtModule; }
00644 
00646   PythonQt::ProfilingCB* profilingCB() const { return _profilingCB; }
00647   
00649   QString getSignature(PyObject* object);
00650   
00652   bool isMethodDescriptor(PyObject* object) const;
00653 
00654 private:
00656   void setupSharedLibrarySuffixes();
00657 
00659   void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module = NULL);
00660 
00662   PyObject* packageByName(const char* name);
00663 
00665   PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
00666 
00668   QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
00669 
00671   QHash<QByteArray, PythonQtClassInfo *>   _knownClassInfos;
00672 
00674   QHash<QByteArray, bool> _knownQObjectClassNames;
00675 
00677   QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
00678 
00680   PythonQtObjectPtr _pythonQtModule;
00681 
00683   QByteArray _pythonQtModuleName;
00684 
00686   PythonQtImportFileInterface* _importInterface;
00687 
00689   PythonQtQFileImporter* _defaultImporter;
00690 
00691   PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
00692   PythonQtQObjectWrappedCB* _wrappedCB;
00693 
00694   QStringList _importIgnorePaths;
00695   QStringList _sharedLibrarySuffixes;
00696 
00698   QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
00699 
00700   QList<PythonQtForeignWrapperFactory*> _foreignWrapperFactories;
00701 
00702   QHash<QByteArray, PyObject*> _packages;
00703 
00704   PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
00705 
00706   PythonQt::ProfilingCB* _profilingCB;
00707 
00708   int _initFlags;
00709   int _PythonQtObjectPtr_metaId;
00710 
00711   friend class PythonQt;
00712 };
00713 
00714 #endif