##// END OF EJS Templates
merged various changes from MeVisLab repository...
florianlink -
r180:a63222bd6a1b
parent child
Show More
@@ -1,1692 +1,1721
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, 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 "PythonQtSignal.h"
47 47 #include "PythonQtSignalReceiver.h"
48 48 #include "PythonQtConversion.h"
49 49 #include "PythonQtStdIn.h"
50 50 #include "PythonQtStdOut.h"
51 51 #include "PythonQtCppWrapperFactory.h"
52 52 #include "PythonQtVariants.h"
53 53 #include "PythonQtStdDecorators.h"
54 54 #include "PythonQtQFileImporter.h"
55 55 #include <pydebug.h>
56 56 #include <vector>
57 57
58 58 PythonQt* PythonQt::_self = NULL;
59 59 int PythonQt::_uniqueModuleCount = 0;
60 60
61 61 void PythonQt_init_QtGuiBuiltin(PyObject*);
62 62 void PythonQt_init_QtCoreBuiltin(PyObject*);
63 63
64 64 void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
65 65 {
66 66 if (!_self) {
67 67 _self = new PythonQt(flags, pythonQtModuleName);
68 68
69 69 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
70 70 qRegisterMetaType<QList<QObject*> >("QList<void*>");
71 71
72 72 PythonQtRegisterToolClassesTemplateConverter(int);
73 73 PythonQtRegisterToolClassesTemplateConverter(float);
74 74 PythonQtRegisterToolClassesTemplateConverter(double);
75 75 PythonQtRegisterToolClassesTemplateConverter(qint32);
76 76 PythonQtRegisterToolClassesTemplateConverter(quint32);
77 77 PythonQtRegisterToolClassesTemplateConverter(qint64);
78 78 PythonQtRegisterToolClassesTemplateConverter(quint64);
79 79 // TODO: which other POD types should be available for QList etc.
80 80
81 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
82
83 81 PythonQt_init_QtCoreBuiltin(NULL);
84 82 PythonQt_init_QtGuiBuiltin(NULL);
85 83
84 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
85 PythonQt::self()->registerCPPClass("QMetaObject",0, "QtCore", PythonQtCreateObject<PythonQtWrapper_QMetaObject>);
86
86 87 PythonQtRegisterToolClassesTemplateConverter(QByteArray);
87 88 PythonQtRegisterToolClassesTemplateConverter(QDate);
88 89 PythonQtRegisterToolClassesTemplateConverter(QTime);
89 90 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
90 91 PythonQtRegisterToolClassesTemplateConverter(QUrl);
91 92 PythonQtRegisterToolClassesTemplateConverter(QLocale);
92 93 PythonQtRegisterToolClassesTemplateConverter(QRect);
93 94 PythonQtRegisterToolClassesTemplateConverter(QRectF);
94 95 PythonQtRegisterToolClassesTemplateConverter(QSize);
95 96 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
96 97 PythonQtRegisterToolClassesTemplateConverter(QLine);
97 98 PythonQtRegisterToolClassesTemplateConverter(QLineF);
98 99 PythonQtRegisterToolClassesTemplateConverter(QPoint);
99 100 PythonQtRegisterToolClassesTemplateConverter(QPointF);
100 101 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
101 102
102 103 PythonQtRegisterToolClassesTemplateConverter(QFont);
103 104 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
104 105 PythonQtRegisterToolClassesTemplateConverter(QBrush);
105 106 PythonQtRegisterToolClassesTemplateConverter(QColor);
106 107 PythonQtRegisterToolClassesTemplateConverter(QPalette);
107 108 PythonQtRegisterToolClassesTemplateConverter(QIcon);
108 109 PythonQtRegisterToolClassesTemplateConverter(QImage);
109 110 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
110 111 PythonQtRegisterToolClassesTemplateConverter(QRegion);
111 112 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
112 113 PythonQtRegisterToolClassesTemplateConverter(QCursor);
113 114 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
114 115 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
115 116 PythonQtRegisterToolClassesTemplateConverter(QPen);
116 117 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
117 118 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
118 119 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
119 120
120 121
121 122 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
122 123 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
123 124 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
124 125 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
125 126 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
126 127 for (unsigned int i = 0;i<16; i++) {
127 128 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
128 129 if (obj) {
129 130 PyModule_AddObject(pack, names[i], obj);
130 131 Py_INCREF(obj);
131 132 PyModule_AddObject(pack2, names[i], obj);
132 133 } else {
133 134 std::cerr << "method not found " << names[i];
134 135 }
135 136 }
136 137 }
137 138 }
138 139
139 140 void PythonQt::cleanup()
140 141 {
141 142 if (_self) {
142 143 delete _self;
143 144 _self = NULL;
144 145 }
145 146 }
146 147
147 148 PythonQt* PythonQt::self() { return _self; }
148 149
149 150 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
150 151 {
151 152 _p = new PythonQtPrivate;
152 153 _p->_initFlags = flags;
153 154
154 155 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
155 156
156 157 if ((flags & PythonAlreadyInitialized) == 0) {
157 158 Py_SetProgramName(const_cast<char*>("PythonQt"));
158 159 if (flags & IgnoreSiteModule) {
159 160 // this prevents the automatic importing of Python site files
160 161 Py_NoSiteFlag = 1;
161 162 }
162 163 Py_Initialize();
163 164 }
164 165
165 166 // add our own python object types for qt object slots
166 167 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
167 168 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
168 169 }
169 170 Py_INCREF(&PythonQtSlotFunction_Type);
170 171
171 172 if (PyType_Ready(&PythonQtSignalFunction_Type) < 0) {
172 173 std::cerr << "could not initialize PythonQtSignalFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
173 174 }
174 175 Py_INCREF(&PythonQtSignalFunction_Type);
175 176
176 177 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
177 178 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
178 179 // add our own python object types for classes
179 180 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
180 181 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
181 182 }
182 183 Py_INCREF(&PythonQtClassWrapper_Type);
183 184
184 185 // add our own python object types for CPP instances
185 186 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
186 187 PythonQt::handleError();
187 188 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
188 189 }
189 190 Py_INCREF(&PythonQtInstanceWrapper_Type);
190 191
191 192 // add our own python object types for redirection of stdout
192 193 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
193 194 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
194 195 }
195 196 Py_INCREF(&PythonQtStdOutRedirectType);
196 197
197 198 // add our own python object types for redirection of stdin
198 199 if (PyType_Ready(&PythonQtStdInRedirectType) < 0) {
199 200 std::cerr << "could not initialize PythonQtStdInRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
200 201 }
201 202 Py_INCREF(&PythonQtStdInRedirectType);
202 203
203 204 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
204 205
205 206 _p->setupSharedLibrarySuffixes();
206 207
207 208 }
208 209
209 210 PythonQt::~PythonQt() {
210 211 delete _p;
211 212 _p = NULL;
212 213 }
213 214
214 215 PythonQtPrivate::~PythonQtPrivate() {
215 216 delete _defaultImporter;
216 217 _defaultImporter = NULL;
217 218
218 219 {
219 220 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
220 221 while (i.hasNext()) {
221 222 delete i.next().value();
222 223 }
223 224 }
224 225 PythonQtConv::global_valueStorage.clear();
225 226 PythonQtConv::global_ptrStorage.clear();
226 227 PythonQtConv::global_variantStorage.clear();
227 228
228 229 PythonQtMethodInfo::cleanupCachedMethodInfos();
229 230 }
230 231
231 232 void PythonQt::setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData)
232 233 {
233 234 if (!callback)
234 235 {
235 236 std::cerr << "PythonQt::setRedirectStdInCallback - callback parameter is NULL !" << std::endl;
236 237 return;
237 238 }
238 239
239 240 PythonQtObjectPtr sys;
240 241 PythonQtObjectPtr in;
241 242 sys.setNewRef(PyImport_ImportModule("sys"));
242 243
243 244 // Backup original 'sys.stdin' if not yet done
244 245 PyRun_SimpleString("if not hasattr(sys, 'pythonqt_original_stdin'):"
245 246 "sys.pythonqt_original_stdin = sys.stdin");
246 247
247 248 in = PythonQtStdInRedirectType.tp_new(&PythonQtStdInRedirectType, NULL, NULL);
248 249 ((PythonQtStdInRedirect*)in.object())->_cb = callback;
249 250 ((PythonQtStdInRedirect*)in.object())->_callData = callbackData;
250 251 // replace the built in file objects with our own objects
251 252 PyModule_AddObject(sys, "stdin", in);
252 253
253 254 // Backup custom 'stdin' into 'pythonqt_stdin'
254 255 PyRun_SimpleString("sys.pythonqt_stdin = sys.stdin");
255 256 }
256 257
257 258 void PythonQt::setRedirectStdInCallbackEnabled(bool enabled)
258 259 {
259 260 if (enabled)
260 261 {
261 262 PyRun_SimpleString("if hasattr(sys, 'pythonqt_stdin'):"
262 263 "sys.stdin = sys.pythonqt_stdin");
263 264 }
264 265 else
265 266 {
266 267 PyRun_SimpleString("if hasattr(sys,'pythonqt_original_stdin'):"
267 268 "sys.stdin = sys.pythonqt_original_stdin");
268 269 }
269 270 }
270 271
271 272 PythonQtImportFileInterface* PythonQt::importInterface()
272 273 {
273 274 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
274 275 }
275 276
276 277 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
277 278 {
278 279 if (_self->_p->_noLongerWrappedCB) {
279 280 (*_self->_p->_noLongerWrappedCB)(o);
280 281 };
281 282 }
282 283
283 284 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
284 285 {
285 286 _p->registerClass(metaobject, package, wrapperCreator, shell);
286 287 }
287 288
288 289 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
289 290 {
290 291 // we register all classes in the hierarchy
291 292 const QMetaObject* m = metaobject;
292 293 bool first = true;
293 294 while (m) {
294 295 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
295 296 if (!info->pythonQtClassWrapper()) {
296 297 info->setTypeSlots(typeSlots);
297 298 info->setupQObject(m);
298 299 createPythonQtClassWrapper(info, package, module);
299 300 if (m->superClass()) {
300 301 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
301 302 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
302 303 }
303 304 } else if (first && module) {
304 305 // There is a wrapper already, but if we got a module, we want to place the wrapper into that module as well,
305 306 // since it might have been placed into "private" earlier on.
306 307 // If the wrapper was already added to module before, it is just readded, which does no harm.
307 308 PyObject* classWrapper = info->pythonQtClassWrapper();
308 309 // AddObject steals a reference, so we need to INCREF
309 310 Py_INCREF(classWrapper);
310 311 PyModule_AddObject(module, info->className(), classWrapper);
311 312 }
312 313 if (first) {
313 314 first = false;
314 315 if (wrapperCreator) {
315 316 info->setDecoratorProvider(wrapperCreator);
316 317 }
317 318 if (shell) {
318 319 info->setShellSetInstanceWrapperCB(shell);
319 320 }
320 321 }
321 322 m = m->superClass();
322 323 }
323 324 }
324 325
325 326 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
326 327 {
327 328 PyObject* pack = module?module:packageByName(package);
328 329 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
329 330 PyModule_AddObject(pack, info->className(), pyobj);
330 331 if (!module && package && strncmp(package,"Qt",2)==0) {
331 332 // since PyModule_AddObject steals the reference, we need a incref once more...
332 333 Py_INCREF(pyobj);
333 334 // put all qt objects into Qt as well
334 335 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
335 336 }
336 337 info->setPythonQtClassWrapper(pyobj);
337 338 }
338 339
339 340 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
340 341 {
341 342 if (!obj) {
342 343 Py_INCREF(Py_None);
343 344 return Py_None;
344 345 }
345 346 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
346 347 if (!wrap) {
347 348 // smuggling it in...
348 349 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
349 350 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
350 351 registerClass(obj->metaObject());
351 352 classInfo = _knownClassInfos.value(obj->metaObject()->className());
352 353 }
353 354 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
354 355 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
355 356 } else {
356 357 Py_INCREF(wrap);
357 358 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
358 359 }
359 360 return (PyObject*)wrap;
360 361 }
361 362
362 363 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
363 364 {
364 365 if (!ptr) {
365 366 Py_INCREF(Py_None);
366 367 return Py_None;
367 368 }
368 369
369 370 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
370 371 if (!wrap) {
371 372 PythonQtClassInfo* info = _knownClassInfos.value(name);
372 373 if (!info) {
373 374 // maybe it is a PyObject, which we can return directly
374 375 if (name == "PyObject") {
375 376 PyObject* p = (PyObject*)ptr;
376 377 Py_INCREF(p);
377 378 return p;
378 379 }
379 380
380 381 // we do not know the metaobject yet, but we might know it by it's name:
381 382 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
382 383 // yes, we know it, so we can convert to QObject
383 384 QObject* qptr = (QObject*)ptr;
384 385 registerClass(qptr->metaObject());
385 386 info = _knownClassInfos.value(qptr->metaObject()->className());
386 387 }
387 388 }
388 389 if (info && info->isQObject()) {
389 390 QObject* qptr = (QObject*)ptr;
390 391 // if the object is a derived object, we want to switch the class info to the one of the derived class:
391 392 if (name!=(qptr->metaObject()->className())) {
392 393 registerClass(qptr->metaObject());
393 394 info = _knownClassInfos.value(qptr->metaObject()->className());
394 395 }
395 396 wrap = createNewPythonQtInstanceWrapper(qptr, info);
396 397 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
397 398 return (PyObject*)wrap;
398 399 }
399 400
400 401 // not a known QObject, try to wrap via foreign wrapper factories
401 402 PyObject* foreignWrapper = NULL;
402 403 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
403 404 foreignWrapper = _foreignWrapperFactories.at(i)->wrap(name, ptr);
404 405 if (foreignWrapper) {
405 406 return foreignWrapper;
406 407 }
407 408 }
408 409
409 410 // not a known QObject, so try our wrapper factory:
410 411 QObject* wrapper = NULL;
411 412 for (int i=0; i<_cppWrapperFactories.size(); i++) {
412 413 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
413 414 if (wrapper) {
414 415 break;
415 416 }
416 417 }
417 418
418 419 if (info) {
419 420 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
420 421 ptr = info->castDownIfPossible(ptr, &info);
421 422
422 423 // if downcasting found out that the object is a QObject,
423 424 // handle it like one:
424 425 if (info && info->isQObject()) {
425 426 QObject* qptr = (QObject*)ptr;
426 427 // if the object is a derived object, we want to switch the class info to the one of the derived class:
427 428 if (name!=(qptr->metaObject()->className())) {
428 429 registerClass(qptr->metaObject());
429 430 info = _knownClassInfos.value(qptr->metaObject()->className());
430 431 }
431 432 wrap = createNewPythonQtInstanceWrapper(qptr, info);
432 433 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
433 434 return (PyObject*)wrap;
434 435 }
435 436 }
436 437
437 438 if (!info || info->pythonQtClassWrapper()==NULL) {
438 439 // still unknown, register as CPP class
439 440 registerCPPClass(name.constData());
440 441 info = _knownClassInfos.value(name);
441 442 }
442 443 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
443 444 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
444 445 info->setMetaObject(wrapper->metaObject());
445 446 }
446 447
447 448 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
448 449 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
449 450 } else {
450 451 Py_INCREF(wrap);
451 452 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
452 453 }
453 454 return (PyObject*)wrap;
454 455 }
455 456
456 457 PyObject* PythonQtPrivate::dummyTuple() {
457 458 static PyObject* dummyTuple = NULL;
458 459 if (dummyTuple==NULL) {
459 460 dummyTuple = PyTuple_New(1);
460 461 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
461 462 }
462 463 return dummyTuple;
463 464 }
464 465
465 466
466 467 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
467 468 // call the associated class type to create a new instance...
468 469 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
469 470
470 471 result->setQObject(obj);
471 472 result->_wrappedPtr = wrappedPtr;
472 473 result->_ownedByPythonQt = false;
473 474 result->_useQMetaTypeDestroy = false;
474 475
475 476 if (wrappedPtr) {
476 477 _wrappedObjects.insert(wrappedPtr, result);
477 478 } else {
478 479 _wrappedObjects.insert(obj, result);
479 480 if (obj->parent()== NULL && _wrappedCB) {
480 481 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
481 482 (*_wrappedCB)(obj);
482 483 }
483 484 }
484 485 return result;
485 486 }
486 487
487 488 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
488 489 PythonQtClassWrapper* result;
489 490
490 491 PyObject* className = PyString_FromString(info->className());
491 492
492 493 PyObject* baseClasses = PyTuple_New(1);
493 494 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
494 495
495 496 PyObject* typeDict = PyDict_New();
496 497 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
497 498 PyDict_SetItemString(typeDict, "__module__", moduleName);
498 499
499 500 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
500 501
501 502 // set the class info so that PythonQtClassWrapper_new can read it
502 503 _currentClassInfoForClassWrapperCreation = info;
503 504 // create the new type object by calling the type
504 505 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
505 506
506 507 Py_DECREF(baseClasses);
507 508 Py_DECREF(typeDict);
508 509 Py_DECREF(args);
509 510 Py_DECREF(className);
510 511
511 512 return result;
512 513 }
513 514
514 515 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
515 516 {
516 517 PyObject* args = Py_BuildValue("(i)", enumValue);
517 518 PyObject* result = PyObject_Call(enumType, args, NULL);
518 519 Py_DECREF(args);
519 520 return result;
520 521 }
521 522
522 523 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
523 524 PyObject* result;
524 525
525 526 PyObject* className = PyString_FromString(enumName);
526 527
527 528 PyObject* baseClasses = PyTuple_New(1);
528 529 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
529 530
530 531 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
531 532 PyObject* typeDict = PyDict_New();
532 533 PyDict_SetItemString(typeDict, "__module__", module);
533 534
534 535 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
535 536
536 537 // create the new int derived type object by calling the core type
537 538 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
538 539
539 540 Py_DECREF(baseClasses);
540 541 Py_DECREF(typeDict);
541 542 Py_DECREF(args);
542 543 Py_DECREF(className);
543 544
544 545 return result;
545 546 }
546 547
547 548 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
548 549 {
549 550 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
550 551 if (!r) {
551 552 r = new PythonQtSignalReceiver(obj);
552 553 _p->_signalReceivers.insert(obj, r);
553 554 }
554 555 return r;
555 556 }
556 557
557 558 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
558 559 {
559 560 bool flag = false;
560 561 PythonQtObjectPtr callable = lookupCallable(module, objectname);
561 562 if (callable) {
562 563 PythonQtSignalReceiver* r = getSignalReceiver(obj);
563 564 flag = r->addSignalHandler(signal, callable);
564 565 if (!flag) {
565 566 // signal not found
566 567 }
567 568 } else {
568 569 // callable not found
569 570 }
570 571 return flag;
571 572 }
572 573
573 574 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
574 575 {
575 576 bool flag = false;
576 577 PythonQtSignalReceiver* r = getSignalReceiver(obj);
577 578 if (r) {
578 579 flag = r->addSignalHandler(signal, receiver);
579 580 }
580 581 return flag;
581 582 }
582 583
583 584 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
584 585 {
585 586 bool flag = false;
586 587 PythonQtObjectPtr callable = lookupCallable(module, objectname);
587 588 if (callable) {
588 589 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
589 590 if (r) {
590 591 flag = r->removeSignalHandler(signal, callable);
591 592 }
592 593 } else {
593 594 // callable not found
594 595 }
595 596 return flag;
596 597 }
597 598
598 599 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
599 600 {
600 601 bool flag = false;
601 602 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
602 603 if (r) {
603 604 flag = r->removeSignalHandler(signal, receiver);
604 605 }
605 606 return flag;
606 607 }
607 608
608 609 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
609 610 {
610 611 PythonQtObjectPtr p = lookupObject(module, name);
611 612 if (p) {
612 613 if (PyCallable_Check(p)) {
613 614 return p;
614 615 }
615 616 }
616 617 PyErr_Clear();
617 618 return NULL;
618 619 }
619 620
620 621 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
621 622 {
622 623 QStringList l = name.split('.');
623 624 PythonQtObjectPtr p = module;
624 625 PythonQtObjectPtr prev;
625 626 QByteArray b;
626 627 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
627 628 prev = p;
628 629 b = (*i).toLatin1();
629 630 if (PyDict_Check(p)) {
630 631 p = PyDict_GetItemString(p, b.data());
631 632 } else {
632 633 p.setNewRef(PyObject_GetAttrString(p, b.data()));
633 634 }
634 635 }
635 636 PyErr_Clear();
636 637 return p;
637 638 }
638 639
639 640 PythonQtObjectPtr PythonQt::getMainModule() {
640 641 //both borrowed
641 642 PythonQtObjectPtr dict = PyImport_GetModuleDict();
642 643 return PyDict_GetItemString(dict, "__main__");
643 644 }
644 645
645 646 PythonQtObjectPtr PythonQt::importModule(const QString& name)
646 647 {
647 648 PythonQtObjectPtr mod;
648 649 mod.setNewRef(PyImport_ImportModule(name.toLatin1().constData()));
649 650 return mod;
650 651 }
651 652
652 653
653 654 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
654 655 QVariant result;
655 656 if (pycode) {
656 657 PyObject* dict = NULL;
657 658 if (PyModule_Check(object)) {
658 659 dict = PyModule_GetDict(object);
659 660 } else if (PyDict_Check(object)) {
660 661 dict = object;
661 662 }
662 663 PyObject* r = NULL;
663 664 if (dict) {
664 665 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
665 666 }
666 667 if (r) {
667 668 result = PythonQtConv::PyObjToQVariant(r);
668 669 Py_DECREF(r);
669 670 } else {
670 671 handleError();
671 672 }
672 673 } else {
673 674 handleError();
674 675 }
675 676 return result;
676 677 }
677 678
678 679 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
679 680 {
680 681 QVariant result;
681 682 PythonQtObjectPtr p;
682 683 PyObject* dict = NULL;
683 684 if (PyModule_Check(object)) {
684 685 dict = PyModule_GetDict(object);
685 686 } else if (PyDict_Check(object)) {
686 687 dict = object;
687 688 }
688 689 if (dict) {
689 690 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
690 691 }
691 692 if (p) {
692 693 result = PythonQtConv::PyObjToQVariant(p);
693 694 } else {
694 695 handleError();
695 696 }
696 697 return result;
697 698 }
698 699
699 700 void PythonQt::evalFile(PyObject* module, const QString& filename)
700 701 {
701 702 PythonQtObjectPtr code = parseFile(filename);
702 703 if (code) {
703 704 evalCode(module, code);
704 705 } else {
705 706 handleError();
706 707 }
707 708 }
708 709
709 710 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
710 711 {
711 712 PythonQtObjectPtr p;
712 713 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
713 714 if (!p) {
714 715 handleError();
715 716 }
716 717 return p;
717 718 }
718 719
719 720 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
720 721 {
721 722 PythonQtObjectPtr code = parseFile(filename);
722 723 PythonQtObjectPtr module = _p->createModule(name, code);
723 724 return module;
724 725 }
725 726
726 727 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
727 728 {
728 729 PyErr_Clear();
729 730 QString scriptCode = script;
730 731 if (scriptCode.isEmpty()) {
731 732 // we always need at least a linefeed
732 733 scriptCode = "\n";
733 734 }
734 735 PythonQtObjectPtr pycode;
735 736 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
736 737 PythonQtObjectPtr module = _p->createModule(name, pycode);
737 738 return module;
738 739 }
739 740
740 741 PythonQtObjectPtr PythonQt::createUniqueModule()
741 742 {
742 743 static QString pyQtStr("PythonQt_module");
743 744 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
744 745 return createModuleFromScript(moduleName);
745 746 }
746 747
747 748 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
748 749 {
749 750 if (PyModule_Check(object)) {
750 751 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
751 752 } else if (PyDict_Check(object)) {
752 753 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
753 754 } else {
754 755 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
755 756 }
756 757 }
757 758
758 759 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
759 760 {
760 761 if (PyModule_Check(object)) {
761 762 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
762 763 } else if (PyDict_Check(object)) {
763 764 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
764 765 } else {
765 766 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
766 767 }
767 768 }
768 769
769 770 void PythonQt::removeVariable(PyObject* object, const QString& name)
770 771 {
771 772 if (PyDict_Check(object)) {
772 773 PyDict_DelItemString(object, name.toLatin1().data());
773 774 } else {
774 775 PyObject_DelAttrString(object, name.toLatin1().data());
775 776 }
776 777 }
777 778
778 779 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
779 780 {
780 781 QVariant result;
781 782 PythonQtObjectPtr obj = lookupObject(object, objectname);
782 783 if (obj) {
783 784 result = PythonQtConv::PyObjToQVariant(obj);
784 785 }
785 786 return result;
786 787 }
787 788
788 789 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
789 790 {
790 791 QStringList results;
791 792
792 793 PythonQtObjectPtr object;
793 794 if (objectname.isEmpty()) {
794 795 object = module;
795 796 } else {
796 797 object = lookupObject(module, objectname);
797 798 if (!object && type == CallOverloads) {
798 799 PyObject* dict = lookupObject(module, "__builtins__");
799 800 if (dict) {
800 801 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
801 802 }
802 803 }
803 804 }
804 805
805 806 if (object) {
806 807 results = introspectObject(object, type);
807 808 }
808 809
809 810 return results;
810 811 }
811 812
812 813 QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
813 814 {
814 815 QStringList results;
815 816
816 817 if (type == CallOverloads) {
817 818 if (PythonQtSlotFunction_Check(object)) {
818 819 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object;
819 820 PythonQtSlotInfo* info = o->m_ml;
820 821
821 822 while (info) {
822 823 results << info->fullSignature();
823 824 info = info->nextInfo();
824 825 }
825 826 } else if (PythonQtSignalFunction_Check(object)) {
826 827 PythonQtSignalFunctionObject* o = (PythonQtSignalFunctionObject*)object;
827 828 PythonQtSlotInfo* info = o->m_ml;
828 829
829 830 while (info) {
830 831 results << info->fullSignature();
831 832 info = info->nextInfo();
832 833 }
833 834 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
834 835 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
835 836 PythonQtSlotInfo* info = o->classInfo()->constructors();
836 837
837 838 while (info) {
838 839 results << info->fullSignature();
839 840 info = info->nextInfo();
840 841 }
841 842 } else {
842 843 QString signature = _p->getSignature(object);
843 844 if (!signature.isEmpty()) {
844 845 results << signature;
845 846 } else {
846 847 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
847 848 if (doc) {
848 849 results << PyString_AsString(doc);
849 850 Py_DECREF(doc);
850 851 }
851 852 }
852 853 }
853 854 } else {
854 855 PyObject* keys = NULL;
855 856 bool isDict = false;
856 857 if (PyDict_Check(object)) {
857 858 keys = PyDict_Keys(object);
858 859 isDict = true;
859 860 } else {
860 861 keys = PyObject_Dir(object);
861 862 }
862 863 if (keys) {
863 864 int count = PyList_Size(keys);
864 865 PyObject* key;
865 866 PyObject* value;
866 867 QString keystr;
867 868 for (int i = 0;i<count;i++) {
868 869 key = PyList_GetItem(keys,i);
869 870 if (isDict) {
870 871 value = PyDict_GetItem(object, key);
871 872 Py_INCREF(value);
872 873 } else {
873 874 value = PyObject_GetAttr(object, key);
874 875 }
875 876 if (!value) continue;
876 877 keystr = PyString_AsString(key);
877 878 static const QString underscoreStr("__tmp");
878 879 if (!keystr.startsWith(underscoreStr)) {
879 880 switch (type) {
880 881 case Anything:
881 882 results << keystr;
882 883 break;
883 884 case Class:
884 885 if (value->ob_type == &PyClass_Type || value->ob_type == &PyType_Type) {
885 886 results << keystr;
886 887 }
887 888 break;
888 889 case Variable:
889 890 if (value->ob_type != &PyClass_Type
890 891 && value->ob_type != &PyCFunction_Type
891 892 && value->ob_type != &PyFunction_Type
892 893 && value->ob_type != &PyMethod_Type
893 894 && value->ob_type != &PyModule_Type
894 895 && value->ob_type != &PyType_Type
895 896 && value->ob_type != &PythonQtSlotFunction_Type
896 897 ) {
897 898 results << keystr;
898 899 }
899 900 break;
900 901 case Function:
901 902 if (value->ob_type == &PyCFunction_Type ||
902 903 value->ob_type == &PyFunction_Type ||
903 904 value->ob_type == &PyMethod_Type ||
904 905 value->ob_type == &PythonQtSlotFunction_Type
905 906 ) {
906 907 results << keystr;
907 908 }
908 909 break;
909 910 case Module:
910 911 if (value->ob_type == &PyModule_Type) {
911 912 results << keystr;
912 913 }
913 914 break;
914 915 default:
915 916 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
916 917 }
917 918 }
918 919 Py_DECREF(value);
919 920 }
920 921 Py_DECREF(keys);
921 922 }
923 if ((type == Anything) || (type == Variable)) {
924 if (object->ob_type == &PythonQtClassWrapper_Type) {
925 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
926 PythonQtClassInfo* info = o->classInfo();
927 results += info->propertyList();
928 }
929 }
922 930 }
923 931 return results;
924 932 }
925 933
926 934 PyObject* PythonQt::getObjectByType(const QString& typeName)
927 935 {
928 936 PythonQtObjectPtr sys;
929 937 sys.setNewRef(PyImport_ImportModule("sys"));
930 938 PythonQtObjectPtr modules = lookupObject(sys, "modules");
931 939 Q_ASSERT(PyDict_Check(modules));
932 940
933 941 QStringList tmp = typeName.split(".");
934 942 QString simpleTypeName = tmp.takeLast();
935 943 QString moduleName = tmp.join(".");
936 944
937 945 PyObject* object = NULL;
938 946 PyObject* moduleObject = PyDict_GetItemString(modules, moduleName.toLatin1().constData());
939 947 if (moduleObject) {
940 948 object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
941 949 }
942 950
943 951 if (!object) {
944 952 moduleObject = PyDict_GetItemString(modules, "__builtin__");
945 953 if (moduleObject) {
946 954 object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
947 955 }
948 956 }
949 957
950 958 return object;
951 959 }
952 960
953 961 QStringList PythonQt::introspectType(const QString& typeName, ObjectType type)
954 962 {
955 963 QStringList results;
956 964 PyObject* object = getObjectByType(typeName);
957 965 if (!object) {
958 966 // the last item may be a member, split it away and try again
959 967 QStringList tmp = typeName.split(".");
960 968 QString memberName = tmp.takeLast();
961 QString typeName = tmp.takeLast();
969 QString typeName;
970 if (tmp.isEmpty()) {
971 typeName = memberName;
972 memberName.clear();
973 } else {
974 typeName = tmp.takeLast();
975 }
962 976 PyObject* typeObject = getObjectByType(typeName);
963 977 if (typeObject) {
964 978 object = PyObject_GetAttrString(typeObject, memberName.toLatin1().constData());
965 979 }
966 980 }
967 981 if (object) {
968 982 results = introspectObject(object, type);
969 983 Py_DECREF(object);
970 984 }
971 985 return results;
972 986 }
973 987
974 988 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
975 989 {
976 990 PythonQtObjectPtr callable = lookupCallable(object, name);
977 991 if (callable) {
978 992 return call(callable, args);
979 993 } else {
980 994 return QVariant();
981 995 }
982 996 }
983 997
984 998 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
985 999 {
986 1000 QVariant r;
987 1001 PythonQtObjectPtr result;
988 1002 result.setNewRef(callAndReturnPyObject(callable, args));
989 1003 if (result) {
990 1004 r = PythonQtConv::PyObjToQVariant(result);
991 1005 } else {
992 1006 PythonQt::self()->handleError();
993 1007 }
994 1008 return r;
995 1009 }
996 1010
997 1011 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args)
998 1012 {
999 1013 PyObject* result = NULL;
1000 1014 if (callable) {
1001 1015 PythonQtObjectPtr pargs;
1002 1016 int count = args.size();
1003 1017 if (count>0) {
1004 1018 pargs.setNewRef(PyTuple_New(count));
1005 1019 }
1006 1020 bool err = false;
1007 1021 // transform QVariants to Python
1008 1022 for (int i = 0; i < count; i++) {
1009 1023 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
1010 1024 if (arg) {
1011 1025 // steals reference, no unref
1012 1026 PyTuple_SetItem(pargs, i,arg);
1013 1027 } else {
1014 1028 err = true;
1015 1029 break;
1016 1030 }
1017 1031 }
1018 1032
1019 1033 if (!err) {
1020 1034 PyErr_Clear();
1021 1035 result = PyObject_CallObject(callable, pargs);
1022 1036 }
1023 1037 }
1024 1038 return result;
1025 1039 }
1026 1040
1027 1041 void PythonQt::addInstanceDecorators(QObject* o)
1028 1042 {
1029 1043 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
1030 1044 }
1031 1045
1032 1046 void PythonQt::addClassDecorators(QObject* o)
1033 1047 {
1034 1048 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
1035 1049 }
1036 1050
1037 1051 void PythonQt::addDecorators(QObject* o)
1038 1052 {
1039 1053 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
1040 1054 }
1041 1055
1042 1056 void PythonQt::registerQObjectClassNames(const QStringList& names)
1043 1057 {
1044 1058 _p->registerQObjectClassNames(names);
1045 1059 }
1046 1060
1047 1061 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
1048 1062 {
1049 1063 _p->_importInterface = importInterface;
1050 1064 PythonQtImport::init();
1051 1065 }
1052 1066
1053 1067 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
1054 1068 {
1055 1069 _p->_importIgnorePaths = paths;
1056 1070 }
1057 1071
1058 1072 const QStringList& PythonQt::getImporterIgnorePaths()
1059 1073 {
1060 1074 return _p->_importIgnorePaths;
1061 1075 }
1062 1076
1063 1077 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
1064 1078 {
1065 1079 _p->_cppWrapperFactories.append(factory);
1066 1080 }
1067 1081
1068 1082 void PythonQt::addWrapperFactory( PythonQtForeignWrapperFactory* factory )
1069 1083 {
1070 1084 _p->_foreignWrapperFactories.append(factory);
1071 1085 }
1072 1086
1073 1087 //---------------------------------------------------------------------------------------------------
1074 1088 PythonQtPrivate::PythonQtPrivate()
1075 1089 {
1076 1090 _importInterface = NULL;
1077 1091 _defaultImporter = new PythonQtQFileImporter;
1078 1092 _noLongerWrappedCB = NULL;
1079 1093 _wrappedCB = NULL;
1080 1094 _currentClassInfoForClassWrapperCreation = NULL;
1081 1095 _profilingCB = NULL;
1082 1096 }
1083 1097
1084 1098 void PythonQtPrivate::setupSharedLibrarySuffixes()
1085 1099 {
1086 1100 _sharedLibrarySuffixes.clear();
1087 1101 PythonQtObjectPtr imp;
1088 1102 imp.setNewRef(PyImport_ImportModule("imp"));
1089 1103 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
1090 1104 QVariant result = imp.call("get_suffixes");
1091 1105 #ifdef __linux
1092 1106 #ifdef _DEBUG
1093 1107 // First look for shared libraries with the '_d' suffix in debug mode on Linux.
1094 1108 // This is a workaround, because python does not append the '_d' suffix on Linux
1095 1109 // and would always load the release library otherwise.
1096 1110 _sharedLibrarySuffixes << "_d.so";
1097 1111 #endif
1098 1112 #endif
1099 1113 foreach (QVariant entry, result.toList()) {
1100 1114 QVariantList suffixEntry = entry.toList();
1101 1115 if (suffixEntry.count()==3) {
1102 1116 int code = suffixEntry.at(2).toInt();
1103 1117 if (code == cExtensionCode) {
1104 1118 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
1105 1119 }
1106 1120 }
1107 1121 }
1108 1122 }
1109 1123
1110 1124 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
1111 1125 {
1112 1126 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
1113 1127 _currentClassInfoForClassWrapperCreation = NULL;
1114 1128 return info;
1115 1129 }
1116 1130
1117 1131 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
1118 1132 {
1119 1133 o->setParent(this);
1120 1134 int numMethods = o->metaObject()->methodCount();
1121 1135 for (int i = 0; i < numMethods; i++) {
1122 1136 QMetaMethod m = o->metaObject()->method(i);
1123 1137 if ((m.methodType() == QMetaMethod::Method ||
1124 1138 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
1125 1139 if (qstrncmp(m.signature(), "new_", 4)==0) {
1126 1140 if ((decoTypes & ConstructorDecorator) == 0) continue;
1127 1141 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1128 1142 if (info->parameters().at(0).pointerCount == 1) {
1129 1143 QByteArray signature = m.signature();
1130 1144 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
1131 1145 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1132 1146 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1133 1147 classInfo->addConstructor(newSlot);
1134 1148 }
1135 1149 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
1136 1150 if ((decoTypes & DestructorDecorator) == 0) continue;
1137 1151 QByteArray signature = m.signature();
1138 1152 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
1139 1153 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1140 1154 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1141 1155 classInfo->setDestructor(newSlot);
1142 1156 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
1143 1157 if ((decoTypes & StaticDecorator) == 0) continue;
1144 1158 QByteArray signature = m.signature();
1145 1159 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
1146 1160 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
1147 1161 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1148 1162 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1149 1163 classInfo->addDecoratorSlot(newSlot);
1150 1164 } else {
1151 1165 if ((decoTypes & InstanceDecorator) == 0) continue;
1152 1166 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1153 1167 if (info->parameters().count()>1) {
1154 1168 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
1155 1169 if (p.pointerCount==1) {
1156 1170 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
1157 1171 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
1158 1172 classInfo->addDecoratorSlot(newSlot);
1159 1173 }
1160 1174 }
1161 1175 }
1162 1176 }
1163 1177 }
1164 1178 }
1165 1179
1166 1180 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
1167 1181 {
1168 1182 foreach(QString name, names) {
1169 1183 _knownQObjectClassNames.insert(name.toLatin1(), true);
1170 1184 }
1171 1185 }
1172 1186
1173 1187 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
1174 1188 {
1175 1189 _signalReceivers.remove(obj);
1176 1190 }
1177 1191
1178 1192 bool PythonQt::handleError()
1179 1193 {
1180 1194 bool flag = false;
1181 1195 if (PyErr_Occurred()) {
1182 1196
1183 1197 // currently we just print the error and the stderr handler parses the errors
1184 1198 PyErr_Print();
1185 1199
1186 1200 /*
1187 1201 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1188 1202 PyObject *ptype;
1189 1203 PyObject *pvalue;
1190 1204 PyObject *ptraceback;
1191 1205 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1192 1206
1193 1207 Py_XDECREF(ptype);
1194 1208 Py_XDECREF(pvalue);
1195 1209 Py_XDECREF(ptraceback);
1196 1210 */
1197 1211 PyErr_Clear();
1198 1212 flag = true;
1199 1213 }
1200 1214 return flag;
1201 1215 }
1202 1216
1203 1217 void PythonQt::addSysPath(const QString& path)
1204 1218 {
1205 1219 PythonQtObjectPtr sys;
1206 1220 sys.setNewRef(PyImport_ImportModule("sys"));
1207 1221 PythonQtObjectPtr obj = lookupObject(sys, "path");
1208 1222 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1209 1223 }
1210 1224
1211 1225 void PythonQt::overwriteSysPath(const QStringList& paths)
1212 1226 {
1213 1227 PythonQtObjectPtr sys;
1214 1228 sys.setNewRef(PyImport_ImportModule("sys"));
1215 1229 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1216 1230 }
1217 1231
1218 1232 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1219 1233 {
1220 1234 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1221 1235 }
1222 1236
1223 1237 void PythonQt::stdOutRedirectCB(const QString& str)
1224 1238 {
1225 1239 if (!PythonQt::self()) {
1226 1240 std::cout << str.toLatin1().data() << std::endl;
1227 1241 return;
1228 1242 }
1229 1243 emit PythonQt::self()->pythonStdOut(str);
1230 1244 }
1231 1245
1232 1246 void PythonQt::stdErrRedirectCB(const QString& str)
1233 1247 {
1234 1248 if (!PythonQt::self()) {
1235 1249 std::cerr << str.toLatin1().data() << std::endl;
1236 1250 return;
1237 1251 }
1238 1252 emit PythonQt::self()->pythonStdErr(str);
1239 1253 }
1240 1254
1241 1255 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1242 1256 {
1243 1257 _p->_wrappedCB = cb;
1244 1258 }
1245 1259
1246 1260 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1247 1261 {
1248 1262 _p->_noLongerWrappedCB = cb;
1249 1263 }
1250 1264
1251 1265 void PythonQt::setProfilingCallback(ProfilingCB* cb)
1252 1266 {
1253 1267 _p->_profilingCB = cb;
1254 1268 }
1255 1269
1256 1270
1257 1271 static PyMethodDef PythonQtMethods[] = {
1258 1272 {NULL, NULL, 0, NULL}
1259 1273 };
1260 1274
1261 1275 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1262 1276 {
1263 1277 QByteArray name = "PythonQt";
1264 1278 if (!pythonQtModuleName.isEmpty()) {
1265 1279 name = pythonQtModuleName;
1266 1280 }
1267 1281 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1268 1282 _p->_pythonQtModuleName = name;
1269 1283
1270 1284 if (redirectStdOut) {
1271 1285 PythonQtObjectPtr sys;
1272 1286 PythonQtObjectPtr out;
1273 1287 PythonQtObjectPtr err;
1274 1288 sys.setNewRef(PyImport_ImportModule("sys"));
1275 1289 // create a redirection object for stdout and stderr
1276 1290 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1277 1291 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1278 1292 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1279 1293 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1280 1294 // replace the built in file objects with our own objects
1281 1295 PyModule_AddObject(sys, "stdout", out);
1282 1296 PyModule_AddObject(sys, "stderr", err);
1283 1297 }
1284 1298 }
1285 1299
1286 1300 QString PythonQt::getReturnTypeOfWrappedMethod(PyObject* module, const QString& name)
1287 1301 {
1288 1302 QStringList tmp = name.split(".");
1289 1303 QString methodName = tmp.takeLast();
1290 1304 QString variableName = tmp.join(".");
1291 1305 // TODO: the variableName may be a type name, this needs to be handled differently,
1292 1306 // because it is not necessarily known in the module context
1293 1307 PythonQtObjectPtr variableObject = lookupObject(module, variableName);
1294 1308 if (variableObject.isNull()) {
1295 1309 return "";
1296 1310 }
1297 1311
1298 1312 return getReturnTypeOfWrappedMethodHelper(variableObject, methodName, name);
1299 1313 }
1300 1314
1301 1315 QString PythonQt::getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName)
1302 1316 {
1303 1317 PythonQtObjectPtr typeObject = getObjectByType(typeName);
1304 1318 if (typeObject.isNull()) {
1305 1319 return "";
1306 1320 }
1307 1321 return getReturnTypeOfWrappedMethodHelper(typeObject, methodName, typeName + "." + methodName);
1308 1322 }
1309 1323
1310 1324 QString PythonQt::getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context)
1311 1325 {
1312 1326 PythonQtObjectPtr methodObject;
1313 1327 if (PyDict_Check(variableObject)) {
1314 1328 methodObject = PyDict_GetItemString(variableObject, methodName.toLatin1().constData());
1315 1329 } else {
1316 1330 methodObject.setNewRef(PyObject_GetAttrString(variableObject, methodName.toLatin1().constData()));
1317 1331 }
1318 1332 if (methodObject.isNull()) {
1319 1333 return "";
1320 1334 }
1321 1335
1322 1336 QString type;
1323 1337
1324 1338 if (methodObject->ob_type == &PyClass_Type || methodObject->ob_type == &PyType_Type) {
1325 1339 // the methodObject is not a method, but the name of a type/class. This means
1326 1340 // a constructor is called. Return the context.
1327 1341 type = context;
1328 1342 } else if (methodObject->ob_type == &PythonQtSlotFunction_Type) {
1329 1343 QString className;
1330 1344
1331 1345 if (PyObject_TypeCheck(variableObject, &PythonQtInstanceWrapper_Type)) {
1332 1346 // the type name of wrapped instance is the class name
1333 1347 className = variableObject->ob_type->tp_name;
1334 1348 } else {
1335 1349 PyObject* classNameObject = PyObject_GetAttrString(variableObject, "__name__");
1336 1350 if (classNameObject) {
1337 1351 Q_ASSERT(PyString_Check(classNameObject));
1338 1352 className = PyString_AsString(classNameObject);
1339 1353 Py_DECREF(classNameObject);
1340 1354 }
1341 1355 }
1342 1356
1343 1357 if (!className.isEmpty()) {
1344 1358 PythonQtClassInfo* info = _p->_knownClassInfos.value(className.toLatin1().constData());
1345 1359 if (info) {
1346 1360 PythonQtSlotInfo* slotInfo = info->member(methodName.toLatin1().constData())._slot;
1347 1361 if (slotInfo) {
1348 1362 if (slotInfo->metaMethod()) {
1349 1363 type = slotInfo->metaMethod()->typeName();
1350 1364 if (!type.isEmpty()) {
1351 1365 QChar c = type.at(type.length()-1);
1352 1366 while (c == '*' || c == '&') {
1353 1367 type.truncate(type.length()-1);
1354 1368 if (!type.isEmpty()) {
1355 1369 c = type.at(type.length()-1);
1356 1370 } else {
1357 1371 break;
1358 1372 }
1359 1373 }
1360 1374 // split away template arguments
1361 1375 type = type.split("<").first();
1362 1376 // split away const
1363 1377 type = type.split(" ").last().trimmed();
1364 1378
1365 1379 // if the type is a known class info, then create the full type name, i.e. include the
1366 1380 // module name. For example, the slot may return a QDate, then this looks up the
1367 1381 // name _PythonQt.QtCore.QDate.
1368 1382 PythonQtClassInfo* typeInfo = _p->_knownClassInfos.value(type.toLatin1().constData());
1369 1383 if (typeInfo && typeInfo->pythonQtClassWrapper()) {
1370 1384 PyObject* s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__module__");
1371 1385 Q_ASSERT(PyString_Check(s));
1372 1386 type = QString(PyString_AsString(s)) + "." + type;
1373 1387 Py_DECREF(s);
1374 1388 s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__name__");
1375 1389 Q_ASSERT(PyString_Check(s));
1376 1390 Py_DECREF(s);
1377 1391 }
1378 1392 }
1379 1393 }
1380 1394 }
1381 1395 }
1382 1396 }
1383 1397 }
1384 1398 return type;
1385 1399 }
1386 1400
1387 1401 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1388 1402 {
1389 1403 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1390 1404 }
1391 1405
1392 1406
1393 1407 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1394 1408 {
1395 1409 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1396 1410 if (!info) {
1397 1411 info = new PythonQtClassInfo();
1398 1412 info->setupCPPObject(typeName);
1399 1413 _knownClassInfos.insert(typeName, info);
1400 1414 }
1401 1415 return info;
1402 1416 }
1403 1417
1404 1418 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1405 1419 {
1406 1420 _p->addPolymorphicHandler(typeName, cb);
1407 1421 }
1408 1422
1409 1423 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1410 1424 {
1411 1425 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1412 1426 info->addPolymorphicHandler(cb);
1413 1427 }
1414 1428
1415 1429 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1416 1430 {
1417 1431 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1418 1432 }
1419 1433
1420 1434 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1421 1435 {
1422 1436 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1423 1437 if (info) {
1424 1438 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1425 1439 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1426 1440 return true;
1427 1441 } else {
1428 1442 return false;
1429 1443 }
1430 1444 }
1431 1445
1432 1446 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1433 1447 {
1434 1448 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1435 1449 if (!info->pythonQtClassWrapper()) {
1436 1450 info->setTypeSlots(typeSlots);
1437 1451 info->setupCPPObject(typeName);
1438 1452 createPythonQtClassWrapper(info, package, module);
1439 1453 }
1440 1454 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1441 1455 addParentClass(typeName, parentTypeName, 0);
1442 1456 }
1443 1457 if (wrapperCreator) {
1444 1458 info->setDecoratorProvider(wrapperCreator);
1445 1459 }
1446 1460 if (shell) {
1447 1461 info->setShellSetInstanceWrapperCB(shell);
1448 1462 }
1449 1463 }
1450 1464
1451 1465 PyObject* PythonQtPrivate::packageByName(const char* name)
1452 1466 {
1453 1467 if (name==NULL || name[0]==0) {
1454 1468 name = "private";
1455 1469 }
1456 1470 PyObject* v = _packages.value(name);
1457 1471 if (!v) {
1458 1472 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1459 1473 _packages.insert(name, v);
1460 1474 // AddObject steals the reference, so increment it!
1461 1475 Py_INCREF(v);
1462 1476 PyModule_AddObject(_pythonQtModule, name, v);
1463 1477 }
1464 1478 return v;
1465 1479 }
1466 1480
1467 1481 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1468 1482 {
1469 1483 QString error = "Return value '" + PythonQtConv::PyObjGetString(result) + "' can not be converted to expected C++ type '" + methodInfo->parameters().at(0).name + "' as return value of virtual method " + signature;
1470 1484 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1471 1485 PythonQt::self()->handleError();
1472 1486 }
1473 1487
1474 1488 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1475 1489 {
1476 1490 if (_p->_initFlags & ExternalHelp) {
1477 1491 emit pythonHelpRequest(QByteArray(info->className()));
1478 1492 return Py_BuildValue("");
1479 1493 } else {
1480 1494 return PyString_FromString(info->help().toLatin1().data());
1481 1495 }
1482 1496 }
1483 1497
1484 1498 void PythonQt::clearNotFoundCachedMembers()
1485 1499 {
1486 1500 foreach(PythonQtClassInfo* info, _p->_knownClassInfos) {
1487 1501 info->clearNotFoundCachedMembers();
1488 1502 }
1489 1503 }
1490 1504
1491 1505 void PythonQt::removeWrapperFactory( PythonQtCppWrapperFactory* factory )
1492 1506 {
1493 1507 _p->_cppWrapperFactories.removeAll(factory);
1494 1508 }
1495 1509
1496 1510 void PythonQt::removeWrapperFactory( PythonQtForeignWrapperFactory* factory )
1497 1511 {
1498 1512 _p->_foreignWrapperFactories.removeAll(factory);
1499 1513 }
1500 1514
1501 1515 void PythonQtPrivate::removeWrapperPointer(void* obj)
1502 1516 {
1503 1517 _wrappedObjects.remove(obj);
1504 1518 }
1505 1519
1506 1520 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1507 1521 {
1508 1522 _wrappedObjects.insert(obj, wrapper);
1509 1523 }
1510 1524
1511 1525 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1512 1526 {
1513 1527 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1514 1528 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1515 1529 // this is a wrapper whose QObject was already removed due to destruction
1516 1530 // so the obj pointer has to be a new QObject with the same address...
1517 1531 // we remove the old one and set the copy to NULL
1518 1532 wrap->_objPointerCopy = NULL;
1519 1533 removeWrapperPointer(obj);
1520 1534 wrap = NULL;
1521 1535 }
1522 1536 return wrap;
1523 1537 }
1524 1538
1525 1539 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1526 1540 {
1527 1541 PythonQtObjectPtr result;
1528 1542 if (pycode) {
1529 1543 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1530 1544 } else {
1531 1545 PythonQt::self()->handleError();
1532 1546 }
1533 1547 return result;
1534 1548 }
1535 1549
1536 1550 void* PythonQtPrivate::unwrapForeignWrapper( const QByteArray& classname, PyObject* obj )
1537 1551 {
1538 1552 void* foreignObject = NULL;
1539 1553 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
1540 1554 foreignObject = _foreignWrapperFactories.at(i)->unwrap(classname, obj);
1541 1555 if (foreignObject) {
1542 1556 return foreignObject;
1543 1557 }
1544 1558 }
1545 1559 return NULL;
1546 1560 }
1547 1561
1548 1562 bool PythonQtPrivate::isMethodDescriptor(PyObject* object) const
1549 1563 {
1550 1564 // This implementation is the same as in inspect.ismethoddescriptor(), inspect.py.
1551 1565 if (PyObject_HasAttrString(object, "__get__") &&
1552 1566 !PyObject_HasAttrString(object, "__set__") &&
1553 1567 !PyMethod_Check(object) &&
1554 1568 !PyFunction_Check(object) &&
1555 1569 !PyClass_Check(object)) {
1556 1570 return true;
1557 1571 }
1558 1572 return false;
1559 1573 }
1560 1574
1561 1575 QString PythonQtPrivate::getSignature(PyObject* object)
1562 1576 {
1563 1577 QString signature;
1564 1578
1565 1579 if (object) {
1566 1580 PyMethodObject* method = NULL;
1567 1581 PyFunctionObject* func = NULL;
1568 1582
1569 1583 bool decrefMethod = false;
1570 1584
1571 1585 if (object->ob_type == &PyClass_Type || object->ob_type == &PyType_Type) {
1572 1586 method = (PyMethodObject*)PyObject_GetAttrString(object, "__init__");
1573 1587 decrefMethod = true;
1574 1588 } else if (object->ob_type == &PyFunction_Type) {
1575 1589 func = (PyFunctionObject*)object;
1576 1590 } else if (object->ob_type == &PyMethod_Type) {
1577 1591 method = (PyMethodObject*)object;
1578 1592 }
1579 1593 if (method) {
1580 1594 if (PyFunction_Check(method->im_func)) {
1581 1595 func = (PyFunctionObject*)method->im_func;
1582 1596 } else if (isMethodDescriptor((PyObject*)method)) {
1583 1597 QString docstr;
1584 1598 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
1585 1599 if (doc) {
1586 1600 docstr = PyString_AsString(doc);
1587 1601 Py_DECREF(doc);
1588 1602 }
1589 1603
1590 1604 PyObject* s = PyObject_GetAttrString(object, "__name__");
1591 1605 if (s) {
1592 1606 Q_ASSERT(PyString_Check(s));
1593 1607 signature = PyString_AsString(s);
1594 1608 if (docstr.startsWith(signature + "(")) {
1595 1609 signature = docstr;
1596 1610 } else {
1597 1611 signature += "(...)";
1598 1612 if (!docstr.isEmpty()) {
1599 1613 signature += "\n\n" + docstr;
1600 1614 }
1601 1615 }
1602 1616 Py_DECREF(s);
1603 1617 }
1604 1618 }
1605 1619 }
1606 1620
1607 1621 if (func) {
1608 1622 QString funcName;
1609 1623 PyObject* s = PyObject_GetAttrString((PyObject*)func, "__name__");
1610 1624 if (s) {
1611 1625 Q_ASSERT(PyString_Check(s));
1612 1626 funcName = PyString_AsString(s);
1613 1627 Py_DECREF(s);
1614 1628 }
1615 1629 if (method && funcName == "__init__") {
1616 1630 PyObject* s = PyObject_GetAttrString(object, "__name__");
1617 1631 if (s) {
1618 1632 Q_ASSERT(PyString_Check(s));
1619 1633 funcName = PyString_AsString(s);
1620 1634 Py_DECREF(s);
1621 1635 }
1622 1636 }
1623 1637
1624 1638 QStringList arguments;
1625 1639 QStringList defaults;
1626 1640 QString varargs;
1627 1641 QString varkeywords;
1628 1642 // NOTE: This implementation is based on function getargs() in inspect.py.
1629 1643 // inspect.getargs() can handle anonymous (tuple) arguments, while this code does not.
1630 1644 // It can be implemented, but it may be rarely needed and not necessary.
1631 1645 PyCodeObject* code = (PyCodeObject*)func->func_code;
1632 1646 if (code->co_varnames) {
1633 1647 int nargs = code->co_argcount;
1634 1648 Q_ASSERT(PyTuple_Check(code->co_varnames));
1635 1649 for (int i=0; i<nargs; i++) {
1636 1650 PyObject* name = PyTuple_GetItem(code->co_varnames, i);
1637 1651 Q_ASSERT(PyString_Check(name));
1638 1652 arguments << PyString_AsString(name);
1639 1653 }
1640 1654 if (code->co_flags & CO_VARARGS) {
1641 1655 PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
1642 1656 Q_ASSERT(PyString_Check(s));
1643 1657 varargs = PyString_AsString(s);
1644 1658 nargs += 1;
1645 1659 }
1646 1660 if (code->co_flags & CO_VARKEYWORDS) {
1647 1661 PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
1648 1662 Q_ASSERT(PyString_Check(s));
1649 1663 varkeywords = PyString_AsString(s);
1650 1664 }
1651 1665 }
1652 1666
1653 1667 PyObject* defaultsTuple = func->func_defaults;
1654 1668 if (defaultsTuple) {
1655 1669 Q_ASSERT(PyTuple_Check(defaultsTuple));
1656 1670 for (Py_ssize_t i=0; i<PyTuple_Size(defaultsTuple); i++) {
1657 1671 PyObject* d = PyTuple_GetItem(defaultsTuple, i);
1658 1672 PyObject* s = PyObject_Repr(d);
1659 1673 Q_ASSERT(PyString_Check(s));
1660 1674 defaults << PyString_AsString(s);
1661 1675 Py_DECREF(s);
1662 1676 }
1663 1677 }
1664 1678
1665 1679 int firstdefault = arguments.size() - defaults.size();
1666 1680 for (int i=0; i<arguments.size(); i++) {
1667 1681 if (!signature.isEmpty()) { signature += ", "; }
1668 1682 if (!method || i>0 || arguments[i] != "self") {
1669 1683 signature += arguments[i];
1670 1684 if (i >= firstdefault) {
1671 1685 signature += "=" + defaults[i-firstdefault];
1672 1686 }
1673 1687 }
1674 1688 }
1675 1689 if (!varargs.isEmpty()) {
1676 1690 if (!signature.isEmpty()) { signature += ", "; }
1677 1691 signature += "*" + varargs;
1678 1692 }
1679 1693 if (!varkeywords.isEmpty()) {
1680 1694 if (!signature.isEmpty()) { signature += ", "; }
1681 1695 signature += "**" + varkeywords;
1682 1696 }
1683 1697 signature = funcName + "(" + signature + ")";
1684 1698 }
1685 1699
1686 1700 if (method && decrefMethod) {
1687 1701 Py_DECREF(method);
1688 1702 }
1689 1703 }
1690 1704
1691 1705 return signature;
1692 1706 }
1707
1708 void PythonQtPrivate::shellClassDeleted( void* shellClass )
1709 {
1710 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(shellClass);
1711 if (wrap && wrap->_wrappedPtr) {
1712 // this is a pure C++ wrapper and the shell has gone, so we need
1713 // to set the _wrappedPtr to NULL on the wrapper
1714 wrap->_wrappedPtr = NULL;
1715 // and then we remove the wrapper, since the wrapped class is gone
1716 _wrappedObjects.remove(shellClass);
1717 }
1718 // if the wrapper is a QObject, we do not handle this here,
1719 // it will be handled by the QPointer<> to the QObject, which becomes NULL
1720 // via the QObject destructor.
1721 } No newline at end of file
@@ -1,711 +1,714
1 1 #ifndef _PYTHONQT_H
2 2 #define _PYTHONQT_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, 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 "PythonQtStdIn.h"
51 51 #include <QObject>
52 52 #include <QVariant>
53 53 #include <QList>
54 54 #include <QHash>
55 55 #include <QByteArray>
56 56 #include <QStringList>
57 57 #include <QtDebug>
58 58 #include <iostream>
59 59
60 60
61 61 class PythonQtClassInfo;
62 62 class PythonQtPrivate;
63 63 class PythonQtMethodInfo;
64 64 class PythonQtSignalReceiver;
65 65 class PythonQtImportFileInterface;
66 66 class PythonQtCppWrapperFactory;
67 67 class PythonQtForeignWrapperFactory;
68 68 class PythonQtQFileImporter;
69 69
70 70 typedef void PythonQtQObjectWrappedCB(QObject* object);
71 71 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
72 72 typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, const char **class_name);
73 73
74 74 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
75 75
76 76 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) {
77 77 (reinterpret_cast<T*>(object))->_wrapper = wrapper;
78 78 }
79 79
80 80 //! returns the offset that needs to be added to upcast an object of type T1 to T2
81 81 template<class T1, class T2> int PythonQtUpcastingOffset() {
82 82 return ((reinterpret_cast<char*>(static_cast<T2*>(reinterpret_cast<T1*>(0x100))))
83 83 - (reinterpret_cast<char*>(reinterpret_cast<T1*>(0x100))));
84 84 }
85 85
86 86 //! callback to create a QObject lazily
87 87 typedef QObject* PythonQtQObjectCreatorFunctionCB();
88 88
89 89 //! helper template to create a derived QObject class
90 90 template<class T> QObject* PythonQtCreateObject() { return new T(); };
91 91
92 92 //! The main interface to the Python Qt binding, realized as a singleton
93 93 /*!
94 94 Use PythonQt::init() to initialize the singleton and PythonQt::self() to access it.
95 95 While there can be only one PythonQt instance, you can have any number of Python context to do scripting in.
96 96 One possibility is to use createModuleFromFile(), createModuleFromScript() or createUniqueModule() to get a context
97 97 that is separated from the other contexts. Alternatively you can use Python dicts as contexts for script evaluation,
98 98 but you will need to populate the dict with the __builtins__ instance to have all Pythons available when running
99 99 code in the scope of a dict.
100 100 */
101 101 class PYTHONQT_EXPORT PythonQt : public QObject {
102 102
103 103 Q_OBJECT
104 104
105 105 public:
106 106
107 107 //! flags that can be passed to PythonQt::init()
108 108 enum InitFlags {
109 109 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
110 110 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
111 111 ExternalHelp = 4, //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
112 112 PythonAlreadyInitialized = 8 //!<< sets that PythonQt should not can PyInitialize, since it is already done
113 113 };
114 114
115 115 //! flags that tell PythonQt which operators to expect on the registered type
116 116 enum TypeSlots {
117 117 Type_Add = 1,
118 118 Type_Subtract = 1 << 1,
119 119 Type_Multiply = 1 << 2,
120 120 Type_Divide = 1 << 3,
121 121 Type_Mod = 1 << 4,
122 122 Type_And = 1 << 5,
123 123 Type_Or = 1 << 6,
124 124 Type_Xor = 1 << 7,
125 125 Type_LShift = 1 << 8,
126 126 Type_RShift = 1 << 9,
127 127
128 128 Type_InplaceAdd = 1 << 10,
129 129 Type_InplaceSubtract = 1 << 11,
130 130 Type_InplaceMultiply = 1 << 12,
131 131 Type_InplaceDivide = 1 << 13,
132 132 Type_InplaceMod = 1 << 14,
133 133 Type_InplaceAnd = 1 << 15,
134 134 Type_InplaceOr = 1 << 16,
135 135 Type_InplaceXor = 1 << 17,
136 136 Type_InplaceLShift = 1 << 18,
137 137 Type_InplaceRShift = 1 << 19,
138 138
139 139 // Not yet needed/nicely mappable/generated...
140 140 //Type_Positive = 1 << 29,
141 141 //Type_Negative = 1 << 29,
142 142 //Type_Abs = 1 << 29,
143 143 //Type_Hash = 1 << 29,
144 144
145 145 Type_Invert = 1 << 29,
146 146 Type_RichCompare = 1 << 30,
147 147 Type_NonZero = 1 << 31,
148 148
149 149 };
150 150
151 151 //! enum for profiling callback
152 152 enum ProfilingCallbackState {
153 153 Enter = 1,
154 154 Leave = 2
155 155 };
156 156
157 157 //! callback for profiling. className and methodName are only passed when state == Enter, otherwise
158 158 //! they are NULL.
159 159 typedef void ProfilingCB(ProfilingCallbackState state, const char* className, const char* methodName);
160 160
161 161 //---------------------------------------------------------------------------
162 162 //! \name Singleton Initialization
163 163 //@{
164 164
165 165 //! initialize the python qt binding (flags are a or combination of PythonQt::InitFlags), if \c pythonQtModuleName is given
166 166 //! it defines the name of the python module that PythonQt will add, otherwise "PythonQt" is used.
167 167 //! This can be used to e.g. pass in PySide or PyQt4 to make it more compatible.
168 168 static void init(int flags = IgnoreSiteModule | RedirectStdOut, const QByteArray& pythonQtModuleName = QByteArray());
169 169
170 170 //! cleanup of the singleton
171 171 static void cleanup();
172 172
173 173 //! get the singleton instance
174 174 static PythonQt* self();
175 175
176 176 //@}
177 177
178 178 //! defines the object types for introspection
179 179 enum ObjectType {
180 180 Class,
181 181 Function,
182 182 Variable,
183 183 Module,
184 184 Anything,
185 185 CallOverloads
186 186 };
187 187
188 188
189 189 //---------------------------------------------------------------------------
190 190 //! \name Standard input handling
191 191 //@{
192 192
193 193 //! Overwrite default handling of stdin using a custom callback. It internally backup
194 194 //! the original 'sys.stdin' into 'sys.pythonqt_original_stdin'
195 195 void setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData = 0);
196 196
197 197 //! Enable or disable stdin custom callback. It resets 'sys.stdin' using either 'sys.pythonqt_stdin'
198 198 //! or 'sys.pythonqt_original_stdin'
199 199 void setRedirectStdInCallbackEnabled(bool enabled);
200 200
201 201 //@}
202 202
203 203 //---------------------------------------------------------------------------
204 204 //! \name Modules
205 205 //@{
206 206
207 207 //! get the __main__ module of python
208 208 PythonQtObjectPtr getMainModule();
209 209
210 210 //! import the given module and return a reference to it (useful to import e.g. "sys" and call something on it)
211 211 //! If a module is already imported, this returns the already imported module.
212 212 PythonQtObjectPtr importModule(const QString& name);
213 213
214 214 //! creates the new module \c name and evaluates the given file in the context of that module
215 215 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
216 216 //! to a module later on.
217 217 //! The user needs to make sure that the \c name is unique in the python module dictionary.
218 218 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
219 219
220 220 //! creates the new module \c name and evaluates the given script in the context of that module.
221 221 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
222 222 //! to a module later on.
223 223 //! The user needs to make sure that the \c name is unique in the python module dictionary.
224 224 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
225 225
226 226 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
227 227 //! script code
228 228 PythonQtObjectPtr createUniqueModule();
229 229
230 230 //@}
231 231
232 232 //---------------------------------------------------------------------------
233 233 //! \name Importing/Paths
234 234 //@{
235 235
236 236 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
237 237 void overwriteSysPath(const QStringList& paths);
238 238
239 239 //! prepend a path to sys.path to allow importing from it
240 240 void addSysPath(const QString& path);
241 241
242 242 //! sets the __path__ list of a module to the given list (important for local imports)
243 243 void setModuleImportPath(PyObject* module, const QStringList& paths);
244 244
245 245 //@}
246 246
247 247 //---------------------------------------------------------------------------
248 248 //! \name Registering Classes
249 249 //@{
250 250
251 251 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
252 252 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
253 253 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
254 254 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
255 255
256 256 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
257 257 //! (ownership of wrapper is passed to PythonQt)
258 258 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
259 259
260 260 This will add a wrapper object that is used to make calls to the given classname \c typeName.
261 261 All slots that take a pointer to typeName as the first argument will be callable from Python on
262 262 a variant object that contains such a type.
263 263 */
264 264 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
265 265
266 266 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
267 267 //! and it will register the classes when it first sees a pointer to such a derived class
268 268 void registerQObjectClassNames(const QStringList& names);
269 269
270 270 //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance
271 271 //! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that
272 272 //! type is really derived from parentType.
273 273 //! Returns false if the typeName was not yet registered.
274 274 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
275 275
276 276 //! add a handler for polymorphic downcasting
277 277 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
278 278
279 279 //@}
280 280
281 281 //---------------------------------------------------------------------------
282 282 //! \name Script Parsing and Evaluation
283 283 //@{
284 284
285 285 //! parses the given file and returns the python code object, this can then be used to call evalCode()
286 286 PythonQtObjectPtr parseFile(const QString& filename);
287 287
288 288 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
289 289 //! If pycode is NULL, a python error is printed.
290 290 QVariant evalCode(PyObject* object, PyObject* pycode);
291 291
292 292 //! evaluates the given script code and returns the result value
293 293 QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input);
294 294
295 295 //! evaluates the given script code from file
296 296 void evalFile(PyObject* object, const QString& filename);
297 297
298 298 //@}
299 299
300 300 //---------------------------------------------------------------------------
301 301 //! \name Signal Handlers
302 302 //@{
303 303
304 304 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
305 305 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
306 306
307 307 //! remove a signal handler from the given \c signal of \c obj
308 308 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
309 309
310 310 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
311 311 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
312 312
313 313 //! remove a signal handler from the given \c signal of \c obj
314 314 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
315 315
316 316 //@}
317 317
318 318 //---------------------------------------------------------------------------
319 319 //! \name Variable access
320 320 //@{
321 321
322 322 //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable)
323 323 void addObject(PyObject* object, const QString& name, QObject* qObject);
324 324
325 325 //! add the given variable to the object
326 326 void addVariable(PyObject* object, const QString& name, const QVariant& v);
327 327
328 328 //! remove the given variable
329 329 void removeVariable(PyObject* module, const QString& name);
330 330
331 331 //! get the variable with the \c name of the \c object, returns an invalid QVariant on error
332 332 QVariant getVariable(PyObject* object, const QString& name);
333 333
334 334 //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname
335 335 QStringList introspection(PyObject* object, const QString& objectname, ObjectType type);
336 336 //! read vars etc. in scope of the given \c object
337 337 QStringList introspectObject(PyObject* object, ObjectType type);
338 338 //! read vars etc. in scope of the type object called \c typename. First the typename
339 339 //! of the form module.type is split into module and type. Then the module is looked up
340 340 //! in sys.modules. If the module or type is not found there, then the type is looked up in
341 341 //! the __builtin__ module.
342 342 QStringList introspectType(const QString& typeName, ObjectType type);
343 343
344 344 //! returns the found callable object or NULL
345 345 //! @return new reference
346 346 PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
347 347
348 348 //! returns the return type of the method of a wrapped c++ object referenced by \c objectname
349 349 QString getReturnTypeOfWrappedMethod(PyObject* module, const QString& objectname);
350 350 //! returns the return type of the method \c methodName of a wrapped c++ type referenced by \c typeName
351 351 QString getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName);
352 352 //@}
353 353
354 354 //---------------------------------------------------------------------------
355 355 //! \name Calling Python Objects
356 356 //@{
357 357
358 358 //! call the given python \c callable in the scope of object, returns the result converted to a QVariant
359 359 QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList());
360 360
361 361 //! call the given python object, returns the result converted to a QVariant
362 362 QVariant call(PyObject* callable, const QVariantList& args = QVariantList());
363 363
364 364 //! call the given python object, returns the result as new PyObject
365 365 PyObject* callAndReturnPyObject(PyObject* callable, const QVariantList& args = QVariantList());
366 366
367 367 //@}
368 368
369 369 //---------------------------------------------------------------------------
370 370 //! \name Decorations, Constructors, Wrappers...
371 371 //@{
372 372
373 373 //! add an object whose slots will be used as decorator slots for
374 374 //! other QObjects or CPP classes. The slots need to follow the
375 375 //! convention that the first argument is a pointer to the wrapped object.
376 376 //! (ownership is passed to PythonQt)
377 377 /*!
378 378 Example:
379 379
380 380 A slot with the signature
381 381
382 382 \code
383 383 bool doSomething(QWidget* w, int a)
384 384 \endcode
385 385
386 386 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
387 387 that will be called with the concrete instance as first argument.
388 388 So in Python you can now e.g. call
389 389
390 390 \code
391 391 someWidget.doSomething(12)
392 392 \endcode
393 393
394 394 without QWidget really having this method. This allows to easily make normal methods
395 395 of Qt classes callable by forwarding them with such decorator slots
396 396 or to make CPP classes (which are not derived from QObject) callable from Python.
397 397 */
398 398 void addInstanceDecorators(QObject* o);
399 399
400 400 //! add an object whose slots will be used as decorator slots for
401 401 //! class objects (ownership is passed to PythonQt)
402 402 /*!
403 403 The slots need to follow the following convention:
404 404 - SomeClass* new_SomeClass(...)
405 405 - QVariant new_SomeClass(...)
406 406 - void delete_SomeClass(SomeClass*)
407 407 - ... static_SomeClass_someName(...)
408 408
409 409 This will add:
410 410 - a constructor
411 411 - a constructor which generates a QVariant
412 412 - a destructor (only useful for CPP objects)
413 413 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
414 414
415 415 */
416 416 void addClassDecorators(QObject* o);
417 417
418 418 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
419 419 void addDecorators(QObject* o);
420 420
421 421 //! add the given factory to PythonQt (ownership stays with caller)
422 422 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
423 423
424 424 //! add the given factory to PythonQt (ownership stays with caller)
425 425 void addWrapperFactory(PythonQtForeignWrapperFactory* factory);
426 426
427 427 //! remove the wrapper factory
428 428 void removeWrapperFactory(PythonQtCppWrapperFactory* factory);
429 429
430 430 //! remove the wrapper factory
431 431 void removeWrapperFactory(PythonQtForeignWrapperFactory* factory);
432 432
433 433 //@}
434 434
435 435 //---------------------------------------------------------------------------
436 436 //! \name Custom Importer
437 437 //@{
438 438
439 439 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
440 440 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
441 441 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
442 442 //! This is not reversible, so even setting setImporter(NULL) afterwards will
443 443 //! keep the custom PythonQt importer with a QFile default import interface.
444 444 //! Subsequent python import calls will make use of the passed importInterface
445 445 //! which forwards all import calls to the given \c importInterface.
446 446 //! Passing NULL will install a default QFile importer.
447 447 //! (\c importInterface ownership stays with caller)
448 448 void setImporter(PythonQtImportFileInterface* importInterface);
449 449
450 450 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
451 451 //! (without calling setImporter or installDefaultImporter at least once, the default python import
452 452 //! mechanism is in place)
453 453 //! the default importer allows to import files from anywhere QFile can read from,
454 454 //! including the Qt resource system using ":". Keep in mind that you need to extend
455 455 //! "sys.path" with ":" to be able to import from the Qt resources.
456 456 void installDefaultImporter() { setImporter(NULL); }
457 457
458 458 //! set paths that the importer should ignore
459 459 void setImporterIgnorePaths(const QStringList& paths);
460 460
461 461 //! get paths that the importer should ignore
462 462 const QStringList& getImporterIgnorePaths();
463 463
464 464 //! get access to the file importer (if set)
465 465 static PythonQtImportFileInterface* importInterface();
466 466
467 467 //@}
468 468
469 469 //---------------------------------------------------------------------------
470 470 //! \name Other Stuff
471 471 //@{
472 472
473 473 //! get access to internal data (should not be used on the public API, but is used by some C functions)
474 474 static PythonQtPrivate* priv() { return _self->_p; }
475 475
476 476 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
477 477 //! The error is currently just output to the python stderr, future version might implement better trace printing
478 478 bool handleError();
479 479
480 480 //! clear all NotFound entries on all class infos, to ensure that
481 481 //! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded
482 482 void clearNotFoundCachedMembers();
483 483
484 484 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
485 485 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
486 486 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
487 487 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
488 488
489 489 //! call the callback if it is set
490 490 static void qObjectNoLongerWrappedCB(QObject* o);
491 491
492 492 //! called by internal help methods
493 493 PyObject* helpCalled(PythonQtClassInfo* info);
494 494
495 495 //! returns the found object or NULL
496 496 //! @return new reference
497 497 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
498 498
499 499 //! sets a callback that is called before and after function calls for profiling
500 500 void setProfilingCallback(ProfilingCB* cb);
501 501
502 502 //@}
503 503
504 504 signals:
505 505 //! emitted when python outputs something to stdout (and redirection is turned on)
506 506 void pythonStdOut(const QString& str);
507 507 //! emitted when python outputs something to stderr (and redirection is turned on)
508 508 void pythonStdErr(const QString& str);
509 509
510 510 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
511 511 void pythonHelpRequest(const QByteArray& cppClassName);
512 512
513 513 private:
514 514 void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName);
515 515
516 516 QString getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context);
517 517
518 518 PyObject* getObjectByType(const QString& typeName);
519 519
520 520 //! callback for stdout redirection, emits pythonStdOut signal
521 521 static void stdOutRedirectCB(const QString& str);
522 522 //! callback for stderr redirection, emits pythonStdErr signal
523 523 static void stdErrRedirectCB(const QString& str);
524 524
525 525 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
526 526 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
527 527
528 528 PythonQt(int flags, const QByteArray& pythonQtModuleName);
529 529 ~PythonQt();
530 530
531 531 static PythonQt* _self;
532 532 static int _uniqueModuleCount;
533 533
534 534 PythonQtPrivate* _p;
535 535
536 536 };
537 537
538 538 //! internal PythonQt details
539 539 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
540 540
541 541 Q_OBJECT
542 542
543 543 public:
544 544 PythonQtPrivate();
545 545 ~PythonQtPrivate();
546 546
547 547 enum DecoratorTypes {
548 548 StaticDecorator = 1,
549 549 ConstructorDecorator = 2,
550 550 DestructorDecorator = 4,
551 551 InstanceDecorator = 8,
552 552 AllDecorators = 0xffff
553 553 };
554 554
555 555 //! get the suffixes that are used for shared libraries
556 556 const QStringList& sharedLibrarySuffixes() { return _sharedLibrarySuffixes; }
557 557
558 558 //! returns if the id is the id for PythonQtObjectPtr
559 559 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
560 560
561 561 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
562 562 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
563 563 //! remove the wrapper ptr again
564 564 void removeWrapperPointer(void* obj);
565 565
566 //! called by destructor of shells to allow invalidation of the Python wrapper
567 void shellClassDeleted(void* shellClass);
568
566 569 //! try to unwrap the given object to a C++ pointer using the foreign wrapper factories
567 570 void* unwrapForeignWrapper(const QByteArray& classname, PyObject* obj);
568 571
569 572 //! add parent class relation
570 573 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
571 574
572 575 //! add a handler for polymorphic downcasting
573 576 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
574 577
575 578 //! lookup existing classinfo and return new if not yet present
576 579 PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
577 580
578 581 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
579 582 void removeSignalEmitter(QObject* obj);
580 583
581 584 //! wrap the given QObject into a Python object (or return existing wrapper!)
582 585 PyObject* wrapQObject(QObject* obj);
583 586
584 587 //! 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
585 588 PyObject* wrapPtr(void* ptr, const QByteArray& name);
586 589
587 590 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
588 591 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
589 592 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
590 593 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
591 594
592 595 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
593 596 //! (ownership of wrapper is passed to PythonQt)
594 597 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
595 598
596 599 This will add a wrapper object that is used to make calls to the given classname \c typeName.
597 600 All slots that take a pointer to typeName as the first argument will be callable from Python on
598 601 a variant object that contains such a type.
599 602 */
600 603 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
601 604
602 605 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
603 606 //! and it will register the classes when it first sees a pointer to such a derived class
604 607 void registerQObjectClassNames(const QStringList& names);
605 608
606 609 //! add a decorator object
607 610 void addDecorators(QObject* o, int decoTypes);
608 611
609 612 //! helper method that creates a PythonQtClassWrapper object (returns a new reference)
610 613 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* module);
611 614
612 615 //! create a new instance of the given enum type with given value (returns a new reference)
613 616 static PyObject* createEnumValueInstance(PyObject* enumType, unsigned int enumValue);
614 617
615 618 //! helper that creates a new int derived class that represents the enum of the given name (returns a new reference)
616 619 static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
617 620
618 621 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
619 622 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
620 623
621 624 //! get the class info for a meta object (if available)
622 625 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
623 626
624 627 //! get the class info for a meta object (if available)
625 628 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
626 629
627 630 //! creates the new module from the given pycode
628 631 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
629 632
630 633 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
631 634 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
632 635
633 636 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
634 637 static PyObject* dummyTuple();
635 638
636 639 //! called by virtual overloads when a python return value can not be converted to the required Qt type
637 640 void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result);
638 641
639 642 //! get access to the PythonQt module
640 643 PythonQtObjectPtr pythonQtModule() const { return _pythonQtModule; }
641 644
642 645 //! returns the profiling callback, which may be NULL
643 646 PythonQt::ProfilingCB* profilingCB() const { return _profilingCB; }
644 647
645 648 //! determines the signature of the given callable object (similar as pydoc)
646 649 QString getSignature(PyObject* object);
647 650
648 651 //! returns true if the object is a method descriptor (same as inspect.ismethoddescriptor() in inspect.py)
649 652 bool isMethodDescriptor(PyObject* object) const;
650 653
651 654 private:
652 655 //! Setup the shared library suffixes by getting them from the "imp" module.
653 656 void setupSharedLibrarySuffixes();
654 657
655 658 //! create a new pythonqt class wrapper and place it in the pythonqt module
656 659 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module = NULL);
657 660
658 661 //! get/create new package module (the returned object is a borrowed reference)
659 662 PyObject* packageByName(const char* name);
660 663
661 664 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
662 665 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
663 666
664 667 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
665 668 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
666 669
667 670 //! stores the meta info of known Qt classes
668 671 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
669 672
670 673 //! names of qobject derived classes that can be casted to qobject savely
671 674 QHash<QByteArray, bool> _knownQObjectClassNames;
672 675
673 676 //! stores signal receivers for QObjects
674 677 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
675 678
676 679 //! the PythonQt python module
677 680 PythonQtObjectPtr _pythonQtModule;
678 681
679 682 //! the name of the PythonQt python module
680 683 QByteArray _pythonQtModuleName;
681 684
682 685 //! the importer interface (if set)
683 686 PythonQtImportFileInterface* _importInterface;
684 687
685 688 //! the default importer
686 689 PythonQtQFileImporter* _defaultImporter;
687 690
688 691 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
689 692 PythonQtQObjectWrappedCB* _wrappedCB;
690 693
691 694 QStringList _importIgnorePaths;
692 695 QStringList _sharedLibrarySuffixes;
693 696
694 697 //! the cpp object wrapper factories
695 698 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
696 699
697 700 QList<PythonQtForeignWrapperFactory*> _foreignWrapperFactories;
698 701
699 702 QHash<QByteArray, PyObject*> _packages;
700 703
701 704 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
702 705
703 706 PythonQt::ProfilingCB* _profilingCB;
704 707
705 708 int _initFlags;
706 709 int _PythonQtObjectPtr_metaId;
707 710
708 711 friend class PythonQt;
709 712 };
710 713
711 714 #endif
@@ -1,894 +1,885
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, 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 "PythonQtClassInfo.h"
43 43 #include "PythonQtMethodInfo.h"
44 44 #include "PythonQt.h"
45 45 #include <QMetaMethod>
46 46 #include <QMetaObject>
47 47 #include <QMetaEnum>
48 48
49 49 QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;
50 50
51 51 PythonQtClassInfo::PythonQtClassInfo() {
52 52 _meta = NULL;
53 53 _constructors = NULL;
54 54 _destructor = NULL;
55 55 _decoratorProvider = NULL;
56 56 _decoratorProviderCB = NULL;
57 57 _pythonQtClassWrapper = NULL;
58 58 _shellSetInstanceWrapperCB = NULL;
59 59 _metaTypeId = -1;
60 60 _typeSlots = 0;
61 61 _isQObject = false;
62 62 _enumsCreated = false;
63 63 }
64 64
65 65 PythonQtClassInfo::~PythonQtClassInfo()
66 66 {
67 67 clearCachedMembers();
68 68
69 69 if (_constructors) {
70 70 _constructors->deleteOverloadsAndThis();
71 71 }
72 72 if (_destructor) {
73 73 _destructor->deleteOverloadsAndThis();
74 74 }
75 75 foreach(PythonQtSlotInfo* info, _decoratorSlots) {
76 76 info->deleteOverloadsAndThis();
77 77 }
78 78 }
79 79
80 80 void PythonQtClassInfo::setupQObject(const QMetaObject* meta)
81 81 {
82 82 // _wrappedClassName is already set earlier in the class setup
83 83 _isQObject = true;
84 84 _meta = meta;
85 85 }
86 86
87 87 void PythonQtClassInfo::setupCPPObject(const QByteArray& classname)
88 88 {
89 89 _isQObject = false;
90 90 _wrappedClassName = classname;
91 91 _metaTypeId = QMetaType::type(classname);
92 92 }
93 93
94 94 void PythonQtClassInfo::clearCachedMembers()
95 95 {
96 96 QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers);
97 97 while (i.hasNext()) {
98 98 PythonQtMemberInfo member = i.next().value();
99 99 if (member._type== PythonQtMemberInfo::Slot || member._type== PythonQtMemberInfo::Signal) {
100 100 PythonQtSlotInfo* info = member._slot;
101 101 while (info) {
102 102 PythonQtSlotInfo* next = info->nextInfo();
103 103 delete info;
104 104 info = next;
105 105 }
106 106 }
107 107 }
108 108 }
109 109
110 110 int PythonQtClassInfo::findCharOffset(const char* sigStart, char someChar)
111 111 {
112 112 const char* sigEnd = sigStart;
113 113 char c;
114 114 do {
115 115 c = *sigEnd++;
116 116 } while (c!=someChar && c!=0);
117 117 return sigEnd-sigStart-1;
118 118 }
119 119
120 120 bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName)
121 121 {
122 122 if (!_meta) return false;
123 123
124 124 bool found = false;
125 125 bool nameMapped = false;
126 126 const char* attributeName = memberName;
127 127 // look for properties
128 128 int i = _meta->indexOfProperty(attributeName);
129 129 if (i==-1) {
130 130 // try to map name to objectName
131 131 if (qstrcmp(attributeName, "name")==0) {
132 132 attributeName = "objectName";
133 133 nameMapped = true;
134 134 i = _meta->indexOfProperty(attributeName);
135 135 }
136 136 }
137 137 if (i!=-1) {
138 138 PythonQtMemberInfo newInfo(_meta->property(i));
139 139 _cachedMembers.insert(attributeName, newInfo);
140 140 if (nameMapped) {
141 141 _cachedMembers.insert(memberName, newInfo);
142 142 }
143 143 #ifdef PYTHONQT_DEBUG
144 144 std::cout << "caching property " << memberName << " on " << _meta->className() << std::endl;
145 145 #endif
146 146 found = true;
147 147 }
148 148 return found;
149 149 }
150 150
151 151 PythonQtSlotInfo* PythonQtClassInfo::recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
152 152 {
153 153 inputInfo = findDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset);
154 154 foreach(const ParentClassInfo& info, _parentClasses) {
155 155 inputInfo = info._parent->recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset+info._upcastingOffset);
156 156 }
157 157 return inputInfo;
158 158 }
159 159
160 160 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset) {
161 161 QObject* decoratorProvider = decorator();
162 162 int memberNameLen = static_cast<int>(strlen(memberName));
163 163 if (decoratorProvider) {
164 164 //qDebug()<< "looking " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
165 165 const QMetaObject* meta = decoratorProvider->metaObject();
166 166 int numMethods = meta->methodCount();
167 167 int startFrom = QObject::staticMetaObject.methodCount();
168 168 for (int i = startFrom; i < numMethods; i++) {
169 169 QMetaMethod m = meta->method(i);
170 170 if ((m.methodType() == QMetaMethod::Method ||
171 171 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
172 172
173 173 const char* sigStart = m.signature();
174 174 bool isClassDeco = false;
175 175 if (qstrncmp(sigStart, "static_", 7)==0) {
176 176 // skip the static_classname_ part of the string
177 177 sigStart += 7 + 1 + strlen(className());
178 178 isClassDeco = true;
179 179 } else if (qstrncmp(sigStart, "new_", 4)==0) {
180 180 isClassDeco = true;
181 181 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
182 182 isClassDeco = true;
183 183 }
184 184 // find the first '('
185 185 int offset = findCharOffset(sigStart, '(');
186 186
187 187 // XXX no checking is currently done if the slots have correct first argument or not...
188 188
189 189 // check if same length and same name
190 190 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
191 191 found = true;
192 192 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i, decoratorProvider, isClassDeco?PythonQtSlotInfo::ClassDecorator:PythonQtSlotInfo::InstanceDecorator);
193 193 info->setUpcastingOffset(upcastingOffset);
194 194 //qDebug()<< "adding " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
195 195 if (tail) {
196 196 tail->setNextInfo(info);
197 197 } else {
198 198 PythonQtMemberInfo newInfo(info);
199 199 memberCache.insert(memberName, newInfo);
200 200 }
201 201 tail = info;
202 202 }
203 203 }
204 204 }
205 205 }
206 206
207 207 tail = findDecoratorSlots(memberName, memberNameLen, tail, found, memberCache, upcastingOffset);
208 208
209 return tail;
210 }
211
212 bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName)
213 {
214 bool found = false;
215 int memberNameLen = static_cast<int>(strlen(memberName));
216 PythonQtSlotInfo* tail = NULL;
209 // now look for slots/signals/methods on this level of the meta object
217 210 if (_meta) {
218 211 int numMethods = _meta->methodCount();
219 for (int i = 0; i < numMethods; i++) {
212 // start from methodOffset, to only add slots which are located in this class,
213 // and not in the parent class, which is traversed recursively later on.
214 // (if the class in not a QObject, we are working with a script wrapper QObject
215 // and need to read all slots/signals starting from 0).
216 int methodOffset = _isQObject?_meta->methodOffset():0;
217 for (int i = methodOffset; i < numMethods; i++) {
220 218 QMetaMethod m = _meta->method(i);
221 219 if (((m.methodType() == QMetaMethod::Method ||
222 220 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public)
223 221 || m.methodType()==QMetaMethod::Signal) {
224 222
225 223 const char* sigStart = m.signature();
226 224 // find the first '('
227 225 int offset = findCharOffset(sigStart, '(');
228 226
229 227 // check if same length and same name
230 228 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
231 229 found = true;
232 230 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i);
233 231 if (tail) {
234 232 tail->setNextInfo(info);
235 233 } else {
236 234 PythonQtMemberInfo newInfo(info);
237 _cachedMembers.insert(memberName, newInfo);
235 memberCache.insert(memberName, newInfo);
238 236 }
239 237 tail = info;
240 238 }
241 239 }
242 240 }
243 241 }
242 return tail;
243 }
244
245 bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName)
246 {
247 bool found = false;
248 PythonQtSlotInfo* tail = NULL;
244 249
245 250 // look for dynamic decorators in this class and in derived classes
251 // (do this first to allow overloading of existing slots with generated wrappers,
252 // e.g. QDialog::accept is overloaded with PythonQtWrapper_QDialog::accept decorator)
246 253 tail = recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, tail, found, _cachedMembers, 0);
247 254
248 255 return found;
249 256 }
250 257
251 258 bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* memberName)
252 259 {
253 260 bool found = false;
254 261 // look for enum values
255 262 int enumCount = meta->enumeratorCount();
256 263 for (int i=0;i<enumCount; i++) {
257 264 QMetaEnum e = meta->enumerator(i);
258 265 // we do not want flags, they will cause our values to appear two times
259 266 if (e.isFlag()) continue;
260 267
261 268 for (int j=0; j < e.keyCount(); j++) {
262 269 if (qstrcmp(e.key(j), memberName)==0) {
263 270 PyObject* enumType = findEnumWrapper(e.name());
264 271 if (enumType) {
265 272 PythonQtObjectPtr enumValuePtr;
266 273 enumValuePtr.setNewRef(PythonQtPrivate::createEnumValueInstance(enumType, e.value(j)));
267 274 PythonQtMemberInfo newInfo(enumValuePtr);
268 275 _cachedMembers.insert(memberName, newInfo);
269 276 #ifdef PYTHONQT_DEBUG
270 277 std::cout << "caching enum " << memberName << " on " << meta->className() << std::endl;
271 278 #endif
272 279 found = true;
273 280 break;
274 281 } else {
275 282 std::cout << "enum " << e.name() << " not found on " << className() << std::endl;
276 283 }
277 284 }
278 285 }
279 286 }
280 287 return found;
281 288 }
282 289
283 290 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
284 291 {
285 292 PythonQtMemberInfo info = _cachedMembers.value(memberName);
286 293 if (info._type != PythonQtMemberInfo::Invalid) {
287 294 return info;
288 295 } else {
289 296 bool found = false;
290 297
291 298 found = lookForPropertyAndCache(memberName);
292 299 if (!found) {
293 300 found = lookForMethodAndCache(memberName);
294 301 }
295 302 if (!found) {
296 303 if (_meta) {
297 304 // check enums in our meta object directly
298 305 found = lookForEnumAndCache(_meta, memberName);
299 306 }
300 307 if (!found) {
301 308 // check enums in the class hierachy of CPP classes
302 309 // look for dynamic decorators in this class and in derived classes
303 310 QList<QObject*> decoObjects;
304 311 recursiveCollectDecoratorObjects(decoObjects);
305 312 foreach(QObject* deco, decoObjects) {
306 313 // call on ourself for caching, but with different metaObject():
307 314 found = lookForEnumAndCache(deco->metaObject(), memberName);
308 315 if (found) {
309 316 break;
310 317 }
311 318 }
312 319 }
313 320 }
314 321 if (!found) {
315 322 // maybe it is an enum wrapper?
316 323 PyObject* p = findEnumWrapper(memberName);
317 324 if (p) {
318 325 info._type = PythonQtMemberInfo::EnumWrapper;
319 326 info._enumWrapper = p;
320 327 _cachedMembers.insert(memberName, info);
321 328 found = true;
322 329 }
323 330 }
324 331 if (!found) {
325 332 // since python keywords can not be looked up, we check if the name contains a single trailing _
326 333 // and remove that and look again, so that we e.g. find exec on an exec_ lookup
327 334 QByteArray mbrName(memberName);
328 335 if ((mbrName.length()>2) &&
329 336 (mbrName.at(mbrName.length()-1) == '_') &&
330 337 (mbrName.at(mbrName.length()-2) != '_')) {
331 338 mbrName = mbrName.mid(0,mbrName.length()-1);
332 339 found = lookForMethodAndCache(mbrName.constData());
333 340 if (found) {
334 341 return _cachedMembers.value(mbrName);
335 342 }
336 343 }
337 344 }
338 345 if (!found) {
339 346 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
340 347 info._type = PythonQtMemberInfo::NotFound;
341 348 _cachedMembers.insert(memberName, info);
342 349 }
343 350 }
344 351
345 352 return _cachedMembers.value(memberName);
346 353 }
347 354
348 355 void PythonQtClassInfo::recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects) {
349 356 QObject* deco = decorator();
350 357 if (deco) {
351 358 decoratorObjects.append(deco);
352 359 }
353 360 foreach(const ParentClassInfo& info, _parentClasses) {
354 361 info._parent->recursiveCollectDecoratorObjects(decoratorObjects);
355 362 }
356 363 }
357 364
358 365 void PythonQtClassInfo::recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects) {
359 366 classInfoObjects.append(this);
360 367 foreach(const ParentClassInfo& info, _parentClasses) {
361 368 info._parent->recursiveCollectClassInfos(classInfoObjects);
362 369 }
363 370 }
364 371
365 372 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
366 373 {
367 374 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
368 375 while (it.hasNext()) {
369 376
370 377 PythonQtSlotInfo* infoOrig = it.next();
371 378
372 379 const char* sigStart = infoOrig->metaMethod()->signature();
373 380 if (qstrncmp("static_", sigStart, 7)==0) {
374 381 sigStart += 7;
375 382 sigStart += findCharOffset(sigStart, '_')+1;
376 383 }
377 384 int offset = findCharOffset(sigStart, '(');
378 385 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
379 386 //make a copy, otherwise we will have trouble on overloads!
380 387 PythonQtSlotInfo* info = new PythonQtSlotInfo(*infoOrig);
381 388 info->setUpcastingOffset(upcastingOffset);
382 389 found = true;
383 390 if (tail) {
384 391 tail->setNextInfo(info);
385 392 } else {
386 393 PythonQtMemberInfo newInfo(info);
387 394 memberCache.insert(memberName, newInfo);
388 395 }
389 396 tail = info;
390 397 }
391 398 }
392 399 return tail;
393 400 }
394 401
395 402 void PythonQtClassInfo::listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly) {
396 403 QObject* decoratorProvider = decorator();
397 404 if (decoratorProvider) {
398 405 const QMetaObject* meta = decoratorProvider->metaObject();
399 406 int numMethods = meta->methodCount();
400 407 int startFrom = QObject::staticMetaObject.methodCount();
401 408 for (int i = startFrom; i < numMethods; i++) {
402 409 QMetaMethod m = meta->method(i);
403 410 if ((m.methodType() == QMetaMethod::Method ||
404 411 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
405 412
406 413 const char* sigStart = m.signature();
407 414 bool isClassDeco = false;
408 415 if (qstrncmp(sigStart, "static_", 7)==0) {
409 416 // skip the static_classname_ part of the string
410 417 sigStart += 7 + 1 + strlen(className());
411 418 isClassDeco = true;
412 419 } else if (qstrncmp(sigStart, "new_", 4)==0) {
413 420 continue;
414 421 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
415 422 continue;
416 423 } else if (qstrncmp(sigStart, "py_", 3)==0) {
417 424 // hide everything that starts with py_
418 425 continue;
419 426 }
420 427 // find the first '('
421 428 int offset = findCharOffset(sigStart, '(');
422 429
423 430 // XXX no checking is currently done if the slots have correct first argument or not...
424 431 if (!metaOnly || isClassDeco) {
425 432 list << QString::fromLatin1(sigStart, offset);
426 433 }
427 434 }
428 435 }
429 436 }
430 437
431 438 // look for global decorator slots
432 439 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
433 440 while (it.hasNext()) {
434 441 PythonQtSlotInfo* slot = it.next();
435 442 if (metaOnly) {
436 443 if (slot->isClassDecorator()) {
437 444 QByteArray first = slot->slotName();
438 445 if (first.startsWith("static_")) {
439 446 int idx = first.indexOf('_');
440 447 idx = first.indexOf('_', idx+1);
441 448 first = first.mid(idx+1);
442 449 }
443 450 list << first;
444 451 }
445 452 } else {
446 453 list << slot->slotName();
447 454 }
448 455 }
449 456 }
450 457
451 458 QStringList PythonQtClassInfo::propertyList()
452 459 {
453 460 QStringList l;
454 461 if (_isQObject && _meta) {
455 462 int i;
456 463 int numProperties = _meta->propertyCount();
457 464 for (i = 0; i < numProperties; i++) {
458 465 QMetaProperty p = _meta->property(i);
459 466 l << QString(p.name());
460 467 }
461 468 }
462 469 return l;
463 470 }
464 471
465 472 QStringList PythonQtClassInfo::memberList()
466 473 {
467 474 decorator();
468 475
469 476 QStringList l;
470 477 QString h;
471 478 // normal slots of QObject (or wrapper QObject)
472 479 if (_meta) {
473 480 int numMethods = _meta->methodCount();
474 481 bool skipQObj = !_isQObject;
475 482 for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) {
476 483 QMetaMethod m = _meta->method(i);
477 484 if (((m.methodType() == QMetaMethod::Method ||
478 485 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public)
479 486 || m.methodType()==QMetaMethod::Signal) {
480 487 QByteArray signa(m.signature());
481 488 signa = signa.left(signa.indexOf('('));
482 489 l << signa;
483 490 }
484 491 }
485 492 }
486 493
487 494 {
488 495 // look for dynamic decorators in this class and in derived classes
489 496 QList<PythonQtClassInfo*> infos;
490 497 recursiveCollectClassInfos(infos);
491 498 foreach(PythonQtClassInfo* info, infos) {
492 499 info->listDecoratorSlotsFromDecoratorProvider(l, false);
493 500 }
494 501 }
495 502
496 503 // List enumerator keys...
497 504 QList<const QMetaObject*> enumMetaObjects;
498 505 if (_meta) {
499 506 enumMetaObjects << _meta;
500 507 }
501 508 // check enums in the class hierachy of CPP classes
502 509 QList<QObject*> decoObjects;
503 510 recursiveCollectDecoratorObjects(decoObjects);
504 511 foreach(QObject* deco, decoObjects) {
505 512 enumMetaObjects << deco->metaObject();
506 513 }
507 514
508 515 foreach(const QMetaObject* meta, enumMetaObjects) {
509 516 for (int i = 0; i<meta->enumeratorCount(); i++) {
510 517 QMetaEnum e = meta->enumerator(i);
511 518 l << e.name();
512 519 // we do not want flags, they will cause our values to appear two times
513 520 if (e.isFlag()) continue;
514 521
515 522 for (int j=0; j < e.keyCount(); j++) {
516 523 l << QString(e.key(j));
517 524 }
518 525 }
519 526 }
520 527
521 528 return QSet<QString>::fromList(l).toList();
522 529 }
523 530
524 531 const char* PythonQtClassInfo::className()
525 532 {
526 533 return _wrappedClassName.constData();
527 534 }
528 535
529 536 void* PythonQtClassInfo::castTo(void* ptr, const char* classname)
530 537 {
531 538 if (ptr==NULL) {
532 539 return NULL;
533 540 }
534 541 if (_wrappedClassName == classname) {
535 542 return ptr;
536 543 }
537 544 foreach(const ParentClassInfo& info, _parentClasses) {
538 545 void* result = info._parent->castTo((char*)ptr + info._upcastingOffset, classname);
539 546 if (result) {
540 547 return result;
541 548 }
542 549 }
543 550 return NULL;
544 551 }
545 552
546 553 bool PythonQtClassInfo::inherits(const char* name)
547 554 {
548 555 if (_wrappedClassName == name) {
549 556 return true;
550 557 }
551 558 foreach(const ParentClassInfo& info, _parentClasses) {
552 559 if (info._parent->inherits(name)) {
553 560 return true;
554 561 }
555 562 }
556 563 return false;
557 564 }
558 565
559 566 bool PythonQtClassInfo::inherits(PythonQtClassInfo* classInfo)
560 567 {
561 568 if (classInfo == this) {
562 569 return true;
563 570 }
564 571 foreach(const ParentClassInfo& info, _parentClasses) {
565 572 if (info._parent->inherits(classInfo)) {
566 573 return true;
567 574 }
568 575 }
569 576 return false;
570 577 }
571 578
572 579 QString PythonQtClassInfo::help()
573 580 {
574 581 decorator();
575 582 QString h;
576 583 h += QString("--- ") + QString(className()) + QString(" ---\n");
577 584
578 585 if (_isQObject) {
579 586 h += "Properties:\n";
580 587
581 588 int i;
582 589 int numProperties = _meta->propertyCount();
583 590 for (i = 0; i < numProperties; i++) {
584 591 QMetaProperty p = _meta->property(i);
585 592 h += QString(p.name()) + " (" + QString(p.typeName()) + " )\n";
586 593 }
587 594 }
588 595
589 596 if (constructors()) {
590 597 h += "Constructors:\n";
591 598 PythonQtSlotInfo* constr = constructors();
592 599 while (constr) {
593 600 h += constr->fullSignature() + "\n";
594 601 constr = constr->nextInfo();
595 602 }
596 603 }
597 604
598 605 h += "Slots:\n";
599 606 h += "QString help()\n";
600 607 h += "QString className()\n";
601 608
602 609 if (_meta) {
603 610 int numMethods = _meta->methodCount();
604 611 for (int i = 0; i < numMethods; i++) {
605 612 QMetaMethod m = _meta->method(i);
606 613 if ((m.methodType() == QMetaMethod::Method ||
607 614 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
608 615 PythonQtSlotInfo slot(this, m, i);
609 616 h += slot.fullSignature()+ "\n";
610 617 }
611 618 }
612 619 }
613 620
614 621 // TODO xxx : decorators and enums from decorator() are missing...
615 622 // maybe we can reuse memberlist()?
616 623
617 624 if (_meta && _meta->enumeratorCount()) {
618 625 h += "Enums:\n";
619 626 for (int i = 0; i<_meta->enumeratorCount(); i++) {
620 627 QMetaEnum e = _meta->enumerator(i);
621 628 h += QString(e.name()) + " {";
622 629 for (int j=0; j < e.keyCount(); j++) {
623 630 if (j) { h+= ", "; }
624 631 h += e.key(j);
625 632 }
626 633 h += " }\n";
627 634 }
628 635 }
629 636
630 637 if (_isQObject && _meta) {
631 638 int numMethods = _meta->methodCount();
632 639 if (numMethods>0) {
633 640 h += "Signals:\n";
634 641 for (int i = 0; i < numMethods; i++) {
635 642 QMetaMethod m = _meta->method(i);
636 643 if (m.methodType() == QMetaMethod::Signal) {
637 644 h += QString(m.signature()) + "\n";
638 645 }
639 646 }
640 647 }
641 648 }
642 649 return h;
643 650 }
644 651
645 652 PythonQtSlotInfo* PythonQtClassInfo::constructors()
646 653 {
647 654 if (!_constructors) {
648 655 // force creation of lazy decorator, which will register the decorators
649 656 decorator();
650 657 }
651 658 return _constructors;
652 659 }
653 660
654 661 PythonQtSlotInfo* PythonQtClassInfo::destructor()
655 662 {
656 663 if (!_destructor) {
657 664 // force creation of lazy decorator, which will register the decorators
658 665 decorator();
659 666 }
660 667 return _destructor;
661 668 }
662 669
663 670 void PythonQtClassInfo::addConstructor(PythonQtSlotInfo* info)
664 671 {
665 672 PythonQtSlotInfo* prev = constructors();
666 673 if (prev) {
667 674 info->setNextInfo(prev->nextInfo());
668 675 prev->setNextInfo(info);
669 676 } else {
670 677 _constructors = info;
671 678 }
672 679 }
673 680
674 681 void PythonQtClassInfo::addDecoratorSlot(PythonQtSlotInfo* info)
675 682 {
676 683 _decoratorSlots.append(info);
677 684 }
678 685
679 686 void PythonQtClassInfo::setDestructor(PythonQtSlotInfo* info)
680 687 {
681 688 if (_destructor) {
682 689 _destructor->deleteOverloadsAndThis();
683 690 }
684 691 _destructor = info;
685 692 }
686 693
687 694 void PythonQtClassInfo::setMetaObject(const QMetaObject* meta)
688 695 {
689 696 _meta = meta;
690 697 clearCachedMembers();
691 698 }
692 699
693 700 QObject* PythonQtClassInfo::decorator()
694 701 {
695 702 if (!_decoratorProvider && _decoratorProviderCB) {
696 703 _decoratorProvider = (*_decoratorProviderCB)();
697 704 if (_decoratorProvider) {
698 705 _decoratorProvider->setParent(PythonQt::priv());
699 706 // setup enums early, since they might be needed by the constructor decorators:
700 707 if (!_enumsCreated) {
701 708 createEnumWrappers();
702 709 }
703 710 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
704 711 }
705 712 }
706 713 // check if enums need to be created and create them if they are not yet created
707 714 if (!_enumsCreated) {
708 715 createEnumWrappers();
709 716 }
710 717 return _decoratorProvider;
711 718 }
712 719
713 bool PythonQtClassInfo::hasOwnerMethodButNoOwner(void* object)
714 {
715 PythonQtMemberInfo info = member("py_hasOwner");
716 if (info._type == PythonQtMemberInfo::Slot) {
717 void* obj = object;
718 bool result = false;
719 void* args[2];
720 args[0] = &result;
721 args[1] = &obj;
722 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
723 return !result;
724 } else {
725 return false;
726 }
727 }
728
729 720 void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, const char** resultClassName)
730 721 {
731 722 if (!_polymorphicHandlers.isEmpty()) {
732 723 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
733 724 void* resultPtr = (*cb)(ptr, resultClassName);
734 725 if (resultPtr) {
735 726 return resultPtr;
736 727 }
737 728 }
738 729 }
739 730 foreach(const ParentClassInfo& info, _parentClasses) {
740 731 if (!info._parent->isQObject()) {
741 732 void* resultPtr = info._parent->recursiveCastDownIfPossible((char*)ptr + info._upcastingOffset, resultClassName);
742 733 if (resultPtr) {
743 734 return resultPtr;
744 735 }
745 736 }
746 737 }
747 738 return NULL;
748 739 }
749 740
750 741 void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo)
751 742 {
752 743 const char* className;
753 744 // this would do downcasting recursively...
754 745 // void* resultPtr = recursiveCastDownIfPossible(ptr, &className);
755 746
756 747 // we only do downcasting on the base object, not on the whole inheritance tree...
757 748 void* resultPtr = NULL;
758 749 if (!_polymorphicHandlers.isEmpty()) {
759 750 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
760 751 resultPtr = (*cb)(ptr, &className);
761 752 if (resultPtr) {
762 753 break;
763 754 }
764 755 }
765 756 }
766 757 if (resultPtr) {
767 758 *resultClassInfo = PythonQt::priv()->getClassInfo(className);
768 759 } else {
769 760 *resultClassInfo = this;
770 761 resultPtr = ptr;
771 762 }
772 763 return resultPtr;
773 764 }
774 765
775 766 PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum)
776 767 {
777 768 if (isLocalEnum) {
778 769 *isLocalEnum = true;
779 770 }
780 771 int scopePos = name.lastIndexOf("::");
781 772 if (scopePos != -1) {
782 773 if (isLocalEnum) {
783 774 *isLocalEnum = false;
784 775 }
785 776 // split into scope and enum name
786 777 QByteArray enumScope = name.mid(0,scopePos);
787 778 QByteArray enumName = name.mid(scopePos+2);
788 779 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(enumScope);
789 780 if (info) {
790 781 return info->findEnumWrapper(enumName);
791 782 } else{
792 783 return NULL;
793 784 }
794 785 }
795 786 if (localScope) {
796 787 return localScope->findEnumWrapper(name);
797 788 } else {
798 789 return NULL;
799 790 }
800 791 }
801 792
802 793 void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta)
803 794 {
804 795 for (int i = meta->enumeratorOffset();i<meta->enumeratorCount();i++) {
805 796 QMetaEnum e = meta->enumerator(i);
806 797 PythonQtObjectPtr p;
807 798 p.setNewRef(PythonQtPrivate::createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper));
808 799 _enumWrappers.append(p);
809 800 }
810 801 }
811 802
812 803 void PythonQtClassInfo::createEnumWrappers()
813 804 {
814 805 if (!_enumsCreated) {
815 806 _enumsCreated = true;
816 807 if (_meta) {
817 808 createEnumWrappers(_meta);
818 809 }
819 810 if (decorator()) {
820 811 createEnumWrappers(decorator()->metaObject());
821 812 }
822 813 foreach(const ParentClassInfo& info, _parentClasses) {
823 814 info._parent->createEnumWrappers();
824 815 }
825 816 }
826 817 }
827 818
828 819 PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) {
829 820 // force enum creation
830 821 if (!_enumsCreated) {
831 822 createEnumWrappers();
832 823 }
833 824 foreach(const PythonQtObjectPtr& p, _enumWrappers) {
834 825 const char* className = ((PyTypeObject*)p.object())->tp_name;
835 826 if (qstrcmp(className, name)==0) {
836 827 return p.object();
837 828 }
838 829 }
839 830 foreach(const ParentClassInfo& info, _parentClasses) {
840 831 PyObject* p = info._parent->findEnumWrapper(name);
841 832 if (p) return p;
842 833 }
843 834 return NULL;
844 835 }
845 836
846 837 void PythonQtClassInfo::setDecoratorProvider( PythonQtQObjectCreatorFunctionCB* cb )
847 838 {
848 839 _decoratorProviderCB = cb;
849 840 _decoratorProvider = NULL;
850 841 _enumsCreated = false;
851 842 }
852 843
853 844 void PythonQtClassInfo::clearNotFoundCachedMembers()
854 845 {
855 846 // remove all not found entries, since a new decorator means new slots,
856 847 // which might have been cached as "NotFound" already.
857 848 QMutableHashIterator<QByteArray, PythonQtMemberInfo> it(_cachedMembers);
858 849 while (it.hasNext()) {
859 850 it.next();
860 851 if (it.value()._type == PythonQtMemberInfo::NotFound) {
861 852 it.remove();
862 853 }
863 854 }
864 855 }
865 856
866 857 //-------------------------------------------------------------------------
867 858
868 859 PythonQtMemberInfo::PythonQtMemberInfo( PythonQtSlotInfo* info )
869 860 {
870 861 if (info->metaMethod()->methodType() == QMetaMethod::Signal) {
871 862 _type = Signal;
872 863 } else {
873 864 _type = Slot;
874 865 }
875 866 _slot = info;
876 867 _enumValue = NULL;
877 868 }
878 869
879 870 PythonQtMemberInfo::PythonQtMemberInfo( const PythonQtObjectPtr& enumValue )
880 871 {
881 872 _type = EnumValue;
882 873 _slot = NULL;
883 874 _enumValue = enumValue;
884 875 _enumWrapper = NULL;
885 876 }
886 877
887 878 PythonQtMemberInfo::PythonQtMemberInfo( const QMetaProperty& prop )
888 879 {
889 880 _type = Property;
890 881 _slot = NULL;
891 882 _enumValue = NULL;
892 883 _property = prop;
893 884 _enumWrapper = NULL;
894 885 } No newline at end of file
@@ -1,250 +1,247
1 1 #ifndef _PYTHONQTCLASSINFO_H
2 2 #define _PYTHONQTCLASSINFO_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 #include <QMetaObject>
37 37 #include <QMetaMethod>
38 38 #include <QHash>
39 39 #include <QByteArray>
40 40 #include <QList>
41 41 #include "PythonQt.h"
42 42
43 43 class PythonQtSlotInfo;
44 44
45 45 struct PythonQtMemberInfo {
46 46 enum Type {
47 47 Invalid, Slot, Signal, EnumValue, EnumWrapper, Property, NotFound
48 48 };
49 49
50 50 PythonQtMemberInfo():_type(Invalid),_slot(NULL),_enumWrapper(NULL),_enumValue(0) { }
51 51
52 52 PythonQtMemberInfo(PythonQtSlotInfo* info);
53 53
54 54 PythonQtMemberInfo(const PythonQtObjectPtr& enumValue);
55 55
56 56 PythonQtMemberInfo(const QMetaProperty& prop);
57 57
58 58 Type _type;
59 59
60 60 // TODO: this could be a union...
61 61 PythonQtSlotInfo* _slot;
62 62 PyObject* _enumWrapper;
63 63 PythonQtObjectPtr _enumValue;
64 64 QMetaProperty _property;
65 65 };
66 66
67 67 //! a class that stores all required information about a Qt object (and an optional associated C++ class name)
68 68 /*! for fast lookup of slots when calling the object from Python
69 69 */
70 70 class PYTHONQT_EXPORT PythonQtClassInfo {
71 71
72 72 public:
73 73 PythonQtClassInfo();
74 74 ~PythonQtClassInfo();
75 75
76 76 //! store information about parent classes
77 77 struct ParentClassInfo {
78 78 ParentClassInfo(PythonQtClassInfo* parent, int upcastingOffset=0):_parent(parent),_upcastingOffset(upcastingOffset)
79 79 {};
80 80
81 81 PythonQtClassInfo* _parent;
82 82 int _upcastingOffset;
83 83 };
84 84
85 85
86 86 //! setup as a QObject, taking the meta object as meta information about the QObject
87 87 void setupQObject(const QMetaObject* meta);
88 88
89 89 //! setup as a CPP (non-QObject), taking the classname
90 90 void setupCPPObject(const QByteArray& classname);
91 91
92 92 //! set the type capabilities
93 93 void setTypeSlots(int typeSlots) { _typeSlots = typeSlots; }
94 94 //! get the type capabilities
95 95 int typeSlots() const { return _typeSlots; }
96 96
97 97 //! get the Python method definition for a given slot name (without return type and signature)
98 98 PythonQtMemberInfo member(const char* member);
99 99
100 100 //! get access to the constructor slot (which may be overloaded if there are multiple constructors)
101 101 PythonQtSlotInfo* constructors();
102 102
103 103 //! get access to the destructor slot
104 104 PythonQtSlotInfo* destructor();
105 105
106 106 //! add a constructor, ownership is passed to classinfo
107 107 void addConstructor(PythonQtSlotInfo* info);
108 108
109 109 //! set a destructor, ownership is passed to classinfo
110 110 void setDestructor(PythonQtSlotInfo* info);
111 111
112 112 //! add a decorator slot, ownership is passed to classinfo
113 113 void addDecoratorSlot(PythonQtSlotInfo* info);
114 114
115 115 //! get the classname (either of the QObject or of the wrapped CPP object)
116 116 const char* className();
117 117
118 118 //! returns if the QObject
119 119 bool isQObject() { return _isQObject; }
120 120
121 121 //! returns if the class is a CPP wrapper
122 122 bool isCPPWrapper() { return !_isQObject; }
123 123
124 124 //! get the meta object
125 125 const QMetaObject* metaObject() { return _meta; }
126 126
127 127 //! set the meta object, this will reset the caching
128 128 void setMetaObject(const QMetaObject* meta);
129 129
130 130 //! returns if this class inherits from the given classname
131 131 bool inherits(const char* classname);
132 132
133 133 //! returns if this class inherits from the given classinfo
134 134 bool inherits(PythonQtClassInfo* info);
135 135
136 136 //! casts the given \c ptr to an object of type \c classname, returns the new pointer
137 137 //! which might be different to \c ptr due to C++ multiple inheritance
138 138 //! (if the cast is not possible or if ptr is NULL, NULL is returned)
139 139 void* castTo(void* ptr, const char* classname);
140 140
141 141 //! get help string for the metaobject
142 142 QString help();
143 143
144 144 //! get list of all properties (on QObjects only, otherwise the list is empty)
145 145 QStringList propertyList();
146 146
147 147 //! get list of all members (excluding properties, which can be listed with propertyList())
148 148 QStringList memberList();
149 149
150 150 //! get the meta type id of this class (only valid for isCPPWrapper() == true)
151 151 int metaTypeId() { return _metaTypeId; }
152 152
153 153 //! set an additional decorator provider that offers additional decorator slots for this class
154 154 void setDecoratorProvider(PythonQtQObjectCreatorFunctionCB* cb);
155 155
156 156 //! get the decorator qobject instance
157 157 QObject* decorator();
158 158
159 159 //! add the parent class info of a CPP object
160 160 void addParentClass(const ParentClassInfo& info) { _parentClasses.append(info); }
161 161
162 //! check if the special method "py_hasOwner" is implemented and if it returns false, which means that the object may be destroyed
163 bool hasOwnerMethodButNoOwner(void* object);
164
165 162 //! set the associated PythonQtClassWrapper (which handles instance creation of this type)
166 163 void setPythonQtClassWrapper(PyObject* obj) { _pythonQtClassWrapper = obj; }
167 164
168 165 //! get the associated PythonQtClassWrapper (which handles instance creation of this type)
169 166 PyObject* pythonQtClassWrapper() { return _pythonQtClassWrapper; }
170 167
171 168 //! set the shell set instance wrapper cb
172 169 void setShellSetInstanceWrapperCB(PythonQtShellSetInstanceWrapperCB* cb) {
173 170 _shellSetInstanceWrapperCB = cb;
174 171 }
175 172
176 173 //! get the shell set instance wrapper cb
177 174 PythonQtShellSetInstanceWrapperCB* shellSetInstanceWrapperCB() {
178 175 return _shellSetInstanceWrapperCB;
179 176 }
180 177
181 178 //! add a handler for polymorphic downcasting
182 179 void addPolymorphicHandler(PythonQtPolymorphicHandlerCB* cb) { _polymorphicHandlers.append(cb); }
183 180
184 181 //! cast the pointer down in the class hierarchy if a polymorphic handler allows to do that
185 182 void* castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo);
186 183
187 184 //! returns if the localScope has an enum of that type name or if the enum contains a :: scope, if that class contails the enum
188 185 static PyObject* findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum = NULL);
189 186
190 187 //! clear all members that where cached as "NotFound"
191 188 void clearNotFoundCachedMembers();
192 189
193 190 private:
194 191 void createEnumWrappers();
195 192 void createEnumWrappers(const QMetaObject* meta);
196 193 PyObject* findEnumWrapper(const char* name);
197 194
198 195 //! clear all cached members
199 196 void clearCachedMembers();
200 197
201 198 void* recursiveCastDownIfPossible(void* ptr, const char** resultClassName);
202 199
203 200 PythonQtSlotInfo* findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
204 201 void listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly);
205 202 PythonQtSlotInfo* recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
206 203
207 204 void recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects);
208 205 void recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects);
209 206
210 207 bool lookForPropertyAndCache(const char* memberName);
211 208 bool lookForMethodAndCache(const char* memberName);
212 209 bool lookForEnumAndCache(const QMetaObject* m, const char* memberName);
213 210
214 211 PythonQtSlotInfo* findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
215 212 int findCharOffset(const char* sigStart, char someChar);
216 213
217 214 QHash<QByteArray, PythonQtMemberInfo> _cachedMembers;
218 215
219 216 PythonQtSlotInfo* _constructors;
220 217 PythonQtSlotInfo* _destructor;
221 218 QList<PythonQtSlotInfo*> _decoratorSlots;
222 219
223 220 QList<PythonQtObjectPtr> _enumWrappers;
224 221
225 222 const QMetaObject* _meta;
226 223
227 224 QByteArray _wrappedClassName;
228 225 QList<ParentClassInfo> _parentClasses;
229 226
230 227 QList<PythonQtPolymorphicHandlerCB*> _polymorphicHandlers;
231 228
232 229 QObject* _decoratorProvider;
233 230 PythonQtQObjectCreatorFunctionCB* _decoratorProviderCB;
234 231
235 232 PyObject* _pythonQtClassWrapper;
236 233
237 234 PythonQtShellSetInstanceWrapperCB* _shellSetInstanceWrapperCB;
238 235
239 236 int _metaTypeId;
240 237 int _typeSlots;
241 238
242 239 bool _isQObject;
243 240 bool _enumsCreated;
244 241
245 242 };
246 243
247 244 //---------------------------------------------------------------
248 245
249 246
250 247 #endif
@@ -1,1232 +1,1277
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, 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 PythonQtConversion.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 "PythonQtConversion.h"
43 43 #include "PythonQtVariants.h"
44 44 #include <QDateTime>
45 45 #include <QTime>
46 46 #include <QDate>
47 47
48 48 PythonQtValueStorage<qint64, 128> PythonQtConv::global_valueStorage;
49 49 PythonQtValueStorage<void*, 128> PythonQtConv::global_ptrStorage;
50 50 PythonQtValueStorageWithCleanup<QVariant, 128> PythonQtConv::global_variantStorage;
51 51
52 52 QHash<int, PythonQtConvertMetaTypeToPythonCB*> PythonQtConv::_metaTypeToPythonConverters;
53 53 QHash<int, PythonQtConvertPythonToMetaTypeCB*> PythonQtConv::_pythonToMetaTypeConverters;
54 54
55 55 PyObject* PythonQtConv::GetPyBool(bool val)
56 56 {
57 57 PyObject* r = val?Py_True:Py_False;
58 58 Py_INCREF(r);
59 59 return r;
60 60 }
61 61
62 62 PyObject* PythonQtConv::ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data) {
63 63 // is it an enum value?
64 64 if (info.enumWrapper) {
65 65 if (info.pointerCount==0) {
66 66 return PythonQtPrivate::createEnumValueInstance(info.enumWrapper, *((unsigned int*)data));
67 67 } else {
68 68 // we do not support pointers to enums (who needs them?)
69 69 Py_INCREF(Py_None);
70 70 return Py_None;
71 71 }
72 72 }
73 73
74 74 if (info.typeId == QMetaType::Void) {
75 75 Py_INCREF(Py_None);
76 76 return Py_None;
77 77 } else if ((info.pointerCount == 1) && (info.typeId == QMetaType::Char)) {
78 78 // a char ptr will probably be a null terminated string, so we support that:
79 79 return PyString_FromString(*((char**)data));
80 80 } else if ((info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) &&
81 81 info.name.startsWith("QList<")) {
82 82 // it is a QList template:
83 83 QByteArray innerType = info.name.mid(6,info.name.length()-7);
84 84 if (innerType.endsWith("*")) {
85 85 innerType.truncate(innerType.length()-1);
86 86 QList<void*>* listPtr = NULL;
87 87 if (info.pointerCount == 1) {
88 88 listPtr = *((QList<void*>**)data);
89 89 } else if (info.pointerCount == 0) {
90 90 listPtr = (QList<void*>*)data;
91 91 }
92 92 if (listPtr) {
93 93 return ConvertQListOfPointerTypeToPythonList(listPtr, innerType);
94 94 } else {
95 95 return NULL;
96 96 }
97 97 }
98 98 }
99 99
100 100 if (info.typeId >= QMetaType::User) {
101 101 // if a converter is registered, we use is:
102 102 PythonQtConvertMetaTypeToPythonCB* converter = _metaTypeToPythonConverters.value(info.typeId);
103 103 if (converter) {
104 104 return (*converter)(data, info.typeId);
105 105 }
106 106 }
107 107
108 108 // special handling did not match, so we convert the usual way (either pointer or value version):
109 109 if (info.pointerCount == 1) {
110 110 // convert the pointer to a Python Object (we can handle ANY C++ object, in the worst case we just know the type and the pointer)
111 111 return PythonQt::priv()->wrapPtr(*((void**)data), info.name);
112 112 } else if (info.pointerCount == 0) {
113 113 // handle values that are not yet handled and not pointers
114 114 return ConvertQtValueToPythonInternal(info.typeId, data);
115 115 } else {
116 116 return NULL;
117 117 }
118 118 }
119 119
120 120 PyObject* PythonQtConv::ConvertQtValueToPythonInternal(int type, const void* data) {
121 121 switch (type) {
122 122 case QMetaType::Void:
123 123 Py_INCREF(Py_None);
124 124 return Py_None;
125 125 case QMetaType::Char:
126 126 return PyInt_FromLong(*((char*)data));
127 127 case QMetaType::UChar:
128 128 return PyInt_FromLong(*((unsigned char*)data));
129 129 case QMetaType::Short:
130 130 return PyInt_FromLong(*((short*)data));
131 131 case QMetaType::UShort:
132 132 return PyInt_FromLong(*((unsigned short*)data));
133 133 case QMetaType::Long:
134 134 return PyInt_FromLong(*((long*)data));
135 135 case QMetaType::ULong:
136 136 // does not fit into simple int of python
137 137 return PyLong_FromUnsignedLong(*((unsigned long*)data));
138 138 case QMetaType::Bool:
139 139 return PythonQtConv::GetPyBool(*((bool*)data));
140 140 case QMetaType::Int:
141 141 return PyInt_FromLong(*((int*)data));
142 142 case QMetaType::UInt:
143 143 // does not fit into simple int of python
144 144 return PyLong_FromUnsignedLong(*((unsigned int*)data));
145 145 case QMetaType::QChar:
146 146 return PyInt_FromLong(*((short*)data));
147 147 case QMetaType::Float:
148 148 return PyFloat_FromDouble(*((float*)data));
149 149 case QMetaType::Double:
150 150 return PyFloat_FromDouble(*((double*)data));
151 151 case QMetaType::LongLong:
152 152 return PyLong_FromLongLong(*((qint64*)data));
153 153 case QMetaType::ULongLong:
154 154 return PyLong_FromUnsignedLongLong(*((quint64*)data));
155 155 // implicit conversion from QByteArray to str has been removed:
156 156 //case QMetaType::QByteArray: {
157 157 // QByteArray* v = (QByteArray*) data;
158 158 // return PyString_FromStringAndSize(*v, v->size());
159 159 // }
160 160 case QMetaType::QVariantMap:
161 161 return PythonQtConv::QVariantMapToPyObject(*((QVariantMap*)data));
162 162 case QMetaType::QVariantList:
163 163 return PythonQtConv::QVariantListToPyObject(*((QVariantList*)data));
164 164 case QMetaType::QString:
165 165 return PythonQtConv::QStringToPyObject(*((QString*)data));
166 166 case QMetaType::QStringList:
167 167 return PythonQtConv::QStringListToPyObject(*((QStringList*)data));
168 168
169 169 case PythonQtMethodInfo::Variant:
170 170 return PythonQtConv::QVariantToPyObject(*((QVariant*)data));
171 171 case QMetaType::QObjectStar:
172 172 case QMetaType::QWidgetStar:
173 173 return PythonQt::priv()->wrapQObject(*((QObject**)data));
174 174
175 175 default:
176 176 if (PythonQt::priv()->isPythonQtObjectPtrMetaId(type)) {
177 177 // special case, it is a PythonQtObjectPtr which contains a PyObject, take it directly:
178 178 PyObject* o = ((PythonQtObjectPtr*)data)->object();
179 179 Py_INCREF(o);
180 180 return o;
181 181 } else {
182 182 if (type > 0) {
183 183 // if the type is known, we can construct it via QMetaType::construct
184 184 void* newCPPObject = QMetaType::construct(type, data);
185 185 // XXX this could be optimized by using metatypeid directly
186 186 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)PythonQt::priv()->wrapPtr(newCPPObject, QMetaType::typeName(type));
187 187 wrap->_ownedByPythonQt = true;
188 188 wrap->_useQMetaTypeDestroy = true;
189 189 return (PyObject*)wrap;
190 190 }
191 191 std::cerr << "Unknown type that can not be converted to Python: " << type << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
192 192 }
193 193 }
194 194 Py_INCREF(Py_None);
195 195 return Py_None;
196 196 }
197 197
198 198 void* PythonQtConv::CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info) {
199 199 void* ptr = NULL;
200 200 if (info.pointerCount>1) {
201 201 return NULL;
202 202 } else if (info.pointerCount==1) {
203 203 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
204 204 } else if (info.enumWrapper) {
205 205 // create enum return value
206 206 PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, ptr);
207 207 } else {
208 208 switch (info.typeId) {
209 209 case QMetaType::Char:
210 210 case QMetaType::UChar:
211 211 case QMetaType::Short:
212 212 case QMetaType::UShort:
213 213 case QMetaType::Long:
214 214 case QMetaType::ULong:
215 215 case QMetaType::Bool:
216 216 case QMetaType::Int:
217 217 case QMetaType::UInt:
218 218 case QMetaType::QChar:
219 219 case QMetaType::Float:
220 220 case QMetaType::Double:
221 221 PythonQtValueStorage_ADD_VALUE(global_valueStorage, qint64, 0, ptr);
222 222 break;
223 223 case PythonQtMethodInfo::Variant:
224 224 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, 0, ptr);
225 225 // return the ptr to the variant
226 226 break;
227 227 default:
228 228 if (info.typeId == PythonQtMethodInfo::Unknown) {
229 229 // check if we have a QList of pointers, which we can circumvent with a QList<void*>
230 230 if (info.name.startsWith("QList<")) {
231 231 QByteArray innerType = info.name.mid(6,info.name.length()-7);
232 232 if (innerType.endsWith("*")) {
233 233 static int id = QMetaType::type("QList<void*>");
234 234 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr);
235 235 // return the constData pointer that will be filled with the result value later on
236 236 ptr = (void*)((QVariant*)ptr)->constData();
237 237 }
238 238 }
239 239 }
240 240
241 241 if (!ptr && info.typeId!=PythonQtMethodInfo::Unknown) {
242 242 // everything else is stored in a QVariant, if we know the meta type...
243 243 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
244 244 // return the constData pointer that will be filled with the result value later on
245 245 ptr = (void*)((QVariant*)ptr)->constData();
246 246 }
247 247 }
248 248 }
249 249 return ptr;
250 250 }
251 251
252 252 void* PythonQtConv::castWrapperTo(PythonQtInstanceWrapper* wrapper, const QByteArray& className, bool& ok)
253 253 {
254 254 void* object;
255 255 if (wrapper->classInfo()->isCPPWrapper()) {
256 256 object = wrapper->_wrappedPtr;
257 257 } else {
258 258 QObject* tmp = wrapper->_obj;
259 259 object = tmp;
260 260 }
261 261 if (object) {
262 262 // if we can be upcasted to the given name, we pass the casted pointer in:
263 263 object = wrapper->classInfo()->castTo(object, className);
264 264 ok = object!=NULL;
265 265 } else {
266 266 // if it is a NULL ptr, we need to check if it inherits, so that we might pass the NULL ptr
267 267 ok = wrapper->classInfo()->inherits(className);
268 268 }
269 269 return object;
270 270 }
271 271
272 272 void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject)
273 273 {
274 274 void* ptr = alreadyAllocatedCPPObject;
275 275
276 276 static int penId = QMetaType::type("QPen");
277 277 static int brushId = QMetaType::type("QBrush");
278 278 static int cursorId = QMetaType::type("QCursor");
279 279 static int colorId = QMetaType::type("QColor");
280 280 static PyObject* qtGlobalColorEnum = PythonQtClassInfo::findEnumWrapper("Qt::GlobalColor", NULL);
281 281 if (typeId == cursorId) {
282 282 static PyObject* qtCursorShapeEnum = PythonQtClassInfo::findEnumWrapper("Qt::CursorShape", NULL);
283 283 if ((PyObject*)obj->ob_type == qtCursorShapeEnum) {
284 284 Qt::CursorShape val = (Qt::CursorShape)PyInt_AS_LONG(obj);
285 285 if (!ptr) {
286 286 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QCursor(), ptr);
287 287 ptr = (void*)((QVariant*)ptr)->constData();
288 288 }
289 289 *((QCursor*)ptr) = QCursor(val);
290 290 return ptr;
291 291 }
292 292 } else if (typeId == penId) {
293 293 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
294 294 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
295 295 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
296 296 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
297 297 if (!ptr) {
298 298 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
299 299 ptr = (void*)((QVariant*)ptr)->constData();
300 300 }
301 301 *((QPen*)ptr) = QPen(QColor(val));
302 302 return ptr;
303 303 } else if ((PyObject*)obj->ob_type == qtColorClass) {
304 304 if (!ptr) {
305 305 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
306 306 ptr = (void*)((QVariant*)ptr)->constData();
307 307 }
308 308 *((QPen*)ptr) = QPen(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
309 309 return ptr;
310 310 }
311 311 } else if (typeId == brushId) {
312 312 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
313 313 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
314 314 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
315 315 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
316 316 if (!ptr) {
317 317 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
318 318 ptr = (void*)((QVariant*)ptr)->constData();
319 319 }
320 320 *((QBrush*)ptr) = QBrush(QColor(val));
321 321 return ptr;
322 322 } else if ((PyObject*)obj->ob_type == qtColorClass) {
323 323 if (!ptr) {
324 324 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
325 325 ptr = (void*)((QVariant*)ptr)->constData();
326 326 }
327 327 *((QBrush*)ptr) = QBrush(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
328 328 return ptr;
329 329 }
330 330 } else if (typeId == colorId) {
331 331 // colors can be created from Qt::GlobalColor (and from colors, but that's the default)
332 332 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
333 333 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
334 334 if (!ptr) {
335 335 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QColor(), ptr);
336 336 ptr = (void*)((QVariant*)ptr)->constData();
337 337 }
338 338 *((QColor*)ptr) = QColor(val);
339 339 return ptr;
340 340 }
341 341 }
342 342 return NULL;
343 343 }
344 344
345 345 void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* /*classInfo*/, void* alreadyAllocatedCPPObject)
346 346 {
347 347 bool ok = false;
348 348 void* ptr = NULL;
349 349
350 350 // autoconversion of QPen/QBrush/QCursor/QColor from different type
351 351 if (info.pointerCount==0 && !strict) {
352 352 ptr = handlePythonToQtAutoConversion(info.typeId, obj, alreadyAllocatedCPPObject);
353 353 if (ptr) {
354 354 return ptr;
355 355 }
356 356 }
357 357
358 358 if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) && info.typeId != PythonQtMethodInfo::Variant) {
359 359 // if we have a Qt wrapper object and if we do not need a QVariant, we do the following:
360 360 // (the Variant case is handled below in a switch)
361 361
362 362 // a C++ wrapper (can be passed as pointer or reference)
363 363 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)obj;
364 364 void* object = castWrapperTo(wrap, info.name, ok);
365 365 if (ok) {
366 366 if (info.pointerCount==1) {
367 367 // store the wrapped pointer in an extra pointer and let ptr point to the extra pointer
368 368 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, object, ptr);
369 369 } else if (info.pointerCount==0) {
370 370 // store the wrapped pointer directly, since we are a reference
371 371 ptr = object;
372 372 }
373 373 } else {
374 374 // not matching
375 375 }
376 376 } else if (info.pointerCount == 1) {
377 377 // a pointer
378 378 if (info.typeId == QMetaType::Char || info.typeId == QMetaType::UChar)
379 379 {
380 if (obj->ob_type == &PyString_Type) {
381 // take direct reference to string data
382 const char* data = PyString_AS_STRING(obj);
383 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (void*)data, ptr);
384 } else {
385 // convert to string
380 386 QString str = PyObjGetString(obj, strict, ok);
381 387 if (ok) {
388 QByteArray bytes;
389 bytes = str.toUtf8();
390 if (ok) {
382 391 void* ptr2 = NULL;
383 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str.toUtf8()), ptr2);
392 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(NULL,global_variantStorage, QVariant, QVariant(bytes), ptr2);
384 393 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr);
385 394 }
395 }
396 }
397 } else if (info.typeId == QMetaType::QString) {
398 // TODO: this is a special case for bad Qt APIs which take a QString*, like QtGui.QFileDialog.getSaveFileName
399 // In general we would need to decide to either support * args for all basic types (ignoring the fact that the
400 // result value is not useable in Python), or if all these APIs need to be wrapped manually/differently, like PyQt/PySide do.
401 QString str = PyObjGetString(obj, strict, ok);
402 if (ok) {
403 void* ptr2 = NULL;
404 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(NULL,global_variantStorage, QVariant, QVariant(str), ptr2);
405 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (void*)((QVariant*)ptr2)->constData(), ptr);
406 }
386 407 } else if (info.name == "PyObject") {
387 408 // handle low level PyObject directly
388 409 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, obj, ptr);
389 410 } else if (obj == Py_None) {
390 411 // None is treated as a NULL ptr
391 412 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
392 413 } else {
393 414 void* foreignWrapper = PythonQt::priv()->unwrapForeignWrapper(info.name, obj);
394 415 if (foreignWrapper) {
395 416 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, foreignWrapper, ptr);
396 417 } else {
397 418 // if we are not strict, we try if we are passed a 0 integer
398 419 if (!strict) {
399 420 bool ok;
400 421 int value = PyObjGetInt(obj, true, ok);
401 422 if (ok && value==0) {
402 423 // TODOXXX is this wise? or should it be expected from the programmer to use None?
403 424 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
404 425 }
405 426 }
406 427 }
407 428 }
408 429 } else if (info.pointerCount == 0) {
409 430 // not a pointer
410 431 switch (info.typeId) {
411 432 case QMetaType::Char:
412 433 {
413 434 int val = PyObjGetInt(obj, strict, ok);
414 435 if (ok) {
415 436 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, char, val, ptr);
416 437 }
417 438 }
418 439 break;
419 440 case QMetaType::UChar:
420 441 {
421 442 int val = PyObjGetInt(obj, strict, ok);
422 443 if (ok) {
423 444 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned char, val, ptr);
424 445 }
425 446 }
426 447 break;
427 448 case QMetaType::Short:
428 449 {
429 450 int val = PyObjGetInt(obj, strict, ok);
430 451 if (ok) {
431 452 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
432 453 }
433 454 }
434 455 break;
435 456 case QMetaType::UShort:
436 457 {
437 458 int val = PyObjGetInt(obj, strict, ok);
438 459 if (ok) {
439 460 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned short, val, ptr);
440 461 }
441 462 }
442 463 break;
443 464 case QMetaType::Long:
444 465 {
445 466 long val = (long)PyObjGetLongLong(obj, strict, ok);
446 467 if (ok) {
447 468 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, long, val, ptr);
448 469 }
449 470 }
450 471 break;
451 472 case QMetaType::ULong:
452 473 {
453 474 unsigned long val = (unsigned long)PyObjGetLongLong(obj, strict, ok);
454 475 if (ok) {
455 476 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned long, val, ptr);
456 477 }
457 478 }
458 479 break;
459 480 case QMetaType::Bool:
460 481 {
461 482 bool val = PyObjGetBool(obj, strict, ok);
462 483 if (ok) {
463 484 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, bool, val, ptr);
464 485 }
465 486 }
466 487 break;
467 488 case QMetaType::Int:
468 489 {
469 490 int val = PyObjGetInt(obj, strict, ok);
470 491 if (ok) {
471 492 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, int, val, ptr);
472 493 }
473 494 }
474 495 break;
475 496 case QMetaType::UInt:
476 497 {
477 498 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
478 499 if (ok) {
479 500 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
480 501 }
481 502 }
482 503 break;
483 504 case QMetaType::QChar:
484 505 {
485 506 int val = PyObjGetInt(obj, strict, ok);
486 507 if (ok) {
487 508 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
488 509 }
489 510 }
490 511 break;
491 512 case QMetaType::Float:
492 513 {
493 514 float val = (float)PyObjGetDouble(obj, strict, ok);
494 515 if (ok) {
495 516 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, float, val, ptr);
496 517 }
497 518 }
498 519 break;
499 520 case QMetaType::Double:
500 521 {
501 522 double val = (double)PyObjGetDouble(obj, strict, ok);
502 523 if (ok) {
503 524 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, double, val, ptr);
504 525 }
505 526 }
506 527 break;
507 528 case QMetaType::LongLong:
508 529 {
509 530 qint64 val = PyObjGetLongLong(obj, strict, ok);
510 531 if (ok) {
511 532 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, qint64, val, ptr);
512 533 }
513 534 }
514 535 break;
515 536 case QMetaType::ULongLong:
516 537 {
517 538 quint64 val = PyObjGetULongLong(obj, strict, ok);
518 539 if (ok) {
519 540 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, quint64, val, ptr);
520 541 }
521 542 }
522 543 break;
523 544 case QMetaType::QByteArray:
524 545 {
525 546 QByteArray bytes = PyObjGetBytes(obj, strict, ok);
526 547 if (ok) {
527 548 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(bytes), ptr);
528 549 ptr = (void*)((QVariant*)ptr)->constData();
529 550 }
530 551 }
531 552 break;
532 553 case QMetaType::QString:
533 554 {
534 555 QString str = PyObjGetString(obj, strict, ok);
535 556 if (ok) {
536 557 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str), ptr);
537 558 ptr = (void*)((QVariant*)ptr)->constData();
538 559 }
539 560 }
540 561 break;
541 562 case QMetaType::QStringList:
542 563 {
543 564 QStringList l = PyObjToStringList(obj, strict, ok);
544 565 if (ok) {
545 566 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(l), ptr);
546 567 ptr = (void*)((QVariant*)ptr)->constData();
547 568 }
548 569 }
549 570 break;
550 571
551 572 case PythonQtMethodInfo::Variant:
552 573 {
553 574 QVariant v = PyObjToQVariant(obj);
554 575 // the only case where conversion can fail it None and we want to pass that to, e.g. setProperty(),
555 576 // so we do not check v.isValid() here
556 577 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
557 578 }
558 579 break;
559 580 default:
560 581 {
561 582 // check for enum case
562 583 if (info.enumWrapper) {
563 584 unsigned int val;
564 585 ok = false;
565 586 if ((PyObject*)obj->ob_type == info.enumWrapper) {
566 587 // we have a exact enum type match:
567 588 val = PyInt_AS_LONG(obj);
568 589 ok = true;
569 590 } else if (!strict) {
570 591 // we try to get any integer, when not being strict. If we are strict, integers are not wanted because
571 592 // we want an integer overload to be taken first!
572 593 val = (unsigned int)PyObjGetLongLong(obj, false, ok);
573 594 }
574 595 if (ok) {
575 596 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
576 597 return ptr;
577 598 } else {
578 599 return NULL;
579 600 }
580 601 }
581 602
582 603 if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
583 604 // check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant
584 605 if (info.name.startsWith("QList<")) {
585 606 QByteArray innerType = info.name.mid(6,info.name.length()-7);
586 607 if (innerType.endsWith("*")) {
587 608 innerType.truncate(innerType.length()-1);
588 609 static int id = QMetaType::type("QList<void*>");
589 610 if (!alreadyAllocatedCPPObject) {
590 611 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(id), ptr);
591 612 ptr = (void*)((QVariant*)ptr)->constData();
592 613 } else {
593 614 ptr = alreadyAllocatedCPPObject;
594 615 }
595 616 ok = ConvertPythonListToQListOfPointerType(obj, (QList<void*>*)ptr, innerType, strict);
596 617 if (ok) {
597 618 return ptr;
598 619 } else {
599 620 return NULL;
600 621 }
601 622 }
602 623 }
603 624 }
604 625
605 626 // We only do this for registered type > QMetaType::User for performance reasons.
606 627 if (info.typeId >= QMetaType::User) {
607 628 // Maybe we have a special converter that is registered for that type:
608 629 PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(info.typeId);
609 630 if (converter) {
610 631 if (!alreadyAllocatedCPPObject) {
611 632 // create a new empty variant of concrete type:
612 633 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
613 634 ptr = (void*)((QVariant*)ptr)->constData();
614 635 } else {
615 636 ptr = alreadyAllocatedCPPObject;
616 637 }
617 638 // now call the converter, passing the internal object of the variant
618 639 ok = (*converter)(obj, ptr, info.typeId, strict);
619 640 if (ok) {
620 641 return ptr;
621 642 } else {
622 643 return NULL;
623 644 }
624 645 }
625 646 }
626 647 // if no type id is available, conversion to a QVariant makes no sense/is not possible
627 648 if (info.typeId != PythonQtMethodInfo::Unknown) {
628 649 // for all other types, we use the same qvariant conversion and pass out the constData of the variant:
629 650 QVariant v = PyObjToQVariant(obj, info.typeId);
630 651 if (v.isValid()) {
631 652 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
632 653 ptr = (void*)((QVariant*)ptr)->constData();
633 654 }
634 655 }
635 656 }
636 657 }
637 658 }
638 659 return ptr;
639 660 }
640 661
641 662
642 663 QStringList PythonQtConv::PyObjToStringList(PyObject* val, bool strict, bool& ok) {
643 664 QStringList v;
644 665 ok = false;
645 666 // if we are strict, we do not want to convert a string to a stringlist
646 667 // (strings in python are detected to be sequences)
647 668 if (strict &&
648 669 (val->ob_type == &PyString_Type ||
649 670 PyUnicode_Check(val))) {
650 671 ok = false;
651 672 return v;
652 673 }
653 674 if (PySequence_Check(val)) {
654 675 int count = PySequence_Size(val);
655 676 for (int i = 0;i<count;i++) {
656 677 PyObject* value = PySequence_GetItem(val,i);
657 678 v.append(PyObjGetString(value,false,ok));
658 679 }
659 680 ok = true;
660 681 }
661 682 return v;
662 683 }
663 684
664 685 QString PythonQtConv::PyObjGetRepresentation(PyObject* val)
665 686 {
666 687 QString r;
667 688 PyObject* str = PyObject_Repr(val);
668 689 if (str) {
669 690 r = QString(PyString_AS_STRING(str));
670 691 Py_DECREF(str);
671 692 }
672 693 return r;
673 694 }
674 695
675 696 QString PythonQtConv::PyObjGetString(PyObject* val, bool strict, bool& ok) {
676 697 QString r;
677 698 ok = true;
678 699 if (val->ob_type == &PyString_Type) {
679 700 r = QString(PyString_AS_STRING(val));
680 701 } else if (PyUnicode_Check(val)) {
681 702 PyObject *ptmp = PyUnicode_AsUTF8String(val);
682 703 if(ptmp) {
683 704 r = QString::fromUtf8(PyString_AS_STRING(ptmp));
684 705 Py_DECREF(ptmp);
685 706 }
686 707 } else if (!strict) {
687 708 // EXTRA: could also use _Unicode, but why should we?
688 709 PyObject* str = PyObject_Str(val);
689 710 if (str) {
690 711 r = QString(PyString_AS_STRING(str));
691 712 Py_DECREF(str);
692 713 } else {
693 714 ok = false;
694 715 }
695 716 } else {
696 717 ok = false;
697 718 }
698 719 return r;
699 720 }
700 721
701 722 QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) {
702 723 // TODO: support buffer objects in general
703 724 QByteArray r;
704 725 ok = true;
705 726 if (val->ob_type == &PyString_Type) {
706 727 long size = PyString_GET_SIZE(val);
707 728 r = QByteArray(PyString_AS_STRING(val), size);
708 729 } else {
709 730 ok = false;
710 731 }
711 732 return r;
712 733 }
713 734
714 735 bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) {
715 736 bool d = false;
716 737 ok = false;
717 738 if (val == Py_False) {
718 739 d = false;
719 740 ok = true;
720 741 } else if (val == Py_True) {
721 742 d = true;
722 743 ok = true;
723 744 } else if (!strict) {
724 745 d = PyObjGetInt(val, false, ok)!=0;
725 746 ok = true;
726 747 }
727 748 return d;
728 749 }
729 750
730 751 int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) {
731 752 int d = 0;
732 753 ok = true;
733 754 if (val->ob_type == &PyInt_Type) {
734 755 d = PyInt_AS_LONG(val);
735 756 } else if (!strict) {
736 757 if (PyObject_TypeCheck(val, &PyInt_Type)) {
737 758 // support for derived int classes, e.g. for our enums
738 759 d = PyInt_AS_LONG(val);
739 760 } else if (val->ob_type == &PyFloat_Type) {
740 761 d = floor(PyFloat_AS_DOUBLE(val));
741 762 } else if (val->ob_type == &PyLong_Type) {
742 763 // handle error on overflow!
743 764 d = PyLong_AsLong(val);
744 765 } else if (val == Py_False) {
745 766 d = 0;
746 767 } else if (val == Py_True) {
747 768 d = 1;
748 769 } else {
770 PyErr_Clear();
771 // PyInt_AsLong will try conversion to an int if the object is not an int:
772 d = PyInt_AsLong(val);
773 if (PyErr_Occurred()) {
749 774 ok = false;
775 PyErr_Clear();
776 }
750 777 }
751 778 } else {
752 779 ok = false;
753 780 }
754 781 return d;
755 782 }
756 783
757 784 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
758 785 qint64 d = 0;
759 786 ok = true;
760 787 if (val->ob_type == &PyInt_Type) {
761 788 d = PyInt_AS_LONG(val);
762 789 } else if (val->ob_type == &PyLong_Type) {
763 790 d = PyLong_AsLongLong(val);
764 791 } else if (!strict) {
765 792 if (PyObject_TypeCheck(val, &PyInt_Type)) {
766 793 // support for derived int classes, e.g. for our enums
767 794 d = PyInt_AS_LONG(val);
768 795 } else if (val->ob_type == &PyFloat_Type) {
769 796 d = floor(PyFloat_AS_DOUBLE(val));
770 797 } else if (val == Py_False) {
771 798 d = 0;
772 799 } else if (val == Py_True) {
773 800 d = 1;
774 801 } else {
802 PyErr_Clear();
803 // PyLong_AsLongLong will try conversion to an int if the object is not an int:
804 d = PyLong_AsLongLong(val);
805 if (PyErr_Occurred()) {
775 806 ok = false;
807 PyErr_Clear();
808 }
776 809 }
777 810 } else {
778 811 ok = false;
779 812 }
780 813 return d;
781 814 }
782 815
783 816 quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) {
784 817 quint64 d = 0;
785 818 ok = true;
786 819 if (PyObject_TypeCheck(val, &PyInt_Type)) {
787 820 d = PyInt_AS_LONG(val);
788 821 } else if (val->ob_type == &PyLong_Type) {
789 822 d = PyLong_AsLongLong(val);
790 823 } else if (!strict) {
791 824 if (PyObject_TypeCheck(val, &PyInt_Type)) {
792 825 // support for derived int classes, e.g. for our enums
793 826 d = PyInt_AS_LONG(val);
794 827 } else if (val->ob_type == &PyFloat_Type) {
795 828 d = floor(PyFloat_AS_DOUBLE(val));
796 829 } else if (val == Py_False) {
797 830 d = 0;
798 831 } else if (val == Py_True) {
799 832 d = 1;
800 833 } else {
834 PyErr_Clear();
835 // PyLong_AsLongLong will try conversion to an int if the object is not an int:
836 d = PyLong_AsLongLong(val);
837 if (PyErr_Occurred()) {
838 PyErr_Clear();
801 839 ok = false;
802 840 }
841 }
803 842 } else {
804 843 ok = false;
805 844 }
806 845 return d;
807 846 }
808 847
809 848 double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) {
810 849 double d = 0;
811 850 ok = true;
812 851 if (val->ob_type == &PyFloat_Type) {
813 852 d = PyFloat_AS_DOUBLE(val);
814 853 } else if (!strict) {
815 854 if (PyObject_TypeCheck(val, &PyInt_Type)) {
816 855 d = PyInt_AS_LONG(val);
817 856 } else if (val->ob_type == &PyLong_Type) {
818 857 d = PyLong_AsLong(val);
819 858 } else if (val == Py_False) {
820 859 d = 0;
821 860 } else if (val == Py_True) {
822 861 d = 1;
823 862 } else {
863 PyErr_Clear();
864 // PyFloat_AsDouble will try conversion to a double if the object is not a float:
865 d = PyFloat_AsDouble(val);
866 if (PyErr_Occurred()) {
867 PyErr_Clear();
824 868 ok = false;
825 869 }
870 }
826 871 } else {
827 872 ok = false;
828 873 }
829 874 return d;
830 875 }
831 876
832 877 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
833 878 {
834 879 QVariant v;
835 880 bool ok = true;
836 881
837 882 if (type==-1) {
838 883 // no special type requested
839 884 if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) {
840 885 type = QVariant::String;
841 886 } else if (PyObject_TypeCheck(val, &PyInt_Type)) {
842 887 type = QVariant::Int;
843 888 } else if (val->ob_type==&PyLong_Type) {
844 889 type = QVariant::LongLong;
845 890 } else if (val->ob_type==&PyFloat_Type) {
846 891 type = QVariant::Double;
847 892 } else if (val == Py_False || val == Py_True) {
848 893 type = QVariant::Bool;
849 894 } else if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
850 895 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
851 896 // c++ wrapper, check if the class names of the c++ objects match
852 897 if (wrap->classInfo()->isCPPWrapper()) {
853 898 if (wrap->classInfo()->metaTypeId()>0) {
854 899 // construct a new variant from the C++ object if it has a meta type (this will COPY the object!)
855 900 v = QVariant(wrap->classInfo()->metaTypeId(), wrap->_wrappedPtr);
856 901 } else {
857 902 // TODOXXX we could as well check if there is a registered meta type for "classname*", so that we may pass
858 903 // the pointer here...
859 904 // is this worth anything? we loose the knowledge of the cpp object type
860 905 v = qVariantFromValue(wrap->_wrappedPtr);
861 906 }
862 907 } else {
863 908 // this gives us a QObject pointer
864 909 QObject* myObject = wrap->_obj;
865 910 v = qVariantFromValue(myObject);
866 911 }
867 912 return v;
868 913 } else if (val->ob_type==&PyDict_Type) {
869 914 type = QVariant::Map;
870 915 } else if (val->ob_type==&PyList_Type || val->ob_type==&PyTuple_Type || PySequence_Check(val)) {
871 916 type = QVariant::List;
872 917 } else if (val == Py_None) {
873 918 // none is invalid
874 919 type = QVariant::Invalid;
875 920 } else {
876 921 // this used to be:
877 922 // type = QVariant::String;
878 923 // but now we want to transport the Python Objects directly:
879 924 PythonQtObjectPtr o(val);
880 925 v = qVariantFromValue(o);
881 926 return v;
882 927 }
883 928 }
884 929 // special type request:
885 930 switch (type) {
886 931 case QVariant::Invalid:
887 932 return v;
888 933 break;
889 934 case QVariant::Int:
890 935 {
891 936 int d = PyObjGetInt(val, false, ok);
892 937 if (ok) return QVariant(d);
893 938 }
894 939 break;
895 940 case QVariant::UInt:
896 941 {
897 942 int d = PyObjGetInt(val, false,ok);
898 943 if (ok) v = QVariant((unsigned int)d);
899 944 }
900 945 break;
901 946 case QVariant::Bool:
902 947 {
903 948 int d = PyObjGetBool(val,false,ok);
904 949 if (ok) v = QVariant((bool)(d!=0));
905 950 }
906 951 break;
907 952 case QVariant::Double:
908 953 {
909 954 double d = PyObjGetDouble(val,false,ok);
910 955 if (ok) v = QVariant(d);
911 956 break;
912 957 }
913 958 case QMetaType::Float:
914 959 {
915 960 float d = (float) PyObjGetDouble(val,false,ok);
916 961 if (ok) v = qVariantFromValue(d);
917 962 break;
918 963 }
919 964 case QMetaType::Long:
920 965 {
921 966 long d = (long) PyObjGetLongLong(val,false,ok);
922 967 if (ok) v = qVariantFromValue(d);
923 968 break;
924 969 }
925 970 case QMetaType::ULong:
926 971 {
927 972 unsigned long d = (unsigned long) PyObjGetLongLong(val,false,ok);
928 973 if (ok) v = qVariantFromValue(d);
929 974 break;
930 975 }
931 976 case QMetaType::LongLong:
932 977 {
933 978 qint64 d = PyObjGetLongLong(val, false, ok);
934 979 if (ok) v = qVariantFromValue(d);
935 980 }
936 981 break;
937 982 case QMetaType::ULongLong:
938 983 {
939 984 quint64 d = PyObjGetULongLong(val, false, ok);
940 985 if (ok) v = qVariantFromValue(d);
941 986 }
942 987 break;
943 988 case QMetaType::Short:
944 989 {
945 990 short d = (short) PyObjGetInt(val,false,ok);
946 991 if (ok) v = qVariantFromValue(d);
947 992 break;
948 993 }
949 994 case QMetaType::UShort:
950 995 {
951 996 unsigned short d = (unsigned short) PyObjGetInt(val,false,ok);
952 997 if (ok) v = qVariantFromValue(d);
953 998 break;
954 999 }
955 1000 case QMetaType::Char:
956 1001 {
957 1002 char d = (char) PyObjGetInt(val,false,ok);
958 1003 if (ok) v = qVariantFromValue(d);
959 1004 break;
960 1005 }
961 1006 case QMetaType::UChar:
962 1007 {
963 1008 unsigned char d = (unsigned char) PyObjGetInt(val,false,ok);
964 1009 if (ok) v = qVariantFromValue(d);
965 1010 break;
966 1011 }
967 1012
968 1013 case QVariant::ByteArray:
969 1014 case QVariant::String:
970 1015 {
971 1016 bool ok;
972 1017 v = QVariant(PyObjGetString(val, false, ok));
973 1018 }
974 1019 break;
975 1020
976 1021 // these are important for MeVisLab
977 1022 case QVariant::Map:
978 1023 {
979 1024 if (PyMapping_Check(val)) {
980 1025 QMap<QString,QVariant> map;
981 1026 PyObject* items = PyMapping_Items(val);
982 1027 if (items) {
983 1028 int count = PyList_Size(items);
984 1029 PyObject* value;
985 1030 PyObject* key;
986 1031 PyObject* tuple;
987 1032 for (int i = 0;i<count;i++) {
988 1033 tuple = PyList_GetItem(items,i);
989 1034 key = PyTuple_GetItem(tuple, 0);
990 1035 value = PyTuple_GetItem(tuple, 1);
991 1036 map.insert(PyObjGetString(key), PyObjToQVariant(value,-1));
992 1037 }
993 1038 Py_DECREF(items);
994 1039 v = map;
995 1040 }
996 1041 }
997 1042 }
998 1043 break;
999 1044 case QVariant::List:
1000 1045 if (PySequence_Check(val)) {
1001 1046 QVariantList list;
1002 1047 int count = PySequence_Size(val);
1003 1048 PyObject* value;
1004 1049 for (int i = 0;i<count;i++) {
1005 1050 value = PySequence_GetItem(val,i);
1006 1051 list.append(PyObjToQVariant(value, -1));
1007 1052 }
1008 1053 v = list;
1009 1054 }
1010 1055 break;
1011 1056 case QVariant::StringList:
1012 1057 {
1013 1058 bool ok;
1014 1059 QStringList l = PyObjToStringList(val, false, ok);
1015 1060 if (ok) {
1016 1061 v = l;
1017 1062 }
1018 1063 }
1019 1064 break;
1020 1065
1021 1066 default:
1022 1067 if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
1023 1068 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
1024 1069 if (wrap->classInfo()->isCPPWrapper() && wrap->classInfo()->metaTypeId() == type) {
1025 1070 // construct a new variant from the C++ object if it has the same meta type
1026 1071 v = QVariant(type, wrap->_wrappedPtr);
1027 1072 } else {
1028 1073 v = QVariant();
1029 1074 }
1030 1075 } else {
1031 1076 v = QVariant();
1032 1077 }
1033 1078 }
1034 1079 return v;
1035 1080 }
1036 1081
1037 1082 PyObject* PythonQtConv::QStringToPyObject(const QString& str)
1038 1083 {
1039 1084 if (str.isNull()) {
1040 1085 return PyString_FromString("");
1041 1086 } else {
1042 1087 return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, NULL, NULL);
1043 1088 }
1044 1089 }
1045 1090
1046 1091 PyObject* PythonQtConv::QStringListToPyObject(const QStringList& list)
1047 1092 {
1048 1093 PyObject* result = PyTuple_New(list.count());
1049 1094 int i = 0;
1050 1095 QString str;
1051 1096 foreach (str, list) {
1052 1097 PyTuple_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(str));
1053 1098 i++;
1054 1099 }
1055 1100 // why is the error state bad after this?
1056 1101 PyErr_Clear();
1057 1102 return result;
1058 1103 }
1059 1104
1060 1105 PyObject* PythonQtConv::QStringListToPyList(const QStringList& list)
1061 1106 {
1062 1107 PyObject* result = PyList_New(list.count());
1063 1108 int i = 0;
1064 1109 for (QStringList::ConstIterator it = list.begin(); it!=list.end(); ++it) {
1065 1110 PyList_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(*it));
1066 1111 i++;
1067 1112 }
1068 1113 return result;
1069 1114 }
1070 1115
1071 1116 PyObject* PythonQtConv::QVariantToPyObject(const QVariant& v)
1072 1117 {
1073 1118 return ConvertQtValueToPythonInternal(v.userType(), (void*)v.constData());
1074 1119 }
1075 1120
1076 1121 PyObject* PythonQtConv::QVariantMapToPyObject(const QVariantMap& m) {
1077 1122 PyObject* result = PyDict_New();
1078 1123 QVariantMap::const_iterator t = m.constBegin();
1079 1124 PyObject* key;
1080 1125 PyObject* val;
1081 1126 for (;t!=m.end();t++) {
1082 1127 key = QStringToPyObject(t.key());
1083 1128 val = QVariantToPyObject(t.value());
1084 1129 PyDict_SetItem(result, key, val);
1085 1130 Py_DECREF(key);
1086 1131 Py_DECREF(val);
1087 1132 }
1088 1133 return result;
1089 1134 }
1090 1135
1091 1136 PyObject* PythonQtConv::QVariantListToPyObject(const QVariantList& l) {
1092 1137 PyObject* result = PyTuple_New(l.count());
1093 1138 int i = 0;
1094 1139 QVariant v;
1095 1140 foreach (v, l) {
1096 1141 PyTuple_SET_ITEM(result, i, PythonQtConv::QVariantToPyObject(v));
1097 1142 i++;
1098 1143 }
1099 1144 // why is the error state bad after this?
1100 1145 PyErr_Clear();
1101 1146 return result;
1102 1147 }
1103 1148
1104 1149 PyObject* PythonQtConv::ConvertQListOfPointerTypeToPythonList(QList<void*>* list, const QByteArray& typeName)
1105 1150 {
1106 1151 PyObject* result = PyTuple_New(list->count());
1107 1152 int i = 0;
1108 1153 foreach (void* value, *list) {
1109 1154 PyTuple_SET_ITEM(result, i, PythonQt::priv()->wrapPtr(value, typeName));
1110 1155 i++;
1111 1156 }
1112 1157 return result;
1113 1158 }
1114 1159
1115 1160 bool PythonQtConv::ConvertPythonListToQListOfPointerType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool /*strict*/)
1116 1161 {
1117 1162 bool result = false;
1118 1163 if (PySequence_Check(obj)) {
1119 1164 result = true;
1120 1165 int count = PySequence_Size(obj);
1121 1166 PyObject* value;
1122 1167 for (int i = 0;i<count;i++) {
1123 1168 value = PySequence_GetItem(obj,i);
1124 1169 if (PyObject_TypeCheck(value, &PythonQtInstanceWrapper_Type)) {
1125 1170 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)value;
1126 1171 bool ok;
1127 1172 void* object = castWrapperTo(wrap, type, ok);
1128 1173 if (ok) {
1129 1174 list->append(object);
1130 1175 } else {
1131 1176 result = false;
1132 1177 break;
1133 1178 }
1134 1179 }
1135 1180 }
1136 1181 }
1137 1182 return result;
1138 1183 }
1139 1184
1140 1185 int PythonQtConv::getInnerTemplateMetaType(const QByteArray& typeName)
1141 1186 {
1142 1187 int idx = typeName.indexOf("<");
1143 1188 if (idx>0) {
1144 1189 int idx2 = typeName.indexOf(">");
1145 1190 if (idx2>0) {
1146 1191 QByteArray innerType = typeName.mid(idx+1,idx2-idx-1);
1147 1192 return QMetaType::type(innerType.constData());
1148 1193 }
1149 1194 }
1150 1195 return QMetaType::Void;
1151 1196 }
1152 1197
1153 1198
1154 1199 QString PythonQtConv::CPPObjectToString(int type, const void* data) {
1155 1200 QString r;
1156 1201 switch (type) {
1157 1202 case QVariant::Size: {
1158 1203 const QSize* s = static_cast<const QSize*>(data);
1159 1204 r = QString::number(s->width()) + ", " + QString::number(s->height());
1160 1205 }
1161 1206 break;
1162 1207 case QVariant::SizeF: {
1163 1208 const QSizeF* s = static_cast<const QSizeF*>(data);
1164 1209 r = QString::number(s->width()) + ", " + QString::number(s->height());
1165 1210 }
1166 1211 break;
1167 1212 case QVariant::Point: {
1168 1213 const QPoint* s = static_cast<const QPoint*>(data);
1169 1214 r = QString::number(s->x()) + ", " + QString::number(s->y());
1170 1215 }
1171 1216 break;
1172 1217 case QVariant::PointF: {
1173 1218 const QPointF* s = static_cast<const QPointF*>(data);
1174 1219 r = QString::number(s->x()) + ", " + QString::number(s->y());
1175 1220 }
1176 1221 break;
1177 1222 case QVariant::Rect: {
1178 1223 const QRect* s = static_cast<const QRect*>(data);
1179 1224 r = QString::number(s->x()) + ", " + QString::number(s->y());
1180 1225 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1181 1226 }
1182 1227 break;
1183 1228 case QVariant::RectF: {
1184 1229 const QRectF* s = static_cast<const QRectF*>(data);
1185 1230 r = QString::number(s->x()) + ", " + QString::number(s->y());
1186 1231 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1187 1232 }
1188 1233 break;
1189 1234 case QVariant::Date: {
1190 1235 const QDate* s = static_cast<const QDate*>(data);
1191 1236 r = s->toString(Qt::ISODate);
1192 1237 }
1193 1238 break;
1194 1239 case QVariant::DateTime: {
1195 1240 const QDateTime* s = static_cast<const QDateTime*>(data);
1196 1241 r = s->toString(Qt::ISODate);
1197 1242 }
1198 1243 break;
1199 1244 case QVariant::Time: {
1200 1245 const QTime* s = static_cast<const QTime*>(data);
1201 1246 r = s->toString(Qt::ISODate);
1202 1247 }
1203 1248 break;
1204 1249 case QVariant::Pixmap:
1205 1250 {
1206 1251 const QPixmap* s = static_cast<const QPixmap*>(data);
1207 1252 r = QString("Pixmap ") + QString::number(s->width()) + ", " + QString::number(s->height());
1208 1253 }
1209 1254 break;
1210 1255 case QVariant::Image:
1211 1256 {
1212 1257 const QImage* s = static_cast<const QImage*>(data);
1213 1258 r = QString("Image ") + QString::number(s->width()) + ", " + QString::number(s->height());
1214 1259 }
1215 1260 break;
1216 1261 case QVariant::Url:
1217 1262 {
1218 1263 const QUrl* s = static_cast<const QUrl*>(data);
1219 1264 r = s->toString();
1220 1265 }
1221 1266 break;
1222 1267 //TODO: add more printing for other variant types
1223 1268 default:
1224 1269 // this creates a copy, but that should not be expensive for typical simple variants
1225 1270 // (but we do not want to do this for our won user types!
1226 1271 if (type>0 && type < (int)QVariant::UserType) {
1227 1272 QVariant v(type, data);
1228 1273 r = v.toString();
1229 1274 }
1230 1275 }
1231 1276 return r;
1232 1277 }
@@ -1,774 +1,774
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, 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 PythonQtInstanceWrapper.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 "PythonQtInstanceWrapper.h"
43 43 #include <QObject>
44 44 #include "PythonQt.h"
45 45 #include "PythonQtSlot.h"
46 46 #include "PythonQtSignal.h"
47 47 #include "PythonQtClassInfo.h"
48 48 #include "PythonQtConversion.h"
49 49 #include "PythonQtClassWrapper.h"
50 50
51 51 PythonQtClassInfo* PythonQtInstanceWrapperStruct::classInfo()
52 52 {
53 53 // take the class info from our type object
54 54 return ((PythonQtClassWrapper*)ob_type)->_classInfo;
55 55 }
56 56
57 57 static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, bool force = false) {
58 58
59 59 // is this a C++ wrapper?
60 60 if (self->_wrappedPtr) {
61 61 //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
62 62
63 63 PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr);
64 64 // we own our qobject, so we delete it now:
65 65 delete self->_obj;
66 66 self->_obj = NULL;
67 if (force || self->classInfo()->hasOwnerMethodButNoOwner(self->_wrappedPtr) || self->_ownedByPythonQt) {
67 if (force || self->_ownedByPythonQt) {
68 68 int type = self->classInfo()->metaTypeId();
69 69 if (self->_useQMetaTypeDestroy && type>=0) {
70 70 // use QMetaType to destroy the object
71 71 QMetaType::destroy(type, self->_wrappedPtr);
72 72 } else {
73 73 PythonQtSlotInfo* slot = self->classInfo()->destructor();
74 74 if (slot) {
75 75 void* args[2];
76 76 args[0] = NULL;
77 77 args[1] = &self->_wrappedPtr;
78 78 slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, slot->slotIndex(), args);
79 79 self->_wrappedPtr = NULL;
80 80 } else {
81 81 if (type>=0) {
82 82 // use QMetaType to destroy the object
83 83 QMetaType::destroy(type, self->_wrappedPtr);
84 84 } else {
85 85 // TODO: warn about not being able to destroy the object?
86 86 }
87 87 }
88 88 }
89 89 }
90 90 } else {
91 91 //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
92 92 if (self->_objPointerCopy) {
93 93 PythonQt::priv()->removeWrapperPointer(self->_objPointerCopy);
94 94 }
95 95 if (self->_obj) {
96 96 if (force || self->_ownedByPythonQt) {
97 97 if (force || !self->_obj->parent()) {
98 98 delete self->_obj;
99 99 }
100 100 } else {
101 101 if (self->_obj->parent()==NULL) {
102 102 // tell someone who is interested that the qobject is no longer wrapped, if it has no parent
103 103 PythonQt::qObjectNoLongerWrappedCB(self->_obj);
104 104 }
105 105 }
106 106 }
107 107 }
108 108 self->_obj = NULL;
109 109 }
110 110
111 111 static void PythonQtInstanceWrapper_dealloc(PythonQtInstanceWrapper* self)
112 112 {
113 113 PythonQtInstanceWrapper_deleteObject(self);
114 114 self->_obj.~QPointer<QObject>();
115 115 self->ob_type->tp_free((PyObject*)self);
116 116 }
117 117
118 118 static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
119 119 {
120 120 //PythonQtClassWrapper *classType = (PythonQtClassWrapper*)type;
121 121 PythonQtInstanceWrapper *self;
122 122 static PyObject* emptyTuple = NULL;
123 123 if (emptyTuple==NULL) {
124 124 emptyTuple = PyTuple_New(0);
125 125 }
126 126
127 127 self = (PythonQtInstanceWrapper*)PyBaseObject_Type.tp_new(type, emptyTuple, NULL);
128 128
129 129 if (self != NULL) {
130 130 new (&self->_obj) QPointer<QObject>();
131 131 self->_wrappedPtr = NULL;
132 132 self->_ownedByPythonQt = false;
133 133 self->_useQMetaTypeDestroy = false;
134 134 self->_isShellInstance = false;
135 135 }
136 136 return (PyObject *)self;
137 137 }
138 138
139 139 int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds)
140 140 {
141 141 if (args == PythonQtPrivate::dummyTuple()) {
142 142 // we are called from the internal PythonQt API, so our data will be filled later on...
143 143 return 0;
144 144 }
145 145
146 146 // we are called from python, try to construct our object
147 147 if (self->classInfo()->constructors()) {
148 148 void* directCPPPointer = NULL;
149 149 PythonQtSlotFunction_CallImpl(self->classInfo(), NULL, self->classInfo()->constructors(), args, kwds, NULL, &directCPPPointer);
150 150 if (PyErr_Occurred()) {
151 151 return -1;
152 152 }
153 153 if (directCPPPointer) {
154 154 // change ownershipflag to be owned by PythonQt
155 155 self->_ownedByPythonQt = true;
156 156 self->_useQMetaTypeDestroy = false;
157 157 if (self->classInfo()->isCPPWrapper()) {
158 158 self->_wrappedPtr = directCPPPointer;
159 159 // TODO xxx: if there is a wrapper factory, we might want to generate a wrapper for our class?!
160 160 } else {
161 161 self->setQObject((QObject*)directCPPPointer);
162 162 }
163 163 // register with PythonQt
164 164 PythonQt::priv()->addWrapperPointer(directCPPPointer, self);
165 165
166 166 PythonQtShellSetInstanceWrapperCB* cb = self->classInfo()->shellSetInstanceWrapperCB();
167 167 if (cb) {
168 168 // if we are a derived python class, we set the wrapper
169 169 // to activate the shell class, otherwise we just ignore that it is a shell...
170 170 // we detect it be checking if the type does not have PythonQtInstanceWrapper_Type as direct base class,
171 171 // which is the case for all non-python derived types
172 172 if (((PyObject*)self)->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
173 173 // set the wrapper and remember that we have a shell instance!
174 174 (*cb)(directCPPPointer, self);
175 175 self->_isShellInstance = true;
176 176 }
177 177 }
178 178 }
179 179 } else {
180 180 QString error = QString("No constructors available for ") + self->classInfo()->className();
181 181 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
182 182 return -1;
183 183 }
184 184 return 0;
185 185 }
186 186
187 187 static PyObject *PythonQtInstanceWrapper_richcompare(PythonQtInstanceWrapper* wrapper, PyObject* other, int code)
188 188 {
189 189 bool validPtrs = false;
190 190 bool areSamePtrs = false;
191 191 if (PyObject_TypeCheck((PyObject*)wrapper, &PythonQtInstanceWrapper_Type)) {
192 192 if (PyObject_TypeCheck(other, &PythonQtInstanceWrapper_Type)) {
193 193 validPtrs = true;
194 194 PythonQtInstanceWrapper* w1 = wrapper;
195 195 PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)other;
196 196 // check pointers directly
197 197 if (w1->_wrappedPtr != NULL) {
198 198 if (w1->_wrappedPtr == w2->_wrappedPtr) {
199 199 areSamePtrs = true;
200 200 }
201 201 } else if (w1->_obj == w2->_obj) {
202 202 areSamePtrs = true;
203 203 }
204 204 } else if (other == Py_None) {
205 205 validPtrs = true;
206 206 if (wrapper->_obj || wrapper->_wrappedPtr) {
207 207 areSamePtrs = false;
208 208 } else {
209 209 areSamePtrs = true;
210 210 }
211 211 }
212 212 }
213 213
214 214 if ((wrapper->classInfo()->typeSlots() & PythonQt::Type_RichCompare) == 0) {
215 215 // shortcut if richcompare is not supported:
216 216 if (validPtrs && code == Py_EQ) {
217 217 return PythonQtConv::GetPyBool(areSamePtrs);
218 218 } else if (validPtrs && code == Py_NE) {
219 219 return PythonQtConv::GetPyBool(!areSamePtrs);
220 220 }
221 221 Py_INCREF(Py_NotImplemented);
222 222 return Py_NotImplemented;
223 223 }
224 224
225 225 QByteArray memberName;
226 226 switch (code) {
227 227 case Py_LT:
228 228 {
229 229 static QByteArray name = "__lt__";
230 230 memberName = name;
231 231 }
232 232 break;
233 233
234 234 case Py_LE:
235 235 {
236 236 static QByteArray name = "__le__";
237 237 memberName = name;
238 238 }
239 239 break;
240 240
241 241 case Py_EQ:
242 242 {
243 243 static QByteArray name = "__eq__";
244 244 memberName = name;
245 245 }
246 246 break;
247 247
248 248 case Py_NE:
249 249 {
250 250 static QByteArray name = "__ne__";
251 251 memberName = name;
252 252 }
253 253 break;
254 254
255 255 case Py_GT:
256 256 {
257 257 static QByteArray name = "__gt__";
258 258 memberName = name;
259 259 }
260 260 break;
261 261
262 262 case Py_GE:
263 263 {
264 264 static QByteArray name = "__ge__";
265 265 memberName = name;
266 266 }
267 267 break;
268 268 }
269 269
270 270 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
271 271 if (opSlot._type == PythonQtMemberInfo::Slot) {
272 272 // TODO get rid of tuple
273 273 PyObject* args = PyTuple_New(1);
274 274 Py_INCREF(other);
275 275 PyTuple_SET_ITEM(args, 0, other);
276 276 PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr);
277 277 Py_DECREF(args);
278 278 return result;
279 279 } else {
280 280 // not implemented, let python try something else!
281 281 Py_INCREF(Py_NotImplemented);
282 282 return Py_NotImplemented;
283 283 }
284 284 }
285 285
286 286
287 287 static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* obj)
288 288 {
289 289 return PyString_FromString(obj->ob_type->tp_name);
290 290 }
291 291
292 292 PyObject *PythonQtInstanceWrapper_inherits(PythonQtInstanceWrapper* obj, PyObject *args)
293 293 {
294 294 char *name = NULL;
295 295 if (!PyArg_ParseTuple(args, "s:PythonQtInstanceWrapper.inherits",&name)) {
296 296 return NULL;
297 297 }
298 298 return PythonQtConv::GetPyBool(obj->classInfo()->inherits(name));
299 299 }
300 300
301 301 static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* obj)
302 302 {
303 303 return PythonQt::self()->helpCalled(obj->classInfo());
304 304 }
305 305
306 306 PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self)
307 307 {
308 308 PythonQtInstanceWrapper_deleteObject(self, true);
309 309 Py_INCREF(Py_None);
310 310 return Py_None;
311 311 }
312 312
313 313
314 314 static PyMethodDef PythonQtInstanceWrapper_methods[] = {
315 315 {"className", (PyCFunction)PythonQtInstanceWrapper_classname, METH_NOARGS,
316 316 "Return the classname of the object"
317 317 },
318 318 {"inherits", (PyCFunction)PythonQtInstanceWrapper_inherits, METH_VARARGS,
319 319 "Returns if the class inherits or is of given type name"
320 320 },
321 321 {"help", (PyCFunction)PythonQtInstanceWrapper_help, METH_NOARGS,
322 322 "Shows the help of available methods for this class"
323 323 },
324 324 {"delete", (PyCFunction)PythonQtInstanceWrapper_delete, METH_NOARGS,
325 325 "Deletes the C++ object (at your own risk, my friend!)"
326 326 },
327 327 {NULL, NULL, 0, NULL} /* Sentinel */
328 328 };
329 329
330 330
331 331 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
332 332 {
333 333 const char *attributeName;
334 334 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
335 335
336 336 if ((attributeName = PyString_AsString(name)) == NULL) {
337 337 return NULL;
338 338 }
339 339
340 340 if (qstrcmp(attributeName, "__dict__")==0) {
341 341 PyObject* dict = PyBaseObject_Type.tp_getattro(obj, name);
342 342 dict = PyDict_Copy(dict);
343 343
344 344 if (wrapper->_obj) {
345 345 // only the properties are missing, the rest is already available from
346 346 // PythonQtClassWrapper...
347 347 QStringList l = wrapper->classInfo()->propertyList();
348 348 foreach (QString name, l) {
349 349 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
350 350 if (o) {
351 351 PyDict_SetItemString(dict, name.toLatin1().data(), o);
352 352 Py_DECREF(o);
353 353 } else {
354 354 std::cerr << "PythonQtInstanceWrapper: something is wrong, could not get attribute " << name.toLatin1().data();
355 355 }
356 356 }
357 357
358 358 QList<QByteArray> dynamicProps = wrapper->_obj->dynamicPropertyNames();
359 359 foreach (QByteArray name, dynamicProps) {
360 360 PyObject* o = PyObject_GetAttrString(obj, name.data());
361 361 if (o) {
362 362 PyDict_SetItemString(dict, name.data(), o);
363 363 Py_DECREF(o);
364 364 } else {
365 365 std::cerr << "PythonQtInstanceWrapper: dynamic property could not be read " << name.data();
366 366 }
367 367 }
368 368 }
369 369 // Note: we do not put children into the dict, is would look confusing?!
370 370 return dict;
371 371 }
372 372
373 373 // first look in super, to return derived methods from base object first
374 374 PyObject* superAttr = PyBaseObject_Type.tp_getattro(obj, name);
375 375 if (superAttr) {
376 376 return superAttr;
377 377 }
378 378 PyErr_Clear();
379 379
380 380 // mlabDebugConst("Python","get " << attributeName);
381 381
382 382 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
383 383 switch (member._type) {
384 384 case PythonQtMemberInfo::Property:
385 385 if (wrapper->_obj) {
386 386 if (member._property.userType() != QVariant::Invalid) {
387 387
388 388 PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB();
389 389 if (profilingCB) {
390 390 QString methodName = "getProperty(";
391 391 methodName += attributeName;
392 392 methodName += ")";
393 393 profilingCB(PythonQt::Enter, wrapper->_obj->metaObject()->className(), methodName.toLatin1());
394 394 }
395 395
396 396 PyObject* value = PythonQtConv::QVariantToPyObject(member._property.read(wrapper->_obj));
397 397
398 398 if (profilingCB) {
399 399 profilingCB(PythonQt::Leave, NULL, NULL);
400 400 }
401 401
402 402 return value;
403 403
404 404 } else {
405 405 Py_INCREF(Py_None);
406 406 return Py_None;
407 407 }
408 408 } else {
409 409 QString error = QString("Trying to read property '") + attributeName + "' from a destroyed " + wrapper->classInfo()->className() + " object";
410 410 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
411 411 return NULL;
412 412 }
413 413 break;
414 414 case PythonQtMemberInfo::Slot:
415 415 return PythonQtSlotFunction_New(member._slot, obj, NULL);
416 416 break;
417 417 case PythonQtMemberInfo::Signal:
418 418 return PythonQtSignalFunction_New(member._slot, obj, NULL);
419 419 break;
420 420 case PythonQtMemberInfo::EnumValue:
421 421 {
422 422 PyObject* enumValue = member._enumValue;
423 423 Py_INCREF(enumValue);
424 424 return enumValue;
425 425 }
426 426 break;
427 427 case PythonQtMemberInfo::EnumWrapper:
428 428 {
429 429 PyObject* enumWrapper = member._enumWrapper;
430 430 Py_INCREF(enumWrapper);
431 431 return enumWrapper;
432 432 }
433 433 break;
434 434 case PythonQtMemberInfo::NotFound:
435 435 {
436 436 static const QByteArray getterString("py_get_");
437 437 // check for a getter slot
438 438 PythonQtMemberInfo member = wrapper->classInfo()->member(getterString + attributeName);
439 439 if (member._type == PythonQtMemberInfo::Slot) {
440 440 return PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, member._slot, NULL, NULL, wrapper->_wrappedPtr);
441 441 }
442 442
443 443 // handle dynamic properties
444 444 if (wrapper->_obj) {
445 445 QVariant v = wrapper->_obj->property(attributeName);
446 446 if (v.isValid()) {
447 447 return PythonQtConv::QVariantToPyObject(v);
448 448 }
449 449 }
450 450 }
451 451 break;
452 452 default:
453 453 // is an invalid type, go on
454 454 break;
455 455 }
456 456
457 457 // look for the internal methods (className(), help())
458 458 PyObject* internalMethod = Py_FindMethod( PythonQtInstanceWrapper_methods, obj, (char*)attributeName);
459 459 if (internalMethod) {
460 460 return internalMethod;
461 461 }
462 462 PyErr_Clear();
463 463
464 464 if (wrapper->_obj) {
465 465 // look for a child
466 466 QObjectList children = wrapper->_obj->children();
467 467 for (int i = 0; i < children.count(); i++) {
468 468 QObject *child = children.at(i);
469 469 if (child->objectName() == attributeName) {
470 470 return PythonQt::priv()->wrapQObject(child);
471 471 }
472 472 }
473 473 }
474 474
475 475 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
476 476 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
477 477 return NULL;
478 478 }
479 479
480 480 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
481 481 {
482 482 QString error;
483 483 const char *attributeName;
484 484 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
485 485
486 486 if ((attributeName = PyString_AsString(name)) == NULL)
487 487 return -1;
488 488
489 489 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
490 490 if (member._type == PythonQtMemberInfo::Property) {
491 491
492 492 if (!wrapper->_obj) {
493 493 error = QString("Trying to set property '") + attributeName + "' on a destroyed " + wrapper->classInfo()->className() + " object";
494 494 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
495 495 return -1;
496 496 }
497 497
498 498 QMetaProperty prop = member._property;
499 499 if (prop.isWritable()) {
500 500 QVariant v;
501 501 if (prop.isEnumType()) {
502 502 // this will give us either a string or an int, everything else will probably be an error
503 503 v = PythonQtConv::PyObjToQVariant(value);
504 504 } else {
505 505 int t = prop.userType();
506 506 v = PythonQtConv::PyObjToQVariant(value, t);
507 507 }
508 508 bool success = false;
509 509 if (v.isValid()) {
510 510 PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB();
511 511 if (profilingCB) {
512 512 QString methodName = "setProperty(";
513 513 methodName += attributeName;
514 514 methodName += ")";
515 515 profilingCB(PythonQt::Enter, wrapper->_obj->metaObject()->className(), methodName.toLatin1());
516 516 }
517 517
518 518 success = prop.write(wrapper->_obj, v);
519 519
520 520 if (profilingCB) {
521 521 profilingCB(PythonQt::Leave, NULL, NULL);
522 522 }
523 523 }
524 524 if (success) {
525 525 return 0;
526 526 } else {
527 527 error = QString("Property '") + attributeName + "' of type '" +
528 528 prop.typeName() + "' does not accept an object of type "
529 529 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
530 530 }
531 531 } else {
532 532 error = QString("Property '") + attributeName + "' of " + obj->ob_type->tp_name + " object is not writable";
533 533 }
534 534 } else if (member._type == PythonQtMemberInfo::Slot) {
535 535 error = QString("Slot '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
536 536 } else if (member._type == PythonQtMemberInfo::Signal) {
537 537 error = QString("Signal '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
538 538 } else if (member._type == PythonQtMemberInfo::EnumValue) {
539 539 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
540 540 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
541 541 error = QString("Enum '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
542 542 } else if (member._type == PythonQtMemberInfo::NotFound) {
543 543 // check for a setter slot
544 544 static const QByteArray setterString("py_set_");
545 545 PythonQtMemberInfo setter = wrapper->classInfo()->member(setterString + attributeName);
546 546 if (setter._type == PythonQtMemberInfo::Slot) {
547 547 // call the setter and ignore the result value
548 548 void* result;
549 549 PyObject* args = PyTuple_New(1);
550 550 Py_INCREF(value);
551 551 PyTuple_SET_ITEM(args, 0, value);
552 552 PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, setter._slot, args, NULL, wrapper->_wrappedPtr, &result);
553 553 Py_DECREF(args);
554 554 return 0;
555 555 }
556 556
557 557 // handle dynamic properties
558 558 if (wrapper->_obj) {
559 559 QVariant prop = wrapper->_obj->property(attributeName);
560 560 if (prop.isValid()) {
561 561 QVariant v = PythonQtConv::PyObjToQVariant(value);
562 562 if (v.isValid()) {
563 563 wrapper->_obj->setProperty(attributeName, v);
564 564 return 0;
565 565 } else {
566 566 error = QString("Dynamic property '") + attributeName + "' does not accept an object of type "
567 567 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
568 568 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
569 569 return -1;
570 570 }
571 571 }
572 572 }
573 573
574 574 // if we are a derived python class, we allow setting attributes.
575 575 // if we are a direct CPP wrapper, we do NOT allow it, since
576 576 // it would be confusing to allow it because a wrapper will go away when it is not seen by python anymore
577 577 // and when it is recreated from a CPP pointer the attributes are gone...
578 578 if (obj->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
579 579 return PyBaseObject_Type.tp_setattro(obj,name,value);
580 580 } else {
581 581 error = QString("'") + attributeName + "' does not exist on " + obj->ob_type->tp_name + " and creating new attributes on C++ objects is not allowed";
582 582 }
583 583 }
584 584
585 585 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
586 586 return -1;
587 587 }
588 588
589 589 static QString getStringFromObject(PythonQtInstanceWrapper* wrapper) {
590 590 QString result;
591 591 if (wrapper->_wrappedPtr) {
592 592 // first try some manually string conversions for some variants
593 593 int metaid = wrapper->classInfo()->metaTypeId();
594 594 result = PythonQtConv::CPPObjectToString(metaid, wrapper->_wrappedPtr);
595 595 if (!result.isEmpty()) {
596 596 return result;
597 597 }
598 598 }
599 599 if (wrapper->_wrappedPtr || wrapper->_obj) {
600 600 // next, try to call py_toString
601 601 PythonQtMemberInfo info = wrapper->classInfo()->member("py_toString");
602 602 if (info._type == PythonQtMemberInfo::Slot) {
603 603 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, NULL, NULL, wrapper->_wrappedPtr);
604 604 if (resultObj) {
605 605 // TODO this is one conversion too much, would be nicer to call the slot directly...
606 606 result = PythonQtConv::PyObjGetString(resultObj);
607 607 Py_DECREF(resultObj);
608 608 }
609 609 }
610 610 }
611 611 return result;
612 612 }
613 613
614 614 static PyObject * PythonQtInstanceWrapper_str(PyObject * obj)
615 615 {
616 616 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
617 617
618 618 // QByteArray should be directly returned as a str
619 619 if (wrapper->classInfo()->metaTypeId()==QVariant::ByteArray) {
620 620 QByteArray* b = (QByteArray*) wrapper->_wrappedPtr;
621 621 if (b->data()) {
622 622 return PyString_FromStringAndSize(b->data(), b->size());
623 623 } else {
624 624 return PyString_FromString("");
625 625 }
626 626 }
627 627
628 628 const char* typeName = obj->ob_type->tp_name;
629 629 QObject *qobj = wrapper->_obj;
630 630 QString str = getStringFromObject(wrapper);
631 631 if (!str.isEmpty()) {
632 632 return PyString_FromFormat("%s", str.toLatin1().constData());
633 633 }
634 634 if (wrapper->_wrappedPtr) {
635 635 if (wrapper->_obj) {
636 636 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
637 637 } else {
638 638 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
639 639 }
640 640 } else {
641 641 return PyString_FromFormat("%s (QObject %p)", typeName, qobj);
642 642 }
643 643 }
644 644
645 645 static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj)
646 646 {
647 647 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
648 648 const char* typeName = obj->ob_type->tp_name;
649 649
650 650 QObject *qobj = wrapper->_obj;
651 651 QString str = getStringFromObject(wrapper);
652 652 if (!str.isEmpty()) {
653 653 if (str.startsWith(typeName)) {
654 654 return PyString_FromFormat("%s", str.toLatin1().constData());
655 655 } else {
656 656 return PyString_FromFormat("%s (%s, at: %p)", typeName, str.toLatin1().constData(), wrapper->_wrappedPtr ? wrapper->_wrappedPtr : qobj);
657 657 }
658 658 }
659 659 if (wrapper->_wrappedPtr) {
660 660 if (wrapper->_obj) {
661 661 return PyString_FromFormat("%s (C++ object at: %p wrapped by %s at: %p)", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
662 662 } else {
663 663 return PyString_FromFormat("%s (C++ object at: %p)", typeName, wrapper->_wrappedPtr);
664 664 }
665 665 } else {
666 666 return PyString_FromFormat("%s (%s at: %p)", typeName, wrapper->classInfo()->className(), qobj);
667 667 }
668 668 }
669 669
670 670 static int PythonQtInstanceWrapper_builtin_nonzero(PyObject *obj)
671 671 {
672 672 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
673 673 return (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
674 674 }
675 675
676 676
677 677 static long PythonQtInstanceWrapper_hash(PythonQtInstanceWrapper *obj)
678 678 {
679 679 if (obj->_wrappedPtr != NULL) {
680 680 return reinterpret_cast<long>(obj->_wrappedPtr);
681 681 } else {
682 682 QObject* qobj = obj->_obj; // get pointer from QPointer wrapper
683 683 return reinterpret_cast<long>(qobj);
684 684 }
685 685 }
686 686
687 687
688 688
689 689 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
690 690 static PyNumberMethods PythonQtInstanceWrapper_as_number = {
691 691 0, /* nb_add */
692 692 0, /* nb_subtract */
693 693 0, /* nb_multiply */
694 694 0, /* nb_divide */
695 695 0, /* nb_remainder */
696 696 0, /* nb_divmod */
697 697 0, /* nb_power */
698 698 0, /* nb_negative */
699 699 0, /* nb_positive */
700 700 0, /* nb_absolute */
701 701 PythonQtInstanceWrapper_builtin_nonzero, /* nb_nonzero */
702 702 0, /* nb_invert */
703 703 0, /* nb_lshift */
704 704 0, /* nb_rshift */
705 705 0, /* nb_and */
706 706 0, /* nb_xor */
707 707 0, /* nb_or */
708 708 0, /* nb_coerce */
709 709 0, /* nb_int */
710 710 0, /* nb_long */
711 711 0, /* nb_float */
712 712 0, /* nb_oct */
713 713 0, /* nb_hex */
714 714 0, /* nb_inplace_add */
715 715 0, /* nb_inplace_subtract */
716 716 0, /* nb_inplace_multiply */
717 717 0, /* nb_inplace_divide */
718 718 0, /* nb_inplace_remainder */
719 719 0, /* nb_inplace_power */
720 720 0, /* nb_inplace_lshift */
721 721 0, /* nb_inplace_rshift */
722 722 0, /* nb_inplace_and */
723 723 0, /* nb_inplace_xor */
724 724 0, /* nb_inplace_or */
725 725 0, /* nb_floor_divide */
726 726 0, /* nb_true_divide */
727 727 0, /* nb_inplace_floor_divide */
728 728 0, /* nb_inplace_true_divide */
729 729 };
730 730
731 731 PyTypeObject PythonQtInstanceWrapper_Type = {
732 732 PyObject_HEAD_INIT(&PythonQtClassWrapper_Type)
733 733 0, /*ob_size*/
734 734 "PythonQt.PythonQtInstanceWrapper", /*tp_name*/
735 735 sizeof(PythonQtInstanceWrapper), /*tp_basicsize*/
736 736 0, /*tp_itemsize*/
737 737 (destructor)PythonQtInstanceWrapper_dealloc, /*tp_dealloc*/
738 738 0, /*tp_print*/
739 739 0, /*tp_getattr*/
740 740 0, /*tp_setattr*/
741 741 0, /*tp_compare*/
742 742 PythonQtInstanceWrapper_repr, /*tp_repr*/
743 743 &PythonQtInstanceWrapper_as_number, /*tp_as_number*/
744 744 0, /*tp_as_sequence*/
745 745 0, /*tp_as_mapping*/
746 746 (hashfunc)PythonQtInstanceWrapper_hash, /*tp_hash */
747 747 0, /*tp_call*/
748 748 PythonQtInstanceWrapper_str, /*tp_str*/
749 749 PythonQtInstanceWrapper_getattro, /*tp_getattro*/
750 750 PythonQtInstanceWrapper_setattro, /*tp_setattro*/
751 751 0, /*tp_as_buffer*/
752 752 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
753 753 "PythonQtInstanceWrapper object", /* tp_doc */
754 754 0, /* tp_traverse */
755 755 0, /* tp_clear */
756 756 (richcmpfunc)PythonQtInstanceWrapper_richcompare, /* tp_richcompare */
757 757 0, /* tp_weaklistoffset */
758 758 0, /* tp_iter */
759 759 0, /* tp_iternext */
760 760 0, /* tp_methods */
761 761 0, /* tp_members */
762 762 0, /* tp_getset */
763 763 0, /* tp_base */
764 764 0, /* tp_dict */
765 765 0, /* tp_descr_get */
766 766 0, /* tp_descr_set */
767 767 0, /* tp_dictoffset */
768 768 (initproc)PythonQtInstanceWrapper_init, /* tp_init */
769 769 0, /* tp_alloc */
770 770 PythonQtInstanceWrapper_new, /* tp_new */
771 771 };
772 772
773 773 //-------------------------------------------------------
774 774
@@ -1,352 +1,377
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, 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 PythonQtMethodInfo.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 "PythonQtMethodInfo.h"
43 43 #include "PythonQtClassInfo.h"
44 44 #include <iostream>
45 45
46 46 QHash<QByteArray, PythonQtMethodInfo*> PythonQtMethodInfo::_cachedSignatures;
47 47 QHash<QByteArray, QByteArray> PythonQtMethodInfo::_parameterNameAliases;
48 48
49 49 PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo)
50 50 {
51 51 #ifdef PYTHONQT_DEBUG
52 52 QByteArray sig(meta.signature());
53 53 sig = sig.mid(sig.indexOf('('));
54 54 QByteArray fullSig = QByteArray(meta.typeName()) + " " + sig;
55 55 std::cout << "caching " << fullSig.data() << std::endl;
56 56 #endif
57 57
58 58 ParameterInfo type;
59 59 fillParameterInfo(type, QByteArray(meta.typeName()), classInfo);
60 60 _parameters.append(type);
61 61 QList<QByteArray> names = meta.parameterTypes();
62 62 foreach (const QByteArray& name, names) {
63 63 fillParameterInfo(type, name, classInfo);
64 64 _parameters.append(type);
65 65 }
66 66 }
67 67
68 68 PythonQtMethodInfo::PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args)
69 69 {
70 70 ParameterInfo type;
71 71 fillParameterInfo(type, typeName, NULL);
72 72 _parameters.append(type);
73 73 foreach (const QByteArray& name, args) {
74 74 fillParameterInfo(type, name, NULL);
75 75 _parameters.append(type);
76 76 }
77 77 }
78 78
79 79 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo)
80 80 {
81 81 QByteArray sig(signal.signature());
82 82 sig = sig.mid(sig.indexOf('('));
83 83 QByteArray fullSig = QByteArray(signal.typeName()) + " " + sig;
84 84 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
85 85 if (!result) {
86 86 result = new PythonQtMethodInfo(signal, classInfo);
87 87 _cachedSignatures.insert(fullSig, result);
88 88 }
89 89 return result;
90 90 }
91 91
92 92 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(int numArgs, const char** args)
93 93 {
94 94 QByteArray typeName = args[0];
95 95 QList<QByteArray> arguments;
96 96 QByteArray fullSig = typeName;
97 97 fullSig += "(";
98 98 for (int i =1;i<numArgs; i++) {
99 99 if (i>1) {
100 100 fullSig += ",";
101 101 }
102 102 QByteArray arg(args[i]);
103 103 fullSig += arg;
104 104 arguments << arg;
105 105 }
106 106 fullSig += ")";
107 107 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
108 108 if (!result) {
109 109 result = new PythonQtMethodInfo(typeName, arguments);
110 110 _cachedSignatures.insert(fullSig, result);
111 111 }
112 112 return result;
113 113 }
114 114
115 115 void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo)
116 116 {
117 117 QByteArray name = orgName;
118 118
119 119 type.enumWrapper = NULL;
120 120
121 121 int len = name.length();
122 122 if (len>0) {
123 123 if (strncmp(name.constData(), "const ", 6)==0) {
124 124 name = name.mid(6);
125 125 len -= 6;
126 126 type.isConst = true;
127 127 } else {
128 128 type.isConst = false;
129 129 }
130 130 char pointerCount = 0;
131 131 bool hadReference = false;
132 132 // remove * and & from the end of the string, handle & and * the same way
133 133 while (name.at(len-1) == '*') {
134 134 len--;
135 135 pointerCount++;
136 136 }
137 137 while (name.at(len-1) == '&') {
138 138 len--;
139 139 hadReference = true;
140 140 }
141 141 if (len!=name.length()) {
142 142 name = name.left(len);
143 143 }
144 144 type.pointerCount = pointerCount;
145 145
146 146 QByteArray alias = _parameterNameAliases.value(name);
147 147 if (!alias.isEmpty()) {
148 148 name = alias;
149 149 }
150 150
151 151 type.typeId = nameToType(name);
152 152 if ((type.pointerCount == 0) && type.typeId == Unknown) {
153 153 type.typeId = QMetaType::type(name.constData());
154 154 if (type.typeId == QMetaType::Void) {
155 155 type.typeId = Unknown;
156 156 }
157 157 }
158 158 type.name = name;
159 159
160 160 if (type.typeId == PythonQtMethodInfo::Unknown || type.typeId >= QMetaType::User) {
161 161 bool isLocalEnum;
162 162 // TODOXXX: make use of this flag!
163 163 type.enumWrapper = PythonQtClassInfo::findEnumWrapper(type.name, classInfo, &isLocalEnum);
164 164 }
165 165 } else {
166 166 type.typeId = QMetaType::Void;
167 167 type.pointerCount = 0;
168 168 type.isConst = false;
169 169 }
170 170 }
171 171
172 172 int PythonQtMethodInfo::nameToType(const char* name)
173 173 {
174 174 if (_parameterTypeDict.isEmpty()) {
175 175 // we could also use QMetaType::nameToType, but that does a string compare search
176 176 // and does not support QVariant
177 177
178 178 // QMetaType names
179 179 _parameterTypeDict.insert("long", QMetaType::Long);
180 180 _parameterTypeDict.insert("int", QMetaType::Int);
181 181 _parameterTypeDict.insert("short", QMetaType::Short);
182 182 _parameterTypeDict.insert("char", QMetaType::Char);
183 183 _parameterTypeDict.insert("ulong", QMetaType::ULong);
184 184 _parameterTypeDict.insert("unsigned long", QMetaType::ULong);
185 185 _parameterTypeDict.insert("uint", QMetaType::UInt);
186 186 _parameterTypeDict.insert("unsigned int", QMetaType::UInt);
187 187 _parameterTypeDict.insert("ushort", QMetaType::UShort);
188 188 _parameterTypeDict.insert("unsigned short", QMetaType::UShort);
189 189 _parameterTypeDict.insert("uchar", QMetaType::UChar);
190 190 _parameterTypeDict.insert("unsigned char", QMetaType::UChar);
191 191 _parameterTypeDict.insert("bool", QMetaType::Bool);
192 192 _parameterTypeDict.insert("float", QMetaType::Float);
193 193 _parameterTypeDict.insert("double", QMetaType::Double);
194 194 _parameterTypeDict.insert("qreal", QMetaType::Double);
195 195 _parameterTypeDict.insert("QChar", QMetaType::QChar);
196 196 _parameterTypeDict.insert("QByteArray", QMetaType::QByteArray);
197 197 _parameterTypeDict.insert("QString", QMetaType::QString);
198 198 _parameterTypeDict.insert("", QMetaType::Void);
199 199 _parameterTypeDict.insert("void", QMetaType::Void);
200
201 // GL types
202 _parameterTypeDict.insert("GLenum", QMetaType::UInt);
203 _parameterTypeDict.insert("GLboolean", QMetaType::UChar);
204 _parameterTypeDict.insert("GLbitfield", QMetaType::UInt);
205 _parameterTypeDict.insert("GLbyte", QMetaType::Char);
206 _parameterTypeDict.insert("GLubyte", QMetaType::UChar);
207 _parameterTypeDict.insert("GLshort", QMetaType::Short);
208 _parameterTypeDict.insert("GLushort", QMetaType::UShort);
209 _parameterTypeDict.insert("GLint", QMetaType::Int);
210 _parameterTypeDict.insert("GLuint", QMetaType::UInt);
211 _parameterTypeDict.insert("GLsizei", QMetaType::UInt);
212 _parameterTypeDict.insert("GLclampf", QMetaType::Float);
213 _parameterTypeDict.insert("GLfloat", QMetaType::Float);
214 _parameterTypeDict.insert("GLclampd", QMetaType::Double);
215 _parameterTypeDict.insert("GLdouble", QMetaType::Double);
216 _parameterTypeDict.insert("GLvoid", QMetaType::Void);
217 if (QT_POINTER_SIZE == 8) {
218 _parameterTypeDict.insert("qgl_GLintptr", QMetaType::LongLong);
219 _parameterTypeDict.insert("qgl_GLsizeiptr", QMetaType::LongLong);
220 } else {
221 _parameterTypeDict.insert("qgl_GLintptr", QMetaType::Int);
222 _parameterTypeDict.insert("qgl_GLsizeiptr", QMetaType::Int);
223 }
224
200 225 // QVariant names
201 226 _parameterTypeDict.insert("Q_LLONG", QMetaType::LongLong);
202 227 _parameterTypeDict.insert("Q_ULLONG", QMetaType::ULongLong);
203 228 _parameterTypeDict.insert("qlonglong", QMetaType::LongLong);
204 229 _parameterTypeDict.insert("qulonglong", QMetaType::ULongLong);
205 230 _parameterTypeDict.insert("qint64", QMetaType::LongLong);
206 231 _parameterTypeDict.insert("quint64", QMetaType::ULongLong);
207 232 _parameterTypeDict.insert("QVariantMap", QMetaType::QVariantMap);
208 233 _parameterTypeDict.insert("QVariantList", QMetaType::QVariantList);
209 234 _parameterTypeDict.insert("QMap<QString,QVariant>", QMetaType::QVariantMap);
210 235 _parameterTypeDict.insert("QList<QVariant>", QMetaType::QVariantList);
211 236 _parameterTypeDict.insert("QStringList", QMetaType::QStringList);
212 237 _parameterTypeDict.insert("QBitArray", QMetaType::QBitArray);
213 238 _parameterTypeDict.insert("QDate", QMetaType::QDate);
214 239 _parameterTypeDict.insert("QTime", QMetaType::QTime);
215 240 _parameterTypeDict.insert("QDateTime", QMetaType::QDateTime);
216 241 _parameterTypeDict.insert("QUrl", QMetaType::QUrl);
217 242 _parameterTypeDict.insert("QLocale", QMetaType::QLocale);
218 243 _parameterTypeDict.insert("QRect", QMetaType::QRect);
219 244 _parameterTypeDict.insert("QRectF", QMetaType::QRectF);
220 245 _parameterTypeDict.insert("QSize", QMetaType::QSize);
221 246 _parameterTypeDict.insert("QSizeF", QMetaType::QSizeF);
222 247 _parameterTypeDict.insert("QLine", QMetaType::QLine);
223 248 _parameterTypeDict.insert("QLineF", QMetaType::QLineF);
224 249 _parameterTypeDict.insert("QPoint", QMetaType::QPoint);
225 250 _parameterTypeDict.insert("QPointF", QMetaType::QPointF);
226 251 _parameterTypeDict.insert("QRegExp", QMetaType::QRegExp);
227 252 _parameterTypeDict.insert("QFont", QMetaType::QFont);
228 253 _parameterTypeDict.insert("QPixmap", QMetaType::QPixmap);
229 254 _parameterTypeDict.insert("QBrush", QMetaType::QBrush);
230 255 _parameterTypeDict.insert("QColor", QMetaType::QColor);
231 256 _parameterTypeDict.insert("QCursor", QMetaType::QCursor);
232 257 _parameterTypeDict.insert("QPalette", QMetaType::QPalette);
233 258 _parameterTypeDict.insert("QIcon", QMetaType::QIcon);
234 259 _parameterTypeDict.insert("QImage", QMetaType::QImage);
235 260 _parameterTypeDict.insert("QRegion", QMetaType::QRegion);
236 261 _parameterTypeDict.insert("QBitmap", QMetaType::QBitmap);
237 262 _parameterTypeDict.insert("QSizePolicy", QMetaType::QSizePolicy);
238 263 _parameterTypeDict.insert("QKeySequence", QMetaType::QKeySequence);
239 264 _parameterTypeDict.insert("QPen", QMetaType::QPen);
240 265 _parameterTypeDict.insert("QTextLength", QMetaType::QTextLength);
241 266 _parameterTypeDict.insert("QTextFormat", QMetaType::QTextFormat);
242 267 _parameterTypeDict.insert("QMatrix", QMetaType::QMatrix);
243 268 _parameterTypeDict.insert("QVariant", PythonQtMethodInfo::Variant);
244 269 // own special types... (none so far, could be e.g. ObjectList
245 270 }
246 271 QHash<QByteArray, int>::const_iterator it = _parameterTypeDict.find(name);
247 272 if (it!=_parameterTypeDict.end()) {
248 273 return it.value();
249 274 } else {
250 275 return PythonQtMethodInfo::Unknown;
251 276 }
252 277 }
253 278
254 279 void PythonQtMethodInfo::cleanupCachedMethodInfos()
255 280 {
256 281 QHashIterator<QByteArray, PythonQtMethodInfo *> i(_cachedSignatures);
257 282 while (i.hasNext()) {
258 283 delete i.next().value();
259 284 }
260 285 }
261 286
262 287 void PythonQtMethodInfo::addParameterTypeAlias(const QByteArray& alias, const QByteArray& name)
263 288 {
264 289 _parameterNameAliases.insert(alias, name);
265 290 }
266 291
267 292 //-------------------------------------------------------------------------------------------------
268 293
269 294 void PythonQtSlotInfo::deleteOverloadsAndThis()
270 295 {
271 296 PythonQtSlotInfo* cur = this;
272 297 while(cur->nextInfo()) {
273 298 PythonQtSlotInfo* next = cur->nextInfo();
274 299 delete cur;
275 300 cur = next;
276 301 }
277 302 }
278 303
279 304
280 305 QString PythonQtSlotInfo::fullSignature()
281 306 {
282 307 bool skipFirstArg = isInstanceDecorator();
283 308 QString result = _meta.typeName();
284 309 QByteArray sig = slotName();
285 310 QList<QByteArray> names = _meta.parameterNames();
286 311
287 312 bool isStatic = false;
288 313 bool isConstructor = false;
289 314 bool isDestructor = false;
290 315
291 316 if (_type == ClassDecorator) {
292 317 if (sig.startsWith("new_")) {
293 318 sig = sig.mid(4);
294 319 isConstructor = true;
295 320 } else if (sig.startsWith("delete_")) {
296 321 sig = sig.mid(7);
297 322 isDestructor = true;
298 323 } else if(sig.startsWith("static_")) {
299 324 isStatic = true;
300 325 sig = sig.mid(7);
301 326 int idx = sig.indexOf("_");
302 327 if (idx>=0) {
303 328 sig = sig.mid(idx+1);
304 329 }
305 330 }
306 331 }
307 332
308 333 result += QByteArray(" ") + sig;
309 334 result += "(";
310 335
311 336 int lastEntry = _parameters.count()-1;
312 337 for (int i = skipFirstArg?2:1; i<_parameters.count(); i++) {
313 338 if (_parameters.at(i).isConst) {
314 339 result += "const ";
315 340 }
316 341 result += _parameters.at(i).name;
317 342 if (_parameters.at(i).pointerCount) {
318 343 QByteArray stars;
319 344 stars.fill('*', _parameters.at(i).pointerCount);
320 345 result += stars;
321 346 }
322 347 if (!names.at(i-1).isEmpty()) {
323 348 result += " ";
324 349 result += names.at(i-1);
325 350 }
326 351 if (i!=lastEntry) {
327 352 result += ", ";
328 353 }
329 354 }
330 355 result += ")";
331 356
332 357 if (isStatic) {
333 358 result = QString("static ") + result;
334 359 }
335 360 if (isConstructor) {
336 361 // result = QString("constructor ") + result;
337 362 }
338 363 if (isDestructor) {
339 364 result = QString("~") + result;
340 365 }
341 366 return result;
342 367 }
343 368
344 369
345 370 QByteArray PythonQtSlotInfo::slotName()
346 371 {
347 372 QByteArray sig(_meta.signature());
348 373 int idx = sig.indexOf('(');
349 374 sig = sig.left(idx);
350 375 return sig;
351 376 }
352 377
@@ -1,242 +1,273
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, 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 PythonQtSignalReceiver.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 "PythonQtSignalReceiver.h"
43 43 #include "PythonQtClassInfo.h"
44 44 #include "PythonQtMethodInfo.h"
45 45 #include "PythonQtConversion.h"
46 46 #include <QMetaObject>
47 47 #include <QMetaMethod>
48 48 #include "funcobject.h"
49 49
50 // use -2 to signal that the variable is uninitialized
51 int PythonQtSignalReceiver::_destroyedSignal1Id = -2;
52 int PythonQtSignalReceiver::_destroyedSignal2Id = -2;
53
50 54 void PythonQtSignalTarget::call(void **arguments) const {
51 55 PyObject* result = call(_callable, methodInfo(), arguments);
52 56 if (result) {
53 57 Py_DECREF(result);
54 58 }
55 59 }
56 60
57 61 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInfo* methodInfos, void **arguments, bool skipFirstArgumentOfMethodInfo)
58 62 {
59 63 Q_UNUSED(skipFirstArgumentOfMethodInfo)
60 64
61 65 // Note: we check if the callable is a PyFunctionObject and has a fixed number of arguments
62 66 // if that is the case, we only pass these arguments to python and skip the additional arguments from the signal
63 67
64 68 int numPythonArgs = -1;
65 69 if (PyFunction_Check(callable)) {
66 70 PyObject* o = callable;
67 71 PyFunctionObject* func = (PyFunctionObject*)o;
68 72 PyCodeObject* code = (PyCodeObject*)func->func_code;
69 73 if (!(code->co_flags & CO_VARARGS)) {
70 74 numPythonArgs = code->co_argcount;
71 75 } else {
72 76 // variable numbers of arguments allowed
73 77 }
74 78 } else if (PyMethod_Check(callable)) {
75 79 PyObject* o = callable;
76 80 PyMethodObject* method = (PyMethodObject*)o;
77 81 if (PyFunction_Check(method->im_func)) {
78 82 PyFunctionObject* func = (PyFunctionObject*)method->im_func;
79 83 PyCodeObject* code = (PyCodeObject*)func->func_code;
80 84 if (!(code->co_flags & CO_VARARGS)) {
81 85 numPythonArgs = code->co_argcount - 1; // we subtract one because the first is "self"
82 86 } else {
83 87 // variable numbers of arguments allowed
84 88 }
85 89 }
86 90 }
87 91
88 92 const PythonQtMethodInfo* m = methodInfos;
89 93 // parameterCount includes return value:
90 94 int count = m->parameterCount();
91 95 if (numPythonArgs!=-1) {
92 96 if (count>numPythonArgs+1) {
93 97 // take less arguments
94 98 count = numPythonArgs+1;
95 99 }
96 100 }
97 101
98 102 PyObject* pargs = NULL;
99 103 if (count>1) {
100 104 pargs = PyTuple_New(count-1);
101 105 }
102 106 bool err = false;
103 107 // transform Qt values to Python
104 108 const QList<PythonQtMethodInfo::ParameterInfo>& params = m->parameters();
105 109 for (int i = 1; i < count; i++) {
106 110 const PythonQtMethodInfo::ParameterInfo& param = params.at(i);
107 111 PyObject* arg = PythonQtConv::ConvertQtValueToPython(param, arguments[i]);
108 112 if (arg) {
109 113 // steals reference, no unref
110 114 PyTuple_SetItem(pargs, i-1,arg);
111 115 } else {
112 116 err = true;
113 117 break;
114 118 }
115 119 }
116 120
117 121 PyObject* result = NULL;
118 122 if (!err) {
119 123 PyErr_Clear();
120 124 result = PyObject_CallObject(callable, pargs);
121 125 if (result) {
122 126 // ok
123 127 } else {
124 128 PythonQt::self()->handleError();
125 129 }
126 130 }
127 131 if (pargs) {
128 132 // free the arguments again
129 133 Py_DECREF(pargs);
130 134 }
131 135
132 136 return result;
133 137 }
134 138
135 139 bool PythonQtSignalTarget::isSame( int signalId, PyObject* callable ) const
136 140 {
137 141 return PyObject_Compare(callable, _callable) == 0 && signalId==_signalId;
138 142 }
139 143
140 144 //------------------------------------------------------------------------------
141 145
142 146 PythonQtSignalReceiver::PythonQtSignalReceiver(QObject* obj):PythonQtSignalReceiverBase(obj)
143 147 {
148 if (_destroyedSignal1Id == -2) {
149 // initialize these once
150 _destroyedSignal1Id = QObject::staticMetaObject.indexOfSignal("destroyed()");
151 _destroyedSignal2Id = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
152 if (_destroyedSignal1Id == -1 || _destroyedSignal2Id == -1) {
153 std::cerr << "PythonQt: could not find destroyed signal index, should never happen!" << std::endl;
154 }
155 }
156
157 _destroyedSignalCount = 0;
144 158 _obj = obj;
145 159
146 160 // fetch the class info for object, since we will need to for correct enum resolution in
147 161 // signals
148 162 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
149 163 if (!_objClassInfo || !_objClassInfo->isQObject()) {
150 164 PythonQt::self()->registerClass(obj->metaObject());
151 165 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
152 166 }
153 167 // force decorator/enum creation
154 168 _objClassInfo->decorator();
155 169
156 170 _slotCount = staticMetaObject.methodOffset();
157 171 }
158 172
159 173 PythonQtSignalReceiver::~PythonQtSignalReceiver()
160 174 {
161 175 PythonQt::priv()->removeSignalEmitter(_obj);
162 176 }
163 177
164 178
165 179 bool PythonQtSignalReceiver::addSignalHandler(const char* signal, PyObject* callable)
166 180 {
167 181 bool flag = false;
168 182 int sigId = getSignalIndex(signal);
169 183 if (sigId>=0) {
170 184 // create PythonQtMethodInfo from signal
171 185 QMetaMethod meta = _obj->metaObject()->method(sigId);
172 186 const PythonQtMethodInfo* signalInfo = PythonQtMethodInfo::getCachedMethodInfo(meta, _objClassInfo);
173 187 PythonQtSignalTarget t(sigId, signalInfo, _slotCount, callable);
174 188 _targets.append(t);
175 189 // now connect to ourselves with the new slot id
176 190 QMetaObject::connect(_obj, sigId, this, _slotCount, Qt::AutoConnection, 0);
177 191
178 192 _slotCount++;
179 193 flag = true;
194
195 if (sigId == _destroyedSignal1Id || sigId == _destroyedSignal2Id) {
196 _destroyedSignalCount++;
197 if (_destroyedSignalCount==1) {
198 // make ourself parent of PythonQt, to not get deleted as a child of the QObject we are
199 // listening to, since we do that manually when we receive the destroyed signal
200 this->setParent(PythonQt::priv());
201 }
202 }
180 203 }
181 204 return flag;
182 205 }
183 206
184 207 bool PythonQtSignalReceiver::removeSignalHandler(const char* signal, PyObject* callable)
185 208 {
186 bool found = false;
209 int foundCount = 0;
187 210 int sigId = getSignalIndex(signal);
188 211 if (sigId>=0) {
189 212 QMutableListIterator<PythonQtSignalTarget> i(_targets);
190 213 if (callable) {
191 214 while (i.hasNext()) {
192 215 if (i.next().isSame(sigId, callable)) {
193 216 i.remove();
194 found = true;
217 foundCount++;
195 218 break;
196 219 }
197 220 }
198 221 } else {
199 222 while (i.hasNext()) {
200 223 if (i.next().signalId() == sigId) {
201 224 i.remove();
202 found = true;
225 foundCount++;
203 226 }
204 227 }
205 228 }
206 229 }
207 return found;
230 if ((foundCount>0) && (sigId == _destroyedSignal1Id) || (sigId == _destroyedSignal2Id)) {
231 _destroyedSignalCount -= foundCount;
232 if (_destroyedSignalCount==0) {
233 // make ourself child of QObject again, to get deleted when the object gets deleted
234 this->setParent(_obj);
208 235 }
209
210 void PythonQtSignalReceiver::removeSignalHandlers()
211 {
212 _targets.clear();
236 }
237 return foundCount>0;
213 238 }
214 239
215 240 int PythonQtSignalReceiver::getSignalIndex(const char* signal)
216 241 {
217 242 int sigId = _obj->metaObject()->indexOfSignal(signal+1);
218 243 if (sigId<0) {
219 244 QByteArray tmpSig = QMetaObject::normalizedSignature(signal+1);
220 245 sigId = _obj->metaObject()->indexOfSignal(tmpSig);
221 246 }
222 247 return sigId;
223 248 }
224 249
225 250 int PythonQtSignalReceiver::qt_metacall(QMetaObject::Call c, int id, void **arguments)
226 251 {
227 252 // mlabDebugConst("PythonQt", "PythonQtSignalReceiver invoke " << _obj->className() << " " << _obj->name() << " " << id);
228 253 if (c != QMetaObject::InvokeMetaMethod) {
229 254 QObject::qt_metacall(c, id, arguments);
230 255 }
231 256
232 bool found = false;
233 257 foreach(const PythonQtSignalTarget& t, _targets) {
234 258 if (t.slotId() == id) {
235 found = true;
236 259 t.call(arguments);
260 // if the signal is the last destroyed signal, we delete ourselves
261 int sigId = t.signalId();
262 if ((sigId == _destroyedSignal1Id) || (sigId == _destroyedSignal2Id)) {
263 _destroyedSignalCount--;
264 if (_destroyedSignalCount == 0) {
265 delete this;
266 }
267 }
237 268 break;
238 269 }
239 270 }
240 271 return 0;
241 272 }
242 273
@@ -1,143 +1,144
1 1 #ifndef _PYTHONQTSIGNALRECEIVER_H
2 2 #define _PYTHONQTSIGNALRECEIVER_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, 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 PythonQtSignalReceiver.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 "PythonQtPythonInclude.h"
46 46
47 47 #include "PythonQtSystem.h"
48 48 #include "PythonQtObjectPtr.h"
49 49
50 50 class PythonQtMethodInfo;
51 51 class PythonQtClassInfo;
52 52
53 53 //! stores information about a signal target
54 54 /*! copy construction and assignment works fine with the C++ standard behavior and are thus not implemented
55 55 */
56 56 class PYTHONQT_EXPORT PythonQtSignalTarget {
57 57 public:
58 58 PythonQtSignalTarget() {
59 59 _signalId = -1;
60 60 _methodInfo = NULL;
61 61 _slotId = -1;
62 62 }
63 63
64 64 PythonQtSignalTarget(int signalId,const PythonQtMethodInfo* methodInfo, int slotId, PyObject* callable)
65 65 {
66 66 _signalId = signalId;
67 67 _slotId = slotId;
68 68 _methodInfo = methodInfo;
69 69 _callable = callable;
70 70 };
71 71
72 72 ~PythonQtSignalTarget() {
73 73 };
74 74
75 75 //! get the id of the original signal
76 76 int signalId() const { return _signalId; }
77 77
78 78 //! get the id that was assigned to this simulated slot
79 79 int slotId() const { return _slotId; }
80 80
81 81 //! get the signals parameter info
82 82 const PythonQtMethodInfo* methodInfo() const { return _methodInfo; }
83 83
84 84 //! call the python callable with the given arguments (as defined in methodInfo)
85 85 void call(void **arguments) const;
86 86
87 87 //! check if it is the same signal target
88 88 bool isSame(int signalId, PyObject* callable) const;
89 89
90 90 //! call the given callable with arguments described by PythonQtMethodInfo, returns a new reference as result value (or NULL)
91 91 static PyObject* call(PyObject* callable, const PythonQtMethodInfo* methodInfo, void **arguments, bool skipFirstArgumentOfMethodInfo = false);
92 92
93 93 private:
94 94 int _signalId;
95 95 int _slotId;
96 96 const PythonQtMethodInfo* _methodInfo;
97 97 PythonQtObjectPtr _callable;
98 98 };
99 99
100 100 //! base class for signal receivers
101 101 /*!
102 102 */
103 103 class PythonQtSignalReceiverBase : public QObject {
104 104 Q_OBJECT
105 105 public:
106 106 PythonQtSignalReceiverBase(QObject* obj):QObject(obj) {};
107 107 };
108 108
109 109 //! receives all signals for one QObject
110 110 /*! we derive from our base but do not declare the QObject macro because we want to reimplement qt_metacall only.
111 111 */
112 112 class PythonQtSignalReceiver : public PythonQtSignalReceiverBase {
113 113
114 114 public:
115 115 PythonQtSignalReceiver(QObject* obj);
116 116 ~PythonQtSignalReceiver();
117 117
118 118 //! add a signal handler
119 119 bool addSignalHandler(const char* signal, PyObject* callable);
120 120
121 121 //! remove a signal handler for given callable (or all callables on that signal if callable is NULL)
122 122 bool removeSignalHandler(const char* signal, PyObject* callable = NULL);
123 123
124 //! remove all signal handlers
125 void removeSignalHandlers();
126
127 124 //! we implement this method to simulate a number of slots that match the ids in _targets
128 125 virtual int qt_metacall(QMetaObject::Call c, int id, void **arguments);
129 126
130 127 private:
131 128 //! get the index of the signal
132 129 int getSignalIndex(const char* signal);
133 130
134 131 QObject* _obj;
135 132 PythonQtClassInfo* _objClassInfo;
136 133 int _slotCount;
134 int _destroyedSignalCount;
137 135 // linear list may get slow on multiple targets, but I think typically we have many objects and just a few signals
138 136 QList<PythonQtSignalTarget> _targets;
137
138 static int _destroyedSignal1Id;
139 static int _destroyedSignal2Id;
139 140 };
140 141
141 142
142 143 #endif
143 144
@@ -1,318 +1,323
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, 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 PythonQtStdDecorators.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2007-04
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtStdDecorators.h"
43 43 #include "PythonQt.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include <QCoreApplication>
46 46
47 47 bool PythonQtStdDecorators::connect(QObject* sender, const QByteArray& signal, PyObject* callable)
48 48 {
49 49 bool result = false;
50 50 QByteArray signalTmp;
51 51 char first = signal.at(0);
52 52 if (first>='0' && first<='9') {
53 53 signalTmp = signal;
54 54 } else {
55 55 signalTmp = "2" + signal;
56 56 }
57 57
58 58 if (sender) {
59 59 result = PythonQt::self()->addSignalHandler(sender, signalTmp, callable);
60 60 if (!result) {
61 61 if (sender->metaObject()->indexOfSignal(QMetaObject::normalizedSignature(signalTmp.constData()+1)) == -1) {
62 62 qWarning("PythonQt: QObject::connect() signal '%s' does not exist on %s", signal.constData(), sender->metaObject()->className());
63 63 }
64 64 }
65 65 }
66 66 return result;
67 67 }
68 68
69 bool PythonQtStdDecorators::connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot)
69 bool PythonQtStdDecorators::connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot, Qt::ConnectionType type)
70 70 {
71 71 bool r = false;
72 72 if (sender && receiver) {
73 73 QByteArray signalTmp;
74 74 char first = signal.at(0);
75 75 if (first>='0' && first<='9') {
76 76 signalTmp = signal;
77 77 } else {
78 78 signalTmp = "2" + signal;
79 79 }
80 80
81 81 QByteArray slotTmp;
82 82 first = slot.at(0);
83 83 if (first>='0' && first<='9') {
84 84 slotTmp = slot;
85 85 } else {
86 86 slotTmp = "1" + slot;
87 87 }
88 r = QObject::connect(sender, signalTmp, receiver, slotTmp);
88 r = QObject::connect(sender, signalTmp, receiver, slotTmp, type);
89 89 }
90 90 return r;
91 91 }
92 92
93 93 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal, PyObject* callable)
94 94 {
95 95 bool result = false;
96 96 QByteArray signalTmp;
97 97 char first = signal.at(0);
98 98 if (first>='0' && first<='9') {
99 99 signalTmp = signal;
100 100 } else {
101 101 signalTmp = "2" + signal;
102 102 }
103 103 if (sender) {
104 104 result = PythonQt::self()->removeSignalHandler(sender, signalTmp, callable);
105 105 if (callable == NULL) {
106 106 result |= QObject::disconnect(sender, signalTmp, NULL, NULL);
107 107 }
108 108 if (!result) {
109 109 if (sender->metaObject()->indexOfSignal(QMetaObject::normalizedSignature(signalTmp.constData()+1)) == -1) {
110 110 qWarning("PythonQt: QObject::disconnect() signal '%s' does not exist on %s", signal.constData(), sender->metaObject()->className());
111 111 }
112 112 }
113 113 }
114 114 return result;
115 115 }
116 116
117 117 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot)
118 118 {
119 119 bool r = false;
120 120 if (sender && receiver) {
121 121 QByteArray signalTmp;
122 122 char first = signal.at(0);
123 123 if (first>='0' && first<='9') {
124 124 signalTmp = signal;
125 125 } else {
126 126 signalTmp = "2" + signal;
127 127 }
128 128
129 129 QByteArray slotTmp;
130 130 first = slot.at(0);
131 131 if (first>='0' && first<='9') {
132 132 slotTmp = slot;
133 133 } else {
134 134 slotTmp = "1" + slot;
135 135 }
136 136
137 137 r = QObject::disconnect(sender, signalTmp, receiver, slotTmp);
138 138 }
139 139 return r;
140 140 }
141 141
142 142 QObject* PythonQtStdDecorators::parent(QObject* o) {
143 143 return o->parent();
144 144 }
145 145
146 146 void PythonQtStdDecorators::setParent(QObject* o, QObject* parent)
147 147 {
148 148 o->setParent(parent);
149 149 }
150 150
151 151 const QObjectList* PythonQtStdDecorators::children(QObject* o)
152 152 {
153 153 return &o->children();
154 154 }
155 155
156 156 bool PythonQtStdDecorators::setProperty(QObject* o, const char* name, const QVariant& value)
157 157 {
158 158 return o->setProperty(name, value);
159 159 }
160 160
161 161 QVariant PythonQtStdDecorators::property(QObject* o, const char* name)
162 162 {
163 163 return o->property(name);
164 164 }
165 165
166 166 QString PythonQtStdDecorators::tr(QObject* obj, const QByteArray& text, const QByteArray& ambig, int n)
167 167 {
168 168 return QCoreApplication::translate(obj->metaObject()->className(), text.constData(), ambig.constData(), QCoreApplication::CodecForTr, n);
169 169 }
170 170
171 171 QObject* PythonQtStdDecorators::findChild(QObject* parent, PyObject* type, const QString& name)
172 172 {
173 173 const QMetaObject* meta = NULL;
174 174 const char* typeName = NULL;
175 175
176 176 if (PyObject_TypeCheck(type, &PythonQtClassWrapper_Type)) {
177 177 meta = ((PythonQtClassWrapper*)type)->classInfo()->metaObject();
178 178 } else if (PyObject_TypeCheck(type, &PythonQtInstanceWrapper_Type)) {
179 179 meta = ((PythonQtInstanceWrapper*)type)->classInfo()->metaObject();
180 180 } else if (PyString_Check(type)) {
181 181 typeName = PyString_AsString(type);
182 182 }
183 183
184 184 if (!typeName && !meta)
185 185 return NULL;
186 186
187 187 return findChild(parent, typeName, meta, name);
188 188 }
189 189
190 190 QList<QObject*> PythonQtStdDecorators::findChildren(QObject* parent, PyObject* type, const QString& name)
191 191 {
192 192 const QMetaObject* meta = NULL;
193 193 const char* typeName = NULL;
194 194
195 195 if (PyObject_TypeCheck(type, &PythonQtClassWrapper_Type)) {
196 196 meta = ((PythonQtClassWrapper*)type)->classInfo()->metaObject();
197 197 } else if (PyObject_TypeCheck(type, &PythonQtInstanceWrapper_Type)) {
198 198 meta = ((PythonQtInstanceWrapper*)type)->classInfo()->metaObject();
199 199 } else if (PyString_Check(type)) {
200 200 typeName = PyString_AsString(type);
201 201 }
202 202
203 203 QList<QObject*> list;
204 204
205 205 if (!typeName && !meta)
206 206 return list;
207 207
208 208 findChildren(parent, typeName, meta, name, list);
209 209
210 210 return list;
211 211 }
212 212
213 213 QList<QObject*> PythonQtStdDecorators::findChildren(QObject* parent, PyObject* type, const QRegExp& regExp)
214 214 {
215 215 const QMetaObject* meta = NULL;
216 216 const char* typeName = NULL;
217 217
218 218 if (PyObject_TypeCheck(type, &PythonQtClassWrapper_Type)) {
219 219 meta = ((PythonQtClassWrapper*)type)->classInfo()->metaObject();
220 220 } else if (PyObject_TypeCheck(type, &PythonQtInstanceWrapper_Type)) {
221 221 meta = ((PythonQtInstanceWrapper*)type)->classInfo()->metaObject();
222 222 } else if (PyString_Check(type)) {
223 223 typeName = PyString_AsString(type);
224 224 }
225 225
226 226 QList<QObject*> list;
227 227
228 228 if (!typeName && !meta)
229 229 return list;
230 230
231 231 findChildren(parent, typeName, meta, regExp, list);
232 232
233 233 return list;
234 234 }
235 235
236 236 QObject* PythonQtStdDecorators::findChild(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name)
237 237 {
238 238 const QObjectList &children = parent->children();
239 239
240 240 int i;
241 241 for (i = 0; i < children.size(); ++i) {
242 242 QObject* obj = children.at(i);
243 243
244 244 if (!obj)
245 245 return NULL;
246 246
247 247 // Skip if the name doesn't match.
248 248 if (!name.isNull() && obj->objectName() != name)
249 249 continue;
250 250
251 251 if ((typeName && obj->inherits(typeName)) ||
252 252 (meta && meta->cast(obj)))
253 253 return obj;
254 254 }
255 255
256 256 for (i = 0; i < children.size(); ++i) {
257 257 QObject* obj = findChild(children.at(i), typeName, meta, name);
258 258
259 259 if (obj != NULL)
260 260 return obj;
261 261 }
262 262
263 263 return NULL;
264 264 }
265 265
266 266 int PythonQtStdDecorators::findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name, QList<QObject*>& list)
267 267 {
268 268 const QObjectList& children = parent->children();
269 269 int i;
270 270
271 271 for (i = 0; i < children.size(); ++i) {
272 272 QObject* obj = children.at(i);
273 273
274 274 if (!obj)
275 275 return -1;
276 276
277 277 // Skip if the name doesn't match.
278 278 if (!name.isNull() && obj->objectName() != name)
279 279 continue;
280 280
281 281 if ((typeName && obj->inherits(typeName)) ||
282 282 (meta && meta->cast(obj))) {
283 283 list += obj;
284 284 }
285 285
286 286 if (findChildren(obj, typeName, meta, name, list) < 0)
287 287 return -1;
288 288 }
289 289
290 290 return 0;
291 291 }
292 292
293 293 int PythonQtStdDecorators::findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QRegExp& regExp, QList<QObject*>& list)
294 294 {
295 295 const QObjectList& children = parent->children();
296 296 int i;
297 297
298 298 for (i = 0; i < children.size(); ++i) {
299 299 QObject* obj = children.at(i);
300 300
301 301 if (!obj)
302 302 return -1;
303 303
304 304 // Skip if the name doesn't match.
305 305 if (regExp.indexIn(obj->objectName()) == -1)
306 306 continue;
307 307
308 308 if ((typeName && obj->inherits(typeName)) ||
309 309 (meta && meta->cast(obj))) {
310 310 list += obj;
311 311 }
312 312
313 313 if (findChildren(obj, typeName, meta, regExp, list) < 0)
314 314 return -1;
315 315 }
316 316
317 317 return 0;
318 318 }
319
320 const QMetaObject* PythonQtStdDecorators::metaObject( QObject* obj )
321 {
322 return obj->metaObject();
323 } No newline at end of file
@@ -1,109 +1,159
1 1 #ifndef _PYTHONQTSTDDECORATORS_H
2 2 #define _PYTHONQTSTDDECORATORS_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, 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 PythonQtStdDecorators.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2007-04
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtPythonInclude.h"
46 46
47 47 #include "PythonQtSystem.h"
48 48
49 49 #include <QObject>
50 50 #include <QVariantList>
51 51 #include <QTextDocument>
52 52 #include <QColor>
53 53 #include <QDateTime>
54 54 #include <QDate>
55 55 #include <QTime>
56 #include <QImage>
57 #include <QMetaMethod>
58 #include <QMetaEnum>
59 #include <QMetaProperty>
56 60
57 61 class PYTHONQT_EXPORT PythonQtStdDecorators : public QObject
58 62 {
59 63 Q_OBJECT
60 64
61 65 public slots:
62 66 bool connect(QObject* sender, const QByteArray& signal, PyObject* callable);
63 bool connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot);
67 bool connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot, Qt::ConnectionType type = Qt::AutoConnection);
68 bool connect(QObject* receiver, QObject* sender, const QByteArray& signal, const QByteArray& slot, Qt::ConnectionType type = Qt::AutoConnection) { return connect(sender, signal, receiver, slot, type); }
69 bool static_QObject_connect(QObject* sender, const QByteArray& signal, PyObject* callable) { return connect(sender, signal, callable); }
70 bool static_QObject_connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot, Qt::ConnectionType type = Qt::AutoConnection) { return connect(sender, signal, receiver, slot, type); }
64 71 bool disconnect(QObject* sender, const QByteArray& signal, PyObject* callable = NULL);
65 72 bool disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot);
73 bool static_QObject_disconnect(QObject* sender, const QByteArray& signal, PyObject* callable = NULL) { return disconnect(sender, signal, callable); }
74 bool static_QObject_disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot) { return connect(sender, signal, receiver, slot); }
75
76 const QMetaObject* metaObject( QObject* obj );
66 77
67 78 QObject* parent(QObject* o);
68 79 void setParent(QObject* o, QObject* parent);
69 80
70 81 const QObjectList* children(QObject* o);
71 82 QObject* findChild(QObject* parent, PyObject* type, const QString& name = QString());
72 83 QList<QObject*> findChildren(QObject* parent, PyObject* type, const QString& name= QString());
73 84 QList<QObject*> findChildren(QObject* parent, PyObject* type, const QRegExp& regExp);
74 85
75 86 bool setProperty(QObject* o, const char* name, const QVariant& value);
76 87 QVariant property(QObject* o, const char* name);
77 88
78 89 double static_Qt_qAbs(double a) { return qAbs(a); }
79 90 double static_Qt_qBound(double a,double b,double c) { return qBound(a,b,c); }
80 91 void static_Qt_qDebug(const QByteArray& msg) { qDebug("%s", msg.constData()); }
81 92 // TODO: multi arg qDebug...
82 93 void static_Qt_qWarning(const QByteArray& msg) { qWarning("%s", msg.constData()); }
83 94 // TODO: multi arg qWarning...
84 95 void static_Qt_qCritical(const QByteArray& msg) { qCritical("%s", msg.constData()); }
85 96 // TODO: multi arg qCritical...
86 97 void static_Qt_qFatal(const QByteArray& msg) { qFatal("%s", msg.constData()); }
87 98 // TODO: multi arg qFatal...
88 99 bool static_Qt_qFuzzyCompare(double a, double b) { return qFuzzyCompare(a, b); }
89 100 double static_Qt_qMax(double a, double b) { return qMax(a, b); }
90 101 double static_Qt_qMin(double a, double b) { return qMin(a, b); }
91 102 int static_Qt_qRound(double a) { return qRound(a); }
92 103 qint64 static_Qt_qRound64(double a) { return qRound64(a); }
93 104 const char* static_Qt_qVersion() { return qVersion(); }
94 105 int static_Qt_qrand() { return qrand(); }
95 106 void static_Qt_qsrand(uint a) { qsrand(a); }
96 107
97 108 QString tr(QObject* obj, const QByteArray& text, const QByteArray& ambig = QByteArray(), int n = -1);
98 109
99 110 QByteArray static_Qt_SIGNAL(const QByteArray& s) { return QByteArray("2") + s; }
100 111 QByteArray static_Qt_SLOT(const QByteArray& s) { return QByteArray("1") + s; }
101 112
102 113 private:
103 114 QObject* findChild(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name);
104 115 int findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name, QList<QObject*>& list);
105 116 int findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QRegExp& regExp, QList<QObject*>& list);
106 117 };
107 118
119 class PythonQtWrapper_QMetaObject : public QObject
120 {
121 Q_OBJECT
122
123 public slots:
124 const char *className(QMetaObject* obj) const { return obj->className(); }
125 const QMetaObject *superClass(QMetaObject* obj) const { return obj->superClass(); }
126
127 int methodOffset(QMetaObject* obj) const { return obj->methodOffset(); }
128 int enumeratorOffset(QMetaObject* obj) const { return obj->enumeratorOffset(); }
129 int propertyOffset(QMetaObject* obj) const { return obj->propertyOffset(); }
130 int classInfoOffset(QMetaObject* obj) const { return obj->classInfoOffset(); }
131
132 int constructorCount(QMetaObject* obj) const { return obj->constructorCount(); }
133 int methodCount(QMetaObject* obj) const { return obj->methodCount(); }
134 int enumeratorCount(QMetaObject* obj) const { return obj->enumeratorCount(); }
135 int propertyCount(QMetaObject* obj) const { return obj->propertyCount(); }
136 int classInfoCount(QMetaObject* obj) const { return obj->classInfoCount(); }
137
138 int indexOfConstructor(QMetaObject* obj, const char *constructor) const { return obj->indexOfConstructor(constructor); }
139 int indexOfMethod(QMetaObject* obj, const char *method) const { return obj->indexOfMethod(method); }
140 int indexOfSignal(QMetaObject* obj, const char *signal) const { return obj->indexOfSignal(signal); }
141 int indexOfSlot(QMetaObject* obj, const char *slot) const { return obj->indexOfSlot(slot); }
142 int indexOfEnumerator(QMetaObject* obj, const char *name) const { return obj->indexOfEnumerator(name); }
143 int indexOfProperty(QMetaObject* obj, const char *name) const { return obj->indexOfProperty(name); }
144 int indexOfClassInfo(QMetaObject* obj, const char *name) const { return obj->indexOfClassInfo(name); }
145
146 QMetaMethod constructor(QMetaObject* obj, int index) const { return obj->constructor(index); }
147 QMetaMethod method(QMetaObject* obj, int index) const { return obj->method(index); }
148 QMetaEnum enumerator(QMetaObject* obj, int index) const { return obj->enumerator(index); }
149 QMetaProperty property(QMetaObject* obj, int index) const { return obj->property(index); }
150 QMetaClassInfo classInfo(QMetaObject* obj, int index) const { return obj->classInfo(index); }
151 QMetaProperty userProperty(QMetaObject* obj) const { return obj->userProperty(); }
152
153 bool static_QMetaObject_checkConnectArgs(const char *signal, const char *method) { return QMetaObject::checkConnectArgs(signal, method); }
154 QByteArray static_QMetaObject_normalizedSignature(const char *method) { return QMetaObject::normalizedSignature(method); }
155 QByteArray static_QMetaObject_normalizedType(const char *type) { return QMetaObject::normalizedType(type); }
156
157 };
108 158
109 159 #endif
General Comments 0
You need to be logged in to leave comments. Login now