##// END OF EJS Templates
removed implicit conversion of QByteArray to python str, use str() to convert to Python string or QByteArray::data()...
florianlink -
r125:50c6d9f6a6dd
parent child
Show More
@@ -1,1219 +1,1220
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtImporter.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include "PythonQtMethodInfo.h"
46 46 #include "PythonQtSignalReceiver.h"
47 47 #include "PythonQtConversion.h"
48 48 #include "PythonQtStdOut.h"
49 49 #include "PythonQtCppWrapperFactory.h"
50 50 #include "PythonQtVariants.h"
51 51 #include "PythonQtStdDecorators.h"
52 52 #include "PythonQtQFileImporter.h"
53 53 #include <pydebug.h>
54 54 #include <vector>
55 55
56 56 PythonQt* PythonQt::_self = NULL;
57 57 int PythonQt::_uniqueModuleCount = 0;
58 58
59 59 void PythonQt_init_QtGuiBuiltin(PyObject*);
60 60 void PythonQt_init_QtCoreBuiltin(PyObject*);
61 61
62 62 void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
63 63 {
64 64 if (!_self) {
65 65 _self = new PythonQt(flags, pythonQtModuleName);
66 66
67 67 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
68 68 qRegisterMetaType<QList<QObject*> >("QList<void*>");
69 69
70 70 PythonQtRegisterToolClassesTemplateConverter(int);
71 71 PythonQtRegisterToolClassesTemplateConverter(float);
72 72 PythonQtRegisterToolClassesTemplateConverter(double);
73 73 PythonQtRegisterToolClassesTemplateConverter(qint32);
74 74 PythonQtRegisterToolClassesTemplateConverter(quint32);
75 75 PythonQtRegisterToolClassesTemplateConverter(qint64);
76 76 PythonQtRegisterToolClassesTemplateConverter(quint64);
77 77 // TODO: which other POD types should be available for QList etc.
78 78
79 79 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
80 80
81 81 PythonQt_init_QtCoreBuiltin(NULL);
82 82 PythonQt_init_QtGuiBuiltin(NULL);
83 83
84 PythonQtRegisterToolClassesTemplateConverter(QByteArray);
84 85 PythonQtRegisterToolClassesTemplateConverter(QDate);
85 86 PythonQtRegisterToolClassesTemplateConverter(QTime);
86 87 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
87 88 PythonQtRegisterToolClassesTemplateConverter(QUrl);
88 89 PythonQtRegisterToolClassesTemplateConverter(QLocale);
89 90 PythonQtRegisterToolClassesTemplateConverter(QRect);
90 91 PythonQtRegisterToolClassesTemplateConverter(QRectF);
91 92 PythonQtRegisterToolClassesTemplateConverter(QSize);
92 93 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
93 94 PythonQtRegisterToolClassesTemplateConverter(QLine);
94 95 PythonQtRegisterToolClassesTemplateConverter(QLineF);
95 96 PythonQtRegisterToolClassesTemplateConverter(QPoint);
96 97 PythonQtRegisterToolClassesTemplateConverter(QPointF);
97 98 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
98 99
99 100 PythonQtRegisterToolClassesTemplateConverter(QFont);
100 101 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
101 102 PythonQtRegisterToolClassesTemplateConverter(QBrush);
102 103 PythonQtRegisterToolClassesTemplateConverter(QColor);
103 104 PythonQtRegisterToolClassesTemplateConverter(QPalette);
104 105 PythonQtRegisterToolClassesTemplateConverter(QIcon);
105 106 PythonQtRegisterToolClassesTemplateConverter(QImage);
106 107 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
107 108 PythonQtRegisterToolClassesTemplateConverter(QRegion);
108 109 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
109 110 PythonQtRegisterToolClassesTemplateConverter(QCursor);
110 111 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
111 112 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
112 113 PythonQtRegisterToolClassesTemplateConverter(QPen);
113 114 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
114 115 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
115 116 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
116 117
117 118
118 119 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
119 120 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
120 121 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
121 122 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
122 123 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
123 124 for (unsigned int i = 0;i<16; i++) {
124 125 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
125 126 if (obj) {
126 127 PyModule_AddObject(pack, names[i], obj);
127 128 Py_INCREF(obj);
128 129 PyModule_AddObject(pack2, names[i], obj);
129 130 } else {
130 131 std::cerr << "method not found " << names[i];
131 132 }
132 133 }
133 134 }
134 135 }
135 136
136 137 void PythonQt::cleanup()
137 138 {
138 139 if (_self) {
139 140 delete _self;
140 141 _self = NULL;
141 142 }
142 143 }
143 144
144 145 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
145 146 {
146 147 _p = new PythonQtPrivate;
147 148 _p->_initFlags = flags;
148 149
149 150 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
150 151
151 152 Py_SetProgramName("PythonQt");
152 153 if (flags & IgnoreSiteModule) {
153 154 // this prevents the automatic importing of Python site files
154 155 Py_NoSiteFlag = 1;
155 156 }
156 157 Py_Initialize();
157 158
158 159 // add our own python object types for qt object slots
159 160 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
160 161 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
161 162 }
162 163 Py_INCREF(&PythonQtSlotFunction_Type);
163 164
164 165 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
165 166 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
166 167 // add our own python object types for classes
167 168 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
168 169 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
169 170 }
170 171 Py_INCREF(&PythonQtClassWrapper_Type);
171 172
172 173 // add our own python object types for CPP instances
173 174 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
174 175 PythonQt::handleError();
175 176 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
176 177 }
177 178 Py_INCREF(&PythonQtInstanceWrapper_Type);
178 179
179 180 // add our own python object types for redirection of stdout
180 181 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
181 182 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
182 183 }
183 184 Py_INCREF(&PythonQtStdOutRedirectType);
184 185
185 186 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
186 187
187 188 _p->setupSharedLibrarySuffixes();
188 189
189 190 }
190 191
191 192 PythonQt::~PythonQt() {
192 193 delete _p;
193 194 _p = NULL;
194 195 }
195 196
196 197 PythonQtPrivate::~PythonQtPrivate() {
197 198 delete _defaultImporter;
198 199 _defaultImporter = NULL;
199 200
200 201 {
201 202 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
202 203 while (i.hasNext()) {
203 204 delete i.next().value();
204 205 }
205 206 }
206 207 PythonQtConv::global_valueStorage.clear();
207 208 PythonQtConv::global_ptrStorage.clear();
208 209 PythonQtConv::global_variantStorage.clear();
209 210
210 211 PythonQtMethodInfo::cleanupCachedMethodInfos();
211 212 }
212 213
213 214 PythonQtImportFileInterface* PythonQt::importInterface()
214 215 {
215 216 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
216 217 }
217 218
218 219 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
219 220 {
220 221 if (_self->_p->_noLongerWrappedCB) {
221 222 (*_self->_p->_noLongerWrappedCB)(o);
222 223 };
223 224 }
224 225
225 226 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
226 227 {
227 228 _p->registerClass(metaobject, package, wrapperCreator, shell);
228 229 }
229 230
230 231 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
231 232 {
232 233 // we register all classes in the hierarchy
233 234 const QMetaObject* m = metaobject;
234 235 bool first = true;
235 236 while (m) {
236 237 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
237 238 if (!info->pythonQtClassWrapper()) {
238 239 info->setTypeSlots(typeSlots);
239 240 info->setupQObject(m);
240 241 createPythonQtClassWrapper(info, package, module);
241 242 if (m->superClass()) {
242 243 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
243 244 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
244 245 }
245 246 }
246 247 if (first) {
247 248 first = false;
248 249 if (wrapperCreator) {
249 250 info->setDecoratorProvider(wrapperCreator);
250 251 }
251 252 if (shell) {
252 253 info->setShellSetInstanceWrapperCB(shell);
253 254 }
254 255 }
255 256 m = m->superClass();
256 257 }
257 258 }
258 259
259 260 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
260 261 {
261 262 PyObject* pack = module?module:packageByName(package);
262 263 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
263 264 PyModule_AddObject(pack, info->className(), pyobj);
264 265 if (!module && package && strncmp(package,"Qt",2)==0) {
265 266 // since PyModule_AddObject steals the reference, we need a incref once more...
266 267 Py_INCREF(pyobj);
267 268 // put all qt objects into Qt as well
268 269 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
269 270 }
270 271 info->setPythonQtClassWrapper(pyobj);
271 272 }
272 273
273 274 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
274 275 {
275 276 if (!obj) {
276 277 Py_INCREF(Py_None);
277 278 return Py_None;
278 279 }
279 280 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
280 281 if (!wrap) {
281 282 // smuggling it in...
282 283 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
283 284 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
284 285 registerClass(obj->metaObject());
285 286 classInfo = _knownClassInfos.value(obj->metaObject()->className());
286 287 }
287 288 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
288 289 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
289 290 } else {
290 291 Py_INCREF(wrap);
291 292 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
292 293 }
293 294 return (PyObject*)wrap;
294 295 }
295 296
296 297 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
297 298 {
298 299 if (!ptr) {
299 300 Py_INCREF(Py_None);
300 301 return Py_None;
301 302 }
302 303
303 304 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
304 305 if (!wrap) {
305 306 PythonQtClassInfo* info = _knownClassInfos.value(name);
306 307 if (!info) {
307 308 // maybe it is a PyObject, which we can return directly
308 309 if (name == "PyObject") {
309 310 PyObject* p = (PyObject*)ptr;
310 311 Py_INCREF(p);
311 312 return p;
312 313 }
313 314
314 315 // we do not know the metaobject yet, but we might know it by it's name:
315 316 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
316 317 // yes, we know it, so we can convert to QObject
317 318 QObject* qptr = (QObject*)ptr;
318 319 registerClass(qptr->metaObject());
319 320 info = _knownClassInfos.value(qptr->metaObject()->className());
320 321 }
321 322 }
322 323 if (info && info->isQObject()) {
323 324 QObject* qptr = (QObject*)ptr;
324 325 // if the object is a derived object, we want to switch the class info to the one of the derived class:
325 326 if (name!=(qptr->metaObject()->className())) {
326 327 registerClass(qptr->metaObject());
327 328 info = _knownClassInfos.value(qptr->metaObject()->className());
328 329 }
329 330 wrap = createNewPythonQtInstanceWrapper(qptr, info);
330 331 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
331 332 return (PyObject*)wrap;
332 333 }
333 334
334 335 // not a known QObject, so try our wrapper factory:
335 336 QObject* wrapper = NULL;
336 337 for (int i=0; i<_cppWrapperFactories.size(); i++) {
337 338 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
338 339 if (wrapper) {
339 340 break;
340 341 }
341 342 }
342 343
343 344 if (info) {
344 345 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
345 346 ptr = info->castDownIfPossible(ptr, &info);
346 347 }
347 348
348 349 if (!info || info->pythonQtClassWrapper()==NULL) {
349 350 // still unknown, register as CPP class
350 351 registerCPPClass(name.constData());
351 352 info = _knownClassInfos.value(name);
352 353 }
353 354 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
354 355 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
355 356 info->setMetaObject(wrapper->metaObject());
356 357 }
357 358 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
358 359 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
359 360 } else {
360 361 Py_INCREF(wrap);
361 362 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
362 363 }
363 364 return (PyObject*)wrap;
364 365 }
365 366
366 367 PyObject* PythonQtPrivate::dummyTuple() {
367 368 static PyObject* dummyTuple = NULL;
368 369 if (dummyTuple==NULL) {
369 370 dummyTuple = PyTuple_New(1);
370 371 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
371 372 }
372 373 return dummyTuple;
373 374 }
374 375
375 376
376 377 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
377 378 // call the associated class type to create a new instance...
378 379 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
379 380
380 381 result->setQObject(obj);
381 382 result->_wrappedPtr = wrappedPtr;
382 383 result->_ownedByPythonQt = false;
383 384 result->_useQMetaTypeDestroy = false;
384 385
385 386 if (wrappedPtr) {
386 387 _wrappedObjects.insert(wrappedPtr, result);
387 388 } else {
388 389 _wrappedObjects.insert(obj, result);
389 390 if (obj->parent()== NULL && _wrappedCB) {
390 391 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
391 392 (*_wrappedCB)(obj);
392 393 }
393 394 }
394 395 return result;
395 396 }
396 397
397 398 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
398 399 PythonQtClassWrapper* result;
399 400
400 401 PyObject* className = PyString_FromString(info->className());
401 402
402 403 PyObject* baseClasses = PyTuple_New(1);
403 404 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
404 405
405 406 PyObject* typeDict = PyDict_New();
406 407 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
407 408 PyDict_SetItemString(typeDict, "__module__", moduleName);
408 409
409 410 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
410 411
411 412 // set the class info so that PythonQtClassWrapper_new can read it
412 413 _currentClassInfoForClassWrapperCreation = info;
413 414 // create the new type object by calling the type
414 415 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
415 416
416 417 Py_DECREF(baseClasses);
417 418 Py_DECREF(typeDict);
418 419 Py_DECREF(args);
419 420 Py_DECREF(className);
420 421
421 422 return result;
422 423 }
423 424
424 425 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
425 426 {
426 427 PyObject* args = Py_BuildValue("(i)", enumValue);
427 428 PyObject* result = PyObject_Call(enumType, args, NULL);
428 429 Py_DECREF(args);
429 430 return result;
430 431 }
431 432
432 433 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
433 434 PyObject* result;
434 435
435 436 PyObject* className = PyString_FromString(enumName);
436 437
437 438 PyObject* baseClasses = PyTuple_New(1);
438 439 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
439 440
440 441 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
441 442 PyObject* typeDict = PyDict_New();
442 443 PyDict_SetItemString(typeDict, "__module__", module);
443 444
444 445 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
445 446
446 447 // create the new int derived type object by calling the core type
447 448 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
448 449
449 450 Py_DECREF(baseClasses);
450 451 Py_DECREF(typeDict);
451 452 Py_DECREF(args);
452 453 Py_DECREF(className);
453 454
454 455 return result;
455 456 }
456 457
457 458 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
458 459 {
459 460 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
460 461 if (!r) {
461 462 r = new PythonQtSignalReceiver(obj);
462 463 _p->_signalReceivers.insert(obj, r);
463 464 }
464 465 return r;
465 466 }
466 467
467 468 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
468 469 {
469 470 bool flag = false;
470 471 PythonQtObjectPtr callable = lookupCallable(module, objectname);
471 472 if (callable) {
472 473 PythonQtSignalReceiver* r = getSignalReceiver(obj);
473 474 flag = r->addSignalHandler(signal, callable);
474 475 if (!flag) {
475 476 // signal not found
476 477 }
477 478 } else {
478 479 // callable not found
479 480 }
480 481 return flag;
481 482 }
482 483
483 484 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
484 485 {
485 486 bool flag = false;
486 487 PythonQtSignalReceiver* r = getSignalReceiver(obj);
487 488 if (r) {
488 489 flag = r->addSignalHandler(signal, receiver);
489 490 }
490 491 return flag;
491 492 }
492 493
493 494 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
494 495 {
495 496 bool flag = false;
496 497 PythonQtObjectPtr callable = lookupCallable(module, objectname);
497 498 if (callable) {
498 499 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
499 500 if (r) {
500 501 flag = r->removeSignalHandler(signal, callable);
501 502 }
502 503 } else {
503 504 // callable not found
504 505 }
505 506 return flag;
506 507 }
507 508
508 509 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
509 510 {
510 511 bool flag = false;
511 512 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
512 513 if (r) {
513 514 flag = r->removeSignalHandler(signal, receiver);
514 515 }
515 516 return flag;
516 517 }
517 518
518 519 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
519 520 {
520 521 PythonQtObjectPtr p = lookupObject(module, name);
521 522 if (p) {
522 523 if (PyCallable_Check(p)) {
523 524 return p;
524 525 }
525 526 }
526 527 PyErr_Clear();
527 528 return NULL;
528 529 }
529 530
530 531 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
531 532 {
532 533 QStringList l = name.split('.');
533 534 PythonQtObjectPtr p = module;
534 535 PythonQtObjectPtr prev;
535 536 QString s;
536 537 QByteArray b;
537 538 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
538 539 prev = p;
539 540 b = (*i).toLatin1();
540 541 if (PyDict_Check(p)) {
541 542 p = PyDict_GetItemString(p, b.data());
542 543 } else {
543 544 p.setNewRef(PyObject_GetAttrString(p, b.data()));
544 545 }
545 546 }
546 547 PyErr_Clear();
547 548 return p;
548 549 }
549 550
550 551 PythonQtObjectPtr PythonQt::getMainModule() {
551 552 //both borrowed
552 553 PythonQtObjectPtr dict = PyImport_GetModuleDict();
553 554 return PyDict_GetItemString(dict, "__main__");
554 555 }
555 556
556 557 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
557 558 QVariant result;
558 559 if (pycode) {
559 560 PyObject* dict = NULL;
560 561 if (PyModule_Check(object)) {
561 562 dict = PyModule_GetDict(object);
562 563 } else if (PyDict_Check(object)) {
563 564 dict = object;
564 565 }
565 566 PyObject* r = NULL;
566 567 if (dict) {
567 568 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
568 569 }
569 570 if (r) {
570 571 result = PythonQtConv::PyObjToQVariant(r);
571 572 Py_DECREF(r);
572 573 } else {
573 574 handleError();
574 575 }
575 576 } else {
576 577 handleError();
577 578 }
578 579 return result;
579 580 }
580 581
581 582 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
582 583 {
583 584 QVariant result;
584 585 PythonQtObjectPtr p;
585 586 PyObject* dict = NULL;
586 587 if (PyModule_Check(object)) {
587 588 dict = PyModule_GetDict(object);
588 589 } else if (PyDict_Check(object)) {
589 590 dict = object;
590 591 }
591 592 if (dict) {
592 593 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
593 594 }
594 595 if (p) {
595 596 result = PythonQtConv::PyObjToQVariant(p);
596 597 } else {
597 598 handleError();
598 599 }
599 600 return result;
600 601 }
601 602
602 603 void PythonQt::evalFile(PyObject* module, const QString& filename)
603 604 {
604 605 PythonQtObjectPtr code = parseFile(filename);
605 606 if (code) {
606 607 evalCode(module, code);
607 608 } else {
608 609 handleError();
609 610 }
610 611 }
611 612
612 613 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
613 614 {
614 615 PythonQtObjectPtr p;
615 616 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
616 617 if (!p) {
617 618 handleError();
618 619 }
619 620 return p;
620 621 }
621 622
622 623 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
623 624 {
624 625 PythonQtObjectPtr code = parseFile(filename);
625 626 PythonQtObjectPtr module = _p->createModule(name, code);
626 627 return module;
627 628 }
628 629
629 630 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
630 631 {
631 632 PyErr_Clear();
632 633 QString scriptCode = script;
633 634 if (scriptCode.isEmpty()) {
634 635 // we always need at least a linefeed
635 636 scriptCode = "\n";
636 637 }
637 638 PythonQtObjectPtr pycode;
638 639 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
639 640 PythonQtObjectPtr module = _p->createModule(name, pycode);
640 641 return module;
641 642 }
642 643
643 644 PythonQtObjectPtr PythonQt::createUniqueModule()
644 645 {
645 646 static QString pyQtStr("PythonQt_module");
646 647 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
647 648 return createModuleFromScript(moduleName);
648 649 }
649 650
650 651 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
651 652 {
652 653 if (PyModule_Check(object)) {
653 654 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
654 655 } else if (PyDict_Check(object)) {
655 656 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
656 657 } else {
657 658 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
658 659 }
659 660 }
660 661
661 662 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
662 663 {
663 664 if (PyModule_Check(object)) {
664 665 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
665 666 } else if (PyDict_Check(object)) {
666 667 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
667 668 } else {
668 669 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
669 670 }
670 671 }
671 672
672 673 void PythonQt::removeVariable(PyObject* object, const QString& name)
673 674 {
674 675 if (PyDict_Check(object)) {
675 676 PyDict_DelItemString(object, name.toLatin1().data());
676 677 } else {
677 678 PyObject_DelAttrString(object, name.toLatin1().data());
678 679 }
679 680 }
680 681
681 682 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
682 683 {
683 684 QVariant result;
684 685 PythonQtObjectPtr obj = lookupObject(object, objectname);
685 686 if (obj) {
686 687 result = PythonQtConv::PyObjToQVariant(obj);
687 688 }
688 689 return result;
689 690 }
690 691
691 692 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
692 693 {
693 694 QStringList results;
694 695
695 696 PythonQtObjectPtr object;
696 697 if (objectname.isEmpty()) {
697 698 object = module;
698 699 } else {
699 700 object = lookupObject(module, objectname);
700 701 if (!object && type == CallOverloads) {
701 702 PyObject* dict = lookupObject(module, "__builtins__");
702 703 if (dict) {
703 704 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
704 705 }
705 706 }
706 707 }
707 708
708 709 if (object) {
709 710 if (type == CallOverloads) {
710 711 if (PythonQtSlotFunction_Check(object)) {
711 712 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
712 713 PythonQtSlotInfo* info = o->m_ml;
713 714
714 715 while (info) {
715 716 results << info->fullSignature();
716 717 info = info->nextInfo();
717 718 }
718 719 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
719 720 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
720 721 PythonQtSlotInfo* info = o->classInfo()->constructors();
721 722
722 723 while (info) {
723 724 results << info->fullSignature();
724 725 info = info->nextInfo();
725 726 }
726 727 } else {
727 728 //TODO: use pydoc!
728 729 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
729 730 if (doc) {
730 731 results << PyString_AsString(doc);
731 732 Py_DECREF(doc);
732 733 }
733 734 }
734 735 } else {
735 736 PyObject* keys = NULL;
736 737 bool isDict = false;
737 738 if (PyDict_Check(object)) {
738 739 keys = PyDict_Keys(object);
739 740 isDict = true;
740 741 } else {
741 742 keys = PyObject_Dir(object);
742 743 }
743 744 if (keys) {
744 745 int count = PyList_Size(keys);
745 746 PyObject* key;
746 747 PyObject* value;
747 748 QString keystr;
748 749 for (int i = 0;i<count;i++) {
749 750 key = PyList_GetItem(keys,i);
750 751 if (isDict) {
751 752 value = PyDict_GetItem(object, key);
752 753 Py_INCREF(value);
753 754 } else {
754 755 value = PyObject_GetAttr(object, key);
755 756 }
756 757 if (!value) continue;
757 758 keystr = PyString_AsString(key);
758 759 static const QString underscoreStr("__tmp");
759 760 if (!keystr.startsWith(underscoreStr)) {
760 761 switch (type) {
761 762 case Anything:
762 763 results << keystr;
763 764 break;
764 765 case Class:
765 766 if (value->ob_type == &PyClass_Type) {
766 767 results << keystr;
767 768 }
768 769 break;
769 770 case Variable:
770 771 if (value->ob_type != &PyClass_Type
771 772 && value->ob_type != &PyCFunction_Type
772 773 && value->ob_type != &PyFunction_Type
773 774 && value->ob_type != &PyModule_Type
774 775 ) {
775 776 results << keystr;
776 777 }
777 778 break;
778 779 case Function:
779 780 if (value->ob_type == &PyFunction_Type ||
780 781 value->ob_type == &PyMethod_Type
781 782 ) {
782 783 results << keystr;
783 784 }
784 785 break;
785 786 case Module:
786 787 if (value->ob_type == &PyModule_Type) {
787 788 results << keystr;
788 789 }
789 790 break;
790 791 default:
791 792 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
792 793 }
793 794 }
794 795 Py_DECREF(value);
795 796 }
796 797 Py_DECREF(keys);
797 798 }
798 799 }
799 800 }
800 801 return results;
801 802 }
802 803
803 804 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
804 805 {
805 806 PythonQtObjectPtr callable = lookupCallable(object, name);
806 807 if (callable) {
807 808 return call(callable, args);
808 809 } else {
809 810 return QVariant();
810 811 }
811 812 }
812 813
813 814 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
814 815 {
815 816 QVariant r;
816 817 PythonQtObjectPtr result;
817 818 result.setNewRef(callAndReturnPyObject(callable, args));
818 819 if (result) {
819 820 r = PythonQtConv::PyObjToQVariant(result);
820 821 } else {
821 822 PythonQt::self()->handleError();
822 823 }
823 824 return r;
824 825 }
825 826
826 827 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args)
827 828 {
828 829 PyObject* result = NULL;
829 830 if (callable) {
830 831 PythonQtObjectPtr pargs;
831 832 int count = args.size();
832 833 if (count>0) {
833 834 pargs.setNewRef(PyTuple_New(count));
834 835 }
835 836 bool err = false;
836 837 // transform QVariants to Python
837 838 for (int i = 0; i < count; i++) {
838 839 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
839 840 if (arg) {
840 841 // steals reference, no unref
841 842 PyTuple_SetItem(pargs, i,arg);
842 843 } else {
843 844 err = true;
844 845 break;
845 846 }
846 847 }
847 848
848 849 if (!err) {
849 850 PyErr_Clear();
850 851 result = PyObject_CallObject(callable, pargs);
851 852 }
852 853 }
853 854 return result;
854 855 }
855 856
856 857 void PythonQt::addInstanceDecorators(QObject* o)
857 858 {
858 859 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
859 860 }
860 861
861 862 void PythonQt::addClassDecorators(QObject* o)
862 863 {
863 864 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
864 865 }
865 866
866 867 void PythonQt::addDecorators(QObject* o)
867 868 {
868 869 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
869 870 }
870 871
871 872 void PythonQt::registerQObjectClassNames(const QStringList& names)
872 873 {
873 874 _p->registerQObjectClassNames(names);
874 875 }
875 876
876 877 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
877 878 {
878 879 _p->_importInterface = importInterface;
879 880 PythonQtImport::init();
880 881 }
881 882
882 883 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
883 884 {
884 885 _p->_importIgnorePaths = paths;
885 886 }
886 887
887 888 const QStringList& PythonQt::getImporterIgnorePaths()
888 889 {
889 890 return _p->_importIgnorePaths;
890 891 }
891 892
892 893 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
893 894 {
894 895 _p->_cppWrapperFactories.append(factory);
895 896 }
896 897
897 898 //---------------------------------------------------------------------------------------------------
898 899 PythonQtPrivate::PythonQtPrivate()
899 900 {
900 901 _importInterface = NULL;
901 902 _defaultImporter = new PythonQtQFileImporter;
902 903 _noLongerWrappedCB = NULL;
903 904 _wrappedCB = NULL;
904 905 _currentClassInfoForClassWrapperCreation = NULL;
905 906 }
906 907
907 908 void PythonQtPrivate::setupSharedLibrarySuffixes()
908 909 {
909 910 _sharedLibrarySuffixes.clear();
910 911 PythonQtObjectPtr imp;
911 912 imp.setNewRef(PyImport_ImportModule("imp"));
912 913 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
913 914 QVariant result = imp.call("get_suffixes");
914 915 foreach (QVariant entry, result.toList()) {
915 916 QVariantList suffixEntry = entry.toList();
916 917 if (suffixEntry.count()==3) {
917 918 int code = suffixEntry.at(2).toInt();
918 919 if (code == cExtensionCode) {
919 920 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
920 921 }
921 922 }
922 923 }
923 924 }
924 925
925 926 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
926 927 {
927 928 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
928 929 _currentClassInfoForClassWrapperCreation = NULL;
929 930 return info;
930 931 }
931 932
932 933 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
933 934 {
934 935 o->setParent(this);
935 936 int numMethods = o->metaObject()->methodCount();
936 937 for (int i = 0; i < numMethods; i++) {
937 938 QMetaMethod m = o->metaObject()->method(i);
938 939 if ((m.methodType() == QMetaMethod::Method ||
939 940 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
940 941 if (qstrncmp(m.signature(), "new_", 4)==0) {
941 942 if ((decoTypes & ConstructorDecorator) == 0) continue;
942 943 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
943 944 if (info->parameters().at(0).isPointer) {
944 945 QByteArray signature = m.signature();
945 946 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
946 947 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
947 948 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
948 949 classInfo->addConstructor(newSlot);
949 950 }
950 951 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
951 952 if ((decoTypes & DestructorDecorator) == 0) continue;
952 953 QByteArray signature = m.signature();
953 954 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
954 955 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
955 956 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
956 957 classInfo->setDestructor(newSlot);
957 958 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
958 959 if ((decoTypes & StaticDecorator) == 0) continue;
959 960 QByteArray signature = m.signature();
960 961 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
961 962 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
962 963 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
963 964 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
964 965 classInfo->addDecoratorSlot(newSlot);
965 966 } else {
966 967 if ((decoTypes & InstanceDecorator) == 0) continue;
967 968 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
968 969 if (info->parameters().count()>1) {
969 970 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
970 971 if (p.isPointer) {
971 972 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
972 973 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
973 974 classInfo->addDecoratorSlot(newSlot);
974 975 }
975 976 }
976 977 }
977 978 }
978 979 }
979 980 }
980 981
981 982 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
982 983 {
983 984 foreach(QString name, names) {
984 985 _knownQObjectClassNames.insert(name.toLatin1(), true);
985 986 }
986 987 }
987 988
988 989 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
989 990 {
990 991 _signalReceivers.remove(obj);
991 992 }
992 993
993 994 bool PythonQt::handleError()
994 995 {
995 996 bool flag = false;
996 997 if (PyErr_Occurred()) {
997 998
998 999 // currently we just print the error and the stderr handler parses the errors
999 1000 PyErr_Print();
1000 1001
1001 1002 /*
1002 1003 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1003 1004 PyObject *ptype;
1004 1005 PyObject *pvalue;
1005 1006 PyObject *ptraceback;
1006 1007 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1007 1008
1008 1009 Py_XDECREF(ptype);
1009 1010 Py_XDECREF(pvalue);
1010 1011 Py_XDECREF(ptraceback);
1011 1012 */
1012 1013 PyErr_Clear();
1013 1014 flag = true;
1014 1015 }
1015 1016 return flag;
1016 1017 }
1017 1018
1018 1019 void PythonQt::addSysPath(const QString& path)
1019 1020 {
1020 1021 PythonQtObjectPtr sys;
1021 1022 sys.setNewRef(PyImport_ImportModule("sys"));
1022 1023 PythonQtObjectPtr obj = lookupObject(sys, "path");
1023 1024 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1024 1025 }
1025 1026
1026 1027 void PythonQt::overwriteSysPath(const QStringList& paths)
1027 1028 {
1028 1029 PythonQtObjectPtr sys;
1029 1030 sys.setNewRef(PyImport_ImportModule("sys"));
1030 1031 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1031 1032 }
1032 1033
1033 1034 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1034 1035 {
1035 1036 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1036 1037 }
1037 1038
1038 1039 void PythonQt::stdOutRedirectCB(const QString& str)
1039 1040 {
1040 1041 emit PythonQt::self()->pythonStdOut(str);
1041 1042 }
1042 1043
1043 1044 void PythonQt::stdErrRedirectCB(const QString& str)
1044 1045 {
1045 1046 emit PythonQt::self()->pythonStdErr(str);
1046 1047 }
1047 1048
1048 1049 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1049 1050 {
1050 1051 _p->_wrappedCB = cb;
1051 1052 }
1052 1053
1053 1054 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1054 1055 {
1055 1056 _p->_noLongerWrappedCB = cb;
1056 1057 }
1057 1058
1058 1059
1059 1060
1060 1061 static PyMethodDef PythonQtMethods[] = {
1061 1062 {NULL, NULL, 0, NULL}
1062 1063 };
1063 1064
1064 1065 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1065 1066 {
1066 1067 QByteArray name = "PythonQt";
1067 1068 if (!pythonQtModuleName.isEmpty()) {
1068 1069 name = pythonQtModuleName;
1069 1070 }
1070 1071 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1071 1072 _p->_pythonQtModuleName = name;
1072 1073
1073 1074 if (redirectStdOut) {
1074 1075 PythonQtObjectPtr sys;
1075 1076 PythonQtObjectPtr out;
1076 1077 PythonQtObjectPtr err;
1077 1078 sys.setNewRef(PyImport_ImportModule("sys"));
1078 1079 // create a redirection object for stdout and stderr
1079 1080 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1080 1081 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1081 1082 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1082 1083 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1083 1084 // replace the built in file objects with our own objects
1084 1085 PyModule_AddObject(sys, "stdout", out);
1085 1086 PyModule_AddObject(sys, "stderr", err);
1086 1087 }
1087 1088 }
1088 1089
1089 1090 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1090 1091 {
1091 1092 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1092 1093 }
1093 1094
1094 1095
1095 1096 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1096 1097 {
1097 1098 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1098 1099 if (!info) {
1099 1100 info = new PythonQtClassInfo();
1100 1101 info->setupCPPObject(typeName);
1101 1102 _knownClassInfos.insert(typeName, info);
1102 1103 }
1103 1104 return info;
1104 1105 }
1105 1106
1106 1107 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1107 1108 {
1108 1109 _p->addPolymorphicHandler(typeName, cb);
1109 1110 }
1110 1111
1111 1112 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1112 1113 {
1113 1114 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1114 1115 info->addPolymorphicHandler(cb);
1115 1116 }
1116 1117
1117 1118 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1118 1119 {
1119 1120 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1120 1121 }
1121 1122
1122 1123 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1123 1124 {
1124 1125 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1125 1126 if (info) {
1126 1127 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1127 1128 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1128 1129 return true;
1129 1130 } else {
1130 1131 return false;
1131 1132 }
1132 1133 }
1133 1134
1134 1135 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1135 1136 {
1136 1137 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1137 1138 if (!info->pythonQtClassWrapper()) {
1138 1139 info->setTypeSlots(typeSlots);
1139 1140 info->setupCPPObject(typeName);
1140 1141 createPythonQtClassWrapper(info, package, module);
1141 1142 }
1142 1143 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1143 1144 addParentClass(typeName, parentTypeName, 0);
1144 1145 }
1145 1146 if (wrapperCreator) {
1146 1147 info->setDecoratorProvider(wrapperCreator);
1147 1148 }
1148 1149 if (shell) {
1149 1150 info->setShellSetInstanceWrapperCB(shell);
1150 1151 }
1151 1152 }
1152 1153
1153 1154 PyObject* PythonQtPrivate::packageByName(const char* name)
1154 1155 {
1155 1156 if (name==NULL || name[0]==0) {
1156 1157 name = "private";
1157 1158 }
1158 1159 PyObject* v = _packages.value(name);
1159 1160 if (!v) {
1160 1161 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1161 1162 _packages.insert(name, v);
1162 1163 // AddObject steals the reference, so increment it!
1163 1164 Py_INCREF(v);
1164 1165 PyModule_AddObject(_pythonQtModule, name, v);
1165 1166 }
1166 1167 return v;
1167 1168 }
1168 1169
1169 1170 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1170 1171 {
1171 1172 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;
1172 1173 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1173 1174 PythonQt::self()->handleError();
1174 1175 }
1175 1176
1176 1177 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1177 1178 {
1178 1179 if (_p->_initFlags & ExternalHelp) {
1179 1180 emit pythonHelpRequest(QByteArray(info->className()));
1180 1181 return Py_BuildValue("");
1181 1182 } else {
1182 1183 return PyString_FromString(info->help().toLatin1().data());
1183 1184 }
1184 1185 }
1185 1186
1186 1187 void PythonQtPrivate::removeWrapperPointer(void* obj)
1187 1188 {
1188 1189 _wrappedObjects.remove(obj);
1189 1190 }
1190 1191
1191 1192 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1192 1193 {
1193 1194 _wrappedObjects.insert(obj, wrapper);
1194 1195 }
1195 1196
1196 1197 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1197 1198 {
1198 1199 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1199 1200 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1200 1201 // this is a wrapper whose QObject was already removed due to destruction
1201 1202 // so the obj pointer has to be a new QObject with the same address...
1202 1203 // we remove the old one and set the copy to NULL
1203 1204 wrap->_objPointerCopy = NULL;
1204 1205 removeWrapperPointer(obj);
1205 1206 wrap = NULL;
1206 1207 }
1207 1208 return wrap;
1208 1209 }
1209 1210
1210 1211 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1211 1212 {
1212 1213 PythonQtObjectPtr result;
1213 1214 if (pycode) {
1214 1215 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1215 1216 } else {
1216 1217 PythonQt::self()->handleError();
1217 1218 }
1218 1219 return result;
1219 1220 }
@@ -1,1226 +1,1228
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file 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 PythonQtValueStorage<QVariant, 32> 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.isPointer) {
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.isPointer && (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;
87 87 if (info.isPointer) {
88 88 listPtr = *((QList<void*>**)data);
89 89 } else {
90 90 listPtr = (QList<void*>*)data;
91 91 }
92 92 return ConvertQListOfPointerTypeToPythonList(listPtr, innerType);
93 93 }
94 94 }
95 95
96 96 if (info.typeId >= QMetaType::User) {
97 97 // if a converter is registered, we use is:
98 98 PythonQtConvertMetaTypeToPythonCB* converter = _metaTypeToPythonConverters.value(info.typeId);
99 99 if (converter) {
100 100 return (*converter)(data, info.typeId);
101 101 }
102 102 }
103 103
104 104 // special handling did not match, so we convert the usual way (either pointer or value version):
105 105 if (info.isPointer) {
106 106 // 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)
107 107 return PythonQt::priv()->wrapPtr(*((void**)data), info.name);
108 108 } else {
109 109 // handle values that are not yet handled and not pointers
110 110 return ConvertQtValueToPythonInternal(info.typeId, data);
111 111 }
112 112 }
113 113
114 114 PyObject* PythonQtConv::ConvertQtValueToPythonInternal(int type, const void* data) {
115 115 switch (type) {
116 116 case QMetaType::Void:
117 117 Py_INCREF(Py_None);
118 118 return Py_None;
119 119 case QMetaType::Char:
120 120 return PyInt_FromLong(*((char*)data));
121 121 case QMetaType::UChar:
122 122 return PyInt_FromLong(*((unsigned char*)data));
123 123 case QMetaType::Short:
124 124 return PyInt_FromLong(*((short*)data));
125 125 case QMetaType::UShort:
126 126 return PyInt_FromLong(*((unsigned short*)data));
127 127 case QMetaType::Long:
128 128 return PyInt_FromLong(*((long*)data));
129 129 case QMetaType::ULong:
130 130 // does not fit into simple int of python
131 131 return PyLong_FromUnsignedLong(*((unsigned long*)data));
132 132 case QMetaType::Bool:
133 133 return PythonQtConv::GetPyBool(*((bool*)data));
134 134 case QMetaType::Int:
135 135 return PyInt_FromLong(*((int*)data));
136 136 case QMetaType::UInt:
137 137 // does not fit into simple int of python
138 138 return PyLong_FromUnsignedLong(*((unsigned int*)data));
139 139 case QMetaType::QChar:
140 140 return PyInt_FromLong(*((short*)data));
141 141 case QMetaType::Float:
142 142 return PyFloat_FromDouble(*((float*)data));
143 143 case QMetaType::Double:
144 144 return PyFloat_FromDouble(*((double*)data));
145 145 case QMetaType::LongLong:
146 146 return PyLong_FromLongLong(*((qint64*)data));
147 147 case QMetaType::ULongLong:
148 148 return PyLong_FromUnsignedLongLong(*((quint64*)data));
149 case QMetaType::QByteArray: {
150 QByteArray* v = (QByteArray*) data;
151 return PyString_FromStringAndSize(*v, v->size());
152 }
149 // implicit conversion from QByteArray to str has been removed:
150 //case QMetaType::QByteArray: {
151 // QByteArray* v = (QByteArray*) data;
152 // return PyString_FromStringAndSize(*v, v->size());
153 // }
153 154 case QMetaType::QVariantMap:
154 155 return PythonQtConv::QVariantMapToPyObject(*((QVariantMap*)data));
155 156 case QMetaType::QVariantList:
156 157 return PythonQtConv::QVariantListToPyObject(*((QVariantList*)data));
157 158 case QMetaType::QString:
158 159 return PythonQtConv::QStringToPyObject(*((QString*)data));
159 160 case QMetaType::QStringList:
160 161 return PythonQtConv::QStringListToPyObject(*((QStringList*)data));
161 162
162 163 case PythonQtMethodInfo::Variant:
163 164 return PythonQtConv::QVariantToPyObject(*((QVariant*)data));
164 165 case QMetaType::QObjectStar:
165 166 case QMetaType::QWidgetStar:
166 167 return PythonQt::priv()->wrapQObject(*((QObject**)data));
167 168
168 169 default:
169 170 if (PythonQt::priv()->isPythonQtObjectPtrMetaId(type)) {
170 171 // special case, it is a PythonQtObjectPtr which contains a PyObject, take it directly:
171 172 PyObject* o = ((PythonQtObjectPtr*)data)->object();
172 173 Py_INCREF(o);
173 174 return o;
174 175 } else {
175 176 if (type > 0) {
176 177 // if the type is known, we can construct it via QMetaType::construct
177 178 void* newCPPObject = QMetaType::construct(type, data);
178 179 // XXX this could be optimized by using metatypeid directly
179 180 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)PythonQt::priv()->wrapPtr(newCPPObject, QMetaType::typeName(type));
180 181 wrap->_ownedByPythonQt = true;
181 182 wrap->_useQMetaTypeDestroy = true;
182 183 return (PyObject*)wrap;
183 184 }
184 185 std::cerr << "Unknown type that can not be converted to Python: " << type << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
185 186 }
186 187 }
187 188 Py_INCREF(Py_None);
188 189 return Py_None;
189 190 }
190 191
191 192 void* PythonQtConv::CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info) {
192 193 void* ptr = NULL;
193 194 if (info.isPointer) {
194 195 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
195 196 } else if (info.enumWrapper) {
196 197 // create enum return value
197 198 PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, ptr);
198 199 } else {
199 200 switch (info.typeId) {
200 201 case QMetaType::Char:
201 202 case QMetaType::UChar:
202 203 case QMetaType::Short:
203 204 case QMetaType::UShort:
204 205 case QMetaType::Long:
205 206 case QMetaType::ULong:
206 207 case QMetaType::Bool:
207 208 case QMetaType::Int:
208 209 case QMetaType::UInt:
209 210 case QMetaType::QChar:
210 211 case QMetaType::Float:
211 212 case QMetaType::Double:
212 213 PythonQtValueStorage_ADD_VALUE(global_valueStorage, qint64, 0, ptr);
213 214 break;
214 215 case PythonQtMethodInfo::Variant:
215 216 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, 0, ptr);
216 217 // return the ptr to the variant
217 218 break;
218 219 default:
219 220 if (info.typeId == PythonQtMethodInfo::Unknown) {
220 221 // check if we have a QList of pointers, which we can circumvent with a QList<void*>
221 222 if (info.name.startsWith("QList<")) {
222 223 QByteArray innerType = info.name.mid(6,info.name.length()-7);
223 224 if (innerType.endsWith("*")) {
224 225 static int id = QMetaType::type("QList<void*>");
225 226 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr);
226 227 // return the constData pointer that will be filled with the result value later on
227 228 ptr = (void*)((QVariant*)ptr)->constData();
228 229 }
229 230 }
230 231 }
231 232
232 233 if (!ptr && info.typeId!=PythonQtMethodInfo::Unknown) {
233 234 // everything else is stored in a QVariant, if we know the meta type...
234 235 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
235 236 // return the constData pointer that will be filled with the result value later on
236 237 ptr = (void*)((QVariant*)ptr)->constData();
237 238 }
238 239 }
239 240 }
240 241 return ptr;
241 242 }
242 243
243 244 void* PythonQtConv::castWrapperTo(PythonQtInstanceWrapper* wrapper, const QByteArray& className, bool& ok)
244 245 {
245 246 void* object;
246 247 if (wrapper->classInfo()->isCPPWrapper()) {
247 248 object = wrapper->_wrappedPtr;
248 249 } else {
249 250 QObject* tmp = wrapper->_obj;
250 251 object = tmp;
251 252 }
252 253 if (object) {
253 254 // if we can be upcasted to the given name, we pass the casted pointer in:
254 255 object = wrapper->classInfo()->castTo(object, className);
255 256 ok = object!=NULL;
256 257 } else {
257 258 // if it is a NULL ptr, we need to check if it inherits, so that we might pass the NULL ptr
258 259 ok = wrapper->classInfo()->inherits(className);
259 260 }
260 261 return object;
261 262 }
262 263
263 264 void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject)
264 265 {
265 266 void* ptr = alreadyAllocatedCPPObject;
266 267
267 268 static int penId = QMetaType::type("QPen");
268 269 static int brushId = QMetaType::type("QBrush");
269 270 static int cursorId = QMetaType::type("QCursor");
270 271 static int colorId = QMetaType::type("QColor");
271 272 static PyObject* qtGlobalColorEnum = PythonQtClassInfo::findEnumWrapper("Qt::GlobalColor", NULL);
272 273 if (typeId == cursorId) {
273 274 static PyObject* qtCursorShapeEnum = PythonQtClassInfo::findEnumWrapper("Qt::CursorShape", NULL);
274 275 if ((PyObject*)obj->ob_type == qtCursorShapeEnum) {
275 276 Qt::CursorShape val = (Qt::CursorShape)PyInt_AS_LONG(obj);
276 277 if (!ptr) {
277 278 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QCursor(), ptr);
278 279 ptr = (void*)((QVariant*)ptr)->constData();
279 280 }
280 281 *((QCursor*)ptr) = QCursor(val);
281 282 return ptr;
282 283 }
283 284 } else if (typeId == penId) {
284 285 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
285 286 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
286 287 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
287 288 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
288 289 if (!ptr) {
289 290 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
290 291 ptr = (void*)((QVariant*)ptr)->constData();
291 292 }
292 293 *((QPen*)ptr) = QPen(QColor(val));
293 294 return ptr;
294 295 } else if ((PyObject*)obj->ob_type == qtColorClass) {
295 296 if (!ptr) {
296 297 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
297 298 ptr = (void*)((QVariant*)ptr)->constData();
298 299 }
299 300 *((QPen*)ptr) = QPen(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
300 301 return ptr;
301 302 }
302 303 } else if (typeId == brushId) {
303 304 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
304 305 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
305 306 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
306 307 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
307 308 if (!ptr) {
308 309 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
309 310 ptr = (void*)((QVariant*)ptr)->constData();
310 311 }
311 312 *((QBrush*)ptr) = QBrush(QColor(val));
312 313 return ptr;
313 314 } else if ((PyObject*)obj->ob_type == qtColorClass) {
314 315 if (!ptr) {
315 316 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
316 317 ptr = (void*)((QVariant*)ptr)->constData();
317 318 }
318 319 *((QBrush*)ptr) = QBrush(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
319 320 return ptr;
320 321 }
321 322 } else if (typeId == colorId) {
322 323 // colors can be created from Qt::GlobalColor (and from colors, but that's the default)
323 324 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
324 325 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
325 326 if (!ptr) {
326 327 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QColor(), ptr);
327 328 ptr = (void*)((QVariant*)ptr)->constData();
328 329 }
329 330 *((QColor*)ptr) = QColor(val);
330 331 return ptr;
331 332 }
332 333 }
333 334 return NULL;
334 335 }
335 336
336 337 void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* /*classInfo*/, void* alreadyAllocatedCPPObject)
337 338 {
338 339 bool ok = false;
339 340 void* ptr = NULL;
340 341
341 342 // autoconversion of QPen/QBrush/QCursor/QColor from different type
342 343 if (!info.isPointer && !strict) {
343 344 ptr = handlePythonToQtAutoConversion(info.typeId, obj, alreadyAllocatedCPPObject);
344 345 if (ptr) {
345 346 return ptr;
346 347 }
347 348 }
348 349
349 350 if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) && info.typeId != PythonQtMethodInfo::Variant) {
350 351 // if we have a Qt wrapper object and if we do not need a QVariant, we do the following:
351 352 // (the Variant case is handled below in a switch)
352 353
353 354 // a C++ wrapper (can be passed as pointer or reference)
354 355 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)obj;
355 356 void* object = castWrapperTo(wrap, info.name, ok);
356 357 if (ok) {
357 358 if (info.isPointer) {
358 359 // store the wrapped pointer in an extra pointer and let ptr point to the extra pointer
359 360 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, object, ptr);
360 361 } else {
361 362 // store the wrapped pointer directly, since we are a reference
362 363 ptr = object;
363 364 }
364 365 } else {
365 366 // not matching
366 367 }
367 368 } else if (info.isPointer) {
368 369 // a pointer
369 370 if (info.typeId == QMetaType::Char || info.typeId == QMetaType::UChar)
370 371 {
371 372 QString str = PyObjGetString(obj, strict, ok);
372 373 if (ok) {
373 374 void* ptr2 = NULL;
374 375 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str.toUtf8()), ptr2);
375 376 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr);
376 377 }
377 378 } else if (info.name == "PyObject") {
378 379 // handle low level PyObject directly
379 380 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, obj, ptr);
380 381 } else if (obj == Py_None) {
381 382 // None is treated as a NULL ptr
382 383 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
383 384 } else {
384 385 // if we are not strict, we try if we are passed a 0 integer
385 386 if (!strict) {
386 387 bool ok;
387 388 int value = PyObjGetInt(obj, true, ok);
388 389 if (ok && value==0) {
389 390 // TODOXXX is this wise? or should it be expected from the programmer to use None?
390 391 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
391 392 }
392 393 }
393 394 }
394 395 } else {
395 396 // not a pointer
396 397 switch (info.typeId) {
397 398 case QMetaType::Char:
398 399 {
399 400 int val = PyObjGetInt(obj, strict, ok);
400 401 if (ok) {
401 402 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, char, val, ptr);
402 403 }
403 404 }
404 405 break;
405 406 case QMetaType::UChar:
406 407 {
407 408 int val = PyObjGetInt(obj, strict, ok);
408 409 if (ok) {
409 410 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned char, val, ptr);
410 411 }
411 412 }
412 413 break;
413 414 case QMetaType::Short:
414 415 {
415 416 int val = PyObjGetInt(obj, strict, ok);
416 417 if (ok) {
417 418 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
418 419 }
419 420 }
420 421 break;
421 422 case QMetaType::UShort:
422 423 {
423 424 int val = PyObjGetInt(obj, strict, ok);
424 425 if (ok) {
425 426 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned short, val, ptr);
426 427 }
427 428 }
428 429 break;
429 430 case QMetaType::Long:
430 431 {
431 432 long val = (long)PyObjGetLongLong(obj, strict, ok);
432 433 if (ok) {
433 434 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, long, val, ptr);
434 435 }
435 436 }
436 437 break;
437 438 case QMetaType::ULong:
438 439 {
439 440 unsigned long val = (unsigned long)PyObjGetLongLong(obj, strict, ok);
440 441 if (ok) {
441 442 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned long, val, ptr);
442 443 }
443 444 }
444 445 break;
445 446 case QMetaType::Bool:
446 447 {
447 448 bool val = PyObjGetBool(obj, strict, ok);
448 449 if (ok) {
449 450 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, bool, val, ptr);
450 451 }
451 452 }
452 453 break;
453 454 case QMetaType::Int:
454 455 {
455 456 int val = PyObjGetInt(obj, strict, ok);
456 457 if (ok) {
457 458 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, int, val, ptr);
458 459 }
459 460 }
460 461 break;
461 462 case QMetaType::UInt:
462 463 {
463 464 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
464 465 if (ok) {
465 466 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
466 467 }
467 468 }
468 469 break;
469 470 case QMetaType::QChar:
470 471 {
471 472 int val = PyObjGetInt(obj, strict, ok);
472 473 if (ok) {
473 474 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
474 475 }
475 476 }
476 477 break;
477 478 case QMetaType::Float:
478 479 {
479 480 float val = (float)PyObjGetDouble(obj, strict, ok);
480 481 if (ok) {
481 482 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, float, val, ptr);
482 483 }
483 484 }
484 485 break;
485 486 case QMetaType::Double:
486 487 {
487 488 double val = (double)PyObjGetDouble(obj, strict, ok);
488 489 if (ok) {
489 490 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, double, val, ptr);
490 491 }
491 492 }
492 493 break;
493 494 case QMetaType::LongLong:
494 495 {
495 496 qint64 val = PyObjGetLongLong(obj, strict, ok);
496 497 if (ok) {
497 498 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, qint64, val, ptr);
498 499 }
499 500 }
500 501 break;
501 502 case QMetaType::ULongLong:
502 503 {
503 504 quint64 val = PyObjGetULongLong(obj, strict, ok);
504 505 if (ok) {
505 506 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, quint64, val, ptr);
506 507 }
507 508 }
508 509 break;
509 510 case QMetaType::QByteArray:
510 511 {
511 512 QByteArray bytes = PyObjGetBytes(obj, strict, ok);
512 513 if (ok) {
513 514 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(bytes), ptr);
514 515 ptr = (void*)((QVariant*)ptr)->constData();
515 516 }
516 517 }
517 518 break;
518 519 case QMetaType::QString:
519 520 {
520 521 QString str = PyObjGetString(obj, strict, ok);
521 522 if (ok) {
522 523 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str), ptr);
523 524 ptr = (void*)((QVariant*)ptr)->constData();
524 525 }
525 526 }
526 527 break;
527 528 case QMetaType::QStringList:
528 529 {
529 530 QStringList l = PyObjToStringList(obj, strict, ok);
530 531 if (ok) {
531 532 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(l), ptr);
532 533 ptr = (void*)((QVariant*)ptr)->constData();
533 534 }
534 535 }
535 536 break;
536 537
537 538 case PythonQtMethodInfo::Variant:
538 539 {
539 540 QVariant v = PyObjToQVariant(obj);
540 541 // the only case where conversion can fail it None and we want to pass that to, e.g. setProperty(),
541 542 // so we do not check v.isValid() here
542 543 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
543 544 }
544 545 break;
545 546 default:
546 547 {
547 548 // check for enum case
548 549 if (info.enumWrapper) {
549 550 unsigned int val;
550 551 ok = false;
551 552 if ((PyObject*)obj->ob_type == info.enumWrapper) {
552 553 // we have a exact enum type match:
553 554 val = PyInt_AS_LONG(obj);
554 555 ok = true;
555 556 } else if (!strict) {
556 557 // we try to get any integer, when not being strict. If we are strict, integers are not wanted because
557 558 // we want an integer overload to be taken first!
558 559 val = (unsigned int)PyObjGetLongLong(obj, false, ok);
559 560 }
560 561 if (ok) {
561 562 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
562 563 return ptr;
563 564 } else {
564 565 return NULL;
565 566 }
566 567 }
567 568
568 569 if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
569 570 // check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant
570 571 if (info.name.startsWith("QList<")) {
571 572 QByteArray innerType = info.name.mid(6,info.name.length()-7);
572 573 if (innerType.endsWith("*")) {
573 574 innerType.truncate(innerType.length()-1);
574 575 static int id = QMetaType::type("QList<void*>");
575 576 if (!alreadyAllocatedCPPObject) {
576 577 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(id), ptr);
577 578 ptr = (void*)((QVariant*)ptr)->constData();
578 579 } else {
579 580 ptr = alreadyAllocatedCPPObject;
580 581 }
581 582 ok = ConvertPythonListToQListOfPointerType(obj, (QList<void*>*)ptr, innerType, strict);
582 583 if (ok) {
583 584 return ptr;
584 585 } else {
585 586 return NULL;
586 587 }
587 588 }
588 589 }
589 590 }
590 591
591 592 // We only do this for registered type > QMetaType::User for performance reasons.
592 593 if (info.typeId >= QMetaType::User) {
593 594 // Maybe we have a special converter that is registered for that type:
594 595 PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(info.typeId);
595 596 if (converter) {
596 597 if (!alreadyAllocatedCPPObject) {
597 598 // create a new empty variant of concrete type:
598 599 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
599 600 ptr = (void*)((QVariant*)ptr)->constData();
600 601 } else {
601 602 ptr = alreadyAllocatedCPPObject;
602 603 }
603 604 // now call the converter, passing the internal object of the variant
604 605 ok = (*converter)(obj, ptr, info.typeId, strict);
605 606 if (ok) {
606 607 return ptr;
607 608 } else {
608 609 return NULL;
609 610 }
610 611 }
611 612 }
612 613 // if no type id is available, conversion to a QVariant makes no sense/is not possible
613 614 if (info.typeId != PythonQtMethodInfo::Unknown) {
614 615 // for all other types, we use the same qvariant conversion and pass out the constData of the variant:
615 616 QVariant v = PyObjToQVariant(obj, info.typeId);
616 617 if (v.isValid()) {
617 618 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
618 619 ptr = (void*)((QVariant*)ptr)->constData();
619 620 }
620 621 }
621 622 }
622 623 }
623 624 }
624 625 return ptr;
625 626 }
626 627
627 628
628 629 QStringList PythonQtConv::PyObjToStringList(PyObject* val, bool strict, bool& ok) {
629 630 QStringList v;
630 631 ok = false;
631 632 // if we are strict, we do not want to convert a string to a stringlist
632 633 // (strings in python are detected to be sequences)
633 634 if (strict &&
634 635 (val->ob_type == &PyString_Type ||
635 636 PyUnicode_Check(val))) {
636 637 ok = false;
637 638 return v;
638 639 }
639 640 if (PySequence_Check(val)) {
640 641 int count = PySequence_Size(val);
641 642 for (int i = 0;i<count;i++) {
642 643 PyObject* value = PySequence_GetItem(val,i);
643 644 v.append(PyObjGetString(value,false,ok));
644 645 }
645 646 ok = true;
646 647 }
647 648 return v;
648 649 }
649 650
650 651 QString PythonQtConv::PyObjGetRepresentation(PyObject* val)
651 652 {
652 653 QString r;
653 654 PyObject* str = PyObject_Repr(val);
654 655 if (str) {
655 656 r = QString(PyString_AS_STRING(str));
656 657 Py_DECREF(str);
657 658 }
658 659 return r;
659 660 }
660 661
661 662 QString PythonQtConv::PyObjGetString(PyObject* val, bool strict, bool& ok) {
662 663 QString r;
663 664 ok = true;
664 665 if (val->ob_type == &PyString_Type) {
665 666 r = QString(PyString_AS_STRING(val));
666 667 } else if (PyUnicode_Check(val)) {
667 668 #ifdef WIN32
668 669 r = QString::fromUtf16(PyUnicode_AS_UNICODE(val));
669 670 #else
670 671 PyObject *ptmp = PyUnicode_AsUTF8String(val);
671 672 if(ptmp) {
672 673 r = QString::fromUtf8(PyString_AS_STRING(ptmp));
673 674 Py_DECREF(ptmp);
674 675 }
675 676 #endif
676 677 } else if (!strict) {
677 678 // EXTRA: could also use _Unicode, but why should we?
678 679 PyObject* str = PyObject_Str(val);
679 680 if (str) {
680 681 r = QString(PyString_AS_STRING(str));
681 682 Py_DECREF(str);
682 683 } else {
683 684 ok = false;
684 685 }
685 686 } else {
686 687 ok = false;
687 688 }
688 689 return r;
689 690 }
690 691
691 692 QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) {
693 // TODO: support buffer objects in general
692 694 QByteArray r;
693 695 ok = true;
694 696 if (val->ob_type == &PyString_Type) {
695 697 long size = PyString_GET_SIZE(val);
696 698 r = QByteArray(PyString_AS_STRING(val), size);
697 699 } else {
698 700 ok = false;
699 701 }
700 702 return r;
701 703 }
702 704
703 705 bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) {
704 706 bool d = false;
705 707 ok = false;
706 708 if (val == Py_False) {
707 709 d = false;
708 710 ok = true;
709 711 } else if (val == Py_True) {
710 712 d = true;
711 713 ok = true;
712 714 } else if (!strict) {
713 715 d = PyObjGetInt(val, false, ok)!=0;
714 716 ok = true;
715 717 }
716 718 return d;
717 719 }
718 720
719 721 int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) {
720 722 int d = 0;
721 723 ok = true;
722 724 if (val->ob_type == &PyInt_Type) {
723 725 d = PyInt_AS_LONG(val);
724 726 } else if (!strict) {
725 727 if (PyObject_TypeCheck(val, &PyInt_Type)) {
726 728 // support for derived int classes, e.g. for our enums
727 729 d = PyInt_AS_LONG(val);
728 730 } else if (val->ob_type == &PyFloat_Type) {
729 731 d = floor(PyFloat_AS_DOUBLE(val));
730 732 } else if (val->ob_type == &PyLong_Type) {
731 733 // handle error on overflow!
732 734 d = PyLong_AsLong(val);
733 735 } else if (val == Py_False) {
734 736 d = 0;
735 737 } else if (val == Py_True) {
736 738 d = 1;
737 739 } else {
738 740 ok = false;
739 741 }
740 742 } else {
741 743 ok = false;
742 744 }
743 745 return d;
744 746 }
745 747
746 748 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
747 749 qint64 d = 0;
748 750 ok = true;
749 751 if (val->ob_type == &PyInt_Type) {
750 752 d = PyInt_AS_LONG(val);
751 753 } else if (val->ob_type == &PyLong_Type) {
752 754 d = PyLong_AsLongLong(val);
753 755 } else if (!strict) {
754 756 if (PyObject_TypeCheck(val, &PyInt_Type)) {
755 757 // support for derived int classes, e.g. for our enums
756 758 d = PyInt_AS_LONG(val);
757 759 } else if (val->ob_type == &PyFloat_Type) {
758 760 d = floor(PyFloat_AS_DOUBLE(val));
759 761 } else if (val == Py_False) {
760 762 d = 0;
761 763 } else if (val == Py_True) {
762 764 d = 1;
763 765 } else {
764 766 ok = false;
765 767 }
766 768 } else {
767 769 ok = false;
768 770 }
769 771 return d;
770 772 }
771 773
772 774 quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) {
773 775 quint64 d = 0;
774 776 ok = true;
775 777 if (PyObject_TypeCheck(val, &PyInt_Type)) {
776 778 d = PyInt_AS_LONG(val);
777 779 } else if (val->ob_type == &PyLong_Type) {
778 780 d = PyLong_AsLongLong(val);
779 781 } else if (!strict) {
780 782 if (PyObject_TypeCheck(val, &PyInt_Type)) {
781 783 // support for derived int classes, e.g. for our enums
782 784 d = PyInt_AS_LONG(val);
783 785 } else if (val->ob_type == &PyFloat_Type) {
784 786 d = floor(PyFloat_AS_DOUBLE(val));
785 787 } else if (val == Py_False) {
786 788 d = 0;
787 789 } else if (val == Py_True) {
788 790 d = 1;
789 791 } else {
790 792 ok = false;
791 793 }
792 794 } else {
793 795 ok = false;
794 796 }
795 797 return d;
796 798 }
797 799
798 800 double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) {
799 801 double d = 0;
800 802 ok = true;
801 803 if (val->ob_type == &PyFloat_Type) {
802 804 d = PyFloat_AS_DOUBLE(val);
803 805 } else if (!strict) {
804 806 if (PyObject_TypeCheck(val, &PyInt_Type)) {
805 807 d = PyInt_AS_LONG(val);
806 808 } else if (val->ob_type == &PyLong_Type) {
807 809 d = PyLong_AsLong(val);
808 810 } else if (val == Py_False) {
809 811 d = 0;
810 812 } else if (val == Py_True) {
811 813 d = 1;
812 814 } else {
813 815 ok = false;
814 816 }
815 817 } else {
816 818 ok = false;
817 819 }
818 820 return d;
819 821 }
820 822
821 823 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
822 824 {
823 825 QVariant v;
824 826 bool ok = true;
825 827
826 828 if (type==-1) {
827 829 // no special type requested
828 830 if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) {
829 831 type = QVariant::String;
830 832 } else if (PyObject_TypeCheck(val, &PyInt_Type)) {
831 833 type = QVariant::Int;
832 834 } else if (val->ob_type==&PyLong_Type) {
833 835 type = QVariant::LongLong;
834 836 } else if (val->ob_type==&PyFloat_Type) {
835 837 type = QVariant::Double;
836 838 } else if (val == Py_False || val == Py_True) {
837 839 type = QVariant::Bool;
838 840 } else if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
839 841 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
840 842 // c++ wrapper, check if the class names of the c++ objects match
841 843 if (wrap->classInfo()->isCPPWrapper()) {
842 844 if (wrap->classInfo()->metaTypeId()>0) {
843 845 // construct a new variant from the C++ object if it has a meta type (this will COPY the object!)
844 846 v = QVariant(wrap->classInfo()->metaTypeId(), wrap->_wrappedPtr);
845 847 } else {
846 848 // TODOXXX we could as well check if there is a registered meta type for "classname*", so that we may pass
847 849 // the pointer here...
848 850 // is this worth anything? we loose the knowledge of the cpp object type
849 851 v = qVariantFromValue(wrap->_wrappedPtr);
850 852 }
851 853 } else {
852 854 // this gives us a QObject pointer
853 855 QObject* myObject = wrap->_obj;
854 856 v = qVariantFromValue(myObject);
855 857 }
856 858 return v;
857 859 } else if (val->ob_type==&PyDict_Type) {
858 860 type = QVariant::Map;
859 861 } else if (val->ob_type==&PyList_Type || val->ob_type==&PyTuple_Type || PySequence_Check(val)) {
860 862 type = QVariant::List;
861 863 } else if (val == Py_None) {
862 864 // none is invalid
863 865 type = QVariant::Invalid;
864 866 } else {
865 867 // this used to be:
866 868 // type = QVariant::String;
867 869 // but now we want to transport the Python Objects directly:
868 870 PythonQtObjectPtr o(val);
869 871 v = qVariantFromValue(o);
870 872 return v;
871 873 }
872 874 }
873 875 // special type request:
874 876 switch (type) {
875 877 case QVariant::Invalid:
876 878 return v;
877 879 break;
878 880 case QVariant::Int:
879 881 {
880 882 int d = PyObjGetInt(val, false, ok);
881 883 if (ok) return QVariant(d);
882 884 }
883 885 break;
884 886 case QVariant::UInt:
885 887 {
886 888 int d = PyObjGetInt(val, false,ok);
887 889 if (ok) v = QVariant((unsigned int)d);
888 890 }
889 891 break;
890 892 case QVariant::Bool:
891 893 {
892 894 int d = PyObjGetBool(val,false,ok);
893 895 if (ok) v = QVariant((bool)(d!=0));
894 896 }
895 897 break;
896 898 case QVariant::Double:
897 899 {
898 900 double d = PyObjGetDouble(val,false,ok);
899 901 if (ok) v = QVariant(d);
900 902 break;
901 903 }
902 904 case QMetaType::Float:
903 905 {
904 906 float d = (float) PyObjGetDouble(val,false,ok);
905 907 if (ok) v = qVariantFromValue(d);
906 908 break;
907 909 }
908 910 case QMetaType::Long:
909 911 {
910 912 long d = (long) PyObjGetLongLong(val,false,ok);
911 913 if (ok) v = qVariantFromValue(d);
912 914 break;
913 915 }
914 916 case QMetaType::ULong:
915 917 {
916 918 unsigned long d = (unsigned long) PyObjGetLongLong(val,false,ok);
917 919 if (ok) v = qVariantFromValue(d);
918 920 break;
919 921 }
920 922 case QMetaType::LongLong:
921 923 {
922 924 qint64 d = PyObjGetLongLong(val, false, ok);
923 925 if (ok) v = qVariantFromValue(d);
924 926 }
925 927 break;
926 928 case QMetaType::ULongLong:
927 929 {
928 930 quint64 d = PyObjGetULongLong(val, false, ok);
929 931 if (ok) v = qVariantFromValue(d);
930 932 }
931 933 break;
932 934 case QMetaType::Short:
933 935 {
934 936 short d = (short) PyObjGetInt(val,false,ok);
935 937 if (ok) v = qVariantFromValue(d);
936 938 break;
937 939 }
938 940 case QMetaType::UShort:
939 941 {
940 942 unsigned short d = (unsigned short) PyObjGetInt(val,false,ok);
941 943 if (ok) v = qVariantFromValue(d);
942 944 break;
943 945 }
944 946 case QMetaType::Char:
945 947 {
946 948 char d = (char) PyObjGetInt(val,false,ok);
947 949 if (ok) v = qVariantFromValue(d);
948 950 break;
949 951 }
950 952 case QMetaType::UChar:
951 953 {
952 954 unsigned char d = (unsigned char) PyObjGetInt(val,false,ok);
953 955 if (ok) v = qVariantFromValue(d);
954 956 break;
955 957 }
956 958
957 959 case QVariant::ByteArray:
958 960 case QVariant::String:
959 961 {
960 962 bool ok;
961 963 v = QVariant(PyObjGetString(val, false, ok));
962 964 }
963 965 break;
964 966
965 967 // these are important for MeVisLab
966 968 case QVariant::Map:
967 969 {
968 970 if (PyMapping_Check(val)) {
969 971 QMap<QString,QVariant> map;
970 972 PyObject* items = PyMapping_Items(val);
971 973 if (items) {
972 974 int count = PyList_Size(items);
973 975 PyObject* value;
974 976 PyObject* key;
975 977 PyObject* tuple;
976 978 for (int i = 0;i<count;i++) {
977 979 tuple = PyList_GetItem(items,i);
978 980 key = PyTuple_GetItem(tuple, 0);
979 981 value = PyTuple_GetItem(tuple, 1);
980 982 map.insert(PyObjGetString(key), PyObjToQVariant(value,-1));
981 983 }
982 984 Py_DECREF(items);
983 985 v = map;
984 986 }
985 987 }
986 988 }
987 989 break;
988 990 case QVariant::List:
989 991 if (PySequence_Check(val)) {
990 992 QVariantList list;
991 993 int count = PySequence_Size(val);
992 994 PyObject* value;
993 995 for (int i = 0;i<count;i++) {
994 996 value = PySequence_GetItem(val,i);
995 997 list.append(PyObjToQVariant(value, -1));
996 998 }
997 999 v = list;
998 1000 }
999 1001 break;
1000 1002 case QVariant::StringList:
1001 1003 {
1002 1004 bool ok;
1003 1005 QStringList l = PyObjToStringList(val, false, ok);
1004 1006 if (ok) {
1005 1007 v = l;
1006 1008 }
1007 1009 }
1008 1010 break;
1009 1011
1010 1012 default:
1011 1013 if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
1012 1014 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
1013 1015 if (wrap->classInfo()->isCPPWrapper() && wrap->classInfo()->metaTypeId() == type) {
1014 1016 // construct a new variant from the C++ object if it has the same meta type
1015 1017 v = QVariant(type, wrap->_wrappedPtr);
1016 1018 } else {
1017 1019 v = QVariant();
1018 1020 }
1019 1021 } else {
1020 1022 v = QVariant();
1021 1023 }
1022 1024 }
1023 1025 return v;
1024 1026 }
1025 1027
1026 1028 PyObject* PythonQtConv::QStringToPyObject(const QString& str)
1027 1029 {
1028 1030 if (str.isNull()) {
1029 1031 return PyString_FromString("");
1030 1032 } else {
1031 1033 #ifdef WIN32
1032 1034 // return PyString_FromString(str.toLatin1().data());
1033 1035 return PyUnicode_FromUnicode(str.utf16(), str.length());
1034 1036 #else
1035 1037 return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, NULL, NULL);
1036 1038 #endif
1037 1039 }
1038 1040 }
1039 1041
1040 1042 PyObject* PythonQtConv::QStringListToPyObject(const QStringList& list)
1041 1043 {
1042 1044 PyObject* result = PyTuple_New(list.count());
1043 1045 int i = 0;
1044 1046 QString str;
1045 1047 foreach (str, list) {
1046 1048 PyTuple_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(str));
1047 1049 i++;
1048 1050 }
1049 1051 // why is the error state bad after this?
1050 1052 PyErr_Clear();
1051 1053 return result;
1052 1054 }
1053 1055
1054 1056 PyObject* PythonQtConv::QStringListToPyList(const QStringList& list)
1055 1057 {
1056 1058 PyObject* result = PyList_New(list.count());
1057 1059 int i = 0;
1058 1060 for (QStringList::ConstIterator it = list.begin(); it!=list.end(); ++it) {
1059 1061 PyList_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(*it));
1060 1062 i++;
1061 1063 }
1062 1064 return result;
1063 1065 }
1064 1066
1065 1067 PyObject* PythonQtConv::QVariantToPyObject(const QVariant& v)
1066 1068 {
1067 1069 return ConvertQtValueToPythonInternal(v.userType(), (void*)v.constData());
1068 1070 }
1069 1071
1070 1072 PyObject* PythonQtConv::QVariantMapToPyObject(const QVariantMap& m) {
1071 1073 PyObject* result = PyDict_New();
1072 1074 QVariantMap::const_iterator t = m.constBegin();
1073 1075 PyObject* key;
1074 1076 PyObject* val;
1075 1077 for (;t!=m.end();t++) {
1076 1078 key = QStringToPyObject(t.key());
1077 1079 val = QVariantToPyObject(t.value());
1078 1080 PyDict_SetItem(result, key, val);
1079 1081 Py_DECREF(key);
1080 1082 Py_DECREF(val);
1081 1083 }
1082 1084 return result;
1083 1085 }
1084 1086
1085 1087 PyObject* PythonQtConv::QVariantListToPyObject(const QVariantList& l) {
1086 1088 PyObject* result = PyTuple_New(l.count());
1087 1089 int i = 0;
1088 1090 QVariant v;
1089 1091 foreach (v, l) {
1090 1092 PyTuple_SET_ITEM(result, i, PythonQtConv::QVariantToPyObject(v));
1091 1093 i++;
1092 1094 }
1093 1095 // why is the error state bad after this?
1094 1096 PyErr_Clear();
1095 1097 return result;
1096 1098 }
1097 1099
1098 1100 PyObject* PythonQtConv::ConvertQListOfPointerTypeToPythonList(QList<void*>* list, const QByteArray& typeName)
1099 1101 {
1100 1102 PyObject* result = PyTuple_New(list->count());
1101 1103 int i = 0;
1102 1104 foreach (void* value, *list) {
1103 1105 PyTuple_SET_ITEM(result, i, PythonQt::priv()->wrapPtr(value, typeName));
1104 1106 i++;
1105 1107 }
1106 1108 return result;
1107 1109 }
1108 1110
1109 1111 bool PythonQtConv::ConvertPythonListToQListOfPointerType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool /*strict*/)
1110 1112 {
1111 1113 bool result = false;
1112 1114 if (PySequence_Check(obj)) {
1113 1115 result = true;
1114 1116 int count = PySequence_Size(obj);
1115 1117 PyObject* value;
1116 1118 for (int i = 0;i<count;i++) {
1117 1119 value = PySequence_GetItem(obj,i);
1118 1120 if (PyObject_TypeCheck(value, &PythonQtInstanceWrapper_Type)) {
1119 1121 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)value;
1120 1122 bool ok;
1121 1123 void* object = castWrapperTo(wrap, type, ok);
1122 1124 if (ok) {
1123 1125 list->append(object);
1124 1126 } else {
1125 1127 result = false;
1126 1128 break;
1127 1129 }
1128 1130 }
1129 1131 }
1130 1132 }
1131 1133 return result;
1132 1134 }
1133 1135
1134 1136 int PythonQtConv::getInnerTemplateMetaType(const QByteArray& typeName)
1135 1137 {
1136 1138 int idx = typeName.indexOf("<");
1137 1139 if (idx>0) {
1138 1140 int idx2 = typeName.indexOf(">");
1139 1141 if (idx2>0) {
1140 1142 QByteArray innerType = typeName.mid(idx+1,idx2-idx-1);
1141 1143 return QMetaType::type(innerType.constData());
1142 1144 }
1143 1145 }
1144 1146 return QMetaType::Void;
1145 1147 }
1146 1148
1147 1149
1148 1150 QString PythonQtConv::CPPObjectToString(int type, const void* data) {
1149 1151 QString r;
1150 1152 switch (type) {
1151 1153 case QVariant::Size: {
1152 1154 const QSize* s = static_cast<const QSize*>(data);
1153 1155 r = QString::number(s->width()) + ", " + QString::number(s->height());
1154 1156 }
1155 1157 break;
1156 1158 case QVariant::SizeF: {
1157 1159 const QSizeF* s = static_cast<const QSizeF*>(data);
1158 1160 r = QString::number(s->width()) + ", " + QString::number(s->height());
1159 1161 }
1160 1162 break;
1161 1163 case QVariant::Point: {
1162 1164 const QPoint* s = static_cast<const QPoint*>(data);
1163 1165 r = QString::number(s->x()) + ", " + QString::number(s->y());
1164 1166 }
1165 1167 break;
1166 1168 case QVariant::PointF: {
1167 1169 const QPointF* s = static_cast<const QPointF*>(data);
1168 1170 r = QString::number(s->x()) + ", " + QString::number(s->y());
1169 1171 }
1170 1172 break;
1171 1173 case QVariant::Rect: {
1172 1174 const QRect* s = static_cast<const QRect*>(data);
1173 1175 r = QString::number(s->x()) + ", " + QString::number(s->y());
1174 1176 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1175 1177 }
1176 1178 break;
1177 1179 case QVariant::RectF: {
1178 1180 const QRectF* s = static_cast<const QRectF*>(data);
1179 1181 r = QString::number(s->x()) + ", " + QString::number(s->y());
1180 1182 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1181 1183 }
1182 1184 break;
1183 1185 case QVariant::Date: {
1184 1186 const QDate* s = static_cast<const QDate*>(data);
1185 1187 r = s->toString(Qt::ISODate);
1186 1188 }
1187 1189 break;
1188 1190 case QVariant::DateTime: {
1189 1191 const QDateTime* s = static_cast<const QDateTime*>(data);
1190 1192 r = s->toString(Qt::ISODate);
1191 1193 }
1192 1194 break;
1193 1195 case QVariant::Time: {
1194 1196 const QTime* s = static_cast<const QTime*>(data);
1195 1197 r = s->toString(Qt::ISODate);
1196 1198 }
1197 1199 break;
1198 1200 case QVariant::Pixmap:
1199 1201 {
1200 1202 const QPixmap* s = static_cast<const QPixmap*>(data);
1201 1203 r = QString("Pixmap ") + QString::number(s->width()) + ", " + QString::number(s->height());
1202 1204 }
1203 1205 break;
1204 1206 case QVariant::Image:
1205 1207 {
1206 1208 const QImage* s = static_cast<const QImage*>(data);
1207 1209 r = QString("Image ") + QString::number(s->width()) + ", " + QString::number(s->height());
1208 1210 }
1209 1211 break;
1210 1212 case QVariant::Url:
1211 1213 {
1212 1214 const QUrl* s = static_cast<const QUrl*>(data);
1213 1215 r = s->toString();
1214 1216 }
1215 1217 break;
1216 1218 //TODO: add more printing for other variant types
1217 1219 default:
1218 1220 // this creates a copy, but that should not be expensive for typical simple variants
1219 1221 // (but we do not want to do this for our won user types!
1220 1222 if (type>0 && type < (int)QVariant::UserType) {
1221 1223 QVariant v(type, data);
1222 1224 r = v.toString();
1223 1225 }
1224 1226 }
1225 1227 return r;
1226 1228 }
@@ -1,509 +1,509
1 1 #ifndef _PYTHONQTDOC_H
2 2 #define _PYTHONQTDOC_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtDoc.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-10
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 /*!
46 46 \if USE_GLOBAL_DOXYGEN_DOC
47 47 \page PythonQtPage PythonQt Overview
48 48 \else
49 49 \mainpage PythonQt Overview
50 50 \endif
51 51
52 52 \section Introduction
53 53
54 54 \b PythonQt is a dynamic Python (http://www.python.org) binding for the Qt framework (http://qt.nokia.com).
55 55 It offers an easy way to embed the Python scripting language into
56 56 your C++ Qt applications. It makes heavy use of the QMetaObject system and thus requires Qt4.x.
57 57
58 58 The focus of PythonQt is on embedding Python into an existing C++ application, not on writing the whole
59 59 application completely in Python. If you want to write your whole application in Python,
60 60 you should use <a href="http://www.riverbankcomputing.co.uk/pyqt/">PyQt</a> or <a href="http://www.pyside.org">PySide</a> instead.
61 61
62 62 If you are looking for a simple way to embed Python objects into your C++/Qt Application
63 63 and to script parts of your application via Python, PythonQt is the way to go!
64 64
65 65 PythonQt is a stable library that was developed to make the
66 66 Image Processing and Visualization platform MeVisLab (http://www.mevislab.de)
67 67 scriptable from Python.
68 68
69 69 \section Download
70 70
71 71 PythonQt is hosted on SourceForge at http://sourceforge.net/projects/pythonqt , you can access it via SVN
72 72 or download a tarball.
73 73
74 74 \section Licensing
75 75
76 76 PythonQt is distributed under the LGPL license, so it pairs well with the LGPL of the Qt 4.5 release and allows
77 77 to be used in commercial applications when following the LGPL 2.1 obligations.
78 78
79 79 \section LicensingWrapper Licensing of Wrapper Generator
80 80
81 81 The build system of PythonQt makes use of a modified version of the LGPL'ed QtScript generator,
82 82 located in the "generator" directory.
83 83
84 84 See http://qt.gitorious.org/qt-labs/qtscriptgenerator for details on the original project.
85 85 Thanks a lot to the QtJambi guys and the QtScript Generator project for the C++ parser and
86 86 Qt typesystem files!
87 87
88 88 The PythonQt wrappers generated by the generator located in the "generated_cpp" directory are free to be used without any licensing restrictions.
89 89
90 90 The generated wrappers are pre-generated and checked-in for Qt 4.6.1, so you only need to build and run the
91 91 generator when you want to build additional wrappers or you want to upgrade/downgrade to another Qt version.
92 92 You may use the generator to generate C++ bindings for your own C++ classes (e.g., to make them inheritable in Python),
93 93 , but this is currently not documented and involves creating your own typesystem files (although the Qt Jambi examples might help you).
94 94
95 95 \section Features
96 96
97 97 The following are the built-in features of the PythonQt library:
98 98
99 99 - Access all \b slots, \b properties, children and registered enums of any QObject derived class from Python
100 100 - Connecting Qt Signals to Python functions (both from within Python and from C++)
101 101 - Easy wrapping of Python objects from C++ with smart, reference-counting PythonQtObjectPtr.
102 102 - Convenient conversions to/from QVariant for PythonQtObjectPtr.
103 103 - Wrapping of C++ objects (which are not derived from QObject) via PythonQtCppWrapperFactory
104 104 - Extending C++ and QObject derived classes with additional slots, static methods and constructors (see Decorators)
105 105 - StdOut/Err redirection to Qt signals instead of cout
106 106 - Interface for creating your own \c import replacement, so that Python scripts can be e.g. signed/verified before they are executed (PythonQtImportFileInterface)
107 107 - Mapping of plain-old-datatypes and ALL QVariant types to and from Python
108 108 - Support for wrapping of user QVariant types which are registerd via QMetaType
109 109 - Support for Qt namespace (with all enumerators)
110 110 - All PythonQt wrapped objects support the dir() statement, so that you can see easily which attributes a QObject, CPP object or QVariant has
111 111 - No preprocessing/wrapping tool needs to be started, PythonQt can script any QObject without prior knowledge about it (except for the MetaObject information from the \b moc)
112 112 - Multiple inheritance for C++ objects (e.g. a QWidget is derived from QObject and QPaintDevice, PythonQt will automatically cast a QWidget to a QPaintDevice when needed)
113 113 - Polymorphic downcasting (if e.g. PythonQt sees a QEvent, it can downcast it depending on the type(), so the Python e.g. sees a QPaintEvent instead of a plain QEvent)
114 114 - Deriving C++ objects from Python and overwriting virtual method with a Python implementation (requires usage of wrapper generator or manual work!)
115 115 - Extensible handler for Python/C++ conversion of complex types, e.g. mapping of QVector<SomeObject> to/from a Python array
116 116
117 117 \section FeaturesQtAll Features (with PythonQt_QtAll linked in)
118 118
119 119 Thanks to the new wrapper generator, PythonQt now offers the additional PythonQt_QtAll library which wraps the complete Qt API, including all C++ classes and all non-slots on QObject derived classes.
120 120 This offers the following features:
121 121
122 122 - Complete Qt API wrapped and accessible
123 123 - The following modules are available as submodules of the PythonQt module:
124 124 - QtCore
125 125 - QtGui
126 126 - QtNetwork
127 127 - QtOpenGL
128 128 - QtSql
129 129 - QtSvg
130 130 - QtUiTools
131 131 - QtWebKit
132 132 - QtXml
133 133 - QtXmlPatterns
134 134 - (phonon, QtHelp, assistant, designer are currently not supported, this would require some additional effort on the code generator)
135 135 - For convenience, all classes are also available in the PythonQt.Qt module, for people who do not care in which module a class is located
136 136 - Any Qt class that has virtual methods can be easily derived from Python and the virtual methods can be reimplemented in Python
137 137 - Polymorphic downcasting on QEvent, QGraphicsItem, QStyleOption, ...
138 138 - Multiple inheritance support (e.g., QGraphicsTextItem is a QObject AND a QGraphicsItem, PythonQt will handle this well)
139 139
140 140 \section Comparision Comparision with PyQt/PySide
141 141
142 142 - PythonQt is not as Pythonic as PyQt in many details (e.g. buffer protocol, pickling, translation support, ...) and it is mainly thought for embedding and intercommunication between Qt/Cpp and Python
143 143 - PythonQt allows to communicate in both directions, e.g., calling a Python object from C++ AND calling a C++ method from Python, while PyQt only handles the Python->C++ direction
144 144 - PythonQt offers properties as Python attributes, while PyQt offers them as setter/getter methods (e.g. QWidget.width is a property in PythonQt and a method in PyQt)
145 145 - PythonQt does not support instanceof checks for Qt classes, except for the exact match and derived Python classes
146 146 - QObject.emit to emit Qt signals from Python is not yet implemented but PythonQt allows to just emit a signal by calling it
147 147 - PythonQt does not (yet) offer to add new signals to Python/C++ objects
148 148 - Ownership of objects is a bit different in PythonQt, currently Python classes derived from a C++ class need to be manually referenced in Python to not get deleted too early (this will be fixed)
149 - QString and QBytearray are always converted to unicode and str Python objects (PyQt returns QString and QByteArray instead).
149 - QStrings are always converted to unicode Python objects (PyQt returns QString instead), we prefered to return Python strings.
150 150 - Probably there are lots of details that differ, I do not know PyQt that well to list them all.
151 151
152 152 \section Interface
153 153
154 154 The main interface to PythonQt is the PythonQt singleton.
155 155 PythonQt needs to be initialized via PythonQt::init() once.
156 156 Afterwards you communicate with the singleton via PythonQt::self().
157 157 PythonQt offers a complete Qt binding, which
158 158 needs to be enabled via PythonQt_QtAll::init().
159 159
160 160
161 161 \section Datatype Datatype Mapping
162 162
163 163 The following table shows the mapping between Python and Qt objects:
164 164 <table>
165 165 <tr><th>Qt/C++</th><th>Python</th></tr>
166 166 <tr><td>bool</td><td>bool</td></tr>
167 167 <tr><td>double</td><td>float</td></tr>
168 168 <tr><td>float</td><td>float</td></tr>
169 169 <tr><td>char/uchar,int/uint,short,ushort,QChar</td><td>integer</td></tr>
170 170 <tr><td>long</td><td>integer</td></tr>
171 171 <tr><td>ulong,longlong,ulonglong</td><td>long</td></tr>
172 172 <tr><td>QString</td><td>unicode string</td></tr>
173 173 <tr><td>QByteArray</td><td>str</td></tr>
174 174 <tr><td>char*</td><td>str</td></tr>
175 175 <tr><td>QStringList</td><td>tuple of unicode strings</td></tr>
176 176 <tr><td>QVariantList</td><td>tuple of objects</td></tr>
177 177 <tr><td>QVariantMap</td><td>dict of objects</td></tr>
178 178 <tr><td>QVariant</td><td>depends on type, see below</td></tr>
179 179 <tr><td>QSize, QRect and all other standard Qt QVariants</td><td>variant wrapper that supports complete API of the respective Qt classes</td></tr>
180 180 <tr><td>OwnRegisteredMetaType</td><td>C++ wrapper, optionally with additional information/wrapping provided by registerCPPClass()</td></tr>
181 181 <tr><td>QList<AnyObject*></td><td>converts to a list of CPP wrappers</td></tr>
182 182 <tr><td>EnumType</td><td>integer (all enums that are known via the moc and the Qt namespace are supported)</td></tr>
183 183 <tr><td>QObject (and derived classes)</td><td>QObject wrapper</td></tr>
184 184 <tr><td>C++ object</td><td>CPP wrapper, either wrapped via PythonQtCppWrapperFactory or just decorated with decorators</td></tr>
185 185 <tr><td>PyObject</td><td>PyObject</td></tr>
186 186 </table>
187 187
188 188 PyObject is passed as simple pointer, which allows to pass/return any Python Object directly to/from
189 189 a Qt slot.
190 190 QVariants are mapped recursively as given above, e.g. a dictionary can
191 191 contain lists of dictionaries of doubles.
192 192 For example a QVariant of type "String" is mapped to a python unicode string.
193 193 All Qt QVariant types are implemented, PythonQt supports the complete Qt API for these object.
194 194
195 195 \section QObject QObject Wrapping
196 196
197 197 All classes derived from QObject are automatically wrapped with a python wrapper class
198 198 when they become visible to the Python interpreter. This can happen via
199 199 - the PythonQt::addObject() method
200 200 - when a Qt \b slot returns a QObject derived object to python
201 201 - when a Qt \b signal contains a QObject and is connected to a python function
202 202
203 203 It is important that you call PythonQt::registerClass() for any QObject derived class
204 204 that may become visible to Python, except when you add it via PythonQt::addObject().
205 205 This will register the complete parent hierachy of the registered class, so that
206 206 when you register e.g. a QPushButton, QWidget will be registered as well (and all intermediate
207 207 parents).
208 208
209 209 From Python, you can talk to the returned QObjects in a natural way by calling
210 210 their slots and receiving the return values. You can also read/write all
211 211 properties of the objects as if they where normal python properties.
212 212
213 213 In addition to this, the wrapped objects support
214 214 - className() - returns a string that reprents the classname of the QObject
215 215 - help() - shows all properties, slots, enums, decorator slots and constructors of the object, in a printable form
216 216 - delete() - deletes the object (use with care, especially if you passed the ownership to C++)
217 217 - connect(signal, function) - connect the signal of the given object to a python function
218 218 - connect(signal, qobject, slot) - connect the signal of the given object to a slot of another QObject
219 219 - disconnect(signal, function) - disconnect the signal of the given object from a python function
220 220 - disconnect(signal, qobject, slot) - disconnect the signal of the given object from a slot of another QObject
221 221 - children() - returns the children of the object
222 222 - setParent(QObject) - set the parent
223 223 - QObject* parent() - get the parent
224 224
225 225 The below example shows how to connect signals in Python:
226 226
227 227 \code
228 228 # define a signal handler function
229 229 def someFunction(flag):
230 230 print flag
231 231
232 232 # button1 is a QPushButton that has been added to Python via addObject()
233 233 # connect the clicked signal to a python function:
234 234 button1.connect("clicked(bool)", someFunction)
235 235
236 236 \endcode
237 237
238 238 \section CPP CPP Wrapping
239 239
240 240 You can create dedicated wrapper QObjects for any C++ class. This is done by deriving from PythonQtCppWrapperFactory
241 241 and adding your factory via addWrapperFactory().
242 242 Whenever PythonQt encounters a CPP pointer (e.g. on a slot or signal)
243 243 and it does not known it as a QObject derived class, it will create a generic CPP wrapper. So even unknown C++ objects
244 244 can be passed through Python. If the wrapper factory supports the CPP class, a QObject wrapper will be created for each
245 245 instance that enters Python. An alternative to a complete wrapper via the wrapper factory are decorators, see \ref Decorators
246 246
247 247 \section MetaObject Meta Object/Class access
248 248
249 249 For each known C++ class, PythonQt provides a Python class. These classes are visible
250 250 inside of the "PythonQt" python module or in subpackages if a package is given when the class is registered.
251 251
252 252 A Meta class supports:
253 253
254 254 - access to all declared enum values
255 255 - constructors
256 256 - static methods
257 257 - unbound non-static methods
258 258 - help() and className()
259 259
260 260 From within Python, you can import the module "PythonQt" to access these classes and the Qt namespace.
261 261
262 262 \code
263 263 from PythonQt import QtCore
264 264
265 265 # namespace access:
266 266 print QtCore.Qt.AlignLeft
267 267
268 268 # constructors
269 269 a = QtCore.QSize(12,13)
270 270 b = QtCore.QFont()
271 271
272 272 # static method
273 273 QtCore.QDate.currentDate()
274 274
275 275 # enum value
276 276 QtCore.QFont.UltraCondensed
277 277
278 278 \endcode
279 279
280 280 \section Decorators Decorator slots
281 281
282 282 PythonQt introduces a new generic approach to extend any wrapped QObject or CPP object with
283 283
284 284 - constructors
285 285 - destructors (for CPP objects)
286 286 - additional slots
287 287 - static slots (callable on both the Meta object and the instances)
288 288
289 289 The idea behind decorators is that we wanted to make it as easy as possible to extend
290 290 wrapped objects. Since we already have an implementation for invoking any Qt Slot from
291 291 Python, it looked promising to use this approach for the extension of wrapped objects as well.
292 292 This avoids that the PythonQt user needs to care about how Python arguments are mapped from/to
293 293 Qt when he wants to create static methods, constructors and additional member functions.
294 294
295 295 The basic idea about decorators is to create a QObject derived class that implements slots
296 296 which take one of the above roles (e.g. constructor, destructor etc.) via a naming convention.
297 297 These slots are then assigned to other classes via the naming convention.
298 298
299 299 - SomeClassName* new_SomeClassName(...) - defines a constructor for "SomeClassName" that returns a new object of type SomeClassName (where SomeClassName can be any CPP class, not just QObject classes)
300 300 - void delete_SomeClassName(SomeClassName* o) - defines a destructor, which should delete the passed in object o
301 301 - anything static_SomeClassName_someMethodName(...) - defines a static method that is callable on instances and the meta class
302 302 - anything someMethodName(SomeClassName* o, ...) - defines a slot that will be available on SomeClassName instances (and derived instances). When such a slot is called the first argument is the pointer to the instance and the rest of the arguments can be used to make a call on the instance.
303 303
304 304 The below example shows all kinds of decorators in action:
305 305
306 306 \code
307 307
308 308 // an example CPP object
309 309 class YourCPPObject {
310 310 public:
311 311 YourCPPObject(int arg1, float arg2) { a = arg1; b = arg2; }
312 312
313 313 float doSomething(int arg1) { return arg1*a*b; };
314 314
315 315 private:
316 316
317 317 int a;
318 318 float b;
319 319 };
320 320
321 321 // an example decorator
322 322 class ExampleDecorator : public QObject
323 323 {
324 324 Q_OBJECT
325 325
326 326 public slots:
327 327 // add a constructor to QSize that takes a QPoint
328 328 QSize* new_QSize(const QPoint& p) { return new QSize(p.x(), p.y()); }
329 329
330 330 // add a constructor for QPushButton that takes a text and a parent widget
331 331 QPushButton* new_QPushButton(const QString& text, QWidget* parent=NULL) { return new QPushButton(text, parent); }
332 332
333 333 // add a constructor for a CPP object
334 334 YourCPPObject* new_YourCPPObject(int arg1, float arg2) { return new YourCPPObject(arg1, arg2); }
335 335
336 336 // add a destructor for a CPP object
337 337 void delete_YourCPPObject(YourCPPObject* obj) { delete obj; }
338 338
339 339 // add a static method to QWidget
340 340 QWidget* static_QWidget_mouseGrabber() { return QWidget::mouseGrabber(); }
341 341
342 342 // add an additional slot to QWidget (make move() callable, which is not declared as a slot in QWidget)
343 343 void move(QWidget* w, const QPoint& p) { w->move(p); }
344 344
345 345 // add an additional slot to QWidget, overloading the above move method
346 346 void move(QWidget* w, int x, int y) { w->move(x,y); }
347 347
348 348 // add a method to your own CPP object
349 349 int doSomething(YourCPPObject* obj, int arg1) { return obj->doSomething(arg1); }
350 350 };
351 351
352 352 ...
353 353
354 354 PythonQt::self()->addDecorators(new ExampleDecorator());
355 355 PythonQt::self()->registerCPPClass("YourCPPObject");
356 356
357 357 \endcode
358 358
359 359 After you have registered an instance of the above ExampleDecorator, you can do the following from Python
360 360 (all these calls are mapped to the above decorator slots):
361 361
362 362 \code
363 363 from PythonQt import QtCore, QtGui, YourCPPObject
364 364
365 365 # call our new constructor of QSize
366 366 size = QtCore.QSize(QPoint(1,2));
367 367
368 368 # call our new QPushButton constructor
369 369 button = QtGui.QPushButton("sometext");
370 370
371 371 # call the move slot (overload1)
372 372 button.move(QPoint(0,0))
373 373
374 374 # call the move slot (overload2)
375 375 button.move(0,0)
376 376
377 377 # call the static method
378 378 grabber = QtGui.QWidget.mouseWrapper();
379 379
380 380 # create a CPP object via constructor
381 381 yourCpp = YourCPPObject(1,11.5)
382 382
383 383 # call the wrapped method on CPP object
384 384 print yourCpp.doSomething(1);
385 385
386 386 # destructor will be called:
387 387 yourCpp = None
388 388
389 389 \endcode
390 390
391 391 \section Building
392 392
393 393 PythonQt requires Qt 4.6.1 (or higher) and Python 2.5 or 2.6 on Windows, Linux and MacOS X. It has not yet been tested with Python 3.x, but it should only require minor changes.
394 394 To compile PythonQt, you will need a python developer installation which includes Python's header files and
395 395 the python2x.[lib | dll | so | dynlib].
396 396 The build scripts a currently set to use Python 2.5.
397 397 You may need to tweak the \b build/python.prf file to set the correct Python includes and libs on your system.
398 398
399 399 \subsection Windows
400 400
401 401 On Windows, the (non-source) Python Windows installer can be used.
402 402 Make sure that you use the same compiler, the current Python distribution is built
403 403 with Visual Studio 2003. If you want to use another compiler, you will need to build
404 404 Python yourself, using your compiler.
405 405
406 406 To build PythonQt, you need to set the environment variable \b PYTHON_PATH to point to the root
407 407 dir of the python installation and \b PYTHON_LIB to point to
408 408 the directory where the python lib file is located.
409 409
410 410 When using the prebuild Python installer, this will be:
411 411
412 412 \code
413 413 > set PYTHON_PATH = c:\Python25
414 414 > set PYTHON_LIB = c:\Python25\libs
415 415 \endcode
416 416
417 417 When using the python sources, this will be something like:
418 418
419 419 \code
420 420 > set PYTHON_PATH = c:\yourDir\Python-2.5.1\
421 421 > set PYTHON_LIB = c:\yourDir\Python-2.5.1\PCbuild8\Win32
422 422 \endcode
423 423
424 424 To build all, do the following (after setting the above variables):
425 425
426 426 \code
427 427 > cd PythonQtRoot
428 428 > vcvars32
429 429 > qmake
430 430 > nmake
431 431 \endcode
432 432
433 433 This should build everything. If Python can not be linked or include files can not be found,
434 434 you probably need to tweak \b build/python.prf
435 435
436 436 The tests and examples are located in PythonQt/lib.
437 437
438 438 \subsection Linux
439 439
440 440 On Linux, you need to install a Python-dev package.
441 441 If Python can not be linked or include files can not be found,
442 442 you probably need to tweak \b build/python.prf
443 443
444 444 To build PythonQt, just do a:
445 445
446 446 \code
447 447 > cd PythonQtRoot
448 448 > qmake
449 449 > make all
450 450 \endcode
451 451
452 452 The tests and examples are located in PythonQt/lib.
453 453 You should add PythonQt/lib to your LD_LIBRARY_PATH so that the runtime
454 454 linker can find the *.so files.
455 455
456 456 \subsection MacOsX
457 457
458 458 On Mac, Python is installed as a Framework, so you should not need to install it.
459 459 To build PythonQt, just do a:
460 460
461 461 \code
462 462 > cd PythonQtRoot
463 463 > qmake
464 464 > make all
465 465 \endcode
466 466
467 467 \section Tests
468 468
469 469 There is a unit test that tests most features of PythonQt, see the \b tests subdirectory for details.
470 470
471 471 \section Examples
472 472
473 473 Examples are available in the \b examples directory. The PyScriptingConsole implements a simple
474 474 interactive scripting console that shows how to script a simple application.
475 475
476 476 The following shows how to integrate PythonQt into you Qt application:
477 477
478 478 \code
479 479 #include "PythonQt.h"
480 480 #include <QApplication>
481 481 ...
482 482
483 483 int main( int argc, char **argv )
484 484 {
485 485
486 486 QApplication qapp(argc, argv);
487 487
488 488 // init PythonQt and Python itself
489 489 PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
490 490
491 491
492 492 // get a smart pointer to the __main__ module of the Python interpreter
493 493 PythonQtObjectPtr mainContext = PythonQt::self()->getMainModule();
494 494
495 495 // add a QObject as variable of name "example" to the namespace of the __main__ module
496 496 PyExampleObject example;
497 497 PythonQt::self()->addObject(mainContext, "example", &example);
498 498
499 499 // do something
500 500 PythonQt::self()->runScript(mainContext, "print example\n");
501 501 PythonQt::self()->runScript(mainContext, "def multiply(a,b):\n return a*b;\n");
502 502 QVariantList args;
503 503 args << 42 << 47;
504 504 QVariant result = PythonQt::self()->call(mainContext,"multiply", args);
505 505 ...
506 506 \endcode
507 507
508 508
509 509 */
@@ -1,715 +1,726
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtInstanceWrapper.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtInstanceWrapper.h"
43 43 #include <QObject>
44 44 #include "PythonQt.h"
45 45 #include "PythonQtSlot.h"
46 46 #include "PythonQtClassInfo.h"
47 47 #include "PythonQtConversion.h"
48 48 #include "PythonQtClassWrapper.h"
49 49
50 50 PythonQtClassInfo* PythonQtInstanceWrapperStruct::classInfo()
51 51 {
52 52 // take the class info from our type object
53 53 return ((PythonQtClassWrapper*)ob_type)->_classInfo;
54 54 }
55 55
56 56 static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, bool force = false) {
57 57
58 58 // is this a C++ wrapper?
59 59 if (self->_wrappedPtr) {
60 60 //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
61 61
62 62 PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr);
63 63 // we own our qobject, so we delete it now:
64 64 delete self->_obj;
65 65 self->_obj = NULL;
66 66 if (force || self->classInfo()->hasOwnerMethodButNoOwner(self->_wrappedPtr) || self->_ownedByPythonQt) {
67 67 int type = self->classInfo()->metaTypeId();
68 68 if (self->_useQMetaTypeDestroy && type>=0) {
69 69 // use QMetaType to destroy the object
70 70 QMetaType::destroy(type, self->_wrappedPtr);
71 71 } else {
72 72 PythonQtSlotInfo* slot = self->classInfo()->destructor();
73 73 if (slot) {
74 74 void* args[2];
75 75 args[0] = NULL;
76 76 args[1] = &self->_wrappedPtr;
77 77 slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, slot->slotIndex(), args);
78 78 self->_wrappedPtr = NULL;
79 79 } else {
80 80 if (type>=0) {
81 81 // use QMetaType to destroy the object
82 82 QMetaType::destroy(type, self->_wrappedPtr);
83 83 } else {
84 84 // TODO: warn about not being able to destroy the object?
85 85 }
86 86 }
87 87 }
88 88 }
89 89 } else {
90 90 //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
91 91 if (self->_objPointerCopy) {
92 92 PythonQt::priv()->removeWrapperPointer(self->_objPointerCopy);
93 93 }
94 94 if (self->_obj) {
95 95 if (force || self->_ownedByPythonQt) {
96 96 if (force || !self->_obj->parent()) {
97 97 delete self->_obj;
98 98 }
99 99 } else {
100 100 if (self->_obj->parent()==NULL) {
101 101 // tell someone who is interested that the qobject is no longer wrapped, if it has no parent
102 102 PythonQt::qObjectNoLongerWrappedCB(self->_obj);
103 103 }
104 104 }
105 105 }
106 106 }
107 107 self->_obj = NULL;
108 108 }
109 109
110 110 static void PythonQtInstanceWrapper_dealloc(PythonQtInstanceWrapper* self)
111 111 {
112 112 PythonQtInstanceWrapper_deleteObject(self);
113 113 self->_obj.~QPointer<QObject>();
114 114 self->ob_type->tp_free((PyObject*)self);
115 115 }
116 116
117 117 static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
118 118 {
119 119 //PythonQtClassWrapper *classType = (PythonQtClassWrapper*)type;
120 120 PythonQtInstanceWrapper *self;
121 121 static PyObject* emptyTuple = NULL;
122 122 if (emptyTuple==NULL) {
123 123 emptyTuple = PyTuple_New(0);
124 124 }
125 125
126 126 self = (PythonQtInstanceWrapper*)PyBaseObject_Type.tp_new(type, emptyTuple, NULL);
127 127
128 128 if (self != NULL) {
129 129 new (&self->_obj) QPointer<QObject>();
130 130 self->_wrappedPtr = NULL;
131 131 self->_ownedByPythonQt = false;
132 132 self->_useQMetaTypeDestroy = false;
133 133 self->_isShellInstance = false;
134 134 }
135 135 return (PyObject *)self;
136 136 }
137 137
138 138 int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds)
139 139 {
140 140 if (args == PythonQtPrivate::dummyTuple()) {
141 141 // we are called from the internal PythonQt API, so our data will be filled later on...
142 142 return 0;
143 143 }
144 144
145 145 // we are called from python, try to construct our object
146 146 if (self->classInfo()->constructors()) {
147 147 void* directCPPPointer = NULL;
148 148 PythonQtSlotFunction_CallImpl(self->classInfo(), NULL, self->classInfo()->constructors(), args, kwds, NULL, &directCPPPointer);
149 149 if (PyErr_Occurred()) {
150 150 return -1;
151 151 }
152 152 if (directCPPPointer) {
153 153 // change ownershipflag to be owned by PythonQt
154 154 self->_ownedByPythonQt = true;
155 155 self->_useQMetaTypeDestroy = false;
156 156 if (self->classInfo()->isCPPWrapper()) {
157 157 self->_wrappedPtr = directCPPPointer;
158 158 // TODO xxx: if there is a wrapper factory, we might want to generate a wrapper for our class?!
159 159 } else {
160 160 self->setQObject((QObject*)directCPPPointer);
161 161 }
162 162 // register with PythonQt
163 163 PythonQt::priv()->addWrapperPointer(directCPPPointer, self);
164 164
165 165 PythonQtShellSetInstanceWrapperCB* cb = self->classInfo()->shellSetInstanceWrapperCB();
166 166 if (cb) {
167 167 // if we are a derived python class, we set the wrapper
168 168 // to activate the shell class, otherwise we just ignore that it is a shell...
169 169 // we detect it be checking if the type does not have PythonQtInstanceWrapper_Type as direct base class,
170 170 // which is the case for all non-python derived types
171 171 if (((PyObject*)self)->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
172 172 // set the wrapper and remember that we have a shell instance!
173 173 (*cb)(directCPPPointer, self);
174 174 self->_isShellInstance = true;
175 175 }
176 176 }
177 177 }
178 178 } else {
179 179 QString error = QString("No constructors available for ") + self->classInfo()->className();
180 180 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
181 181 return -1;
182 182 }
183 183 return 0;
184 184 }
185 185
186 186 static PyObject *PythonQtInstanceWrapper_richcompare(PythonQtInstanceWrapper* wrapper, PyObject* other, int code)
187 187 {
188 188 bool validPtrs = false;
189 189 bool areSamePtrs = false;
190 190 if (PyObject_TypeCheck((PyObject*)wrapper, &PythonQtInstanceWrapper_Type)) {
191 191 if (PyObject_TypeCheck(other, &PythonQtInstanceWrapper_Type)) {
192 192 validPtrs = true;
193 193 PythonQtInstanceWrapper* w1 = wrapper;
194 194 PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)other;
195 195 // check pointers directly
196 196 if (w1->_wrappedPtr != NULL) {
197 197 if (w1->_wrappedPtr == w2->_wrappedPtr) {
198 198 areSamePtrs = true;
199 199 }
200 200 } else if (w1->_obj == w2->_obj) {
201 201 areSamePtrs = true;
202 202 }
203 203 } else if (other == Py_None) {
204 204 validPtrs = true;
205 205 if (wrapper->_obj || wrapper->_wrappedPtr) {
206 206 areSamePtrs = false;
207 207 } else {
208 208 areSamePtrs = true;
209 209 }
210 210 }
211 211 }
212 212
213 213 if ((wrapper->classInfo()->typeSlots() & PythonQt::Type_RichCompare) == 0) {
214 214 // shortcut if richcompare is not supported:
215 215 if (validPtrs && code == Py_EQ) {
216 216 return PythonQtConv::GetPyBool(areSamePtrs);
217 217 } else if (validPtrs && code == Py_NE) {
218 218 return PythonQtConv::GetPyBool(!areSamePtrs);
219 219 }
220 220 Py_INCREF(Py_NotImplemented);
221 221 return Py_NotImplemented;
222 222 }
223 223
224 224 QByteArray memberName;
225 225 switch (code) {
226 226 case Py_LT:
227 227 {
228 228 static QByteArray name = "__lt__";
229 229 memberName = name;
230 230 }
231 231 break;
232 232
233 233 case Py_LE:
234 234 {
235 235 static QByteArray name = "__le__";
236 236 memberName = name;
237 237 }
238 238 break;
239 239
240 240 case Py_EQ:
241 241 {
242 242 static QByteArray name = "__eq__";
243 243 memberName = name;
244 244 }
245 245 break;
246 246
247 247 case Py_NE:
248 248 {
249 249 static QByteArray name = "__ne__";
250 250 memberName = name;
251 251 }
252 252 break;
253 253
254 254 case Py_GT:
255 255 {
256 256 static QByteArray name = "__gt__";
257 257 memberName = name;
258 258 }
259 259 break;
260 260
261 261 case Py_GE:
262 262 {
263 263 static QByteArray name = "__ge__";
264 264 memberName = name;
265 265 }
266 266 break;
267 267 }
268 268
269 269 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
270 270 if (opSlot._type == PythonQtMemberInfo::Slot) {
271 271 // TODO get rid of tuple
272 272 PyObject* args = PyTuple_New(1);
273 273 Py_INCREF(other);
274 274 PyTuple_SET_ITEM(args, 0, other);
275 275 PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr);
276 276 Py_DECREF(args);
277 277 return result;
278 278 } else {
279 279 // not implemented, let python try something else!
280 280 Py_INCREF(Py_NotImplemented);
281 281 return Py_NotImplemented;
282 282 }
283 283 }
284 284
285 285
286 286 static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* obj)
287 287 {
288 288 return PyString_FromString(obj->ob_type->tp_name);
289 289 }
290 290
291 291 static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* obj)
292 292 {
293 293 return PythonQt::self()->helpCalled(obj->classInfo());
294 294 }
295 295
296 296 static PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self)
297 297 {
298 298 PythonQtInstanceWrapper_deleteObject(self, true);
299 299 Py_INCREF(Py_None);
300 300 return Py_None;
301 301 }
302 302
303 303
304 304 static PyMethodDef PythonQtInstanceWrapper_methods[] = {
305 305 {"className", (PyCFunction)PythonQtInstanceWrapper_classname, METH_NOARGS,
306 306 "Return the classname of the object"
307 307 },
308 308 {"help", (PyCFunction)PythonQtInstanceWrapper_help, METH_NOARGS,
309 309 "Shows the help of available methods for this class"
310 310 },
311 311 {"delete", (PyCFunction)PythonQtInstanceWrapper_delete, METH_NOARGS,
312 312 "Deletes the C++ object (at your own risk, my friend!)"
313 313 },
314 314 {NULL, NULL, 0, NULL} /* Sentinel */
315 315 };
316 316
317 317
318 318 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
319 319 {
320 320 const char *attributeName;
321 321 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
322 322
323 323 if ((attributeName = PyString_AsString(name)) == NULL) {
324 324 return NULL;
325 325 }
326 326
327 327 if (qstrcmp(attributeName, "__dict__")==0) {
328 328 PyObject* dict = PyBaseObject_Type.tp_getattro(obj, name);
329 329 dict = PyDict_Copy(dict);
330 330
331 331 if (wrapper->_obj) {
332 332 // only the properties are missing, the rest is already available from
333 333 // PythonQtClassWrapper...
334 334 QStringList l = wrapper->classInfo()->propertyList();
335 335 foreach (QString name, l) {
336 336 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
337 337 if (o) {
338 338 PyDict_SetItemString(dict, name.toLatin1().data(), o);
339 339 Py_DECREF(o);
340 340 } else {
341 341 std::cerr << "PythonQtInstanceWrapper: something is wrong, could not get attribute " << name.toLatin1().data();
342 342 }
343 343 }
344 344
345 345 QList<QByteArray> dynamicProps = wrapper->_obj->dynamicPropertyNames();
346 346 foreach (QByteArray name, dynamicProps) {
347 347 PyObject* o = PyObject_GetAttrString(obj, name.data());
348 348 if (o) {
349 349 PyDict_SetItemString(dict, name.data(), o);
350 350 Py_DECREF(o);
351 351 } else {
352 352 std::cerr << "PythonQtInstanceWrapper: dynamic property could not be read " << name.data();
353 353 }
354 354 }
355 355 }
356 356 // Note: we do not put children into the dict, is would look confusing?!
357 357 return dict;
358 358 }
359 359
360 360 // first look in super, to return derived methods from base object first
361 361 PyObject* superAttr = PyBaseObject_Type.tp_getattro(obj, name);
362 362 if (superAttr) {
363 363 return superAttr;
364 364 }
365 365 PyErr_Clear();
366 366
367 367 // mlabDebugConst("Python","get " << attributeName);
368 368
369 369 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
370 370 switch (member._type) {
371 371 case PythonQtMemberInfo::Property:
372 372 if (wrapper->_obj) {
373 373 if (member._property.userType() != QVariant::Invalid) {
374 374 return PythonQtConv::QVariantToPyObject(member._property.read(wrapper->_obj));
375 375 } else {
376 376 Py_INCREF(Py_None);
377 377 return Py_None;
378 378 }
379 379 } else {
380 380 QString error = QString("Trying to read property '") + attributeName + "' from a destroyed " + wrapper->classInfo()->className() + " object";
381 381 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
382 382 return NULL;
383 383 }
384 384 break;
385 385 case PythonQtMemberInfo::Slot:
386 386 return PythonQtSlotFunction_New(member._slot, obj, NULL);
387 387 break;
388 388 case PythonQtMemberInfo::EnumValue:
389 389 {
390 390 PyObject* enumValue = member._enumValue;
391 391 Py_INCREF(enumValue);
392 392 return enumValue;
393 393 }
394 394 break;
395 395 case PythonQtMemberInfo::EnumWrapper:
396 396 {
397 397 PyObject* enumWrapper = member._enumWrapper;
398 398 Py_INCREF(enumWrapper);
399 399 return enumWrapper;
400 400 }
401 401 break;
402 402 case PythonQtMemberInfo::NotFound:
403 403 {
404 404 static const QByteArray getterString("py_get_");
405 405 // check for a getter slot
406 406 PythonQtMemberInfo member = wrapper->classInfo()->member(getterString + attributeName);
407 407 if (member._type == PythonQtMemberInfo::Slot) {
408 408 return PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, member._slot, NULL, NULL, wrapper->_wrappedPtr);
409 409 }
410 410
411 411 // handle dynamic properties
412 412 if (wrapper->_obj) {
413 413 QVariant v = wrapper->_obj->property(attributeName);
414 414 if (v.isValid()) {
415 415 return PythonQtConv::QVariantToPyObject(v);
416 416 }
417 417 }
418 418 }
419 419 break;
420 420 default:
421 421 // is an invalid type, go on
422 422 break;
423 423 }
424 424
425 425 // look for the internal methods (className(), help())
426 426 PyObject* internalMethod = Py_FindMethod( PythonQtInstanceWrapper_methods, obj, (char*)attributeName);
427 427 if (internalMethod) {
428 428 return internalMethod;
429 429 }
430 430 PyErr_Clear();
431 431
432 432 if (wrapper->_obj) {
433 433 // look for a child
434 434 QObjectList children = wrapper->_obj->children();
435 435 for (int i = 0; i < children.count(); i++) {
436 436 QObject *child = children.at(i);
437 437 if (child->objectName() == attributeName) {
438 438 return PythonQt::priv()->wrapQObject(child);
439 439 }
440 440 }
441 441 }
442 442
443 443 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
444 444 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
445 445 return NULL;
446 446 }
447 447
448 448 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
449 449 {
450 450 QString error;
451 451 const char *attributeName;
452 452 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
453 453
454 454 if ((attributeName = PyString_AsString(name)) == NULL)
455 455 return -1;
456 456
457 457 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
458 458 if (member._type == PythonQtMemberInfo::Property) {
459 459
460 460 if (!wrapper->_obj) {
461 461 error = QString("Trying to set property '") + attributeName + "' on a destroyed " + wrapper->classInfo()->className() + " object";
462 462 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
463 463 return -1;
464 464 }
465 465
466 466 QMetaProperty prop = member._property;
467 467 if (prop.isWritable()) {
468 468 QVariant v;
469 469 if (prop.isEnumType()) {
470 470 // this will give us either a string or an int, everything else will probably be an error
471 471 v = PythonQtConv::PyObjToQVariant(value);
472 472 } else {
473 473 int t = prop.userType();
474 474 v = PythonQtConv::PyObjToQVariant(value, t);
475 475 }
476 476 bool success = false;
477 477 if (v.isValid()) {
478 478 success = prop.write(wrapper->_obj, v);
479 479 }
480 480 if (success) {
481 481 return 0;
482 482 } else {
483 483 error = QString("Property '") + attributeName + "' of type '" +
484 484 prop.typeName() + "' does not accept an object of type "
485 485 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
486 486 }
487 487 } else {
488 488 error = QString("Property '") + attributeName + "' of " + obj->ob_type->tp_name + " object is not writable";
489 489 }
490 490 } else if (member._type == PythonQtMemberInfo::Slot) {
491 491 error = QString("Slot '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
492 492 } else if (member._type == PythonQtMemberInfo::EnumValue) {
493 493 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
494 494 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
495 495 error = QString("Enum '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
496 496 } else if (member._type == PythonQtMemberInfo::NotFound) {
497 497 // check for a setter slot
498 498 static const QByteArray setterString("py_set_");
499 499 PythonQtMemberInfo setter = wrapper->classInfo()->member(setterString + attributeName);
500 500 if (setter._type == PythonQtMemberInfo::Slot) {
501 501 // call the setter and ignore the result value
502 502 void* result;
503 503 PyObject* args = PyTuple_New(1);
504 504 Py_INCREF(value);
505 505 PyTuple_SET_ITEM(args, 0, value);
506 506 PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, setter._slot, args, NULL, wrapper->_wrappedPtr, &result);
507 507 Py_DECREF(args);
508 508 return 0;
509 509 }
510 510
511 511 // handle dynamic properties
512 512 if (wrapper->_obj) {
513 513 QVariant prop = wrapper->_obj->property(attributeName);
514 514 if (prop.isValid()) {
515 515 QVariant v = PythonQtConv::PyObjToQVariant(value);
516 516 if (v.isValid()) {
517 517 wrapper->_obj->setProperty(attributeName, v);
518 518 return 0;
519 519 } else {
520 520 error = QString("Dynamic property '") + attributeName + "' does not accept an object of type "
521 521 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
522 522 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
523 523 return -1;
524 524 }
525 525 }
526 526 }
527 527
528 528 // if we are a derived python class, we allow setting attributes.
529 529 // if we are a direct CPP wrapper, we do NOT allow it, since
530 530 // it would be confusing to allow it because a wrapper will go away when it is not seen by python anymore
531 531 // and when it is recreated from a CPP pointer the attributes are gone...
532 532 if (obj->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
533 533 return PyBaseObject_Type.tp_setattro(obj,name,value);
534 534 } else {
535 535 error = QString("'") + attributeName + "' does not exist on " + obj->ob_type->tp_name + " and creating new attributes on C++ objects is not allowed";
536 536 }
537 537 }
538 538
539 539 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
540 540 return -1;
541 541 }
542 542
543 543 static QString getStringFromObject(PythonQtInstanceWrapper* wrapper) {
544 544 QString result;
545 545 if (wrapper->_wrappedPtr) {
546 546 // first try some manually string conversions for some variants
547 547 int metaid = wrapper->classInfo()->metaTypeId();
548 548 result = PythonQtConv::CPPObjectToString(metaid, wrapper->_wrappedPtr);
549 549 if (!result.isEmpty()) {
550 550 return result;
551 551 }
552 552 }
553 553 // next, try to call py_toString
554 554 PythonQtMemberInfo info = wrapper->classInfo()->member("py_toString");
555 555 if (info._type == PythonQtMemberInfo::Slot) {
556 556 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, NULL, NULL, wrapper->_wrappedPtr);
557 557 if (resultObj) {
558 558 // TODO this is one conversion too much, would be nicer to call the slot directly...
559 559 result = PythonQtConv::PyObjGetString(resultObj);
560 560 Py_DECREF(resultObj);
561 561 }
562 562 }
563 563 return result;
564 564 }
565 565
566 566 static PyObject * PythonQtInstanceWrapper_str(PyObject * obj)
567 567 {
568 568 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
569
570 // QByteArray should be directly returned as a str
571 if (wrapper->classInfo()->metaTypeId()==QVariant::ByteArray) {
572 QByteArray* b = (QByteArray*) wrapper->_wrappedPtr;
573 if (b->data()) {
574 return PyString_FromStringAndSize(b->data(), b->size());
575 } else {
576 return PyString_FromString("");
577 }
578 }
579
569 580 const char* typeName = obj->ob_type->tp_name;
570 581 QObject *qobj = wrapper->_obj;
571 582 QString str = getStringFromObject(wrapper);
572 583 if (!str.isEmpty()) {
573 584 return PyString_FromFormat("%s", str.toLatin1().constData());
574 585 }
575 586 if (wrapper->_wrappedPtr) {
576 587 if (wrapper->_obj) {
577 588 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
578 589 } else {
579 590 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
580 591 }
581 592 } else {
582 593 return PyString_FromFormat("%s (QObject %p)", typeName, qobj);
583 594 }
584 595 }
585 596
586 597 static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj)
587 598 {
588 599 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
589 600 const char* typeName = obj->ob_type->tp_name;
590 601
591 602 QObject *qobj = wrapper->_obj;
592 603 QString str = getStringFromObject(wrapper);
593 604 if (!str.isEmpty()) {
594 605 if (str.startsWith(typeName)) {
595 606 return PyString_FromFormat("%s", str.toLatin1().constData());
596 607 } else {
597 608 return PyString_FromFormat("%s(%s, %p)", typeName, str.toLatin1().constData(), wrapper->_wrappedPtr);
598 609 }
599 610 }
600 611 if (wrapper->_wrappedPtr) {
601 612 if (wrapper->_obj) {
602 613 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
603 614 } else {
604 615 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
605 616 }
606 617 } else {
607 618 return PyString_FromFormat("%s (%s %p)", typeName, wrapper->classInfo()->className(), qobj);
608 619 }
609 620 }
610 621
611 622 static int PythonQtInstanceWrapper_builtin_nonzero(PyObject *obj)
612 623 {
613 624 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
614 625 return (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
615 626 }
616 627
617 628
618 629 static long PythonQtInstanceWrapper_hash(PythonQtInstanceWrapper *obj)
619 630 {
620 631 if (obj->_wrappedPtr != NULL) {
621 632 return reinterpret_cast<long>(obj->_wrappedPtr);
622 633 } else {
623 634 QObject* qobj = obj->_obj; // get pointer from QPointer wrapper
624 635 return reinterpret_cast<long>(qobj);
625 636 }
626 637 }
627 638
628 639
629 640
630 641 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
631 642 static PyNumberMethods PythonQtInstanceWrapper_as_number = {
632 643 0, /* nb_add */
633 644 0, /* nb_subtract */
634 645 0, /* nb_multiply */
635 646 0, /* nb_divide */
636 647 0, /* nb_remainder */
637 648 0, /* nb_divmod */
638 649 0, /* nb_power */
639 650 0, /* nb_negative */
640 651 0, /* nb_positive */
641 652 0, /* nb_absolute */
642 653 PythonQtInstanceWrapper_builtin_nonzero, /* nb_nonzero */
643 654 0, /* nb_invert */
644 655 0, /* nb_lshift */
645 656 0, /* nb_rshift */
646 657 0, /* nb_and */
647 658 0, /* nb_xor */
648 659 0, /* nb_or */
649 660 0, /* nb_coerce */
650 661 0, /* nb_int */
651 662 0, /* nb_long */
652 663 0, /* nb_float */
653 664 0, /* nb_oct */
654 665 0, /* nb_hex */
655 666 0, /* nb_inplace_add */
656 667 0, /* nb_inplace_subtract */
657 668 0, /* nb_inplace_multiply */
658 669 0, /* nb_inplace_divide */
659 670 0, /* nb_inplace_remainder */
660 671 0, /* nb_inplace_power */
661 672 0, /* nb_inplace_lshift */
662 673 0, /* nb_inplace_rshift */
663 674 0, /* nb_inplace_and */
664 675 0, /* nb_inplace_xor */
665 676 0, /* nb_inplace_or */
666 677 0, /* nb_floor_divide */
667 678 0, /* nb_true_divide */
668 679 0, /* nb_inplace_floor_divide */
669 680 0, /* nb_inplace_true_divide */
670 681 };
671 682
672 683 PyTypeObject PythonQtInstanceWrapper_Type = {
673 684 PyObject_HEAD_INIT(&PythonQtClassWrapper_Type)
674 685 0, /*ob_size*/
675 686 "PythonQt.PythonQtInstanceWrapper", /*tp_name*/
676 687 sizeof(PythonQtInstanceWrapper), /*tp_basicsize*/
677 688 0, /*tp_itemsize*/
678 689 (destructor)PythonQtInstanceWrapper_dealloc, /*tp_dealloc*/
679 690 0, /*tp_print*/
680 691 0, /*tp_getattr*/
681 692 0, /*tp_setattr*/
682 693 0, /*tp_compare*/
683 694 PythonQtInstanceWrapper_repr, /*tp_repr*/
684 695 &PythonQtInstanceWrapper_as_number, /*tp_as_number*/
685 696 0, /*tp_as_sequence*/
686 697 0, /*tp_as_mapping*/
687 698 (hashfunc)PythonQtInstanceWrapper_hash, /*tp_hash */
688 699 0, /*tp_call*/
689 700 PythonQtInstanceWrapper_str, /*tp_str*/
690 701 PythonQtInstanceWrapper_getattro, /*tp_getattro*/
691 702 PythonQtInstanceWrapper_setattro, /*tp_setattro*/
692 703 0, /*tp_as_buffer*/
693 704 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
694 705 "PythonQtInstanceWrapper object", /* tp_doc */
695 706 0, /* tp_traverse */
696 707 0, /* tp_clear */
697 708 (richcmpfunc)PythonQtInstanceWrapper_richcompare, /* tp_richcompare */
698 709 0, /* tp_weaklistoffset */
699 710 0, /* tp_iter */
700 711 0, /* tp_iternext */
701 712 0, /* tp_methods */
702 713 0, /* tp_members */
703 714 0, /* tp_getset */
704 715 0, /* tp_base */
705 716 0, /* tp_dict */
706 717 0, /* tp_descr_get */
707 718 0, /* tp_descr_set */
708 719 0, /* tp_dictoffset */
709 720 (initproc)PythonQtInstanceWrapper_init, /* tp_init */
710 721 0, /* tp_alloc */
711 722 PythonQtInstanceWrapper_new, /* tp_new */
712 723 };
713 724
714 725 //-------------------------------------------------------
715 726
General Comments 0
You need to be logged in to leave comments. Login now