##// END OF EJS Templates
added initial version of foreign wrappers, needs testing...
florianlink -
r167:2184742f9ca8
parent child
Show More
@@ -1,1318 +1,1342
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 "PythonQtSignalReceiver.h"
47 47 #include "PythonQtConversion.h"
48 48 #include "PythonQtStdIn.h"
49 49 #include "PythonQtStdOut.h"
50 50 #include "PythonQtCppWrapperFactory.h"
51 51 #include "PythonQtVariants.h"
52 52 #include "PythonQtStdDecorators.h"
53 53 #include "PythonQtQFileImporter.h"
54 54 #include <pydebug.h>
55 55 #include <vector>
56 56
57 57 PythonQt* PythonQt::_self = NULL;
58 58 int PythonQt::_uniqueModuleCount = 0;
59 59
60 60 void PythonQt_init_QtGuiBuiltin(PyObject*);
61 61 void PythonQt_init_QtCoreBuiltin(PyObject*);
62 62
63 63 void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
64 64 {
65 65 if (!_self) {
66 66 _self = new PythonQt(flags, pythonQtModuleName);
67 67
68 68 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
69 69 qRegisterMetaType<QList<QObject*> >("QList<void*>");
70 70
71 71 PythonQtRegisterToolClassesTemplateConverter(int);
72 72 PythonQtRegisterToolClassesTemplateConverter(float);
73 73 PythonQtRegisterToolClassesTemplateConverter(double);
74 74 PythonQtRegisterToolClassesTemplateConverter(qint32);
75 75 PythonQtRegisterToolClassesTemplateConverter(quint32);
76 76 PythonQtRegisterToolClassesTemplateConverter(qint64);
77 77 PythonQtRegisterToolClassesTemplateConverter(quint64);
78 78 // TODO: which other POD types should be available for QList etc.
79 79
80 80 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
81 81
82 82 PythonQt_init_QtCoreBuiltin(NULL);
83 83 PythonQt_init_QtGuiBuiltin(NULL);
84 84
85 85 PythonQtRegisterToolClassesTemplateConverter(QByteArray);
86 86 PythonQtRegisterToolClassesTemplateConverter(QDate);
87 87 PythonQtRegisterToolClassesTemplateConverter(QTime);
88 88 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
89 89 PythonQtRegisterToolClassesTemplateConverter(QUrl);
90 90 PythonQtRegisterToolClassesTemplateConverter(QLocale);
91 91 PythonQtRegisterToolClassesTemplateConverter(QRect);
92 92 PythonQtRegisterToolClassesTemplateConverter(QRectF);
93 93 PythonQtRegisterToolClassesTemplateConverter(QSize);
94 94 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
95 95 PythonQtRegisterToolClassesTemplateConverter(QLine);
96 96 PythonQtRegisterToolClassesTemplateConverter(QLineF);
97 97 PythonQtRegisterToolClassesTemplateConverter(QPoint);
98 98 PythonQtRegisterToolClassesTemplateConverter(QPointF);
99 99 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
100 100
101 101 PythonQtRegisterToolClassesTemplateConverter(QFont);
102 102 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
103 103 PythonQtRegisterToolClassesTemplateConverter(QBrush);
104 104 PythonQtRegisterToolClassesTemplateConverter(QColor);
105 105 PythonQtRegisterToolClassesTemplateConverter(QPalette);
106 106 PythonQtRegisterToolClassesTemplateConverter(QIcon);
107 107 PythonQtRegisterToolClassesTemplateConverter(QImage);
108 108 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
109 109 PythonQtRegisterToolClassesTemplateConverter(QRegion);
110 110 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
111 111 PythonQtRegisterToolClassesTemplateConverter(QCursor);
112 112 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
113 113 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
114 114 PythonQtRegisterToolClassesTemplateConverter(QPen);
115 115 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
116 116 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
117 117 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
118 118
119 119
120 120 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
121 121 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
122 122 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
123 123 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
124 124 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
125 125 for (unsigned int i = 0;i<16; i++) {
126 126 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
127 127 if (obj) {
128 128 PyModule_AddObject(pack, names[i], obj);
129 129 Py_INCREF(obj);
130 130 PyModule_AddObject(pack2, names[i], obj);
131 131 } else {
132 132 std::cerr << "method not found " << names[i];
133 133 }
134 134 }
135 135 }
136 136 }
137 137
138 138 void PythonQt::cleanup()
139 139 {
140 140 if (_self) {
141 141 delete _self;
142 142 _self = NULL;
143 143 }
144 144 }
145 145
146 146 PythonQt* PythonQt::self() { return _self; }
147 147
148 148 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
149 149 {
150 150 _p = new PythonQtPrivate;
151 151 _p->_initFlags = flags;
152 152
153 153 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
154 154
155 155 if ((flags & PythonAlreadyInitialized) == 0) {
156 156 Py_SetProgramName(const_cast<char*>("PythonQt"));
157 157 if (flags & IgnoreSiteModule) {
158 158 // this prevents the automatic importing of Python site files
159 159 Py_NoSiteFlag = 1;
160 160 }
161 161 Py_Initialize();
162 162 }
163 163
164 164 // add our own python object types for qt object slots
165 165 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
166 166 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
167 167 }
168 168 Py_INCREF(&PythonQtSlotFunction_Type);
169 169
170 170 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
171 171 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
172 172 // add our own python object types for classes
173 173 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
174 174 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
175 175 }
176 176 Py_INCREF(&PythonQtClassWrapper_Type);
177 177
178 178 // add our own python object types for CPP instances
179 179 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
180 180 PythonQt::handleError();
181 181 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
182 182 }
183 183 Py_INCREF(&PythonQtInstanceWrapper_Type);
184 184
185 185 // add our own python object types for redirection of stdout
186 186 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
187 187 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
188 188 }
189 189 Py_INCREF(&PythonQtStdOutRedirectType);
190 190
191 191 // add our own python object types for redirection of stdin
192 192 if (PyType_Ready(&PythonQtStdInRedirectType) < 0) {
193 193 std::cerr << "could not initialize PythonQtStdInRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
194 194 }
195 195 Py_INCREF(&PythonQtStdInRedirectType);
196 196
197 197 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
198 198
199 199 _p->setupSharedLibrarySuffixes();
200 200
201 201 }
202 202
203 203 PythonQt::~PythonQt() {
204 204 delete _p;
205 205 _p = NULL;
206 206 }
207 207
208 208 PythonQtPrivate::~PythonQtPrivate() {
209 209 delete _defaultImporter;
210 210 _defaultImporter = NULL;
211 211
212 212 {
213 213 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
214 214 while (i.hasNext()) {
215 215 delete i.next().value();
216 216 }
217 217 }
218 218 PythonQtConv::global_valueStorage.clear();
219 219 PythonQtConv::global_ptrStorage.clear();
220 220 PythonQtConv::global_variantStorage.clear();
221 221
222 222 PythonQtMethodInfo::cleanupCachedMethodInfos();
223 223 }
224 224
225 225 void PythonQt::setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData)
226 226 {
227 227 if (!callback)
228 228 {
229 229 std::cerr << "PythonQt::setRedirectStdInCallback - callback parameter is NULL !" << std::endl;
230 230 return;
231 231 }
232 232
233 233 PythonQtObjectPtr sys;
234 234 PythonQtObjectPtr in;
235 235 sys.setNewRef(PyImport_ImportModule("sys"));
236 236
237 237 // Backup original 'sys.stdin' if not yet done
238 238 PyRun_SimpleString("if not hasattr(sys, 'pythonqt_original_stdin'):"
239 239 "sys.pythonqt_original_stdin = sys.stdin");
240 240
241 241 in = PythonQtStdInRedirectType.tp_new(&PythonQtStdInRedirectType, NULL, NULL);
242 242 ((PythonQtStdInRedirect*)in.object())->_cb = callback;
243 243 ((PythonQtStdInRedirect*)in.object())->_callData = callbackData;
244 244 // replace the built in file objects with our own objects
245 245 PyModule_AddObject(sys, "stdin", in);
246 246
247 247 // Backup custom 'stdin' into 'pythonqt_stdin'
248 248 PyRun_SimpleString("sys.pythonqt_stdin = sys.stdin");
249 249 }
250 250
251 251 void PythonQt::setRedirectStdInCallbackEnabled(bool enabled)
252 252 {
253 253 if (enabled)
254 254 {
255 255 PyRun_SimpleString("if hasattr(sys, 'pythonqt_stdin'):"
256 256 "sys.stdin = sys.pythonqt_stdin");
257 257 }
258 258 else
259 259 {
260 260 PyRun_SimpleString("if hasattr(sys,'pythonqt_original_stdin'):"
261 261 "sys.stdin = sys.pythonqt_original_stdin");
262 262 }
263 263 }
264 264
265 265 PythonQtImportFileInterface* PythonQt::importInterface()
266 266 {
267 267 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
268 268 }
269 269
270 270 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
271 271 {
272 272 if (_self->_p->_noLongerWrappedCB) {
273 273 (*_self->_p->_noLongerWrappedCB)(o);
274 274 };
275 275 }
276 276
277 277 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
278 278 {
279 279 _p->registerClass(metaobject, package, wrapperCreator, shell);
280 280 }
281 281
282 282 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
283 283 {
284 284 // we register all classes in the hierarchy
285 285 const QMetaObject* m = metaobject;
286 286 bool first = true;
287 287 while (m) {
288 288 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
289 289 if (!info->pythonQtClassWrapper()) {
290 290 info->setTypeSlots(typeSlots);
291 291 info->setupQObject(m);
292 292 createPythonQtClassWrapper(info, package, module);
293 293 if (m->superClass()) {
294 294 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
295 295 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
296 296 }
297 297 } else if (first && module) {
298 298 // There is a wrapper already, but if we got a module, we want to place the wrapper into that module as well,
299 299 // since it might have been placed into "private" earlier on.
300 300 // If the wrapper was already added to module before, it is just readded, which does no harm.
301 301 PyObject* classWrapper = info->pythonQtClassWrapper();
302 302 // AddObject steals a reference, so we need to INCREF
303 303 Py_INCREF(classWrapper);
304 304 PyModule_AddObject(module, info->className(), classWrapper);
305 305 }
306 306 if (first) {
307 307 first = false;
308 308 if (wrapperCreator) {
309 309 info->setDecoratorProvider(wrapperCreator);
310 310 }
311 311 if (shell) {
312 312 info->setShellSetInstanceWrapperCB(shell);
313 313 }
314 314 }
315 315 m = m->superClass();
316 316 }
317 317 }
318 318
319 319 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
320 320 {
321 321 PyObject* pack = module?module:packageByName(package);
322 322 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
323 323 PyModule_AddObject(pack, info->className(), pyobj);
324 324 if (!module && package && strncmp(package,"Qt",2)==0) {
325 325 // since PyModule_AddObject steals the reference, we need a incref once more...
326 326 Py_INCREF(pyobj);
327 327 // put all qt objects into Qt as well
328 328 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
329 329 }
330 330 info->setPythonQtClassWrapper(pyobj);
331 331 }
332 332
333 333 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
334 334 {
335 335 if (!obj) {
336 336 Py_INCREF(Py_None);
337 337 return Py_None;
338 338 }
339 339 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
340 340 if (!wrap) {
341 341 // smuggling it in...
342 342 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
343 343 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
344 344 registerClass(obj->metaObject());
345 345 classInfo = _knownClassInfos.value(obj->metaObject()->className());
346 346 }
347 347 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
348 348 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
349 349 } else {
350 350 Py_INCREF(wrap);
351 351 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
352 352 }
353 353 return (PyObject*)wrap;
354 354 }
355 355
356 356 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
357 357 {
358 358 if (!ptr) {
359 359 Py_INCREF(Py_None);
360 360 return Py_None;
361 361 }
362 362
363 363 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
364 364 if (!wrap) {
365 365 PythonQtClassInfo* info = _knownClassInfos.value(name);
366 366 if (!info) {
367 367 // maybe it is a PyObject, which we can return directly
368 368 if (name == "PyObject") {
369 369 PyObject* p = (PyObject*)ptr;
370 370 Py_INCREF(p);
371 371 return p;
372 372 }
373 373
374 374 // we do not know the metaobject yet, but we might know it by it's name:
375 375 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
376 376 // yes, we know it, so we can convert to QObject
377 377 QObject* qptr = (QObject*)ptr;
378 378 registerClass(qptr->metaObject());
379 379 info = _knownClassInfos.value(qptr->metaObject()->className());
380 380 }
381 381 }
382 382 if (info && info->isQObject()) {
383 383 QObject* qptr = (QObject*)ptr;
384 384 // if the object is a derived object, we want to switch the class info to the one of the derived class:
385 385 if (name!=(qptr->metaObject()->className())) {
386 386 registerClass(qptr->metaObject());
387 387 info = _knownClassInfos.value(qptr->metaObject()->className());
388 388 }
389 389 wrap = createNewPythonQtInstanceWrapper(qptr, info);
390 390 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
391 391 return (PyObject*)wrap;
392 392 }
393 393
394 // not a known QObject, try to wrap via foreign wrapper factories
395 PyObject* foreignWrapper = NULL;
396 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
397 foreignWrapper = _foreignWrapperFactories.at(i)->wrap(name, ptr);
398 if (foreignWrapper) {
399 return foreignWrapper;
400 }
401 }
402
394 403 // not a known QObject, so try our wrapper factory:
395 404 QObject* wrapper = NULL;
396 405 for (int i=0; i<_cppWrapperFactories.size(); i++) {
397 406 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
398 407 if (wrapper) {
399 408 break;
400 409 }
401 410 }
402 411
403 412 if (info) {
404 413 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
405 414 ptr = info->castDownIfPossible(ptr, &info);
406 415 }
407 416
408 417 if (!info || info->pythonQtClassWrapper()==NULL) {
409 418 // still unknown, register as CPP class
410 419 registerCPPClass(name.constData());
411 420 info = _knownClassInfos.value(name);
412 421 }
413 422 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
414 423 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
415 424 info->setMetaObject(wrapper->metaObject());
416 425 }
417 426
418 // TODO XXX: delegate wrapping via CB here (pass name and ptr)
419
420 427 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
421 428 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
422 429 } else {
423 430 Py_INCREF(wrap);
424 431 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
425 432 }
426 433 return (PyObject*)wrap;
427 434 }
428 435
429 436 PyObject* PythonQtPrivate::dummyTuple() {
430 437 static PyObject* dummyTuple = NULL;
431 438 if (dummyTuple==NULL) {
432 439 dummyTuple = PyTuple_New(1);
433 440 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
434 441 }
435 442 return dummyTuple;
436 443 }
437 444
438 445
439 446 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
440 447 // call the associated class type to create a new instance...
441 448 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
442 449
443 450 result->setQObject(obj);
444 451 result->_wrappedPtr = wrappedPtr;
445 452 result->_ownedByPythonQt = false;
446 453 result->_useQMetaTypeDestroy = false;
447 454
448 455 if (wrappedPtr) {
449 456 _wrappedObjects.insert(wrappedPtr, result);
450 457 } else {
451 458 _wrappedObjects.insert(obj, result);
452 459 if (obj->parent()== NULL && _wrappedCB) {
453 460 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
454 461 (*_wrappedCB)(obj);
455 462 }
456 463 }
457 464 return result;
458 465 }
459 466
460 467 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
461 468 PythonQtClassWrapper* result;
462 469
463 470 PyObject* className = PyString_FromString(info->className());
464 471
465 472 PyObject* baseClasses = PyTuple_New(1);
466 473 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
467 474
468 475 PyObject* typeDict = PyDict_New();
469 476 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
470 477 PyDict_SetItemString(typeDict, "__module__", moduleName);
471 478
472 479 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
473 480
474 481 // set the class info so that PythonQtClassWrapper_new can read it
475 482 _currentClassInfoForClassWrapperCreation = info;
476 483 // create the new type object by calling the type
477 484 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
478 485
479 486 Py_DECREF(baseClasses);
480 487 Py_DECREF(typeDict);
481 488 Py_DECREF(args);
482 489 Py_DECREF(className);
483 490
484 491 return result;
485 492 }
486 493
487 494 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
488 495 {
489 496 PyObject* args = Py_BuildValue("(i)", enumValue);
490 497 PyObject* result = PyObject_Call(enumType, args, NULL);
491 498 Py_DECREF(args);
492 499 return result;
493 500 }
494 501
495 502 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
496 503 PyObject* result;
497 504
498 505 PyObject* className = PyString_FromString(enumName);
499 506
500 507 PyObject* baseClasses = PyTuple_New(1);
501 508 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
502 509
503 510 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
504 511 PyObject* typeDict = PyDict_New();
505 512 PyDict_SetItemString(typeDict, "__module__", module);
506 513
507 514 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
508 515
509 516 // create the new int derived type object by calling the core type
510 517 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
511 518
512 519 Py_DECREF(baseClasses);
513 520 Py_DECREF(typeDict);
514 521 Py_DECREF(args);
515 522 Py_DECREF(className);
516 523
517 524 return result;
518 525 }
519 526
520 527 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
521 528 {
522 529 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
523 530 if (!r) {
524 531 r = new PythonQtSignalReceiver(obj);
525 532 _p->_signalReceivers.insert(obj, r);
526 533 }
527 534 return r;
528 535 }
529 536
530 537 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
531 538 {
532 539 bool flag = false;
533 540 PythonQtObjectPtr callable = lookupCallable(module, objectname);
534 541 if (callable) {
535 542 PythonQtSignalReceiver* r = getSignalReceiver(obj);
536 543 flag = r->addSignalHandler(signal, callable);
537 544 if (!flag) {
538 545 // signal not found
539 546 }
540 547 } else {
541 548 // callable not found
542 549 }
543 550 return flag;
544 551 }
545 552
546 553 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
547 554 {
548 555 bool flag = false;
549 556 PythonQtSignalReceiver* r = getSignalReceiver(obj);
550 557 if (r) {
551 558 flag = r->addSignalHandler(signal, receiver);
552 559 }
553 560 return flag;
554 561 }
555 562
556 563 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
557 564 {
558 565 bool flag = false;
559 566 PythonQtObjectPtr callable = lookupCallable(module, objectname);
560 567 if (callable) {
561 568 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
562 569 if (r) {
563 570 flag = r->removeSignalHandler(signal, callable);
564 571 }
565 572 } else {
566 573 // callable not found
567 574 }
568 575 return flag;
569 576 }
570 577
571 578 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
572 579 {
573 580 bool flag = false;
574 581 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
575 582 if (r) {
576 583 flag = r->removeSignalHandler(signal, receiver);
577 584 }
578 585 return flag;
579 586 }
580 587
581 588 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
582 589 {
583 590 PythonQtObjectPtr p = lookupObject(module, name);
584 591 if (p) {
585 592 if (PyCallable_Check(p)) {
586 593 return p;
587 594 }
588 595 }
589 596 PyErr_Clear();
590 597 return NULL;
591 598 }
592 599
593 600 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
594 601 {
595 602 QStringList l = name.split('.');
596 603 PythonQtObjectPtr p = module;
597 604 PythonQtObjectPtr prev;
598 605 QString s;
599 606 QByteArray b;
600 607 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
601 608 prev = p;
602 609 b = (*i).toLatin1();
603 610 if (PyDict_Check(p)) {
604 611 p = PyDict_GetItemString(p, b.data());
605 612 } else {
606 613 p.setNewRef(PyObject_GetAttrString(p, b.data()));
607 614 }
608 615 }
609 616 PyErr_Clear();
610 617 return p;
611 618 }
612 619
613 620 PythonQtObjectPtr PythonQt::getMainModule() {
614 621 //both borrowed
615 622 PythonQtObjectPtr dict = PyImport_GetModuleDict();
616 623 return PyDict_GetItemString(dict, "__main__");
617 624 }
618 625
619 626 PythonQtObjectPtr PythonQt::importModule(const QString& name)
620 627 {
621 628 PythonQtObjectPtr mod;
622 629 mod.setNewRef(PyImport_ImportModule(name.toLatin1().constData()));
623 630 return mod;
624 631 }
625 632
626 633
627 634 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
628 635 QVariant result;
629 636 if (pycode) {
630 637 PyObject* dict = NULL;
631 638 if (PyModule_Check(object)) {
632 639 dict = PyModule_GetDict(object);
633 640 } else if (PyDict_Check(object)) {
634 641 dict = object;
635 642 }
636 643 PyObject* r = NULL;
637 644 if (dict) {
638 645 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
639 646 }
640 647 if (r) {
641 648 result = PythonQtConv::PyObjToQVariant(r);
642 649 Py_DECREF(r);
643 650 } else {
644 651 handleError();
645 652 }
646 653 } else {
647 654 handleError();
648 655 }
649 656 return result;
650 657 }
651 658
652 659 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
653 660 {
654 661 QVariant result;
655 662 PythonQtObjectPtr p;
656 663 PyObject* dict = NULL;
657 664 if (PyModule_Check(object)) {
658 665 dict = PyModule_GetDict(object);
659 666 } else if (PyDict_Check(object)) {
660 667 dict = object;
661 668 }
662 669 if (dict) {
663 670 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
664 671 }
665 672 if (p) {
666 673 result = PythonQtConv::PyObjToQVariant(p);
667 674 } else {
668 675 handleError();
669 676 }
670 677 return result;
671 678 }
672 679
673 680 void PythonQt::evalFile(PyObject* module, const QString& filename)
674 681 {
675 682 PythonQtObjectPtr code = parseFile(filename);
676 683 if (code) {
677 684 evalCode(module, code);
678 685 } else {
679 686 handleError();
680 687 }
681 688 }
682 689
683 690 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
684 691 {
685 692 PythonQtObjectPtr p;
686 693 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
687 694 if (!p) {
688 695 handleError();
689 696 }
690 697 return p;
691 698 }
692 699
693 700 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
694 701 {
695 702 PythonQtObjectPtr code = parseFile(filename);
696 703 PythonQtObjectPtr module = _p->createModule(name, code);
697 704 return module;
698 705 }
699 706
700 707 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
701 708 {
702 709 PyErr_Clear();
703 710 QString scriptCode = script;
704 711 if (scriptCode.isEmpty()) {
705 712 // we always need at least a linefeed
706 713 scriptCode = "\n";
707 714 }
708 715 PythonQtObjectPtr pycode;
709 716 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
710 717 PythonQtObjectPtr module = _p->createModule(name, pycode);
711 718 return module;
712 719 }
713 720
714 721 PythonQtObjectPtr PythonQt::createUniqueModule()
715 722 {
716 723 static QString pyQtStr("PythonQt_module");
717 724 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
718 725 return createModuleFromScript(moduleName);
719 726 }
720 727
721 728 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
722 729 {
723 730 if (PyModule_Check(object)) {
724 731 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
725 732 } else if (PyDict_Check(object)) {
726 733 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
727 734 } else {
728 735 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
729 736 }
730 737 }
731 738
732 739 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
733 740 {
734 741 if (PyModule_Check(object)) {
735 742 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
736 743 } else if (PyDict_Check(object)) {
737 744 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
738 745 } else {
739 746 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
740 747 }
741 748 }
742 749
743 750 void PythonQt::removeVariable(PyObject* object, const QString& name)
744 751 {
745 752 if (PyDict_Check(object)) {
746 753 PyDict_DelItemString(object, name.toLatin1().data());
747 754 } else {
748 755 PyObject_DelAttrString(object, name.toLatin1().data());
749 756 }
750 757 }
751 758
752 759 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
753 760 {
754 761 QVariant result;
755 762 PythonQtObjectPtr obj = lookupObject(object, objectname);
756 763 if (obj) {
757 764 result = PythonQtConv::PyObjToQVariant(obj);
758 765 }
759 766 return result;
760 767 }
761 768
762 769 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
763 770 {
764 771 QStringList results;
765 772
766 773 PythonQtObjectPtr object;
767 774 if (objectname.isEmpty()) {
768 775 object = module;
769 776 } else {
770 777 object = lookupObject(module, objectname);
771 778 if (!object && type == CallOverloads) {
772 779 PyObject* dict = lookupObject(module, "__builtins__");
773 780 if (dict) {
774 781 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
775 782 }
776 783 }
777 784 }
778 785
779 786 if (object) {
780 787 if (type == CallOverloads) {
781 788 if (PythonQtSlotFunction_Check(object)) {
782 789 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
783 790 PythonQtSlotInfo* info = o->m_ml;
784 791
785 792 while (info) {
786 793 results << info->fullSignature();
787 794 info = info->nextInfo();
788 795 }
789 796 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
790 797 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
791 798 PythonQtSlotInfo* info = o->classInfo()->constructors();
792 799
793 800 while (info) {
794 801 results << info->fullSignature();
795 802 info = info->nextInfo();
796 803 }
797 804 } else {
798 805 //TODO: use pydoc!
799 806 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
800 807 if (doc) {
801 808 results << PyString_AsString(doc);
802 809 Py_DECREF(doc);
803 810 }
804 811 }
805 812 } else {
806 813 PyObject* keys = NULL;
807 814 bool isDict = false;
808 815 if (PyDict_Check(object)) {
809 816 keys = PyDict_Keys(object);
810 817 isDict = true;
811 818 } else {
812 819 keys = PyObject_Dir(object);
813 820 }
814 821 if (keys) {
815 822 int count = PyList_Size(keys);
816 823 PyObject* key;
817 824 PyObject* value;
818 825 QString keystr;
819 826 for (int i = 0;i<count;i++) {
820 827 key = PyList_GetItem(keys,i);
821 828 if (isDict) {
822 829 value = PyDict_GetItem(object, key);
823 830 Py_INCREF(value);
824 831 } else {
825 832 value = PyObject_GetAttr(object, key);
826 833 }
827 834 if (!value) continue;
828 835 keystr = PyString_AsString(key);
829 836 static const QString underscoreStr("__tmp");
830 837 if (!keystr.startsWith(underscoreStr)) {
831 838 switch (type) {
832 839 case Anything:
833 840 results << keystr;
834 841 break;
835 842 case Class:
836 843 if (value->ob_type == &PyClass_Type) {
837 844 results << keystr;
838 845 }
839 846 break;
840 847 case Variable:
841 848 if (value->ob_type != &PyClass_Type
842 849 && value->ob_type != &PyCFunction_Type
843 850 && value->ob_type != &PyFunction_Type
844 851 && value->ob_type != &PyModule_Type
845 852 ) {
846 853 results << keystr;
847 854 }
848 855 break;
849 856 case Function:
850 857 if (value->ob_type == &PyFunction_Type ||
851 858 value->ob_type == &PyMethod_Type
852 859 ) {
853 860 results << keystr;
854 861 }
855 862 break;
856 863 case Module:
857 864 if (value->ob_type == &PyModule_Type) {
858 865 results << keystr;
859 866 }
860 867 break;
861 868 default:
862 869 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
863 870 }
864 871 }
865 872 Py_DECREF(value);
866 873 }
867 874 Py_DECREF(keys);
868 875 }
869 876 }
870 877 }
871 878 return results;
872 879 }
873 880
874 881 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
875 882 {
876 883 PythonQtObjectPtr callable = lookupCallable(object, name);
877 884 if (callable) {
878 885 return call(callable, args);
879 886 } else {
880 887 return QVariant();
881 888 }
882 889 }
883 890
884 891 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
885 892 {
886 893 QVariant r;
887 894 PythonQtObjectPtr result;
888 895 result.setNewRef(callAndReturnPyObject(callable, args));
889 896 if (result) {
890 897 r = PythonQtConv::PyObjToQVariant(result);
891 898 } else {
892 899 PythonQt::self()->handleError();
893 900 }
894 901 return r;
895 902 }
896 903
897 904 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args)
898 905 {
899 906 PyObject* result = NULL;
900 907 if (callable) {
901 908 PythonQtObjectPtr pargs;
902 909 int count = args.size();
903 910 if (count>0) {
904 911 pargs.setNewRef(PyTuple_New(count));
905 912 }
906 913 bool err = false;
907 914 // transform QVariants to Python
908 915 for (int i = 0; i < count; i++) {
909 916 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
910 917 if (arg) {
911 918 // steals reference, no unref
912 919 PyTuple_SetItem(pargs, i,arg);
913 920 } else {
914 921 err = true;
915 922 break;
916 923 }
917 924 }
918 925
919 926 if (!err) {
920 927 PyErr_Clear();
921 928 result = PyObject_CallObject(callable, pargs);
922 929 }
923 930 }
924 931 return result;
925 932 }
926 933
927 934 void PythonQt::addInstanceDecorators(QObject* o)
928 935 {
929 936 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
930 937 }
931 938
932 939 void PythonQt::addClassDecorators(QObject* o)
933 940 {
934 941 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
935 942 }
936 943
937 944 void PythonQt::addDecorators(QObject* o)
938 945 {
939 946 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
940 947 }
941 948
942 949 void PythonQt::registerQObjectClassNames(const QStringList& names)
943 950 {
944 951 _p->registerQObjectClassNames(names);
945 952 }
946 953
947 954 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
948 955 {
949 956 _p->_importInterface = importInterface;
950 957 PythonQtImport::init();
951 958 }
952 959
953 960 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
954 961 {
955 962 _p->_importIgnorePaths = paths;
956 963 }
957 964
958 965 const QStringList& PythonQt::getImporterIgnorePaths()
959 966 {
960 967 return _p->_importIgnorePaths;
961 968 }
962 969
963 970 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
964 971 {
965 972 _p->_cppWrapperFactories.append(factory);
966 973 }
967 974
975 void PythonQt::addWrapperFactory( PythonQtForeignWrapperFactory* factory )
976 {
977 _p->_foreignWrapperFactories.append(factory);
978 }
979
968 980 //---------------------------------------------------------------------------------------------------
969 981 PythonQtPrivate::PythonQtPrivate()
970 982 {
971 983 _importInterface = NULL;
972 984 _defaultImporter = new PythonQtQFileImporter;
973 985 _noLongerWrappedCB = NULL;
974 986 _wrappedCB = NULL;
975 987 _currentClassInfoForClassWrapperCreation = NULL;
976 988 _profilingCB = NULL;
977 989 }
978 990
979 991 void PythonQtPrivate::setupSharedLibrarySuffixes()
980 992 {
981 993 _sharedLibrarySuffixes.clear();
982 994 PythonQtObjectPtr imp;
983 995 imp.setNewRef(PyImport_ImportModule("imp"));
984 996 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
985 997 QVariant result = imp.call("get_suffixes");
986 998 #ifdef __linux
987 999 #ifdef _DEBUG
988 1000 // First look for shared libraries with the '_d' suffix in debug mode on Linux.
989 1001 // This is a workaround, because python does not append the '_d' suffix on Linux
990 1002 // and would always load the release library otherwise.
991 1003 _sharedLibrarySuffixes << "_d.so";
992 1004 #endif
993 1005 #endif
994 1006 foreach (QVariant entry, result.toList()) {
995 1007 QVariantList suffixEntry = entry.toList();
996 1008 if (suffixEntry.count()==3) {
997 1009 int code = suffixEntry.at(2).toInt();
998 1010 if (code == cExtensionCode) {
999 1011 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
1000 1012 }
1001 1013 }
1002 1014 }
1003 1015 }
1004 1016
1005 1017 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
1006 1018 {
1007 1019 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
1008 1020 _currentClassInfoForClassWrapperCreation = NULL;
1009 1021 return info;
1010 1022 }
1011 1023
1012 1024 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
1013 1025 {
1014 1026 o->setParent(this);
1015 1027 int numMethods = o->metaObject()->methodCount();
1016 1028 for (int i = 0; i < numMethods; i++) {
1017 1029 QMetaMethod m = o->metaObject()->method(i);
1018 1030 if ((m.methodType() == QMetaMethod::Method ||
1019 1031 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
1020 1032 if (qstrncmp(m.signature(), "new_", 4)==0) {
1021 1033 if ((decoTypes & ConstructorDecorator) == 0) continue;
1022 1034 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1023 1035 if (info->parameters().at(0).pointerCount == 1) {
1024 1036 QByteArray signature = m.signature();
1025 1037 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
1026 1038 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1027 1039 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1028 1040 classInfo->addConstructor(newSlot);
1029 1041 }
1030 1042 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
1031 1043 if ((decoTypes & DestructorDecorator) == 0) continue;
1032 1044 QByteArray signature = m.signature();
1033 1045 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
1034 1046 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1035 1047 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1036 1048 classInfo->setDestructor(newSlot);
1037 1049 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
1038 1050 if ((decoTypes & StaticDecorator) == 0) continue;
1039 1051 QByteArray signature = m.signature();
1040 1052 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
1041 1053 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
1042 1054 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1043 1055 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1044 1056 classInfo->addDecoratorSlot(newSlot);
1045 1057 } else {
1046 1058 if ((decoTypes & InstanceDecorator) == 0) continue;
1047 1059 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1048 1060 if (info->parameters().count()>1) {
1049 1061 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
1050 1062 if (p.pointerCount==1) {
1051 1063 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
1052 1064 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
1053 1065 classInfo->addDecoratorSlot(newSlot);
1054 1066 }
1055 1067 }
1056 1068 }
1057 1069 }
1058 1070 }
1059 1071 }
1060 1072
1061 1073 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
1062 1074 {
1063 1075 foreach(QString name, names) {
1064 1076 _knownQObjectClassNames.insert(name.toLatin1(), true);
1065 1077 }
1066 1078 }
1067 1079
1068 1080 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
1069 1081 {
1070 1082 _signalReceivers.remove(obj);
1071 1083 }
1072 1084
1073 1085 bool PythonQt::handleError()
1074 1086 {
1075 1087 bool flag = false;
1076 1088 if (PyErr_Occurred()) {
1077 1089
1078 1090 // currently we just print the error and the stderr handler parses the errors
1079 1091 PyErr_Print();
1080 1092
1081 1093 /*
1082 1094 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1083 1095 PyObject *ptype;
1084 1096 PyObject *pvalue;
1085 1097 PyObject *ptraceback;
1086 1098 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1087 1099
1088 1100 Py_XDECREF(ptype);
1089 1101 Py_XDECREF(pvalue);
1090 1102 Py_XDECREF(ptraceback);
1091 1103 */
1092 1104 PyErr_Clear();
1093 1105 flag = true;
1094 1106 }
1095 1107 return flag;
1096 1108 }
1097 1109
1098 1110 void PythonQt::addSysPath(const QString& path)
1099 1111 {
1100 1112 PythonQtObjectPtr sys;
1101 1113 sys.setNewRef(PyImport_ImportModule("sys"));
1102 1114 PythonQtObjectPtr obj = lookupObject(sys, "path");
1103 1115 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1104 1116 }
1105 1117
1106 1118 void PythonQt::overwriteSysPath(const QStringList& paths)
1107 1119 {
1108 1120 PythonQtObjectPtr sys;
1109 1121 sys.setNewRef(PyImport_ImportModule("sys"));
1110 1122 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1111 1123 }
1112 1124
1113 1125 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1114 1126 {
1115 1127 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1116 1128 }
1117 1129
1118 1130 void PythonQt::stdOutRedirectCB(const QString& str)
1119 1131 {
1120 1132 if (!PythonQt::self()) {
1121 1133 std::cout << str.toLatin1().data() << std::endl;
1122 1134 return;
1123 1135 }
1124 1136 emit PythonQt::self()->pythonStdOut(str);
1125 1137 }
1126 1138
1127 1139 void PythonQt::stdErrRedirectCB(const QString& str)
1128 1140 {
1129 1141 if (!PythonQt::self()) {
1130 1142 std::cerr << str.toLatin1().data() << std::endl;
1131 1143 return;
1132 1144 }
1133 1145 emit PythonQt::self()->pythonStdErr(str);
1134 1146 }
1135 1147
1136 1148 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1137 1149 {
1138 1150 _p->_wrappedCB = cb;
1139 1151 }
1140 1152
1141 1153 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1142 1154 {
1143 1155 _p->_noLongerWrappedCB = cb;
1144 1156 }
1145 1157
1146 1158 void PythonQt::setProfilingCallback(ProfilingCB* cb)
1147 1159 {
1148 1160 _p->_profilingCB = cb;
1149 1161 }
1150 1162
1151 1163
1152 1164 static PyMethodDef PythonQtMethods[] = {
1153 1165 {NULL, NULL, 0, NULL}
1154 1166 };
1155 1167
1156 1168 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1157 1169 {
1158 1170 QByteArray name = "PythonQt";
1159 1171 if (!pythonQtModuleName.isEmpty()) {
1160 1172 name = pythonQtModuleName;
1161 1173 }
1162 1174 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1163 1175 _p->_pythonQtModuleName = name;
1164 1176
1165 1177 if (redirectStdOut) {
1166 1178 PythonQtObjectPtr sys;
1167 1179 PythonQtObjectPtr out;
1168 1180 PythonQtObjectPtr err;
1169 1181 sys.setNewRef(PyImport_ImportModule("sys"));
1170 1182 // create a redirection object for stdout and stderr
1171 1183 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1172 1184 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1173 1185 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1174 1186 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1175 1187 // replace the built in file objects with our own objects
1176 1188 PyModule_AddObject(sys, "stdout", out);
1177 1189 PyModule_AddObject(sys, "stderr", err);
1178 1190 }
1179 1191 }
1180 1192
1181 1193 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1182 1194 {
1183 1195 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1184 1196 }
1185 1197
1186 1198
1187 1199 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1188 1200 {
1189 1201 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1190 1202 if (!info) {
1191 1203 info = new PythonQtClassInfo();
1192 1204 info->setupCPPObject(typeName);
1193 1205 _knownClassInfos.insert(typeName, info);
1194 1206 }
1195 1207 return info;
1196 1208 }
1197 1209
1198 1210 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1199 1211 {
1200 1212 _p->addPolymorphicHandler(typeName, cb);
1201 1213 }
1202 1214
1203 1215 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1204 1216 {
1205 1217 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1206 1218 info->addPolymorphicHandler(cb);
1207 1219 }
1208 1220
1209 1221 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1210 1222 {
1211 1223 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1212 1224 }
1213 1225
1214 1226 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1215 1227 {
1216 1228 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1217 1229 if (info) {
1218 1230 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1219 1231 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1220 1232 return true;
1221 1233 } else {
1222 1234 return false;
1223 1235 }
1224 1236 }
1225 1237
1226 1238 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1227 1239 {
1228 1240 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1229 1241 if (!info->pythonQtClassWrapper()) {
1230 1242 info->setTypeSlots(typeSlots);
1231 1243 info->setupCPPObject(typeName);
1232 1244 createPythonQtClassWrapper(info, package, module);
1233 1245 }
1234 1246 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1235 1247 addParentClass(typeName, parentTypeName, 0);
1236 1248 }
1237 1249 if (wrapperCreator) {
1238 1250 info->setDecoratorProvider(wrapperCreator);
1239 1251 }
1240 1252 if (shell) {
1241 1253 info->setShellSetInstanceWrapperCB(shell);
1242 1254 }
1243 1255 }
1244 1256
1245 1257 PyObject* PythonQtPrivate::packageByName(const char* name)
1246 1258 {
1247 1259 if (name==NULL || name[0]==0) {
1248 1260 name = "private";
1249 1261 }
1250 1262 PyObject* v = _packages.value(name);
1251 1263 if (!v) {
1252 1264 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1253 1265 _packages.insert(name, v);
1254 1266 // AddObject steals the reference, so increment it!
1255 1267 Py_INCREF(v);
1256 1268 PyModule_AddObject(_pythonQtModule, name, v);
1257 1269 }
1258 1270 return v;
1259 1271 }
1260 1272
1261 1273 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1262 1274 {
1263 1275 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;
1264 1276 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1265 1277 PythonQt::self()->handleError();
1266 1278 }
1267 1279
1268 1280 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1269 1281 {
1270 1282 if (_p->_initFlags & ExternalHelp) {
1271 1283 emit pythonHelpRequest(QByteArray(info->className()));
1272 1284 return Py_BuildValue("");
1273 1285 } else {
1274 1286 return PyString_FromString(info->help().toLatin1().data());
1275 1287 }
1276 1288 }
1277 1289
1278 1290 void PythonQt::clearNotFoundCachedMembers()
1279 1291 {
1280 1292 foreach(PythonQtClassInfo* info, _p->_knownClassInfos) {
1281 1293 info->clearNotFoundCachedMembers();
1282 1294 }
1283 1295 }
1284 1296
1285 1297 void PythonQtPrivate::removeWrapperPointer(void* obj)
1286 1298 {
1287 1299 _wrappedObjects.remove(obj);
1288 1300 }
1289 1301
1290 1302 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1291 1303 {
1292 1304 _wrappedObjects.insert(obj, wrapper);
1293 1305 }
1294 1306
1295 1307 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1296 1308 {
1297 1309 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1298 1310 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1299 1311 // this is a wrapper whose QObject was already removed due to destruction
1300 1312 // so the obj pointer has to be a new QObject with the same address...
1301 1313 // we remove the old one and set the copy to NULL
1302 1314 wrap->_objPointerCopy = NULL;
1303 1315 removeWrapperPointer(obj);
1304 1316 wrap = NULL;
1305 1317 }
1306 1318 return wrap;
1307 1319 }
1308 1320
1309 1321 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1310 1322 {
1311 1323 PythonQtObjectPtr result;
1312 1324 if (pycode) {
1313 1325 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1314 1326 } else {
1315 1327 PythonQt::self()->handleError();
1316 1328 }
1317 1329 return result;
1318 1330 }
1331
1332 void* PythonQtPrivate::unwrapForeignWrapper( const QByteArray& classname, PyObject* obj )
1333 {
1334 void* foreignObject = NULL;
1335 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
1336 foreignObject = _foreignWrapperFactories.at(i)->unwrap(classname, obj);
1337 if (foreignObject) {
1338 return foreignObject;
1339 }
1340 }
1341 return NULL;
1342 } No newline at end of file
@@ -1,675 +1,684
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 class PythonQtForeignWrapperFactory;
67 68 class PythonQtQFileImporter;
68 69
69 70 typedef void PythonQtQObjectWrappedCB(QObject* object);
70 71 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
71 72 typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, const char **class_name);
72 73
73 74 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
74 75
75 76 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) {
76 77 (reinterpret_cast<T*>(object))->_wrapper = wrapper;
77 78 }
78 79
79 80 //! returns the offset that needs to be added to upcast an object of type T1 to T2
80 81 template<class T1, class T2> int PythonQtUpcastingOffset() {
81 82 return ((reinterpret_cast<char*>(static_cast<T2*>(reinterpret_cast<T1*>(0x100))))
82 83 - (reinterpret_cast<char*>(reinterpret_cast<T1*>(0x100))));
83 84 }
84 85
85 86 //! callback to create a QObject lazily
86 87 typedef QObject* PythonQtQObjectCreatorFunctionCB();
87 88
88 89 //! helper template to create a derived QObject class
89 90 template<class T> QObject* PythonQtCreateObject() { return new T(); };
90 91
91 92 //! The main interface to the Python Qt binding, realized as a singleton
92 93 /*!
93 94 Use PythonQt::init() to initialize the singleton and PythonQt::self() to access it.
94 95 While there can be only one PythonQt instance, you can have any number of Python context to do scripting in.
95 96 One possibility is to use createModuleFromFile(), createModuleFromScript() or createUniqueModule() to get a context
96 97 that is separated from the other contexts. Alternatively you can use Python dicts as contexts for script evaluation,
97 98 but you will need to populate the dict with the __builtins__ instance to have all Pythons available when running
98 99 code in the scope of a dict.
99 100 */
100 101 class PYTHONQT_EXPORT PythonQt : public QObject {
101 102
102 103 Q_OBJECT
103 104
104 105 public:
105 106
106 107 //! flags that can be passed to PythonQt::init()
107 108 enum InitFlags {
108 109 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
109 110 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
110 111 ExternalHelp = 4, //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
111 112 PythonAlreadyInitialized = 8 //!<< sets that PythonQt should not can PyInitialize, since it is already done
112 113 };
113 114
114 115 //! flags that tell PythonQt which operators to expect on the registered type
115 116 enum TypeSlots {
116 117 Type_Add = 1,
117 118 Type_Subtract = 1 << 1,
118 119 Type_Multiply = 1 << 2,
119 120 Type_Divide = 1 << 3,
120 121 Type_Mod = 1 << 4,
121 122 Type_And = 1 << 5,
122 123 Type_Or = 1 << 6,
123 124 Type_Xor = 1 << 7,
124 125 Type_LShift = 1 << 8,
125 126 Type_RShift = 1 << 9,
126 127
127 128 Type_InplaceAdd = 1 << 10,
128 129 Type_InplaceSubtract = 1 << 11,
129 130 Type_InplaceMultiply = 1 << 12,
130 131 Type_InplaceDivide = 1 << 13,
131 132 Type_InplaceMod = 1 << 14,
132 133 Type_InplaceAnd = 1 << 15,
133 134 Type_InplaceOr = 1 << 16,
134 135 Type_InplaceXor = 1 << 17,
135 136 Type_InplaceLShift = 1 << 18,
136 137 Type_InplaceRShift = 1 << 19,
137 138
138 139 // Not yet needed/nicely mappable/generated...
139 140 //Type_Positive = 1 << 29,
140 141 //Type_Negative = 1 << 29,
141 142 //Type_Abs = 1 << 29,
142 143 //Type_Hash = 1 << 29,
143 144
144 145 Type_Invert = 1 << 29,
145 146 Type_RichCompare = 1 << 30,
146 147 Type_NonZero = 1 << 31,
147 148
148 149 };
149 150
150 151 //! enum for profiling callback
151 152 enum ProfilingCallbackState {
152 153 Enter = 1,
153 154 Leave = 2
154 155 };
155 156
156 157 //! callback for profiling. className and methodName are only passed when state == Enter, otherwise
157 158 //! they are NULL.
158 159 typedef void ProfilingCB(ProfilingCallbackState state, const char* className, const char* methodName);
159 160
160 161 //---------------------------------------------------------------------------
161 162 //! \name Singleton Initialization
162 163 //@{
163 164
164 165 //! initialize the python qt binding (flags are a or combination of PythonQt::InitFlags), if \c pythonQtModuleName is given
165 166 //! it defines the name of the python module that PythonQt will add, otherwise "PythonQt" is used.
166 167 //! This can be used to e.g. pass in PySide or PyQt4 to make it more compatible.
167 168 static void init(int flags = IgnoreSiteModule | RedirectStdOut, const QByteArray& pythonQtModuleName = QByteArray());
168 169
169 170 //! cleanup of the singleton
170 171 static void cleanup();
171 172
172 173 //! get the singleton instance
173 174 static PythonQt* self();
174 175
175 176 //@}
176 177
177 178 //! defines the object types for introspection
178 179 enum ObjectType {
179 180 Class,
180 181 Function,
181 182 Variable,
182 183 Module,
183 184 Anything,
184 185 CallOverloads
185 186 };
186 187
187 188
188 189 //---------------------------------------------------------------------------
189 190 //! \name Standard input handling
190 191 //@{
191 192
192 193 //! Overwrite default handling of stdin using a custom callback. It internally backup
193 194 //! the original 'sys.stdin' into 'sys.pythonqt_original_stdin'
194 195 void setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData = 0);
195 196
196 197 //! Enable or disable stdin custom callback. It resets 'sys.stdin' using either 'sys.pythonqt_stdin'
197 198 //! or 'sys.pythonqt_original_stdin'
198 199 void setRedirectStdInCallbackEnabled(bool enabled);
199 200
200 201 //@}
201 202
202 203 //---------------------------------------------------------------------------
203 204 //! \name Modules
204 205 //@{
205 206
206 207 //! get the __main__ module of python
207 208 PythonQtObjectPtr getMainModule();
208 209
209 210 //! import the given module and return a reference to it (useful to import e.g. "sys" and call something on it)
210 211 //! If a module is already imported, this returns the already imported module.
211 212 PythonQtObjectPtr importModule(const QString& name);
212 213
213 214 //! creates the new module \c name and evaluates the given file in the context of that module
214 215 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
215 216 //! to a module later on.
216 217 //! The user needs to make sure that the \c name is unique in the python module dictionary.
217 218 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
218 219
219 220 //! creates the new module \c name and evaluates the given script in the context of that module.
220 221 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
221 222 //! to a module later on.
222 223 //! The user needs to make sure that the \c name is unique in the python module dictionary.
223 224 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
224 225
225 226 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
226 227 //! script code
227 228 PythonQtObjectPtr createUniqueModule();
228 229
229 230 //@}
230 231
231 232 //---------------------------------------------------------------------------
232 233 //! \name Importing/Paths
233 234 //@{
234 235
235 236 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
236 237 void overwriteSysPath(const QStringList& paths);
237 238
238 239 //! prepend a path to sys.path to allow importing from it
239 240 void addSysPath(const QString& path);
240 241
241 242 //! sets the __path__ list of a module to the given list (important for local imports)
242 243 void setModuleImportPath(PyObject* module, const QStringList& paths);
243 244
244 245 //@}
245 246
246 247 //---------------------------------------------------------------------------
247 248 //! \name Registering Classes
248 249 //@{
249 250
250 251 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
251 252 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
252 253 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
253 254 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
254 255
255 256 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
256 257 //! (ownership of wrapper is passed to PythonQt)
257 258 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
258 259
259 260 This will add a wrapper object that is used to make calls to the given classname \c typeName.
260 261 All slots that take a pointer to typeName as the first argument will be callable from Python on
261 262 a variant object that contains such a type.
262 263 */
263 264 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
264 265
265 266 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
266 267 //! and it will register the classes when it first sees a pointer to such a derived class
267 268 void registerQObjectClassNames(const QStringList& names);
268 269
269 270 //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance
270 271 //! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that
271 272 //! type is really derived from parentType.
272 273 //! Returns false if the typeName was not yet registered.
273 274 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
274 275
275 276 //! add a handler for polymorphic downcasting
276 277 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
277 278
278 279 //@}
279 280
280 281 //---------------------------------------------------------------------------
281 282 //! \name Script Parsing and Evaluation
282 283 //@{
283 284
284 285 //! parses the given file and returns the python code object, this can then be used to call evalCode()
285 286 PythonQtObjectPtr parseFile(const QString& filename);
286 287
287 288 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
288 289 //! If pycode is NULL, a python error is printed.
289 290 QVariant evalCode(PyObject* object, PyObject* pycode);
290 291
291 292 //! evaluates the given script code and returns the result value
292 293 QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input);
293 294
294 295 //! evaluates the given script code from file
295 296 void evalFile(PyObject* object, const QString& filename);
296 297
297 298 //@}
298 299
299 300 //---------------------------------------------------------------------------
300 301 //! \name Signal Handlers
301 302 //@{
302 303
303 304 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
304 305 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
305 306
306 307 //! remove a signal handler from the given \c signal of \c obj
307 308 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
308 309
309 310 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
310 311 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
311 312
312 313 //! remove a signal handler from the given \c signal of \c obj
313 314 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
314 315
315 316 //@}
316 317
317 318 //---------------------------------------------------------------------------
318 319 //! \name Variable access
319 320 //@{
320 321
321 322 //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable)
322 323 void addObject(PyObject* object, const QString& name, QObject* qObject);
323 324
324 325 //! add the given variable to the object
325 326 void addVariable(PyObject* object, const QString& name, const QVariant& v);
326 327
327 328 //! remove the given variable
328 329 void removeVariable(PyObject* module, const QString& name);
329 330
330 331 //! get the variable with the \c name of the \c object, returns an invalid QVariant on error
331 332 QVariant getVariable(PyObject* object, const QString& name);
332 333
333 334 //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname
334 335 QStringList introspection(PyObject* object, const QString& objectname, ObjectType type);
335 336
336 337 //! returns the found callable object or NULL
337 338 //! @return new reference
338 339 PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
339 340
340 341 //@}
341 342
342 343 //---------------------------------------------------------------------------
343 344 //! \name Calling Python Objects
344 345 //@{
345 346
346 347 //! call the given python \c callable in the scope of object, returns the result converted to a QVariant
347 348 QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList());
348 349
349 350 //! call the given python object, returns the result converted to a QVariant
350 351 QVariant call(PyObject* callable, const QVariantList& args = QVariantList());
351 352
352 353 //! call the given python object, returns the result as new PyObject
353 354 PyObject* callAndReturnPyObject(PyObject* callable, const QVariantList& args = QVariantList());
354 355
355 356 //@}
356 357
357 358 //---------------------------------------------------------------------------
358 359 //! \name Decorations, Constructors, Wrappers...
359 360 //@{
360 361
361 362 //! add an object whose slots will be used as decorator slots for
362 363 //! other QObjects or CPP classes. The slots need to follow the
363 364 //! convention that the first argument is a pointer to the wrapped object.
364 365 //! (ownership is passed to PythonQt)
365 366 /*!
366 367 Example:
367 368
368 369 A slot with the signature
369 370
370 371 \code
371 372 bool doSomething(QWidget* w, int a)
372 373 \endcode
373 374
374 375 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
375 376 that will be called with the concrete instance as first argument.
376 377 So in Python you can now e.g. call
377 378
378 379 \code
379 380 someWidget.doSomething(12)
380 381 \endcode
381 382
382 383 without QWidget really having this method. This allows to easily make normal methods
383 384 of Qt classes callable by forwarding them with such decorator slots
384 385 or to make CPP classes (which are not derived from QObject) callable from Python.
385 386 */
386 387 void addInstanceDecorators(QObject* o);
387 388
388 389 //! add an object whose slots will be used as decorator slots for
389 390 //! class objects (ownership is passed to PythonQt)
390 391 /*!
391 392 The slots need to follow the following convention:
392 393 - SomeClass* new_SomeClass(...)
393 394 - QVariant new_SomeClass(...)
394 395 - void delete_SomeClass(SomeClass*)
395 396 - ... static_SomeClass_someName(...)
396 397
397 398 This will add:
398 399 - a constructor
399 400 - a constructor which generates a QVariant
400 401 - a destructor (only useful for CPP objects)
401 402 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
402 403
403 404 */
404 405 void addClassDecorators(QObject* o);
405 406
406 407 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
407 408 void addDecorators(QObject* o);
408 409
409 410 //! add the given factory to PythonQt (ownership stays with caller)
410 411 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
411 412
413 //! add the given factory to PythonQt (ownership stays with caller)
414 void addWrapperFactory(PythonQtForeignWrapperFactory* factory);
415
412 416 //@}
413 417
414 418 //---------------------------------------------------------------------------
415 419 //! \name Custom Importer
416 420 //@{
417 421
418 422 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
419 423 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
420 424 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
421 425 //! This is not reversible, so even setting setImporter(NULL) afterwards will
422 426 //! keep the custom PythonQt importer with a QFile default import interface.
423 427 //! Subsequent python import calls will make use of the passed importInterface
424 428 //! which forwards all import calls to the given \c importInterface.
425 429 //! Passing NULL will install a default QFile importer.
426 430 //! (\c importInterface ownership stays with caller)
427 431 void setImporter(PythonQtImportFileInterface* importInterface);
428 432
429 433 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
430 434 //! (without calling setImporter or installDefaultImporter at least once, the default python import
431 435 //! mechanism is in place)
432 436 //! the default importer allows to import files from anywhere QFile can read from,
433 437 //! including the Qt resource system using ":". Keep in mind that you need to extend
434 438 //! "sys.path" with ":" to be able to import from the Qt resources.
435 439 void installDefaultImporter() { setImporter(NULL); }
436 440
437 441 //! set paths that the importer should ignore
438 442 void setImporterIgnorePaths(const QStringList& paths);
439 443
440 444 //! get paths that the importer should ignore
441 445 const QStringList& getImporterIgnorePaths();
442 446
443 447 //! get access to the file importer (if set)
444 448 static PythonQtImportFileInterface* importInterface();
445 449
446 450 //@}
447 451
448 452 //---------------------------------------------------------------------------
449 453 //! \name Other Stuff
450 454 //@{
451 455
452 456 //! get access to internal data (should not be used on the public API, but is used by some C functions)
453 457 static PythonQtPrivate* priv() { return _self->_p; }
454 458
455 459 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
456 460 //! The error is currently just output to the python stderr, future version might implement better trace printing
457 461 bool handleError();
458 462
459 463 //! clear all NotFound entries on all class infos, to ensure that
460 464 //! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded
461 465 void clearNotFoundCachedMembers();
462 466
463 467 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
464 468 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
465 469 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
466 470 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
467 471
468 472 //! call the callback if it is set
469 473 static void qObjectNoLongerWrappedCB(QObject* o);
470 474
471 475 //! called by internal help methods
472 476 PyObject* helpCalled(PythonQtClassInfo* info);
473 477
474 478 //! returns the found object or NULL
475 479 //! @return new reference
476 480 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
477 481
478 482 //! sets a callback that is called before and after function calls for profiling
479 483 void setProfilingCallback(ProfilingCB* cb);
480 484
481 485 //@}
482 486
483 487 signals:
484 488 //! emitted when python outputs something to stdout (and redirection is turned on)
485 489 void pythonStdOut(const QString& str);
486 490 //! emitted when python outputs something to stderr (and redirection is turned on)
487 491 void pythonStdErr(const QString& str);
488 492
489 493 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
490 494 void pythonHelpRequest(const QByteArray& cppClassName);
491 495
492 496 private:
493 497 void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName);
494 498
495 499 //! callback for stdout redirection, emits pythonStdOut signal
496 500 static void stdOutRedirectCB(const QString& str);
497 501 //! callback for stderr redirection, emits pythonStdErr signal
498 502 static void stdErrRedirectCB(const QString& str);
499 503
500 504 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
501 505 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
502 506
503 507 PythonQt(int flags, const QByteArray& pythonQtModuleName);
504 508 ~PythonQt();
505 509
506 510 static PythonQt* _self;
507 511 static int _uniqueModuleCount;
508 512
509 513 PythonQtPrivate* _p;
510 514
511 515 };
512 516
513 517 //! internal PythonQt details
514 518 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
515 519
516 520 Q_OBJECT
517 521
518 522 public:
519 523 PythonQtPrivate();
520 524 ~PythonQtPrivate();
521 525
522 526 enum DecoratorTypes {
523 527 StaticDecorator = 1,
524 528 ConstructorDecorator = 2,
525 529 DestructorDecorator = 4,
526 530 InstanceDecorator = 8,
527 531 AllDecorators = 0xffff
528 532 };
529 533
530 534 //! get the suffixes that are used for shared libraries
531 535 const QStringList& sharedLibrarySuffixes() { return _sharedLibrarySuffixes; }
532 536
533 537 //! returns if the id is the id for PythonQtObjectPtr
534 538 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
535 539
536 540 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
537 541 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
538 542 //! remove the wrapper ptr again
539 543 void removeWrapperPointer(void* obj);
540 544
545 //! try to unwrap the given object to a C++ pointer using the foreign wrapper factories
546 void* unwrapForeignWrapper(const QByteArray& classname, PyObject* obj);
547
541 548 //! add parent class relation
542 549 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
543 550
544 551 //! add a handler for polymorphic downcasting
545 552 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
546 553
547 554 //! lookup existing classinfo and return new if not yet present
548 555 PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
549 556
550 557 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
551 558 void removeSignalEmitter(QObject* obj);
552 559
553 560 //! wrap the given QObject into a Python object (or return existing wrapper!)
554 561 PyObject* wrapQObject(QObject* obj);
555 562
556 563 //! 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
557 564 PyObject* wrapPtr(void* ptr, const QByteArray& name);
558 565
559 566 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
560 567 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
561 568 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
562 569 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
563 570
564 571 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
565 572 //! (ownership of wrapper is passed to PythonQt)
566 573 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
567 574
568 575 This will add a wrapper object that is used to make calls to the given classname \c typeName.
569 576 All slots that take a pointer to typeName as the first argument will be callable from Python on
570 577 a variant object that contains such a type.
571 578 */
572 579 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);
573 580
574 581 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
575 582 //! and it will register the classes when it first sees a pointer to such a derived class
576 583 void registerQObjectClassNames(const QStringList& names);
577 584
578 585 //! add a decorator object
579 586 void addDecorators(QObject* o, int decoTypes);
580 587
581 588 //! helper method that creates a PythonQtClassWrapper object (returns a new reference)
582 589 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* module);
583 590
584 591 //! create a new instance of the given enum type with given value (returns a new reference)
585 592 static PyObject* createEnumValueInstance(PyObject* enumType, unsigned int enumValue);
586 593
587 594 //! helper that creates a new int derived class that represents the enum of the given name (returns a new reference)
588 595 static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
589 596
590 597 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
591 598 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
592 599
593 600 //! get the class info for a meta object (if available)
594 601 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
595 602
596 603 //! get the class info for a meta object (if available)
597 604 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
598 605
599 606 //! creates the new module from the given pycode
600 607 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
601 608
602 609 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
603 610 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
604 611
605 612 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
606 613 static PyObject* dummyTuple();
607 614
608 615 //! called by virtual overloads when a python return value can not be converted to the required Qt type
609 616 void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result);
610 617
611 618 //! get access to the PythonQt module
612 619 PythonQtObjectPtr pythonQtModule() const { return _pythonQtModule; }
613 620
614 621 //! returns the profiling callback, which may be NULL
615 622 PythonQt::ProfilingCB* profilingCB() const { return _profilingCB; }
616 623
617 624 private:
618 625 //! Setup the shared library suffixes by getting them from the "imp" module.
619 626 void setupSharedLibrarySuffixes();
620 627
621 628 //! create a new pythonqt class wrapper and place it in the pythonqt module
622 629 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module = NULL);
623 630
624 631 //! get/create new package module (the returned object is a borrowed reference)
625 632 PyObject* packageByName(const char* name);
626 633
627 634 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
628 635 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
629 636
630 637 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
631 638 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
632 639
633 640 //! stores the meta info of known Qt classes
634 641 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
635 642
636 643 //! names of qobject derived classes that can be casted to qobject savely
637 644 QHash<QByteArray, bool> _knownQObjectClassNames;
638 645
639 646 //! stores signal receivers for QObjects
640 647 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
641 648
642 649 //! the PythonQt python module
643 650 PythonQtObjectPtr _pythonQtModule;
644 651
645 652 //! the name of the PythonQt python module
646 653 QByteArray _pythonQtModuleName;
647 654
648 655 //! the importer interface (if set)
649 656 PythonQtImportFileInterface* _importInterface;
650 657
651 658 //! the default importer
652 659 PythonQtQFileImporter* _defaultImporter;
653 660
654 661 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
655 662 PythonQtQObjectWrappedCB* _wrappedCB;
656 663
657 664 QStringList _importIgnorePaths;
658 665 QStringList _sharedLibrarySuffixes;
659 666
660 667 //! the cpp object wrapper factories
661 668 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
662 669
670 QList<PythonQtForeignWrapperFactory*> _foreignWrapperFactories;
671
663 672 QHash<QByteArray, PyObject*> _packages;
664 673
665 674 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
666 675
667 676 PythonQt::ProfilingCB* _profilingCB;
668 677
669 678 int _initFlags;
670 679 int _PythonQtObjectPtr_metaId;
671 680
672 681 friend class PythonQt;
673 682 };
674 683
675 684 #endif
@@ -1,1229 +1,1232
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 380 QString str = PyObjGetString(obj, strict, ok);
381 381 if (ok) {
382 382 void* ptr2 = NULL;
383 383 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str.toUtf8()), ptr2);
384 384 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr);
385 385 }
386 386 } else if (info.name == "PyObject") {
387 387 // handle low level PyObject directly
388 388 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, obj, ptr);
389 }
390 // TODO XXX: pass obj and name and add when it returns a pointer
391 else if (obj == Py_None) {
389 } else if (obj == Py_None) {
392 390 // None is treated as a NULL ptr
393 391 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
394 392 } else {
395 // if we are not strict, we try if we are passed a 0 integer
396 if (!strict) {
397 bool ok;
398 int value = PyObjGetInt(obj, true, ok);
399 if (ok && value==0) {
400 // TODOXXX is this wise? or should it be expected from the programmer to use None?
401 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
393 void* foreignWrapper = PythonQt::priv()->unwrapForeignWrapper(info.name, obj);
394 if (foreignWrapper) {
395 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, foreignWrapper, ptr);
396 } else {
397 // if we are not strict, we try if we are passed a 0 integer
398 if (!strict) {
399 bool ok;
400 int value = PyObjGetInt(obj, true, ok);
401 if (ok && value==0) {
402 // TODOXXX is this wise? or should it be expected from the programmer to use None?
403 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
404 }
402 405 }
403 406 }
404 407 }
405 408 } else if (info.pointerCount == 0) {
406 409 // not a pointer
407 410 switch (info.typeId) {
408 411 case QMetaType::Char:
409 412 {
410 413 int val = PyObjGetInt(obj, strict, ok);
411 414 if (ok) {
412 415 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, char, val, ptr);
413 416 }
414 417 }
415 418 break;
416 419 case QMetaType::UChar:
417 420 {
418 421 int val = PyObjGetInt(obj, strict, ok);
419 422 if (ok) {
420 423 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned char, val, ptr);
421 424 }
422 425 }
423 426 break;
424 427 case QMetaType::Short:
425 428 {
426 429 int val = PyObjGetInt(obj, strict, ok);
427 430 if (ok) {
428 431 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
429 432 }
430 433 }
431 434 break;
432 435 case QMetaType::UShort:
433 436 {
434 437 int val = PyObjGetInt(obj, strict, ok);
435 438 if (ok) {
436 439 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned short, val, ptr);
437 440 }
438 441 }
439 442 break;
440 443 case QMetaType::Long:
441 444 {
442 445 long val = (long)PyObjGetLongLong(obj, strict, ok);
443 446 if (ok) {
444 447 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, long, val, ptr);
445 448 }
446 449 }
447 450 break;
448 451 case QMetaType::ULong:
449 452 {
450 453 unsigned long val = (unsigned long)PyObjGetLongLong(obj, strict, ok);
451 454 if (ok) {
452 455 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned long, val, ptr);
453 456 }
454 457 }
455 458 break;
456 459 case QMetaType::Bool:
457 460 {
458 461 bool val = PyObjGetBool(obj, strict, ok);
459 462 if (ok) {
460 463 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, bool, val, ptr);
461 464 }
462 465 }
463 466 break;
464 467 case QMetaType::Int:
465 468 {
466 469 int val = PyObjGetInt(obj, strict, ok);
467 470 if (ok) {
468 471 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, int, val, ptr);
469 472 }
470 473 }
471 474 break;
472 475 case QMetaType::UInt:
473 476 {
474 477 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
475 478 if (ok) {
476 479 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
477 480 }
478 481 }
479 482 break;
480 483 case QMetaType::QChar:
481 484 {
482 485 int val = PyObjGetInt(obj, strict, ok);
483 486 if (ok) {
484 487 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
485 488 }
486 489 }
487 490 break;
488 491 case QMetaType::Float:
489 492 {
490 493 float val = (float)PyObjGetDouble(obj, strict, ok);
491 494 if (ok) {
492 495 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, float, val, ptr);
493 496 }
494 497 }
495 498 break;
496 499 case QMetaType::Double:
497 500 {
498 501 double val = (double)PyObjGetDouble(obj, strict, ok);
499 502 if (ok) {
500 503 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, double, val, ptr);
501 504 }
502 505 }
503 506 break;
504 507 case QMetaType::LongLong:
505 508 {
506 509 qint64 val = PyObjGetLongLong(obj, strict, ok);
507 510 if (ok) {
508 511 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, qint64, val, ptr);
509 512 }
510 513 }
511 514 break;
512 515 case QMetaType::ULongLong:
513 516 {
514 517 quint64 val = PyObjGetULongLong(obj, strict, ok);
515 518 if (ok) {
516 519 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, quint64, val, ptr);
517 520 }
518 521 }
519 522 break;
520 523 case QMetaType::QByteArray:
521 524 {
522 525 QByteArray bytes = PyObjGetBytes(obj, strict, ok);
523 526 if (ok) {
524 527 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(bytes), ptr);
525 528 ptr = (void*)((QVariant*)ptr)->constData();
526 529 }
527 530 }
528 531 break;
529 532 case QMetaType::QString:
530 533 {
531 534 QString str = PyObjGetString(obj, strict, ok);
532 535 if (ok) {
533 536 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str), ptr);
534 537 ptr = (void*)((QVariant*)ptr)->constData();
535 538 }
536 539 }
537 540 break;
538 541 case QMetaType::QStringList:
539 542 {
540 543 QStringList l = PyObjToStringList(obj, strict, ok);
541 544 if (ok) {
542 545 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(l), ptr);
543 546 ptr = (void*)((QVariant*)ptr)->constData();
544 547 }
545 548 }
546 549 break;
547 550
548 551 case PythonQtMethodInfo::Variant:
549 552 {
550 553 QVariant v = PyObjToQVariant(obj);
551 554 // the only case where conversion can fail it None and we want to pass that to, e.g. setProperty(),
552 555 // so we do not check v.isValid() here
553 556 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
554 557 }
555 558 break;
556 559 default:
557 560 {
558 561 // check for enum case
559 562 if (info.enumWrapper) {
560 563 unsigned int val;
561 564 ok = false;
562 565 if ((PyObject*)obj->ob_type == info.enumWrapper) {
563 566 // we have a exact enum type match:
564 567 val = PyInt_AS_LONG(obj);
565 568 ok = true;
566 569 } else if (!strict) {
567 570 // we try to get any integer, when not being strict. If we are strict, integers are not wanted because
568 571 // we want an integer overload to be taken first!
569 572 val = (unsigned int)PyObjGetLongLong(obj, false, ok);
570 573 }
571 574 if (ok) {
572 575 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
573 576 return ptr;
574 577 } else {
575 578 return NULL;
576 579 }
577 580 }
578 581
579 582 if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
580 583 // check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant
581 584 if (info.name.startsWith("QList<")) {
582 585 QByteArray innerType = info.name.mid(6,info.name.length()-7);
583 586 if (innerType.endsWith("*")) {
584 587 innerType.truncate(innerType.length()-1);
585 588 static int id = QMetaType::type("QList<void*>");
586 589 if (!alreadyAllocatedCPPObject) {
587 590 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(id), ptr);
588 591 ptr = (void*)((QVariant*)ptr)->constData();
589 592 } else {
590 593 ptr = alreadyAllocatedCPPObject;
591 594 }
592 595 ok = ConvertPythonListToQListOfPointerType(obj, (QList<void*>*)ptr, innerType, strict);
593 596 if (ok) {
594 597 return ptr;
595 598 } else {
596 599 return NULL;
597 600 }
598 601 }
599 602 }
600 603 }
601 604
602 605 // We only do this for registered type > QMetaType::User for performance reasons.
603 606 if (info.typeId >= QMetaType::User) {
604 607 // Maybe we have a special converter that is registered for that type:
605 608 PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(info.typeId);
606 609 if (converter) {
607 610 if (!alreadyAllocatedCPPObject) {
608 611 // create a new empty variant of concrete type:
609 612 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
610 613 ptr = (void*)((QVariant*)ptr)->constData();
611 614 } else {
612 615 ptr = alreadyAllocatedCPPObject;
613 616 }
614 617 // now call the converter, passing the internal object of the variant
615 618 ok = (*converter)(obj, ptr, info.typeId, strict);
616 619 if (ok) {
617 620 return ptr;
618 621 } else {
619 622 return NULL;
620 623 }
621 624 }
622 625 }
623 626 // if no type id is available, conversion to a QVariant makes no sense/is not possible
624 627 if (info.typeId != PythonQtMethodInfo::Unknown) {
625 628 // for all other types, we use the same qvariant conversion and pass out the constData of the variant:
626 629 QVariant v = PyObjToQVariant(obj, info.typeId);
627 630 if (v.isValid()) {
628 631 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
629 632 ptr = (void*)((QVariant*)ptr)->constData();
630 633 }
631 634 }
632 635 }
633 636 }
634 637 }
635 638 return ptr;
636 639 }
637 640
638 641
639 642 QStringList PythonQtConv::PyObjToStringList(PyObject* val, bool strict, bool& ok) {
640 643 QStringList v;
641 644 ok = false;
642 645 // if we are strict, we do not want to convert a string to a stringlist
643 646 // (strings in python are detected to be sequences)
644 647 if (strict &&
645 648 (val->ob_type == &PyString_Type ||
646 649 PyUnicode_Check(val))) {
647 650 ok = false;
648 651 return v;
649 652 }
650 653 if (PySequence_Check(val)) {
651 654 int count = PySequence_Size(val);
652 655 for (int i = 0;i<count;i++) {
653 656 PyObject* value = PySequence_GetItem(val,i);
654 657 v.append(PyObjGetString(value,false,ok));
655 658 }
656 659 ok = true;
657 660 }
658 661 return v;
659 662 }
660 663
661 664 QString PythonQtConv::PyObjGetRepresentation(PyObject* val)
662 665 {
663 666 QString r;
664 667 PyObject* str = PyObject_Repr(val);
665 668 if (str) {
666 669 r = QString(PyString_AS_STRING(str));
667 670 Py_DECREF(str);
668 671 }
669 672 return r;
670 673 }
671 674
672 675 QString PythonQtConv::PyObjGetString(PyObject* val, bool strict, bool& ok) {
673 676 QString r;
674 677 ok = true;
675 678 if (val->ob_type == &PyString_Type) {
676 679 r = QString(PyString_AS_STRING(val));
677 680 } else if (PyUnicode_Check(val)) {
678 681 PyObject *ptmp = PyUnicode_AsUTF8String(val);
679 682 if(ptmp) {
680 683 r = QString::fromUtf8(PyString_AS_STRING(ptmp));
681 684 Py_DECREF(ptmp);
682 685 }
683 686 } else if (!strict) {
684 687 // EXTRA: could also use _Unicode, but why should we?
685 688 PyObject* str = PyObject_Str(val);
686 689 if (str) {
687 690 r = QString(PyString_AS_STRING(str));
688 691 Py_DECREF(str);
689 692 } else {
690 693 ok = false;
691 694 }
692 695 } else {
693 696 ok = false;
694 697 }
695 698 return r;
696 699 }
697 700
698 701 QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) {
699 702 // TODO: support buffer objects in general
700 703 QByteArray r;
701 704 ok = true;
702 705 if (val->ob_type == &PyString_Type) {
703 706 long size = PyString_GET_SIZE(val);
704 707 r = QByteArray(PyString_AS_STRING(val), size);
705 708 } else {
706 709 ok = false;
707 710 }
708 711 return r;
709 712 }
710 713
711 714 bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) {
712 715 bool d = false;
713 716 ok = false;
714 717 if (val == Py_False) {
715 718 d = false;
716 719 ok = true;
717 720 } else if (val == Py_True) {
718 721 d = true;
719 722 ok = true;
720 723 } else if (!strict) {
721 724 d = PyObjGetInt(val, false, ok)!=0;
722 725 ok = true;
723 726 }
724 727 return d;
725 728 }
726 729
727 730 int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) {
728 731 int d = 0;
729 732 ok = true;
730 733 if (val->ob_type == &PyInt_Type) {
731 734 d = PyInt_AS_LONG(val);
732 735 } else if (!strict) {
733 736 if (PyObject_TypeCheck(val, &PyInt_Type)) {
734 737 // support for derived int classes, e.g. for our enums
735 738 d = PyInt_AS_LONG(val);
736 739 } else if (val->ob_type == &PyFloat_Type) {
737 740 d = floor(PyFloat_AS_DOUBLE(val));
738 741 } else if (val->ob_type == &PyLong_Type) {
739 742 // handle error on overflow!
740 743 d = PyLong_AsLong(val);
741 744 } else if (val == Py_False) {
742 745 d = 0;
743 746 } else if (val == Py_True) {
744 747 d = 1;
745 748 } else {
746 749 ok = false;
747 750 }
748 751 } else {
749 752 ok = false;
750 753 }
751 754 return d;
752 755 }
753 756
754 757 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
755 758 qint64 d = 0;
756 759 ok = true;
757 760 if (val->ob_type == &PyInt_Type) {
758 761 d = PyInt_AS_LONG(val);
759 762 } else if (val->ob_type == &PyLong_Type) {
760 763 d = PyLong_AsLongLong(val);
761 764 } else if (!strict) {
762 765 if (PyObject_TypeCheck(val, &PyInt_Type)) {
763 766 // support for derived int classes, e.g. for our enums
764 767 d = PyInt_AS_LONG(val);
765 768 } else if (val->ob_type == &PyFloat_Type) {
766 769 d = floor(PyFloat_AS_DOUBLE(val));
767 770 } else if (val == Py_False) {
768 771 d = 0;
769 772 } else if (val == Py_True) {
770 773 d = 1;
771 774 } else {
772 775 ok = false;
773 776 }
774 777 } else {
775 778 ok = false;
776 779 }
777 780 return d;
778 781 }
779 782
780 783 quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) {
781 784 quint64 d = 0;
782 785 ok = true;
783 786 if (PyObject_TypeCheck(val, &PyInt_Type)) {
784 787 d = PyInt_AS_LONG(val);
785 788 } else if (val->ob_type == &PyLong_Type) {
786 789 d = PyLong_AsLongLong(val);
787 790 } else if (!strict) {
788 791 if (PyObject_TypeCheck(val, &PyInt_Type)) {
789 792 // support for derived int classes, e.g. for our enums
790 793 d = PyInt_AS_LONG(val);
791 794 } else if (val->ob_type == &PyFloat_Type) {
792 795 d = floor(PyFloat_AS_DOUBLE(val));
793 796 } else if (val == Py_False) {
794 797 d = 0;
795 798 } else if (val == Py_True) {
796 799 d = 1;
797 800 } else {
798 801 ok = false;
799 802 }
800 803 } else {
801 804 ok = false;
802 805 }
803 806 return d;
804 807 }
805 808
806 809 double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) {
807 810 double d = 0;
808 811 ok = true;
809 812 if (val->ob_type == &PyFloat_Type) {
810 813 d = PyFloat_AS_DOUBLE(val);
811 814 } else if (!strict) {
812 815 if (PyObject_TypeCheck(val, &PyInt_Type)) {
813 816 d = PyInt_AS_LONG(val);
814 817 } else if (val->ob_type == &PyLong_Type) {
815 818 d = PyLong_AsLong(val);
816 819 } else if (val == Py_False) {
817 820 d = 0;
818 821 } else if (val == Py_True) {
819 822 d = 1;
820 823 } else {
821 824 ok = false;
822 825 }
823 826 } else {
824 827 ok = false;
825 828 }
826 829 return d;
827 830 }
828 831
829 832 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
830 833 {
831 834 QVariant v;
832 835 bool ok = true;
833 836
834 837 if (type==-1) {
835 838 // no special type requested
836 839 if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) {
837 840 type = QVariant::String;
838 841 } else if (PyObject_TypeCheck(val, &PyInt_Type)) {
839 842 type = QVariant::Int;
840 843 } else if (val->ob_type==&PyLong_Type) {
841 844 type = QVariant::LongLong;
842 845 } else if (val->ob_type==&PyFloat_Type) {
843 846 type = QVariant::Double;
844 847 } else if (val == Py_False || val == Py_True) {
845 848 type = QVariant::Bool;
846 849 } else if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
847 850 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
848 851 // c++ wrapper, check if the class names of the c++ objects match
849 852 if (wrap->classInfo()->isCPPWrapper()) {
850 853 if (wrap->classInfo()->metaTypeId()>0) {
851 854 // construct a new variant from the C++ object if it has a meta type (this will COPY the object!)
852 855 v = QVariant(wrap->classInfo()->metaTypeId(), wrap->_wrappedPtr);
853 856 } else {
854 857 // TODOXXX we could as well check if there is a registered meta type for "classname*", so that we may pass
855 858 // the pointer here...
856 859 // is this worth anything? we loose the knowledge of the cpp object type
857 860 v = qVariantFromValue(wrap->_wrappedPtr);
858 861 }
859 862 } else {
860 863 // this gives us a QObject pointer
861 864 QObject* myObject = wrap->_obj;
862 865 v = qVariantFromValue(myObject);
863 866 }
864 867 return v;
865 868 } else if (val->ob_type==&PyDict_Type) {
866 869 type = QVariant::Map;
867 870 } else if (val->ob_type==&PyList_Type || val->ob_type==&PyTuple_Type || PySequence_Check(val)) {
868 871 type = QVariant::List;
869 872 } else if (val == Py_None) {
870 873 // none is invalid
871 874 type = QVariant::Invalid;
872 875 } else {
873 876 // this used to be:
874 877 // type = QVariant::String;
875 878 // but now we want to transport the Python Objects directly:
876 879 PythonQtObjectPtr o(val);
877 880 v = qVariantFromValue(o);
878 881 return v;
879 882 }
880 883 }
881 884 // special type request:
882 885 switch (type) {
883 886 case QVariant::Invalid:
884 887 return v;
885 888 break;
886 889 case QVariant::Int:
887 890 {
888 891 int d = PyObjGetInt(val, false, ok);
889 892 if (ok) return QVariant(d);
890 893 }
891 894 break;
892 895 case QVariant::UInt:
893 896 {
894 897 int d = PyObjGetInt(val, false,ok);
895 898 if (ok) v = QVariant((unsigned int)d);
896 899 }
897 900 break;
898 901 case QVariant::Bool:
899 902 {
900 903 int d = PyObjGetBool(val,false,ok);
901 904 if (ok) v = QVariant((bool)(d!=0));
902 905 }
903 906 break;
904 907 case QVariant::Double:
905 908 {
906 909 double d = PyObjGetDouble(val,false,ok);
907 910 if (ok) v = QVariant(d);
908 911 break;
909 912 }
910 913 case QMetaType::Float:
911 914 {
912 915 float d = (float) PyObjGetDouble(val,false,ok);
913 916 if (ok) v = qVariantFromValue(d);
914 917 break;
915 918 }
916 919 case QMetaType::Long:
917 920 {
918 921 long d = (long) PyObjGetLongLong(val,false,ok);
919 922 if (ok) v = qVariantFromValue(d);
920 923 break;
921 924 }
922 925 case QMetaType::ULong:
923 926 {
924 927 unsigned long d = (unsigned long) PyObjGetLongLong(val,false,ok);
925 928 if (ok) v = qVariantFromValue(d);
926 929 break;
927 930 }
928 931 case QMetaType::LongLong:
929 932 {
930 933 qint64 d = PyObjGetLongLong(val, false, ok);
931 934 if (ok) v = qVariantFromValue(d);
932 935 }
933 936 break;
934 937 case QMetaType::ULongLong:
935 938 {
936 939 quint64 d = PyObjGetULongLong(val, false, ok);
937 940 if (ok) v = qVariantFromValue(d);
938 941 }
939 942 break;
940 943 case QMetaType::Short:
941 944 {
942 945 short d = (short) PyObjGetInt(val,false,ok);
943 946 if (ok) v = qVariantFromValue(d);
944 947 break;
945 948 }
946 949 case QMetaType::UShort:
947 950 {
948 951 unsigned short d = (unsigned short) PyObjGetInt(val,false,ok);
949 952 if (ok) v = qVariantFromValue(d);
950 953 break;
951 954 }
952 955 case QMetaType::Char:
953 956 {
954 957 char d = (char) PyObjGetInt(val,false,ok);
955 958 if (ok) v = qVariantFromValue(d);
956 959 break;
957 960 }
958 961 case QMetaType::UChar:
959 962 {
960 963 unsigned char d = (unsigned char) PyObjGetInt(val,false,ok);
961 964 if (ok) v = qVariantFromValue(d);
962 965 break;
963 966 }
964 967
965 968 case QVariant::ByteArray:
966 969 case QVariant::String:
967 970 {
968 971 bool ok;
969 972 v = QVariant(PyObjGetString(val, false, ok));
970 973 }
971 974 break;
972 975
973 976 // these are important for MeVisLab
974 977 case QVariant::Map:
975 978 {
976 979 if (PyMapping_Check(val)) {
977 980 QMap<QString,QVariant> map;
978 981 PyObject* items = PyMapping_Items(val);
979 982 if (items) {
980 983 int count = PyList_Size(items);
981 984 PyObject* value;
982 985 PyObject* key;
983 986 PyObject* tuple;
984 987 for (int i = 0;i<count;i++) {
985 988 tuple = PyList_GetItem(items,i);
986 989 key = PyTuple_GetItem(tuple, 0);
987 990 value = PyTuple_GetItem(tuple, 1);
988 991 map.insert(PyObjGetString(key), PyObjToQVariant(value,-1));
989 992 }
990 993 Py_DECREF(items);
991 994 v = map;
992 995 }
993 996 }
994 997 }
995 998 break;
996 999 case QVariant::List:
997 1000 if (PySequence_Check(val)) {
998 1001 QVariantList list;
999 1002 int count = PySequence_Size(val);
1000 1003 PyObject* value;
1001 1004 for (int i = 0;i<count;i++) {
1002 1005 value = PySequence_GetItem(val,i);
1003 1006 list.append(PyObjToQVariant(value, -1));
1004 1007 }
1005 1008 v = list;
1006 1009 }
1007 1010 break;
1008 1011 case QVariant::StringList:
1009 1012 {
1010 1013 bool ok;
1011 1014 QStringList l = PyObjToStringList(val, false, ok);
1012 1015 if (ok) {
1013 1016 v = l;
1014 1017 }
1015 1018 }
1016 1019 break;
1017 1020
1018 1021 default:
1019 1022 if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
1020 1023 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
1021 1024 if (wrap->classInfo()->isCPPWrapper() && wrap->classInfo()->metaTypeId() == type) {
1022 1025 // construct a new variant from the C++ object if it has the same meta type
1023 1026 v = QVariant(type, wrap->_wrappedPtr);
1024 1027 } else {
1025 1028 v = QVariant();
1026 1029 }
1027 1030 } else {
1028 1031 v = QVariant();
1029 1032 }
1030 1033 }
1031 1034 return v;
1032 1035 }
1033 1036
1034 1037 PyObject* PythonQtConv::QStringToPyObject(const QString& str)
1035 1038 {
1036 1039 if (str.isNull()) {
1037 1040 return PyString_FromString("");
1038 1041 } else {
1039 1042 return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, NULL, NULL);
1040 1043 }
1041 1044 }
1042 1045
1043 1046 PyObject* PythonQtConv::QStringListToPyObject(const QStringList& list)
1044 1047 {
1045 1048 PyObject* result = PyTuple_New(list.count());
1046 1049 int i = 0;
1047 1050 QString str;
1048 1051 foreach (str, list) {
1049 1052 PyTuple_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(str));
1050 1053 i++;
1051 1054 }
1052 1055 // why is the error state bad after this?
1053 1056 PyErr_Clear();
1054 1057 return result;
1055 1058 }
1056 1059
1057 1060 PyObject* PythonQtConv::QStringListToPyList(const QStringList& list)
1058 1061 {
1059 1062 PyObject* result = PyList_New(list.count());
1060 1063 int i = 0;
1061 1064 for (QStringList::ConstIterator it = list.begin(); it!=list.end(); ++it) {
1062 1065 PyList_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(*it));
1063 1066 i++;
1064 1067 }
1065 1068 return result;
1066 1069 }
1067 1070
1068 1071 PyObject* PythonQtConv::QVariantToPyObject(const QVariant& v)
1069 1072 {
1070 1073 return ConvertQtValueToPythonInternal(v.userType(), (void*)v.constData());
1071 1074 }
1072 1075
1073 1076 PyObject* PythonQtConv::QVariantMapToPyObject(const QVariantMap& m) {
1074 1077 PyObject* result = PyDict_New();
1075 1078 QVariantMap::const_iterator t = m.constBegin();
1076 1079 PyObject* key;
1077 1080 PyObject* val;
1078 1081 for (;t!=m.end();t++) {
1079 1082 key = QStringToPyObject(t.key());
1080 1083 val = QVariantToPyObject(t.value());
1081 1084 PyDict_SetItem(result, key, val);
1082 1085 Py_DECREF(key);
1083 1086 Py_DECREF(val);
1084 1087 }
1085 1088 return result;
1086 1089 }
1087 1090
1088 1091 PyObject* PythonQtConv::QVariantListToPyObject(const QVariantList& l) {
1089 1092 PyObject* result = PyTuple_New(l.count());
1090 1093 int i = 0;
1091 1094 QVariant v;
1092 1095 foreach (v, l) {
1093 1096 PyTuple_SET_ITEM(result, i, PythonQtConv::QVariantToPyObject(v));
1094 1097 i++;
1095 1098 }
1096 1099 // why is the error state bad after this?
1097 1100 PyErr_Clear();
1098 1101 return result;
1099 1102 }
1100 1103
1101 1104 PyObject* PythonQtConv::ConvertQListOfPointerTypeToPythonList(QList<void*>* list, const QByteArray& typeName)
1102 1105 {
1103 1106 PyObject* result = PyTuple_New(list->count());
1104 1107 int i = 0;
1105 1108 foreach (void* value, *list) {
1106 1109 PyTuple_SET_ITEM(result, i, PythonQt::priv()->wrapPtr(value, typeName));
1107 1110 i++;
1108 1111 }
1109 1112 return result;
1110 1113 }
1111 1114
1112 1115 bool PythonQtConv::ConvertPythonListToQListOfPointerType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool /*strict*/)
1113 1116 {
1114 1117 bool result = false;
1115 1118 if (PySequence_Check(obj)) {
1116 1119 result = true;
1117 1120 int count = PySequence_Size(obj);
1118 1121 PyObject* value;
1119 1122 for (int i = 0;i<count;i++) {
1120 1123 value = PySequence_GetItem(obj,i);
1121 1124 if (PyObject_TypeCheck(value, &PythonQtInstanceWrapper_Type)) {
1122 1125 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)value;
1123 1126 bool ok;
1124 1127 void* object = castWrapperTo(wrap, type, ok);
1125 1128 if (ok) {
1126 1129 list->append(object);
1127 1130 } else {
1128 1131 result = false;
1129 1132 break;
1130 1133 }
1131 1134 }
1132 1135 }
1133 1136 }
1134 1137 return result;
1135 1138 }
1136 1139
1137 1140 int PythonQtConv::getInnerTemplateMetaType(const QByteArray& typeName)
1138 1141 {
1139 1142 int idx = typeName.indexOf("<");
1140 1143 if (idx>0) {
1141 1144 int idx2 = typeName.indexOf(">");
1142 1145 if (idx2>0) {
1143 1146 QByteArray innerType = typeName.mid(idx+1,idx2-idx-1);
1144 1147 return QMetaType::type(innerType.constData());
1145 1148 }
1146 1149 }
1147 1150 return QMetaType::Void;
1148 1151 }
1149 1152
1150 1153
1151 1154 QString PythonQtConv::CPPObjectToString(int type, const void* data) {
1152 1155 QString r;
1153 1156 switch (type) {
1154 1157 case QVariant::Size: {
1155 1158 const QSize* s = static_cast<const QSize*>(data);
1156 1159 r = QString::number(s->width()) + ", " + QString::number(s->height());
1157 1160 }
1158 1161 break;
1159 1162 case QVariant::SizeF: {
1160 1163 const QSizeF* s = static_cast<const QSizeF*>(data);
1161 1164 r = QString::number(s->width()) + ", " + QString::number(s->height());
1162 1165 }
1163 1166 break;
1164 1167 case QVariant::Point: {
1165 1168 const QPoint* s = static_cast<const QPoint*>(data);
1166 1169 r = QString::number(s->x()) + ", " + QString::number(s->y());
1167 1170 }
1168 1171 break;
1169 1172 case QVariant::PointF: {
1170 1173 const QPointF* s = static_cast<const QPointF*>(data);
1171 1174 r = QString::number(s->x()) + ", " + QString::number(s->y());
1172 1175 }
1173 1176 break;
1174 1177 case QVariant::Rect: {
1175 1178 const QRect* s = static_cast<const QRect*>(data);
1176 1179 r = QString::number(s->x()) + ", " + QString::number(s->y());
1177 1180 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1178 1181 }
1179 1182 break;
1180 1183 case QVariant::RectF: {
1181 1184 const QRectF* s = static_cast<const QRectF*>(data);
1182 1185 r = QString::number(s->x()) + ", " + QString::number(s->y());
1183 1186 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1184 1187 }
1185 1188 break;
1186 1189 case QVariant::Date: {
1187 1190 const QDate* s = static_cast<const QDate*>(data);
1188 1191 r = s->toString(Qt::ISODate);
1189 1192 }
1190 1193 break;
1191 1194 case QVariant::DateTime: {
1192 1195 const QDateTime* s = static_cast<const QDateTime*>(data);
1193 1196 r = s->toString(Qt::ISODate);
1194 1197 }
1195 1198 break;
1196 1199 case QVariant::Time: {
1197 1200 const QTime* s = static_cast<const QTime*>(data);
1198 1201 r = s->toString(Qt::ISODate);
1199 1202 }
1200 1203 break;
1201 1204 case QVariant::Pixmap:
1202 1205 {
1203 1206 const QPixmap* s = static_cast<const QPixmap*>(data);
1204 1207 r = QString("Pixmap ") + QString::number(s->width()) + ", " + QString::number(s->height());
1205 1208 }
1206 1209 break;
1207 1210 case QVariant::Image:
1208 1211 {
1209 1212 const QImage* s = static_cast<const QImage*>(data);
1210 1213 r = QString("Image ") + QString::number(s->width()) + ", " + QString::number(s->height());
1211 1214 }
1212 1215 break;
1213 1216 case QVariant::Url:
1214 1217 {
1215 1218 const QUrl* s = static_cast<const QUrl*>(data);
1216 1219 r = s->toString();
1217 1220 }
1218 1221 break;
1219 1222 //TODO: add more printing for other variant types
1220 1223 default:
1221 1224 // this creates a copy, but that should not be expensive for typical simple variants
1222 1225 // (but we do not want to do this for our won user types!
1223 1226 if (type>0 && type < (int)QVariant::UserType) {
1224 1227 QVariant v(type, data);
1225 1228 r = v.toString();
1226 1229 }
1227 1230 }
1228 1231 return r;
1229 1232 }
@@ -1,62 +1,80
1 1 #ifndef _PYTHONQTCPPWRAPPERFACTORY_H
2 2 #define _PYTHONQTCPPWRAPPERFACTORY_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 PythonQtCppWrapperFactory.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-06
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 //! Factory interface for C++ classes that can be wrapped by QObject objects
46 46 /*! To create your own factory, derive PythonQtCppWrapperFactory and implement
47 47 the create() method.
48 48 A factory can be added to PythonQt by PythonQt::addCppWrapperFactory().
49 49 */
50 50 class PYTHONQT_EXPORT PythonQtCppWrapperFactory
51 51 {
52 52 public:
53 53 PythonQtCppWrapperFactory() {};
54 54 virtual ~PythonQtCppWrapperFactory() {};
55 55
56 56 //! create a wrapper for the given object
57 virtual QObject* create(const QByteArray& name, void *ptr) = 0;
57 virtual QObject* create(const QByteArray& classname, void *ptr) = 0;
58
59 };
60
61 //! Factory interface for C++ classes that can be mapped directly from/to
62 //! Python with other means than PythonQt/QObjects.
63 class PYTHONQT_EXPORT PythonQtForeignWrapperFactory
64 {
65 public:
66 PythonQtForeignWrapperFactory() {};
67 virtual ~PythonQtForeignWrapperFactory() {};
68
69 //! create a Python object (with new reference count), wrapping the given \p ptr as class of type \p classname
70 //! Return NULL (and not Py_None) if the object could not be wrapped.
71 virtual PyObject* wrap(const QByteArray& classname, void *ptr) = 0;
72
73 //! unwrap the given object to a C++ object of type \p classname if possible
74 //! Return NULL otherwise.
75 virtual void* unwrap(const QByteArray& classname, PyObject* object) = 0;
58 76
59 77 };
60 78
61 79 #endif
62 80
General Comments 0
You need to be logged in to leave comments. Login now