Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/ElmerGUI/PythonQt/src/PythonQt.cpp
3206 views
1
/*
2
*
3
* Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4
*
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2.1 of the License, or (at your option) any later version.
9
*
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
14
*
15
* Further, this software is distributed without any warranty that it is
16
* free of the rightful claim of any third person regarding infringement
17
* or the like. Any license provided herein, whether implied or
18
* otherwise, applies only to this software file. Patent licenses, if
19
* any, provided herein do not apply to combinations of this program with
20
* other software, or any other product whatsoever.
21
*
22
* You should have received a copy of the GNU Lesser General Public
23
* License along with this library; if not, write to the Free Software
24
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
*
26
* Contact information: MeVis Research GmbH, Universitaetsallee 29,
27
* 28359 Bremen, Germany or:
28
*
29
* http://www.mevis.de
30
*
31
*/
32
33
//----------------------------------------------------------------------------------
34
/*!
35
// \file PythonQt.cpp
36
// \author Florian Link
37
// \author Last changed by $Author: florian $
38
// \date 2006-05
39
*/
40
//----------------------------------------------------------------------------------
41
42
#include "PythonQt.h"
43
#include "PythonQtImporter.h"
44
#include "PythonQtClassInfo.h"
45
#include "PythonQtMethodInfo.h"
46
#include "PythonQtSignalReceiver.h"
47
#include "PythonQtConversion.h"
48
#include "PythonQtStdOut.h"
49
#include "PythonQtCppWrapperFactory.h"
50
#include "PythonQtVariants.h"
51
#include "PythonQtStdDecorators.h"
52
#include <pydebug.h>
53
54
PythonQt* PythonQt::_self = NULL;
55
56
57
void PythonQt::init(int flags)
58
{
59
if (!_self) {
60
_self = new PythonQt(flags);
61
}
62
63
PythonQt::self()->addDecorators(new PythonQtStdDecorators());
64
65
PythonQt::priv()->addVariantWrapper("QBitArray", new PythonQtQBitArrayWrapper);
66
PythonQt::priv()->addVariantWrapper("QDate", new PythonQtQDateWrapper);
67
PythonQt::priv()->addVariantWrapper("QTime", new PythonQtQTimeWrapper);
68
PythonQt::priv()->addVariantWrapper("QDateTime", new PythonQtQDateTimeWrapper);
69
PythonQt::priv()->addVariantWrapper("QUrl", new PythonQtQUrlWrapper);
70
PythonQt::priv()->addVariantWrapper("QLocale", new PythonQtQLocaleWrapper);
71
PythonQt::priv()->addVariantWrapper("QRect", new PythonQtQRectWrapper);
72
PythonQt::priv()->addVariantWrapper("QRectF", new PythonQtQRectFWrapper);
73
PythonQt::priv()->addVariantWrapper("QSize", new PythonQtQSizeWrapper);
74
PythonQt::priv()->addVariantWrapper("QSizeF", new PythonQtQSizeFWrapper);
75
PythonQt::priv()->addVariantWrapper("QLine", new PythonQtQLineWrapper);
76
PythonQt::priv()->addVariantWrapper("QLineF", new PythonQtQLineFWrapper);
77
PythonQt::priv()->addVariantWrapper("QPoint", new PythonQtQPointWrapper);
78
PythonQt::priv()->addVariantWrapper("QPointF", new PythonQtQPointFWrapper);
79
PythonQt::priv()->addVariantWrapper("QRegExp", new PythonQtQRegExpWrapper);
80
PythonQt::priv()->addVariantWrapper("QFont", new PythonQtQFontWrapper);
81
PythonQt::priv()->addVariantWrapper("QPixmap", new PythonQtQPixmapWrapper);
82
PythonQt::priv()->addVariantWrapper("QBrush", new PythonQtQBrushWrapper);
83
PythonQt::priv()->addVariantWrapper("QColor", new PythonQtQColorWrapper);
84
PythonQt::priv()->addVariantWrapper("QPalette", new PythonQtQPaletteWrapper);
85
PythonQt::priv()->addVariantWrapper("QIcon", new PythonQtQIconWrapper);
86
PythonQt::priv()->addVariantWrapper("QImage", new PythonQtQImageWrapper);
87
PythonQt::priv()->addVariantWrapper("QPolygon", new PythonQtQPolygonWrapper);
88
PythonQt::priv()->addVariantWrapper("QRegion", new PythonQtQRegionWrapper);
89
PythonQt::priv()->addVariantWrapper("QBitmap", new PythonQtQBitmapWrapper);
90
PythonQt::priv()->addVariantWrapper("QCursor", new PythonQtQCursorWrapper);
91
PythonQt::priv()->addVariantWrapper("QSizePolicy", new PythonQtQSizePolicyWrapper);
92
PythonQt::priv()->addVariantWrapper("QKeySequence", new PythonQtQKeySequenceWrapper);
93
PythonQt::priv()->addVariantWrapper("QPen", new PythonQtQPenWrapper);
94
PythonQt::priv()->addVariantWrapper("QTextLength", new PythonQtQTextLengthWrapper);
95
PythonQt::priv()->addVariantWrapper("QTextFormat", new PythonQtQTextFormatWrapper);
96
PythonQt::priv()->addVariantWrapper("QMatrix", new PythonQtQMatrixWrapper);
97
98
}
99
100
void PythonQt::cleanup()
101
{
102
if (_self) {
103
delete _self;
104
_self = NULL;
105
}
106
}
107
108
PythonQt::PythonQt(int flags)
109
{
110
_p = new PythonQtPrivate;
111
_p->_initFlags = flags;
112
113
_p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
114
115
Py_SetProgramName("PythonQt");
116
if (flags & IgnoreSiteModule) {
117
// this prevents the automatic importing of Python site files
118
Py_NoSiteFlag = 1;
119
}
120
Py_Initialize();
121
122
// add our own python object types for qt object slots
123
if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
124
std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
125
}
126
Py_INCREF(&PythonQtSlotFunction_Type);
127
128
// add our own python object types for qt objects
129
if (PyType_Ready(&PythonQtWrapper_Type) < 0) {
130
std::cerr << "could not initialize PythonQtWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
131
}
132
Py_INCREF(&PythonQtWrapper_Type);
133
134
// add our own python object types for qt objects
135
if (PyType_Ready(&PythonQtVariantWrapper_Type) < 0) {
136
std::cerr << "could not initialize PythonQtVariantWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
137
}
138
Py_INCREF(&PythonQtVariantWrapper_Type);
139
140
// add our own python object types for qt objects
141
if (PyType_Ready(&PythonQtMetaObjectWrapper_Type) < 0) {
142
std::cerr << "could not initialize PythonQtMetaObjectWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
143
}
144
Py_INCREF(&PythonQtMetaObjectWrapper_Type);
145
146
// add our own python object types for redirection of stdout
147
if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
148
std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
149
}
150
Py_INCREF(&PythonQtStdOutRedirectType);
151
152
initPythonQtModule(flags & RedirectStdOut);
153
154
}
155
156
PythonQt::~PythonQt() {
157
delete _p;
158
_p = NULL;
159
}
160
161
PythonQtPrivate::~PythonQtPrivate() {
162
{
163
QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownQtClasses);
164
while (i.hasNext()) {
165
delete i.next().value();
166
}
167
}
168
{
169
QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownQtWrapperClasses);
170
while (i.hasNext()) {
171
delete i.next().value();
172
}
173
}
174
{
175
QHashIterator<int , QPair<PythonQtClassInfo*, QObject*> > i(_knownVariantWrappers);
176
while (i.hasNext()) {
177
delete i.next().value().first;
178
}
179
}
180
{
181
QHashIterator<QByteArray, PythonQtSlotInfo *> i(_constructorSlots);
182
while (i.hasNext()) {
183
delete i.next().value();
184
}
185
}
186
{
187
QHashIterator<QByteArray, PythonQtSlotInfo *> i(_destructorSlots);
188
while (i.hasNext()) {
189
delete i.next().value();
190
}
191
}
192
PythonQtConv::global_valueStorage.clear();
193
PythonQtConv::global_ptrStorage.clear();
194
PythonQtConv::global_variantStorage.clear();
195
196
PythonQtMethodInfo::cleanupCachedMethodInfos();
197
198
delete _qtNamespace;
199
}
200
201
PythonQtImportFileInterface* PythonQt::importInterface()
202
{
203
return _self->_p->_importInterface;
204
}
205
206
void PythonQt::registerClass(const QMetaObject* metaobject)
207
{
208
_p->registerClass(metaobject);
209
}
210
211
void PythonQtPrivate::registerClass(const QMetaObject* metaobject)
212
{
213
// we register all classes in the hierarchy
214
const QMetaObject* m = metaobject;
215
while (m) {
216
PythonQtClassInfo* info = _knownQtClasses.value(m->className());
217
if (!info) {
218
info = new PythonQtClassInfo(m);
219
_knownQtClasses.insert(m->className(), info);
220
PyModule_AddObject(_pythonQtModule, m->className(), (PyObject*)createNewPythonQtMetaObjectWrapper(info));
221
}
222
m = m->superClass();
223
}
224
}
225
226
bool PythonQtPrivate::isEnumType(const QMetaObject* meta, const QByteArray& name) {
227
int i = meta?meta->indexOfEnumerator(name.constData()):-1;
228
if (i!=-1) {
229
return true;
230
} else {
231
// look for scope
232
int scopePos = name.indexOf("::");
233
if (scopePos != -1) {
234
// slit into scope and enum name
235
QByteArray enumScope = name.mid(0,scopePos);
236
QByteArray enumName = name.mid(scopePos+2);
237
if (enumScope == "Qt") {
238
// special qt namespace case
239
return isEnumType(&staticQtMetaObject, enumName);
240
} else {
241
// look for known classes as scope
242
// TODO: Q_GADGETS are not yet handled
243
PythonQtClassInfo* info = _knownQtClasses.value(enumScope);
244
if (info) {
245
return isEnumType(info->metaObject(), enumName);
246
}
247
}
248
}
249
}
250
return false;
251
}
252
253
PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
254
{
255
if (!obj) {
256
Py_INCREF(Py_None);
257
return Py_None;
258
}
259
PythonQtWrapper* wrap = _wrappedObjects.value(obj);
260
if (!wrap) {
261
// smuggling it in...
262
PythonQtClassInfo* classInfo = _knownQtClasses.value(obj->metaObject()->className());
263
if (!classInfo) {
264
registerClass(obj->metaObject());
265
classInfo = _knownQtClasses.value(obj->metaObject()->className());
266
}
267
wrap = createNewPythonQtWrapper(obj, classInfo);
268
// insert destroyed handler
269
connect(obj, SIGNAL(destroyed(QObject*)), this, SLOT(wrappedObjectDestroyed(QObject*)));
270
// mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
271
} else {
272
Py_INCREF(wrap);
273
// mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
274
}
275
return (PyObject*)wrap;
276
}
277
278
PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
279
{
280
if (!ptr) {
281
Py_INCREF(Py_None);
282
return Py_None;
283
}
284
PythonQtWrapper* wrap = _wrappedObjects.value(ptr);
285
if (!wrap) {
286
PythonQtClassInfo* info = _knownQtClasses.value(name);
287
if (!info) {
288
// we do not know the metaobject yet, but we might know it by it's name:
289
if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
290
// yes, we know it, so we can convert to QObject
291
QObject* qptr = (QObject*)ptr;
292
registerClass(qptr->metaObject());
293
info = _knownQtClasses.value(qptr->metaObject()->className());
294
}
295
}
296
if (info) {
297
QObject* qptr = (QObject*)ptr;
298
// if the object is a derived object, we want to switch the class info to the one of the derived class:
299
if (name!=(qptr->metaObject()->className())) {
300
registerClass(qptr->metaObject());
301
info = _knownQtClasses.value(qptr->metaObject()->className());
302
}
303
wrap = createNewPythonQtWrapper(qptr, info);
304
// insert destroyed handler
305
connect(qptr, SIGNAL(destroyed(QObject*)), this, SLOT(wrappedObjectDestroyed(QObject*)));
306
// mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
307
} else {
308
// maybe it is a PyObject, which we can return directly
309
if (name == "PyObject") {
310
PyObject* p = (PyObject*)ptr;
311
Py_INCREF(p);
312
return p;
313
}
314
// not a known QObject, so try our wrapper factory:
315
QObject* wrapper = NULL;
316
for (int i=0; i<_cppWrapperFactories.size(); i++) {
317
wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
318
if (wrapper) {
319
break;
320
}
321
}
322
PythonQtClassInfo* info = _knownQtWrapperClasses.value(name);
323
if (!info) {
324
info = new PythonQtClassInfo(wrapper?wrapper->metaObject():&QObject::staticQtMetaObject, name);
325
_knownQtWrapperClasses.insert(name, info);
326
PyModule_AddObject(_pythonQtModule, name, (PyObject*)createNewPythonQtMetaObjectWrapper(info));
327
} else {
328
if (wrapper && (info->metaObject() != wrapper->metaObject())) {
329
info->setMetaObject(wrapper->metaObject());
330
}
331
}
332
wrap = createNewPythonQtWrapper(wrapper, info, ptr);
333
// mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
334
}
335
} else {
336
Py_INCREF(wrap);
337
//mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
338
}
339
return (PyObject*)wrap;
340
}
341
342
void PythonQt::registerCPPClassNames(const QStringList& names)
343
{
344
foreach ( QString n, names) {
345
QByteArray name = n.toLatin1();
346
PythonQtClassInfo* info = _p->_knownQtWrapperClasses.value(name);
347
if (!info) {
348
info = new PythonQtClassInfo(&QObject::staticMetaObject, name);
349
_p->_knownQtWrapperClasses.insert(name, info);
350
PyModule_AddObject(_p->_pythonQtModule, name.data(), (PyObject*)_p->createNewPythonQtMetaObjectWrapper(info));
351
}
352
}
353
}
354
355
PythonQtWrapper* PythonQtPrivate::createNewPythonQtWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
356
PythonQtWrapper* result;
357
result = (PythonQtWrapper *)PythonQtWrapper_Type.tp_new(&PythonQtWrapper_Type,
358
NULL, NULL);
359
360
result->_obj = obj;
361
result->_info = info;
362
result->_wrappedPtr = wrappedPtr;
363
result->_ownedByPythonQt = false;
364
365
if (wrappedPtr) {
366
_wrappedObjects.insert(wrappedPtr, result);
367
} else {
368
_wrappedObjects.insert(obj, result);
369
}
370
return result;
371
}
372
373
PythonQtVariantWrapper* PythonQtPrivate::createNewPythonQtVariantWrapper(const QVariant& variant) {
374
PythonQtVariantWrapper* result;
375
result = (PythonQtVariantWrapper *)PythonQtVariantWrapper_Type.tp_new(&PythonQtVariantWrapper_Type,
376
NULL, NULL);
377
378
*result->_variant = variant;
379
QPair<PythonQtClassInfo*, QObject*> pair = _knownVariantWrappers.value(variant.userType());
380
result->_wrapper = pair.second;
381
result->_info = pair.first;
382
return result;
383
}
384
385
PythonQtMetaObjectWrapper* PythonQtPrivate::createNewPythonQtMetaObjectWrapper(PythonQtClassInfo* info) {
386
PythonQtMetaObjectWrapper* result;
387
result = (PythonQtMetaObjectWrapper *)PythonQtMetaObjectWrapper_Type.tp_new(&PythonQtMetaObjectWrapper_Type,
388
NULL, NULL);
389
result->_info = info;
390
return result;
391
}
392
393
394
PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
395
{
396
PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
397
if (!r) {
398
r = new PythonQtSignalReceiver(obj);
399
_p->_signalReceivers.insert(obj, r);
400
// insert destroyed handler
401
connect(obj, SIGNAL(destroyed(QObject*)), _p ,SLOT(destroyedSignalEmitter(QObject*)));
402
}
403
return r;
404
}
405
406
bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
407
{
408
bool flag = false;
409
PythonQtObjectPtr callable = lookupCallable(module, objectname);
410
if (callable) {
411
PythonQtSignalReceiver* r = getSignalReceiver(obj);
412
flag = r->addSignalHandler(signal, callable);
413
if (!flag) {
414
// signal not found
415
}
416
} else {
417
// callable not found
418
}
419
return flag;
420
}
421
422
bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
423
{
424
bool flag = false;
425
PythonQtSignalReceiver* r = getSignalReceiver(obj);
426
if (r) {
427
flag = r->addSignalHandler(signal, receiver);
428
}
429
return flag;
430
}
431
432
bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
433
{
434
bool flag = false;
435
PythonQtObjectPtr callable = lookupCallable(module, objectname);
436
if (callable) {
437
PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
438
if (r) {
439
flag = r->removeSignalHandler(signal, callable);
440
}
441
} else {
442
// callable not found
443
}
444
return flag;
445
}
446
447
bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
448
{
449
bool flag = false;
450
PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
451
if (r) {
452
flag = r->removeSignalHandler(signal, receiver);
453
}
454
return flag;
455
}
456
457
PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
458
{
459
PythonQtObjectPtr p = lookupObject(module, name);
460
if (p) {
461
if (PyCallable_Check(p)) {
462
return p;
463
}
464
}
465
PyErr_Clear();
466
return NULL;
467
}
468
469
PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
470
{
471
QStringList l = name.split('.');
472
PythonQtObjectPtr p = module;
473
PythonQtObjectPtr prev;
474
QString s;
475
QByteArray b;
476
for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
477
prev = p;
478
b = (*i).toLatin1();
479
p.setNewRef(PyObject_GetAttrString(p, b.data()));
480
}
481
PyErr_Clear();
482
return p;
483
}
484
485
PythonQtObjectPtr PythonQt::getMainModule() {
486
//both borrowed
487
PythonQtObjectPtr dict = PyImport_GetModuleDict();
488
return PyDict_GetItemString(dict, "__main__");
489
}
490
491
QVariant PythonQt::evalCode(PyObject* module, PyObject* pycode) {
492
QVariant result;
493
if (pycode) {
494
PyObject* r = PyEval_EvalCode((PyCodeObject*)pycode, PyModule_GetDict((PyObject*)module) , PyModule_GetDict((PyObject*)module));
495
if (r) {
496
result = PythonQtConv::PyObjToQVariant(r);
497
Py_DECREF(r);
498
} else {
499
handleError();
500
}
501
} else {
502
handleError();
503
}
504
return result;
505
}
506
507
QVariant PythonQt::evalScript(PyObject* module, const QString& script, int start)
508
{
509
QVariant result;
510
PythonQtObjectPtr p;
511
p.setNewRef(PyRun_String(script.toLatin1().data(), start, PyModule_GetDict(module), PyModule_GetDict(module)));
512
if (p) {
513
result = PythonQtConv::PyObjToQVariant(p);
514
} else {
515
handleError();
516
}
517
return result;
518
}
519
520
void PythonQt::evalFile(PyObject* module, const QString& filename)
521
{
522
PythonQtObjectPtr code = parseFile(filename);
523
if (code) {
524
evalCode(module, code);
525
} else {
526
handleError();
527
}
528
}
529
530
PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
531
{
532
PythonQtObjectPtr p;
533
p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
534
if (!p) {
535
handleError();
536
}
537
return p;
538
}
539
540
void PythonQt::addObject(PyObject* module, const QString& name, QObject* object)
541
{
542
PyModule_AddObject(module, name.toLatin1().data(), _p->wrapQObject(object));
543
}
544
545
void PythonQt::addVariable(PyObject* module, const QString& name, const QVariant& v)
546
{
547
PyModule_AddObject(module, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
548
}
549
550
void PythonQt::removeVariable(PyObject* module, const QString& name)
551
{
552
PyObject_DelAttrString(module, name.toLatin1().data());
553
}
554
555
QVariant PythonQt::getVariable(PyObject* module, const QString& objectname)
556
{
557
QVariant result;
558
PythonQtObjectPtr obj = lookupObject(module, objectname);
559
if (obj) {
560
result = PythonQtConv::PyObjToQVariant(obj);
561
}
562
return result;
563
}
564
565
QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
566
{
567
QStringList results;
568
569
PythonQtObjectPtr object;
570
if (objectname.isEmpty()) {
571
object = module;
572
} else {
573
object = lookupObject(module, objectname);
574
}
575
576
if (object) {
577
if (type == CallOverloads) {
578
if (PythonQtSlotFunction_Check(object)) {
579
PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
580
PythonQtSlotInfo* info = o->m_ml;
581
582
while (info) {
583
results << info->fullSignature(info->isInstanceDecorator() || o->m_self->ob_type == &PythonQtVariantWrapper_Type);
584
info = info->nextInfo();
585
}
586
} else if (object->ob_type == &PythonQtMetaObjectWrapper_Type) {
587
PythonQtMetaObjectWrapper* o = (PythonQtMetaObjectWrapper*)object.object();
588
PythonQtSlotInfo* info = o->_info->constructors();
589
590
while (info) {
591
results << info->fullSignature(false);
592
info = info->nextInfo();
593
}
594
} else {
595
PyObject* doc = PyObject_GetAttrString(object, "__doc__");
596
if (doc) {
597
results << PyString_AsString(doc);
598
Py_DECREF(doc);
599
}
600
}
601
} else {
602
PyObject* keys = PyObject_Dir(object);
603
if (keys) {
604
int count = PyList_Size(keys);
605
PyObject* key;
606
PyObject* value;
607
QString keystr;
608
for (int i = 0;i<count;i++) {
609
key = PyList_GetItem(keys,i);
610
value = PyObject_GetAttr(object, key);
611
if (!value) continue;
612
keystr = PyString_AsString(key);
613
static const QString underscoreStr("__");
614
if (!keystr.startsWith(underscoreStr)) {
615
switch (type) {
616
case Anything:
617
results << keystr;
618
break;
619
case Class:
620
if (value->ob_type == &PyClass_Type) {
621
results << keystr;
622
}
623
break;
624
case Variable:
625
if (value->ob_type != &PyClass_Type
626
&& value->ob_type != &PyCFunction_Type
627
&& value->ob_type != &PyFunction_Type
628
&& value->ob_type != &PyModule_Type
629
) {
630
results << keystr;
631
}
632
break;
633
case Function:
634
if (value->ob_type == &PyFunction_Type ||
635
value->ob_type == &PyMethod_Type
636
) {
637
results << keystr;
638
}
639
break;
640
case Module:
641
if (value->ob_type == &PyModule_Type) {
642
results << keystr;
643
}
644
break;
645
default:
646
std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
647
}
648
}
649
Py_DECREF(value);
650
}
651
Py_DECREF(keys);
652
}
653
}
654
}
655
return results;
656
}
657
658
QVariant PythonQt::call(PyObject* module, const QString& name, const QVariantList& args)
659
{
660
QVariant r;
661
662
PythonQtObjectPtr callable = lookupCallable(module, name);
663
if (callable) {
664
PythonQtObjectPtr pargs;
665
int count = args.size();
666
if (count>0) {
667
pargs.setNewRef(PyTuple_New(count));
668
}
669
bool err = false;
670
// transform QVariants to Python
671
for (int i = 0; i < count; i++) {
672
PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
673
if (arg) {
674
// steals reference, no unref
675
PyTuple_SetItem(pargs, i,arg);
676
} else {
677
err = true;
678
break;
679
}
680
}
681
682
if (!err) {
683
PyErr_Clear();
684
PythonQtObjectPtr result;
685
result.setNewRef(PyObject_CallObject(callable, pargs));
686
if (result) {
687
// ok
688
r = PythonQtConv::PyObjToQVariant(result);
689
} else {
690
PythonQt::self()->handleError();
691
}
692
}
693
}
694
return r;
695
}
696
697
void PythonQt::addInstanceDecorators(QObject* o)
698
{
699
_p->addDecorators(o, true, false);
700
}
701
702
void PythonQt::addClassDecorators(QObject* o)
703
{
704
_p->addDecorators(o, false, true);
705
}
706
707
void PythonQt::addDecorators(QObject* o)
708
{
709
_p->addDecorators(o, true, true);
710
}
711
712
void PythonQt::registerQObjectClassNames(const QStringList& names)
713
{
714
_p->registerQObjectClassNames(names);
715
}
716
717
void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
718
{
719
static bool first = true;
720
if (first) {
721
first = false;
722
_p->_importInterface = importInterface;
723
PythonQtImport::init();
724
}
725
}
726
727
void PythonQt::setImporterIgnorePaths(const QStringList& paths)
728
{
729
_p->_importIgnorePaths = paths;
730
}
731
732
const QStringList& PythonQt::getImporterIgnorePaths()
733
{
734
return _p->_importIgnorePaths;
735
}
736
737
void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
738
{
739
_p->_cppWrapperFactories.append(factory);
740
}
741
742
void PythonQt::addConstructorHandler(PythonQtConstructorHandler* factory)
743
{
744
_p->_constructorHandlers.append(factory);
745
}
746
747
const QList<PythonQtConstructorHandler*>& PythonQt::constructorHandlers()
748
{
749
return _p->_constructorHandlers;
750
};
751
752
//---------------------------------------------------------------------------------------------------
753
PythonQtPrivate::PythonQtPrivate()
754
{
755
_importInterface = NULL;
756
}
757
758
void PythonQtPrivate::addDecorators(QObject* o, bool instanceDeco, bool classDeco)
759
{
760
o->setParent(this);
761
int numMethods = o->metaObject()->methodCount();
762
for (int i = 0; i < numMethods; i++) {
763
QMetaMethod m = o->metaObject()->method(i);
764
if ((m.methodType() == QMetaMethod::Method ||
765
m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
766
const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m);
767
if (qstrncmp(m.signature(), "new_", 4)==0) {
768
if (!classDeco) continue;
769
// either it returns a * or a QVariant and the name starts with "new_"
770
bool isVariantReturn = info->parameters().at(0).typeId == PythonQtMethodInfo::Variant;
771
if ((info->parameters().at(0).isPointer || isVariantReturn)) {
772
QByteArray signature = m.signature();
773
QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
774
PythonQtSlotInfo* prev = _constructorSlots.value(nameOfClass);
775
PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
776
if (prev) {
777
newSlot->setNextInfo(prev->nextInfo());
778
prev->setNextInfo(newSlot);
779
} else {
780
_constructorSlots.insert(nameOfClass, newSlot);
781
}
782
}
783
} else if (qstrncmp(m.signature(), "delete_", 7)==0) {
784
if (!classDeco) continue;
785
QByteArray signature = m.signature();
786
QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
787
PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
788
_destructorSlots.insert(nameOfClass, newSlot);
789
} else if (qstrncmp(m.signature(), "static_", 7)==0) {
790
if (!classDeco) continue;
791
QByteArray signature = m.signature();
792
QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
793
nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
794
PythonQtSlotInfo* slotCopy = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
795
_knownQtDecoratorSlots.insert(nameOfClass, slotCopy);
796
} else {
797
if (!instanceDeco) continue;
798
if (info->parameters().count()>1) {
799
PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
800
if (p.isPointer) {
801
PythonQtSlotInfo* slotCopy = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::InstanceDecorator);
802
_knownQtDecoratorSlots.insert(p.name, slotCopy);
803
}
804
}
805
}
806
}
807
}
808
}
809
810
void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
811
{
812
foreach(QString name, names) {
813
_knownQObjectClassNames.insert(name.toLatin1(), true);
814
}
815
}
816
817
QList<PythonQtSlotInfo*> PythonQtPrivate::getDecoratorSlots(const QByteArray& className)
818
{
819
return _knownQtDecoratorSlots.values(className);
820
}
821
822
void PythonQtPrivate::wrappedObjectDestroyed(QObject* obj)
823
{
824
// mlabDebugConst("MLABPython","PyWrapper QObject destroyed " << o << " " << o->name() << " " << o->className());
825
PythonQtWrapper* wrap = _wrappedObjects[obj];
826
if (wrap) {
827
_wrappedObjects.remove(obj);
828
// remove the pointer but keep the wrapper alive in python
829
wrap->_obj = NULL;
830
}
831
}
832
833
void PythonQtPrivate::destroyedSignalEmitter(QObject* obj)
834
{
835
_signalReceivers.take(obj);
836
}
837
838
bool PythonQt::handleError()
839
{
840
bool flag = false;
841
if (PyErr_Occurred()) {
842
843
// currently we just print the error and the stderr handler parses the errors
844
PyErr_Print();
845
846
/*
847
// EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
848
PyObject *ptype;
849
PyObject *pvalue;
850
PyObject *ptraceback;
851
PyErr_Fetch( &ptype, &pvalue, &ptraceback);
852
853
Py_XDECREF(ptype);
854
Py_XDECREF(pvalue);
855
Py_XDECREF(ptraceback);
856
*/
857
PyErr_Clear();
858
flag = true;
859
}
860
return flag;
861
}
862
863
void PythonQt::overwriteSysPath(const QStringList& paths)
864
{
865
PythonQtObjectPtr sys;
866
sys.setNewRef(PyImport_ImportModule("sys"));
867
PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
868
}
869
870
void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
871
{
872
PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
873
}
874
875
void PythonQt::stdOutRedirectCB(const QString& str)
876
{
877
emit PythonQt::self()->pythonStdOut(str);
878
}
879
880
void PythonQt::stdErrRedirectCB(const QString& str)
881
{
882
emit PythonQt::self()->pythonStdErr(str);
883
}
884
885
886
887
static PyMethodDef PythonQtMethods[] = {
888
{NULL, NULL, 0, NULL}
889
};
890
891
void PythonQt::initPythonQtModule(bool redirectStdOut)
892
{
893
_p->_pythonQtModule.setNewRef(Py_InitModule("PythonQt", PythonQtMethods));
894
_p->_qtNamespace = new PythonQtClassInfo(&staticQtMetaObject);
895
PyModule_AddObject(_p->_pythonQtModule, "Qt", (PyObject*)_p->createNewPythonQtMetaObjectWrapper(_p->_qtNamespace));
896
897
if (redirectStdOut) {
898
PythonQtObjectPtr sys;
899
PythonQtObjectPtr out;
900
PythonQtObjectPtr err;
901
sys.setNewRef(PyImport_ImportModule("sys"));
902
// create a redirection object for stdout and stderr
903
out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
904
((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
905
err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
906
((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
907
// replace the built in file objects with our own objects
908
PyModule_AddObject(sys, "stdout", out);
909
PyModule_AddObject(sys, "stderr", err);
910
}
911
}
912
913
void PythonQt::addVariantWrapper(const char* typeName, QObject* wrapper)
914
{
915
_p->addVariantWrapper(typeName, wrapper);
916
}
917
918
919
void PythonQtPrivate::addVariantWrapper(const char* typeName, QObject* wrapper)
920
{
921
int type = QMetaType::type(typeName);
922
PythonQtClassInfo* info = new PythonQtClassInfo(wrapper->metaObject(), typeName);
923
_knownVariantWrappers.insert(type, qMakePair(info, wrapper));
924
addDecorators(wrapper, false, true);
925
PyModule_AddObject(_pythonQtModule, typeName, (PyObject*)createNewPythonQtMetaObjectWrapper(info));
926
}
927
928
PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
929
{
930
if (_p->_initFlags & ExternalHelp) {
931
emit pythonHelpRequest(QByteArray(info->className()));
932
return Py_BuildValue("");
933
} else {
934
return PyString_FromString(info->help().toLatin1().data());
935
}
936
}
937
938