##// END OF EJS Templates
fixed bad reference counting and borrowed references...
florianlink -
r19:4f416979f8bf
parent child
Show More
@@ -1,1116 +1,1117
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtImporter.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include "PythonQtMethodInfo.h"
46 46 #include "PythonQtSignalReceiver.h"
47 47 #include "PythonQtConversion.h"
48 48 #include "PythonQtStdOut.h"
49 49 #include "PythonQtCppWrapperFactory.h"
50 50 #include "PythonQtVariants.h"
51 51 #include "PythonQtStdDecorators.h"
52 52 #include "PythonQtQFileImporter.h"
53 53 #include <pydebug.h>
54 54 #include <vector>
55 55
56 56 PythonQt* PythonQt::_self = NULL;
57 57 int PythonQt::_uniqueModuleCount = 0;
58 58
59 59 void PythonQt::init(int flags)
60 60 {
61 61 if (!_self) {
62 62 _self = new PythonQt(flags);
63 63 }
64 64
65 65 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
66 66 qRegisterMetaType<QList<QObject*> >("QList<void*>");
67 67
68 68 PythonQtRegisterToolClassesTemplateConverter(int);
69 69 PythonQtRegisterToolClassesTemplateConverter(float);
70 70 PythonQtRegisterToolClassesTemplateConverter(double);
71 71 // TODO: which other POD types should be available for QList etc.
72 72
73 73 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
74 74
75 75 PythonQt::self()->registerCPPClass("Qt", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_Qt>);
76 76 PythonQt::self()->registerCPPClass("QBitArray", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QBitArray>);
77 77 PythonQt::self()->registerCPPClass("QDate", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QDate>);
78 78 PythonQt::self()->registerCPPClass("QTime", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QTime>);
79 79 PythonQt::self()->registerCPPClass("QDateTime", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QDateTime>);
80 80 PythonQt::self()->registerCPPClass("QUrl", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QUrl>);
81 81 PythonQt::self()->registerCPPClass("QLocale", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLocale>);
82 82 PythonQt::self()->registerCPPClass("QRect", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRect>);
83 83 PythonQt::self()->registerCPPClass("QRectF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRectF>);
84 84 PythonQt::self()->registerCPPClass("QSize", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QSize>);
85 85 PythonQt::self()->registerCPPClass("QSizeF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QSizeF>);
86 86 PythonQt::self()->registerCPPClass("QLine", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLine>);
87 87 PythonQt::self()->registerCPPClass("QLineF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLineF>);
88 88 PythonQt::self()->registerCPPClass("QPoint", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QPoint>);
89 89 PythonQt::self()->registerCPPClass("QPointF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QPointF>);
90 90 PythonQt::self()->registerCPPClass("QRegExp", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRegExp>);
91 91
92 92 PythonQtRegisterToolClassesTemplateConverter(QDate);
93 93 PythonQtRegisterToolClassesTemplateConverter(QTime);
94 94 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
95 95 PythonQtRegisterToolClassesTemplateConverter(QUrl);
96 96 PythonQtRegisterToolClassesTemplateConverter(QLocale);
97 97 PythonQtRegisterToolClassesTemplateConverter(QRect);
98 98 PythonQtRegisterToolClassesTemplateConverter(QRectF);
99 99 PythonQtRegisterToolClassesTemplateConverter(QSize);
100 100 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
101 101 PythonQtRegisterToolClassesTemplateConverter(QLine);
102 102 PythonQtRegisterToolClassesTemplateConverter(QLineF);
103 103 PythonQtRegisterToolClassesTemplateConverter(QPoint);
104 104 PythonQtRegisterToolClassesTemplateConverter(QPointF);
105 105 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
106 106
107 107 PythonQt::self()->registerCPPClass("QFont", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QFont>);
108 108 PythonQt::self()->registerCPPClass("QPixmap", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPixmap>);
109 109 PythonQt::self()->registerCPPClass("QBrush", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QBrush>);
110 110 PythonQt::self()->registerCPPClass("QColor", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QColor>);
111 111 PythonQt::self()->registerCPPClass("QPalette", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPalette>);
112 112 PythonQt::self()->registerCPPClass("QIcon", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QIcon>);
113 113 PythonQt::self()->registerCPPClass("QImage", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QImage>);
114 114 PythonQt::self()->registerCPPClass("QPolygon", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPolygon>);
115 115 PythonQt::self()->registerCPPClass("QRegion", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QRegion>);
116 116 PythonQt::self()->registerCPPClass("QBitmap", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QBitmap>);
117 117 PythonQt::self()->registerCPPClass("QCursor", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QCursor>);
118 118 PythonQt::self()->registerCPPClass("QSizePolicy", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QSizePolicy>);
119 119 PythonQt::self()->registerCPPClass("QKeySequence", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QKeySequence>);
120 120 PythonQt::self()->registerCPPClass("QPen", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPen>);
121 121 PythonQt::self()->registerCPPClass("QTextLength", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QTextLength>);
122 122 PythonQt::self()->registerCPPClass("QTextFormat", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QTextFormat>);
123 123 PythonQt::self()->registerCPPClass("QMatrix", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QMatrix>);
124 124
125 125 PythonQtRegisterToolClassesTemplateConverter(QFont);
126 126 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
127 127 PythonQtRegisterToolClassesTemplateConverter(QBrush);
128 128 PythonQtRegisterToolClassesTemplateConverter(QColor);
129 129 PythonQtRegisterToolClassesTemplateConverter(QPalette);
130 130 PythonQtRegisterToolClassesTemplateConverter(QIcon);
131 131 PythonQtRegisterToolClassesTemplateConverter(QImage);
132 132 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
133 133 PythonQtRegisterToolClassesTemplateConverter(QRegion);
134 134 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
135 135 PythonQtRegisterToolClassesTemplateConverter(QCursor);
136 136 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
137 137 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
138 138 PythonQtRegisterToolClassesTemplateConverter(QPen);
139 139 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
140 140 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
141 141 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
142 142
143 143 }
144 144
145 145 void PythonQt::cleanup()
146 146 {
147 147 if (_self) {
148 148 delete _self;
149 149 _self = NULL;
150 150 }
151 151 }
152 152
153 153 PythonQt::PythonQt(int flags)
154 154 {
155 155 _p = new PythonQtPrivate;
156 156 _p->_initFlags = flags;
157 157
158 158 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
159 159
160 160 Py_SetProgramName("PythonQt");
161 161 if (flags & IgnoreSiteModule) {
162 162 // this prevents the automatic importing of Python site files
163 163 Py_NoSiteFlag = 1;
164 164 }
165 165 Py_Initialize();
166 166
167 167 // add our own python object types for qt object slots
168 168 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
169 169 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
170 170 }
171 171 Py_INCREF(&PythonQtSlotFunction_Type);
172 172
173 173 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
174 174 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
175 175 // add our own python object types for classes
176 176 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
177 177 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
178 178 }
179 179 Py_INCREF(&PythonQtClassWrapper_Type);
180 180
181 181 // add our own python object types for CPP instances
182 182 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
183 183 PythonQt::handleError();
184 184 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
185 185 }
186 186 Py_INCREF(&PythonQtInstanceWrapper_Type);
187 187
188 188 // add our own python object types for redirection of stdout
189 189 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
190 190 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
191 191 }
192 192 Py_INCREF(&PythonQtStdOutRedirectType);
193 193
194 194 initPythonQtModule(flags & RedirectStdOut);
195 195
196 196 }
197 197
198 198 PythonQt::~PythonQt() {
199 199 delete _p;
200 200 _p = NULL;
201 201 }
202 202
203 203 PythonQtPrivate::~PythonQtPrivate() {
204 204 delete _defaultImporter;
205 205 _defaultImporter = NULL;
206 206 {
207 207 QHashIterator<QByteArray, PythonQtSlotInfo *> i(_knownQtDecoratorSlots);
208 208 while (i.hasNext()) {
209 209 delete i.next().value();
210 210 }
211 211 }
212 212 {
213 213 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownQtClasses);
214 214 while (i.hasNext()) {
215 215 delete i.next().value();
216 216 }
217 217 }
218 218 {
219 219 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownQtWrapperClasses);
220 220 while (i.hasNext()) {
221 221 delete i.next().value();
222 222 }
223 223 }
224 224 {
225 225 QHashIterator<QByteArray, PythonQtSlotInfo *> i(_constructorSlots);
226 226 while (i.hasNext()) {
227 227 PythonQtSlotInfo* cur = i.next().value();
228 228 while(cur->nextInfo()) {
229 229 PythonQtSlotInfo* next = cur->nextInfo();
230 230 delete cur;
231 231 cur = next;
232 232 }
233 233 delete cur;
234 234 }
235 235 }
236 236 {
237 237 QHashIterator<QByteArray, PythonQtSlotInfo *> i(_destructorSlots);
238 238 while (i.hasNext()) {
239 239 PythonQtSlotInfo* cur = i.next().value();
240 240 while(cur->nextInfo()) {
241 241 PythonQtSlotInfo* next = cur->nextInfo();
242 242 delete cur;
243 243 cur = next;
244 244 }
245 245 delete cur;
246 246 }
247 247 }
248 248 PythonQtConv::global_valueStorage.clear();
249 249 PythonQtConv::global_ptrStorage.clear();
250 250 PythonQtConv::global_variantStorage.clear();
251 251
252 252 PythonQtMethodInfo::cleanupCachedMethodInfos();
253 253 }
254 254
255 255 PythonQtImportFileInterface* PythonQt::importInterface()
256 256 {
257 257 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
258 258 }
259 259
260 260 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
261 261 {
262 262 if (_self->_p->_noLongerWrappedCB) {
263 263 (*_self->_p->_noLongerWrappedCB)(o);
264 264 };
265 265 }
266 266
267 267 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator)
268 268 {
269 269 _p->registerClass(metaobject, package, wrapperCreator);
270 270 }
271 271
272 272 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator)
273 273 {
274 274 // we register all classes in the hierarchy
275 275 const QMetaObject* m = metaobject;
276 276 bool first = true;
277 277 while (m) {
278 278 PythonQtClassInfo* info = _knownQtClasses.value(m->className());
279 279 if (!info) {
280 280 info = createPythonQtClassInfo(m, NULL, package);
281 281 _knownQtClasses.insert(m->className(), info);
282 282 }
283 283 if (first) {
284 284 first = false;
285 285 if (wrapperCreator) {
286 286 info->setDecoratorProvider(wrapperCreator);
287 287 }
288 288 }
289 289 m = m->superClass();
290 290 }
291 291 }
292 292
293 293 PythonQtClassInfo* PythonQtPrivate::createPythonQtClassInfo(const QMetaObject* meta, const char* cppClassName, const char* package)
294 294 {
295 295 PythonQtClassInfo* info = new PythonQtClassInfo(meta, cppClassName);
296 PythonQtObjectPtr pack = packageByName(package);
296 PyObject* pack = packageByName(package);
297 297 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, package);
298 298 PyModule_AddObject(pack, meta?meta->className():cppClassName, pyobj);
299 299 if (package && strncmp(package,"Qt",2)==0) {
300 // since PyModule_AddObject steals the reference, we need a incref once more...
301 Py_INCREF(pyobj);
300 302 // put all qt objects into Qt as well
301 PythonQtObjectPtr pack = packageByName("Qt");
302 PyModule_AddObject(pack, meta?meta->className():cppClassName, pyobj);
303 PyModule_AddObject(packageByName("Qt"), meta?meta->className():cppClassName, pyobj);
303 304 }
304 305 info->setPythonQtClassWrapper(pyobj);
305 306 return info;
306 307 }
307 308
308 309 bool PythonQtPrivate::isEnumType(const QMetaObject* meta, const QByteArray& name) {
309 310 int i = meta?meta->indexOfEnumerator(name.constData()):-1;
310 311 if (i!=-1) {
311 312 return true;
312 313 } else {
313 314 // look for scope
314 315 int scopePos = name.indexOf("::");
315 316 if (scopePos != -1) {
316 317 // slit into scope and enum name
317 318 QByteArray enumScope = name.mid(0,scopePos);
318 319 QByteArray enumName = name.mid(scopePos+2);
319 320 if (enumScope == "Qt") {
320 321 // special qt namespace case
321 322 return isEnumType(&staticQtMetaObject, enumName);
322 323 } else {
323 324 // look for known classes as scope
324 325 // TODO: Q_GADGETS are not yet handled
325 326 PythonQtClassInfo* info = _knownQtClasses.value(enumScope);
326 327 if (info) {
327 328 return isEnumType(info->metaObject(), enumName);
328 329 }
329 330 }
330 331 }
331 332 }
332 333 return false;
333 334 }
334 335
335 336 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
336 337 {
337 338 if (!obj) {
338 339 Py_INCREF(Py_None);
339 340 return Py_None;
340 341 }
341 342 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
342 343 if (!wrap) {
343 344 // smuggling it in...
344 345 PythonQtClassInfo* classInfo = _knownQtClasses.value(obj->metaObject()->className());
345 346 if (!classInfo) {
346 347 registerClass(obj->metaObject());
347 348 classInfo = _knownQtClasses.value(obj->metaObject()->className());
348 349 }
349 350 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
350 351 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
351 352 } else {
352 353 Py_INCREF(wrap);
353 354 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
354 355 }
355 356 return (PyObject*)wrap;
356 357 }
357 358
358 359 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
359 360 {
360 361 if (!ptr) {
361 362 Py_INCREF(Py_None);
362 363 return Py_None;
363 364 }
364 365 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
365 366 if (!wrap) {
366 367 PythonQtClassInfo* info = _knownQtClasses.value(name);
367 368 if (!info) {
368 369 // we do not know the metaobject yet, but we might know it by it's name:
369 370 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
370 371 // yes, we know it, so we can convert to QObject
371 372 QObject* qptr = (QObject*)ptr;
372 373 registerClass(qptr->metaObject());
373 374 info = _knownQtClasses.value(qptr->metaObject()->className());
374 375 }
375 376 }
376 377 if (info) {
377 378 QObject* qptr = (QObject*)ptr;
378 379 // if the object is a derived object, we want to switch the class info to the one of the derived class:
379 380 if (name!=(qptr->metaObject()->className())) {
380 381 registerClass(qptr->metaObject());
381 382 info = _knownQtClasses.value(qptr->metaObject()->className());
382 383 }
383 384 wrap = createNewPythonQtInstanceWrapper(qptr, info);
384 385 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
385 386 } else {
386 387 // maybe it is a PyObject, which we can return directly
387 388 if (name == "PyObject") {
388 389 PyObject* p = (PyObject*)ptr;
389 390 Py_INCREF(p);
390 391 return p;
391 392 }
392 393 // not a known QObject, so try our wrapper factory:
393 394 QObject* wrapper = NULL;
394 395 for (int i=0; i<_cppWrapperFactories.size(); i++) {
395 396 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
396 397 if (wrapper) {
397 398 break;
398 399 }
399 400 }
400 401 PythonQtClassInfo* info = _knownQtWrapperClasses.value(name);
401 402 if (!info) {
402 403 registerCPPClass(name.constData());
403 404 info = _knownQtWrapperClasses.value(name);
404 405 }
405 406 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
406 407 info->setMetaObject(wrapper->metaObject());
407 408 }
408 409 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
409 410 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
410 411 }
411 412 } else {
412 413 Py_INCREF(wrap);
413 414 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
414 415 }
415 416 return (PyObject*)wrap;
416 417 }
417 418
418 419 PyObject* PythonQtPrivate::dummyTuple() {
419 420 static PyObject* dummyTuple = NULL;
420 421 if (dummyTuple==NULL) {
421 422 dummyTuple = PyTuple_New(1);
422 423 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
423 424 }
424 425 return dummyTuple;
425 426 }
426 427
427 428
428 429 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
429 430 // call the associated class type to create a new instance...
430 431 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
431 432
432 433 result->setQObject(obj);
433 434 result->_wrappedPtr = wrappedPtr;
434 435 result->_ownedByPythonQt = false;
435 436 result->_useQMetaTypeDestroy = false;
436 437
437 438 if (wrappedPtr) {
438 439 _wrappedObjects.insert(wrappedPtr, result);
439 440 } else {
440 441 _wrappedObjects.insert(obj, result);
441 442 if (obj->parent()== NULL && _wrappedCB) {
442 443 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
443 444 (*_wrappedCB)(obj);
444 445 }
445 446 }
446 447 return result;
447 448 }
448 449
449 450 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package) {
450 451 PythonQtClassWrapper* result;
451 452
452 453 PyObject* className = PyString_FromString(info->className());
453 454
454 455 PyObject* baseClasses = PyTuple_New(1);
455 456 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
456 457
457 458 PyObject* typeDict = PyDict_New();
458 459 QByteArray moduleName("PythonQt");
459 460 if (package && strcmp(package, "")!=0) {
460 461 moduleName += ".";
461 462 moduleName += package;
462 463 }
463 464 PyDict_SetItemString(typeDict, "__module__", PyString_FromString(moduleName.constData()));
464 465
465 466 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
466 467
467 468 // set the class info so that PythonQtClassWrapper_new can read it
468 469 _currentClassInfoForClassWrapperCreation = info;
469 470 // create the new type object by calling the type
470 471 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
471 472
472 473 Py_DECREF(baseClasses);
473 474 Py_DECREF(typeDict);
474 475 Py_DECREF(args);
475 476 Py_DECREF(className);
476 477
477 //TODO XXX why is this incref needed? It looks like the types get garbage collected somehow?!
478 Py_INCREF((PyObject*)result);
479 478 return result;
480 479 }
481 480
482 481
483 482 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
484 483 {
485 484 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
486 485 if (!r) {
487 486 r = new PythonQtSignalReceiver(obj);
488 487 _p->_signalReceivers.insert(obj, r);
489 488 }
490 489 return r;
491 490 }
492 491
493 492 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
494 493 {
495 494 bool flag = false;
496 495 PythonQtObjectPtr callable = lookupCallable(module, objectname);
497 496 if (callable) {
498 497 PythonQtSignalReceiver* r = getSignalReceiver(obj);
499 498 flag = r->addSignalHandler(signal, callable);
500 499 if (!flag) {
501 500 // signal not found
502 501 }
503 502 } else {
504 503 // callable not found
505 504 }
506 505 return flag;
507 506 }
508 507
509 508 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
510 509 {
511 510 bool flag = false;
512 511 PythonQtSignalReceiver* r = getSignalReceiver(obj);
513 512 if (r) {
514 513 flag = r->addSignalHandler(signal, receiver);
515 514 }
516 515 return flag;
517 516 }
518 517
519 518 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
520 519 {
521 520 bool flag = false;
522 521 PythonQtObjectPtr callable = lookupCallable(module, objectname);
523 522 if (callable) {
524 523 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
525 524 if (r) {
526 525 flag = r->removeSignalHandler(signal, callable);
527 526 }
528 527 } else {
529 528 // callable not found
530 529 }
531 530 return flag;
532 531 }
533 532
534 533 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
535 534 {
536 535 bool flag = false;
537 536 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
538 537 if (r) {
539 538 flag = r->removeSignalHandler(signal, receiver);
540 539 }
541 540 return flag;
542 541 }
543 542
544 543 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
545 544 {
546 545 PythonQtObjectPtr p = lookupObject(module, name);
547 546 if (p) {
548 547 if (PyCallable_Check(p)) {
549 548 return p;
550 549 }
551 550 }
552 551 PyErr_Clear();
553 552 return NULL;
554 553 }
555 554
556 555 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
557 556 {
558 557 QStringList l = name.split('.');
559 558 PythonQtObjectPtr p = module;
560 559 PythonQtObjectPtr prev;
561 560 QString s;
562 561 QByteArray b;
563 562 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
564 563 prev = p;
565 564 b = (*i).toLatin1();
566 565 p.setNewRef(PyObject_GetAttrString(p, b.data()));
567 566 }
568 567 PyErr_Clear();
569 568 return p;
570 569 }
571 570
572 571 PythonQtObjectPtr PythonQt::getMainModule() {
573 572 //both borrowed
574 573 PythonQtObjectPtr dict = PyImport_GetModuleDict();
575 574 return PyDict_GetItemString(dict, "__main__");
576 575 }
577 576
578 577 QVariant PythonQt::evalCode(PyObject* module, PyObject* pycode) {
579 578 QVariant result;
580 579 if (pycode) {
581 580 PyObject* r = PyEval_EvalCode((PyCodeObject*)pycode, PyModule_GetDict((PyObject*)module) , PyModule_GetDict((PyObject*)module));
582 581 if (r) {
583 582 result = PythonQtConv::PyObjToQVariant(r);
584 583 Py_DECREF(r);
585 584 } else {
586 585 handleError();
587 586 }
588 587 } else {
589 588 handleError();
590 589 }
591 590 return result;
592 591 }
593 592
594 593 QVariant PythonQt::evalScript(PyObject* module, const QString& script, int start)
595 594 {
596 595 QVariant result;
597 596 PythonQtObjectPtr p;
598 597 p.setNewRef(PyRun_String(script.toLatin1().data(), start, PyModule_GetDict(module), PyModule_GetDict(module)));
599 598 if (p) {
600 599 result = PythonQtConv::PyObjToQVariant(p);
601 600 } else {
602 601 handleError();
603 602 }
604 603 return result;
605 604 }
606 605
607 606 void PythonQt::evalFile(PyObject* module, const QString& filename)
608 607 {
609 608 PythonQtObjectPtr code = parseFile(filename);
610 609 if (code) {
611 610 evalCode(module, code);
612 611 } else {
613 612 handleError();
614 613 }
615 614 }
616 615
617 616 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
618 617 {
619 618 PythonQtObjectPtr p;
620 619 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
621 620 if (!p) {
622 621 handleError();
623 622 }
624 623 return p;
625 624 }
626 625
627 626 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
628 627 {
629 628 PythonQtObjectPtr code = parseFile(filename);
630 629 PythonQtObjectPtr module = _p->createModule(name, code);
631 630 return module;
632 631 }
633 632
634 633 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
635 634 {
636 635 PyErr_Clear();
637 636 QString scriptCode = script;
638 637 if (scriptCode.isEmpty()) {
639 638 // we always need at least a linefeed
640 639 scriptCode = "\n";
641 640 }
642 641 PythonQtObjectPtr pycode;
643 642 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
644 643 PythonQtObjectPtr module = _p->createModule(name, pycode);
645 644 return module;
646 645 }
647 646
648 647 PythonQtObjectPtr PythonQt::createUniqueModule()
649 648 {
650 649 static QString pyQtStr("PythonQt_module");
651 650 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
652 651 return createModuleFromScript(moduleName);
653 652 }
654 653
655 654 void PythonQt::addObject(PyObject* module, const QString& name, QObject* object)
656 655 {
657 656 PyModule_AddObject(module, name.toLatin1().data(), _p->wrapQObject(object));
658 657 }
659 658
660 659 void PythonQt::addVariable(PyObject* module, const QString& name, const QVariant& v)
661 660 {
662 661 PyModule_AddObject(module, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
663 662 }
664 663
665 664 void PythonQt::removeVariable(PyObject* module, const QString& name)
666 665 {
667 666 PyObject_DelAttrString(module, name.toLatin1().data());
668 667 }
669 668
670 669 QVariant PythonQt::getVariable(PyObject* module, const QString& objectname)
671 670 {
672 671 QVariant result;
673 672 PythonQtObjectPtr obj = lookupObject(module, objectname);
674 673 if (obj) {
675 674 result = PythonQtConv::PyObjToQVariant(obj);
676 675 }
677 676 return result;
678 677 }
679 678
680 679 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
681 680 {
682 681 QStringList results;
683 682
684 683 PythonQtObjectPtr object;
685 684 if (objectname.isEmpty()) {
686 685 object = module;
687 686 } else {
688 687 object = lookupObject(module, objectname);
689 688 if (!object && type == CallOverloads) {
690 689 PyObject* dict = lookupObject(module, "__builtins__");
691 690 if (dict) {
692 691 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
693 692 }
694 693 }
695 694 }
696 695
697 696 if (object) {
698 697 if (type == CallOverloads) {
699 698 if (PythonQtSlotFunction_Check(object)) {
700 699 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
701 700 PythonQtSlotInfo* info = o->m_ml;
702 701
703 702 while (info) {
704 703 results << info->fullSignature(info->isInstanceDecorator());
705 704 info = info->nextInfo();
706 705 }
707 706 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
708 707 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
709 708 PythonQtSlotInfo* info = o->classInfo()->constructors();
710 709
711 710 while (info) {
712 711 results << info->fullSignature(false);
713 712 info = info->nextInfo();
714 713 }
715 714 } else {
716 715 //TODO: use pydoc!
717 716 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
718 717 if (doc) {
719 718 results << PyString_AsString(doc);
720 719 Py_DECREF(doc);
721 720 }
722 721 }
723 722 } else {
724 723 PyObject* keys = PyObject_Dir(object);
725 724 if (keys) {
726 725 int count = PyList_Size(keys);
727 726 PyObject* key;
728 727 PyObject* value;
729 728 QString keystr;
730 729 for (int i = 0;i<count;i++) {
731 730 key = PyList_GetItem(keys,i);
732 731 value = PyObject_GetAttr(object, key);
733 732 if (!value) continue;
734 733 keystr = PyString_AsString(key);
735 734 static const QString underscoreStr("__tmp");
736 735 if (!keystr.startsWith(underscoreStr)) {
737 736 switch (type) {
738 737 case Anything:
739 738 results << keystr;
740 739 break;
741 740 case Class:
742 741 if (value->ob_type == &PyClass_Type) {
743 742 results << keystr;
744 743 }
745 744 break;
746 745 case Variable:
747 746 if (value->ob_type != &PyClass_Type
748 747 && value->ob_type != &PyCFunction_Type
749 748 && value->ob_type != &PyFunction_Type
750 749 && value->ob_type != &PyModule_Type
751 750 ) {
752 751 results << keystr;
753 752 }
754 753 break;
755 754 case Function:
756 755 if (value->ob_type == &PyFunction_Type ||
757 756 value->ob_type == &PyMethod_Type
758 757 ) {
759 758 results << keystr;
760 759 }
761 760 break;
762 761 case Module:
763 762 if (value->ob_type == &PyModule_Type) {
764 763 results << keystr;
765 764 }
766 765 break;
767 766 default:
768 767 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
769 768 }
770 769 }
771 770 Py_DECREF(value);
772 771 }
773 772 Py_DECREF(keys);
774 773 }
775 774 }
776 775 }
777 776 return results;
778 777 }
779 778
780 779 QVariant PythonQt::call(PyObject* module, const QString& name, const QVariantList& args)
781 780 {
782 781 QVariant r;
783 782
784 783 PythonQtObjectPtr callable = lookupCallable(module, name);
785 784 if (callable) {
786 785 PythonQtObjectPtr pargs;
787 786 int count = args.size();
788 787 if (count>0) {
789 788 pargs.setNewRef(PyTuple_New(count));
790 789 }
791 790 bool err = false;
792 791 // transform QVariants to Python
793 792 for (int i = 0; i < count; i++) {
794 793 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
795 794 if (arg) {
796 795 // steals reference, no unref
797 796 PyTuple_SetItem(pargs, i,arg);
798 797 } else {
799 798 err = true;
800 799 break;
801 800 }
802 801 }
803 802
804 803 if (!err) {
805 804 PyErr_Clear();
806 805 PythonQtObjectPtr result;
807 806 result.setNewRef(PyObject_CallObject(callable, pargs));
808 807 if (result) {
809 808 // ok
810 809 r = PythonQtConv::PyObjToQVariant(result);
811 810 } else {
812 811 PythonQt::self()->handleError();
813 812 }
814 813 }
815 814 }
816 815 return r;
817 816 }
818 817
819 818 void PythonQt::addInstanceDecorators(QObject* o)
820 819 {
821 820 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
822 821 }
823 822
824 823 void PythonQt::addClassDecorators(QObject* o)
825 824 {
826 825 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
827 826 }
828 827
829 828 void PythonQt::addDecorators(QObject* o)
830 829 {
831 830 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
832 831 }
833 832
834 833 void PythonQt::registerQObjectClassNames(const QStringList& names)
835 834 {
836 835 _p->registerQObjectClassNames(names);
837 836 }
838 837
839 838 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
840 839 {
841 840 PythonQtImport::init();
842 841 _p->_importInterface = importInterface;
843 842 }
844 843
845 844 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
846 845 {
847 846 _p->_importIgnorePaths = paths;
848 847 }
849 848
850 849 const QStringList& PythonQt::getImporterIgnorePaths()
851 850 {
852 851 return _p->_importIgnorePaths;
853 852 }
854 853
855 854 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
856 855 {
857 856 _p->_cppWrapperFactories.append(factory);
858 857 }
859 858
860 859 //---------------------------------------------------------------------------------------------------
861 860 PythonQtPrivate::PythonQtPrivate()
862 861 {
863 862 _importInterface = NULL;
864 863 _defaultImporter = new PythonQtQFileImporter;
865 864 _noLongerWrappedCB = NULL;
866 865 _wrappedCB = NULL;
867 866 _currentClassInfoForClassWrapperCreation = NULL;
868 867 }
869 868
870 869 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
871 870 {
872 871 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
873 872 _currentClassInfoForClassWrapperCreation = NULL;
874 873 return info;
875 874 }
876 875
877 876 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
878 877 {
879 878 o->setParent(this);
880 879 int numMethods = o->metaObject()->methodCount();
881 880 for (int i = 0; i < numMethods; i++) {
882 881 QMetaMethod m = o->metaObject()->method(i);
883 882 if ((m.methodType() == QMetaMethod::Method ||
884 883 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
885 884 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m);
886 885 if (qstrncmp(m.signature(), "new_", 4)==0) {
887 886 if ((decoTypes & ConstructorDecorator) == 0) continue;
888 887 // either it returns a * or a QVariant and the name starts with "new_"
889 888 bool isVariantReturn = info->parameters().at(0).typeId == PythonQtMethodInfo::Variant;
890 889 if ((info->parameters().at(0).isPointer || isVariantReturn)) {
891 890 QByteArray signature = m.signature();
892 891 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
893 892 PythonQtSlotInfo* prev = _constructorSlots.value(nameOfClass);
894 893 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
895 894 if (prev) {
896 895 newSlot->setNextInfo(prev->nextInfo());
897 896 prev->setNextInfo(newSlot);
898 897 } else {
899 898 _constructorSlots.insert(nameOfClass, newSlot);
900 899 }
901 900 }
902 901 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
903 902 if ((decoTypes & DestructorDecorator) == 0) continue;
904 903 QByteArray signature = m.signature();
905 904 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
906 905 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
907 906 _destructorSlots.insert(nameOfClass, newSlot);
908 907 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
909 908 if ((decoTypes & StaticDecorator) == 0) continue;
910 909 QByteArray signature = m.signature();
911 910 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
912 911 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
913 912 PythonQtSlotInfo* slotCopy = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
914 913 _knownQtDecoratorSlots.insert(nameOfClass, slotCopy);
915 914 } else {
916 915 if ((decoTypes & InstanceDecorator) == 0) continue;
917 916 if (info->parameters().count()>1) {
918 917 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
919 918 if (p.isPointer) {
920 919 PythonQtSlotInfo* slotCopy = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::InstanceDecorator);
921 920 _knownQtDecoratorSlots.insert(p.name, slotCopy);
922 921 }
923 922 }
924 923 }
925 924 }
926 925 }
927 926 }
928 927
929 928 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
930 929 {
931 930 foreach(QString name, names) {
932 931 _knownQObjectClassNames.insert(name.toLatin1(), true);
933 932 }
934 933 }
935 934
936 935 QList<PythonQtSlotInfo*> PythonQtPrivate::getDecoratorSlots(const QByteArray& className)
937 936 {
938 937 return _knownQtDecoratorSlots.values(className);
939 938 }
940 939
941 940 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
942 941 {
943 942 _signalReceivers.remove(obj);
944 943 }
945 944
946 945 bool PythonQt::handleError()
947 946 {
948 947 bool flag = false;
949 948 if (PyErr_Occurred()) {
950 949
951 950 // currently we just print the error and the stderr handler parses the errors
952 951 PyErr_Print();
953 952
954 953 /*
955 954 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
956 955 PyObject *ptype;
957 956 PyObject *pvalue;
958 957 PyObject *ptraceback;
959 958 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
960 959
961 960 Py_XDECREF(ptype);
962 961 Py_XDECREF(pvalue);
963 962 Py_XDECREF(ptraceback);
964 963 */
965 964 PyErr_Clear();
966 965 flag = true;
967 966 }
968 967 return flag;
969 968 }
970 969
971 970 void PythonQt::addSysPath(const QString& path)
972 971 {
973 972 PythonQtObjectPtr sys;
974 973 sys.setNewRef(PyImport_ImportModule("sys"));
975 974 PythonQtObjectPtr obj = lookupObject(sys, "path");
976 975 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
977 976 }
978 977
979 978 void PythonQt::overwriteSysPath(const QStringList& paths)
980 979 {
981 980 PythonQtObjectPtr sys;
982 981 sys.setNewRef(PyImport_ImportModule("sys"));
983 982 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
984 983 }
985 984
986 985 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
987 986 {
988 987 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
989 988 }
990 989
991 990 void PythonQt::stdOutRedirectCB(const QString& str)
992 991 {
993 992 emit PythonQt::self()->pythonStdOut(str);
994 993 }
995 994
996 995 void PythonQt::stdErrRedirectCB(const QString& str)
997 996 {
998 997 emit PythonQt::self()->pythonStdErr(str);
999 998 }
1000 999
1001 1000 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1002 1001 {
1003 1002 _p->_wrappedCB = cb;
1004 1003 }
1005 1004
1006 1005 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1007 1006 {
1008 1007 _p->_noLongerWrappedCB = cb;
1009 1008 }
1010 1009
1011 1010
1012 1011
1013 1012 static PyMethodDef PythonQtMethods[] = {
1014 1013 {NULL, NULL, 0, NULL}
1015 1014 };
1016 1015
1017 1016 void PythonQt::initPythonQtModule(bool redirectStdOut)
1018 1017 {
1019 _p->_pythonQtModule.setNewRef(Py_InitModule("PythonQt", PythonQtMethods));
1018 _p->_pythonQtModule = Py_InitModule("PythonQt", PythonQtMethods);
1020 1019
1021 1020 if (redirectStdOut) {
1022 1021 PythonQtObjectPtr sys;
1023 1022 PythonQtObjectPtr out;
1024 1023 PythonQtObjectPtr err;
1025 1024 sys.setNewRef(PyImport_ImportModule("sys"));
1026 1025 // create a redirection object for stdout and stderr
1027 1026 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1028 1027 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1029 1028 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1030 1029 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1031 1030 // replace the built in file objects with our own objects
1032 1031 PyModule_AddObject(sys, "stdout", out);
1033 1032 PyModule_AddObject(sys, "stderr", err);
1034 1033 }
1035 1034 }
1036 1035
1037 1036 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator)
1038 1037 {
1039 1038 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator);
1040 1039 }
1041 1040
1042 1041
1043 1042 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator)
1044 1043 {
1045 1044 PythonQtClassInfo* info = _knownQtWrapperClasses.value(typeName);
1046 1045 if (!info) {
1047 1046 info = createPythonQtClassInfo(NULL, typeName, package);
1048 1047 _knownQtWrapperClasses.insert(typeName, info);
1049 1048 }
1050 1049 if (parentTypeName) {
1051 1050 info->setWrappedParentClassName(parentTypeName);
1052 1051 }
1053 1052 if (wrapperCreator) {
1054 1053 info->setDecoratorProvider(wrapperCreator);
1055 1054 }
1056 1055 }
1057 1056
1058 PythonQtObjectPtr PythonQtPrivate::packageByName(const char* name)
1057 PyObject* PythonQtPrivate::packageByName(const char* name)
1059 1058 {
1060 1059 if (name==NULL || name[0]==0) {
1061 1060 return _pythonQtModule;
1062 1061 }
1063 PythonQtObjectPtr v = _packages.value(name);
1062 PyObject* v = _packages.value(name);
1064 1063 if (!v) {
1065 v.setNewRef(PyImport_AddModule((QByteArray("PythonQt.") + name).constData()));
1064 v = PyImport_AddModule((QByteArray("PythonQt.") + name).constData());
1066 1065 _packages.insert(name, v);
1066 // AddObject steals the reference, so increment it!
1067 Py_INCREF(v);
1067 1068 PyModule_AddObject(_pythonQtModule, name, v);
1068 1069 }
1069 1070 return v;
1070 1071 }
1071 1072
1072 1073
1073 1074 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1074 1075 {
1075 1076 if (_p->_initFlags & ExternalHelp) {
1076 1077 emit pythonHelpRequest(QByteArray(info->className()));
1077 1078 return Py_BuildValue("");
1078 1079 } else {
1079 1080 return PyString_FromString(info->help().toLatin1().data());
1080 1081 }
1081 1082 }
1082 1083
1083 1084 void PythonQtPrivate::removeWrapperPointer(void* obj)
1084 1085 {
1085 1086 _wrappedObjects.remove(obj);
1086 1087 }
1087 1088
1088 1089 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1089 1090 {
1090 1091 _wrappedObjects.insert(obj, wrapper);
1091 1092 }
1092 1093
1093 1094 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1094 1095 {
1095 1096 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1096 1097 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1097 1098 // this is a wrapper whose QObject was already removed due to destruction
1098 1099 // so the obj pointer has to be a new QObject with the same address...
1099 1100 // we remove the old one and set the copy to NULL
1100 1101 wrap->_objPointerCopy = NULL;
1101 1102 removeWrapperPointer(obj);
1102 1103 wrap = NULL;
1103 1104 }
1104 1105 return wrap;
1105 1106 }
1106 1107
1107 1108 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1108 1109 {
1109 1110 PythonQtObjectPtr result;
1110 1111 if (pycode) {
1111 1112 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1112 1113 } else {
1113 1114 PythonQt::self()->handleError();
1114 1115 }
1115 1116 return result;
1116 1117 }
@@ -1,508 +1,508
1 1 #ifndef _PYTHONQT_H
2 2 #define _PYTHONQT_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQt.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46 #include "PythonQtInstanceWrapper.h"
47 47 #include "PythonQtClassWrapper.h"
48 48 #include "PythonQtSlot.h"
49 49 #include "PythonQtObjectPtr.h"
50 50 #include <QObject>
51 51 #include <QVariant>
52 52 #include <QList>
53 53 #include <QHash>
54 54 #include <QByteArray>
55 55 #include <QStringList>
56 56 #include <QtDebug>
57 57 #include <iostream>
58 58
59 59
60 60 class PythonQtClassInfo;
61 61 class PythonQtPrivate;
62 62 class PythonQtMethodInfo;
63 63 class PythonQtSignalReceiver;
64 64 class PythonQtImportFileInterface;
65 65 class PythonQtCppWrapperFactory;
66 66 class PythonQtQFileImporter;
67 67
68 68 typedef void PythonQtQObjectWrappedCB(QObject* object);
69 69 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
70 70
71 71 //! callback to create a QObject lazyly
72 72 typedef QObject* PythonQtQObjectCreatorFunctionCB();
73 73
74 74 //! helper template to create a derived QObject class
75 75 template<class T> QObject* PythonQtCreateObject() { return new T(); };
76 76
77 77 //! the main interface to the Python Qt binding, realized as a singleton
78 78 class PYTHONQT_EXPORT PythonQt : public QObject {
79 79
80 80 Q_OBJECT
81 81
82 82 public:
83 83 enum InitFlags {
84 84 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
85 85 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
86 86 ExternalHelp = 4 //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
87 87 };
88 88
89 89 //! initialize the python qt binding (flags are a or combination of InitFlags)
90 90 static void init(int flags = IgnoreSiteModule | RedirectStdOut);
91 91
92 92 //! cleanup
93 93 static void cleanup();
94 94
95 95 //! get the singleton instance
96 96 static PythonQt* self() { return _self; }
97 97
98 98 //-----------------------------------------------------------------------------
99 99 // Public API:
100 100
101 101 //! defines the object types for introspection
102 102 enum ObjectType {
103 103 Class,
104 104 Function,
105 105 Variable,
106 106 Module,
107 107 Anything,
108 108 CallOverloads
109 109 };
110 110
111 111 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
112 112 void overwriteSysPath(const QStringList& paths);
113 113
114 114 //! prepend a path to sys.path to allow importing from it
115 115 void addSysPath(const QString& path);
116 116
117 117 //! sets the __path__ list of a module to the given list (important for local imports)
118 118 void setModuleImportPath(PyObject* module, const QStringList& paths);
119 119
120 120 //! get the __main__ module of python
121 121 PythonQtObjectPtr getMainModule();
122 122
123 123 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
124 124 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
125 125 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
126 126 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL);
127 127
128 128 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
129 129 //! (ownership of wrapper is passed to PythonQt)
130 130 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
131 131
132 132 This will add a wrapper object that is used to make calls to the given classname \c typeName.
133 133 All slots that take a pointer to typeName as the first argument will be callable from Python on
134 134 a variant object that contains such a type.
135 135 */
136 136 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL);
137 137
138 138 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
139 139 //! and it will register the classes when it first sees a pointer to such a derived class
140 140 void registerQObjectClassNames(const QStringList& names);
141 141
142 142 //! parses the given file and returns the python code object, this can then be used to call evalCode()
143 143 PythonQtObjectPtr parseFile(const QString& filename);
144 144
145 145 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
146 146 //! If pycode is NULL, a python error is printed.
147 147 QVariant evalCode(PyObject* module, PyObject* pycode);
148 148
149 149 //! evaluates the given script code and returns the result value
150 150 QVariant evalScript(PyObject* module, const QString& script, int start = Py_file_input);
151 151
152 152 //! evaluates the given script code from file
153 153 void evalFile(PyObject* module, const QString& filename);
154 154
155 155 //! creates the new module \c name and evaluates the given file in the context of that module
156 156 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
157 157 //! to a module later on.
158 158 //! The user needs to make sure that the \c name is unique in the python module dictionary.
159 159 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
160 160
161 161 //! creates the new module \c name and evaluates the given script in the context of that module.
162 162 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
163 163 //! to a module later on.
164 164 //! The user needs to make sure that the \c name is unique in the python module dictionary.
165 165 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
166 166
167 167 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
168 168 //! script code
169 169 PythonQtObjectPtr createUniqueModule();
170 170
171 171 //@{ Signal handlers
172 172
173 173 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
174 174 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
175 175
176 176 //! remove a signal handler from the given \c signal of \c obj
177 177 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
178 178
179 179 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
180 180 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
181 181
182 182 //! remove a signal handler from the given \c signal of \c obj
183 183 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
184 184
185 185 //@}
186 186
187 187 //@{ Variable access
188 188
189 189 //! add the given \c object to the \c module as a variable with \c name (it can be removed via clearVariable)
190 190 void addObject(PyObject* module, const QString& name, QObject* object);
191 191
192 192 //! add the given variable to the module
193 193 void addVariable(PyObject* module, const QString& name, const QVariant& v);
194 194
195 195 //! remove the given variable
196 196 void removeVariable(PyObject* module, const QString& name);
197 197
198 198 //! get the variable with the \c name of the \c module, returns an invalid QVariant on error
199 199 QVariant getVariable(PyObject* module, const QString& name);
200 200
201 201 //! read vars etc. in scope of a module, optional looking inside of an object \c objectname
202 202 QStringList introspection(PyObject* module, const QString& objectname, ObjectType type);
203 203
204 204 //! returns the found callable object or NULL
205 205 //! @return new reference
206 206 PythonQtObjectPtr lookupCallable(PyObject* module, const QString& name);
207 207
208 208 //@}
209 209
210 210 //@{ Calling of python callables
211 211
212 212 //! call the given python method, returns the result converted to a QVariant
213 213 QVariant call(PyObject* module, const QString& callable, const QVariantList& args = QVariantList());
214 214
215 215 //@}
216 216
217 217 //@{ Decorations, constructors, wrappers...
218 218
219 219
220 220 //! add an object whose slots will be used as decorator slots for
221 221 //! other QObjects or CPP classes. The slots need to follow the
222 222 //! convention that the first argument is a pointer to the wrapped object.
223 223 //! (ownership is passed to PythonQt)
224 224 /*!
225 225 Example:
226 226
227 227 A slot with the signature
228 228
229 229 \code
230 230 bool doSomething(QWidget* w, int a)
231 231 \endcode
232 232
233 233 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
234 234 that will be called with the concrete instance as first argument.
235 235 So in Python you can now e.g. call
236 236
237 237 \code
238 238 someWidget.doSomething(12)
239 239 \endcode
240 240
241 241 without QWidget really having this method. This allows to easily make normal methods
242 242 of Qt classes callable by forwarding them with such decorator slots
243 243 or to make CPP classes (which are not derived from QObject) callable from Python.
244 244 */
245 245 void addInstanceDecorators(QObject* o);
246 246
247 247 //! add an object whose slots will be used as decorator slots for
248 248 //! class objects (ownership is passed to PythonQt)
249 249 /*!
250 250 The slots need to follow the following convention:
251 251 - SomeClass* new_SomeClass(...)
252 252 - QVariant new_SomeClass(...)
253 253 - void delete_SomeClass(SomeClass*)
254 254 - ... static_SomeClass_someName(...)
255 255
256 256 This will add:
257 257 - a constructor
258 258 - a constructor which generates a QVariant
259 259 - a destructor (only useful for CPP objects)
260 260 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
261 261
262 262 */
263 263 void addClassDecorators(QObject* o);
264 264
265 265 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
266 266 void addDecorators(QObject* o);
267 267
268 268 //! add the given factory to PythonQt (ownership stays with caller)
269 269 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
270 270
271 271 //@}
272 272
273 273 //@{ Custom importer (to replace internal import implementation of python)
274 274
275 275 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
276 276 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
277 277 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
278 278 //! This is not reversible, so even setting setImporter(NULL) afterwards will
279 279 //! keep the custom PythonQt importer with a QFile default import interface.
280 280 //! Subsequent python import calls will make use of the passed importInterface
281 281 //! which forwards all import calls to the given \c importInterface.
282 282 //! Passing NULL will install a default QFile importer.
283 283 //! (\c importInterface ownership stays with caller)
284 284 void setImporter(PythonQtImportFileInterface* importInterface);
285 285
286 286 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
287 287 //! (without calling setImporter or installDefaultImporter at least once, the default python import
288 288 //! mechanism is in place)
289 289 //! the default importer allows to import files from anywhere QFile can read from,
290 290 //! including the Qt resource system using ":". Keep in mind that you need to extend
291 291 //! "sys.path" with ":" to be able to import from the Qt resources.
292 292 void installDefaultImporter() { setImporter(NULL); }
293 293
294 294 //! set paths that the importer should ignore
295 295 void setImporterIgnorePaths(const QStringList& paths);
296 296
297 297 //! get paths that the importer should ignore
298 298 const QStringList& getImporterIgnorePaths();
299 299
300 300 //@}
301 301
302 302 //! get access to internal data (should not be used on the public API, but is used by some C functions)
303 303 static PythonQtPrivate* priv() { return _self->_p; }
304 304
305 305 //! get access to the file importer (if set)
306 306 static PythonQtImportFileInterface* importInterface();
307 307
308 308 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
309 309 //! The error is currently just output to the python stderr, future version might implement better trace printing
310 310 bool handleError();
311 311
312 312 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
313 313 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
314 314 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
315 315 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
316 316
317 317 //! call the callback if it is set
318 318 static void qObjectNoLongerWrappedCB(QObject* o);
319 319
320 320 signals:
321 321 //! emitted when python outputs something to stdout (and redirection is turned on)
322 322 void pythonStdOut(const QString& str);
323 323 //! emitted when python outputs something to stderr (and redirection is turned on)
324 324 void pythonStdErr(const QString& str);
325 325
326 326 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
327 327 void pythonHelpRequest(const QByteArray& cppClassName);
328 328
329 329
330 330 public:
331 331 //! called by internal help methods
332 332 PyObject* helpCalled(PythonQtClassInfo* info);
333 333
334 334 //! returns the found object or NULL
335 335 //! @return new reference
336 336 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
337 337
338 338 private:
339 339 void initPythonQtModule(bool redirectStdOut);
340 340
341 341 //! callback for stdout redirection, emits pythonStdOut signal
342 342 static void stdOutRedirectCB(const QString& str);
343 343 //! callback for stderr redirection, emits pythonStdErr signal
344 344 static void stdErrRedirectCB(const QString& str);
345 345
346 346 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
347 347 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
348 348
349 349 PythonQt(int flags);
350 350 ~PythonQt();
351 351
352 352 static PythonQt* _self;
353 353 static int _uniqueModuleCount;
354 354
355 355 PythonQtPrivate* _p;
356 356
357 357 };
358 358
359 359 //! internal PythonQt details
360 360 class PythonQtPrivate : public QObject {
361 361
362 362 Q_OBJECT
363 363
364 364 public:
365 365 PythonQtPrivate();
366 366 ~PythonQtPrivate();
367 367
368 368 enum DecoratorTypes {
369 369 StaticDecorator = 1,
370 370 ConstructorDecorator = 2,
371 371 DestructorDecorator = 4,
372 372 InstanceDecorator = 8,
373 373 AllDecorators = 0xffff
374 374 };
375 375
376 376 //! returns if the id is the id for PythonQtObjectPtr
377 377 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
378 378
379 379 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
380 380 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
381 381 //! remove the wrapper ptr again
382 382 void removeWrapperPointer(void* obj);
383 383
384 384 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
385 385 void removeSignalEmitter(QObject* obj);
386 386
387 387 //! wrap the given QObject into a Python object (or return existing wrapper!)
388 388 PyObject* wrapQObject(QObject* obj);
389 389
390 390 //! 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
391 391 PyObject* wrapPtr(void* ptr, const QByteArray& name);
392 392
393 393 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
394 394 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
395 395 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
396 396 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL);
397 397
398 398 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
399 399 //! (ownership of wrapper is passed to PythonQt)
400 400 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
401 401
402 402 This will add a wrapper object that is used to make calls to the given classname \c typeName.
403 403 All slots that take a pointer to typeName as the first argument will be callable from Python on
404 404 a variant object that contains such a type.
405 405 */
406 406 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL);
407 407
408 408 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
409 409 //! and it will register the classes when it first sees a pointer to such a derived class
410 410 void registerQObjectClassNames(const QStringList& names);
411 411
412 412 //! add a decorator object
413 413 void addDecorators(QObject* o, int decoTypes);
414 414
415 415 //! get list of all slots that are available as decorator slots
416 416 QList<PythonQtSlotInfo*> getDecoratorSlots(const QByteArray& className);
417 417
418 418 //! check if the enum is either part of the \c meta class or contains a scope and is
419 419 //! an enum of another known metaobject (and as last resort, of the Qt namespace)
420 420 bool isEnumType(const QMetaObject* meta, const QByteArray& name);
421 421
422 422 //! helper method that creates a PythonQtClassWrapper object
423 423 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package = NULL);
424 424
425 425 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
426 426 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
427 427
428 428 //! get the class info for a meta object (if available)
429 429 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownQtClasses.value(meta->className()); }
430 430
431 431 //! get the class info for a meta object (if available)
432 432 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownQtClasses.value(className); }
433 433
434 434 //! get the constructor slot for the given classname
435 435 PythonQtSlotInfo* getConstructorSlot(const QByteArray& className) { return _constructorSlots.value(className); }
436 436
437 437 //! get the destructor slot for the given classname
438 438 PythonQtSlotInfo* getDestructorSlot(const QByteArray& className) { return _destructorSlots.value(className); }
439 439
440 440 //! creates the new module from the given pycode
441 441 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
442 442
443 443 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
444 444 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
445 445
446 446 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
447 447 static PyObject* dummyTuple();
448 448
449 449 private:
450 450
451 451 //! create a new class info and python wrapper type
452 452 PythonQtClassInfo* createPythonQtClassInfo(const QMetaObject* meta, const char* cppClassName, const char* package);
453 453
454 //! get/create new package module
455 PythonQtObjectPtr packageByName(const char* name);
454 //! get/create new package module (the returned object is a borrowed reference)
455 PyObject* packageByName(const char* name);
456 456
457 457 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
458 458 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
459 459
460 460 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
461 461 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
462 462
463 463 //! stores the meta info of known Qt classes
464 464 QHash<QByteArray, PythonQtClassInfo *> _knownQtClasses;
465 465
466 466 //! stores the meta info of known Qt classes
467 467 QHash<QByteArray, PythonQtClassInfo *> _knownQtWrapperClasses;
468 468
469 469 //! stores the meta info of known Qt C++ wrapper classes
470 470 QMultiHash<QByteArray, PythonQtSlotInfo *> _knownQtDecoratorSlots;
471 471
472 472 //! names of qobject derived classes that can be casted to qobject savely
473 473 QHash<QByteArray, bool> _knownQObjectClassNames;
474 474
475 475 //! stores signal receivers for QObjects
476 476 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
477 477
478 478 //! the PythonQt python module
479 479 PythonQtObjectPtr _pythonQtModule;
480 480
481 481 //! the importer interface (if set)
482 482 PythonQtImportFileInterface* _importInterface;
483 483
484 484 //! the default importer
485 485 PythonQtQFileImporter* _defaultImporter;
486 486
487 487 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
488 488 PythonQtQObjectWrappedCB* _wrappedCB;
489 489
490 490 QStringList _importIgnorePaths;
491 491
492 492 //! the cpp object wrapper factories
493 493 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
494 494
495 495 QHash<QByteArray , PythonQtSlotInfo *> _constructorSlots;
496 496 QHash<QByteArray , PythonQtSlotInfo *> _destructorSlots;
497 497
498 QHash<QByteArray, PythonQtObjectPtr> _packages;
498 QHash<QByteArray, PyObject*> _packages;
499 499
500 500 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
501 501
502 502 int _initFlags;
503 503 int _PythonQtObjectPtr_metaId;
504 504
505 505 friend class PythonQt;
506 506 };
507 507
508 508 #endif
General Comments 0
You need to be logged in to leave comments. Login now