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