##// END OF EJS Templates
updated to upstream state in MeVisLab repository...
florianlink -
r157:78da86ccde11
parent child
Show More
@@ -1,1230 +1,1258
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtImporter.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include "PythonQtMethodInfo.h"
46 46 #include "PythonQtSignalReceiver.h"
47 47 #include "PythonQtConversion.h"
48 48 #include "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 84 PythonQtRegisterToolClassesTemplateConverter(QByteArray);
85 85 PythonQtRegisterToolClassesTemplateConverter(QDate);
86 86 PythonQtRegisterToolClassesTemplateConverter(QTime);
87 87 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
88 88 PythonQtRegisterToolClassesTemplateConverter(QUrl);
89 89 PythonQtRegisterToolClassesTemplateConverter(QLocale);
90 90 PythonQtRegisterToolClassesTemplateConverter(QRect);
91 91 PythonQtRegisterToolClassesTemplateConverter(QRectF);
92 92 PythonQtRegisterToolClassesTemplateConverter(QSize);
93 93 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
94 94 PythonQtRegisterToolClassesTemplateConverter(QLine);
95 95 PythonQtRegisterToolClassesTemplateConverter(QLineF);
96 96 PythonQtRegisterToolClassesTemplateConverter(QPoint);
97 97 PythonQtRegisterToolClassesTemplateConverter(QPointF);
98 98 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
99 99
100 100 PythonQtRegisterToolClassesTemplateConverter(QFont);
101 101 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
102 102 PythonQtRegisterToolClassesTemplateConverter(QBrush);
103 103 PythonQtRegisterToolClassesTemplateConverter(QColor);
104 104 PythonQtRegisterToolClassesTemplateConverter(QPalette);
105 105 PythonQtRegisterToolClassesTemplateConverter(QIcon);
106 106 PythonQtRegisterToolClassesTemplateConverter(QImage);
107 107 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
108 108 PythonQtRegisterToolClassesTemplateConverter(QRegion);
109 109 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
110 110 PythonQtRegisterToolClassesTemplateConverter(QCursor);
111 111 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
112 112 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
113 113 PythonQtRegisterToolClassesTemplateConverter(QPen);
114 114 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
115 115 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
116 116 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
117 117
118 118
119 119 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
120 120 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
121 121 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
122 122 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
123 123 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
124 124 for (unsigned int i = 0;i<16; i++) {
125 125 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
126 126 if (obj) {
127 127 PyModule_AddObject(pack, names[i], obj);
128 128 Py_INCREF(obj);
129 129 PyModule_AddObject(pack2, names[i], obj);
130 130 } else {
131 131 std::cerr << "method not found " << names[i];
132 132 }
133 133 }
134 134 }
135 135 }
136 136
137 137 void PythonQt::cleanup()
138 138 {
139 139 if (_self) {
140 140 delete _self;
141 141 _self = NULL;
142 142 }
143 143 }
144 144
145 145 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
146 146 {
147 147 _p = new PythonQtPrivate;
148 148 _p->_initFlags = flags;
149 149
150 150 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
151 151
152 152 if ((flags & PythonAlreadyInitialized) == 0) {
153 153 Py_SetProgramName("PythonQt");
154 154 if (flags & IgnoreSiteModule) {
155 155 // this prevents the automatic importing of Python site files
156 156 Py_NoSiteFlag = 1;
157 157 }
158 158 Py_Initialize();
159 159 }
160
160
161 161 // add our own python object types for qt object slots
162 162 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
163 163 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
164 164 }
165 165 Py_INCREF(&PythonQtSlotFunction_Type);
166 166
167 167 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
168 168 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
169 169 // add our own python object types for classes
170 170 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
171 171 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
172 172 }
173 173 Py_INCREF(&PythonQtClassWrapper_Type);
174 174
175 175 // add our own python object types for CPP instances
176 176 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
177 177 PythonQt::handleError();
178 178 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
179 179 }
180 180 Py_INCREF(&PythonQtInstanceWrapper_Type);
181 181
182 182 // add our own python object types for redirection of stdout
183 183 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
184 184 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
185 185 }
186 186 Py_INCREF(&PythonQtStdOutRedirectType);
187 187
188 188 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
189 189
190 190 _p->setupSharedLibrarySuffixes();
191 191
192 192 }
193 193
194 194 PythonQt::~PythonQt() {
195 195 delete _p;
196 196 _p = NULL;
197 197 }
198 198
199 199 PythonQtPrivate::~PythonQtPrivate() {
200 200 delete _defaultImporter;
201 201 _defaultImporter = NULL;
202 202
203 203 {
204 204 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
205 205 while (i.hasNext()) {
206 206 delete i.next().value();
207 207 }
208 208 }
209 209 PythonQtConv::global_valueStorage.clear();
210 210 PythonQtConv::global_ptrStorage.clear();
211 211 PythonQtConv::global_variantStorage.clear();
212 212
213 213 PythonQtMethodInfo::cleanupCachedMethodInfos();
214 214 }
215 215
216 216 PythonQtImportFileInterface* PythonQt::importInterface()
217 217 {
218 218 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
219 219 }
220 220
221 221 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
222 222 {
223 223 if (_self->_p->_noLongerWrappedCB) {
224 224 (*_self->_p->_noLongerWrappedCB)(o);
225 225 };
226 226 }
227 227
228 228 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
229 229 {
230 230 _p->registerClass(metaobject, package, wrapperCreator, shell);
231 231 }
232 232
233 233 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
234 234 {
235 235 // we register all classes in the hierarchy
236 236 const QMetaObject* m = metaobject;
237 237 bool first = true;
238 238 while (m) {
239 239 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
240 240 if (!info->pythonQtClassWrapper()) {
241 241 info->setTypeSlots(typeSlots);
242 242 info->setupQObject(m);
243 243 createPythonQtClassWrapper(info, package, module);
244 244 if (m->superClass()) {
245 245 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
246 246 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
247 247 }
248 } else if (first && module) {
249 // There is a wrapper already, but if we got a module, we want to place the wrapper into that module as well,
250 // since it might have been placed into "private" earlier on.
251 // If the wrapper was already added to module before, it is just readded, which does no harm.
252 PyObject* classWrapper = info->pythonQtClassWrapper();
253 // AddObject steals a reference, so we need to INCREF
254 Py_INCREF(classWrapper);
255 PyModule_AddObject(module, info->className(), classWrapper);
248 256 }
249 257 if (first) {
250 258 first = false;
251 259 if (wrapperCreator) {
252 260 info->setDecoratorProvider(wrapperCreator);
253 261 }
254 262 if (shell) {
255 263 info->setShellSetInstanceWrapperCB(shell);
256 264 }
257 265 }
258 266 m = m->superClass();
259 267 }
260 268 }
261 269
262 270 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
263 271 {
264 272 PyObject* pack = module?module:packageByName(package);
265 273 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
266 274 PyModule_AddObject(pack, info->className(), pyobj);
267 275 if (!module && package && strncmp(package,"Qt",2)==0) {
268 276 // since PyModule_AddObject steals the reference, we need a incref once more...
269 277 Py_INCREF(pyobj);
270 278 // put all qt objects into Qt as well
271 279 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
272 280 }
273 281 info->setPythonQtClassWrapper(pyobj);
274 282 }
275 283
276 284 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
277 285 {
278 286 if (!obj) {
279 287 Py_INCREF(Py_None);
280 288 return Py_None;
281 289 }
282 290 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
283 291 if (!wrap) {
284 292 // smuggling it in...
285 293 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
286 294 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
287 295 registerClass(obj->metaObject());
288 296 classInfo = _knownClassInfos.value(obj->metaObject()->className());
289 297 }
290 298 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
291 299 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
292 300 } else {
293 301 Py_INCREF(wrap);
294 302 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
295 303 }
296 304 return (PyObject*)wrap;
297 305 }
298 306
299 307 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
300 308 {
301 309 if (!ptr) {
302 310 Py_INCREF(Py_None);
303 311 return Py_None;
304 312 }
305 313
306 314 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
307 315 if (!wrap) {
308 316 PythonQtClassInfo* info = _knownClassInfos.value(name);
309 317 if (!info) {
310 318 // maybe it is a PyObject, which we can return directly
311 319 if (name == "PyObject") {
312 320 PyObject* p = (PyObject*)ptr;
313 321 Py_INCREF(p);
314 322 return p;
315 323 }
316 324
317 325 // we do not know the metaobject yet, but we might know it by it's name:
318 326 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
319 327 // yes, we know it, so we can convert to QObject
320 328 QObject* qptr = (QObject*)ptr;
321 329 registerClass(qptr->metaObject());
322 330 info = _knownClassInfos.value(qptr->metaObject()->className());
323 331 }
324 332 }
325 333 if (info && info->isQObject()) {
326 334 QObject* qptr = (QObject*)ptr;
327 335 // if the object is a derived object, we want to switch the class info to the one of the derived class:
328 336 if (name!=(qptr->metaObject()->className())) {
329 337 registerClass(qptr->metaObject());
330 338 info = _knownClassInfos.value(qptr->metaObject()->className());
331 339 }
332 340 wrap = createNewPythonQtInstanceWrapper(qptr, info);
333 341 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
334 342 return (PyObject*)wrap;
335 343 }
336 344
337 345 // not a known QObject, so try our wrapper factory:
338 346 QObject* wrapper = NULL;
339 347 for (int i=0; i<_cppWrapperFactories.size(); i++) {
340 348 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
341 349 if (wrapper) {
342 350 break;
343 351 }
344 352 }
345 353
346 354 if (info) {
347 355 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
348 356 ptr = info->castDownIfPossible(ptr, &info);
349 357 }
350 358
351 359 if (!info || info->pythonQtClassWrapper()==NULL) {
352 360 // still unknown, register as CPP class
353 361 registerCPPClass(name.constData());
354 362 info = _knownClassInfos.value(name);
355 363 }
356 364 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
357 365 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
358 366 info->setMetaObject(wrapper->metaObject());
359 367 }
360 368 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
361 369 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
362 370 } else {
363 371 Py_INCREF(wrap);
364 372 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
365 373 }
366 374 return (PyObject*)wrap;
367 375 }
368 376
369 377 PyObject* PythonQtPrivate::dummyTuple() {
370 378 static PyObject* dummyTuple = NULL;
371 379 if (dummyTuple==NULL) {
372 380 dummyTuple = PyTuple_New(1);
373 381 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
374 382 }
375 383 return dummyTuple;
376 384 }
377 385
378 386
379 387 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
380 388 // call the associated class type to create a new instance...
381 389 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
382 390
383 391 result->setQObject(obj);
384 392 result->_wrappedPtr = wrappedPtr;
385 393 result->_ownedByPythonQt = false;
386 394 result->_useQMetaTypeDestroy = false;
387 395
388 396 if (wrappedPtr) {
389 397 _wrappedObjects.insert(wrappedPtr, result);
390 398 } else {
391 399 _wrappedObjects.insert(obj, result);
392 400 if (obj->parent()== NULL && _wrappedCB) {
393 401 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
394 402 (*_wrappedCB)(obj);
395 403 }
396 404 }
397 405 return result;
398 406 }
399 407
400 408 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
401 409 PythonQtClassWrapper* result;
402 410
403 411 PyObject* className = PyString_FromString(info->className());
404 412
405 413 PyObject* baseClasses = PyTuple_New(1);
406 414 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
407 415
408 416 PyObject* typeDict = PyDict_New();
409 417 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
410 418 PyDict_SetItemString(typeDict, "__module__", moduleName);
411 419
412 420 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
413 421
414 422 // set the class info so that PythonQtClassWrapper_new can read it
415 423 _currentClassInfoForClassWrapperCreation = info;
416 424 // create the new type object by calling the type
417 425 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
418 426
419 427 Py_DECREF(baseClasses);
420 428 Py_DECREF(typeDict);
421 429 Py_DECREF(args);
422 430 Py_DECREF(className);
423 431
424 432 return result;
425 433 }
426 434
427 435 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
428 436 {
429 437 PyObject* args = Py_BuildValue("(i)", enumValue);
430 438 PyObject* result = PyObject_Call(enumType, args, NULL);
431 439 Py_DECREF(args);
432 440 return result;
433 441 }
434 442
435 443 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
436 444 PyObject* result;
437 445
438 446 PyObject* className = PyString_FromString(enumName);
439 447
440 448 PyObject* baseClasses = PyTuple_New(1);
441 449 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
442 450
443 451 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
444 452 PyObject* typeDict = PyDict_New();
445 453 PyDict_SetItemString(typeDict, "__module__", module);
446 454
447 455 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
448 456
449 457 // create the new int derived type object by calling the core type
450 458 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
451 459
452 460 Py_DECREF(baseClasses);
453 461 Py_DECREF(typeDict);
454 462 Py_DECREF(args);
455 463 Py_DECREF(className);
456 464
457 465 return result;
458 466 }
459 467
460 468 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
461 469 {
462 470 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
463 471 if (!r) {
464 472 r = new PythonQtSignalReceiver(obj);
465 473 _p->_signalReceivers.insert(obj, r);
466 474 }
467 475 return r;
468 476 }
469 477
470 478 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
471 479 {
472 480 bool flag = false;
473 481 PythonQtObjectPtr callable = lookupCallable(module, objectname);
474 482 if (callable) {
475 483 PythonQtSignalReceiver* r = getSignalReceiver(obj);
476 484 flag = r->addSignalHandler(signal, callable);
477 485 if (!flag) {
478 486 // signal not found
479 487 }
480 488 } else {
481 489 // callable not found
482 490 }
483 491 return flag;
484 492 }
485 493
486 494 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
487 495 {
488 496 bool flag = false;
489 497 PythonQtSignalReceiver* r = getSignalReceiver(obj);
490 498 if (r) {
491 499 flag = r->addSignalHandler(signal, receiver);
492 500 }
493 501 return flag;
494 502 }
495 503
496 504 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
497 505 {
498 506 bool flag = false;
499 507 PythonQtObjectPtr callable = lookupCallable(module, objectname);
500 508 if (callable) {
501 509 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
502 510 if (r) {
503 511 flag = r->removeSignalHandler(signal, callable);
504 512 }
505 513 } else {
506 514 // callable not found
507 515 }
508 516 return flag;
509 517 }
510 518
511 519 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
512 520 {
513 521 bool flag = false;
514 522 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
515 523 if (r) {
516 524 flag = r->removeSignalHandler(signal, receiver);
517 525 }
518 526 return flag;
519 527 }
520 528
521 529 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
522 530 {
523 531 PythonQtObjectPtr p = lookupObject(module, name);
524 532 if (p) {
525 533 if (PyCallable_Check(p)) {
526 534 return p;
527 535 }
528 536 }
529 537 PyErr_Clear();
530 538 return NULL;
531 539 }
532 540
533 541 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
534 542 {
535 543 QStringList l = name.split('.');
536 544 PythonQtObjectPtr p = module;
537 545 PythonQtObjectPtr prev;
538 546 QString s;
539 547 QByteArray b;
540 548 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
541 549 prev = p;
542 550 b = (*i).toLatin1();
543 551 if (PyDict_Check(p)) {
544 552 p = PyDict_GetItemString(p, b.data());
545 553 } else {
546 554 p.setNewRef(PyObject_GetAttrString(p, b.data()));
547 555 }
548 556 }
549 557 PyErr_Clear();
550 558 return p;
551 559 }
552 560
553 561 PythonQtObjectPtr PythonQt::getMainModule() {
554 562 //both borrowed
555 563 PythonQtObjectPtr dict = PyImport_GetModuleDict();
556 564 return PyDict_GetItemString(dict, "__main__");
557 565 }
558 566
559 567 PythonQtObjectPtr PythonQt::importModule(const QString& name)
560 568 {
561 569 PythonQtObjectPtr mod;
562 570 mod.setNewRef(PyImport_ImportModule(name.toLatin1().constData()));
563 571 return mod;
564 572 }
565 573
566 574
567 575 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
568 576 QVariant result;
569 577 if (pycode) {
570 578 PyObject* dict = NULL;
571 579 if (PyModule_Check(object)) {
572 580 dict = PyModule_GetDict(object);
573 581 } else if (PyDict_Check(object)) {
574 582 dict = object;
575 583 }
576 584 PyObject* r = NULL;
577 585 if (dict) {
578 586 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
579 587 }
580 588 if (r) {
581 589 result = PythonQtConv::PyObjToQVariant(r);
582 590 Py_DECREF(r);
583 591 } else {
584 592 handleError();
585 593 }
586 594 } else {
587 595 handleError();
588 596 }
589 597 return result;
590 598 }
591 599
592 600 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
593 601 {
594 602 QVariant result;
595 603 PythonQtObjectPtr p;
596 604 PyObject* dict = NULL;
597 605 if (PyModule_Check(object)) {
598 606 dict = PyModule_GetDict(object);
599 607 } else if (PyDict_Check(object)) {
600 608 dict = object;
601 609 }
602 610 if (dict) {
603 611 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
604 612 }
605 613 if (p) {
606 614 result = PythonQtConv::PyObjToQVariant(p);
607 615 } else {
608 616 handleError();
609 617 }
610 618 return result;
611 619 }
612 620
613 621 void PythonQt::evalFile(PyObject* module, const QString& filename)
614 622 {
615 623 PythonQtObjectPtr code = parseFile(filename);
616 624 if (code) {
617 625 evalCode(module, code);
618 626 } else {
619 627 handleError();
620 628 }
621 629 }
622 630
623 631 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
624 632 {
625 633 PythonQtObjectPtr p;
626 634 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
627 635 if (!p) {
628 636 handleError();
629 637 }
630 638 return p;
631 639 }
632 640
633 641 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
634 642 {
635 643 PythonQtObjectPtr code = parseFile(filename);
636 644 PythonQtObjectPtr module = _p->createModule(name, code);
637 645 return module;
638 646 }
639 647
640 648 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
641 649 {
642 650 PyErr_Clear();
643 651 QString scriptCode = script;
644 652 if (scriptCode.isEmpty()) {
645 653 // we always need at least a linefeed
646 654 scriptCode = "\n";
647 655 }
648 656 PythonQtObjectPtr pycode;
649 657 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
650 658 PythonQtObjectPtr module = _p->createModule(name, pycode);
651 659 return module;
652 660 }
653 661
654 662 PythonQtObjectPtr PythonQt::createUniqueModule()
655 663 {
656 664 static QString pyQtStr("PythonQt_module");
657 665 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
658 666 return createModuleFromScript(moduleName);
659 667 }
660 668
661 669 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
662 670 {
663 671 if (PyModule_Check(object)) {
664 672 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
665 673 } else if (PyDict_Check(object)) {
666 674 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
667 675 } else {
668 676 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
669 677 }
670 678 }
671 679
672 680 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
673 681 {
674 682 if (PyModule_Check(object)) {
675 683 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
676 684 } else if (PyDict_Check(object)) {
677 685 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
678 686 } else {
679 687 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
680 688 }
681 689 }
682 690
683 691 void PythonQt::removeVariable(PyObject* object, const QString& name)
684 692 {
685 693 if (PyDict_Check(object)) {
686 694 PyDict_DelItemString(object, name.toLatin1().data());
687 695 } else {
688 696 PyObject_DelAttrString(object, name.toLatin1().data());
689 697 }
690 698 }
691 699
692 700 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
693 701 {
694 702 QVariant result;
695 703 PythonQtObjectPtr obj = lookupObject(object, objectname);
696 704 if (obj) {
697 705 result = PythonQtConv::PyObjToQVariant(obj);
698 706 }
699 707 return result;
700 708 }
701 709
702 710 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
703 711 {
704 712 QStringList results;
705 713
706 714 PythonQtObjectPtr object;
707 715 if (objectname.isEmpty()) {
708 716 object = module;
709 717 } else {
710 718 object = lookupObject(module, objectname);
711 719 if (!object && type == CallOverloads) {
712 720 PyObject* dict = lookupObject(module, "__builtins__");
713 721 if (dict) {
714 722 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
715 723 }
716 724 }
717 725 }
718 726
719 727 if (object) {
720 728 if (type == CallOverloads) {
721 729 if (PythonQtSlotFunction_Check(object)) {
722 730 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
723 731 PythonQtSlotInfo* info = o->m_ml;
724 732
725 733 while (info) {
726 734 results << info->fullSignature();
727 735 info = info->nextInfo();
728 736 }
729 737 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
730 738 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
731 739 PythonQtSlotInfo* info = o->classInfo()->constructors();
732 740
733 741 while (info) {
734 742 results << info->fullSignature();
735 743 info = info->nextInfo();
736 744 }
737 745 } else {
738 746 //TODO: use pydoc!
739 747 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
740 748 if (doc) {
741 749 results << PyString_AsString(doc);
742 750 Py_DECREF(doc);
743 751 }
744 752 }
745 753 } else {
746 754 PyObject* keys = NULL;
747 755 bool isDict = false;
748 756 if (PyDict_Check(object)) {
749 757 keys = PyDict_Keys(object);
750 758 isDict = true;
751 759 } else {
752 760 keys = PyObject_Dir(object);
753 761 }
754 762 if (keys) {
755 763 int count = PyList_Size(keys);
756 764 PyObject* key;
757 765 PyObject* value;
758 766 QString keystr;
759 767 for (int i = 0;i<count;i++) {
760 768 key = PyList_GetItem(keys,i);
761 769 if (isDict) {
762 770 value = PyDict_GetItem(object, key);
763 771 Py_INCREF(value);
764 772 } else {
765 773 value = PyObject_GetAttr(object, key);
766 774 }
767 775 if (!value) continue;
768 776 keystr = PyString_AsString(key);
769 777 static const QString underscoreStr("__tmp");
770 778 if (!keystr.startsWith(underscoreStr)) {
771 779 switch (type) {
772 780 case Anything:
773 781 results << keystr;
774 782 break;
775 783 case Class:
776 784 if (value->ob_type == &PyClass_Type) {
777 785 results << keystr;
778 786 }
779 787 break;
780 788 case Variable:
781 789 if (value->ob_type != &PyClass_Type
782 790 && value->ob_type != &PyCFunction_Type
783 791 && value->ob_type != &PyFunction_Type
784 792 && value->ob_type != &PyModule_Type
785 793 ) {
786 794 results << keystr;
787 795 }
788 796 break;
789 797 case Function:
790 798 if (value->ob_type == &PyFunction_Type ||
791 799 value->ob_type == &PyMethod_Type
792 800 ) {
793 801 results << keystr;
794 802 }
795 803 break;
796 804 case Module:
797 805 if (value->ob_type == &PyModule_Type) {
798 806 results << keystr;
799 807 }
800 808 break;
801 809 default:
802 810 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
803 811 }
804 812 }
805 813 Py_DECREF(value);
806 814 }
807 815 Py_DECREF(keys);
808 816 }
809 817 }
810 818 }
811 819 return results;
812 820 }
813 821
814 822 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
815 823 {
816 824 PythonQtObjectPtr callable = lookupCallable(object, name);
817 825 if (callable) {
818 826 return call(callable, args);
819 827 } else {
820 828 return QVariant();
821 829 }
822 830 }
823 831
824 832 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
825 833 {
826 834 QVariant r;
827 835 PythonQtObjectPtr result;
828 836 result.setNewRef(callAndReturnPyObject(callable, args));
829 837 if (result) {
830 838 r = PythonQtConv::PyObjToQVariant(result);
831 839 } else {
832 840 PythonQt::self()->handleError();
833 841 }
834 842 return r;
835 843 }
836 844
837 845 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args)
838 846 {
839 847 PyObject* result = NULL;
840 848 if (callable) {
841 849 PythonQtObjectPtr pargs;
842 850 int count = args.size();
843 851 if (count>0) {
844 852 pargs.setNewRef(PyTuple_New(count));
845 853 }
846 854 bool err = false;
847 855 // transform QVariants to Python
848 856 for (int i = 0; i < count; i++) {
849 857 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
850 858 if (arg) {
851 859 // steals reference, no unref
852 860 PyTuple_SetItem(pargs, i,arg);
853 861 } else {
854 862 err = true;
855 863 break;
856 864 }
857 865 }
858 866
859 867 if (!err) {
860 868 PyErr_Clear();
861 869 result = PyObject_CallObject(callable, pargs);
862 870 }
863 871 }
864 872 return result;
865 873 }
866 874
867 875 void PythonQt::addInstanceDecorators(QObject* o)
868 876 {
869 877 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
870 878 }
871 879
872 880 void PythonQt::addClassDecorators(QObject* o)
873 881 {
874 882 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
875 883 }
876 884
877 885 void PythonQt::addDecorators(QObject* o)
878 886 {
879 887 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
880 888 }
881 889
882 890 void PythonQt::registerQObjectClassNames(const QStringList& names)
883 891 {
884 892 _p->registerQObjectClassNames(names);
885 893 }
886 894
887 895 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
888 896 {
889 897 _p->_importInterface = importInterface;
890 898 PythonQtImport::init();
891 899 }
892 900
893 901 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
894 902 {
895 903 _p->_importIgnorePaths = paths;
896 904 }
897 905
898 906 const QStringList& PythonQt::getImporterIgnorePaths()
899 907 {
900 908 return _p->_importIgnorePaths;
901 909 }
902 910
903 911 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
904 912 {
905 913 _p->_cppWrapperFactories.append(factory);
906 914 }
907 915
908 916 //---------------------------------------------------------------------------------------------------
909 917 PythonQtPrivate::PythonQtPrivate()
910 918 {
911 919 _importInterface = NULL;
912 920 _defaultImporter = new PythonQtQFileImporter;
913 921 _noLongerWrappedCB = NULL;
914 922 _wrappedCB = NULL;
915 923 _currentClassInfoForClassWrapperCreation = NULL;
924 _profilingCB = NULL;
916 925 }
917 926
918 927 void PythonQtPrivate::setupSharedLibrarySuffixes()
919 928 {
920 929 _sharedLibrarySuffixes.clear();
921 930 PythonQtObjectPtr imp;
922 931 imp.setNewRef(PyImport_ImportModule("imp"));
923 932 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
924 933 QVariant result = imp.call("get_suffixes");
934 #ifdef __linux
935 #ifdef _DEBUG
936 // First look for shared libraries with the '_d' suffix in debug mode on Linux.
937 // This is a workaround, because python does not append the '_d' suffix on Linux
938 // and would always load the release library otherwise.
939 _sharedLibrarySuffixes << "_d.so";
940 #endif
941 #endif
925 942 foreach (QVariant entry, result.toList()) {
926 943 QVariantList suffixEntry = entry.toList();
927 944 if (suffixEntry.count()==3) {
928 945 int code = suffixEntry.at(2).toInt();
929 946 if (code == cExtensionCode) {
930 947 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
931 948 }
932 949 }
933 950 }
934 951 }
935 952
936 953 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
937 954 {
938 955 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
939 956 _currentClassInfoForClassWrapperCreation = NULL;
940 957 return info;
941 958 }
942 959
943 960 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
944 961 {
945 962 o->setParent(this);
946 963 int numMethods = o->metaObject()->methodCount();
947 964 for (int i = 0; i < numMethods; i++) {
948 965 QMetaMethod m = o->metaObject()->method(i);
949 966 if ((m.methodType() == QMetaMethod::Method ||
950 967 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
951 968 if (qstrncmp(m.signature(), "new_", 4)==0) {
952 969 if ((decoTypes & ConstructorDecorator) == 0) continue;
953 970 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
954 971 if (info->parameters().at(0).pointerCount == 1) {
955 972 QByteArray signature = m.signature();
956 973 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
957 974 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
958 975 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
959 976 classInfo->addConstructor(newSlot);
960 977 }
961 978 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
962 979 if ((decoTypes & DestructorDecorator) == 0) continue;
963 980 QByteArray signature = m.signature();
964 981 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
965 982 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
966 983 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
967 984 classInfo->setDestructor(newSlot);
968 985 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
969 986 if ((decoTypes & StaticDecorator) == 0) continue;
970 987 QByteArray signature = m.signature();
971 988 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
972 989 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
973 990 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
974 991 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
975 992 classInfo->addDecoratorSlot(newSlot);
976 993 } else {
977 994 if ((decoTypes & InstanceDecorator) == 0) continue;
978 995 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
979 996 if (info->parameters().count()>1) {
980 997 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
981 998 if (p.pointerCount==1) {
982 999 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
983 1000 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
984 1001 classInfo->addDecoratorSlot(newSlot);
985 1002 }
986 1003 }
987 1004 }
988 1005 }
989 1006 }
990 1007 }
991 1008
992 1009 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
993 1010 {
994 1011 foreach(QString name, names) {
995 1012 _knownQObjectClassNames.insert(name.toLatin1(), true);
996 1013 }
997 1014 }
998 1015
999 1016 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
1000 1017 {
1001 1018 _signalReceivers.remove(obj);
1002 1019 }
1003 1020
1004 1021 bool PythonQt::handleError()
1005 1022 {
1006 1023 bool flag = false;
1007 1024 if (PyErr_Occurred()) {
1008 1025
1009 1026 // currently we just print the error and the stderr handler parses the errors
1010 1027 PyErr_Print();
1011 1028
1012 1029 /*
1013 1030 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1014 1031 PyObject *ptype;
1015 1032 PyObject *pvalue;
1016 1033 PyObject *ptraceback;
1017 1034 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1018 1035
1019 1036 Py_XDECREF(ptype);
1020 1037 Py_XDECREF(pvalue);
1021 1038 Py_XDECREF(ptraceback);
1022 1039 */
1023 1040 PyErr_Clear();
1024 1041 flag = true;
1025 1042 }
1026 1043 return flag;
1027 1044 }
1028 1045
1029 1046 void PythonQt::addSysPath(const QString& path)
1030 1047 {
1031 1048 PythonQtObjectPtr sys;
1032 1049 sys.setNewRef(PyImport_ImportModule("sys"));
1033 1050 PythonQtObjectPtr obj = lookupObject(sys, "path");
1034 1051 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1035 1052 }
1036 1053
1037 1054 void PythonQt::overwriteSysPath(const QStringList& paths)
1038 1055 {
1039 1056 PythonQtObjectPtr sys;
1040 1057 sys.setNewRef(PyImport_ImportModule("sys"));
1041 1058 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1042 1059 }
1043 1060
1044 1061 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1045 1062 {
1046 1063 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1047 1064 }
1048 1065
1049 1066 void PythonQt::stdOutRedirectCB(const QString& str)
1050 1067 {
1051 1068 emit PythonQt::self()->pythonStdOut(str);
1052 1069 }
1053 1070
1054 1071 void PythonQt::stdErrRedirectCB(const QString& str)
1055 1072 {
1056 1073 emit PythonQt::self()->pythonStdErr(str);
1057 1074 }
1058 1075
1059 1076 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1060 1077 {
1061 1078 _p->_wrappedCB = cb;
1062 1079 }
1063 1080
1064 1081 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1065 1082 {
1066 1083 _p->_noLongerWrappedCB = cb;
1067 1084 }
1068 1085
1086 void PythonQt::setProfilingCallback(ProfilingCB* cb)
1087 {
1088 _p->_profilingCB = cb;
1089 }
1069 1090
1070 1091
1071 1092 static PyMethodDef PythonQtMethods[] = {
1072 1093 {NULL, NULL, 0, NULL}
1073 1094 };
1074 1095
1075 1096 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1076 1097 {
1077 1098 QByteArray name = "PythonQt";
1078 1099 if (!pythonQtModuleName.isEmpty()) {
1079 1100 name = pythonQtModuleName;
1080 1101 }
1081 1102 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1082 1103 _p->_pythonQtModuleName = name;
1083
1104
1084 1105 if (redirectStdOut) {
1085 1106 PythonQtObjectPtr sys;
1086 1107 PythonQtObjectPtr out;
1087 1108 PythonQtObjectPtr err;
1088 1109 sys.setNewRef(PyImport_ImportModule("sys"));
1089 1110 // create a redirection object for stdout and stderr
1090 1111 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1091 1112 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1092 1113 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1093 1114 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1094 1115 // replace the built in file objects with our own objects
1095 1116 PyModule_AddObject(sys, "stdout", out);
1096 1117 PyModule_AddObject(sys, "stderr", err);
1097 1118 }
1098 1119 }
1099 1120
1100 1121 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1101 1122 {
1102 1123 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1103 1124 }
1104 1125
1105 1126
1106 1127 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1107 1128 {
1108 1129 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1109 1130 if (!info) {
1110 1131 info = new PythonQtClassInfo();
1111 1132 info->setupCPPObject(typeName);
1112 1133 _knownClassInfos.insert(typeName, info);
1113 1134 }
1114 1135 return info;
1115 1136 }
1116 1137
1117 1138 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1118 1139 {
1119 1140 _p->addPolymorphicHandler(typeName, cb);
1120 1141 }
1121 1142
1122 1143 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1123 1144 {
1124 1145 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1125 1146 info->addPolymorphicHandler(cb);
1126 1147 }
1127 1148
1128 1149 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1129 1150 {
1130 1151 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1131 1152 }
1132 1153
1133 1154 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1134 1155 {
1135 1156 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1136 1157 if (info) {
1137 1158 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1138 1159 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1139 1160 return true;
1140 1161 } else {
1141 1162 return false;
1142 1163 }
1143 1164 }
1144 1165
1145 1166 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1146 1167 {
1147 1168 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1148 1169 if (!info->pythonQtClassWrapper()) {
1149 1170 info->setTypeSlots(typeSlots);
1150 1171 info->setupCPPObject(typeName);
1151 1172 createPythonQtClassWrapper(info, package, module);
1152 1173 }
1153 1174 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1154 1175 addParentClass(typeName, parentTypeName, 0);
1155 1176 }
1156 1177 if (wrapperCreator) {
1157 1178 info->setDecoratorProvider(wrapperCreator);
1158 1179 }
1159 1180 if (shell) {
1160 1181 info->setShellSetInstanceWrapperCB(shell);
1161 1182 }
1162 1183 }
1163 1184
1164 1185 PyObject* PythonQtPrivate::packageByName(const char* name)
1165 1186 {
1166 1187 if (name==NULL || name[0]==0) {
1167 1188 name = "private";
1168 1189 }
1169 1190 PyObject* v = _packages.value(name);
1170 1191 if (!v) {
1171 1192 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1172 1193 _packages.insert(name, v);
1173 1194 // AddObject steals the reference, so increment it!
1174 1195 Py_INCREF(v);
1175 1196 PyModule_AddObject(_pythonQtModule, name, v);
1176 1197 }
1177 1198 return v;
1178 1199 }
1179 1200
1180 1201 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1181 1202 {
1182 1203 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;
1183 1204 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1184 1205 PythonQt::self()->handleError();
1185 1206 }
1186 1207
1187 1208 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1188 1209 {
1189 1210 if (_p->_initFlags & ExternalHelp) {
1190 1211 emit pythonHelpRequest(QByteArray(info->className()));
1191 1212 return Py_BuildValue("");
1192 1213 } else {
1193 1214 return PyString_FromString(info->help().toLatin1().data());
1194 1215 }
1195 1216 }
1196 1217
1218 void PythonQt::clearNotFoundCachedMembers()
1219 {
1220 foreach(PythonQtClassInfo* info, _p->_knownClassInfos) {
1221 info->clearNotFoundCachedMembers();
1222 }
1223 }
1224
1197 1225 void PythonQtPrivate::removeWrapperPointer(void* obj)
1198 1226 {
1199 1227 _wrappedObjects.remove(obj);
1200 1228 }
1201 1229
1202 1230 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1203 1231 {
1204 1232 _wrappedObjects.insert(obj, wrapper);
1205 1233 }
1206 1234
1207 1235 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1208 1236 {
1209 1237 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1210 1238 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1211 1239 // this is a wrapper whose QObject was already removed due to destruction
1212 1240 // so the obj pointer has to be a new QObject with the same address...
1213 1241 // we remove the old one and set the copy to NULL
1214 1242 wrap->_objPointerCopy = NULL;
1215 1243 removeWrapperPointer(obj);
1216 1244 wrap = NULL;
1217 1245 }
1218 1246 return wrap;
1219 1247 }
1220 1248
1221 1249 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1222 1250 {
1223 1251 PythonQtObjectPtr result;
1224 1252 if (pycode) {
1225 1253 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1226 1254 } else {
1227 1255 PythonQt::self()->handleError();
1228 1256 }
1229 1257 return result;
1230 1258 }
@@ -1,634 +1,656
1 1 #ifndef _PYTHONQT_H
2 2 #define _PYTHONQT_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQt.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46 #include "PythonQtInstanceWrapper.h"
47 47 #include "PythonQtClassWrapper.h"
48 48 #include "PythonQtSlot.h"
49 49 #include "PythonQtObjectPtr.h"
50 50 #include <QObject>
51 51 #include <QVariant>
52 52 #include <QList>
53 53 #include <QHash>
54 54 #include <QByteArray>
55 55 #include <QStringList>
56 56 #include <QtDebug>
57 57 #include <iostream>
58 58
59 59
60 60 class PythonQtClassInfo;
61 61 class PythonQtPrivate;
62 62 class PythonQtMethodInfo;
63 63 class PythonQtSignalReceiver;
64 64 class PythonQtImportFileInterface;
65 65 class PythonQtCppWrapperFactory;
66 66 class PythonQtQFileImporter;
67 67
68 68 typedef void PythonQtQObjectWrappedCB(QObject* object);
69 69 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
70 70 typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, char **class_name);
71 71
72 72 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
73 73
74 74 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) { ((T*)object)->_wrapper = wrapper; };
75 75
76 76 //! returns the offset that needs to be added to upcast an object of type T1 to T2
77 77 template<class T1, class T2> int PythonQtUpcastingOffset() {
78 return (((char*)(static_cast<T2*>(reinterpret_cast<T1*>(0x100)))) - ((char*)reinterpret_cast<T1*>(0x100)));
78 return (((char*)(static_cast<T2*>(reinterpret_cast<T1*>(0x100)))) - ((char*)reinterpret_cast<T1*>(0x100)));
79 79 }
80 80
81 81 //! callback to create a QObject lazily
82 82 typedef QObject* PythonQtQObjectCreatorFunctionCB();
83 83
84 84 //! helper template to create a derived QObject class
85 85 template<class T> QObject* PythonQtCreateObject() { return new T(); };
86 86
87 87 //! The main interface to the Python Qt binding, realized as a singleton
88 88 /*!
89 89 Use PythonQt::init() to initialize the singleton and PythonQt::self() to access it.
90 90 While there can be only one PythonQt instance, you can have any number of Python context to do scripting in.
91 91 One possibility is to use createModuleFromFile(), createModuleFromScript() or createUniqueModule() to get a context
92 92 that is separated from the other contexts. Alternatively you can use Python dicts as contexts for script evaluation,
93 93 but you will need to populate the dict with the __builtins__ instance to have all Pythons available when running
94 94 code in the scope of a dict.
95 95 */
96 96 class PYTHONQT_EXPORT PythonQt : public QObject {
97 97
98 98 Q_OBJECT
99 99
100 100 public:
101 101
102 102 //! flags that can be passed to PythonQt::init()
103 103 enum InitFlags {
104 104 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
105 105 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
106 106 ExternalHelp = 4, //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
107 107 PythonAlreadyInitialized = 8 //!<< sets that PythonQt should not can PyInitialize, since it is already done
108 108 };
109 109
110 110 //! flags that tell PythonQt which operators to expect on the registered type
111 111 enum TypeSlots {
112 112 Type_Add = 1,
113 113 Type_Subtract = 1 << 1,
114 114 Type_Multiply = 1 << 2,
115 115 Type_Divide = 1 << 3,
116 116 Type_Mod = 1 << 4,
117 117 Type_And = 1 << 5,
118 118 Type_Or = 1 << 6,
119 119 Type_Xor = 1 << 7,
120 120 Type_LShift = 1 << 8,
121 121 Type_RShift = 1 << 9,
122 122
123 123 Type_InplaceAdd = 1 << 10,
124 124 Type_InplaceSubtract = 1 << 11,
125 125 Type_InplaceMultiply = 1 << 12,
126 126 Type_InplaceDivide = 1 << 13,
127 127 Type_InplaceMod = 1 << 14,
128 128 Type_InplaceAnd = 1 << 15,
129 129 Type_InplaceOr = 1 << 16,
130 130 Type_InplaceXor = 1 << 17,
131 131 Type_InplaceLShift = 1 << 18,
132 132 Type_InplaceRShift = 1 << 19,
133 133
134 134 // Not yet needed/nicely mappable/generated...
135 135 //Type_Positive = 1 << 29,
136 136 //Type_Negative = 1 << 29,
137 137 //Type_Abs = 1 << 29,
138 138 //Type_Hash = 1 << 29,
139 139
140 140 Type_Invert = 1 << 29,
141 141 Type_RichCompare = 1 << 30,
142 142 Type_NonZero = 1 << 31,
143 143
144 144 };
145 145
146 //! enum for profiling callback
147 enum ProfilingCallbackState {
148 Enter = 1,
149 Leave = 2
150 };
151
152 //! callback for profiling. className and methodName are only passed when state == Enter, otherwise
153 //! they are NULL.
154 typedef void ProfilingCB(ProfilingCallbackState state, const char* className, const char* methodName);
155
146 156 //---------------------------------------------------------------------------
147 157 //! \name Singleton Initialization
148 158 //@{
149
159
150 160 //! initialize the python qt binding (flags are a or combination of PythonQt::InitFlags), if \c pythonQtModuleName is given
151 161 //! it defines the name of the python module that PythonQt will add, otherwise "PythonQt" is used.
152 162 //! This can be used to e.g. pass in PySide or PyQt4 to make it more compatible.
153 163 static void init(int flags = IgnoreSiteModule | RedirectStdOut, const QByteArray& pythonQtModuleName = QByteArray());
154 164
155 165 //! cleanup of the singleton
156 166 static void cleanup();
157 167
158 168 //! get the singleton instance
159 169 static PythonQt* self() { return _self; }
160 170
161 171 //@}
162
172
163 173 //! defines the object types for introspection
164 174 enum ObjectType {
165 175 Class,
166 176 Function,
167 177 Variable,
168 178 Module,
169 179 Anything,
170 180 CallOverloads
171 181 };
172 182
173 183 //---------------------------------------------------------------------------
174 184 //! \name Modules
175 185 //@{
176 186
177 187 //! get the __main__ module of python
178 188 PythonQtObjectPtr getMainModule();
179 189
180 190 //! import the given module and return a reference to it (useful to import e.g. "sys" and call something on it)
181 191 //! If a module is already imported, this returns the already imported module.
182 192 PythonQtObjectPtr importModule(const QString& name);
183 193
184 194 //! creates the new module \c name and evaluates the given file in the context of that module
185 195 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
186 196 //! to a module later on.
187 197 //! The user needs to make sure that the \c name is unique in the python module dictionary.
188 198 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
189
199
190 200 //! creates the new module \c name and evaluates the given script in the context of that module.
191 201 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
192 202 //! to a module later on.
193 203 //! The user needs to make sure that the \c name is unique in the python module dictionary.
194 204 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
195
205
196 206 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
197 207 //! script code
198 208 PythonQtObjectPtr createUniqueModule();
199 209
200 210 //@}
201 211
202 212 //---------------------------------------------------------------------------
203 213 //! \name Importing/Paths
204 214 //@{
205 215
206 216 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
207 217 void overwriteSysPath(const QStringList& paths);
208 218
209 219 //! prepend a path to sys.path to allow importing from it
210 220 void addSysPath(const QString& path);
211 221
212 222 //! sets the __path__ list of a module to the given list (important for local imports)
213 223 void setModuleImportPath(PyObject* module, const QStringList& paths);
214 224
215 225 //@}
216
226
217 227 //---------------------------------------------------------------------------
218 228 //! \name Registering Classes
219 229 //@{
220
230
221 231 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
222 232 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
223 233 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
224 234 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
225
235
226 236 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
227 237 //! (ownership of wrapper is passed to PythonQt)
228 238 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
229
239
230 240 This will add a wrapper object that is used to make calls to the given classname \c typeName.
231 241 All slots that take a pointer to typeName as the first argument will be callable from Python on
232 242 a variant object that contains such a type.
233 243 */
234 244 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
235 245
236 246 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
237 247 //! and it will register the classes when it first sees a pointer to such a derived class
238 248 void registerQObjectClassNames(const QStringList& names);
239 249
240 250 //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance
241 251 //! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that
242 252 //! type is really derived from parentType.
243 253 //! Returns false if the typeName was not yet registered.
244 254 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
245 255
246 256 //! add a handler for polymorphic downcasting
247 257 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
248 258
249 259 //@}
250 260
251 261 //---------------------------------------------------------------------------
252 262 //! \name Script Parsing and Evaluation
253 263 //@{
254
264
255 265 //! parses the given file and returns the python code object, this can then be used to call evalCode()
256 266 PythonQtObjectPtr parseFile(const QString& filename);
257 267
258 268 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
259 269 //! If pycode is NULL, a python error is printed.
260 270 QVariant evalCode(PyObject* object, PyObject* pycode);
261 271
262 272 //! evaluates the given script code and returns the result value
263 273 QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input);
264 274
265 275 //! evaluates the given script code from file
266 276 void evalFile(PyObject* object, const QString& filename);
267 277
268 278 //@}
269 279
270 280 //---------------------------------------------------------------------------
271 281 //! \name Signal Handlers
272 282 //@{
273 283
274 284 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
275 285 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
276 286
277 287 //! remove a signal handler from the given \c signal of \c obj
278 288 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
279 289
280 290 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
281 291 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
282 292
283 293 //! remove a signal handler from the given \c signal of \c obj
284 294 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
285 295
286 296 //@}
287 297
288 298 //---------------------------------------------------------------------------
289 299 //! \name Variable access
290 //@{
300 //@{
291 301
292 302 //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable)
293 303 void addObject(PyObject* object, const QString& name, QObject* qObject);
294 304
295 305 //! add the given variable to the object
296 306 void addVariable(PyObject* object, const QString& name, const QVariant& v);
297 307
298 308 //! remove the given variable
299 309 void removeVariable(PyObject* module, const QString& name);
300 310
301 311 //! get the variable with the \c name of the \c object, returns an invalid QVariant on error
302 312 QVariant getVariable(PyObject* object, const QString& name);
303 313
304 314 //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname
305 315 QStringList introspection(PyObject* object, const QString& objectname, ObjectType type);
306 316
307 317 //! returns the found callable object or NULL
308 318 //! @return new reference
309 319 PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
310 320
311 321 //@}
312 322
313 323 //---------------------------------------------------------------------------
314 324 //! \name Calling Python Objects
315 //@{
325 //@{
316 326
317 327 //! call the given python \c callable in the scope of object, returns the result converted to a QVariant
318 328 QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList());
319 329
320 330 //! call the given python object, returns the result converted to a QVariant
321 331 QVariant call(PyObject* callable, const QVariantList& args = QVariantList());
322 332
323 333 //! call the given python object, returns the result as new PyObject
324 334 PyObject* callAndReturnPyObject(PyObject* callable, const QVariantList& args = QVariantList());
325 335
326 336 //@}
327 337
328 338 //---------------------------------------------------------------------------
329 339 //! \name Decorations, Constructors, Wrappers...
330 340 //@{
331 341
332 342 //! add an object whose slots will be used as decorator slots for
333 343 //! other QObjects or CPP classes. The slots need to follow the
334 344 //! convention that the first argument is a pointer to the wrapped object.
335 345 //! (ownership is passed to PythonQt)
336 346 /*!
337 347 Example:
338 348
339 349 A slot with the signature
340 350
341 351 \code
342 352 bool doSomething(QWidget* w, int a)
343 353 \endcode
344 354
345 355 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
346 356 that will be called with the concrete instance as first argument.
347 357 So in Python you can now e.g. call
348 358
349 359 \code
350 360 someWidget.doSomething(12)
351 361 \endcode
352 362
353 363 without QWidget really having this method. This allows to easily make normal methods
354 364 of Qt classes callable by forwarding them with such decorator slots
355 365 or to make CPP classes (which are not derived from QObject) callable from Python.
356 366 */
357 367 void addInstanceDecorators(QObject* o);
358 368
359 369 //! add an object whose slots will be used as decorator slots for
360 370 //! class objects (ownership is passed to PythonQt)
361 371 /*!
362 372 The slots need to follow the following convention:
363 373 - SomeClass* new_SomeClass(...)
364 374 - QVariant new_SomeClass(...)
365 375 - void delete_SomeClass(SomeClass*)
366 376 - ... static_SomeClass_someName(...)
367 377
368 378 This will add:
369 379 - a constructor
370 380 - a constructor which generates a QVariant
371 381 - a destructor (only useful for CPP objects)
372 382 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
373 383
374 384 */
375 385 void addClassDecorators(QObject* o);
376 386
377 387 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
378 388 void addDecorators(QObject* o);
379 389
380 390 //! add the given factory to PythonQt (ownership stays with caller)
381 391 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
382 392
383 393 //@}
384 394
385 395 //---------------------------------------------------------------------------
386 396 //! \name Custom Importer
387 397 //@{
388
398
389 399 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
390 400 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
391 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
401 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
392 402 //! This is not reversible, so even setting setImporter(NULL) afterwards will
393 403 //! keep the custom PythonQt importer with a QFile default import interface.
394 404 //! Subsequent python import calls will make use of the passed importInterface
395 405 //! which forwards all import calls to the given \c importInterface.
396 406 //! Passing NULL will install a default QFile importer.
397 407 //! (\c importInterface ownership stays with caller)
398 408 void setImporter(PythonQtImportFileInterface* importInterface);
399 409
400 410 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
401 411 //! (without calling setImporter or installDefaultImporter at least once, the default python import
402 412 //! mechanism is in place)
403 413 //! the default importer allows to import files from anywhere QFile can read from,
404 414 //! including the Qt resource system using ":". Keep in mind that you need to extend
405 415 //! "sys.path" with ":" to be able to import from the Qt resources.
406 416 void installDefaultImporter() { setImporter(NULL); }
407 417
408 418 //! set paths that the importer should ignore
409 419 void setImporterIgnorePaths(const QStringList& paths);
410 420
411 421 //! get paths that the importer should ignore
412 422 const QStringList& getImporterIgnorePaths();
413 423
414 424 //! get access to the file importer (if set)
415 425 static PythonQtImportFileInterface* importInterface();
416 426
417 427 //@}
418 428
419 429 //---------------------------------------------------------------------------
420 430 //! \name Other Stuff
421 431 //@{
422 432
423 433 //! get access to internal data (should not be used on the public API, but is used by some C functions)
424 434 static PythonQtPrivate* priv() { return _self->_p; }
425 435
426 436 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
427 437 //! The error is currently just output to the python stderr, future version might implement better trace printing
428 438 bool handleError();
429 439
440 //! clear all NotFound entries on all class infos, to ensure that
441 //! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded
442 void clearNotFoundCachedMembers();
443
430 444 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
431 445 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
432 446 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
433 447 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
434 448
435 449 //! call the callback if it is set
436 450 static void qObjectNoLongerWrappedCB(QObject* o);
437 451
438 452 //! called by internal help methods
439 453 PyObject* helpCalled(PythonQtClassInfo* info);
440
454
441 455 //! returns the found object or NULL
442 456 //! @return new reference
443 457 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
444 458
459 //! sets a callback that is called before and after function calls for profiling
460 void setProfilingCallback(ProfilingCB* cb);
461
445 462 //@}
446 463
447 464 signals:
448 465 //! emitted when python outputs something to stdout (and redirection is turned on)
449 466 void pythonStdOut(const QString& str);
450 467 //! emitted when python outputs something to stderr (and redirection is turned on)
451 468 void pythonStdErr(const QString& str);
452 469
453 470 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
454 471 void pythonHelpRequest(const QByteArray& cppClassName);
455 472
456 473 private:
457 474 void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName);
458 475
459 476 //! callback for stdout redirection, emits pythonStdOut signal
460 477 static void stdOutRedirectCB(const QString& str);
461 478 //! callback for stderr redirection, emits pythonStdErr signal
462 479 static void stdErrRedirectCB(const QString& str);
463 480
464 481 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
465 482 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
466 483
467 484 PythonQt(int flags, const QByteArray& pythonQtModuleName);
468 485 ~PythonQt();
469 486
470 487 static PythonQt* _self;
471 488 static int _uniqueModuleCount;
472 489
473 490 PythonQtPrivate* _p;
474 491
475 492 };
476 493
477 494 //! internal PythonQt details
478 495 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
479 496
480 497 Q_OBJECT
481 498
482 499 public:
483 500 PythonQtPrivate();
484 501 ~PythonQtPrivate();
485 502
486 503 enum DecoratorTypes {
487 504 StaticDecorator = 1,
488 505 ConstructorDecorator = 2,
489 506 DestructorDecorator = 4,
490 507 InstanceDecorator = 8,
491 508 AllDecorators = 0xffff
492 509 };
493 510
494 511 //! get the suffixes that are used for shared libraries
495 512 const QStringList& sharedLibrarySuffixes() { return _sharedLibrarySuffixes; }
496 513
497 514 //! returns if the id is the id for PythonQtObjectPtr
498 515 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
499 516
500 517 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
501 518 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
502 519 //! remove the wrapper ptr again
503 520 void removeWrapperPointer(void* obj);
504 521
505 522 //! add parent class relation
506 523 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
507 524
508 525 //! add a handler for polymorphic downcasting
509 526 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
510
527
511 528 //! lookup existing classinfo and return new if not yet present
512 529 PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
513 530
514 531 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
515 532 void removeSignalEmitter(QObject* obj);
516 533
517 534 //! wrap the given QObject into a Python object (or return existing wrapper!)
518 535 PyObject* wrapQObject(QObject* obj);
519 536
520 537 //! wrap the given ptr into a Python object (or return existing wrapper!) if there is a known QObject of that name or a known wrapper in the factory
521 538 PyObject* wrapPtr(void* ptr, const QByteArray& name);
522 539
523 540 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
524 541 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
525 542 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
526 543 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
527 544
528 545 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
529 546 //! (ownership of wrapper is passed to PythonQt)
530 547 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
531
548
532 549 This will add a wrapper object that is used to make calls to the given classname \c typeName.
533 550 All slots that take a pointer to typeName as the first argument will be callable from Python on
534 551 a variant object that contains such a type.
535 552 */
536 553 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
537
554
538 555 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
539 556 //! and it will register the classes when it first sees a pointer to such a derived class
540 557 void registerQObjectClassNames(const QStringList& names);
541 558
542 559 //! add a decorator object
543 560 void addDecorators(QObject* o, int decoTypes);
544 561
545 562 //! helper method that creates a PythonQtClassWrapper object (returns a new reference)
546 563 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* module);
547 564
548 565 //! create a new instance of the given enum type with given value (returns a new reference)
549 566 static PyObject* createEnumValueInstance(PyObject* enumType, unsigned int enumValue);
550 567
551 568 //! helper that creates a new int derived class that represents the enum of the given name (returns a new reference)
552 569 static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
553 570
554 571 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
555 572 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
556 573
557 574 //! get the class info for a meta object (if available)
558 575 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
559 576
560 577 //! get the class info for a meta object (if available)
561 578 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
562 579
563 580 //! creates the new module from the given pycode
564 581 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
565 582
566 583 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
567 584 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
568 585
569 586 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
570 587 static PyObject* dummyTuple();
571 588
572 589 //! called by virtual overloads when a python return value can not be converted to the required Qt type
573 590 void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result);
574
591
575 592 //! get access to the PythonQt module
576 593 PythonQtObjectPtr pythonQtModule() const { return _pythonQtModule; }
577 594
595 //! returns the profiling callback, which may be NULL
596 PythonQt::ProfilingCB* profilingCB() const { return _profilingCB; }
597
578 598 private:
579 599 //! Setup the shared library suffixes by getting them from the "imp" module.
580 600 void setupSharedLibrarySuffixes();
581 601
582 602 //! create a new pythonqt class wrapper and place it in the pythonqt module
583 603 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module = NULL);
584 604
585 605 //! get/create new package module (the returned object is a borrowed reference)
586 606 PyObject* packageByName(const char* name);
587 607
588 608 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
589 609 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
590 610
591 611 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
592 612 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
593 613
594 614 //! stores the meta info of known Qt classes
595 615 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
596 616
597 617 //! names of qobject derived classes that can be casted to qobject savely
598 618 QHash<QByteArray, bool> _knownQObjectClassNames;
599 619
600 620 //! stores signal receivers for QObjects
601 621 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
602 622
603 623 //! the PythonQt python module
604 624 PythonQtObjectPtr _pythonQtModule;
605 625
606 626 //! the name of the PythonQt python module
607 627 QByteArray _pythonQtModuleName;
608
628
609 629 //! the importer interface (if set)
610 630 PythonQtImportFileInterface* _importInterface;
611 631
612 632 //! the default importer
613 633 PythonQtQFileImporter* _defaultImporter;
614
634
615 635 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
616 636 PythonQtQObjectWrappedCB* _wrappedCB;
617 637
618 638 QStringList _importIgnorePaths;
619 639 QStringList _sharedLibrarySuffixes;
620 640
621 641 //! the cpp object wrapper factories
622 642 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
623 643
624 644 QHash<QByteArray, PyObject*> _packages;
625 645
626 646 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
627 647
648 PythonQt::ProfilingCB* _profilingCB;
649
628 650 int _initFlags;
629 651 int _PythonQtObjectPtr_metaId;
630 652
631 653 friend class PythonQt;
632 654 };
633 655
634 656 #endif
@@ -1,849 +1,868
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtClassInfo.h"
43 43 #include "PythonQtMethodInfo.h"
44 44 #include "PythonQt.h"
45 45 #include <QMetaMethod>
46 46 #include <QMetaObject>
47 47 #include <QMetaEnum>
48 48
49 49 QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;
50 50
51 51 PythonQtClassInfo::PythonQtClassInfo() {
52 52 _meta = NULL;
53 53 _constructors = NULL;
54 54 _destructor = NULL;
55 55 _decoratorProvider = NULL;
56 56 _decoratorProviderCB = NULL;
57 57 _pythonQtClassWrapper = NULL;
58 58 _shellSetInstanceWrapperCB = NULL;
59 59 _metaTypeId = -1;
60 60 _typeSlots = 0;
61 61 _isQObject = false;
62 62 _enumsCreated = false;
63 63 }
64 64
65 65 PythonQtClassInfo::~PythonQtClassInfo()
66 66 {
67 67 clearCachedMembers();
68 68
69 69 if (_constructors) {
70 70 _constructors->deleteOverloadsAndThis();
71 71 }
72 72 if (_destructor) {
73 73 _destructor->deleteOverloadsAndThis();
74 74 }
75 75 foreach(PythonQtSlotInfo* info, _decoratorSlots) {
76 76 info->deleteOverloadsAndThis();
77 77 }
78 78 }
79 79
80 80 void PythonQtClassInfo::setupQObject(const QMetaObject* meta)
81 81 {
82 82 // _wrappedClassName is already set earlier in the class setup
83 83 _isQObject = true;
84 84 _meta = meta;
85 85 }
86 86
87 87 void PythonQtClassInfo::setupCPPObject(const QByteArray& classname)
88 88 {
89 89 _isQObject = false;
90 90 _wrappedClassName = classname;
91 91 _metaTypeId = QMetaType::type(classname);
92 92 }
93 93
94 94 void PythonQtClassInfo::clearCachedMembers()
95 95 {
96 96 QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers);
97 97 while (i.hasNext()) {
98 98 PythonQtMemberInfo member = i.next().value();
99 99 if (member._type== PythonQtMemberInfo::Slot) {
100 100 PythonQtSlotInfo* info = member._slot;
101 101 while (info) {
102 102 PythonQtSlotInfo* next = info->nextInfo();
103 103 delete info;
104 104 info = next;
105 105 }
106 106 }
107 107 }
108 108 }
109 109
110 110 int PythonQtClassInfo::findCharOffset(const char* sigStart, char someChar)
111 111 {
112 112 const char* sigEnd = sigStart;
113 113 char c;
114 114 do {
115 115 c = *sigEnd++;
116 116 } while (c!=someChar && c!=0);
117 117 return sigEnd-sigStart-1;
118 118 }
119 119
120 120 bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName)
121 121 {
122 122 if (!_meta) return false;
123 123
124 124 bool found = false;
125 125 bool nameMapped = false;
126 126 const char* attributeName = memberName;
127 127 // look for properties
128 128 int i = _meta->indexOfProperty(attributeName);
129 129 if (i==-1) {
130 130 // try to map name to objectName
131 131 if (qstrcmp(attributeName, "name")==0) {
132 132 attributeName = "objectName";
133 133 nameMapped = true;
134 134 i = _meta->indexOfProperty(attributeName);
135 135 }
136 136 }
137 137 if (i!=-1) {
138 138 PythonQtMemberInfo newInfo(_meta->property(i));
139 139 _cachedMembers.insert(attributeName, newInfo);
140 140 if (nameMapped) {
141 141 _cachedMembers.insert(memberName, newInfo);
142 142 }
143 143 #ifdef PYTHONQT_DEBUG
144 144 std::cout << "caching property " << memberName << " on " << _meta->className() << std::endl;
145 145 #endif
146 146 found = true;
147 147 }
148 148 return found;
149 149 }
150 150
151 151 PythonQtSlotInfo* PythonQtClassInfo::recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
152 152 {
153 153 inputInfo = findDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset);
154 154 foreach(const ParentClassInfo& info, _parentClasses) {
155 155 inputInfo = info._parent->recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset+info._upcastingOffset);
156 156 }
157 157 return inputInfo;
158 158 }
159 159
160 160 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset) {
161 161 QObject* decoratorProvider = decorator();
162 162 int memberNameLen = strlen(memberName);
163 163 if (decoratorProvider) {
164 164 //qDebug()<< "looking " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
165 165 const QMetaObject* meta = decoratorProvider->metaObject();
166 166 int numMethods = meta->methodCount();
167 167 int startFrom = QObject::staticMetaObject.methodCount();
168 168 for (int i = startFrom; i < numMethods; i++) {
169 169 QMetaMethod m = meta->method(i);
170 170 if ((m.methodType() == QMetaMethod::Method ||
171 171 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
172 172
173 173 const char* sigStart = m.signature();
174 174 bool isClassDeco = false;
175 175 if (qstrncmp(sigStart, "static_", 7)==0) {
176 176 // skip the static_classname_ part of the string
177 177 sigStart += 7 + 1 + strlen(className());
178 178 isClassDeco = true;
179 179 } else if (qstrncmp(sigStart, "new_", 4)==0) {
180 180 isClassDeco = true;
181 181 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
182 182 isClassDeco = true;
183 183 }
184 184 // find the first '('
185 185 int offset = findCharOffset(sigStart, '(');
186 186
187 187 // XXX no checking is currently done if the slots have correct first argument or not...
188 188
189 189 // check if same length and same name
190 190 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
191 191 found = true;
192 192 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i, decoratorProvider, isClassDeco?PythonQtSlotInfo::ClassDecorator:PythonQtSlotInfo::InstanceDecorator);
193 193 info->setUpcastingOffset(upcastingOffset);
194 194 //qDebug()<< "adding " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
195 195 if (tail) {
196 196 tail->setNextInfo(info);
197 197 } else {
198 198 PythonQtMemberInfo newInfo(info);
199 199 memberCache.insert(memberName, newInfo);
200 200 }
201 201 tail = info;
202 202 }
203 203 }
204 204 }
205 205 }
206 206
207 207 tail = findDecoratorSlots(memberName, memberNameLen, tail, found, memberCache, upcastingOffset);
208 208
209 209 return tail;
210 210 }
211 211
212 212 bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName)
213 213 {
214 214 bool found = false;
215 215 int memberNameLen = strlen(memberName);
216 216 PythonQtSlotInfo* tail = NULL;
217 217 if (_meta) {
218 218 int numMethods = _meta->methodCount();
219 219 for (int i = 0; i < numMethods; i++) {
220 220 QMetaMethod m = _meta->method(i);
221 221 if (((m.methodType() == QMetaMethod::Method ||
222 222 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public)
223 223 || m.methodType()==QMetaMethod::Signal) {
224 224
225 225 const char* sigStart = m.signature();
226 226 // find the first '('
227 227 int offset = findCharOffset(sigStart, '(');
228 228
229 229 // check if same length and same name
230 230 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
231 231 found = true;
232 232 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i);
233 233 if (tail) {
234 234 tail->setNextInfo(info);
235 235 } else {
236 236 PythonQtMemberInfo newInfo(info);
237 237 _cachedMembers.insert(memberName, newInfo);
238 238 }
239 239 tail = info;
240 240 }
241 241 }
242 242 }
243 243 }
244 244
245 245 // look for dynamic decorators in this class and in derived classes
246 246 tail = recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, tail, found, _cachedMembers, 0);
247 247
248 248 return found;
249 249 }
250 250
251 251 bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* memberName)
252 252 {
253 253 bool found = false;
254 254 // look for enum values
255 255 int enumCount = meta->enumeratorCount();
256 256 for (int i=0;i<enumCount; i++) {
257 257 QMetaEnum e = meta->enumerator(i);
258 258 // we do not want flags, they will cause our values to appear two times
259 259 if (e.isFlag()) continue;
260 260
261 261 for (int j=0; j < e.keyCount(); j++) {
262 262 if (qstrcmp(e.key(j), memberName)==0) {
263 263 PyObject* enumType = findEnumWrapper(e.name());
264 264 if (enumType) {
265 265 PythonQtObjectPtr enumValuePtr;
266 266 enumValuePtr.setNewRef(PythonQtPrivate::createEnumValueInstance(enumType, e.value(j)));
267 267 PythonQtMemberInfo newInfo(enumValuePtr);
268 268 _cachedMembers.insert(memberName, newInfo);
269 269 #ifdef PYTHONQT_DEBUG
270 270 std::cout << "caching enum " << memberName << " on " << meta->className() << std::endl;
271 271 #endif
272 272 found = true;
273 273 break;
274 274 } else {
275 275 std::cout << "enum " << e.name() << " not found on " << className() << std::endl;
276 276 }
277 277 }
278 278 }
279 279 }
280 280 return found;
281 281 }
282 282
283 283 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
284 284 {
285 285 PythonQtMemberInfo info = _cachedMembers.value(memberName);
286 286 if (info._type != PythonQtMemberInfo::Invalid) {
287 287 return info;
288 288 } else {
289 289 bool found = false;
290 290
291 291 found = lookForPropertyAndCache(memberName);
292 292 if (!found) {
293 293 found = lookForMethodAndCache(memberName);
294 294 }
295 295 if (!found) {
296 296 if (_meta) {
297 297 // check enums in our meta object directly
298 298 found = lookForEnumAndCache(_meta, memberName);
299 299 }
300 300 if (!found) {
301 301 // check enums in the class hierachy of CPP classes
302 302 // look for dynamic decorators in this class and in derived classes
303 303 QList<QObject*> decoObjects;
304 304 recursiveCollectDecoratorObjects(decoObjects);
305 305 foreach(QObject* deco, decoObjects) {
306 306 // call on ourself for caching, but with different metaObject():
307 307 found = lookForEnumAndCache(deco->metaObject(), memberName);
308 308 if (found) {
309 309 break;
310 310 }
311 311 }
312 312 }
313 313 }
314 314 if (!found) {
315 315 // maybe it is an enum wrapper?
316 316 PyObject* p = findEnumWrapper(memberName);
317 317 if (p) {
318 318 info._type = PythonQtMemberInfo::EnumWrapper;
319 319 info._enumWrapper = p;
320 320 _cachedMembers.insert(memberName, info);
321 321 found = true;
322 322 }
323 323 }
324 324 if (!found) {
325 325 // since python keywords can not be looked up, we check if the name contains a single trailing _
326 326 // and remove that and look again, so that we e.g. find exec on an exec_ lookup
327 327 QByteArray mbrName(memberName);
328 328 if ((mbrName.length()>2) &&
329 329 (mbrName.at(mbrName.length()-1) == '_') &&
330 330 (mbrName.at(mbrName.length()-2) != '_')) {
331 331 mbrName = mbrName.mid(0,mbrName.length()-1);
332 332 found = lookForMethodAndCache(mbrName.constData());
333 333 if (found) {
334 334 return _cachedMembers.value(mbrName);
335 335 }
336 336 }
337 337 }
338 338 if (!found) {
339 339 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
340 340 info._type = PythonQtMemberInfo::NotFound;
341 341 _cachedMembers.insert(memberName, info);
342 342 }
343 343 }
344 344
345 345 return _cachedMembers.value(memberName);
346 346 }
347 347
348 348 void PythonQtClassInfo::recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects) {
349 349 QObject* deco = decorator();
350 350 if (deco) {
351 351 decoratorObjects.append(deco);
352 352 }
353 353 foreach(const ParentClassInfo& info, _parentClasses) {
354 354 info._parent->recursiveCollectDecoratorObjects(decoratorObjects);
355 355 }
356 356 }
357 357
358 358 void PythonQtClassInfo::recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects) {
359 359 classInfoObjects.append(this);
360 360 foreach(const ParentClassInfo& info, _parentClasses) {
361 361 info._parent->recursiveCollectClassInfos(classInfoObjects);
362 362 }
363 363 }
364 364
365 365 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
366 366 {
367 367 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
368 368 while (it.hasNext()) {
369 369
370 370 PythonQtSlotInfo* infoOrig = it.next();
371 371
372 372 const char* sigStart = infoOrig->metaMethod()->signature();
373 373 if (qstrncmp("static_", sigStart, 7)==0) {
374 374 sigStart += 7;
375 375 sigStart += findCharOffset(sigStart, '_')+1;
376 376 }
377 377 int offset = findCharOffset(sigStart, '(');
378 378 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
379 379 //make a copy, otherwise we will have trouble on overloads!
380 380 PythonQtSlotInfo* info = new PythonQtSlotInfo(*infoOrig);
381 381 info->setUpcastingOffset(upcastingOffset);
382 382 found = true;
383 383 if (tail) {
384 384 tail->setNextInfo(info);
385 385 } else {
386 386 PythonQtMemberInfo newInfo(info);
387 387 memberCache.insert(memberName, newInfo);
388 388 }
389 389 tail = info;
390 390 }
391 391 }
392 392 return tail;
393 393 }
394 394
395 395 void PythonQtClassInfo::listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly) {
396 396 QObject* decoratorProvider = decorator();
397 397 if (decoratorProvider) {
398 398 const QMetaObject* meta = decoratorProvider->metaObject();
399 399 int numMethods = meta->methodCount();
400 400 int startFrom = QObject::staticMetaObject.methodCount();
401 401 for (int i = startFrom; i < numMethods; i++) {
402 402 QMetaMethod m = meta->method(i);
403 403 if ((m.methodType() == QMetaMethod::Method ||
404 404 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
405 405
406 406 const char* sigStart = m.signature();
407 407 bool isClassDeco = false;
408 408 if (qstrncmp(sigStart, "static_", 7)==0) {
409 409 // skip the static_classname_ part of the string
410 410 sigStart += 7 + 1 + strlen(className());
411 411 isClassDeco = true;
412 412 } else if (qstrncmp(sigStart, "new_", 4)==0) {
413 413 continue;
414 414 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
415 415 continue;
416 416 } else if (qstrncmp(sigStart, "py_", 3)==0) {
417 417 // hide everything that starts with py_
418 418 continue;
419 419 }
420 420 // find the first '('
421 421 int offset = findCharOffset(sigStart, '(');
422 422
423 423 // XXX no checking is currently done if the slots have correct first argument or not...
424 424 if (!metaOnly || isClassDeco) {
425 425 list << QString::fromLatin1(sigStart, offset);
426 426 }
427 427 }
428 428 }
429 429 }
430 430
431 431 // look for global decorator slots
432 432 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
433 433 while (it.hasNext()) {
434 434 PythonQtSlotInfo* slot = it.next();
435 435 if (metaOnly) {
436 436 if (slot->isClassDecorator()) {
437 437 QByteArray first = slot->slotName();
438 438 if (first.startsWith("static_")) {
439 439 int idx = first.indexOf('_');
440 440 idx = first.indexOf('_', idx+1);
441 441 first = first.mid(idx+1);
442 442 }
443 443 list << first;
444 444 }
445 445 } else {
446 446 list << slot->slotName();
447 447 }
448 448 }
449 449 }
450 450
451 451 QStringList PythonQtClassInfo::propertyList()
452 452 {
453 453 QStringList l;
454 454 if (_isQObject && _meta) {
455 455 int i;
456 456 int numProperties = _meta->propertyCount();
457 457 for (i = 0; i < numProperties; i++) {
458 458 QMetaProperty p = _meta->property(i);
459 459 l << QString(p.name());
460 460 }
461 461 }
462 462 return l;
463 463 }
464 464
465 465 QStringList PythonQtClassInfo::memberList(bool metaOnly)
466 466 {
467 467 decorator();
468 468
469 469 QStringList l;
470 470 QString h;
471 471 if (_isQObject && _meta && !metaOnly) {
472 472 l = propertyList();
473 473 }
474 474
475 475 // normal slots of QObject (or wrapper QObject)
476 476 if (!metaOnly && _meta) {
477 477 int numMethods = _meta->methodCount();
478 478 bool skipQObj = !_isQObject;
479 479 for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) {
480 480 QMetaMethod m = _meta->method(i);
481 481 if (((m.methodType() == QMetaMethod::Method ||
482 482 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public)
483 483 || m.methodType()==QMetaMethod::Signal) {
484 484 QByteArray signa(m.signature());
485 485 signa = signa.left(signa.indexOf('('));
486 486 l << signa;
487 487 }
488 488 }
489 489 }
490 490
491 491 {
492 492 // look for dynamic decorators in this class and in derived classes
493 493 QList<PythonQtClassInfo*> infos;
494 494 recursiveCollectClassInfos(infos);
495 495 foreach(PythonQtClassInfo* info, infos) {
496 496 info->listDecoratorSlotsFromDecoratorProvider(l, metaOnly);
497 497 }
498 498 }
499 499
500 500 // List enumerator keys...
501 501 QList<const QMetaObject*> enumMetaObjects;
502 502 if (_meta) {
503 503 enumMetaObjects << _meta;
504 504 }
505 505 // check enums in the class hierachy of CPP classes
506 506 QList<QObject*> decoObjects;
507 507 recursiveCollectDecoratorObjects(decoObjects);
508 508 foreach(QObject* deco, decoObjects) {
509 509 enumMetaObjects << deco->metaObject();
510 510 }
511 511
512 512 foreach(const QMetaObject* meta, enumMetaObjects) {
513 513 for (int i = 0; i<meta->enumeratorCount(); i++) {
514 514 QMetaEnum e = meta->enumerator(i);
515 515 l << e.name();
516 516 // we do not want flags, they will cause our values to appear two times
517 517 if (e.isFlag()) continue;
518 518
519 519 for (int j=0; j < e.keyCount(); j++) {
520 520 l << QString(e.key(j));
521 521 }
522 522 }
523 523 }
524 524
525 525 return QSet<QString>::fromList(l).toList();
526 526 }
527 527
528 528 const char* PythonQtClassInfo::className()
529 529 {
530 530 return _wrappedClassName.constData();
531 531 }
532 532
533 533 void* PythonQtClassInfo::castTo(void* ptr, const char* classname)
534 534 {
535 535 if (ptr==NULL) {
536 536 return NULL;
537 537 }
538 538 if (_wrappedClassName == classname) {
539 539 return ptr;
540 540 }
541 541 foreach(const ParentClassInfo& info, _parentClasses) {
542 542 void* result = info._parent->castTo((char*)ptr + info._upcastingOffset, classname);
543 543 if (result) {
544 544 return result;
545 545 }
546 546 }
547 547 return NULL;
548 548 }
549 549
550 550 bool PythonQtClassInfo::inherits(const char* name)
551 551 {
552 552 if (_wrappedClassName == name) {
553 553 return true;
554 554 }
555 555 foreach(const ParentClassInfo& info, _parentClasses) {
556 556 if (info._parent->inherits(name)) {
557 557 return true;
558 558 }
559 559 }
560 560 return false;
561 561 }
562 562
563 563 bool PythonQtClassInfo::inherits(PythonQtClassInfo* classInfo)
564 564 {
565 565 if (classInfo == this) {
566 566 return true;
567 567 }
568 568 foreach(const ParentClassInfo& info, _parentClasses) {
569 569 if (info._parent->inherits(classInfo)) {
570 570 return true;
571 571 }
572 572 }
573 573 return false;
574 574 }
575 575
576 576 QString PythonQtClassInfo::help()
577 577 {
578 578 decorator();
579 579 QString h;
580 580 h += QString("--- ") + QString(className()) + QString(" ---\n");
581 581
582 582 if (_isQObject) {
583 583 h += "Properties:\n";
584 584
585 585 int i;
586 586 int numProperties = _meta->propertyCount();
587 587 for (i = 0; i < numProperties; i++) {
588 588 QMetaProperty p = _meta->property(i);
589 589 h += QString(p.name()) + " (" + QString(p.typeName()) + " )\n";
590 590 }
591 591 }
592 592
593 593 if (constructors()) {
594 594 h += "Constructors:\n";
595 595 PythonQtSlotInfo* constr = constructors();
596 596 while (constr) {
597 597 h += constr->fullSignature() + "\n";
598 598 constr = constr->nextInfo();
599 599 }
600 600 }
601 601
602 602 h += "Slots:\n";
603 603 h += "QString help()\n";
604 604 h += "QString className()\n";
605 605
606 606 if (_meta) {
607 607 int numMethods = _meta->methodCount();
608 608 for (int i = 0; i < numMethods; i++) {
609 609 QMetaMethod m = _meta->method(i);
610 610 if ((m.methodType() == QMetaMethod::Method ||
611 611 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
612 612 PythonQtSlotInfo slot(this, m, i);
613 613 h += slot.fullSignature()+ "\n";
614 614 }
615 615 }
616 616 }
617 617
618 618 // TODO xxx : decorators and enums from decorator() are missing...
619 619 // maybe we can reuse memberlist()?
620 620
621 621 if (_meta && _meta->enumeratorCount()) {
622 622 h += "Enums:\n";
623 623 for (int i = 0; i<_meta->enumeratorCount(); i++) {
624 624 QMetaEnum e = _meta->enumerator(i);
625 625 h += QString(e.name()) + " {";
626 626 for (int j=0; j < e.keyCount(); j++) {
627 627 if (j) { h+= ", "; }
628 628 h += e.key(j);
629 629 }
630 630 h += " }\n";
631 631 }
632 632 }
633 633
634 634 if (_isQObject && _meta) {
635 635 int numMethods = _meta->methodCount();
636 636 if (numMethods>0) {
637 637 h += "Signals:\n";
638 638 for (int i = 0; i < numMethods; i++) {
639 639 QMetaMethod m = _meta->method(i);
640 640 if (m.methodType() == QMetaMethod::Signal) {
641 641 h += QString(m.signature()) + "\n";
642 642 }
643 643 }
644 644 }
645 645 }
646 646 return h;
647 647 }
648 648
649 649 PythonQtSlotInfo* PythonQtClassInfo::constructors()
650 650 {
651 651 if (!_constructors) {
652 652 // force creation of lazy decorator, which will register the decorators
653 653 decorator();
654 654 }
655 655 return _constructors;
656 656 }
657 657
658 658 PythonQtSlotInfo* PythonQtClassInfo::destructor()
659 659 {
660 660 if (!_destructor) {
661 661 // force creation of lazy decorator, which will register the decorators
662 662 decorator();
663 663 }
664 664 return _destructor;
665 665 }
666 666
667 667 void PythonQtClassInfo::addConstructor(PythonQtSlotInfo* info)
668 668 {
669 669 PythonQtSlotInfo* prev = constructors();
670 670 if (prev) {
671 671 info->setNextInfo(prev->nextInfo());
672 672 prev->setNextInfo(info);
673 673 } else {
674 674 _constructors = info;
675 675 }
676 676 }
677 677
678 678 void PythonQtClassInfo::addDecoratorSlot(PythonQtSlotInfo* info)
679 679 {
680 680 _decoratorSlots.append(info);
681 681 }
682 682
683 683 void PythonQtClassInfo::setDestructor(PythonQtSlotInfo* info)
684 684 {
685 685 if (_destructor) {
686 686 _destructor->deleteOverloadsAndThis();
687 687 }
688 688 _destructor = info;
689 689 }
690 690
691 691 void PythonQtClassInfo::setMetaObject(const QMetaObject* meta)
692 692 {
693 693 _meta = meta;
694 694 clearCachedMembers();
695 695 }
696 696
697 697 QObject* PythonQtClassInfo::decorator()
698 698 {
699 699 if (!_decoratorProvider && _decoratorProviderCB) {
700 700 _decoratorProvider = (*_decoratorProviderCB)();
701 701 if (_decoratorProvider) {
702 702 _decoratorProvider->setParent(PythonQt::priv());
703 703 // setup enums early, since they might be needed by the constructor decorators:
704 704 if (!_enumsCreated) {
705 705 createEnumWrappers();
706 706 }
707 707 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
708 708 }
709 709 }
710 710 // check if enums need to be created and create them if they are not yet created
711 711 if (!_enumsCreated) {
712 712 createEnumWrappers();
713 713 }
714 714 return _decoratorProvider;
715 715 }
716 716
717 717 bool PythonQtClassInfo::hasOwnerMethodButNoOwner(void* object)
718 718 {
719 719 PythonQtMemberInfo info = member("py_hasOwner");
720 720 if (info._type == PythonQtMemberInfo::Slot) {
721 721 void* obj = object;
722 722 bool result = false;
723 723 void* args[2];
724 724 args[0] = &result;
725 725 args[1] = &obj;
726 726 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
727 727 return !result;
728 728 } else {
729 729 return false;
730 730 }
731 731 }
732 732
733 733 void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, char** resultClassName)
734 734 {
735 735 if (!_polymorphicHandlers.isEmpty()) {
736 736 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
737 737 void* resultPtr = (*cb)(ptr, resultClassName);
738 738 if (resultPtr) {
739 739 return resultPtr;
740 740 }
741 741 }
742 742 }
743 743 foreach(const ParentClassInfo& info, _parentClasses) {
744 744 if (!info._parent->isQObject()) {
745 745 void* resultPtr = info._parent->recursiveCastDownIfPossible((char*)ptr + info._upcastingOffset, resultClassName);
746 746 if (resultPtr) {
747 747 return resultPtr;
748 748 }
749 749 }
750 750 }
751 751 return NULL;
752 752 }
753 753
754 754 void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo)
755 755 {
756 756 char* className;
757 757 // this would do downcasting recursively...
758 758 // void* resultPtr = recursiveCastDownIfPossible(ptr, &className);
759 759
760 760 // we only do downcasting on the base object, not on the whole inheritance tree...
761 761 void* resultPtr = NULL;
762 762 if (!_polymorphicHandlers.isEmpty()) {
763 763 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
764 764 resultPtr = (*cb)(ptr, &className);
765 765 if (resultPtr) {
766 766 break;
767 767 }
768 768 }
769 769 }
770 770 if (resultPtr) {
771 771 *resultClassInfo = PythonQt::priv()->getClassInfo(className);
772 772 } else {
773 773 *resultClassInfo = this;
774 774 resultPtr = ptr;
775 775 }
776 776 return resultPtr;
777 777 }
778 778
779 779 PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum)
780 780 {
781 781 if (isLocalEnum) {
782 782 *isLocalEnum = true;
783 783 }
784 784 int scopePos = name.lastIndexOf("::");
785 785 if (scopePos != -1) {
786 786 if (isLocalEnum) {
787 787 *isLocalEnum = false;
788 788 }
789 789 // split into scope and enum name
790 790 QByteArray enumScope = name.mid(0,scopePos);
791 791 QByteArray enumName = name.mid(scopePos+2);
792 792 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(enumScope);
793 793 if (info) {
794 794 return info->findEnumWrapper(enumName);
795 795 } else{
796 796 return NULL;
797 797 }
798 798 }
799 799 if (localScope) {
800 800 return localScope->findEnumWrapper(name);
801 801 } else {
802 802 return NULL;
803 803 }
804 804 }
805 805
806 806 void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta)
807 807 {
808 808 for (int i = meta->enumeratorOffset();i<meta->enumeratorCount();i++) {
809 809 QMetaEnum e = meta->enumerator(i);
810 810 PythonQtObjectPtr p;
811 811 p.setNewRef(PythonQtPrivate::createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper));
812 812 _enumWrappers.append(p);
813 813 }
814 814 }
815 815
816 816 void PythonQtClassInfo::createEnumWrappers()
817 817 {
818 818 if (!_enumsCreated) {
819 819 _enumsCreated = true;
820 820 if (_meta) {
821 821 createEnumWrappers(_meta);
822 822 }
823 823 if (decorator()) {
824 824 createEnumWrappers(decorator()->metaObject());
825 825 }
826 826 foreach(const ParentClassInfo& info, _parentClasses) {
827 827 info._parent->createEnumWrappers();
828 828 }
829 829 }
830 830 }
831 831
832 832 PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) {
833 833 // force enum creation
834 834 if (!_enumsCreated) {
835 835 createEnumWrappers();
836 836 }
837 837 foreach(const PythonQtObjectPtr& p, _enumWrappers) {
838 838 const char* className = ((PyTypeObject*)p.object())->tp_name;
839 839 if (qstrcmp(className, name)==0) {
840 840 return p.object();
841 841 }
842 842 }
843 843 foreach(const ParentClassInfo& info, _parentClasses) {
844 844 PyObject* p = info._parent->findEnumWrapper(name);
845 845 if (p) return p;
846 846 }
847 847 return NULL;
848 848 }
849 849
850 void PythonQtClassInfo::setDecoratorProvider( PythonQtQObjectCreatorFunctionCB* cb )
851 {
852 _decoratorProviderCB = cb;
853 _decoratorProvider = NULL;
854 _enumsCreated = false;
855 }
856
857 void PythonQtClassInfo::clearNotFoundCachedMembers()
858 {
859 // remove all not found entries, since a new decorator means new slots,
860 // which might have been cached as "NotFound" already.
861 QMutableHashIterator<QByteArray, PythonQtMemberInfo> it(_cachedMembers);
862 while (it.hasNext()) {
863 it.next();
864 if (it.value()._type == PythonQtMemberInfo::NotFound) {
865 it.remove();
866 }
867 }
868 }
@@ -1,262 +1,265
1 1 #ifndef _PYTHONQTCLASSINFO_H
2 2 #define _PYTHONQTCLASSINFO_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 #include <QMetaObject>
37 37 #include <QMetaMethod>
38 38 #include <QHash>
39 39 #include <QByteArray>
40 40 #include <QList>
41 41 #include "PythonQt.h"
42 42
43 43 class PythonQtSlotInfo;
44 44
45 45 struct PythonQtMemberInfo {
46 46 enum Type {
47 47 Invalid, Slot, EnumValue, EnumWrapper, Property, NotFound
48 48 };
49 49
50 50 PythonQtMemberInfo():_type(Invalid),_slot(NULL),_enumWrapper(NULL),_enumValue(0) { }
51 51
52 52 PythonQtMemberInfo(PythonQtSlotInfo* info) {
53 53 _type = Slot;
54 54 _slot = info;
55 55 _enumValue = NULL;
56 56 }
57 57
58 58 PythonQtMemberInfo(const PythonQtObjectPtr& enumValue) {
59 59 _type = EnumValue;
60 60 _slot = NULL;
61 61 _enumValue = enumValue;
62 62 _enumWrapper = NULL;
63 63 }
64 64
65 65 PythonQtMemberInfo(const QMetaProperty& prop) {
66 66 _type = Property;
67 67 _slot = NULL;
68 68 _enumValue = NULL;
69 69 _property = prop;
70 70 _enumWrapper = NULL;
71 71 }
72 72
73 73 Type _type;
74 74
75 75 // TODO: this could be a union...
76 76 PythonQtSlotInfo* _slot;
77 77 PyObject* _enumWrapper;
78 78 PythonQtObjectPtr _enumValue;
79 79 QMetaProperty _property;
80 80 };
81 81
82 82 //! a class that stores all required information about a Qt object (and an optional associated C++ class name)
83 83 /*! for fast lookup of slots when calling the object from Python
84 84 */
85 85 class PYTHONQT_EXPORT PythonQtClassInfo {
86 86
87 87 public:
88 88 PythonQtClassInfo();
89 89 ~PythonQtClassInfo();
90 90
91 91 //! store information about parent classes
92 92 struct ParentClassInfo {
93 93 ParentClassInfo(PythonQtClassInfo* parent, int upcastingOffset=0):_parent(parent),_upcastingOffset(upcastingOffset)
94 94 {};
95 95
96 96 PythonQtClassInfo* _parent;
97 97 int _upcastingOffset;
98 98 };
99 99
100 100
101 101 //! setup as a QObject, taking the meta object as meta information about the QObject
102 102 void setupQObject(const QMetaObject* meta);
103 103
104 104 //! setup as a CPP (non-QObject), taking the classname
105 105 void setupCPPObject(const QByteArray& classname);
106 106
107 107 //! set the type capabilities
108 108 void setTypeSlots(int typeSlots) { _typeSlots = typeSlots; }
109 109 //! get the type capabilities
110 110 int typeSlots() const { return _typeSlots; }
111 111
112 112 //! get the Python method definition for a given slot name (without return type and signature)
113 113 PythonQtMemberInfo member(const char* member);
114 114
115 115 //! get access to the constructor slot (which may be overloaded if there are multiple constructors)
116 116 PythonQtSlotInfo* constructors();
117 117
118 118 //! get access to the destructor slot
119 119 PythonQtSlotInfo* destructor();
120 120
121 121 //! add a constructor, ownership is passed to classinfo
122 122 void addConstructor(PythonQtSlotInfo* info);
123 123
124 124 //! set a destructor, ownership is passed to classinfo
125 125 void setDestructor(PythonQtSlotInfo* info);
126 126
127 127 //! add a decorator slot, ownership is passed to classinfo
128 128 void addDecoratorSlot(PythonQtSlotInfo* info);
129 129
130 130 //! get the classname (either of the QObject or of the wrapped CPP object)
131 131 const char* className();
132 132
133 133 //! returns if the QObject
134 134 bool isQObject() { return _isQObject; }
135 135
136 136 //! returns if the class is a CPP wrapper
137 137 bool isCPPWrapper() { return !_isQObject; }
138 138
139 139 //! get the meta object
140 140 const QMetaObject* metaObject() { return _meta; }
141 141
142 142 //! set the meta object, this will reset the caching
143 143 void setMetaObject(const QMetaObject* meta);
144 144
145 145 //! returns if this class inherits from the given classname
146 146 bool inherits(const char* classname);
147 147
148 148 //! returns if this class inherits from the given classinfo
149 149 bool inherits(PythonQtClassInfo* info);
150 150
151 151 //! casts the given \c ptr to an object of type \c classname, returns the new pointer
152 152 //! which might be different to \c ptr due to C++ multiple inheritance
153 153 //! (if the cast is not possible or if ptr is NULL, NULL is returned)
154 154 void* castTo(void* ptr, const char* classname);
155 155
156 156 //! get help string for the metaobject
157 157 QString help();
158 158
159 159 //! get list of all properties (on QObjects only, otherwise the list is empty)
160 160 QStringList propertyList();
161 161
162 162 //! get list of all members
163 163 QStringList memberList(bool metaOnly = false);
164 164
165 165 //! get the meta type id of this class (only valid for isCPPWrapper() == true)
166 166 int metaTypeId() { return _metaTypeId; }
167 167
168 168 //! set an additional decorator provider that offers additional decorator slots for this class
169 void setDecoratorProvider(PythonQtQObjectCreatorFunctionCB* cb) { _decoratorProviderCB = cb; _decoratorProvider = NULL; }
169 void setDecoratorProvider(PythonQtQObjectCreatorFunctionCB* cb);
170 170
171 171 //! get the decorator qobject instance
172 172 QObject* decorator();
173 173
174 174 //! add the parent class info of a CPP object
175 175 void addParentClass(const ParentClassInfo& info) { _parentClasses.append(info); }
176 176
177 177 //! check if the special method "py_hasOwner" is implemented and if it returns false, which means that the object may be destroyed
178 178 bool hasOwnerMethodButNoOwner(void* object);
179 179
180 180 //! set the associated PythonQtClassWrapper (which handles instance creation of this type)
181 181 void setPythonQtClassWrapper(PyObject* obj) { _pythonQtClassWrapper = obj; }
182 182
183 183 //! get the associated PythonQtClassWrapper (which handles instance creation of this type)
184 184 PyObject* pythonQtClassWrapper() { return _pythonQtClassWrapper; }
185 185
186 186 //! set the shell set instance wrapper cb
187 187 void setShellSetInstanceWrapperCB(PythonQtShellSetInstanceWrapperCB* cb) {
188 188 _shellSetInstanceWrapperCB = cb;
189 189 }
190 190
191 191 //! get the shell set instance wrapper cb
192 192 PythonQtShellSetInstanceWrapperCB* shellSetInstanceWrapperCB() {
193 193 return _shellSetInstanceWrapperCB;
194 194 }
195 195
196 196 //! add a handler for polymorphic downcasting
197 197 void addPolymorphicHandler(PythonQtPolymorphicHandlerCB* cb) { _polymorphicHandlers.append(cb); }
198 198
199 199 //! cast the pointer down in the class hierarchy if a polymorphic handler allows to do that
200 200 void* castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo);
201 201
202 202 //! returns if the localScope has an enum of that type name or if the enum contains a :: scope, if that class contails the enum
203 203 static PyObject* findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum = NULL);
204
204
205 //! clear all members that where cached as "NotFound"
206 void clearNotFoundCachedMembers();
207
205 208 private:
206 209 void createEnumWrappers();
207 210 void createEnumWrappers(const QMetaObject* meta);
208 211 PyObject* findEnumWrapper(const char* name);
209 212
210 213 //! clear all cached members
211 214 void clearCachedMembers();
212 215
213 216 void* recursiveCastDownIfPossible(void* ptr, char** resultClassName);
214 217
215 218 PythonQtSlotInfo* findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
216 219 void listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly);
217 220 PythonQtSlotInfo* recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
218 221
219 222 void recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects);
220 223 void recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects);
221 224
222 225 bool lookForPropertyAndCache(const char* memberName);
223 226 bool lookForMethodAndCache(const char* memberName);
224 227 bool lookForEnumAndCache(const QMetaObject* m, const char* memberName);
225 228
226 229 PythonQtSlotInfo* findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
227 230 int findCharOffset(const char* sigStart, char someChar);
228
231
229 232 QHash<QByteArray, PythonQtMemberInfo> _cachedMembers;
230 233
231 234 PythonQtSlotInfo* _constructors;
232 235 PythonQtSlotInfo* _destructor;
233 236 QList<PythonQtSlotInfo*> _decoratorSlots;
234 237
235 238 QList<PythonQtObjectPtr> _enumWrappers;
236 239
237 240 const QMetaObject* _meta;
238 241
239 242 QByteArray _wrappedClassName;
240 243 QList<ParentClassInfo> _parentClasses;
241 244
242 245 QList<PythonQtPolymorphicHandlerCB*> _polymorphicHandlers;
243 246
244 247 QObject* _decoratorProvider;
245 248 PythonQtQObjectCreatorFunctionCB* _decoratorProviderCB;
246 249
247 250 PyObject* _pythonQtClassWrapper;
248 251
249 252 PythonQtShellSetInstanceWrapperCB* _shellSetInstanceWrapperCB;
250 253
251 254 int _metaTypeId;
252 255 int _typeSlots;
253 256
254 257 bool _isQObject;
255 258 bool _enumsCreated;
256 259
257 260 };
258 261
259 262 //---------------------------------------------------------------
260 263
261 264
262 265 #endif
@@ -1,462 +1,494
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtClassWrapper.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 "PythonQtClassWrapper.h"
43 43 #include <QObject>
44 44
45 45 #include "PythonQt.h"
46 46 #include "PythonQtSlot.h"
47 47 #include "PythonQtClassInfo.h"
48 48 #include "PythonQtConversion.h"
49 49 #include "PythonQtInstanceWrapper.h"
50 50
51 51 static PyObject* PythonQtInstanceWrapper_invert(PythonQtInstanceWrapper* wrapper)
52 52 {
53 53 PyObject* result = NULL;
54 54 static QByteArray memberName = "__invert__";
55 55 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
56 56 if (opSlot._type == PythonQtMemberInfo::Slot) {
57 57 result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr);
58 58 }
59 59 return result;
60 60 }
61 61
62 62 static int PythonQtInstanceWrapper_nonzero(PythonQtInstanceWrapper* wrapper)
63 63 {
64 64 int result = (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
65 65 if (result) {
66 66 static QByteArray memberName = "__nonzero__";
67 67 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
68 68 if (opSlot._type == PythonQtMemberInfo::Slot) {
69 69 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr);
70 70 if (resultObj == Py_False) {
71 71 result = 0;
72 72 }
73 73 Py_XDECREF(resultObj);
74 74 }
75 75 }
76 76 return result;
77 77 }
78 78
79 79
80 80 static PyObject* PythonQtInstanceWrapper_binaryfunc(PyObject* self, PyObject* other, const QByteArray& opName, const QByteArray& fallbackOpName = QByteArray())
81 81 {
82 82 // since we disabled type checking, we can receive any object as self, but we currently only support
83 83 // different objects on the right. Otherwise we would need to generate __radd__ etc. methods.
84 84 if (!PyObject_TypeCheck(self, &PythonQtInstanceWrapper_Type)) {
85 85 QString error = "Unsupported operation " + opName + "(" + self->ob_type->tp_name + ", " + other->ob_type->tp_name + ")";
86 86 PyErr_SetString(PyExc_ArithmeticError, error.toLatin1().data());
87 87 return NULL;
88 88 }
89 89 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)self;
90 90 PyObject* result = NULL;
91 91 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(opName);
92 92 if (opSlot._type == PythonQtMemberInfo::Slot) {
93 93 // TODO get rid of tuple
94 94 PyObject* args = PyTuple_New(1);
95 95 Py_INCREF(other);
96 96 PyTuple_SET_ITEM(args, 0, other);
97 97 result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr);
98 98 Py_DECREF(args);
99 99 if (!result && !fallbackOpName.isEmpty()) {
100 100 // try fallback if we did not get a result
101 101 result = PythonQtInstanceWrapper_binaryfunc(self, other, fallbackOpName);
102 102 }
103 103 }
104 104 return result;
105 105 }
106 106
107 107 #define BINARY_OP(NAME) \
108 108 static PyObject* PythonQtInstanceWrapper_ ## NAME(PyObject* self, PyObject* other) \
109 109 { \
110 110 static const QByteArray opName("__" #NAME "__"); \
111 111 return PythonQtInstanceWrapper_binaryfunc(self, other, opName); \
112 112 }
113 113
114 114 #define BINARY_OP_INPLACE(NAME) \
115 115 static PyObject* PythonQtInstanceWrapper_i ## NAME(PyObject* self, PyObject* other) \
116 116 { \
117 117 static const QByteArray opName("__i" #NAME "__"); \
118 118 static const QByteArray fallbackName("__" #NAME "__"); \
119 119 return PythonQtInstanceWrapper_binaryfunc(self, other, opName, fallbackName); \
120 120 }
121 121
122 122 BINARY_OP(add)
123 123 BINARY_OP(sub)
124 124 BINARY_OP(mul)
125 125 BINARY_OP(div)
126 126 BINARY_OP(and)
127 127 BINARY_OP(or)
128 128 BINARY_OP(xor)
129 129 BINARY_OP(mod)
130 130 BINARY_OP(lshift)
131 131 BINARY_OP(rshift)
132 132
133 133 BINARY_OP_INPLACE(add)
134 134 BINARY_OP_INPLACE(sub)
135 135 BINARY_OP_INPLACE(mul)
136 136 BINARY_OP_INPLACE(div)
137 137 BINARY_OP_INPLACE(and)
138 138 BINARY_OP_INPLACE(or)
139 139 BINARY_OP_INPLACE(xor)
140 140 BINARY_OP_INPLACE(mod)
141 141 BINARY_OP_INPLACE(lshift)
142 142 BINARY_OP_INPLACE(rshift)
143 143
144 144 static void initializeSlots(PythonQtClassWrapper* wrap)
145 145 {
146 146 int typeSlots = wrap->classInfo()->typeSlots();
147 147 if (typeSlots) {
148 148 if (typeSlots & PythonQt::Type_Add) {
149 149 wrap->_base.as_number.nb_add = (binaryfunc)PythonQtInstanceWrapper_add;
150 150 }
151 151 if (typeSlots & PythonQt::Type_Subtract) {
152 152 wrap->_base.as_number.nb_subtract = (binaryfunc)PythonQtInstanceWrapper_sub;
153 153 }
154 154 if (typeSlots & PythonQt::Type_Multiply) {
155 155 wrap->_base.as_number.nb_multiply = (binaryfunc)PythonQtInstanceWrapper_mul;
156 156 }
157 157 if (typeSlots & PythonQt::Type_Divide) {
158 158 wrap->_base.as_number.nb_divide = (binaryfunc)PythonQtInstanceWrapper_div;
159 159 wrap->_base.as_number.nb_true_divide = (binaryfunc)PythonQtInstanceWrapper_div;
160 160 }
161 161 if (typeSlots & PythonQt::Type_And) {
162 162 wrap->_base.as_number.nb_and = (binaryfunc)PythonQtInstanceWrapper_and;
163 163 }
164 164 if (typeSlots & PythonQt::Type_Or) {
165 165 wrap->_base.as_number.nb_or = (binaryfunc)PythonQtInstanceWrapper_or;
166 166 }
167 167 if (typeSlots & PythonQt::Type_Xor) {
168 168 wrap->_base.as_number.nb_xor = (binaryfunc)PythonQtInstanceWrapper_xor;
169 169 }
170 170 if (typeSlots & PythonQt::Type_Mod) {
171 171 wrap->_base.as_number.nb_remainder = (binaryfunc)PythonQtInstanceWrapper_mod;
172 172 }
173 173 if (typeSlots & PythonQt::Type_LShift) {
174 174 wrap->_base.as_number.nb_lshift = (binaryfunc)PythonQtInstanceWrapper_lshift;
175 175 }
176 176 if (typeSlots & PythonQt::Type_RShift) {
177 177 wrap->_base.as_number.nb_rshift = (binaryfunc)PythonQtInstanceWrapper_rshift;
178 178 }
179 179
180 180 if (typeSlots & PythonQt::Type_InplaceAdd) {
181 181 wrap->_base.as_number.nb_add = (binaryfunc)PythonQtInstanceWrapper_iadd;
182 182 }
183 183 if (typeSlots & PythonQt::Type_InplaceSubtract) {
184 184 wrap->_base.as_number.nb_subtract = (binaryfunc)PythonQtInstanceWrapper_isub;
185 185 }
186 186 if (typeSlots & PythonQt::Type_InplaceMultiply) {
187 187 wrap->_base.as_number.nb_multiply = (binaryfunc)PythonQtInstanceWrapper_imul;
188 188 }
189 189 if (typeSlots & PythonQt::Type_InplaceDivide) {
190 190 wrap->_base.as_number.nb_inplace_divide = (binaryfunc)PythonQtInstanceWrapper_idiv;
191 191 wrap->_base.as_number.nb_inplace_true_divide = (binaryfunc)PythonQtInstanceWrapper_idiv;
192 192 }
193 193 if (typeSlots & PythonQt::Type_InplaceAnd) {
194 194 wrap->_base.as_number.nb_inplace_and = (binaryfunc)PythonQtInstanceWrapper_iand;
195 195 }
196 196 if (typeSlots & PythonQt::Type_InplaceOr) {
197 197 wrap->_base.as_number.nb_inplace_or = (binaryfunc)PythonQtInstanceWrapper_ior;
198 198 }
199 199 if (typeSlots & PythonQt::Type_InplaceXor) {
200 200 wrap->_base.as_number.nb_inplace_xor = (binaryfunc)PythonQtInstanceWrapper_ixor;
201 201 }
202 202 if (typeSlots & PythonQt::Type_InplaceMod) {
203 203 wrap->_base.as_number.nb_inplace_remainder = (binaryfunc)PythonQtInstanceWrapper_imod;
204 204 }
205 205 if (typeSlots & PythonQt::Type_InplaceLShift) {
206 206 wrap->_base.as_number.nb_inplace_lshift = (binaryfunc)PythonQtInstanceWrapper_ilshift;
207 207 }
208 208 if (typeSlots & PythonQt::Type_InplaceRShift) {
209 209 wrap->_base.as_number.nb_inplace_rshift = (binaryfunc)PythonQtInstanceWrapper_irshift;
210 210 }
211 211 if (typeSlots & PythonQt::Type_Invert) {
212 212 wrap->_base.as_number.nb_invert = (unaryfunc)PythonQtInstanceWrapper_invert;
213 213 }
214 214 if (typeSlots & PythonQt::Type_NonZero) {
215 215 wrap->_base.as_number.nb_nonzero = (inquiry)PythonQtInstanceWrapper_nonzero;
216 216 }
217 217 }
218 218 }
219 219
220 220 static PyObject* PythonQtClassWrapper_alloc(PyTypeObject *self, Py_ssize_t nitems)
221 221 {
222 222 // call the default type alloc
223 223 PyObject* obj = PyType_Type.tp_alloc(self, nitems);
224 224
225 225 // take current class type, if we are called via newPythonQtClassWrapper()
226 226 PythonQtClassWrapper* wrap = (PythonQtClassWrapper*)obj;
227 227 wrap->_classInfo = PythonQt::priv()->currentClassInfoForClassWrapperCreation();
228 228 if (wrap->_classInfo) {
229 229 initializeSlots(wrap);
230 230 }
231 231
232 232 return obj;
233 233 }
234 234
235 235
236 236 static int PythonQtClassWrapper_init(PythonQtClassWrapper* self, PyObject* args, PyObject* kwds)
237 237 {
238 238 // call the default type init
239 239 if (PyType_Type.tp_init((PyObject *)self, args, kwds) < 0) {
240 240 return -1;
241 241 }
242 242
243 243 // if we have no CPP class information, try our base class
244 244 if (!self->classInfo()) {
245 245 PyTypeObject* superType = ((PyTypeObject *)self)->tp_base;
246 246
247 247 if (!superType || (superType->ob_type != &PythonQtClassWrapper_Type)) {
248 248 PyErr_Format(PyExc_TypeError, "type %s is not derived from PythonQtClassWrapper", ((PyTypeObject*)self)->tp_name);
249 249 return -1;
250 250 }
251 251
252 252 // take the class info from the superType
253 253 self->_classInfo = ((PythonQtClassWrapper*)superType)->classInfo();
254 254 }
255 255
256 256 return 0;
257 257 }
258 258
259 259 static PyObject *PythonQtClassWrapper_classname(PythonQtClassWrapper* type)
260 260 {
261 261 return PyString_FromString((QString("Class_") + type->classInfo()->className()).toLatin1().data());
262 262 }
263 263
264 264 static PyObject *PythonQtClassWrapper_help(PythonQtClassWrapper* type)
265 265 {
266 266 return PythonQt::self()->helpCalled(type->classInfo());
267 267 }
268 268
269 PyObject *PythonQtClassWrapper_delete(PythonQtClassWrapper *type, PyObject *args)
270 {
271 Q_UNUSED(type);
272
273 Py_ssize_t argc = PyTuple_Size(args);
274 if (argc>0) {
275 PyObject* self = PyTuple_GET_ITEM(args, 0);
276 if (PyObject_TypeCheck(self, &PythonQtInstanceWrapper_Type)) {
277 return PythonQtInstanceWrapper_delete((PythonQtInstanceWrapper*)self);
278 }
279 }
280 return NULL;
281 }
282
283 PyObject *PythonQtClassWrapper_inherits(PythonQtClassWrapper *type, PyObject *args)
284 {
285 Q_UNUSED(type);
286 PythonQtInstanceWrapper* wrapper = NULL;
287 char *name = NULL;
288 if (!PyArg_ParseTuple(args, "O!s:PythonQtClassWrapper.inherits",&PythonQtInstanceWrapper_Type, &wrapper, &name)) {
289 return NULL;
290 }
291 return PythonQtConv::GetPyBool(wrapper->classInfo()->inherits(name));
292 }
293
269 294 PyObject *PythonQtClassWrapper__init__(PythonQtClassWrapper *type, PyObject *args)
270 295 {
271 296 Py_ssize_t argc = PyTuple_Size(args);
272 297 if (argc>0) {
273 298 // we need to call __init__ of the instance
274 299 PyObject* self = PyTuple_GET_ITEM(args, 0);
275 300 if (PyObject_TypeCheck(self, (PyTypeObject*)type->classInfo()->pythonQtClassWrapper())) {
276 301 PyObject* newargs = PyTuple_New(argc-1);
277 302 for (int i = 0;i<argc-1; i++) {
278 303 PyTuple_SET_ITEM(newargs, i,PyTuple_GET_ITEM(args, i+1));
279 304 }
280 305 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)self;
281 306 int result = PythonQtInstanceWrapper_init(wrapper, newargs, NULL);
282 307 Py_DECREF(newargs);
283 308 if (result==0) {
284 309 Py_INCREF(Py_None);
285 310 return Py_None;
286 311 } else {
287 312 // init failed!
288 313 }
289 314 } else {
290 315 // self not of correct type!
291 316 }
292 317 } else {
293 318 // wrong number of args
294 319 }
295 320 return NULL;
296 321 }
297 322
323
298 324 static PyMethodDef PythonQtClassWrapper_methods[] = {
299 325 {"__init__", (PyCFunction)PythonQtClassWrapper__init__, METH_VARARGS,
300 "Return the classname of the object"
326 "Init function"
301 327 },
302 328 {"className", (PyCFunction)PythonQtClassWrapper_classname, METH_NOARGS,
303 329 "Return the classname of the object"
304 330 },
331 {"inherits", (PyCFunction)PythonQtClassWrapper_inherits, METH_VARARGS,
332 "Returns if the class inherits or is of given type name"
333 },
305 334 {"help", (PyCFunction)PythonQtClassWrapper_help, METH_NOARGS,
306 335 "Shows the help of available methods for this class"
307 336 },
337 {"delete", (PyCFunction)PythonQtClassWrapper_delete, METH_VARARGS,
338 "Deletes the given C++ object"
339 },
308 340 {NULL, NULL, 0 , NULL} /* Sentinel */
309 341 };
310 342
311 343
312 344 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name)
313 345 {
314 346 const char *attributeName;
315 347 PythonQtClassWrapper *wrapper = (PythonQtClassWrapper *)obj;
316
348
317 349 if ((attributeName = PyString_AsString(name)) == NULL) {
318 350 return NULL;
319 351 }
320 352 if (obj == (PyObject*)&PythonQtInstanceWrapper_Type) {
321 353 return NULL;
322 354 }
323 355
324 356 if (qstrcmp(attributeName, "__dict__")==0) {
325 357 PyObject* dict = ((PyTypeObject *)wrapper)->tp_dict;
326 358 if (!wrapper->classInfo()) {
327 359 Py_INCREF(dict);
328 360 return dict;
329 361 }
330 362 dict = PyDict_Copy(dict);
331
363
332 364 QStringList l = wrapper->classInfo()->memberList(false);
333 365 foreach (QString name, l) {
334 366 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
335 367 if (o) {
336 368 PyDict_SetItemString(dict, name.toLatin1().data(), o);
337 369 Py_DECREF(o);
338 370 } else {
339 371 // it must have been a property or child, which we do not know as a class object...
340 372 }
341 373 }
342 374 if (wrapper->classInfo()->constructors()) {
343 375 PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[0], obj);
344 376 PyDict_SetItemString(dict, "__init__", func);
345 377 Py_DECREF(func);
346 378 }
347 for (int i = 1;i<3;i++) {
379 for (int i = 1; PythonQtClassWrapper_methods[i].ml_name != NULL; i++) {
348 380 PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[i], obj);
349 381 PyDict_SetItemString(dict, PythonQtClassWrapper_methods[i].ml_name, func);
350 382 Py_DECREF(func);
351 383 }
352 384 return dict;
353 385 }
354 386
355 387 if (wrapper->classInfo()) {
356 388 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
357 389 if (member._type == PythonQtMemberInfo::EnumValue) {
358 390 PyObject* enumValue = member._enumValue;
359 391 Py_INCREF(enumValue);
360 392 return enumValue;
361 393 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
362 394 PyObject* enumWrapper = member._enumWrapper;
363 395 Py_INCREF(enumWrapper);
364 396 return enumWrapper;
365 397 } else if (member._type == PythonQtMemberInfo::Slot) {
366 398 // we return all slots, even the instance slots, since they are callable as unbound slots with self argument
367 399 return PythonQtSlotFunction_New(member._slot, obj, NULL);
368 400 }
369 401 }
370 402
371 403 // look for the interal methods (className(), help())
372 404 PyObject* internalMethod = Py_FindMethod( PythonQtClassWrapper_methods, obj, (char*)attributeName);
373 405 if (internalMethod) {
374 406 return internalMethod;
375 407 }
376 408 PyErr_Clear();
377 409
378 410 // look in super
379 411 PyObject* superAttr = PyType_Type.tp_getattro(obj, name);
380 412 if (superAttr) {
381 413 return superAttr;
382 414 }
383 415
384 416 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
385 417 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
386 418 return NULL;
387 419 }
388 420
389 421 static int PythonQtClassWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
390 422 {
391 423 return PyType_Type.tp_setattro(obj,name,value);
392 424 }
393 425
394 426 /*
395 427 static PyObject * PythonQtClassWrapper_repr(PyObject * obj)
396 428 {
397 429 PythonQtClassWrapper* wrapper = (PythonQtClassWrapper*)obj;
398 430 if (wrapper->classInfo()->isCPPWrapper()) {
399 const QMetaObject* meta = wrapper->classInfo()->metaObject();
431 const QMetaObject* meta = wrapper->classInfo()->metaObject();
400 432 if (!meta) {
401 433 QObject* decorator = wrapper->classInfo()->decorator();
402 434 if (decorator) {
403 435 meta = decorator->metaObject();
404 436 }
405 437 }
406 438 if (meta) {
407 439 return PyString_FromFormat("%s Class (C++ wrapped by %s)", wrapper->classInfo()->className(), meta->className());
408 440 } else {
409 441 return PyString_FromFormat("%s Class (C++ unwrapped)", wrapper->classInfo()->className());
410 442 }
411 443 } else {
412 444 return PyString_FromFormat("%s Class", wrapper->classInfo()->className());
413 445 }
414 446 }
415 447
416 448 */
417 449
418 450 PyTypeObject PythonQtClassWrapper_Type = {
419 451 PyObject_HEAD_INIT(NULL)
420 452 0, /*ob_size*/
421 453 "PythonQt.PythonQtClassWrapper", /*tp_name*/
422 454 sizeof(PythonQtClassWrapper), /*tp_basicsize*/
423 455 0, /*tp_itemsize*/
424 456 0, /*tp_dealloc*/
425 457 0, /*tp_print*/
426 458 0, /*tp_getattr*/
427 459 0, /*tp_setattr*/
428 460 0, /*tp_compare*/
429 461 0, //PythonQtClassWrapper_repr, /*tp_repr*/
430 462 0, /*tp_as_number*/
431 463 0, /*tp_as_sequence*/
432 464 0, /*tp_as_mapping*/
433 465 0, /*tp_hash */
434 466 0, /*tp_call*/
435 467 0, /*tp_str*/
436 468 PythonQtClassWrapper_getattro, /*tp_getattro*/
437 469 PythonQtClassWrapper_setattro, /*tp_setattro*/
438 470 0, /*tp_as_buffer*/
439 471 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
440 472 0, /* tp_doc */
441 473 0, /* tp_traverse */
442 474 0, /* tp_clear */
443 475 0, /* tp_richcompare */
444 476 0, /* tp_weaklistoffset */
445 477 0, /* tp_iter */
446 478 0, /* tp_iternext */
447 479 0, /* tp_methods */
448 480 0, /* tp_members */
449 481 0, /* tp_getset */
450 482 0, /* tp_base */
451 483 0, /* tp_dict */
452 484 0, /* tp_descr_get */
453 485 0, /* tp_descr_set */
454 486 0, /* tp_dictoffset */
455 487 (initproc)PythonQtClassWrapper_init, /* tp_init */
456 488 PythonQtClassWrapper_alloc, /* tp_alloc */
457 489 0, /* tp_new */
458 490 0, /* tp_free */
459 491 };
460 492
461 493 //-------------------------------------------------------
462 494
@@ -1,1236 +1,1236
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtConversion.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtConversion.h"
43 43 #include "PythonQtVariants.h"
44 44 #include <QDateTime>
45 45 #include <QTime>
46 46 #include <QDate>
47 47
48 48 PythonQtValueStorage<qint64, 128> PythonQtConv::global_valueStorage;
49 49 PythonQtValueStorage<void*, 128> PythonQtConv::global_ptrStorage;
50 PythonQtValueStorage<QVariant, 32> PythonQtConv::global_variantStorage;
50 PythonQtValueStorageWithCleanup<QVariant, 128> PythonQtConv::global_variantStorage;
51 51
52 52 QHash<int, PythonQtConvertMetaTypeToPythonCB*> PythonQtConv::_metaTypeToPythonConverters;
53 53 QHash<int, PythonQtConvertPythonToMetaTypeCB*> PythonQtConv::_pythonToMetaTypeConverters;
54 54
55 55 PyObject* PythonQtConv::GetPyBool(bool val)
56 56 {
57 57 PyObject* r = val?Py_True:Py_False;
58 58 Py_INCREF(r);
59 59 return r;
60 60 }
61 61
62 62 PyObject* PythonQtConv::ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data) {
63 63 // is it an enum value?
64 64 if (info.enumWrapper) {
65 65 if (info.pointerCount==0) {
66 66 return PythonQtPrivate::createEnumValueInstance(info.enumWrapper, *((unsigned int*)data));
67 67 } else {
68 68 // we do not support pointers to enums (who needs them?)
69 69 Py_INCREF(Py_None);
70 70 return Py_None;
71 71 }
72 72 }
73 73
74 74 if (info.typeId == QMetaType::Void) {
75 75 Py_INCREF(Py_None);
76 76 return Py_None;
77 77 } else if ((info.pointerCount == 1) && (info.typeId == QMetaType::Char)) {
78 78 // a char ptr will probably be a null terminated string, so we support that:
79 79 return PyString_FromString(*((char**)data));
80 80 } else if ((info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) &&
81 81 info.name.startsWith("QList<")) {
82 82 // it is a QList template:
83 83 QByteArray innerType = info.name.mid(6,info.name.length()-7);
84 84 if (innerType.endsWith("*")) {
85 85 innerType.truncate(innerType.length()-1);
86 86 QList<void*>* listPtr = NULL;
87 87 if (info.pointerCount == 1) {
88 88 listPtr = *((QList<void*>**)data);
89 89 } else if (info.pointerCount == 0) {
90 90 listPtr = (QList<void*>*)data;
91 91 }
92 92 if (listPtr) {
93 93 return ConvertQListOfPointerTypeToPythonList(listPtr, innerType);
94 94 } else {
95 95 return NULL;
96 96 }
97 97 }
98 98 }
99 99
100 100 if (info.typeId >= QMetaType::User) {
101 101 // if a converter is registered, we use is:
102 102 PythonQtConvertMetaTypeToPythonCB* converter = _metaTypeToPythonConverters.value(info.typeId);
103 103 if (converter) {
104 104 return (*converter)(data, info.typeId);
105 105 }
106 106 }
107 107
108 108 // special handling did not match, so we convert the usual way (either pointer or value version):
109 109 if (info.pointerCount == 1) {
110 110 // convert the pointer to a Python Object (we can handle ANY C++ object, in the worst case we just know the type and the pointer)
111 111 return PythonQt::priv()->wrapPtr(*((void**)data), info.name);
112 112 } else if (info.pointerCount == 0) {
113 113 // handle values that are not yet handled and not pointers
114 114 return ConvertQtValueToPythonInternal(info.typeId, data);
115 115 } else {
116 116 return NULL;
117 117 }
118 118 }
119 119
120 120 PyObject* PythonQtConv::ConvertQtValueToPythonInternal(int type, const void* data) {
121 121 switch (type) {
122 122 case QMetaType::Void:
123 123 Py_INCREF(Py_None);
124 124 return Py_None;
125 125 case QMetaType::Char:
126 126 return PyInt_FromLong(*((char*)data));
127 127 case QMetaType::UChar:
128 128 return PyInt_FromLong(*((unsigned char*)data));
129 129 case QMetaType::Short:
130 130 return PyInt_FromLong(*((short*)data));
131 131 case QMetaType::UShort:
132 132 return PyInt_FromLong(*((unsigned short*)data));
133 133 case QMetaType::Long:
134 134 return PyInt_FromLong(*((long*)data));
135 135 case QMetaType::ULong:
136 136 // does not fit into simple int of python
137 137 return PyLong_FromUnsignedLong(*((unsigned long*)data));
138 138 case QMetaType::Bool:
139 139 return PythonQtConv::GetPyBool(*((bool*)data));
140 140 case QMetaType::Int:
141 141 return PyInt_FromLong(*((int*)data));
142 142 case QMetaType::UInt:
143 143 // does not fit into simple int of python
144 144 return PyLong_FromUnsignedLong(*((unsigned int*)data));
145 145 case QMetaType::QChar:
146 146 return PyInt_FromLong(*((short*)data));
147 147 case QMetaType::Float:
148 148 return PyFloat_FromDouble(*((float*)data));
149 149 case QMetaType::Double:
150 150 return PyFloat_FromDouble(*((double*)data));
151 151 case QMetaType::LongLong:
152 152 return PyLong_FromLongLong(*((qint64*)data));
153 153 case QMetaType::ULongLong:
154 154 return PyLong_FromUnsignedLongLong(*((quint64*)data));
155 155 // implicit conversion from QByteArray to str has been removed:
156 156 //case QMetaType::QByteArray: {
157 157 // QByteArray* v = (QByteArray*) data;
158 158 // return PyString_FromStringAndSize(*v, v->size());
159 159 // }
160 160 case QMetaType::QVariantMap:
161 161 return PythonQtConv::QVariantMapToPyObject(*((QVariantMap*)data));
162 162 case QMetaType::QVariantList:
163 163 return PythonQtConv::QVariantListToPyObject(*((QVariantList*)data));
164 164 case QMetaType::QString:
165 165 return PythonQtConv::QStringToPyObject(*((QString*)data));
166 166 case QMetaType::QStringList:
167 167 return PythonQtConv::QStringListToPyObject(*((QStringList*)data));
168 168
169 169 case PythonQtMethodInfo::Variant:
170 170 return PythonQtConv::QVariantToPyObject(*((QVariant*)data));
171 171 case QMetaType::QObjectStar:
172 172 case QMetaType::QWidgetStar:
173 173 return PythonQt::priv()->wrapQObject(*((QObject**)data));
174 174
175 175 default:
176 176 if (PythonQt::priv()->isPythonQtObjectPtrMetaId(type)) {
177 177 // special case, it is a PythonQtObjectPtr which contains a PyObject, take it directly:
178 178 PyObject* o = ((PythonQtObjectPtr*)data)->object();
179 179 Py_INCREF(o);
180 180 return o;
181 181 } else {
182 182 if (type > 0) {
183 183 // if the type is known, we can construct it via QMetaType::construct
184 184 void* newCPPObject = QMetaType::construct(type, data);
185 185 // XXX this could be optimized by using metatypeid directly
186 186 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)PythonQt::priv()->wrapPtr(newCPPObject, QMetaType::typeName(type));
187 187 wrap->_ownedByPythonQt = true;
188 188 wrap->_useQMetaTypeDestroy = true;
189 189 return (PyObject*)wrap;
190 190 }
191 191 std::cerr << "Unknown type that can not be converted to Python: " << type << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
192 192 }
193 193 }
194 194 Py_INCREF(Py_None);
195 195 return Py_None;
196 196 }
197 197
198 198 void* PythonQtConv::CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info) {
199 199 void* ptr = NULL;
200 200 if (info.pointerCount>1) {
201 201 return NULL;
202 202 } else if (info.pointerCount==1) {
203 203 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
204 204 } else if (info.enumWrapper) {
205 205 // create enum return value
206 206 PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, ptr);
207 207 } else {
208 208 switch (info.typeId) {
209 209 case QMetaType::Char:
210 210 case QMetaType::UChar:
211 211 case QMetaType::Short:
212 212 case QMetaType::UShort:
213 213 case QMetaType::Long:
214 214 case QMetaType::ULong:
215 215 case QMetaType::Bool:
216 216 case QMetaType::Int:
217 217 case QMetaType::UInt:
218 218 case QMetaType::QChar:
219 219 case QMetaType::Float:
220 220 case QMetaType::Double:
221 221 PythonQtValueStorage_ADD_VALUE(global_valueStorage, qint64, 0, ptr);
222 222 break;
223 223 case PythonQtMethodInfo::Variant:
224 224 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, 0, ptr);
225 225 // return the ptr to the variant
226 226 break;
227 227 default:
228 228 if (info.typeId == PythonQtMethodInfo::Unknown) {
229 229 // check if we have a QList of pointers, which we can circumvent with a QList<void*>
230 230 if (info.name.startsWith("QList<")) {
231 231 QByteArray innerType = info.name.mid(6,info.name.length()-7);
232 232 if (innerType.endsWith("*")) {
233 233 static int id = QMetaType::type("QList<void*>");
234 234 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr);
235 235 // return the constData pointer that will be filled with the result value later on
236 236 ptr = (void*)((QVariant*)ptr)->constData();
237 237 }
238 238 }
239 239 }
240 240
241 241 if (!ptr && info.typeId!=PythonQtMethodInfo::Unknown) {
242 242 // everything else is stored in a QVariant, if we know the meta type...
243 243 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
244 244 // return the constData pointer that will be filled with the result value later on
245 245 ptr = (void*)((QVariant*)ptr)->constData();
246 246 }
247 247 }
248 248 }
249 249 return ptr;
250 250 }
251 251
252 252 void* PythonQtConv::castWrapperTo(PythonQtInstanceWrapper* wrapper, const QByteArray& className, bool& ok)
253 253 {
254 254 void* object;
255 255 if (wrapper->classInfo()->isCPPWrapper()) {
256 256 object = wrapper->_wrappedPtr;
257 257 } else {
258 258 QObject* tmp = wrapper->_obj;
259 259 object = tmp;
260 260 }
261 261 if (object) {
262 262 // if we can be upcasted to the given name, we pass the casted pointer in:
263 263 object = wrapper->classInfo()->castTo(object, className);
264 264 ok = object!=NULL;
265 265 } else {
266 266 // if it is a NULL ptr, we need to check if it inherits, so that we might pass the NULL ptr
267 267 ok = wrapper->classInfo()->inherits(className);
268 268 }
269 269 return object;
270 270 }
271 271
272 272 void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject)
273 273 {
274 274 void* ptr = alreadyAllocatedCPPObject;
275 275
276 276 static int penId = QMetaType::type("QPen");
277 277 static int brushId = QMetaType::type("QBrush");
278 278 static int cursorId = QMetaType::type("QCursor");
279 279 static int colorId = QMetaType::type("QColor");
280 280 static PyObject* qtGlobalColorEnum = PythonQtClassInfo::findEnumWrapper("Qt::GlobalColor", NULL);
281 281 if (typeId == cursorId) {
282 282 static PyObject* qtCursorShapeEnum = PythonQtClassInfo::findEnumWrapper("Qt::CursorShape", NULL);
283 283 if ((PyObject*)obj->ob_type == qtCursorShapeEnum) {
284 284 Qt::CursorShape val = (Qt::CursorShape)PyInt_AS_LONG(obj);
285 285 if (!ptr) {
286 286 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QCursor(), ptr);
287 287 ptr = (void*)((QVariant*)ptr)->constData();
288 288 }
289 289 *((QCursor*)ptr) = QCursor(val);
290 290 return ptr;
291 291 }
292 292 } else if (typeId == penId) {
293 293 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
294 294 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
295 295 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
296 296 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
297 297 if (!ptr) {
298 298 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
299 299 ptr = (void*)((QVariant*)ptr)->constData();
300 300 }
301 301 *((QPen*)ptr) = QPen(QColor(val));
302 302 return ptr;
303 303 } else if ((PyObject*)obj->ob_type == qtColorClass) {
304 304 if (!ptr) {
305 305 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
306 306 ptr = (void*)((QVariant*)ptr)->constData();
307 307 }
308 308 *((QPen*)ptr) = QPen(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
309 309 return ptr;
310 310 }
311 311 } else if (typeId == brushId) {
312 312 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
313 313 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
314 314 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
315 315 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
316 316 if (!ptr) {
317 317 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
318 318 ptr = (void*)((QVariant*)ptr)->constData();
319 319 }
320 320 *((QBrush*)ptr) = QBrush(QColor(val));
321 321 return ptr;
322 322 } else if ((PyObject*)obj->ob_type == qtColorClass) {
323 323 if (!ptr) {
324 324 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
325 325 ptr = (void*)((QVariant*)ptr)->constData();
326 326 }
327 327 *((QBrush*)ptr) = QBrush(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
328 328 return ptr;
329 329 }
330 330 } else if (typeId == colorId) {
331 331 // colors can be created from Qt::GlobalColor (and from colors, but that's the default)
332 332 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
333 333 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
334 334 if (!ptr) {
335 335 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QColor(), ptr);
336 336 ptr = (void*)((QVariant*)ptr)->constData();
337 337 }
338 338 *((QColor*)ptr) = QColor(val);
339 339 return ptr;
340 340 }
341 341 }
342 342 return NULL;
343 343 }
344 344
345 345 void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* /*classInfo*/, void* alreadyAllocatedCPPObject)
346 346 {
347 347 bool ok = false;
348 348 void* ptr = NULL;
349 349
350 350 // autoconversion of QPen/QBrush/QCursor/QColor from different type
351 351 if (info.pointerCount==0 && !strict) {
352 352 ptr = handlePythonToQtAutoConversion(info.typeId, obj, alreadyAllocatedCPPObject);
353 353 if (ptr) {
354 354 return ptr;
355 355 }
356 356 }
357 357
358 358 if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) && info.typeId != PythonQtMethodInfo::Variant) {
359 359 // if we have a Qt wrapper object and if we do not need a QVariant, we do the following:
360 360 // (the Variant case is handled below in a switch)
361 361
362 362 // a C++ wrapper (can be passed as pointer or reference)
363 363 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)obj;
364 364 void* object = castWrapperTo(wrap, info.name, ok);
365 365 if (ok) {
366 366 if (info.pointerCount==1) {
367 367 // store the wrapped pointer in an extra pointer and let ptr point to the extra pointer
368 368 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, object, ptr);
369 369 } else if (info.pointerCount==0) {
370 370 // store the wrapped pointer directly, since we are a reference
371 371 ptr = object;
372 372 }
373 373 } else {
374 374 // not matching
375 375 }
376 376 } else if (info.pointerCount == 1) {
377 377 // a pointer
378 378 if (info.typeId == QMetaType::Char || info.typeId == QMetaType::UChar)
379 379 {
380 380 QString str = PyObjGetString(obj, strict, ok);
381 381 if (ok) {
382 382 void* ptr2 = NULL;
383 383 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str.toUtf8()), ptr2);
384 384 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr);
385 385 }
386 386 } else if (info.name == "PyObject") {
387 387 // handle low level PyObject directly
388 388 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, obj, ptr);
389 389 } else if (obj == Py_None) {
390 390 // None is treated as a NULL ptr
391 391 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
392 392 } else {
393 393 // if we are not strict, we try if we are passed a 0 integer
394 394 if (!strict) {
395 395 bool ok;
396 396 int value = PyObjGetInt(obj, true, ok);
397 397 if (ok && value==0) {
398 398 // TODOXXX is this wise? or should it be expected from the programmer to use None?
399 399 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
400 400 }
401 401 }
402 402 }
403 403 } else if (info.pointerCount == 0) {
404 404 // not a pointer
405 405 switch (info.typeId) {
406 406 case QMetaType::Char:
407 407 {
408 408 int val = PyObjGetInt(obj, strict, ok);
409 409 if (ok) {
410 410 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, char, val, ptr);
411 411 }
412 412 }
413 413 break;
414 414 case QMetaType::UChar:
415 415 {
416 416 int val = PyObjGetInt(obj, strict, ok);
417 417 if (ok) {
418 418 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned char, val, ptr);
419 419 }
420 420 }
421 421 break;
422 422 case QMetaType::Short:
423 423 {
424 424 int val = PyObjGetInt(obj, strict, ok);
425 425 if (ok) {
426 426 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
427 427 }
428 428 }
429 429 break;
430 430 case QMetaType::UShort:
431 431 {
432 432 int val = PyObjGetInt(obj, strict, ok);
433 433 if (ok) {
434 434 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned short, val, ptr);
435 435 }
436 436 }
437 437 break;
438 438 case QMetaType::Long:
439 439 {
440 440 long val = (long)PyObjGetLongLong(obj, strict, ok);
441 441 if (ok) {
442 442 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, long, val, ptr);
443 443 }
444 444 }
445 445 break;
446 446 case QMetaType::ULong:
447 447 {
448 448 unsigned long val = (unsigned long)PyObjGetLongLong(obj, strict, ok);
449 449 if (ok) {
450 450 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned long, val, ptr);
451 451 }
452 452 }
453 453 break;
454 454 case QMetaType::Bool:
455 455 {
456 456 bool val = PyObjGetBool(obj, strict, ok);
457 457 if (ok) {
458 458 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, bool, val, ptr);
459 459 }
460 460 }
461 461 break;
462 462 case QMetaType::Int:
463 463 {
464 464 int val = PyObjGetInt(obj, strict, ok);
465 465 if (ok) {
466 466 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, int, val, ptr);
467 467 }
468 468 }
469 469 break;
470 470 case QMetaType::UInt:
471 471 {
472 472 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
473 473 if (ok) {
474 474 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
475 475 }
476 476 }
477 477 break;
478 478 case QMetaType::QChar:
479 479 {
480 480 int val = PyObjGetInt(obj, strict, ok);
481 481 if (ok) {
482 482 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
483 483 }
484 484 }
485 485 break;
486 486 case QMetaType::Float:
487 487 {
488 488 float val = (float)PyObjGetDouble(obj, strict, ok);
489 489 if (ok) {
490 490 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, float, val, ptr);
491 491 }
492 492 }
493 493 break;
494 494 case QMetaType::Double:
495 495 {
496 496 double val = (double)PyObjGetDouble(obj, strict, ok);
497 497 if (ok) {
498 498 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, double, val, ptr);
499 499 }
500 500 }
501 501 break;
502 502 case QMetaType::LongLong:
503 503 {
504 504 qint64 val = PyObjGetLongLong(obj, strict, ok);
505 505 if (ok) {
506 506 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, qint64, val, ptr);
507 507 }
508 508 }
509 509 break;
510 510 case QMetaType::ULongLong:
511 511 {
512 512 quint64 val = PyObjGetULongLong(obj, strict, ok);
513 513 if (ok) {
514 514 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, quint64, val, ptr);
515 515 }
516 516 }
517 517 break;
518 518 case QMetaType::QByteArray:
519 519 {
520 520 QByteArray bytes = PyObjGetBytes(obj, strict, ok);
521 521 if (ok) {
522 522 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(bytes), ptr);
523 523 ptr = (void*)((QVariant*)ptr)->constData();
524 524 }
525 525 }
526 526 break;
527 527 case QMetaType::QString:
528 528 {
529 529 QString str = PyObjGetString(obj, strict, ok);
530 530 if (ok) {
531 531 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str), ptr);
532 532 ptr = (void*)((QVariant*)ptr)->constData();
533 533 }
534 534 }
535 535 break;
536 536 case QMetaType::QStringList:
537 537 {
538 538 QStringList l = PyObjToStringList(obj, strict, ok);
539 539 if (ok) {
540 540 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(l), ptr);
541 541 ptr = (void*)((QVariant*)ptr)->constData();
542 542 }
543 543 }
544 544 break;
545 545
546 546 case PythonQtMethodInfo::Variant:
547 547 {
548 548 QVariant v = PyObjToQVariant(obj);
549 549 // the only case where conversion can fail it None and we want to pass that to, e.g. setProperty(),
550 550 // so we do not check v.isValid() here
551 551 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
552 552 }
553 553 break;
554 554 default:
555 555 {
556 556 // check for enum case
557 557 if (info.enumWrapper) {
558 558 unsigned int val;
559 559 ok = false;
560 560 if ((PyObject*)obj->ob_type == info.enumWrapper) {
561 561 // we have a exact enum type match:
562 562 val = PyInt_AS_LONG(obj);
563 563 ok = true;
564 564 } else if (!strict) {
565 565 // we try to get any integer, when not being strict. If we are strict, integers are not wanted because
566 566 // we want an integer overload to be taken first!
567 567 val = (unsigned int)PyObjGetLongLong(obj, false, ok);
568 568 }
569 569 if (ok) {
570 570 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
571 571 return ptr;
572 572 } else {
573 573 return NULL;
574 574 }
575 575 }
576 576
577 577 if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
578 578 // check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant
579 579 if (info.name.startsWith("QList<")) {
580 580 QByteArray innerType = info.name.mid(6,info.name.length()-7);
581 581 if (innerType.endsWith("*")) {
582 582 innerType.truncate(innerType.length()-1);
583 583 static int id = QMetaType::type("QList<void*>");
584 584 if (!alreadyAllocatedCPPObject) {
585 585 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(id), ptr);
586 586 ptr = (void*)((QVariant*)ptr)->constData();
587 587 } else {
588 588 ptr = alreadyAllocatedCPPObject;
589 589 }
590 590 ok = ConvertPythonListToQListOfPointerType(obj, (QList<void*>*)ptr, innerType, strict);
591 591 if (ok) {
592 592 return ptr;
593 593 } else {
594 594 return NULL;
595 595 }
596 596 }
597 597 }
598 598 }
599 599
600 600 // We only do this for registered type > QMetaType::User for performance reasons.
601 601 if (info.typeId >= QMetaType::User) {
602 602 // Maybe we have a special converter that is registered for that type:
603 603 PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(info.typeId);
604 604 if (converter) {
605 605 if (!alreadyAllocatedCPPObject) {
606 606 // create a new empty variant of concrete type:
607 607 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
608 608 ptr = (void*)((QVariant*)ptr)->constData();
609 609 } else {
610 610 ptr = alreadyAllocatedCPPObject;
611 611 }
612 612 // now call the converter, passing the internal object of the variant
613 613 ok = (*converter)(obj, ptr, info.typeId, strict);
614 614 if (ok) {
615 615 return ptr;
616 616 } else {
617 617 return NULL;
618 618 }
619 619 }
620 620 }
621 621 // if no type id is available, conversion to a QVariant makes no sense/is not possible
622 622 if (info.typeId != PythonQtMethodInfo::Unknown) {
623 623 // for all other types, we use the same qvariant conversion and pass out the constData of the variant:
624 624 QVariant v = PyObjToQVariant(obj, info.typeId);
625 625 if (v.isValid()) {
626 626 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
627 627 ptr = (void*)((QVariant*)ptr)->constData();
628 628 }
629 629 }
630 630 }
631 631 }
632 632 }
633 633 return ptr;
634 634 }
635 635
636 636
637 637 QStringList PythonQtConv::PyObjToStringList(PyObject* val, bool strict, bool& ok) {
638 638 QStringList v;
639 639 ok = false;
640 640 // if we are strict, we do not want to convert a string to a stringlist
641 641 // (strings in python are detected to be sequences)
642 642 if (strict &&
643 643 (val->ob_type == &PyString_Type ||
644 644 PyUnicode_Check(val))) {
645 645 ok = false;
646 646 return v;
647 647 }
648 648 if (PySequence_Check(val)) {
649 649 int count = PySequence_Size(val);
650 650 for (int i = 0;i<count;i++) {
651 651 PyObject* value = PySequence_GetItem(val,i);
652 652 v.append(PyObjGetString(value,false,ok));
653 653 }
654 654 ok = true;
655 655 }
656 656 return v;
657 657 }
658 658
659 659 QString PythonQtConv::PyObjGetRepresentation(PyObject* val)
660 660 {
661 661 QString r;
662 662 PyObject* str = PyObject_Repr(val);
663 663 if (str) {
664 664 r = QString(PyString_AS_STRING(str));
665 665 Py_DECREF(str);
666 666 }
667 667 return r;
668 668 }
669 669
670 670 QString PythonQtConv::PyObjGetString(PyObject* val, bool strict, bool& ok) {
671 671 QString r;
672 672 ok = true;
673 673 if (val->ob_type == &PyString_Type) {
674 674 r = QString(PyString_AS_STRING(val));
675 675 } else if (PyUnicode_Check(val)) {
676 676 #ifdef WIN32
677 677 r = QString::fromUtf16(PyUnicode_AS_UNICODE(val));
678 678 #else
679 679 PyObject *ptmp = PyUnicode_AsUTF8String(val);
680 680 if(ptmp) {
681 681 r = QString::fromUtf8(PyString_AS_STRING(ptmp));
682 682 Py_DECREF(ptmp);
683 683 }
684 684 #endif
685 685 } else if (!strict) {
686 686 // EXTRA: could also use _Unicode, but why should we?
687 687 PyObject* str = PyObject_Str(val);
688 688 if (str) {
689 689 r = QString(PyString_AS_STRING(str));
690 690 Py_DECREF(str);
691 691 } else {
692 692 ok = false;
693 693 }
694 694 } else {
695 695 ok = false;
696 696 }
697 697 return r;
698 698 }
699 699
700 700 QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) {
701 701 // TODO: support buffer objects in general
702 702 QByteArray r;
703 703 ok = true;
704 704 if (val->ob_type == &PyString_Type) {
705 705 long size = PyString_GET_SIZE(val);
706 706 r = QByteArray(PyString_AS_STRING(val), size);
707 707 } else {
708 708 ok = false;
709 709 }
710 710 return r;
711 711 }
712 712
713 713 bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) {
714 714 bool d = false;
715 715 ok = false;
716 716 if (val == Py_False) {
717 717 d = false;
718 718 ok = true;
719 719 } else if (val == Py_True) {
720 720 d = true;
721 721 ok = true;
722 722 } else if (!strict) {
723 723 d = PyObjGetInt(val, false, ok)!=0;
724 724 ok = true;
725 725 }
726 726 return d;
727 727 }
728 728
729 729 int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) {
730 730 int d = 0;
731 731 ok = true;
732 732 if (val->ob_type == &PyInt_Type) {
733 733 d = PyInt_AS_LONG(val);
734 734 } else if (!strict) {
735 735 if (PyObject_TypeCheck(val, &PyInt_Type)) {
736 736 // support for derived int classes, e.g. for our enums
737 737 d = PyInt_AS_LONG(val);
738 738 } else if (val->ob_type == &PyFloat_Type) {
739 739 d = floor(PyFloat_AS_DOUBLE(val));
740 740 } else if (val->ob_type == &PyLong_Type) {
741 741 // handle error on overflow!
742 742 d = PyLong_AsLong(val);
743 743 } else if (val == Py_False) {
744 744 d = 0;
745 745 } else if (val == Py_True) {
746 746 d = 1;
747 747 } else {
748 748 ok = false;
749 749 }
750 750 } else {
751 751 ok = false;
752 752 }
753 753 return d;
754 754 }
755 755
756 756 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
757 757 qint64 d = 0;
758 758 ok = true;
759 759 if (val->ob_type == &PyInt_Type) {
760 760 d = PyInt_AS_LONG(val);
761 761 } else if (val->ob_type == &PyLong_Type) {
762 762 d = PyLong_AsLongLong(val);
763 763 } else if (!strict) {
764 764 if (PyObject_TypeCheck(val, &PyInt_Type)) {
765 765 // support for derived int classes, e.g. for our enums
766 766 d = PyInt_AS_LONG(val);
767 767 } else if (val->ob_type == &PyFloat_Type) {
768 768 d = floor(PyFloat_AS_DOUBLE(val));
769 769 } else if (val == Py_False) {
770 770 d = 0;
771 771 } else if (val == Py_True) {
772 772 d = 1;
773 773 } else {
774 774 ok = false;
775 775 }
776 776 } else {
777 777 ok = false;
778 778 }
779 779 return d;
780 780 }
781 781
782 782 quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) {
783 783 quint64 d = 0;
784 784 ok = true;
785 785 if (PyObject_TypeCheck(val, &PyInt_Type)) {
786 786 d = PyInt_AS_LONG(val);
787 787 } else if (val->ob_type == &PyLong_Type) {
788 788 d = PyLong_AsLongLong(val);
789 789 } else if (!strict) {
790 790 if (PyObject_TypeCheck(val, &PyInt_Type)) {
791 791 // support for derived int classes, e.g. for our enums
792 792 d = PyInt_AS_LONG(val);
793 793 } else if (val->ob_type == &PyFloat_Type) {
794 794 d = floor(PyFloat_AS_DOUBLE(val));
795 795 } else if (val == Py_False) {
796 796 d = 0;
797 797 } else if (val == Py_True) {
798 798 d = 1;
799 799 } else {
800 800 ok = false;
801 801 }
802 802 } else {
803 803 ok = false;
804 804 }
805 805 return d;
806 806 }
807 807
808 808 double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) {
809 809 double d = 0;
810 810 ok = true;
811 811 if (val->ob_type == &PyFloat_Type) {
812 812 d = PyFloat_AS_DOUBLE(val);
813 813 } else if (!strict) {
814 814 if (PyObject_TypeCheck(val, &PyInt_Type)) {
815 815 d = PyInt_AS_LONG(val);
816 816 } else if (val->ob_type == &PyLong_Type) {
817 817 d = PyLong_AsLong(val);
818 818 } else if (val == Py_False) {
819 819 d = 0;
820 820 } else if (val == Py_True) {
821 821 d = 1;
822 822 } else {
823 823 ok = false;
824 824 }
825 825 } else {
826 826 ok = false;
827 827 }
828 828 return d;
829 829 }
830 830
831 831 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
832 832 {
833 833 QVariant v;
834 834 bool ok = true;
835 835
836 836 if (type==-1) {
837 837 // no special type requested
838 838 if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) {
839 839 type = QVariant::String;
840 840 } else if (PyObject_TypeCheck(val, &PyInt_Type)) {
841 841 type = QVariant::Int;
842 842 } else if (val->ob_type==&PyLong_Type) {
843 843 type = QVariant::LongLong;
844 844 } else if (val->ob_type==&PyFloat_Type) {
845 845 type = QVariant::Double;
846 846 } else if (val == Py_False || val == Py_True) {
847 847 type = QVariant::Bool;
848 848 } else if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
849 849 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
850 850 // c++ wrapper, check if the class names of the c++ objects match
851 851 if (wrap->classInfo()->isCPPWrapper()) {
852 852 if (wrap->classInfo()->metaTypeId()>0) {
853 853 // construct a new variant from the C++ object if it has a meta type (this will COPY the object!)
854 854 v = QVariant(wrap->classInfo()->metaTypeId(), wrap->_wrappedPtr);
855 855 } else {
856 856 // TODOXXX we could as well check if there is a registered meta type for "classname*", so that we may pass
857 857 // the pointer here...
858 858 // is this worth anything? we loose the knowledge of the cpp object type
859 859 v = qVariantFromValue(wrap->_wrappedPtr);
860 860 }
861 861 } else {
862 862 // this gives us a QObject pointer
863 863 QObject* myObject = wrap->_obj;
864 864 v = qVariantFromValue(myObject);
865 865 }
866 866 return v;
867 867 } else if (val->ob_type==&PyDict_Type) {
868 868 type = QVariant::Map;
869 869 } else if (val->ob_type==&PyList_Type || val->ob_type==&PyTuple_Type || PySequence_Check(val)) {
870 870 type = QVariant::List;
871 871 } else if (val == Py_None) {
872 872 // none is invalid
873 873 type = QVariant::Invalid;
874 874 } else {
875 875 // this used to be:
876 876 // type = QVariant::String;
877 877 // but now we want to transport the Python Objects directly:
878 878 PythonQtObjectPtr o(val);
879 879 v = qVariantFromValue(o);
880 880 return v;
881 881 }
882 882 }
883 883 // special type request:
884 884 switch (type) {
885 885 case QVariant::Invalid:
886 886 return v;
887 887 break;
888 888 case QVariant::Int:
889 889 {
890 890 int d = PyObjGetInt(val, false, ok);
891 891 if (ok) return QVariant(d);
892 892 }
893 893 break;
894 894 case QVariant::UInt:
895 895 {
896 896 int d = PyObjGetInt(val, false,ok);
897 897 if (ok) v = QVariant((unsigned int)d);
898 898 }
899 899 break;
900 900 case QVariant::Bool:
901 901 {
902 902 int d = PyObjGetBool(val,false,ok);
903 903 if (ok) v = QVariant((bool)(d!=0));
904 904 }
905 905 break;
906 906 case QVariant::Double:
907 907 {
908 908 double d = PyObjGetDouble(val,false,ok);
909 909 if (ok) v = QVariant(d);
910 910 break;
911 911 }
912 912 case QMetaType::Float:
913 913 {
914 914 float d = (float) PyObjGetDouble(val,false,ok);
915 915 if (ok) v = qVariantFromValue(d);
916 916 break;
917 917 }
918 918 case QMetaType::Long:
919 919 {
920 920 long d = (long) PyObjGetLongLong(val,false,ok);
921 921 if (ok) v = qVariantFromValue(d);
922 922 break;
923 923 }
924 924 case QMetaType::ULong:
925 925 {
926 926 unsigned long d = (unsigned long) PyObjGetLongLong(val,false,ok);
927 927 if (ok) v = qVariantFromValue(d);
928 928 break;
929 929 }
930 930 case QMetaType::LongLong:
931 931 {
932 932 qint64 d = PyObjGetLongLong(val, false, ok);
933 933 if (ok) v = qVariantFromValue(d);
934 934 }
935 935 break;
936 936 case QMetaType::ULongLong:
937 937 {
938 938 quint64 d = PyObjGetULongLong(val, false, ok);
939 939 if (ok) v = qVariantFromValue(d);
940 940 }
941 941 break;
942 942 case QMetaType::Short:
943 943 {
944 944 short d = (short) PyObjGetInt(val,false,ok);
945 945 if (ok) v = qVariantFromValue(d);
946 946 break;
947 947 }
948 948 case QMetaType::UShort:
949 949 {
950 950 unsigned short d = (unsigned short) PyObjGetInt(val,false,ok);
951 951 if (ok) v = qVariantFromValue(d);
952 952 break;
953 953 }
954 954 case QMetaType::Char:
955 955 {
956 956 char d = (char) PyObjGetInt(val,false,ok);
957 957 if (ok) v = qVariantFromValue(d);
958 958 break;
959 959 }
960 960 case QMetaType::UChar:
961 961 {
962 962 unsigned char d = (unsigned char) PyObjGetInt(val,false,ok);
963 963 if (ok) v = qVariantFromValue(d);
964 964 break;
965 965 }
966 966
967 967 case QVariant::ByteArray:
968 968 case QVariant::String:
969 969 {
970 970 bool ok;
971 971 v = QVariant(PyObjGetString(val, false, ok));
972 972 }
973 973 break;
974 974
975 975 // these are important for MeVisLab
976 976 case QVariant::Map:
977 977 {
978 978 if (PyMapping_Check(val)) {
979 979 QMap<QString,QVariant> map;
980 980 PyObject* items = PyMapping_Items(val);
981 981 if (items) {
982 982 int count = PyList_Size(items);
983 983 PyObject* value;
984 984 PyObject* key;
985 985 PyObject* tuple;
986 986 for (int i = 0;i<count;i++) {
987 987 tuple = PyList_GetItem(items,i);
988 988 key = PyTuple_GetItem(tuple, 0);
989 989 value = PyTuple_GetItem(tuple, 1);
990 990 map.insert(PyObjGetString(key), PyObjToQVariant(value,-1));
991 991 }
992 992 Py_DECREF(items);
993 993 v = map;
994 994 }
995 995 }
996 996 }
997 997 break;
998 998 case QVariant::List:
999 999 if (PySequence_Check(val)) {
1000 1000 QVariantList list;
1001 1001 int count = PySequence_Size(val);
1002 1002 PyObject* value;
1003 1003 for (int i = 0;i<count;i++) {
1004 1004 value = PySequence_GetItem(val,i);
1005 1005 list.append(PyObjToQVariant(value, -1));
1006 1006 }
1007 1007 v = list;
1008 1008 }
1009 1009 break;
1010 1010 case QVariant::StringList:
1011 1011 {
1012 1012 bool ok;
1013 1013 QStringList l = PyObjToStringList(val, false, ok);
1014 1014 if (ok) {
1015 1015 v = l;
1016 1016 }
1017 1017 }
1018 1018 break;
1019 1019
1020 1020 default:
1021 1021 if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
1022 1022 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
1023 1023 if (wrap->classInfo()->isCPPWrapper() && wrap->classInfo()->metaTypeId() == type) {
1024 1024 // construct a new variant from the C++ object if it has the same meta type
1025 1025 v = QVariant(type, wrap->_wrappedPtr);
1026 1026 } else {
1027 1027 v = QVariant();
1028 1028 }
1029 1029 } else {
1030 1030 v = QVariant();
1031 1031 }
1032 1032 }
1033 1033 return v;
1034 1034 }
1035 1035
1036 1036 PyObject* PythonQtConv::QStringToPyObject(const QString& str)
1037 1037 {
1038 1038 if (str.isNull()) {
1039 1039 return PyString_FromString("");
1040 1040 } else {
1041 1041 #ifdef WIN32
1042 1042 // return PyString_FromString(str.toLatin1().data());
1043 1043 return PyUnicode_FromUnicode(str.utf16(), str.length());
1044 1044 #else
1045 1045 return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, NULL, NULL);
1046 1046 #endif
1047 1047 }
1048 1048 }
1049 1049
1050 1050 PyObject* PythonQtConv::QStringListToPyObject(const QStringList& list)
1051 1051 {
1052 1052 PyObject* result = PyTuple_New(list.count());
1053 1053 int i = 0;
1054 1054 QString str;
1055 1055 foreach (str, list) {
1056 1056 PyTuple_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(str));
1057 1057 i++;
1058 1058 }
1059 1059 // why is the error state bad after this?
1060 1060 PyErr_Clear();
1061 1061 return result;
1062 1062 }
1063 1063
1064 1064 PyObject* PythonQtConv::QStringListToPyList(const QStringList& list)
1065 1065 {
1066 1066 PyObject* result = PyList_New(list.count());
1067 1067 int i = 0;
1068 1068 for (QStringList::ConstIterator it = list.begin(); it!=list.end(); ++it) {
1069 1069 PyList_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(*it));
1070 1070 i++;
1071 1071 }
1072 1072 return result;
1073 1073 }
1074 1074
1075 1075 PyObject* PythonQtConv::QVariantToPyObject(const QVariant& v)
1076 1076 {
1077 1077 return ConvertQtValueToPythonInternal(v.userType(), (void*)v.constData());
1078 1078 }
1079 1079
1080 1080 PyObject* PythonQtConv::QVariantMapToPyObject(const QVariantMap& m) {
1081 1081 PyObject* result = PyDict_New();
1082 1082 QVariantMap::const_iterator t = m.constBegin();
1083 1083 PyObject* key;
1084 1084 PyObject* val;
1085 1085 for (;t!=m.end();t++) {
1086 1086 key = QStringToPyObject(t.key());
1087 1087 val = QVariantToPyObject(t.value());
1088 1088 PyDict_SetItem(result, key, val);
1089 1089 Py_DECREF(key);
1090 1090 Py_DECREF(val);
1091 1091 }
1092 1092 return result;
1093 1093 }
1094 1094
1095 1095 PyObject* PythonQtConv::QVariantListToPyObject(const QVariantList& l) {
1096 1096 PyObject* result = PyTuple_New(l.count());
1097 1097 int i = 0;
1098 1098 QVariant v;
1099 1099 foreach (v, l) {
1100 1100 PyTuple_SET_ITEM(result, i, PythonQtConv::QVariantToPyObject(v));
1101 1101 i++;
1102 1102 }
1103 1103 // why is the error state bad after this?
1104 1104 PyErr_Clear();
1105 1105 return result;
1106 1106 }
1107 1107
1108 1108 PyObject* PythonQtConv::ConvertQListOfPointerTypeToPythonList(QList<void*>* list, const QByteArray& typeName)
1109 1109 {
1110 1110 PyObject* result = PyTuple_New(list->count());
1111 1111 int i = 0;
1112 1112 foreach (void* value, *list) {
1113 1113 PyTuple_SET_ITEM(result, i, PythonQt::priv()->wrapPtr(value, typeName));
1114 1114 i++;
1115 1115 }
1116 1116 return result;
1117 1117 }
1118 1118
1119 1119 bool PythonQtConv::ConvertPythonListToQListOfPointerType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool /*strict*/)
1120 1120 {
1121 1121 bool result = false;
1122 1122 if (PySequence_Check(obj)) {
1123 1123 result = true;
1124 1124 int count = PySequence_Size(obj);
1125 1125 PyObject* value;
1126 1126 for (int i = 0;i<count;i++) {
1127 1127 value = PySequence_GetItem(obj,i);
1128 1128 if (PyObject_TypeCheck(value, &PythonQtInstanceWrapper_Type)) {
1129 1129 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)value;
1130 1130 bool ok;
1131 1131 void* object = castWrapperTo(wrap, type, ok);
1132 1132 if (ok) {
1133 1133 list->append(object);
1134 1134 } else {
1135 1135 result = false;
1136 1136 break;
1137 1137 }
1138 1138 }
1139 1139 }
1140 1140 }
1141 1141 return result;
1142 1142 }
1143 1143
1144 1144 int PythonQtConv::getInnerTemplateMetaType(const QByteArray& typeName)
1145 1145 {
1146 1146 int idx = typeName.indexOf("<");
1147 1147 if (idx>0) {
1148 1148 int idx2 = typeName.indexOf(">");
1149 1149 if (idx2>0) {
1150 1150 QByteArray innerType = typeName.mid(idx+1,idx2-idx-1);
1151 1151 return QMetaType::type(innerType.constData());
1152 1152 }
1153 1153 }
1154 1154 return QMetaType::Void;
1155 1155 }
1156 1156
1157 1157
1158 1158 QString PythonQtConv::CPPObjectToString(int type, const void* data) {
1159 1159 QString r;
1160 1160 switch (type) {
1161 1161 case QVariant::Size: {
1162 1162 const QSize* s = static_cast<const QSize*>(data);
1163 1163 r = QString::number(s->width()) + ", " + QString::number(s->height());
1164 1164 }
1165 1165 break;
1166 1166 case QVariant::SizeF: {
1167 1167 const QSizeF* s = static_cast<const QSizeF*>(data);
1168 1168 r = QString::number(s->width()) + ", " + QString::number(s->height());
1169 1169 }
1170 1170 break;
1171 1171 case QVariant::Point: {
1172 1172 const QPoint* s = static_cast<const QPoint*>(data);
1173 1173 r = QString::number(s->x()) + ", " + QString::number(s->y());
1174 1174 }
1175 1175 break;
1176 1176 case QVariant::PointF: {
1177 1177 const QPointF* s = static_cast<const QPointF*>(data);
1178 1178 r = QString::number(s->x()) + ", " + QString::number(s->y());
1179 1179 }
1180 1180 break;
1181 1181 case QVariant::Rect: {
1182 1182 const QRect* s = static_cast<const QRect*>(data);
1183 1183 r = QString::number(s->x()) + ", " + QString::number(s->y());
1184 1184 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1185 1185 }
1186 1186 break;
1187 1187 case QVariant::RectF: {
1188 1188 const QRectF* s = static_cast<const QRectF*>(data);
1189 1189 r = QString::number(s->x()) + ", " + QString::number(s->y());
1190 1190 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1191 1191 }
1192 1192 break;
1193 1193 case QVariant::Date: {
1194 1194 const QDate* s = static_cast<const QDate*>(data);
1195 1195 r = s->toString(Qt::ISODate);
1196 1196 }
1197 1197 break;
1198 1198 case QVariant::DateTime: {
1199 1199 const QDateTime* s = static_cast<const QDateTime*>(data);
1200 1200 r = s->toString(Qt::ISODate);
1201 1201 }
1202 1202 break;
1203 1203 case QVariant::Time: {
1204 1204 const QTime* s = static_cast<const QTime*>(data);
1205 1205 r = s->toString(Qt::ISODate);
1206 1206 }
1207 1207 break;
1208 1208 case QVariant::Pixmap:
1209 1209 {
1210 1210 const QPixmap* s = static_cast<const QPixmap*>(data);
1211 1211 r = QString("Pixmap ") + QString::number(s->width()) + ", " + QString::number(s->height());
1212 1212 }
1213 1213 break;
1214 1214 case QVariant::Image:
1215 1215 {
1216 1216 const QImage* s = static_cast<const QImage*>(data);
1217 1217 r = QString("Image ") + QString::number(s->width()) + ", " + QString::number(s->height());
1218 1218 }
1219 1219 break;
1220 1220 case QVariant::Url:
1221 1221 {
1222 1222 const QUrl* s = static_cast<const QUrl*>(data);
1223 1223 r = s->toString();
1224 1224 }
1225 1225 break;
1226 1226 //TODO: add more printing for other variant types
1227 1227 default:
1228 1228 // this creates a copy, but that should not be expensive for typical simple variants
1229 1229 // (but we do not want to do this for our won user types!
1230 1230 if (type>0 && type < (int)QVariant::UserType) {
1231 1231 QVariant v(type, data);
1232 1232 r = v.toString();
1233 1233 }
1234 1234 }
1235 1235 return r;
1236 1236 }
@@ -1,210 +1,210
1 1 #ifndef _PYTHONQTCONVERSION_H
2 2 #define _PYTHONQTCONVERSION_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtConversion.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQt.h"
46 46 #include "PythonQtMisc.h"
47 47 #include "PythonQtClassInfo.h"
48 48 #include "PythonQtMethodInfo.h"
49 49
50 50 #include <QWidget>
51 51 #include <QList>
52 52 #include <vector>
53 53
54 54 typedef PyObject* PythonQtConvertMetaTypeToPythonCB(const void* inObject, int metaTypeId);
55 55 typedef bool PythonQtConvertPythonToMetaTypeCB(PyObject* inObject, void* outObject, int metaTypeId, bool strict);
56 56
57 57 #define PythonQtRegisterListTemplateConverter(type, innertype) \
58 58 { int typeId = qRegisterMetaType<type<innertype> >(#type"<"#innertype">"); \
59 59 PythonQtConv::registerPythonToMetaTypeConverter(typeId, PythonQtConvertPythonListToListOfValueType<type<innertype>, innertype>); \
60 60 PythonQtConv::registerMetaTypeToPythonConverter(typeId, PythonQtConvertListOfValueTypeToPythonList<type<innertype>, innertype>); \
61 61 }
62 62
63 63 #define PythonQtRegisterToolClassesTemplateConverter(innertype) \
64 64 PythonQtRegisterListTemplateConverter(QList, innertype); \
65 65 PythonQtRegisterListTemplateConverter(QVector, innertype); \
66 66 PythonQtRegisterListTemplateConverter(std::vector, innertype);
67 67 // TODO: add QHash etc. here!
68 68
69 69 //! a static class that offers methods for type conversion
70 70 class PYTHONQT_EXPORT PythonQtConv {
71 71
72 72 public:
73 73
74 74 //! get a ref counted True or False Python object
75 75 static PyObject* GetPyBool(bool val);
76 76
77 77 //! converts the Qt parameter given in \c data, interpreting it as a \c info parameter, into a Python object,
78 78 static PyObject* ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data);
79 79
80 80 //! convert python object to Qt (according to the given parameter) and if the conversion should be strict (classInfo is currently not used anymore)
81 81 static void* ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* classInfo, void* alreadyAllocatedCPPObject = NULL);
82 82
83 83 //! creates a data storage for the passed parameter type and returns a void pointer to be set as arg[0] of qt_metacall
84 84 static void* CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info);
85 85
86 86 //! converts QString to Python string (unicode!)
87 87 static PyObject* QStringToPyObject(const QString& str);
88 88
89 89 //! converts QStringList to Python tuple
90 90 static PyObject* QStringListToPyObject(const QStringList& list);
91 91
92 92 //! converts QStringList to Python list
93 93 static PyObject* QStringListToPyList(const QStringList& list);
94 94
95 95 //! get string representation of py object
96 96 static QString PyObjGetRepresentation(PyObject* val);
97 97
98 98 //! get string value from py object
99 99 static QString PyObjGetString(PyObject* val) { bool ok; QString s = PyObjGetString(val, false, ok); return s; }
100 100 //! get string value from py object
101 101 static QString PyObjGetString(PyObject* val, bool strict, bool &ok);
102 102 //! get bytes from py object
103 103 static QByteArray PyObjGetBytes(PyObject* val, bool strict, bool &ok);
104 104 //! get int from py object
105 105 static int PyObjGetInt(PyObject* val, bool strict, bool &ok);
106 106 //! get int64 from py object
107 107 static qint64 PyObjGetLongLong(PyObject* val, bool strict, bool &ok);
108 108 //! get int64 from py object
109 109 static quint64 PyObjGetULongLong(PyObject* val, bool strict, bool &ok);
110 110 //! get double from py object
111 111 static double PyObjGetDouble(PyObject* val, bool strict, bool &ok);
112 112 //! get bool from py object
113 113 static bool PyObjGetBool(PyObject* val, bool strict, bool &ok);
114 114
115 115 //! create a string list from python sequence
116 116 static QStringList PyObjToStringList(PyObject* val, bool strict, bool& ok);
117 117
118 118 //! convert python object to qvariant, if type is given it will try to create a qvariant of that type, otherwise
119 119 //! it will guess from the python type
120 120 static QVariant PyObjToQVariant(PyObject* val, int type = -1);
121 121
122 122 //! convert QVariant from PyObject
123 123 static PyObject* QVariantToPyObject(const QVariant& v);
124 124
125 125 static PyObject* QVariantMapToPyObject(const QVariantMap& m);
126 126 static PyObject* QVariantListToPyObject(const QVariantList& l);
127 127
128 128 //! get human readable string from CPP object (when the metatype is known)
129 129 static QString CPPObjectToString(int type, const void* data);
130 130
131 131 //! register a converter callback from python to cpp for given metatype
132 132 static void registerPythonToMetaTypeConverter(int metaTypeId, PythonQtConvertPythonToMetaTypeCB* cb) { _pythonToMetaTypeConverters.insert(metaTypeId, cb); }
133 133
134 134 //! register a converter callback from cpp to python for given metatype
135 135 static void registerMetaTypeToPythonConverter(int metaTypeId, PythonQtConvertMetaTypeToPythonCB* cb) { _metaTypeToPythonConverters.insert(metaTypeId, cb); }
136 136
137 137 //! returns the inner type id of a simple template of the form SomeObject<InnerType>
138 138 static int getInnerTemplateMetaType(const QByteArray& typeName);
139 139
140 140 //! converts the Qt parameter given in \c data, interpreting it as a \c type registered qvariant/meta type, into a Python object,
141 141 static PyObject* ConvertQtValueToPythonInternal(int type, const void* data);
142 142
143 143 public:
144 144
145 145 static PythonQtValueStorage<qint64, 128> global_valueStorage;
146 146 static PythonQtValueStorage<void*, 128> global_ptrStorage;
147 static PythonQtValueStorage<QVariant, 32> global_variantStorage;
147 static PythonQtValueStorageWithCleanup<QVariant, 128> global_variantStorage;
148 148
149 149 protected:
150 150 static QHash<int, PythonQtConvertMetaTypeToPythonCB*> _metaTypeToPythonConverters;
151 151 static QHash<int, PythonQtConvertPythonToMetaTypeCB*> _pythonToMetaTypeConverters;
152 152
153 153 //! handle automatic conversion of some special types (QColor, QBrush, ...)
154 154 static void* handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject);
155 155
156 156 //! converts the list of pointers of given type to Python
157 157 static PyObject* ConvertQListOfPointerTypeToPythonList(QList<void*>* list, const QByteArray& type);
158 158 //! tries to convert the python object to a QList of pointers to \c type objects, returns true on success
159 159 static bool ConvertPythonListToQListOfPointerType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool strict);
160 160
161 161 //! cast wrapper to given className if possible
162 162 static void* castWrapperTo(PythonQtInstanceWrapper* wrapper, const QByteArray& className, bool& ok);
163 163 };
164 164
165 165 template<class ListType, class T>
166 166 PyObject* PythonQtConvertListOfValueTypeToPythonList(const void* /*QList<T>* */ inList, int metaTypeId)
167 167 {
168 168 ListType* list = (ListType*)inList;
169 169 static const int innerType = PythonQtConv::getInnerTemplateMetaType(QByteArray(QMetaType::typeName(metaTypeId)));
170 170 if (innerType == QVariant::Invalid) {
171 171 std::cerr << "PythonQtConvertListOfValueTypeToPythonList: unknown inner type " << QMetaType::typeName(metaTypeId) << std::endl;
172 172 }
173 173 PyObject* result = PyTuple_New(list->size());
174 174 int i = 0;
175 175 foreach (const T& value, *list) {
176 176 PyTuple_SET_ITEM(result, i, PythonQtConv::ConvertQtValueToPythonInternal(innerType, &value));
177 177 i++;
178 178 }
179 179 return result;
180 180 }
181 181
182 182 template<class ListType, class T>
183 183 bool PythonQtConvertPythonListToListOfValueType(PyObject* obj, void* /*QList<T>* */ outList, int metaTypeId, bool /*strict*/)
184 184 {
185 185 ListType* list = (ListType*)outList;
186 186 static const int innerType = PythonQtConv::getInnerTemplateMetaType(QByteArray(QMetaType::typeName(metaTypeId)));
187 187 if (innerType == QVariant::Invalid) {
188 188 std::cerr << "PythonQtConvertPythonListToListOfValueType: unknown inner type " << QMetaType::typeName(metaTypeId) << std::endl;
189 189 }
190 190 bool result = false;
191 191 if (PySequence_Check(obj)) {
192 192 result = true;
193 193 int count = PySequence_Size(obj);
194 194 PyObject* value;
195 195 for (int i = 0;i<count;i++) {
196 196 value = PySequence_GetItem(obj,i);
197 197 // this is quite some overhead, but it avoids having another large switch...
198 198 QVariant v = PythonQtConv::PyObjToQVariant(value, innerType);
199 199 if (v.isValid()) {
200 200 list->push_back(qVariantValue<T>(v));
201 201 } else {
202 202 result = false;
203 203 break;
204 204 }
205 205 }
206 206 }
207 207 return result;
208 208 }
209 209
210 210 #endif
@@ -1,61 +1,61
1 1 #ifndef _PYTHONQTCPPWRAPPERFACTORY_H
2 2 #define _PYTHONQTCPPWRAPPERFACTORY_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtCppWrapperFactory.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-06
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 //! Factory interface for C++ classes that can be wrapped by QObject objects
46 46 /*! To create your own factory, derive PythonQtCppWrapperFactory and implement
47 47 the create() method.
48 48 A factory can be added to PythonQt by PythonQt::addCppWrapperFactory().
49 49 */
50 50 class PYTHONQT_EXPORT PythonQtCppWrapperFactory
51 51 {
52 52 public:
53 53 PythonQtCppWrapperFactory() {};
54 54 virtual ~PythonQtCppWrapperFactory() {};
55 55
56 56 //! create a wrapper for the given object
57 57 virtual QObject* create(const QByteArray& name, void *ptr) = 0;
58 58
59 59 };
60 60
61 #endif No newline at end of file
61 #endif
@@ -1,72 +1,75
1 1 #ifndef _PYTHONQTIMPORTFILEINTERFACE_H
2 2 #define _PYTHONQTIMPORTFILEINTERFACE_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtImportFileInterface.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include <QDateTime>
46 46 #include <QString>
47 47 #include <QByteArray>
48 48
49 //! Defines an abstract interface to file access for the Python import statement.
49 //! Defines an abstract interface to file access for the Python import statement.
50 50 //! see PythonQt::setImporter()
51 51 class PythonQtImportFileInterface {
52 52
53 53 public:
54 54 // get rid of warnings
55 55 virtual ~PythonQtImportFileInterface() {}
56 56
57 57 //! read the given file as byte array, without doing any linefeed translations
58 58 virtual QByteArray readFileAsBytes(const QString& filename) = 0;
59 59
60 60 //! read a source file, expects a readable Python text file with translated line feeds.
61 61 //! If the file can not be load OR it can not be verified, ok is set to false
62 62 virtual QByteArray readSourceFile(const QString& filename, bool& ok) = 0;
63 63
64 64 //! returns if the file exists
65 65 virtual bool exists(const QString& filename) = 0;
66 66
67 67 //! get the last modified data of a file
68 68 virtual QDateTime lastModifiedDate(const QString& filename) = 0;
69 69
70 //! indicates that *.py files which are newer than their corresponding *.pyc files
71 //! are ignored
72 virtual bool ignoreUpdatedPythonSourceFiles() { return false; }
70 73 };
71 74
72 #endif No newline at end of file
75 #endif
@@ -1,793 +1,822
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtImporter.h
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 // This module was inspired by the zipimport.c module of the original
41 41 // Python distribution. Most of the functions are identical or slightly
42 42 // modified to do all the loading of Python files via an external file interface.
43 43 // In contrast to zipimport.c, this module also writes *.pyc files
44 44 // automatically if it has write access/is not inside of a zip file.
45 45 //----------------------------------------------------------------------------------
46 46
47 47 #include "PythonQtImporter.h"
48 48 #include "PythonQtImportFileInterface.h"
49 49 #include "PythonQt.h"
50 50 #include "PythonQtConversion.h"
51 51 #include <QFile>
52 52 #include <QFileInfo>
53 53
54 54 #define IS_SOURCE 0x0
55 55 #define IS_BYTECODE 0x1
56 56 #define IS_PACKAGE 0x2
57 57
58 58 struct st_mlab_searchorder {
59 59 char suffix[14];
60 60 int type;
61 61 };
62 62
63 63 /* mlab_searchorder defines how we search for a module in the Zip
64 64 archive: we first search for a package __init__, then for
65 65 non-package .pyc, .pyo and .py entries. The .pyc and .pyo entries
66 66 are swapped by initmlabimport() if we run in optimized mode. Also,
67 67 '/' is replaced by SEP there. */
68 68 struct st_mlab_searchorder mlab_searchorder[] = {
69 69 {"/__init__.pyc", IS_PACKAGE | IS_BYTECODE},
70 70 {"/__init__.pyo", IS_PACKAGE | IS_BYTECODE},
71 71 {"/__init__.py", IS_PACKAGE | IS_SOURCE},
72 72 {".pyc", IS_BYTECODE},
73 73 {".pyo", IS_BYTECODE},
74 74 {".py", IS_SOURCE},
75 75 {"", 0}
76 76 };
77 77
78 78 extern PyTypeObject PythonQtImporter_Type;
79 79 PyObject *PythonQtImportError;
80 80
81 81 QString PythonQtImport::getSubName(const QString& str)
82 82 {
83 83 int idx = str.lastIndexOf('.');
84 84 if (idx!=-1) {
85 85 return str.mid(idx+1);
86 86 } else {
87 87 return str;
88 88 }
89 89 }
90 90
91 91 PythonQtImport::ModuleInfo PythonQtImport::getModuleInfo(PythonQtImporter* self, const QString& fullname)
92 92 {
93 93 ModuleInfo info;
94 94 QString subname;
95 95 struct st_mlab_searchorder *zso;
96 96
97 97 subname = getSubName(fullname);
98 98 QString path = *self->_path + "/" + subname;
99 99
100 100 QString test;
101 101 for (zso = mlab_searchorder; *zso->suffix; zso++) {
102 102 test = path + zso->suffix;
103 103 if (PythonQt::importInterface()->exists(test)) {
104 104 info.fullPath = test;
105 105 info.moduleName = subname;
106 106 info.type = (zso->type & IS_PACKAGE)?MI_PACKAGE:MI_MODULE;
107 107 return info;
108 108 }
109 109 }
110 110 // test if it is a shared library
111 111 foreach(const QString& suffix, PythonQt::priv()->sharedLibrarySuffixes()) {
112 112 test = path+suffix;
113 113 if (PythonQt::importInterface()->exists(test)) {
114 114 info.fullPath = test;
115 115 info.moduleName = subname;
116 116 info.type = MI_SHAREDLIBRARY;
117 return info;
117 118 }
118 119 }
119 120 return info;
120 121 }
121 122
122 123
123 124 /* PythonQtImporter.__init__
124 125 Just store the path argument (or reject if it is in the ignorePaths list
125 126 */
126 127 int PythonQtImporter_init(PythonQtImporter *self, PyObject *args, PyObject * /*kwds*/)
127 128 {
128 129 self->_path = NULL;
129 130
130 131 const char* cpath;
131 132 if (!PyArg_ParseTuple(args, "s",
132 133 &cpath))
133 134 return -1;
134 135
135 136 QString path(cpath);
136 137 if (PythonQt::importInterface()->exists(path)) {
137 138 const QStringList& ignorePaths = PythonQt::self()->getImporterIgnorePaths();
138 139 foreach(QString ignorePath, ignorePaths) {
139 140 if (path.startsWith(ignorePath)) {
140 141 PyErr_SetString(PythonQtImportError,
141 142 "path ignored");
142 143 return -1;
143 144 }
144 145 }
145 146
146 147 self->_path = new QString(path);
147 148 return 0;
148 149 } else {
149 150 PyErr_SetString(PythonQtImportError,
150 151 "path does not exist error");
151 152 return -1;
152 153 }
153 154 }
154 155
155 156 void
156 157 PythonQtImporter_dealloc(PythonQtImporter *self)
157 158 {
158 159 // free the stored path
159 160 if (self->_path) delete self->_path;
160 161 // free ourself
161 162 self->ob_type->tp_free((PyObject *)self);
162 163 }
163 164
164 165
165 166 /* Check whether we can satisfy the import of the module named by
166 167 'fullname'. Return self if we can, None if we can't. */
167 168 PyObject *
168 169 PythonQtImporter_find_module(PyObject *obj, PyObject *args)
169 170 {
170 171 PythonQtImporter *self = (PythonQtImporter *)obj;
171 172 PyObject *path = NULL;
172 173 char *fullname;
173 174
174 175 if (!PyArg_ParseTuple(args, "s|O:PythonQtImporter.find_module",
175 176 &fullname, &path))
176 177 return NULL;
177 178
178 179 //qDebug() << "looking for " << fullname << " at " << *self->_path;
179 180
180 181 PythonQtImport::ModuleInfo info = PythonQtImport::getModuleInfo(self, fullname);
181 182 if (info.type != PythonQtImport::MI_NOT_FOUND) {
182 183 Py_INCREF(self);
183 184 return (PyObject *)self;
184 185 } else {
185 186 Py_INCREF(Py_None);
186 187 return Py_None;
187 188 }
188 189 }
189 190
190 191 /* Load and return the module named by 'fullname'. */
191 192 PyObject *
192 193 PythonQtImporter_load_module(PyObject *obj, PyObject *args)
193 194 {
194 195 PythonQtImporter *self = (PythonQtImporter *)obj;
195 196 PyObject *code = NULL, *mod = NULL, *dict = NULL;
196 197 char *fullname;
197 198
198 199 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.load_module",
199 200 &fullname))
200 201 return NULL;
201 202
202 203 PythonQtImport::ModuleInfo info = PythonQtImport::getModuleInfo(self, fullname);
203 204 if (info.type == PythonQtImport::MI_NOT_FOUND) {
204 205 return NULL;
205 206 }
206 207
207 208 if (info.type == PythonQtImport::MI_PACKAGE || info.type == PythonQtImport::MI_MODULE) {
208 209 QString fullPath;
209 210 code = PythonQtImport::getModuleCode(self, fullname, fullPath);
210 211 if (code == NULL) {
211 212 return NULL;
212 213 }
213 214
214 215 mod = PyImport_AddModule(fullname);
215 216 if (mod == NULL) {
216 217 Py_DECREF(code);
217 218 return NULL;
218 219 }
219 220 dict = PyModule_GetDict(mod);
220 221
221 222 if (PyDict_SetItemString(dict, "__loader__", (PyObject *)self) != 0) {
222 223 Py_DECREF(code);
223 224 Py_DECREF(mod);
224 225 return NULL;
225 226 }
226 227
227 228 if (info.type == PythonQtImport::MI_PACKAGE) {
228 229 PyObject *pkgpath, *fullpath;
229 230 QString subname = info.moduleName;
230 231 int err;
231 232
232 233 fullpath = PyString_FromFormat("%s%c%s",
233 234 self->_path->toLatin1().constData(),
234 235 SEP,
235 236 subname.toLatin1().constData());
236 237 if (fullpath == NULL) {
237 238 Py_DECREF(code);
238 239 Py_DECREF(mod);
239 240 return NULL;
240 241 }
241 242
242 243 pkgpath = Py_BuildValue("[O]", fullpath);
243 244 Py_DECREF(fullpath);
244 245 if (pkgpath == NULL) {
245 246 Py_DECREF(code);
246 247 Py_DECREF(mod);
247 248 return NULL;
248 249 }
249 250 err = PyDict_SetItemString(dict, "__path__", pkgpath);
250 251 Py_DECREF(pkgpath);
251 252 if (err != 0) {
252 253 Py_DECREF(code);
253 254 Py_DECREF(mod);
254 255 return NULL;
255 256 }
256 257 }
257 258 mod = PyImport_ExecCodeModuleEx(fullname, code, fullPath.toLatin1().data());
258 259 Py_DECREF(code);
259 260 if (Py_VerboseFlag) {
260 261 PySys_WriteStderr("import %s # loaded from %s\n",
261 262 fullname, fullPath.toLatin1().constData());
262 263 }
263 264 } else {
264 265 PythonQtObjectPtr imp;
265 266 imp.setNewRef(PyImport_ImportModule("imp"));
266
267
267 268 // Create a PyList with the current path as its single element,
268 269 // which is required for find_module (it won't accept a tuple...)
269 270 PythonQtObjectPtr pathList;
270 271 pathList.setNewRef(PythonQtConv::QStringListToPyList(QStringList() << *self->_path));
271 272
272 273 QVariantList args;
273 274 // Pass the module name without the package prefix
274 275 args.append(info.moduleName);
275 276 // And the path where we know that the shared library is
276 277 args.append(QVariant::fromValue(pathList));
277 278 QVariant result = imp.call("find_module", args);
278 279 if (result.isValid()) {
279 // This will return a tuple with (file, pathname, description)
280 // This will return a tuple with (file, pathname, description=(suffix,mode,type))
280 281 QVariantList list = result.toList();
281 282 if (list.count()==3) {
282 283 // We prepend the full module name (including package prefix)
283 284 list.prepend(fullname);
284 // And call "load_module" with (fullname, file, pathname, description)
285 #ifdef __linux
286 #ifdef _DEBUG
287 // imp_find_module() does not respect the debug suffix '_d' on Linux,
288 // so it does not return the correct file path and we correct it now
289 // find_module opened a file to the release library, but that file handle is
290 // ignored on Linux and Windows, maybe on MacOS also.
291 list[2] = info.fullPath;
292 #endif
293 #endif
294 // And call "load_module" with (fullname, file, pathname, description=(suffix,mode,type))
285 295 PythonQtObjectPtr module = imp.call("load_module", list);
286 296 mod = module.object();
287 297 if (mod) {
288 298 Py_INCREF(mod);
289 299 }
290 300
291 301 // Finally, we need to close the file again, which find_module opened for us
292 302 PythonQtObjectPtr file = list.at(1);
293 303 file.call("close");
294 304 }
295 305 }
296 306 }
297 307 return mod;
298 308 }
299 309
300 310
301 311 PyObject *
302 312 PythonQtImporter_get_data(PyObject* /*obj*/, PyObject* /*args*/)
303 313 {
304 314 // EXTRA, NOT YET IMPLEMENTED
305 315 return NULL;
306 316 }
307 317
308 318 PyObject *
309 319 PythonQtImporter_get_code(PyObject *obj, PyObject *args)
310 320 {
311 321 PythonQtImporter *self = (PythonQtImporter *)obj;
312 322 char *fullname;
313 323
314 324 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.get_code", &fullname))
315 325 return NULL;
316 326
317 327 QString notused;
318 328 return PythonQtImport::getModuleCode(self, fullname, notused);
319 329 }
320 330
321 331 PyObject *
322 332 PythonQtImporter_get_source(PyObject * /*obj*/, PyObject * /*args*/)
323 333 {
324 334 // EXTRA, NOT YET IMPLEMENTED
325 335 return NULL;
326 336 }
327 337
328 338 PyDoc_STRVAR(doc_find_module,
329 339 "find_module(fullname, path=None) -> self or None.\n\
330 340 \n\
331 341 Search for a module specified by 'fullname'. 'fullname' must be the\n\
332 342 fully qualified (dotted) module name. It returns the PythonQtImporter\n\
333 343 instance itself if the module was found, or None if it wasn't.\n\
334 344 The optional 'path' argument is ignored -- it's there for compatibility\n\
335 345 with the importer protocol.");
336 346
337 347 PyDoc_STRVAR(doc_load_module,
338 348 "load_module(fullname) -> module.\n\
339 349 \n\
340 350 Load the module specified by 'fullname'. 'fullname' must be the\n\
341 351 fully qualified (dotted) module name. It returns the imported\n\
342 352 module, or raises PythonQtImportError if it wasn't found.");
343 353
344 354 PyDoc_STRVAR(doc_get_data,
345 355 "get_data(pathname) -> string with file data.\n\
346 356 \n\
347 357 Return the data associated with 'pathname'. Raise IOError if\n\
348 358 the file wasn't found.");
349 359
350 360 PyDoc_STRVAR(doc_get_code,
351 361 "get_code(fullname) -> code object.\n\
352 362 \n\
353 363 Return the code object for the specified module. Raise PythonQtImportError\n\
354 364 is the module couldn't be found.");
355 365
356 366 PyDoc_STRVAR(doc_get_source,
357 367 "get_source(fullname) -> source string.\n\
358 368 \n\
359 369 Return the source code for the specified module. Raise PythonQtImportError\n\
360 370 is the module couldn't be found, return None if the archive does\n\
361 371 contain the module, but has no source for it.");
362 372
363 373 PyMethodDef PythonQtImporter_methods[] = {
364 374 {"find_module", PythonQtImporter_find_module, METH_VARARGS,
365 375 doc_find_module},
366 376 {"load_module", PythonQtImporter_load_module, METH_VARARGS,
367 377 doc_load_module},
368 378 {"get_data", PythonQtImporter_get_data, METH_VARARGS,
369 379 doc_get_data},
370 380 {"get_code", PythonQtImporter_get_code, METH_VARARGS,
371 381 doc_get_code},
372 382 {"get_source", PythonQtImporter_get_source, METH_VARARGS,
373 383 doc_get_source},
374 384 {NULL, NULL, 0 , NULL} /* sentinel */
375 385 };
376 386
377 387
378 388 PyDoc_STRVAR(PythonQtImporter_doc,
379 389 "PythonQtImporter(path) -> PythonQtImporter object\n\
380 390 \n\
381 391 Create a new PythonQtImporter instance. 'path' must be a valid path on disk/or inside of a zip file known to MeVisLab\n\
382 392 . Every path is accepted.");
383 393
384 394 #define DEFERRED_ADDRESS(ADDR) 0
385 395
386 396 PyTypeObject PythonQtImporter_Type = {
387 397 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
388 398 0,
389 399 "PythonQtImport.PythonQtImporter",
390 400 sizeof(PythonQtImporter),
391 401 0, /* tp_itemsize */
392 402 (destructor)PythonQtImporter_dealloc, /* tp_dealloc */
393 403 0, /* tp_print */
394 404 0, /* tp_getattr */
395 405 0, /* tp_setattr */
396 406 0, /* tp_compare */
397 407 0, /* tp_repr */
398 408 0, /* tp_as_number */
399 409 0, /* tp_as_sequence */
400 410 0, /* tp_as_mapping */
401 411 0, /* tp_hash */
402 412 0, /* tp_call */
403 413 0, /* tp_str */
404 414 PyObject_GenericGetAttr, /* tp_getattro */
405 415 0, /* tp_setattro */
406 416 0, /* tp_as_buffer */
407 417 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE , /* tp_flags */
408 418 PythonQtImporter_doc, /* tp_doc */
409 419 0, /* tp_traverse */
410 420 0, /* tp_clear */
411 421 0, /* tp_richcompare */
412 422 0, /* tp_weaklistoffset */
413 423 0, /* tp_iter */
414 424 0, /* tp_iternext */
415 425 PythonQtImporter_methods, /* tp_methods */
416 426 0, /* tp_members */
417 427 0, /* tp_getset */
418 428 0, /* tp_base */
419 429 0, /* tp_dict */
420 430 0, /* tp_descr_get */
421 431 0, /* tp_descr_set */
422 432 0, /* tp_dictoffset */
423 433 (initproc)PythonQtImporter_init, /* tp_init */
424 434 PyType_GenericAlloc, /* tp_alloc */
425 435 PyType_GenericNew, /* tp_new */
426 436 PyObject_Del, /* tp_free */
427 437 };
428 438
429 439
430 440 /* Given a buffer, return the long that is represented by the first
431 441 4 bytes, encoded as little endian. This partially reimplements
432 442 marshal.c:r_long() */
433 443 long
434 444 PythonQtImport::getLong(unsigned char *buf)
435 445 {
436 446 long x;
437 447 x = buf[0];
438 448 x |= (long)buf[1] << 8;
439 449 x |= (long)buf[2] << 16;
440 450 x |= (long)buf[3] << 24;
441 451 #if SIZEOF_LONG > 4
442 452 /* Sign extension for 64-bit machines */
443 453 x |= -(x & 0x80000000L);
444 454 #endif
445 455 return x;
446 456 }
447 457
448 458 FILE *
449 459 open_exclusive(const QString& filename)
450 460 {
451 461 #if defined(O_EXCL)&&defined(O_CREAT)&&defined(O_WRONLY)&&defined(O_TRUNC)
452 462 /* Use O_EXCL to avoid a race condition when another process tries to
453 463 write the same file. When that happens, our open() call fails,
454 464 which is just fine (since it's only a cache).
455 465 XXX If the file exists and is writable but the directory is not
456 466 writable, the file will never be written. Oh well.
457 467 */
458 468 QFile::remove(filename);
459 469
460 470 int fd;
461 471 int flags = O_EXCL|O_CREAT|O_WRONLY|O_TRUNC;
462 472 #ifdef O_BINARY
463 473 flags |= O_BINARY; /* necessary for Windows */
464 474 #endif
465 475 #ifdef WIN32
466 476 fd = _wopen(filename.ucs2(), flags, 0666);
467 477 #else
468 478 fd = open(filename.local8Bit(), flags, 0666);
469 479 #endif
470 480 if (fd < 0)
471 481 return NULL;
472 482 return fdopen(fd, "wb");
473 483 #else
474 484 /* Best we can do -- on Windows this can't happen anyway */
475 485 return fopen(filename.toLocal8Bit().constData(), "wb");
476 486 #endif
477 487 }
478 488
479 489
480 490 void PythonQtImport::writeCompiledModule(PyCodeObject *co, const QString& filename, long mtime)
481 491 {
482 492 FILE *fp;
483 493 // we do not want to write Qt resources to disk, do we?
484 494 if (filename.startsWith(":")) {
485 495 return;
486 496 }
487 497 fp = open_exclusive(filename);
488 498 if (fp == NULL) {
489 499 if (Py_VerboseFlag)
490 500 PySys_WriteStderr(
491 501 "# can't create %s\n", filename.toLatin1().constData());
492 502 return;
493 503 }
494 504 #if PY_VERSION_HEX < 0x02040000
495 505 PyMarshal_WriteLongToFile(PyImport_GetMagicNumber(), fp);
496 506 #else
497 507 PyMarshal_WriteLongToFile(PyImport_GetMagicNumber(), fp, Py_MARSHAL_VERSION);
498 508 #endif
499 509 /* First write a 0 for mtime */
500 510 #if PY_VERSION_HEX < 0x02040000
501 511 PyMarshal_WriteLongToFile(0L, fp);
502 512 #else
503 513 PyMarshal_WriteLongToFile(0L, fp, Py_MARSHAL_VERSION);
504 514 #endif
505 515 #if PY_VERSION_HEX < 0x02040000
506 516 PyMarshal_WriteObjectToFile((PyObject *)co, fp);
507 517 #else
508 518 PyMarshal_WriteObjectToFile((PyObject *)co, fp, Py_MARSHAL_VERSION);
509 519 #endif
510 520 if (ferror(fp)) {
511 521 if (Py_VerboseFlag)
512 522 PySys_WriteStderr("# can't write %s\n", filename.toLatin1().constData());
513 523 /* Don't keep partial file */
514 524 fclose(fp);
515 525 QFile::remove(filename);
516 526 return;
517 527 }
518 528 /* Now write the true mtime */
519 529 fseek(fp, 4L, 0);
520 530 #if PY_VERSION_HEX < 0x02040000
521 531 PyMarshal_WriteLongToFile(mtime, fp);
522 532 #else
523 533 PyMarshal_WriteLongToFile(mtime, fp, Py_MARSHAL_VERSION);
524 534 #endif
525 535 fflush(fp);
526 536 fclose(fp);
527 537 if (Py_VerboseFlag)
528 538 PySys_WriteStderr("# wrote %s\n", filename.toLatin1().constData());
529 539 //#ifdef macintosh
530 540 // PyMac_setfiletype(cpathname, 'Pyth', 'PYC ');
531 541 //#endif
532 542 }
533 543
534 544 /* Given the contents of a .py[co] file in a buffer, unmarshal the data
535 545 and return the code object. Return None if it the magic word doesn't
536 546 match (we do this instead of raising an exception as we fall back
537 547 to .py if available and we don't want to mask other errors).
538 548 Returns a new reference. */
539 549 PyObject *
540 550 PythonQtImport::unmarshalCode(const QString& path, const QByteArray& data, time_t mtime)
541 551 {
542 552 PyObject *code;
543 553 // ugly cast, but Python API is not const safe
544 554 char *buf = (char*) data.constData();
545 555 int size = data.size();
546 556
547 557 if (size <= 9) {
548 558 PySys_WriteStderr("# %s has bad pyc data\n",
549 559 path.toLatin1().constData());
550 560 Py_INCREF(Py_None);
551 561 return Py_None;
552 562 }
553 563
554 564 if (getLong((unsigned char *)buf) != PyImport_GetMagicNumber()) {
555 565 if (Py_VerboseFlag)
556 566 PySys_WriteStderr("# %s has bad magic\n",
557 567 path.toLatin1().constData());
558 568 Py_INCREF(Py_None);
559 569 return Py_None;
560 570 }
561 571
562 if (mtime != 0 && !(getLong((unsigned char *)buf + 4) == mtime)) {
563 if (Py_VerboseFlag)
564 PySys_WriteStderr("# %s has bad mtime\n",
565 path.toLatin1().constData());
566 Py_INCREF(Py_None);
567 return Py_None;
572 if (mtime != 0) {
573 time_t timeDiff = getLong((unsigned char *)buf + 4) - mtime;
574 if (timeDiff<0) { timeDiff = -timeDiff; }
575 if (timeDiff > 1) {
576 if (Py_VerboseFlag)
577 PySys_WriteStderr("# %s has bad mtime\n",
578 path.toLatin1().constData());
579 Py_INCREF(Py_None);
580 return Py_None;
581 }
568 582 }
569 583
570 584 code = PyMarshal_ReadObjectFromString(buf + 8, size - 8);
571 585 if (code == NULL)
572 586 return NULL;
573 587 if (!PyCode_Check(code)) {
574 588 Py_DECREF(code);
575 589 PyErr_Format(PyExc_TypeError,
576 590 "compiled module %.200s is not a code object",
577 591 path.toLatin1().constData());
578 592 return NULL;
579 593 }
580 594 return code;
581 595 }
582 596
583 597
584 598 /* Given a string buffer containing Python source code, compile it
585 599 return and return a code object as a new reference. */
586 600 PyObject *
587 601 PythonQtImport::compileSource(const QString& path, const QByteArray& data)
588 602 {
589 603 PyObject *code;
590 604 QByteArray data1 = data;
591 605 // in qt4, data is null terminated
592 606 // data1.resize(data.size()+1);
593 607 // data1.data()[data.size()-1] = 0;
594 608 code = Py_CompileString(data.data(), path.toLatin1().constData(),
595 609 Py_file_input);
596 610 return code;
597 611 }
598 612
599 613
600 614 /* Return the code object for the module named by 'fullname' from the
601 615 Zip archive as a new reference. */
602 616 PyObject *
603 617 PythonQtImport::getCodeFromData(const QString& path, int isbytecode,int /*ispackage*/, time_t mtime)
604 618 {
605 619 PyObject *code;
606 620
607 621 QByteArray qdata;
608 622 if (!isbytecode) {
609 623 // mlabDebugConst("MLABPython", "reading source " << path);
610 624 bool ok;
611 625 qdata = PythonQt::importInterface()->readSourceFile(path, ok);
612 626 if (!ok) {
613 627 // mlabErrorConst("PythonQtImporter","File could not be verified" << path);
614 628 return NULL;
615 629 }
616 630 if (qdata == " ") {
617 631 qdata.clear();
618 632 }
619 633 } else {
620 634 qdata = PythonQt::importInterface()->readFileAsBytes(path);
621 635 }
622 636
623 637 if (isbytecode) {
624 638 // mlabDebugConst("MLABPython", "reading bytecode " << path);
625 639 code = unmarshalCode(path, qdata, mtime);
626 640 }
627 641 else {
628 642 // mlabDebugConst("MLABPython", "compiling source " << path);
629 643 code = compileSource(path, qdata);
630 644 if (code) {
631 645 // save a pyc file if possible
632 646 QDateTime time;
633 647 time = PythonQt::importInterface()->lastModifiedDate(path);
634 648 writeCompiledModule((PyCodeObject*)code, path+"c", time.toTime_t());
635 649 }
636 650 }
637 651 return code;
638 652 }
639 653
640 654 time_t
641 655 PythonQtImport::getMTimeOfSource(const QString& path)
642 656 {
643 657 time_t mtime = 0;
644 658 QString path2 = path;
645 659 path2.truncate(path.length()-1);
646 660
647 661 if (PythonQt::importInterface()->exists(path2)) {
648 mtime = PythonQt::importInterface()->lastModifiedDate(path2).toTime_t();
662 QDateTime t = PythonQt::importInterface()->lastModifiedDate(path2);
663 if (t.isValid()) {
664 mtime = t.toTime_t();
665 }
649 666 }
650 667
651 668 return mtime;
652 669 }
653 670
654 671 /* Get the code object associated with the module specified by
655 672 'fullname'. */
656 673 PyObject *
657 674 PythonQtImport::getModuleCode(PythonQtImporter *self, const char* fullname, QString& modpath)
658 675 {
659 676 QString subname;
660 677 struct st_mlab_searchorder *zso;
661 678
662 679 subname = getSubName(fullname);
663 680 QString path = *self->_path + "/" + subname;
664 681
665 682 QString test;
666 683 for (zso = mlab_searchorder; *zso->suffix; zso++) {
667 684 PyObject *code = NULL;
668 685 test = path + zso->suffix;
669 686
670 687 if (Py_VerboseFlag > 1)
671 688 PySys_WriteStderr("# trying %s\n",
672 689 test.toLatin1().constData());
673 690 if (PythonQt::importInterface()->exists(test)) {
674 691 time_t mtime = 0;
675 692 int ispackage = zso->type & IS_PACKAGE;
676 693 int isbytecode = zso->type & IS_BYTECODE;
677 694
678 if (isbytecode) {
695 // if ignoreUpdatedPythonSourceFiles() returns true, then mtime stays 0
696 // and unmarshalCode() in getCodeFromData() will always read an existing *.pyc file,
697 // even if a newer *.py file exists. This is a release optimization where
698 // typically only *.pyc files are delivered without *.py files and reading file
699 // modification time is slow.
700 if (isbytecode && !PythonQt::importInterface()->ignoreUpdatedPythonSourceFiles()) {
679 701 mtime = getMTimeOfSource(test);
680 702 }
681 703 code = getCodeFromData(test, isbytecode, ispackage, mtime);
682 704 if (code == Py_None) {
683 705 Py_DECREF(code);
684 706 continue;
685 707 }
686 708 if (code != NULL) {
687 709 modpath = test;
688 710 }
689 711 return code;
690 712 }
691 713 }
692 714 PyErr_Format(PythonQtImportError, "can't find module '%.200s'", fullname);
693 715
694 716 return NULL;
695 717 }
696 718
697 719 QString PythonQtImport::replaceExtension(const QString& str, const QString& ext)
698 720 {
699 721 QString r;
700 722 int i = str.lastIndexOf('.');
701 723 if (i!=-1) {
702 724 r = str.mid(0,i) + "." + ext;
703 725 } else {
704 726 r = str + "." + ext;
705 727 }
706 728 return r;
707 729 }
708 730
709 731 PyObject* PythonQtImport::getCodeFromPyc(const QString& file)
710 732 {
711 733 PyObject* code;
712 734 const static QString pycStr("pyc");
713 735 QString pyc = replaceExtension(file, pycStr);
714 736 if (PythonQt::importInterface()->exists(pyc)) {
715 737 time_t mtime = 0;
716 mtime = getMTimeOfSource(pyc);
738 // if ignoreUpdatedPythonSourceFiles() returns true, then mtime stays 0
739 // and unmarshalCode() in getCodeFromData() will always read an existing *.pyc file,
740 // even if a newer *.py file exists. This is a release optimization where
741 // typically only *.pyc files are delivered without *.py files and reading file
742 // modification time is slow.
743 if (!PythonQt::importInterface()->ignoreUpdatedPythonSourceFiles()) {
744 mtime = getMTimeOfSource(pyc);
745 }
717 746 code = getCodeFromData(pyc, true, false, mtime);
718 747 if (code != Py_None && code != NULL) {
719 748 return code;
720 749 }
721 750 if (code) {
722 751 Py_DECREF(code);
723 752 }
724 753 }
725 754 code = getCodeFromData(file,false,false,0);
726 755 return code;
727 756 }
728 757
729 758 /* Module init */
730 759
731 760 PyDoc_STRVAR(mlabimport_doc,
732 761 "Imports python files into PythonQt, completely replaces internal python import");
733 762
734 763 void PythonQtImport::init()
735 764 {
736 765 static bool first = true;
737 766 if (!first) {
738 767 return;
739 768 }
740 769 first = false;
741 770
742 771 PyObject *mod;
743 772
744 773 if (PyType_Ready(&PythonQtImporter_Type) < 0)
745 774 return;
746 775
747 776 /* Correct directory separator */
748 777 mlab_searchorder[0].suffix[0] = SEP;
749 778 mlab_searchorder[1].suffix[0] = SEP;
750 779 mlab_searchorder[2].suffix[0] = SEP;
751 780 if (Py_OptimizeFlag) {
752 781 /* Reverse *.pyc and *.pyo */
753 782 struct st_mlab_searchorder tmp;
754 783 tmp = mlab_searchorder[0];
755 784 mlab_searchorder[0] = mlab_searchorder[1];
756 785 mlab_searchorder[1] = tmp;
757 786 tmp = mlab_searchorder[3];
758 787 mlab_searchorder[3] = mlab_searchorder[4];
759 788 mlab_searchorder[4] = tmp;
760 789 }
761 790
762 791 mod = Py_InitModule4("PythonQtImport", NULL, mlabimport_doc,
763 792 NULL, PYTHON_API_VERSION);
764 793
765 794 PythonQtImportError = PyErr_NewException("PythonQtImport.PythonQtImportError",
766 795 PyExc_ImportError, NULL);
767 796 if (PythonQtImportError == NULL)
768 797 return;
769 798
770 799 Py_INCREF(PythonQtImportError);
771 800 if (PyModule_AddObject(mod, "PythonQtImportError",
772 801 PythonQtImportError) < 0)
773 802 return;
774 803
775 804 Py_INCREF(&PythonQtImporter_Type);
776 805 if (PyModule_AddObject(mod, "PythonQtImporter",
777 806 (PyObject *)&PythonQtImporter_Type) < 0)
778 807 return;
779 808
780 809 // set our importer into the path_hooks to handle all path on sys.path
781 810 PyObject* classobj = PyDict_GetItemString(PyModule_GetDict(mod), "PythonQtImporter");
782 811 PyObject* path_hooks = PySys_GetObject("path_hooks");
783 812 PyList_Append(path_hooks, classobj);
784 813
785 814 #ifndef WIN32
786 815 // reload the encodings module, because it might fail to custom import requirements (e.g. encryption).
787 816 PyObject* modules = PyImport_GetModuleDict();
788 817 PyObject* encodingsModule = PyDict_GetItemString(modules, "encodings");
789 818 if (encodingsModule != NULL) {
790 819 PyImport_ReloadModule(encodingsModule);
791 820 }
792 821 #endif
793 822 }
@@ -1,726 +1,766
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtInstanceWrapper.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtInstanceWrapper.h"
43 43 #include <QObject>
44 44 #include "PythonQt.h"
45 45 #include "PythonQtSlot.h"
46 46 #include "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 PyObject *PythonQtInstanceWrapper_inherits(PythonQtInstanceWrapper* obj, PyObject *args)
292 {
293 char *name = NULL;
294 if (!PyArg_ParseTuple(args, "s:PythonQtInstanceWrapper.inherits",&name)) {
295 return NULL;
296 }
297 return PythonQtConv::GetPyBool(obj->classInfo()->inherits(name));
298 }
299
291 300 static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* obj)
292 301 {
293 302 return PythonQt::self()->helpCalled(obj->classInfo());
294 303 }
295 304
296 static PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self)
305 PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self)
297 306 {
298 307 PythonQtInstanceWrapper_deleteObject(self, true);
299 308 Py_INCREF(Py_None);
300 309 return Py_None;
301 310 }
302 311
303 312
304 313 static PyMethodDef PythonQtInstanceWrapper_methods[] = {
305 314 {"className", (PyCFunction)PythonQtInstanceWrapper_classname, METH_NOARGS,
306 315 "Return the classname of the object"
307 316 },
317 {"inherits", (PyCFunction)PythonQtInstanceWrapper_inherits, METH_VARARGS,
318 "Returns if the class inherits or is of given type name"
319 },
308 320 {"help", (PyCFunction)PythonQtInstanceWrapper_help, METH_NOARGS,
309 321 "Shows the help of available methods for this class"
310 322 },
311 323 {"delete", (PyCFunction)PythonQtInstanceWrapper_delete, METH_NOARGS,
312 324 "Deletes the C++ object (at your own risk, my friend!)"
313 325 },
314 326 {NULL, NULL, 0, NULL} /* Sentinel */
315 327 };
316 328
317 329
318 330 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
319 331 {
320 332 const char *attributeName;
321 333 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
322 334
323 335 if ((attributeName = PyString_AsString(name)) == NULL) {
324 336 return NULL;
325 337 }
326 338
327 339 if (qstrcmp(attributeName, "__dict__")==0) {
328 340 PyObject* dict = PyBaseObject_Type.tp_getattro(obj, name);
329 341 dict = PyDict_Copy(dict);
330 342
331 343 if (wrapper->_obj) {
332 344 // only the properties are missing, the rest is already available from
333 345 // PythonQtClassWrapper...
334 346 QStringList l = wrapper->classInfo()->propertyList();
335 347 foreach (QString name, l) {
336 348 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
337 349 if (o) {
338 350 PyDict_SetItemString(dict, name.toLatin1().data(), o);
339 351 Py_DECREF(o);
340 352 } else {
341 353 std::cerr << "PythonQtInstanceWrapper: something is wrong, could not get attribute " << name.toLatin1().data();
342 354 }
343 355 }
344 356
345 357 QList<QByteArray> dynamicProps = wrapper->_obj->dynamicPropertyNames();
346 358 foreach (QByteArray name, dynamicProps) {
347 359 PyObject* o = PyObject_GetAttrString(obj, name.data());
348 360 if (o) {
349 361 PyDict_SetItemString(dict, name.data(), o);
350 362 Py_DECREF(o);
351 363 } else {
352 364 std::cerr << "PythonQtInstanceWrapper: dynamic property could not be read " << name.data();
353 365 }
354 366 }
355 367 }
356 368 // Note: we do not put children into the dict, is would look confusing?!
357 369 return dict;
358 370 }
359 371
360 372 // first look in super, to return derived methods from base object first
361 373 PyObject* superAttr = PyBaseObject_Type.tp_getattro(obj, name);
362 374 if (superAttr) {
363 375 return superAttr;
364 376 }
365 377 PyErr_Clear();
366 378
367 379 // mlabDebugConst("Python","get " << attributeName);
368 380
369 381 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
370 382 switch (member._type) {
371 383 case PythonQtMemberInfo::Property:
372 384 if (wrapper->_obj) {
373 385 if (member._property.userType() != QVariant::Invalid) {
374 return PythonQtConv::QVariantToPyObject(member._property.read(wrapper->_obj));
386
387 PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB();
388 if (profilingCB) {
389 QString methodName = "getProperty(";
390 methodName += attributeName;
391 methodName += ")";
392 profilingCB(PythonQt::Enter, wrapper->_obj->metaObject()->className(), methodName.toLatin1());
393 }
394
395 PyObject* value = PythonQtConv::QVariantToPyObject(member._property.read(wrapper->_obj));
396
397 if (profilingCB) {
398 profilingCB(PythonQt::Leave, NULL, NULL);
399 }
400
401 return value;
402
375 403 } else {
376 404 Py_INCREF(Py_None);
377 405 return Py_None;
378 406 }
379 407 } else {
380 408 QString error = QString("Trying to read property '") + attributeName + "' from a destroyed " + wrapper->classInfo()->className() + " object";
381 409 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
382 410 return NULL;
383 411 }
384 412 break;
385 413 case PythonQtMemberInfo::Slot:
386 414 return PythonQtSlotFunction_New(member._slot, obj, NULL);
387 415 break;
388 416 case PythonQtMemberInfo::EnumValue:
389 417 {
390 418 PyObject* enumValue = member._enumValue;
391 419 Py_INCREF(enumValue);
392 420 return enumValue;
393 421 }
394 422 break;
395 423 case PythonQtMemberInfo::EnumWrapper:
396 424 {
397 425 PyObject* enumWrapper = member._enumWrapper;
398 426 Py_INCREF(enumWrapper);
399 427 return enumWrapper;
400 428 }
401 429 break;
402 430 case PythonQtMemberInfo::NotFound:
403 431 {
404 432 static const QByteArray getterString("py_get_");
405 433 // check for a getter slot
406 434 PythonQtMemberInfo member = wrapper->classInfo()->member(getterString + attributeName);
407 435 if (member._type == PythonQtMemberInfo::Slot) {
408 436 return PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, member._slot, NULL, NULL, wrapper->_wrappedPtr);
409 437 }
410 438
411 439 // handle dynamic properties
412 440 if (wrapper->_obj) {
413 441 QVariant v = wrapper->_obj->property(attributeName);
414 442 if (v.isValid()) {
415 443 return PythonQtConv::QVariantToPyObject(v);
416 444 }
417 445 }
418 446 }
419 447 break;
420 448 default:
421 449 // is an invalid type, go on
422 450 break;
423 451 }
424 452
425 453 // look for the internal methods (className(), help())
426 454 PyObject* internalMethod = Py_FindMethod( PythonQtInstanceWrapper_methods, obj, (char*)attributeName);
427 455 if (internalMethod) {
428 456 return internalMethod;
429 457 }
430 458 PyErr_Clear();
431 459
432 460 if (wrapper->_obj) {
433 461 // look for a child
434 462 QObjectList children = wrapper->_obj->children();
435 463 for (int i = 0; i < children.count(); i++) {
436 464 QObject *child = children.at(i);
437 465 if (child->objectName() == attributeName) {
438 466 return PythonQt::priv()->wrapQObject(child);
439 467 }
440 468 }
441 469 }
442 470
443 471 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
444 472 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
445 473 return NULL;
446 474 }
447 475
448 476 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
449 477 {
450 478 QString error;
451 479 const char *attributeName;
452 480 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
453 481
454 482 if ((attributeName = PyString_AsString(name)) == NULL)
455 483 return -1;
456 484
457 485 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
458 486 if (member._type == PythonQtMemberInfo::Property) {
459 487
460 488 if (!wrapper->_obj) {
461 489 error = QString("Trying to set property '") + attributeName + "' on a destroyed " + wrapper->classInfo()->className() + " object";
462 490 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
463 491 return -1;
464 492 }
465 493
466 494 QMetaProperty prop = member._property;
467 495 if (prop.isWritable()) {
468 496 QVariant v;
469 497 if (prop.isEnumType()) {
470 498 // this will give us either a string or an int, everything else will probably be an error
471 499 v = PythonQtConv::PyObjToQVariant(value);
472 500 } else {
473 501 int t = prop.userType();
474 502 v = PythonQtConv::PyObjToQVariant(value, t);
475 503 }
476 504 bool success = false;
477 505 if (v.isValid()) {
506 PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB();
507 if (profilingCB) {
508 QString methodName = "setProperty(";
509 methodName += attributeName;
510 methodName += ")";
511 profilingCB(PythonQt::Enter, wrapper->_obj->metaObject()->className(), methodName.toLatin1());
512 }
513
478 514 success = prop.write(wrapper->_obj, v);
515
516 if (profilingCB) {
517 profilingCB(PythonQt::Leave, NULL, NULL);
518 }
479 519 }
480 520 if (success) {
481 521 return 0;
482 522 } else {
483 523 error = QString("Property '") + attributeName + "' of type '" +
484 524 prop.typeName() + "' does not accept an object of type "
485 525 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
486 526 }
487 527 } else {
488 528 error = QString("Property '") + attributeName + "' of " + obj->ob_type->tp_name + " object is not writable";
489 529 }
490 530 } else if (member._type == PythonQtMemberInfo::Slot) {
491 531 error = QString("Slot '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
492 532 } else if (member._type == PythonQtMemberInfo::EnumValue) {
493 533 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
494 534 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
495 535 error = QString("Enum '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
496 536 } else if (member._type == PythonQtMemberInfo::NotFound) {
497 537 // check for a setter slot
498 538 static const QByteArray setterString("py_set_");
499 539 PythonQtMemberInfo setter = wrapper->classInfo()->member(setterString + attributeName);
500 540 if (setter._type == PythonQtMemberInfo::Slot) {
501 541 // call the setter and ignore the result value
502 542 void* result;
503 543 PyObject* args = PyTuple_New(1);
504 544 Py_INCREF(value);
505 545 PyTuple_SET_ITEM(args, 0, value);
506 546 PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, setter._slot, args, NULL, wrapper->_wrappedPtr, &result);
507 547 Py_DECREF(args);
508 548 return 0;
509 549 }
510 550
511 551 // handle dynamic properties
512 552 if (wrapper->_obj) {
513 553 QVariant prop = wrapper->_obj->property(attributeName);
514 554 if (prop.isValid()) {
515 555 QVariant v = PythonQtConv::PyObjToQVariant(value);
516 556 if (v.isValid()) {
517 557 wrapper->_obj->setProperty(attributeName, v);
518 558 return 0;
519 559 } else {
520 560 error = QString("Dynamic property '") + attributeName + "' does not accept an object of type "
521 561 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
522 562 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
523 563 return -1;
524 564 }
525 565 }
526 566 }
527 567
528 568 // if we are a derived python class, we allow setting attributes.
529 569 // if we are a direct CPP wrapper, we do NOT allow it, since
530 570 // it would be confusing to allow it because a wrapper will go away when it is not seen by python anymore
531 571 // and when it is recreated from a CPP pointer the attributes are gone...
532 572 if (obj->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
533 573 return PyBaseObject_Type.tp_setattro(obj,name,value);
534 574 } else {
535 575 error = QString("'") + attributeName + "' does not exist on " + obj->ob_type->tp_name + " and creating new attributes on C++ objects is not allowed";
536 576 }
537 577 }
538 578
539 579 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
540 580 return -1;
541 581 }
542 582
543 583 static QString getStringFromObject(PythonQtInstanceWrapper* wrapper) {
544 584 QString result;
545 585 if (wrapper->_wrappedPtr) {
546 586 // first try some manually string conversions for some variants
547 587 int metaid = wrapper->classInfo()->metaTypeId();
548 588 result = PythonQtConv::CPPObjectToString(metaid, wrapper->_wrappedPtr);
549 589 if (!result.isEmpty()) {
550 590 return result;
551 591 }
552 592 }
553 593 // next, try to call py_toString
554 594 PythonQtMemberInfo info = wrapper->classInfo()->member("py_toString");
555 595 if (info._type == PythonQtMemberInfo::Slot) {
556 596 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, NULL, NULL, wrapper->_wrappedPtr);
557 597 if (resultObj) {
558 598 // TODO this is one conversion too much, would be nicer to call the slot directly...
559 599 result = PythonQtConv::PyObjGetString(resultObj);
560 600 Py_DECREF(resultObj);
561 601 }
562 602 }
563 603 return result;
564 604 }
565 605
566 606 static PyObject * PythonQtInstanceWrapper_str(PyObject * obj)
567 607 {
568 608 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
569 609
570 610 // QByteArray should be directly returned as a str
571 611 if (wrapper->classInfo()->metaTypeId()==QVariant::ByteArray) {
572 612 QByteArray* b = (QByteArray*) wrapper->_wrappedPtr;
573 613 if (b->data()) {
574 614 return PyString_FromStringAndSize(b->data(), b->size());
575 615 } else {
576 616 return PyString_FromString("");
577 617 }
578 618 }
579 619
580 620 const char* typeName = obj->ob_type->tp_name;
581 621 QObject *qobj = wrapper->_obj;
582 622 QString str = getStringFromObject(wrapper);
583 623 if (!str.isEmpty()) {
584 624 return PyString_FromFormat("%s", str.toLatin1().constData());
585 625 }
586 626 if (wrapper->_wrappedPtr) {
587 627 if (wrapper->_obj) {
588 628 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
589 629 } else {
590 630 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
591 631 }
592 632 } else {
593 633 return PyString_FromFormat("%s (QObject %p)", typeName, qobj);
594 634 }
595 635 }
596 636
597 637 static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj)
598 638 {
599 639 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
600 640 const char* typeName = obj->ob_type->tp_name;
601 641
602 642 QObject *qobj = wrapper->_obj;
603 643 QString str = getStringFromObject(wrapper);
604 644 if (!str.isEmpty()) {
605 645 if (str.startsWith(typeName)) {
606 646 return PyString_FromFormat("%s", str.toLatin1().constData());
607 647 } else {
608 return PyString_FromFormat("%s(%s, %p)", typeName, str.toLatin1().constData(), wrapper->_wrappedPtr);
648 return PyString_FromFormat("%s (%s, at: %p)", typeName, str.toLatin1().constData(), wrapper->_wrappedPtr ? wrapper->_wrappedPtr : qobj);
609 649 }
610 650 }
611 651 if (wrapper->_wrappedPtr) {
612 652 if (wrapper->_obj) {
613 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
653 return PyString_FromFormat("%s (C++ object at: %p wrapped by %s at: %p)", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
614 654 } else {
615 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
655 return PyString_FromFormat("%s (C++ object at: %p)", typeName, wrapper->_wrappedPtr);
616 656 }
617 657 } else {
618 return PyString_FromFormat("%s (%s %p)", typeName, wrapper->classInfo()->className(), qobj);
658 return PyString_FromFormat("%s (%s at: %p)", typeName, wrapper->classInfo()->className(), qobj);
619 659 }
620 660 }
621 661
622 662 static int PythonQtInstanceWrapper_builtin_nonzero(PyObject *obj)
623 663 {
624 664 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
625 665 return (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
626 666 }
627 667
628 668
629 669 static long PythonQtInstanceWrapper_hash(PythonQtInstanceWrapper *obj)
630 670 {
631 671 if (obj->_wrappedPtr != NULL) {
632 672 return reinterpret_cast<long>(obj->_wrappedPtr);
633 673 } else {
634 674 QObject* qobj = obj->_obj; // get pointer from QPointer wrapper
635 675 return reinterpret_cast<long>(qobj);
636 676 }
637 677 }
638 678
639 679
640 680
641 681 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
642 682 static PyNumberMethods PythonQtInstanceWrapper_as_number = {
643 683 0, /* nb_add */
644 684 0, /* nb_subtract */
645 685 0, /* nb_multiply */
646 686 0, /* nb_divide */
647 687 0, /* nb_remainder */
648 688 0, /* nb_divmod */
649 689 0, /* nb_power */
650 690 0, /* nb_negative */
651 691 0, /* nb_positive */
652 692 0, /* nb_absolute */
653 693 PythonQtInstanceWrapper_builtin_nonzero, /* nb_nonzero */
654 694 0, /* nb_invert */
655 695 0, /* nb_lshift */
656 696 0, /* nb_rshift */
657 697 0, /* nb_and */
658 698 0, /* nb_xor */
659 699 0, /* nb_or */
660 700 0, /* nb_coerce */
661 701 0, /* nb_int */
662 702 0, /* nb_long */
663 703 0, /* nb_float */
664 704 0, /* nb_oct */
665 705 0, /* nb_hex */
666 706 0, /* nb_inplace_add */
667 707 0, /* nb_inplace_subtract */
668 708 0, /* nb_inplace_multiply */
669 709 0, /* nb_inplace_divide */
670 710 0, /* nb_inplace_remainder */
671 711 0, /* nb_inplace_power */
672 712 0, /* nb_inplace_lshift */
673 713 0, /* nb_inplace_rshift */
674 714 0, /* nb_inplace_and */
675 715 0, /* nb_inplace_xor */
676 716 0, /* nb_inplace_or */
677 717 0, /* nb_floor_divide */
678 718 0, /* nb_true_divide */
679 719 0, /* nb_inplace_floor_divide */
680 720 0, /* nb_inplace_true_divide */
681 721 };
682 722
683 723 PyTypeObject PythonQtInstanceWrapper_Type = {
684 724 PyObject_HEAD_INIT(&PythonQtClassWrapper_Type)
685 725 0, /*ob_size*/
686 726 "PythonQt.PythonQtInstanceWrapper", /*tp_name*/
687 727 sizeof(PythonQtInstanceWrapper), /*tp_basicsize*/
688 728 0, /*tp_itemsize*/
689 729 (destructor)PythonQtInstanceWrapper_dealloc, /*tp_dealloc*/
690 730 0, /*tp_print*/
691 731 0, /*tp_getattr*/
692 732 0, /*tp_setattr*/
693 733 0, /*tp_compare*/
694 734 PythonQtInstanceWrapper_repr, /*tp_repr*/
695 735 &PythonQtInstanceWrapper_as_number, /*tp_as_number*/
696 736 0, /*tp_as_sequence*/
697 737 0, /*tp_as_mapping*/
698 738 (hashfunc)PythonQtInstanceWrapper_hash, /*tp_hash */
699 739 0, /*tp_call*/
700 740 PythonQtInstanceWrapper_str, /*tp_str*/
701 741 PythonQtInstanceWrapper_getattro, /*tp_getattro*/
702 742 PythonQtInstanceWrapper_setattro, /*tp_setattro*/
703 743 0, /*tp_as_buffer*/
704 744 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
705 745 "PythonQtInstanceWrapper object", /* tp_doc */
706 746 0, /* tp_traverse */
707 747 0, /* tp_clear */
708 748 (richcmpfunc)PythonQtInstanceWrapper_richcompare, /* tp_richcompare */
709 749 0, /* tp_weaklistoffset */
710 750 0, /* tp_iter */
711 751 0, /* tp_iternext */
712 752 0, /* tp_methods */
713 753 0, /* tp_members */
714 754 0, /* tp_getset */
715 755 0, /* tp_base */
716 756 0, /* tp_dict */
717 757 0, /* tp_descr_get */
718 758 0, /* tp_descr_set */
719 759 0, /* tp_dictoffset */
720 760 (initproc)PythonQtInstanceWrapper_init, /* tp_init */
721 761 0, /* tp_alloc */
722 762 PythonQtInstanceWrapper_new, /* tp_new */
723 763 };
724 764
725 765 //-------------------------------------------------------
726 766
@@ -1,98 +1,100
1 1 #ifndef _PYTHONQTINSTANCEWRAPPER_H
2 2 #define _PYTHONQTINSTANCEWRAPPER_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtInstanceWrapper.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include <Python.h>
46 46
47 47 #include "PythonQtSystem.h"
48 48 #include <QPointer>
49 49
50 50 #include "structmember.h"
51 51 #include "methodobject.h"
52 52 #include "compile.h"
53 53 #include "eval.h"
54 54
55 55 class PythonQtClassInfo;
56 56 class QObject;
57 57
58 58 extern PYTHONQT_EXPORT PyTypeObject PythonQtInstanceWrapper_Type;
59 59
60 60 //---------------------------------------------------------------
61 61 //! a Python wrapper object for Qt objects and C++ objects (that are themselves wrapped by wrapper QObjects)
62 62 typedef struct PythonQtInstanceWrapperStruct {
63 63 PyObject_HEAD
64 64
65 65 //! the class information, this is set even if the _obj or _wrappedPtr is NULL to support typed NULL pointers
66 66 PythonQtClassInfo* classInfo();
67 67
68 68 //! set the QObject pointer
69 69 void setQObject(QObject* object) {
70 70 _obj = object;
71 71 _objPointerCopy = object;
72 72 }
73 73
74 74 //! pointer to the wrapped Qt object or if _wrappedPtr is set, the Qt object that wraps the C++ Ptr
75 75 QPointer<QObject> _obj;
76 76 //! a copy of the _obj pointer, which is required because the wrapper needs to
77 77 //! deregister itself via the _obj pointer, even when the QPointer<QObject> object was destroyed
78 78 void* _objPointerCopy;
79 79
80 80 //! optional C++ object Ptr that is wrapped by the above _obj
81 81 void* _wrappedPtr;
82 82
83 83 // TODO xxx: put booleans into int that holds flags
84 84
85 85 //! flag that stores if the object is owned by pythonQt
86 86 bool _ownedByPythonQt;
87 87
88 88 //! stores that the owned object should be destroyed using QMetaType::destroy()
89 89 bool _useQMetaTypeDestroy;
90 90
91 91 //! stores if the object is a shell instance
92 92 bool _isShellInstance;
93
93
94 94 } PythonQtInstanceWrapper;
95 95
96 96 int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds);
97 97
98 #endif No newline at end of file
98 PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self);
99
100 #endif
@@ -1,353 +1,350
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtMethodInfo.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtMethodInfo.h"
43 43 #include "PythonQtClassInfo.h"
44 44 #include <iostream>
45 45
46 46 QHash<QByteArray, PythonQtMethodInfo*> PythonQtMethodInfo::_cachedSignatures;
47 47 QHash<QByteArray, QByteArray> PythonQtMethodInfo::_parameterNameAliases;
48 48
49 49 PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo)
50 50 {
51 51 #ifdef PYTHONQT_DEBUG
52 52 QByteArray sig(meta.signature());
53 53 sig = sig.mid(sig.indexOf('('));
54 54 QByteArray fullSig = QByteArray(meta.typeName()) + " " + sig;
55 55 std::cout << "caching " << fullSig.data() << std::endl;
56 56 #endif
57 57
58 58 ParameterInfo type;
59 59 fillParameterInfo(type, QByteArray(meta.typeName()), classInfo);
60 60 _parameters.append(type);
61 61 QList<QByteArray> names = meta.parameterTypes();
62 62 foreach (const QByteArray& name, names) {
63 63 fillParameterInfo(type, name, classInfo);
64 64 _parameters.append(type);
65 65 }
66 66 }
67 67
68 68 PythonQtMethodInfo::PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args)
69 69 {
70 70 ParameterInfo type;
71 71 fillParameterInfo(type, typeName, NULL);
72 72 _parameters.append(type);
73 73 foreach (const QByteArray& name, args) {
74 74 fillParameterInfo(type, name, NULL);
75 75 _parameters.append(type);
76 76 }
77 77 }
78 78
79 79 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo)
80 80 {
81 81 QByteArray sig(signal.signature());
82 82 sig = sig.mid(sig.indexOf('('));
83 83 QByteArray fullSig = QByteArray(signal.typeName()) + " " + sig;
84 84 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
85 85 if (!result) {
86 86 result = new PythonQtMethodInfo(signal, classInfo);
87 87 _cachedSignatures.insert(fullSig, result);
88 88 }
89 89 return result;
90 90 }
91 91
92 92 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(int numArgs, const char** args)
93 93 {
94 94 QByteArray typeName = args[0];
95 95 QList<QByteArray> arguments;
96 96 QByteArray fullSig = typeName;
97 97 fullSig += "(";
98 98 for (int i =1;i<numArgs; i++) {
99 99 if (i>1) {
100 100 fullSig += ",";
101 101 }
102 102 arguments << QByteArray(args[i]);
103 103 }
104 104 fullSig += ")";
105 105 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
106 106 if (!result) {
107 107 result = new PythonQtMethodInfo(typeName, arguments);
108 108 _cachedSignatures.insert(fullSig, result);
109 109 }
110 110 return result;
111 111 }
112 112
113 113 void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo)
114 114 {
115 115 QByteArray name = orgName;
116 116
117 117 type.enumWrapper = NULL;
118 118
119 119 int len = name.length();
120 120 if (len>0) {
121 121 if (strncmp(name.constData(), "const ", 6)==0) {
122 122 name = name.mid(6);
123 123 len -= 6;
124 124 type.isConst = true;
125 125 } else {
126 126 type.isConst = false;
127 127 }
128 128 char pointerCount = 0;
129 129 bool hadReference = false;
130 130 // remove * and & from the end of the string, handle & and * the same way
131 131 while (name.at(len-1) == '*') {
132 132 len--;
133 133 pointerCount++;
134 134 }
135 135 while (name.at(len-1) == '&') {
136 136 len--;
137 137 hadReference = true;
138 138 }
139 139 if (len!=name.length()) {
140 140 name = name.left(len);
141 141 }
142 142 type.pointerCount = pointerCount;
143 143
144 144 QByteArray alias = _parameterNameAliases.value(name);
145 145 if (!alias.isEmpty()) {
146 146 name = alias;
147 147 }
148 148
149 149 type.typeId = nameToType(name);
150 150 if ((type.pointerCount == 0) && type.typeId == Unknown) {
151 151 type.typeId = QMetaType::type(name.constData());
152 152 if (type.typeId == QMetaType::Void) {
153 153 type.typeId = Unknown;
154 154 }
155 155 }
156 156 type.name = name;
157 157
158 158 if (type.typeId == PythonQtMethodInfo::Unknown || type.typeId >= QMetaType::User) {
159 159 bool isLocalEnum;
160 160 // TODOXXX: make use of this flag!
161 161 type.enumWrapper = PythonQtClassInfo::findEnumWrapper(type.name, classInfo, &isLocalEnum);
162 162 }
163 163 } else {
164 164 type.typeId = QMetaType::Void;
165 165 type.pointerCount = 0;
166 166 type.isConst = false;
167 167 }
168 168 }
169 169
170 170 int PythonQtMethodInfo::nameToType(const char* name)
171 171 {
172 172 if (_parameterTypeDict.isEmpty()) {
173 173 // we could also use QMetaType::nameToType, but that does a string compare search
174 174 // and does not support QVariant
175 175
176 176 // QMetaType names
177 177 _parameterTypeDict.insert("long", QMetaType::Long);
178 178 _parameterTypeDict.insert("int", QMetaType::Int);
179 179 _parameterTypeDict.insert("short", QMetaType::Short);
180 180 _parameterTypeDict.insert("char", QMetaType::Char);
181 181 _parameterTypeDict.insert("ulong", QMetaType::ULong);
182 182 _parameterTypeDict.insert("unsigned long", QMetaType::ULong);
183 183 _parameterTypeDict.insert("uint", QMetaType::UInt);
184 184 _parameterTypeDict.insert("unsigned int", QMetaType::UInt);
185 185 _parameterTypeDict.insert("ushort", QMetaType::UShort);
186 186 _parameterTypeDict.insert("unsigned short", QMetaType::UShort);
187 187 _parameterTypeDict.insert("uchar", QMetaType::UChar);
188 188 _parameterTypeDict.insert("unsigned char", QMetaType::UChar);
189 189 _parameterTypeDict.insert("bool", QMetaType::Bool);
190 190 _parameterTypeDict.insert("float", QMetaType::Float);
191 191 _parameterTypeDict.insert("double", QMetaType::Double);
192 192 _parameterTypeDict.insert("qreal", QMetaType::Double);
193 193 _parameterTypeDict.insert("QChar", QMetaType::QChar);
194 194 _parameterTypeDict.insert("QByteArray", QMetaType::QByteArray);
195 _parameterTypeDict.insert("Q3CString", QMetaType::QByteArray);
196 195 _parameterTypeDict.insert("QString", QMetaType::QString);
197 196 _parameterTypeDict.insert("", QMetaType::Void);
198 197 _parameterTypeDict.insert("void", QMetaType::Void);
199 198 // QVariant names
200 199 _parameterTypeDict.insert("Q_LLONG", QMetaType::LongLong);
201 200 _parameterTypeDict.insert("Q_ULLONG", QMetaType::ULongLong);
202 201 _parameterTypeDict.insert("qlonglong", QMetaType::LongLong);
203 202 _parameterTypeDict.insert("qulonglong", QMetaType::ULongLong);
204 203 _parameterTypeDict.insert("qint64", QMetaType::LongLong);
205 204 _parameterTypeDict.insert("quint64", QMetaType::ULongLong);
206 _parameterTypeDict.insert("QIconSet", QMetaType::QIcon);
207 205 _parameterTypeDict.insert("QVariantMap", QMetaType::QVariantMap);
208 206 _parameterTypeDict.insert("QVariantList", QMetaType::QVariantList);
209 207 _parameterTypeDict.insert("QMap<QString,QVariant>", QMetaType::QVariantMap);
210 208 _parameterTypeDict.insert("QList<QVariant>", QMetaType::QVariantList);
211 209 _parameterTypeDict.insert("QStringList", QMetaType::QStringList);
212 210 _parameterTypeDict.insert("QBitArray", QMetaType::QBitArray);
213 211 _parameterTypeDict.insert("QDate", QMetaType::QDate);
214 212 _parameterTypeDict.insert("QTime", QMetaType::QTime);
215 213 _parameterTypeDict.insert("QDateTime", QMetaType::QDateTime);
216 214 _parameterTypeDict.insert("QUrl", QMetaType::QUrl);
217 215 _parameterTypeDict.insert("QLocale", QMetaType::QLocale);
218 216 _parameterTypeDict.insert("QRect", QMetaType::QRect);
219 _parameterTypeDict.insert("QRectf", QMetaType::QRectF);
217 _parameterTypeDict.insert("QRectF", QMetaType::QRectF);
220 218 _parameterTypeDict.insert("QSize", QMetaType::QSize);
221 _parameterTypeDict.insert("QSizef", QMetaType::QSizeF);
219 _parameterTypeDict.insert("QSizeF", QMetaType::QSizeF);
222 220 _parameterTypeDict.insert("QLine", QMetaType::QLine);
223 _parameterTypeDict.insert("QLinef", QMetaType::QLineF);
221 _parameterTypeDict.insert("QLineF", QMetaType::QLineF);
224 222 _parameterTypeDict.insert("QPoint", QMetaType::QPoint);
225 _parameterTypeDict.insert("QPointf", QMetaType::QPointF);
223 _parameterTypeDict.insert("QPointF", QMetaType::QPointF);
226 224 _parameterTypeDict.insert("QRegExp", QMetaType::QRegExp);
227 // _parameterTypeDict.insert("QColorGroup", QMetaType::QColorGroup);
228 225 _parameterTypeDict.insert("QFont", QMetaType::QFont);
229 226 _parameterTypeDict.insert("QPixmap", QMetaType::QPixmap);
230 227 _parameterTypeDict.insert("QBrush", QMetaType::QBrush);
231 228 _parameterTypeDict.insert("QColor", QMetaType::QColor);
232 229 _parameterTypeDict.insert("QCursor", QMetaType::QCursor);
233 230 _parameterTypeDict.insert("QPalette", QMetaType::QPalette);
234 231 _parameterTypeDict.insert("QIcon", QMetaType::QIcon);
235 _parameterTypeDict.insert("QImage", QMetaType::QPolygon);
232 _parameterTypeDict.insert("QImage", QMetaType::QImage);
236 233 _parameterTypeDict.insert("QRegion", QMetaType::QRegion);
237 234 _parameterTypeDict.insert("QBitmap", QMetaType::QBitmap);
238 235 _parameterTypeDict.insert("QSizePolicy", QMetaType::QSizePolicy);
239 236 _parameterTypeDict.insert("QKeySequence", QMetaType::QKeySequence);
240 237 _parameterTypeDict.insert("QPen", QMetaType::QPen);
241 238 _parameterTypeDict.insert("QTextLength", QMetaType::QTextLength);
242 239 _parameterTypeDict.insert("QTextFormat", QMetaType::QTextFormat);
243 240 _parameterTypeDict.insert("QMatrix", QMetaType::QMatrix);
244 241 _parameterTypeDict.insert("QVariant", PythonQtMethodInfo::Variant);
245 242 // own special types... (none so far, could be e.g. ObjectList
246 243 }
247 244 QHash<QByteArray, int>::const_iterator it = _parameterTypeDict.find(name);
248 245 if (it!=_parameterTypeDict.end()) {
249 246 return it.value();
250 247 } else {
251 248 return PythonQtMethodInfo::Unknown;
252 249 }
253 250 }
254 251
255 252 void PythonQtMethodInfo::cleanupCachedMethodInfos()
256 253 {
257 254 QHashIterator<QByteArray, PythonQtMethodInfo *> i(_cachedSignatures);
258 255 while (i.hasNext()) {
259 256 delete i.next().value();
260 257 }
261 258 }
262 259
263 260 void PythonQtMethodInfo::addParameterTypeAlias(const QByteArray& alias, const QByteArray& name)
264 261 {
265 262 _parameterNameAliases.insert(alias, name);
266 263 }
267 264
268 265 //-------------------------------------------------------------------------------------------------
269 266
270 267 void PythonQtSlotInfo::deleteOverloadsAndThis()
271 268 {
272 269 PythonQtSlotInfo* cur = this;
273 270 while(cur->nextInfo()) {
274 271 PythonQtSlotInfo* next = cur->nextInfo();
275 272 delete cur;
276 273 cur = next;
277 274 }
278 275 }
279 276
280 277
281 278 QString PythonQtSlotInfo::fullSignature()
282 279 {
283 280 bool skipFirstArg = isInstanceDecorator();
284 281 QString result = _meta.typeName();
285 282 QByteArray sig = slotName();
286 283 QList<QByteArray> names = _meta.parameterNames();
287 284
288 285 bool isStatic = false;
289 286 bool isConstructor = false;
290 287 bool isDestructor = false;
291 288
292 289 if (_type == ClassDecorator) {
293 290 if (sig.startsWith("new_")) {
294 291 sig = sig.mid(strlen("new_"));
295 292 isConstructor = true;
296 293 } else if (sig.startsWith("delete_")) {
297 294 sig = sig.mid(strlen("delete_"));
298 295 isDestructor = true;
299 296 } else if(sig.startsWith("static_")) {
300 297 isStatic = true;
301 298 sig = sig.mid(strlen("static_"));
302 299 int idx = sig.indexOf("_");
303 300 if (idx>=0) {
304 301 sig = sig.mid(idx+1);
305 302 }
306 303 }
307 304 }
308 305
309 306 result += QByteArray(" ") + sig;
310 307 result += "(";
311 308
312 309 int lastEntry = _parameters.count()-1;
313 310 for (int i = skipFirstArg?2:1; i<_parameters.count(); i++) {
314 311 if (_parameters.at(i).isConst) {
315 312 result += "const ";
316 313 }
317 314 result += _parameters.at(i).name;
318 315 if (_parameters.at(i).pointerCount) {
319 316 QByteArray stars;
320 317 stars.fill('*', _parameters.at(i).pointerCount);
321 318 result += stars;
322 319 }
323 320 if (!names.at(i-1).isEmpty()) {
324 321 result += " ";
325 322 result += names.at(i-1);
326 323 }
327 324 if (i!=lastEntry) {
328 325 result += ", ";
329 326 }
330 327 }
331 328 result += ")";
332 329
333 330 if (isStatic) {
334 331 result = QString("static ") + result;
335 332 }
336 333 if (isConstructor) {
337 334 // result = QString("constructor ") + result;
338 335 }
339 336 if (isDestructor) {
340 337 result = QString("~") + result;
341 338 }
342 339 return result;
343 340 }
344 341
345 342
346 343 QByteArray PythonQtSlotInfo::slotName()
347 344 {
348 345 QByteArray sig(_meta.signature());
349 346 int idx = sig.indexOf('(');
350 347 sig = sig.left(idx);
351 348 return sig;
352 349 }
353 350
@@ -1,142 +1,175
1 1 #ifndef _PYTHONQTMISC_H
2 2 #define _PYTHONQTMISC_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtMisc.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45
46 46 #include <QList>
47 47
48 48 #define PythonQtValueStorage_ADD_VALUE(store, type, value, ptr) \
49 49 { type* item = (type*)store.nextValuePtr(); \
50 50 *item = value; \
51 51 ptr = (void*)item; \
52 52 }
53 53
54 54 #define PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedPtr,store, type, value, ptr) \
55 55 { \
56 56 type* item = (type*)(alreadyAllocatedPtr?alreadyAllocatedPtr:store.nextValuePtr()); \
57 57 *item = value; \
58 58 ptr = (void*)item; \
59 59 }
60 60
61 61 //! stores a position in the PythonQtValueStorage
62 62 class PythonQtValueStoragePosition {
63 63
64 64 public:
65 65 PythonQtValueStoragePosition() { chunkIdx = 0; chunkOffset = 0; }
66 66
67 67 int chunkIdx;
68 68 int chunkOffset;
69 69
70 70 };
71 71
72 72 //! a helper class that stores basic C++ value types in chunks
73 73 template <typename T, int chunkEntries> class PythonQtValueStorage
74 74 {
75 75 public:
76 76 PythonQtValueStorage() {
77 77 _chunkIdx = 0;
78 78 _chunkOffset = 0;
79 79 _currentChunk = new T[chunkEntries];
80 80 _chunks.append(_currentChunk);
81 81 };
82 82
83 83 //! clear all memory
84 84 void clear() {
85 85 T* chunk;
86 86 foreach(chunk, _chunks) {
87 87 delete[]chunk;
88 88 }
89 89 _chunks.clear();
90 90 }
91 91
92 //! reset the storage to 0 (without freeing memory, thus caching old entries for reuse)
93 void reset() {
94 _chunkIdx = 0;
95 _chunkOffset = 0;
96 _currentChunk = _chunks.at(0);
97 }
98
99 92 //! get the current position to be restored with setPos
100 93 void getPos(PythonQtValueStoragePosition & pos) {
101 94 pos.chunkIdx = _chunkIdx;
102 95 pos.chunkOffset = _chunkOffset;
103 96 }
104 97
105 98 //! set the current position (without freeing memory, thus caching old entries for reuse)
106 99 void setPos(const PythonQtValueStoragePosition& pos) {
107 100 _chunkOffset = pos.chunkOffset;
108 101 if (_chunkIdx != pos.chunkIdx) {
109 102 _chunkIdx = pos.chunkIdx;
110 103 _currentChunk = _chunks.at(_chunkIdx);
111 104 }
112 105 }
113 106
114 107 //! add one default constructed value and return the pointer to it
115 108 T* nextValuePtr() {
116 109 if (_chunkOffset>=chunkEntries) {
117 110 _chunkIdx++;
118 111 if (_chunkIdx >= _chunks.size()) {
119 112 T* newChunk = new T[chunkEntries];
120 113 _chunks.append(newChunk);
121 114 _currentChunk = newChunk;
122 115 } else {
123 116 _currentChunk = _chunks.at(_chunkIdx);
124 117 }
125 118 _chunkOffset = 0;
126 119 }
127 120 T* newEntry = _currentChunk + _chunkOffset;
128 121 _chunkOffset++;
129 122 return newEntry;
130 123 };
131 124
132 private:
125 protected:
133 126 QList<T*> _chunks;
134 127
135 128 int _chunkIdx;
136 129 int _chunkOffset;
137 130 T* _currentChunk;
138 131
139 132 };
140 133
134 //! a helper class that stores basic C++ value types in chunks and clears the unused values on setPos() usage.
135 template <typename T, int chunkEntries> class PythonQtValueStorageWithCleanup : public PythonQtValueStorage<T, chunkEntries>
136 {
137 public:
138 void setPos(const PythonQtValueStoragePosition& pos) {
139 if (_chunkIdx > pos.chunkIdx) {
140 T* firstChunk = _chunks.at(pos.chunkIdx);
141 // clear region in first chunk
142 for (int i = pos.chunkOffset; i < chunkEntries; i++) {
143 firstChunk[i] = T();
144 }
145 for (int chunk = pos.chunkIdx + 1; chunk < _chunkIdx; chunk++) {
146 // clear the full chunks between the first and last chunk
147 T* fullChunk = _chunks.at(chunk);
148 for (int i = 0; i < chunkEntries; i++) {
149 fullChunk[i] = T();
150 }
151 }
152 // clear region in last chunk
153 T* lastChunk = _chunks.at(_chunkIdx);
154 for (int i = 0; i < _chunkOffset; i++) {
155 lastChunk[i] = T();
156 }
157 } else if (_chunkIdx == pos.chunkIdx) {
158 // clear the region in the last chunk only
159 T* lastChunk = _chunks.at(_chunkIdx);
160 for (int i = pos.chunkOffset; i<_chunkOffset; i++) {
161 lastChunk[i] = T();
162 }
163 }
164
165 PythonQtValueStorage<T, chunkEntries>::setPos(pos);
166 }
167
168 private:
169 using PythonQtValueStorage<T, chunkEntries>::_chunks;
170 using PythonQtValueStorage<T, chunkEntries>::_chunkIdx;
171 using PythonQtValueStorage<T, chunkEntries>::_chunkOffset;
172 using PythonQtValueStorage<T, chunkEntries>::_currentChunk;
173 };
141 174
142 175 #endif
@@ -1,174 +1,174
1 1 #ifndef _PYTHONQTOBJECTPTR_H
2 2 #define _PYTHONQTOBJECTPTR_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtObjectPtr.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include <Python.h>
46 46 #include "PythonQtSystem.h"
47 47 #include <QVariant>
48 48 #include <QVariantList>
49 49
50 50 //! a smart pointer that stores a PyObject pointer and that handles reference counting automatically
51 51 class PYTHONQT_EXPORT PythonQtObjectPtr
52 52 {
53 53 public:
54 54 PythonQtObjectPtr():_object(NULL) {}
55 55
56 56 PythonQtObjectPtr(const PythonQtObjectPtr &p):_object(NULL) {
57 57 setObject(p.object());
58 58 }
59 59
60 //! If the given variant holds a PythonQtObjectPtr, extract the value from it and hold onto the reference. This results in an increment of the reference count.
60 //! If the given variant holds a PythonQtObjectPtr, extract the value from it and hold onto the reference. This results in an increment of the reference count.
61 61 PythonQtObjectPtr(const QVariant& variant):_object(NULL) {
62 fromVariant(variant);
62 fromVariant(variant);
63 63 }
64
64
65 65 PythonQtObjectPtr(PyObject* o) {
66 66 _object = o;
67 67 if (o) Py_INCREF(_object);
68 68 }
69 69
70 ~PythonQtObjectPtr() { if (_object) Py_DECREF(_object); }
71
72 //! If the given variant holds a PythonQtObjectPtr, extract the value from it and hold onto the reference. This results in an increment of the reference count.
70 ~PythonQtObjectPtr() { if (_object) { Py_DECREF(_object); } }
71
72 //! If the given variant holds a PythonQtObjectPtr, extract the value from it and hold onto the reference. This results in an increment of the reference count.
73 73 bool fromVariant(const QVariant& variant);
74
74
75 75 PythonQtObjectPtr &operator=(const PythonQtObjectPtr &p) {
76 76 setObject(p.object());
77 77 return *this;
78 78 }
79 79
80 80 PythonQtObjectPtr &operator=(PyObject* o) {
81 81 setObject(o);
82 82 return *this;
83 83 }
84 84
85
85
86 86 PythonQtObjectPtr &operator=(const QVariant& variant) {
87 87 fromVariant(variant);
88 88 return *this;
89 89 }
90 90
91
91
92 92 bool operator==( const PythonQtObjectPtr &p ) const {
93 93 return object() == p.object();
94 94 }
95 95
96 96 bool operator!= ( const PythonQtObjectPtr& p ) const {
97 97 return !( *this == p );
98 98 }
99 99
100 100 bool operator==( PyObject* p ) const {
101 101 return object() == p;
102 102 }
103 103
104 104 bool operator!= ( PyObject* p ) const {
105 105 return object() != p;
106 106 }
107 107
108 108 bool isNull() const { return !object(); }
109 109
110 110 PyObject* operator->() const { return object(); }
111 111
112 112 PyObject& operator*() const { return *( object() ); }
113 113
114 114 operator PyObject*() const { return object(); }
115 115
116 116 //! sets the object and passes the ownership (stealing the reference, in Python slang)
117 117 void setNewRef(PyObject* o) {
118 118 if (o != _object) {
119 if (_object) Py_DECREF(_object);
119 if (_object) { Py_DECREF(_object); }
120 120 _object = o;
121 121 }
122 122 }
123 123
124 124 PyObject* object() const {
125 125 return _object;
126 126 }
127 127
128 128 //! evaluates the given script code in the context of this object and returns the result value
129 129 QVariant evalScript(const QString& script, int start = Py_file_input);
130 130
131 131 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
132 132 //! If pycode is NULL, a python error is printed.
133 133 QVariant evalCode(PyObject* pycode);
134 134
135 135 //! evaluates the given code in the context
136 136 void evalFile(const QString& filename);
137 137
138 138 //! add the given \c object to the \c module as a variable with \c name (it can be removed via clearVariable)
139 139 void addObject(const QString& name, QObject* object);
140 140
141 141 //! add the given variable to the module
142 142 void addVariable(const QString& name, const QVariant& v);
143 143
144 144 //! remove the given variable
145 145 void removeVariable(const QString& name);
146 146
147 147 //! get the variable with the \c name of the \c module, returns an invalid QVariant on error
148 148 QVariant getVariable(const QString& name);
149 149
150 150 //! call the given python object (in the scope of the current object), returns the result converted to a QVariant
151 151 QVariant call(const QString& callable, const QVariantList& args = QVariantList());
152 152
153 153 //! call the contained python object directly, returns the result converted to a QVariant
154 154 QVariant call(const QVariantList& args = QVariantList());
155 155
156 156 protected:
157 157
158 158 void setObject(PyObject* o) {
159 159 if (o != _object) {
160 if (_object) Py_DECREF(_object);
160 if (_object) { Py_DECREF(_object); }
161 161 _object = o;
162 if (_object) Py_INCREF(_object);
162 if (_object) { Py_INCREF(_object); }
163 163 }
164 164 }
165 165
166 166 private:
167 167 PyObject* _object;
168 168 };
169 169
170 170
171 171 // register it to the meta type system
172 172 Q_DECLARE_METATYPE(PythonQtObjectPtr)
173 173
174 #endif No newline at end of file
174 #endif
@@ -1,226 +1,228
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtSignalReceiver.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtSignalReceiver.h"
43 43 #include "PythonQtClassInfo.h"
44 44 #include "PythonQtMethodInfo.h"
45 45 #include "PythonQtConversion.h"
46 46 #include <QMetaObject>
47 47 #include <QMetaMethod>
48 48 #include "funcobject.h"
49 49
50 50 void PythonQtSignalTarget::call(void **arguments) const {
51 51 PyObject* result = call(_callable, methodInfo(), arguments);
52 52 if (result) {
53 53 Py_DECREF(result);
54 54 }
55 55 }
56 56
57 57 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInfo* methodInfos, void **arguments, bool skipFirstArgumentOfMethodInfo)
58 58 {
59 Q_UNUSED(skipFirstArgumentOfMethodInfo)
60
59 61 // Note: we check if the callable is a PyFunctionObject and has a fixed number of arguments
60 62 // if that is the case, we only pass these arguments to python and skip the additional arguments from the signal
61
63
62 64 int numPythonArgs = -1;
63 65 if (PyFunction_Check(callable)) {
64 66 PyObject* o = callable;
65 67 PyFunctionObject* func = (PyFunctionObject*)o;
66 68 PyCodeObject* code = (PyCodeObject*)func->func_code;
67 69 if (!(code->co_flags & 0x04)) {
68 70 numPythonArgs = code->co_argcount;
69 71 } else {
70 72 // variable numbers of arguments allowed
71 73 }
72 74 } else if (PyMethod_Check(callable)) {
73 75 PyObject* o = callable;
74 76 PyMethodObject* method = (PyMethodObject*)o;
75 77 if (PyFunction_Check(method->im_func)) {
76 78 PyFunctionObject* func = (PyFunctionObject*)method->im_func;
77 79 PyCodeObject* code = (PyCodeObject*)func->func_code;
78 80 if (!(code->co_flags & 0x04)) {
79 81 numPythonArgs = code->co_argcount - 1; // we subtract one because the first is "self"
80 82 } else {
81 83 // variable numbers of arguments allowed
82 84 }
83 85 }
84 86 }
85 87
86 88 const PythonQtMethodInfo* m = methodInfos;
87 89 // parameterCount includes return value:
88 90 int count = m->parameterCount();
89 91 if (numPythonArgs!=-1) {
90 92 if (count>numPythonArgs+1) {
91 93 // take less arguments
92 94 count = numPythonArgs+1;
93 95 }
94 96 }
95 97
96 98 PyObject* pargs = NULL;
97 99 if (count>1) {
98 100 pargs = PyTuple_New(count-1);
99 101 }
100 102 bool err = false;
101 103 // transform Qt values to Python
102 104 const QList<PythonQtMethodInfo::ParameterInfo>& params = m->parameters();
103 105 for (int i = 1; i < count; i++) {
104 106 const PythonQtMethodInfo::ParameterInfo& param = params.at(i);
105 107 PyObject* arg = PythonQtConv::ConvertQtValueToPython(param, arguments[i]);
106 108 if (arg) {
107 109 // steals reference, no unref
108 110 PyTuple_SetItem(pargs, i-1,arg);
109 111 } else {
110 112 err = true;
111 113 break;
112 114 }
113 115 }
114 116
115 117 PyObject* result = NULL;
116 118 if (!err) {
117 119 PyErr_Clear();
118 120 result = PyObject_CallObject(callable, pargs);
119 121 if (result) {
120 122 // ok
121 123 } else {
122 124 PythonQt::self()->handleError();
123 125 }
124 126 }
125 127 if (pargs) {
126 128 // free the arguments again
127 129 Py_DECREF(pargs);
128 130 }
129 131
130 132 return result;
131 133 }
132 134
133 135 //------------------------------------------------------------------------------
134 136
135 137 PythonQtSignalReceiver::PythonQtSignalReceiver(QObject* obj):PythonQtSignalReceiverBase(obj)
136 138 {
137 139 _obj = obj;
138
140
139 141 // fetch the class info for object, since we will need to for correct enum resolution in
140 142 // signals
141 143 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
142 144 if (!_objClassInfo || !_objClassInfo->isQObject()) {
143 145 PythonQt::self()->registerClass(obj->metaObject());
144 146 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
145 147 }
146 148 // force decorator/enum creation
147 149 _objClassInfo->decorator();
148 150
149 151 _slotCount = staticMetaObject.methodOffset();
150 152 }
151 153
152 154 PythonQtSignalReceiver::~PythonQtSignalReceiver()
153 155 {
154 156 PythonQt::priv()->removeSignalEmitter(_obj);
155 157 }
156 158
157 159
158 160 bool PythonQtSignalReceiver::addSignalHandler(const char* signal, PyObject* callable)
159 161 {
160 162 bool flag = false;
161 163 int sigId = getSignalIndex(signal);
162 164 if (sigId>=0) {
163 165 // create PythonQtMethodInfo from signal
164 166 QMetaMethod meta = _obj->metaObject()->method(sigId);
165 167 const PythonQtMethodInfo* signalInfo = PythonQtMethodInfo::getCachedMethodInfo(meta, _objClassInfo);
166 168 PythonQtSignalTarget t(sigId, signalInfo, _slotCount, callable);
167 169 _targets.append(t);
168 170 // now connect to ourselves with the new slot id
169 171 QMetaObject::connect(_obj, sigId, this, _slotCount, Qt::AutoConnection, 0);
170 172
171 173 _slotCount++;
172 174 flag = true;
173 175 }
174 176 return flag;
175 177 }
176 178
177 179 bool PythonQtSignalReceiver::removeSignalHandler(const char* signal, PyObject* callable)
178 180 {
179 181 bool found = false;
180 182 int sigId = getSignalIndex(signal);
181 183 if (sigId>=0) {
182 184 QMutableListIterator<PythonQtSignalTarget> i(_targets);
183 185 while (i.hasNext()) {
184 186 if (i.next().isSame(sigId, callable)) {
185 187 i.remove();
186 188 found = true;
187 189 break;
188 190 }
189 191 }
190 192 }
191 193 return found;
192 194 }
193 195
194 196 void PythonQtSignalReceiver::removeSignalHandlers()
195 197 {
196 198 _targets.clear();
197 199 }
198 200
199 201 int PythonQtSignalReceiver::getSignalIndex(const char* signal)
200 202 {
201 203 int sigId = _obj->metaObject()->indexOfSignal(signal+1);
202 204 if (sigId<0) {
203 205 QByteArray tmpSig = QMetaObject::normalizedSignature(signal+1);
204 206 sigId = _obj->metaObject()->indexOfSignal(tmpSig);
205 207 }
206 208 return sigId;
207 209 }
208 210
209 211 int PythonQtSignalReceiver::qt_metacall(QMetaObject::Call c, int id, void **arguments)
210 212 {
211 213 // mlabDebugConst("PythonQt", "PythonQtSignalReceiver invoke " << _obj->className() << " " << _obj->name() << " " << id);
212 214 if (c != QMetaObject::InvokeMetaMethod) {
213 215 QObject::qt_metacall(c, id, arguments);
214 216 }
215 217
216 218 bool found = false;
217 219 foreach(const PythonQtSignalTarget& t, _targets) {
218 220 if (t.slotId() == id) {
219 221 found = true;
220 222 t.call(arguments);
221 223 break;
222 224 }
223 225 }
224 226 return 0;
225 227 }
226 228
@@ -1,141 +1,141
1 1 #ifndef _PYTHONQTSIGNALRECEIVER_H
2 2 #define _PYTHONQTSIGNALRECEIVER_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtSignalReceiver.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include <Python.h>
46 46 #include "PythonQtSystem.h"
47 47 #include "PythonQtObjectPtr.h"
48 48
49 49 class PythonQtMethodInfo;
50 50 class PythonQtClassInfo;
51 51
52 52 //! stores information about a signal target
53 /*! copy construction and assignment works fine with the C++ standard behaviour and are thus not implemented
53 /*! copy construction and assignment works fine with the C++ standard behavior and are thus not implemented
54 54 */
55 55 class PYTHONQT_EXPORT PythonQtSignalTarget {
56 56 public:
57 57 PythonQtSignalTarget() {
58 58 _signalId = -1;
59 59 _methodInfo = NULL;
60 60 _slotId = -1;
61 61 }
62 62
63 63 PythonQtSignalTarget(int signalId,const PythonQtMethodInfo* methodInfo, int slotId, PyObject* callable)
64 64 {
65 65 _signalId = signalId;
66 66 _slotId = slotId;
67 67 _methodInfo = methodInfo;
68 68 _callable = callable;
69 69 };
70 70
71 71 ~PythonQtSignalTarget() {
72 72 };
73 73
74 74 //! get the id of the original signal
75 75 int signalId() const { return _signalId; }
76 76
77 77 //! get the id that was assigned to this simulated slot
78 78 int slotId() const { return _slotId; }
79 79
80 80 //! get the signals parameter info
81 81 const PythonQtMethodInfo* methodInfo() const { return _methodInfo; }
82 82
83 83 //! call the python callable with the given arguments (as defined in methodInfo)
84 84 void call(void **arguments) const;
85 85
86 86 //! check if it is the same signal target
87 87 bool isSame(int signalId, PyObject* callable) const { return callable==_callable && signalId==_signalId; }
88 88
89 89 //! call the given callable with arguments described by PythonQtMethodInfo, returns a new reference as result value (or NULL)
90 90 static PyObject* call(PyObject* callable, const PythonQtMethodInfo* methodInfo, void **arguments, bool skipFirstArgumentOfMethodInfo = false);
91 91
92 92 private:
93 93 int _signalId;
94 94 int _slotId;
95 95 const PythonQtMethodInfo* _methodInfo;
96 96 PythonQtObjectPtr _callable;
97 97 };
98 98
99 99 //! base class for signal receivers
100 100 /*!
101 101 */
102 102 class PythonQtSignalReceiverBase : public QObject {
103 103 Q_OBJECT
104 104 public:
105 105 PythonQtSignalReceiverBase(QObject* obj):QObject(obj) {};
106 106 };
107 107
108 108 //! receives all signals for one QObject
109 109 /*! we derive from our base but do not declare the QObject macro because we want to reimplement qt_metacall only.
110 110 */
111 111 class PythonQtSignalReceiver : public PythonQtSignalReceiverBase {
112 112
113 113 public:
114 114 PythonQtSignalReceiver(QObject* obj);
115 115 ~PythonQtSignalReceiver();
116 116
117 117 //! add a signal handler
118 118 bool addSignalHandler(const char* signal, PyObject* callable);
119 119
120 120 //! remove a signal handler
121 121 bool removeSignalHandler(const char* signal, PyObject* callable);
122 122
123 123 //! remove all signal handlers
124 124 void removeSignalHandlers();
125 125
126 126 //! we implement this method to simulate a number of slots that match the ids in _targets
127 127 virtual int qt_metacall(QMetaObject::Call c, int id, void **arguments);
128 128
129 129 private:
130 130 //! get the index of the signal
131 131 int getSignalIndex(const char* signal);
132 132
133 133 QObject* _obj;
134 134 PythonQtClassInfo* _objClassInfo;
135 135 int _slotCount;
136 136 // linear list may get slow on multiple targets, but I think typically we have many objects and just a few signals
137 137 QList<PythonQtSignalTarget> _targets;
138 138 };
139 139
140 140
141 141 #endif
@@ -1,509 +1,526
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtSlot.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 "PythonQtSlot.h"
44 44 #include "PythonQtInstanceWrapper.h"
45 45 #include "PythonQtClassInfo.h"
46 46 #include "PythonQtMisc.h"
47 47 #include "PythonQtConversion.h"
48 48 #include <iostream>
49 49
50 50 #define PYTHONQT_MAX_ARGS 32
51 51
52 52
53 53 bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer)
54 54 {
55 55 static unsigned int recursiveEntry = 0;
56
56
57 57 if (directReturnValuePointer) {
58 58 *directReturnValuePointer = NULL;
59 59 }
60 60 // store the current storage position, so that we can get back to this state after a slot is called
61 61 // (do this locally, so that we have all positions on the stack
62 62 PythonQtValueStoragePosition globalValueStoragePos;
63 63 PythonQtValueStoragePosition globalPtrStoragePos;
64 64 PythonQtValueStoragePosition globalVariantStoragePos;
65 65 PythonQtConv::global_valueStorage.getPos(globalValueStoragePos);
66 66 PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos);
67 67 PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos);
68
68
69 69 recursiveEntry++;
70
70
71 71 // the arguments that are passed to qt_metacall
72 72 void* argList[PYTHONQT_MAX_ARGS];
73 73 PyObject* result = NULL;
74 74 int argc = info->parameterCount();
75 75 const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters();
76
76
77 77 const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);
78 78 // set return argument to NULL
79 79 argList[0] = NULL;
80
80
81 81 bool ok = true;
82 82 bool skipFirst = false;
83 83 if (info->isInstanceDecorator()) {
84 84 skipFirst = true;
85 85
86 86 // for decorators on CPP objects, we take the cpp ptr, for QObjects we take the QObject pointer
87 87 void* arg1 = firstArgument;
88 88 if (!arg1) {
89 89 arg1 = objectToCall;
90 90 }
91 91 if (arg1) {
92 92 // upcast to correct parent class
93 93 arg1 = ((char*)arg1)+info->upcastingOffset();
94 94 }
95 95
96 96 argList[1] = &arg1;
97 97 if (ok) {
98 98 for (int i = 2; i<argc && ok; i++) {
99 99 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
100 100 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, classInfo);
101 101 if (argList[i]==NULL) {
102 102 ok = false;
103 103 break;
104 104 }
105 105 }
106 106 }
107 107 } else {
108 108 for (int i = 1; i<argc && ok; i++) {
109 109 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
110 110 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, classInfo);
111 111 if (argList[i]==NULL) {
112 112 ok = false;
113 113 break;
114 114 }
115 115 }
116 116 }
117
117
118 118 if (ok) {
119 119 // parameters are ok, now create the qt return value which is assigned to by metacall
120 120 if (returnValueParam.typeId != QMetaType::Void) {
121 121 // create empty default value for the return value
122 122 if (!directReturnValuePointer) {
123 123 // create empty default value for the return value
124 124 argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);
125 125 if (argList[0]==NULL) {
126 126 // return value could not be created, maybe we have a registered class with a default constructor, so that we can construct the pythonqt wrapper object and
127 127 // pass its internal pointer
128 128 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(returnValueParam.name);
129 129 if (info && info->pythonQtClassWrapper()) {
130 130 PyObject* emptyTuple = PyTuple_New(0);
131 131 // 1) default construct an empty object as python object (owned by PythonQt), by calling the meta class with empty arguments
132 132 result = PyObject_Call((PyObject*)info->pythonQtClassWrapper(), emptyTuple, NULL);
133 133 if (result) {
134 134 argList[0] = ((PythonQtInstanceWrapper*)result)->_wrappedPtr;
135 135 }
136 Py_DECREF(emptyTuple);
137 }
136 Py_DECREF(emptyTuple);
137 }
138 138 }
139 139 } else {
140 140 // we can use our pointer directly!
141 141 argList[0] = directReturnValuePointer;
142 142 }
143 143 }
144 144
145
146 PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB();
147 if (profilingCB) {
148 const char* className = NULL;
149 if (info->decorator()) {
150 className = info->decorator()->metaObject()->className();
151 } else {
152 className = objectToCall->metaObject()->className();
153 }
154
155 profilingCB(PythonQt::Enter, className, info->metaMethod()->signature());
156 }
157
145 158 // invoke the slot via metacall
146 159 (info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
147 160
161 if (profilingCB) {
162 profilingCB(PythonQt::Leave, NULL, NULL);
163 }
164
148 165 // handle the return value (which in most cases still needs to be converted to a Python object)
149 166 if (argList[0] || returnValueParam.typeId == QMetaType::Void) {
150 167 if (directReturnValuePointer) {
151 168 result = NULL;
152 169 } else {
153 170 // the resulting object maybe present already, because we created it above at 1)...
154 171 if (!result) {
155 172 result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]);
156 173 }
157 174 }
158 175 } else {
159 176 QString e = QString("Called ") + info->fullSignature() + ", return type '" + returnValueParam.name + "' is ignored because it is unknown to PythonQt. Probably you should register it using qRegisterMetaType() or add a default constructor decorator to the class.";
160 177 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
161 178 result = NULL;
162 179 }
163 180 }
164 181 recursiveEntry--;
165
182
166 183 // reset the parameter storage position to the stored pos to "pop" the parameter stack
167 184 PythonQtConv::global_valueStorage.setPos(globalValueStoragePos);
168 185 PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos);
169 186 PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos);
170
187
171 188 *pythonReturnValue = result;
172 189 // NOTE: it is important to only return here, otherwise the stack will not be popped!!!
173 190 return result || (directReturnValuePointer && *directReturnValuePointer);
174 191 }
175 192
176 193 //-----------------------------------------------------------------------------------
177 194
178 195 static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL;
179 196
180 197 PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw)
181 198 {
182 199 PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func;
183 200 PythonQtSlotInfo* info = f->m_ml;
184 201 if (PyObject_TypeCheck(f->m_self, &PythonQtInstanceWrapper_Type)) {
185 202 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self;
186 203 if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
187 204 QString error = QString("Trying to call '") + f->m_ml->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
188 205 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
189 206 return NULL;
190 207 } else {
191 208 return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr);
192 209 }
193 210 } else if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
194 211 PythonQtClassWrapper* type = (PythonQtClassWrapper*) f->m_self;
195 212 if (info->isClassDecorator()) {
196 213 return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw);
197 214 } else {
198 215 // otherwise, it is an unbound call and we have an instanceDecorator or normal slot...
199 216 Py_ssize_t argc = PyTuple_Size(args);
200 217 if (argc>0) {
201 218 PyObject* firstArg = PyTuple_GET_ITEM(args, 0);
202 219 if (PyObject_TypeCheck(firstArg, (PyTypeObject*)&PythonQtInstanceWrapper_Type)
203 220 && ((PythonQtInstanceWrapper*)firstArg)->classInfo()->inherits(type->classInfo())) {
204 221 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg;
205 222 if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
206 223 QString error = QString("Trying to call '") + f->m_ml->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
207 224 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
208 225 return NULL;
209 226 }
210 227 // strip the first argument...
211 228 PyObject* newargs = PyTuple_GetSlice(args, 1, argc);
212 229 PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, newargs, kw, self->_wrappedPtr);
213 230 Py_DECREF(newargs);
214 231 return result;
215 232 } else {
216 233 // first arg is not of correct type!
217 234 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument, got " + firstArg->ob_type->tp_name;
218 235 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
219 236 return NULL;
220 237 }
221 238 } else {
222 239 // wrong number of args
223 240 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument.";
224 241 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
225 242 return NULL;
226 243 }
227 244 }
228 245 }
229 246 return NULL;
230 247 }
231 248
232 249 PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg, void** directReturnValuePointer)
233 250 {
234 251 int argc = args?PyTuple_Size(args):0;
235 252
236 253 #ifdef PYTHONQT_DEBUG
237 254 std::cout << "called " << info->metaMethod()->typeName() << " " << info->metaMethod()->signature() << std::endl;
238 255 #endif
239 256
240 257 PyObject* r = NULL;
241 258 bool ok = false;
242 259 if (directReturnValuePointer) {
243 260 *directReturnValuePointer = NULL;
244 261 }
245 262 if (info->nextInfo()) {
246 263 // overloaded slot call, try on all slots with strict conversion first
247 264 bool strict = true;
248 265 PythonQtSlotInfo* i = info;
249 266 while (i) {
250 267 bool skipFirst = i->isInstanceDecorator();
251 268 if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
252 269 PyErr_Clear();
253 270 ok = PythonQtCallSlot(classInfo, objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer);
254 271 if (PyErr_Occurred() || ok) break;
255 272 }
256 273 i = i->nextInfo();
257 274 if (!i) {
258 275 if (strict) {
259 276 // one more run without being strict
260 277 strict = false;
261 278 i = info;
262 279 }
263 280 }
264 281 }
265 282 if (!ok && !PyErr_Occurred()) {
266 283 QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n");
267 284 PythonQtSlotInfo* i = info;
268 285 while (i) {
269 286 e += QString(i->fullSignature()) + "\n";
270 287 i = i->nextInfo();
271 288 }
272 289 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
273 290 }
274 291 } else {
275 292 // simple (non-overloaded) slot call
276 293 bool skipFirst = info->isInstanceDecorator();
277 294 if (info->parameterCount()-1-(skipFirst?1:0) == argc) {
278 295 PyErr_Clear();
279 296 ok = PythonQtCallSlot(classInfo, objectToCall, args, false, info, firstArg, &r, directReturnValuePointer);
280 297 if (!ok && !PyErr_Occurred()) {
281 298 QString e = QString("Called ") + info->fullSignature() + " with wrong arguments: " + PythonQtConv::PyObjGetString(args);
282 299 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
283 300 }
284 301 } else {
285 302 QString e = QString("Called ") + info->fullSignature() + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args);
286 303 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
287 304 }
288 305 }
289
306
290 307 return r;
291 308 }
292 309
293 310 PyObject *
294 311 PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module)
295 312 {
296 313 PythonQtSlotFunctionObject *op;
297 314 op = pythonqtslot_free_list;
298 315 if (op != NULL) {
299 316 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self);
300 317 PyObject_INIT(op, &PythonQtSlotFunction_Type);
301 318 }
302 319 else {
303 320 op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type);
304 321 if (op == NULL)
305 322 return NULL;
306 323 }
307 324 op->m_ml = ml;
308 325 Py_XINCREF(self);
309 326 op->m_self = self;
310 327 Py_XINCREF(module);
311 328 op->m_module = module;
312 329 PyObject_GC_Track(op);
313 330 return (PyObject *)op;
314 331 }
315 332
316 333 PythonQtSlotInfo*
317 334 PythonQtSlotFunction_GetSlotInfo(PyObject *op)
318 335 {
319 336 if (!PythonQtSlotFunction_Check(op)) {
320 337 PyErr_BadInternalCall();
321 338 return NULL;
322 339 }
323 340 return ((PythonQtSlotFunctionObject *)op) -> m_ml;
324 341 }
325 342
326 343 PyObject *
327 344 PythonQtSlotFunction_GetSelf(PyObject *op)
328 345 {
329 346 if (!PythonQtSlotFunction_Check(op)) {
330 347 PyErr_BadInternalCall();
331 348 return NULL;
332 349 }
333 350 return ((PythonQtSlotFunctionObject *)op) -> m_self;
334 351 }
335 352
336 353 /* Methods (the standard built-in methods, that is) */
337 354
338 355 static void
339 356 meth_dealloc(PythonQtSlotFunctionObject *m)
340 357 {
341 358 PyObject_GC_UnTrack(m);
342 359 Py_XDECREF(m->m_self);
343 360 Py_XDECREF(m->m_module);
344 361 m->m_self = (PyObject *)pythonqtslot_free_list;
345 362 pythonqtslot_free_list = m;
346 363 }
347 364
348 365 static PyObject *
349 366 meth_get__doc__(PythonQtSlotFunctionObject * /*m*/, void * /*closure*/)
350 367 {
351 368 Py_INCREF(Py_None);
352 369 return Py_None;
353 370 }
354 371
355 372 static PyObject *
356 373 meth_get__name__(PythonQtSlotFunctionObject *m, void * /*closure*/)
357 374 {
358 375 return PyString_FromString(m->m_ml->metaMethod()->signature());
359 376 }
360 377
361 378 static int
362 379 meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg)
363 380 {
364 381 int err;
365 382 if (m->m_self != NULL) {
366 383 err = visit(m->m_self, arg);
367 384 if (err)
368 385 return err;
369 386 }
370 387 if (m->m_module != NULL) {
371 388 err = visit(m->m_module, arg);
372 389 if (err)
373 390 return err;
374 391 }
375 392 return 0;
376 393 }
377 394
378 395 static PyObject *
379 396 meth_get__self__(PythonQtSlotFunctionObject *m, void * /*closure*/)
380 397 {
381 398 PyObject *self;
382 399 if (PyEval_GetRestricted()) {
383 400 PyErr_SetString(PyExc_RuntimeError,
384 401 "method.__self__ not accessible in restricted mode");
385 402 return NULL;
386 403 }
387 404 self = m->m_self;
388 405 if (self == NULL)
389 406 self = Py_None;
390 407 Py_INCREF(self);
391 408 return self;
392 409 }
393 410
394 411 static PyGetSetDef meth_getsets [] = {
395 412 {"__doc__", (getter)meth_get__doc__, NULL, NULL},
396 413 {"__name__", (getter)meth_get__name__, NULL, NULL},
397 414 {"__self__", (getter)meth_get__self__, NULL, NULL},
398 415 {NULL, NULL, NULL,NULL},
399 416 };
400 417
401 418 #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6
402 419 #define PY_WRITE_RESTRICTED WRITE_RESTRICTED
403 420 #endif
404 421
405 422 #define OFF(x) offsetof(PythonQtSlotFunctionObject, x)
406 423
407 424 static PyMemberDef meth_members[] = {
408 425 {"__module__", T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED},
409 426 {NULL}
410 427 };
411 428
412 429 static PyObject *
413 430 meth_repr(PythonQtSlotFunctionObject *f)
414 431 {
415 432 if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
416 433 PythonQtClassWrapper* self = (PythonQtClassWrapper*) f->m_self;
417 434 return PyString_FromFormat("<unbound qt slot %s of %s type>",
418 435 f->m_ml->slotName().data(),
419 436 self->classInfo()->className());
420 437 } else {
421 438 return PyString_FromFormat("<qt slot %s of %s instance at %p>",
422 439 f->m_ml->slotName().data(),
423 440 f->m_self->ob_type->tp_name,
424 441 f->m_self);
425 442 }
426 443 }
427 444
428 445 static int
429 446 meth_compare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b)
430 447 {
431 448 if (a->m_self != b->m_self)
432 449 return (a->m_self < b->m_self) ? -1 : 1;
433 450 if (a->m_ml == b->m_ml)
434 451 return 0;
435 452 if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0)
436 453 return -1;
437 454 else
438 455 return 1;
439 456 }
440 457
441 458 static long
442 459 meth_hash(PythonQtSlotFunctionObject *a)
443 460 {
444 461 long x,y;
445 462 if (a->m_self == NULL)
446 463 x = 0;
447 464 else {
448 465 x = PyObject_Hash(a->m_self);
449 466 if (x == -1)
450 467 return -1;
451 468 }
452 469 y = _Py_HashPointer((void*)(a->m_ml));
453 470 if (y == -1)
454 471 return -1;
455 472 x ^= y;
456 473 if (x == -1)
457 474 x = -2;
458 475 return x;
459 476 }
460 477
461 478
462 479 PyTypeObject PythonQtSlotFunction_Type = {
463 480 PyObject_HEAD_INIT(&PyType_Type)
464 481 0,
465 482 "builtin_qt_slot",
466 483 sizeof(PythonQtSlotFunctionObject),
467 484 0,
468 485 (destructor)meth_dealloc, /* tp_dealloc */
469 486 0, /* tp_print */
470 487 0, /* tp_getattr */
471 488 0, /* tp_setattr */
472 489 (cmpfunc)meth_compare, /* tp_compare */
473 490 (reprfunc)meth_repr, /* tp_repr */
474 491 0, /* tp_as_number */
475 492 0, /* tp_as_sequence */
476 493 0, /* tp_as_mapping */
477 494 (hashfunc)meth_hash, /* tp_hash */
478 495 PythonQtSlotFunction_Call, /* tp_call */
479 496 0, /* tp_str */
480 497 PyObject_GenericGetAttr, /* tp_getattro */
481 498 0, /* tp_setattro */
482 499 0, /* tp_as_buffer */
483 500 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
484 501 0, /* tp_doc */
485 502 (traverseproc)meth_traverse, /* tp_traverse */
486 503 0, /* tp_clear */
487 504 0, /* tp_richcompare */
488 505 0, /* tp_weaklistoffset */
489 506 0, /* tp_iter */
490 507 0, /* tp_iternext */
491 508 0, /* tp_methods */
492 509 meth_members, /* tp_members */
493 510 meth_getsets, /* tp_getset */
494 511 0, /* tp_base */
495 512 0, /* tp_dict */
496 513 };
497 514
498 515 /* Clear out the free list */
499 516
500 517 void
501 518 PythonQtSlotFunction_Fini(void)
502 519 {
503 520 while (pythonqtslot_free_list) {
504 521 PythonQtSlotFunctionObject *v = pythonqtslot_free_list;
505 522 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(v->m_self);
506 523 PyObject_GC_Del(v);
507 524 }
508 525 }
509 526
@@ -1,314 +1,305
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtStdDecorators.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2007-04
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtStdDecorators.h"
43 43 #include "PythonQt.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include <QCoreApplication>
46 46
47 47 bool PythonQtStdDecorators::connect(QObject* sender, const QByteArray& signal, PyObject* callable)
48 48 {
49 49 QByteArray signalTmp;
50 50 char first = signal.at(0);
51 51 if (first>='0' && first<='9') {
52 52 signalTmp = signal;
53 53 } else {
54 54 signalTmp = "2" + signal;
55 55 }
56
56
57 57 if (sender) {
58 58 return PythonQt::self()->addSignalHandler(sender, signalTmp, callable);
59 59 } else {
60 60 return false;
61 61 }
62 62 }
63 63
64 64 bool PythonQtStdDecorators::connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot)
65 65 {
66 66 bool r = false;
67 67 if (sender && receiver) {
68 68 QByteArray signalTmp;
69 69 char first = signal.at(0);
70 70 if (first>='0' && first<='9') {
71 71 signalTmp = signal;
72 72 } else {
73 73 signalTmp = "2" + signal;
74 74 }
75 75
76 76 QByteArray slotTmp;
77 77 first = slot.at(0);
78 78 if (first>='0' && first<='9') {
79 79 slotTmp = slot;
80 80 } else {
81 81 slotTmp = "1" + slot;
82 82 }
83 83 r = QObject::connect(sender, signalTmp, receiver, slotTmp);
84 84 }
85 85 return r;
86 86 }
87 87
88 88 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal, PyObject* callable)
89 89 {
90 90 QByteArray signalTmp;
91 91 char first = signal.at(0);
92 92 if (first>='0' && first<='9') {
93 93 signalTmp = signal;
94 94 } else {
95 95 signalTmp = "2" + signal;
96 96 }
97 97 if (sender) {
98 98 return PythonQt::self()->removeSignalHandler(sender, signalTmp, callable);
99 99 } else {
100 100 return false;
101 101 }
102 102 }
103 103
104 104 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot)
105 105 {
106 106 bool r = false;
107 107 if (sender && receiver) {
108 108 QByteArray signalTmp;
109 109 char first = signal.at(0);
110 110 if (first>='0' && first<='9') {
111 111 signalTmp = signal;
112 112 } else {
113 113 signalTmp = "2" + signal;
114 114 }
115
115
116 116 QByteArray slotTmp;
117 117 first = slot.at(0);
118 118 if (first>='0' && first<='9') {
119 119 slotTmp = slot;
120 120 } else {
121 121 slotTmp = "1" + slot;
122 122 }
123
123
124 124 r = QObject::disconnect(sender, signalTmp, receiver, slotTmp);
125 125 }
126 126 return r;
127 127 }
128 128
129 #undef emit
130 void PythonQtStdDecorators::emit(QObject* sender, const QByteArray& signal, PyObject* arg1 ,PyObject* arg2 ,
131 PyObject* arg3 ,PyObject* arg4 ,PyObject* arg5 ,PyObject* arg6 ,PyObject* arg7 )
132 {
133 // TODO xxx
134 // use normal PythonQtSlot calling code, add "allowSignal" to member lookup?!
135 }
136 #define emit
137
138 129 QObject* PythonQtStdDecorators::parent(QObject* o) {
139 130 return o->parent();
140 131 }
141 132
142 133 void PythonQtStdDecorators::setParent(QObject* o, QObject* parent)
143 134 {
144 135 o->setParent(parent);
145 136 }
146 137
147 138 const QObjectList* PythonQtStdDecorators::children(QObject* o)
148 139 {
149 140 return &o->children();
150 141 }
151 142
152 143 bool PythonQtStdDecorators::setProperty(QObject* o, const char* name, const QVariant& value)
153 144 {
154 145 return o->setProperty(name, value);
155 146 }
156 147
157 148 QVariant PythonQtStdDecorators::property(QObject* o, const char* name)
158 149 {
159 150 return o->property(name);
160 151 }
161 152
162 153 QString PythonQtStdDecorators::tr(QObject* obj, const QByteArray& text, const QByteArray& ambig, int n)
163 154 {
164 155 return QCoreApplication::translate(obj->metaObject()->className(), text.constData(), ambig.constData(), QCoreApplication::CodecForTr, n);
165 156 }
166 157
167 158 QObject* PythonQtStdDecorators::findChild(QObject* parent, PyObject* type, const QString& name)
168 159 {
169 160 const QMetaObject* meta = NULL;
170 161 const char* typeName = NULL;
171 162
172 163 if (PyObject_TypeCheck(type, &PythonQtClassWrapper_Type)) {
173 164 meta = ((PythonQtClassWrapper*)type)->classInfo()->metaObject();
174 165 } else if (PyObject_TypeCheck(type, &PythonQtInstanceWrapper_Type)) {
175 166 meta = ((PythonQtInstanceWrapper*)type)->classInfo()->metaObject();
176 167 } else if (PyString_Check(type)) {
177 168 typeName = PyString_AsString(type);
178 169 }
179 170
180 171 if (!typeName && !meta)
181 172 return NULL;
182 173
183 174 return findChild(parent, typeName, meta, name);
184 175 }
185 176
186 177 QList<QObject*> PythonQtStdDecorators::findChildren(QObject* parent, PyObject* type, const QString& name)
187 178 {
188 179 const QMetaObject* meta = NULL;
189 180 const char* typeName = NULL;
190 181
191 182 if (PyObject_TypeCheck(type, &PythonQtClassWrapper_Type)) {
192 183 meta = ((PythonQtClassWrapper*)type)->classInfo()->metaObject();
193 184 } else if (PyObject_TypeCheck(type, &PythonQtInstanceWrapper_Type)) {
194 185 meta = ((PythonQtInstanceWrapper*)type)->classInfo()->metaObject();
195 186 } else if (PyString_Check(type)) {
196 187 typeName = PyString_AsString(type);
197 188 }
198 189
199 190 QList<QObject*> list;
200 191
201 192 if (!typeName && !meta)
202 193 return list;
203 194
204 195 findChildren(parent, typeName, meta, name, list);
205 196
206 197 return list;
207 198 }
208 199
209 200 QList<QObject*> PythonQtStdDecorators::findChildren(QObject* parent, PyObject* type, const QRegExp& regExp)
210 201 {
211 202 const QMetaObject* meta = NULL;
212 203 const char* typeName = NULL;
213 204
214 205 if (PyObject_TypeCheck(type, &PythonQtClassWrapper_Type)) {
215 206 meta = ((PythonQtClassWrapper*)type)->classInfo()->metaObject();
216 207 } else if (PyObject_TypeCheck(type, &PythonQtInstanceWrapper_Type)) {
217 208 meta = ((PythonQtInstanceWrapper*)type)->classInfo()->metaObject();
218 209 } else if (PyString_Check(type)) {
219 210 typeName = PyString_AsString(type);
220 211 }
221 212
222 213 QList<QObject*> list;
223 214
224 215 if (!typeName && !meta)
225 216 return list;
226 217
227 218 findChildren(parent, typeName, meta, regExp, list);
228 219
229 220 return list;
230 221 }
231 222
232 223 QObject* PythonQtStdDecorators::findChild(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name)
233 224 {
234 225 const QObjectList &children = parent->children();
235 226
236 227 int i;
237 228 for (i = 0; i < children.size(); ++i) {
238 229 QObject* obj = children.at(i);
239 230
240 231 if (!obj)
241 232 return NULL;
242 233
243 234 // Skip if the name doesn't match.
244 235 if (!name.isNull() && obj->objectName() != name)
245 236 continue;
246 237
247 if ((typeName && obj->inherits(typeName)) ||
238 if ((typeName && obj->inherits(typeName)) ||
248 239 (meta && meta->cast(obj)))
249 240 return obj;
250 241 }
251 242
252 243 for (i = 0; i < children.size(); ++i) {
253 244 QObject* obj = findChild(children.at(i), typeName, meta, name);
254 245
255 246 if (obj != NULL)
256 247 return obj;
257 248 }
258 249
259 250 return NULL;
260 251 }
261 252
262 253 int PythonQtStdDecorators::findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name, QList<QObject*>& list)
263 254 {
264 255 const QObjectList& children = parent->children();
265 256 int i;
266 257
267 258 for (i = 0; i < children.size(); ++i) {
268 259 QObject* obj = children.at(i);
269 260
270 261 if (!obj)
271 262 return -1;
272 263
273 264 // Skip if the name doesn't match.
274 265 if (!name.isNull() && obj->objectName() != name)
275 266 continue;
276 267
277 if ((typeName && obj->inherits(typeName)) ||
268 if ((typeName && obj->inherits(typeName)) ||
278 269 (meta && meta->cast(obj))) {
279 270 list += obj;
280 271 }
281 272
282 273 if (findChildren(obj, typeName, meta, name, list) < 0)
283 274 return -1;
284 275 }
285 276
286 277 return 0;
287 278 }
288 279
289 280 int PythonQtStdDecorators::findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QRegExp& regExp, QList<QObject*>& list)
290 281 {
291 282 const QObjectList& children = parent->children();
292 283 int i;
293 284
294 285 for (i = 0; i < children.size(); ++i) {
295 286 QObject* obj = children.at(i);
296 287
297 288 if (!obj)
298 289 return -1;
299 290
300 291 // Skip if the name doesn't match.
301 292 if (regExp.indexIn(obj->objectName()) == -1)
302 293 continue;
303 294
304 if ((typeName && obj->inherits(typeName)) ||
295 if ((typeName && obj->inherits(typeName)) ||
305 296 (meta && meta->cast(obj))) {
306 297 list += obj;
307 298 }
308 299
309 300 if (findChildren(obj, typeName, meta, regExp, list) < 0)
310 301 return -1;
311 302 }
312 303
313 304 return 0;
314 305 }
@@ -1,112 +1,107
1 1 #ifndef _PYTHONQTSTDDECORATORS_H
2 2 #define _PYTHONQTSTDDECORATORS_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtStdDecorators.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2007-04
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46 #include <Python.h>
47 47 #include <QObject>
48 48 #include <QVariantList>
49 49 #include <QTextDocument>
50 50 #include <QColor>
51 51 #include <QDateTime>
52 52 #include <QDate>
53 53 #include <QTime>
54 54
55 55 class PYTHONQT_EXPORT PythonQtStdDecorators : public QObject
56 56 {
57 57 Q_OBJECT
58 58
59 59 public slots:
60 60 bool connect(QObject* sender, const QByteArray& signal, PyObject* callable);
61 61 bool connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot);
62 62 bool disconnect(QObject* sender, const QByteArray& signal, PyObject* callable);
63 63 bool disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot);
64 64
65 #undef emit
66 void emit(QObject* sender, const QByteArray& signal, PyObject* arg1 = NULL,PyObject* arg2 = NULL,
67 PyObject* arg3 = NULL,PyObject* arg4 = NULL,PyObject* arg5 = NULL,PyObject* arg6 = NULL,PyObject* arg7 = NULL);
68 #define emit
69
70 65 QObject* parent(QObject* o);
71 66 void setParent(QObject* o, QObject* parent);
72 67
73 68 const QObjectList* children(QObject* o);
74 69 QObject* findChild(QObject* parent, PyObject* type, const QString& name = QString());
75 70 QList<QObject*> findChildren(QObject* parent, PyObject* type, const QString& name= QString());
76 71 QList<QObject*> findChildren(QObject* parent, PyObject* type, const QRegExp& regExp);
77
72
78 73 bool setProperty(QObject* o, const char* name, const QVariant& value);
79 74 QVariant property(QObject* o, const char* name);
80 75
81 76 double static_Qt_qAbs(double a) { return qAbs(a); }
82 77 double static_Qt_qBound(double a,double b,double c) { return qBound(a,b,c); }
83 void static_Qt_qDebug(const QByteArray& msg) { qDebug(msg.constData()); }
78 void static_Qt_qDebug(const QByteArray& msg) { qDebug("%s", msg.constData()); }
84 79 // TODO: multi arg qDebug...
85 void static_Qt_qWarning(const QByteArray& msg) { qWarning(msg.constData()); }
80 void static_Qt_qWarning(const QByteArray& msg) { qWarning("%s", msg.constData()); }
86 81 // TODO: multi arg qWarning...
87 void static_Qt_qCritical(const QByteArray& msg) { qCritical(msg.constData()); }
82 void static_Qt_qCritical(const QByteArray& msg) { qCritical("%s", msg.constData()); }
88 83 // TODO: multi arg qCritical...
89 void static_Qt_qFatal(const QByteArray& msg) { qFatal(msg.constData()); }
84 void static_Qt_qFatal(const QByteArray& msg) { qFatal("%s", msg.constData()); }
90 85 // TODO: multi arg qFatal...
91 86 bool static_Qt_qFuzzyCompare(double a, double b) { return qFuzzyCompare(a, b); }
92 87 double static_Qt_qMax(double a, double b) { return qMax(a, b); }
93 88 double static_Qt_qMin(double a, double b) { return qMin(a, b); }
94 89 int static_Qt_qRound(double a) { return qRound(a); }
95 90 qint64 static_Qt_qRound64(double a) { return qRound64(a); }
96 91 const char* static_Qt_qVersion() { return qVersion(); }
97 92 int static_Qt_qrand() { return qrand(); }
98 93 void static_Qt_qsrand(uint a) { qsrand(a); }
99 94
100 95 QString tr(QObject* obj, const QByteArray& text, const QByteArray& ambig = QByteArray(), int n = -1);
101
96
102 97 QByteArray static_Qt_SIGNAL(const QByteArray& s) { return QByteArray("2") + s; }
103 98 QByteArray static_Qt_SLOT(const QByteArray& s) { return QByteArray("1") + s; }
104 99
105 100 private:
106 101 QObject* findChild(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name);
107 102 int findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name, QList<QObject*>& list);
108 103 int findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QRegExp& regExp, QList<QObject*>& list);
109 104 };
110 105
111 106
112 107 #endif
General Comments 0
You need to be logged in to leave comments. Login now