Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/ElmerGUI/PythonQt/src/PythonQt.h
3206 views
1
#ifndef _PYTHONQT_H
2
#define _PYTHONQT_H
3
4
/*
5
*
6
* Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
7
*
8
* This library is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public
10
* License as published by the Free Software Foundation; either
11
* version 2.1 of the License, or (at your option) any later version.
12
*
13
* This library is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
17
*
18
* Further, this software is distributed without any warranty that it is
19
* free of the rightful claim of any third person regarding infringement
20
* or the like. Any license provided herein, whether implied or
21
* otherwise, applies only to this software file. Patent licenses, if
22
* any, provided herein do not apply to combinations of this program with
23
* other software, or any other product whatsoever.
24
*
25
* You should have received a copy of the GNU Lesser General Public
26
* License along with this library; if not, write to the Free Software
27
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28
*
29
* Contact information: MeVis Research GmbH, Universitaetsallee 29,
30
* 28359 Bremen, Germany or:
31
*
32
* http://www.mevis.de
33
*
34
*/
35
36
//----------------------------------------------------------------------------------
37
/*!
38
// \file PythonQt.h
39
// \author Florian Link
40
// \author Last changed by $Author: florian $
41
// \date 2006-05
42
*/
43
//----------------------------------------------------------------------------------
44
45
#include "PythonQtSystem.h"
46
#include "PythonQtWrapper.h"
47
#include "PythonQtVariantWrapper.h"
48
#include "PythonQtMetaObjectWrapper.h"
49
#include "PythonQtSlot.h"
50
#include "PythonQtObjectPtr.h"
51
#include <QObject>
52
#include <QVariant>
53
#include <QList>
54
#include <QHash>
55
#include <QByteArray>
56
#include <QStringList>
57
#include <QtDebug>
58
#include <iostream>
59
60
61
class PythonQtClassInfo;
62
class PythonQtPrivate;
63
class PythonQtMethodInfo;
64
class PythonQtSignalReceiver;
65
class PythonQtImportFileInterface;
66
class PythonQtCppWrapperFactory;
67
class PythonQtConstructorHandler;
68
69
//! the main interface to the Python Qt binding, realized as a singleton
70
class PYTHONQT_EXPORT PythonQt : public QObject {
71
72
Q_OBJECT
73
74
public:
75
enum InitFlags {
76
RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
77
IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
78
ExternalHelp = 4 //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
79
};
80
81
//! initialize the python qt binding (flags are a or combination of InitFlags)
82
static void init(int flags = IgnoreSiteModule | RedirectStdOut);
83
84
//! cleanup
85
static void cleanup();
86
87
//! get the singleton instance
88
static PythonQt* self() { return _self; }
89
90
//-----------------------------------------------------------------------------
91
// Public API:
92
93
//! defines the object types for introspection
94
enum ObjectType {
95
Class,
96
Function,
97
Variable,
98
Module,
99
Anything,
100
CallOverloads
101
};
102
103
//! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
104
void overwriteSysPath(const QStringList& paths);
105
106
//! sets the __path__ list of a module to the given list (important for local imports)
107
void setModuleImportPath(PyObject* module, const QStringList& paths);
108
109
//! get the __main__ module of python
110
PythonQtObjectPtr getMainModule();
111
112
//! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
113
//! All added metaobjects will be visible under the className in the PythonQt module as MetaObjectWrappers and the enums
114
//! and constructors (added by addConstructors) will be available.
115
/* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
116
you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
117
void registerClass(const QMetaObject* metaobject);
118
119
//! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
120
//! and it will register the classes when it first sees a pointer to such a derived class
121
void registerQObjectClassNames(const QStringList& names);
122
123
//! this will register CPP classnames as known CPP classes (NOT QObjects) and make their MetaObjectWrapper available in
124
//! the PythonQt module. In combination with addConstuctors(), this can be used to create CPP objects from PythonQt
125
void registerCPPClassNames(const QStringList& names);
126
127
//! parses the given file and returns the python code object, this can then be used to call evalCode()
128
PythonQtObjectPtr parseFile(const QString& filename);
129
130
//! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
131
//! If pycode is NULL, a python error is printed.
132
QVariant evalCode(PyObject* module, PyObject* pycode);
133
134
//! evaluates the given script code and returns the result value
135
QVariant evalScript(PyObject* module, const QString& script, int start = Py_file_input);
136
137
//! evaluates the given script code from file
138
void evalFile(PyObject* module, const QString& filename);
139
140
//@{ Signal handlers
141
142
//! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
143
bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
144
145
//! remove a signal handler from the given \c signal of \c obj
146
bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
147
148
//! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
149
bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
150
151
//! remove a signal handler from the given \c signal of \c obj
152
bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
153
154
//@}
155
156
//@{ Variable access
157
158
//! add the given \c object to the \c module as a variable with \c name (it can be removed via clearVariable)
159
void addObject(PyObject* module, const QString& name, QObject* object);
160
161
//! add the given variable to the module
162
void addVariable(PyObject* module, const QString& name, const QVariant& v);
163
164
//! remove the given variable
165
void removeVariable(PyObject* module, const QString& name);
166
167
//! get the variable with the \c name of the \c module, returns an invalid QVariant on error
168
QVariant getVariable(PyObject* module, const QString& name);
169
170
//! read vars etc. in scope of a module, optional looking inside of an object \c objectname
171
QStringList introspection(PyObject* module, const QString& objectname, ObjectType type);
172
173
//! returns the found callable object or NULL
174
//! @return new reference
175
PythonQtObjectPtr lookupCallable(PyObject* module, const QString& name);
176
177
//@}
178
179
//@{ Calling of python callables
180
181
//! call the given python method, returns the result converted to a QVariant
182
QVariant call(PyObject* module, const QString& callable, const QVariantList& args);
183
184
//@}
185
186
//@{ Decorations, constructors, wrappers...
187
188
189
//! add an object whose slots will be used as decorator slots for
190
//! other QObjects or CPP classes. The slots need to follow the
191
//! convention that the first argument is a pointer to the wrapped object.
192
//! (ownership is passed to PythonQt)
193
/*!
194
Example:
195
196
A slot with the signature
197
198
\code
199
bool doSomething(QWidget* w, int a)
200
\endcode
201
202
will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
203
that will be called with the concrete instance as first argument.
204
So in Python you can now e.g. call
205
206
\code
207
someWidget.doSomething(12)
208
\endcode
209
210
without QWidget really having this method. This allows to easily make normal methods
211
of Qt classes callable by forwarding them with such decorator slots
212
or to make CPP classes (which are not derived from QObject) callable from Python.
213
*/
214
void addInstanceDecorators(QObject* o);
215
216
//! add an object whose slots will be used as decorator slots for
217
//! class objects (ownership is passed to PythonQt)
218
/*!
219
The slots need to follow the following convention:
220
- SomeClass* new_SomeClass(...)
221
- QVariant new_SomeClass(...)
222
- void delete_SomeClass(SomeClass*)
223
- ... static_SomeClass_someName(...)
224
225
This will add:
226
- a constructor
227
- a constructor which generates a QVariant
228
- a destructor (only useful for CPP objects)
229
- a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
230
231
*/
232
void addClassDecorators(QObject* o);
233
234
//! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
235
void addDecorators(QObject* o);
236
237
//! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
238
//! (ownership of wrapper is passed to PythonQt)
239
/*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
240
241
This will add a wrapper object that is used to make calls to the given classname \c typeName.
242
All slots that take a pointer to typeName as the first argument will be callable from Python on
243
a variant object that contains such a type.
244
*/
245
void addVariantWrapper(const char* typeName, QObject* wrapper);
246
247
//! add the given factory to PythonQt (ownership stays with caller)
248
void addWrapperFactory(PythonQtCppWrapperFactory* factory);
249
250
//! add the given constructor handler to PythonQt (ownership stays with caller)
251
void addConstructorHandler(PythonQtConstructorHandler* handler);
252
253
//! get list of constructor handlers
254
const QList<PythonQtConstructorHandler*>& constructorHandlers();
255
256
//@}
257
258
//@{ Custom importer (to replace internal import implementation of python)
259
260
//! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
261
//! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
262
//! It can only be called once, further calls will be ignored silently. (ownership stays with caller)
263
void setImporter(PythonQtImportFileInterface* importInterface);
264
265
//! set paths that the importer should ignore
266
void setImporterIgnorePaths(const QStringList& paths);
267
268
//! get paths that the importer should ignore
269
const QStringList& getImporterIgnorePaths();
270
271
//@}
272
273
//! get access to internal data (should not be used on the public API, but is used by some C functions)
274
static PythonQtPrivate* priv() { return _self->_p; }
275
276
//! get access to the file importer (if set)
277
static PythonQtImportFileInterface* importInterface();
278
279
//! handle a python error, call this when a python function fails. If no error occurred, it returns false.
280
//! The error is currently just output to the python stderr, future version might implement better trace printing
281
bool handleError();
282
283
signals:
284
//! emitted when python outputs something to stdout (and redirection is turned on)
285
void pythonStdOut(const QString& str);
286
//! emitted when python outputs something to stderr (and redirection is turned on)
287
void pythonStdErr(const QString& str);
288
289
//! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
290
void pythonHelpRequest(const QByteArray& cppClassName);
291
292
293
public:
294
//! called by internal help methods
295
PyObject* helpCalled(PythonQtClassInfo* info);
296
297
private:
298
void initPythonQtModule(bool redirectStdOut);
299
300
//! callback for stdout redirection, emits pythonStdOut signal
301
static void stdOutRedirectCB(const QString& str);
302
//! callback for stderr redirection, emits pythonStdErr signal
303
static void stdErrRedirectCB(const QString& str);
304
305
//! returns the found object or NULL
306
//! @return new reference
307
PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
308
309
//! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
310
PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
311
312
PythonQt(int flags);
313
~PythonQt();
314
315
static PythonQt* _self;
316
317
PythonQtPrivate* _p;
318
319
};
320
321
//! internal PythonQt details
322
class PythonQtPrivate : public QObject {
323
324
Q_OBJECT
325
326
public:
327
PythonQtPrivate();
328
~PythonQtPrivate();
329
330
//! returns if the id is the id for PythonQtObjectPtr
331
bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
332
333
//! remove the wrapper ptr again
334
void removeWrapperPointer(void* obj) { _wrappedObjects.take(obj); }
335
336
//! wrap the given QObject into a Python object (or return existing wrapper!)
337
PyObject* wrapQObject(QObject* obj);
338
339
//! 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
340
PyObject* wrapPtr(void* ptr, const QByteArray& name);
341
342
//! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
343
/* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
344
you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
345
void registerClass(const QMetaObject* metaobject);
346
347
//! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
348
//! and it will register the classes when it first sees a pointer to such a derived class
349
void registerQObjectClassNames(const QStringList& names);
350
351
//! add a decorator object
352
void addDecorators(QObject* o, bool instanceDeco, bool classDeco);
353
354
//! add a wrapper object for the given qvariant, also does an addConstructors() to add constructors for variants
355
void addVariantWrapper(const char* typeName, QObject* wrapper);
356
357
//! get list of all slots that are available as decorator slots
358
QList<PythonQtSlotInfo*> getDecoratorSlots(const QByteArray& className);
359
360
//! check if the enum is either part of the \c meta class or contains a scope and is
361
//! an enum of another known metaobject (and as last resort, of the Qt namespace)
362
bool isEnumType(const QMetaObject* meta, const QByteArray& name);
363
364
//! helper method that creates a PythonQtMetaObjectWrapper object
365
PythonQtMetaObjectWrapper* createNewPythonQtMetaObjectWrapper(PythonQtClassInfo* info);
366
367
//! helper method that creates a PythonQtWrapper object and registers it in the object map
368
PythonQtWrapper* createNewPythonQtWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
369
370
//! helper method that creates a PythonQtVariantWrapper object
371
PythonQtVariantWrapper* createNewPythonQtVariantWrapper(const QVariant& variant);
372
373
//! get the class info for a meta object (if available)
374
PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownQtClasses.value(meta->className()); }
375
376
//! get the constructor slot for the given classname
377
PythonQtSlotInfo* getConstructorSlot(const QByteArray& className) { return _constructorSlots.value(className); }
378
379
//! get the destructor slot for the given classname
380
PythonQtSlotInfo* getDestructorSlot(const QByteArray& className) { return _destructorSlots.value(className); }
381
382
protected slots:
383
//! called when a wrapped QObject is destroyed
384
void wrappedObjectDestroyed(QObject* obj);
385
386
//! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
387
void destroyedSignalEmitter(QObject* obj);
388
389
private:
390
391
//! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
392
QHash<void* , PythonQtWrapper *> _wrappedObjects;
393
394
//! stores the meta info of known Qt classes
395
QHash<QByteArray, PythonQtClassInfo *> _knownQtClasses;
396
397
//! stores the meta info of known Qt classes
398
QHash<QByteArray, PythonQtClassInfo *> _knownQtWrapperClasses;
399
400
//! stores the meta info of known Qt C++ wrapper classes
401
QMultiHash<QByteArray, PythonQtSlotInfo *> _knownQtDecoratorSlots;
402
403
//! names of qobject derived classes that can be casted to qobject safely
404
QHash<QByteArray, bool> _knownQObjectClassNames;
405
406
//! stores signal receivers for QObjects
407
QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
408
409
//! the PythonQt python module
410
PythonQtObjectPtr _pythonQtModule;
411
412
//! the importer interface (if set)
413
PythonQtImportFileInterface* _importInterface;
414
415
QStringList _importIgnorePaths;
416
417
//! the cpp object wrapper factories
418
QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
419
420
//! the cpp object wrapper factories
421
QList<PythonQtConstructorHandler*> _constructorHandlers;
422
423
QHash<QByteArray , PythonQtSlotInfo *> _constructorSlots;
424
QHash<QByteArray , PythonQtSlotInfo *> _destructorSlots;
425
426
QHash<int , QPair<PythonQtClassInfo*, QObject*> > _knownVariantWrappers;
427
428
PythonQtClassInfo* _qtNamespace;
429
430
int _initFlags;
431
int _PythonQtObjectPtr_metaId;
432
433
friend class PythonQt;
434
};
435
436
#endif
437
438