##// END OF EJS Templates
support enum values on signals as well, all tests should succeed now...
florianlink -
r56:607d4eb3cb2d
parent child
Show More
@@ -1,1185 +1,1193
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtImporter.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include "PythonQtMethodInfo.h"
46 46 #include "PythonQtSignalReceiver.h"
47 47 #include "PythonQtConversion.h"
48 48 #include "PythonQtStdOut.h"
49 49 #include "PythonQtCppWrapperFactory.h"
50 50 #include "PythonQtVariants.h"
51 51 #include "PythonQtStdDecorators.h"
52 52 #include "PythonQtQFileImporter.h"
53 53 #include <pydebug.h>
54 54 #include <vector>
55 55
56 56 PythonQt* PythonQt::_self = NULL;
57 57 int PythonQt::_uniqueModuleCount = 0;
58 58
59 59 void PythonQt::init(int flags)
60 60 {
61 61 if (!_self) {
62 62 _self = new PythonQt(flags);
63 63 }
64 64
65 65 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
66 66 qRegisterMetaType<QList<QObject*> >("QList<void*>");
67 67
68 68 PythonQtRegisterToolClassesTemplateConverter(int);
69 69 PythonQtRegisterToolClassesTemplateConverter(float);
70 70 PythonQtRegisterToolClassesTemplateConverter(double);
71 71 // TODO: which other POD types should be available for QList etc.
72 72
73 73 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
74 74
75 75 PythonQt::self()->registerCPPClass("Qt", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_Qt>);
76 76 PythonQt::self()->registerCPPClass("QBitArray", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QBitArray>);
77 77 PythonQt::self()->registerCPPClass("QDate", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QDate>);
78 78 PythonQt::self()->registerCPPClass("QTime", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QTime>);
79 79 PythonQt::self()->registerCPPClass("QDateTime", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QDateTime>);
80 80 PythonQt::self()->registerCPPClass("QUrl", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QUrl>);
81 81 PythonQt::self()->registerCPPClass("QLocale", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLocale>);
82 82 PythonQt::self()->registerCPPClass("QRect", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRect>);
83 83 PythonQt::self()->registerCPPClass("QRectF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRectF>);
84 84 PythonQt::self()->registerCPPClass("QSize", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QSize>);
85 85 PythonQt::self()->registerCPPClass("QSizeF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QSizeF>);
86 86 PythonQt::self()->registerCPPClass("QLine", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLine>);
87 87 PythonQt::self()->registerCPPClass("QLineF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLineF>);
88 88 PythonQt::self()->registerCPPClass("QPoint", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QPoint>);
89 89 PythonQt::self()->registerCPPClass("QPointF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QPointF>);
90 90 PythonQt::self()->registerCPPClass("QRegExp", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRegExp>);
91 91
92 92 PythonQtRegisterToolClassesTemplateConverter(QDate);
93 93 PythonQtRegisterToolClassesTemplateConverter(QTime);
94 94 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
95 95 PythonQtRegisterToolClassesTemplateConverter(QUrl);
96 96 PythonQtRegisterToolClassesTemplateConverter(QLocale);
97 97 PythonQtRegisterToolClassesTemplateConverter(QRect);
98 98 PythonQtRegisterToolClassesTemplateConverter(QRectF);
99 99 PythonQtRegisterToolClassesTemplateConverter(QSize);
100 100 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
101 101 PythonQtRegisterToolClassesTemplateConverter(QLine);
102 102 PythonQtRegisterToolClassesTemplateConverter(QLineF);
103 103 PythonQtRegisterToolClassesTemplateConverter(QPoint);
104 104 PythonQtRegisterToolClassesTemplateConverter(QPointF);
105 105 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
106 106
107 107 PythonQt::self()->registerCPPClass("QFont", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QFont>);
108 108 PythonQt::self()->registerCPPClass("QPixmap", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPixmap>);
109 109 PythonQt::self()->registerCPPClass("QBrush", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QBrush>);
110 110 PythonQt::self()->registerCPPClass("QColor", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QColor>);
111 111 PythonQt::self()->registerCPPClass("QPalette", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPalette>);
112 112 PythonQt::self()->registerCPPClass("QIcon", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QIcon>);
113 113 PythonQt::self()->registerCPPClass("QImage", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QImage>);
114 114 PythonQt::self()->registerCPPClass("QPolygon", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPolygon>);
115 115 PythonQt::self()->registerCPPClass("QRegion", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QRegion>);
116 116 PythonQt::self()->registerCPPClass("QBitmap", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QBitmap>);
117 117 PythonQt::self()->registerCPPClass("QCursor", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QCursor>);
118 118 PythonQt::self()->registerCPPClass("QSizePolicy", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QSizePolicy>);
119 119 PythonQt::self()->registerCPPClass("QKeySequence", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QKeySequence>);
120 120 PythonQt::self()->registerCPPClass("QPen", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPen>);
121 121 PythonQt::self()->registerCPPClass("QTextLength", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QTextLength>);
122 122 PythonQt::self()->registerCPPClass("QTextFormat", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QTextFormat>);
123 123 PythonQt::self()->registerCPPClass("QMatrix", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QMatrix>);
124 124
125 125 PythonQtRegisterToolClassesTemplateConverter(QFont);
126 126 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
127 127 PythonQtRegisterToolClassesTemplateConverter(QBrush);
128 128 PythonQtRegisterToolClassesTemplateConverter(QColor);
129 129 PythonQtRegisterToolClassesTemplateConverter(QPalette);
130 130 PythonQtRegisterToolClassesTemplateConverter(QIcon);
131 131 PythonQtRegisterToolClassesTemplateConverter(QImage);
132 132 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
133 133 PythonQtRegisterToolClassesTemplateConverter(QRegion);
134 134 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
135 135 PythonQtRegisterToolClassesTemplateConverter(QCursor);
136 136 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
137 137 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
138 138 PythonQtRegisterToolClassesTemplateConverter(QPen);
139 139 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
140 140 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
141 141 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
142 142
143 143 }
144 144
145 145 void PythonQt::cleanup()
146 146 {
147 147 if (_self) {
148 148 delete _self;
149 149 _self = NULL;
150 150 }
151 151 }
152 152
153 153 PythonQt::PythonQt(int flags)
154 154 {
155 155 _p = new PythonQtPrivate;
156 156 _p->_initFlags = flags;
157 157
158 158 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
159 159
160 160 Py_SetProgramName("PythonQt");
161 161 if (flags & IgnoreSiteModule) {
162 162 // this prevents the automatic importing of Python site files
163 163 Py_NoSiteFlag = 1;
164 164 }
165 165 Py_Initialize();
166 166
167 167 // add our own python object types for qt object slots
168 168 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
169 169 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
170 170 }
171 171 Py_INCREF(&PythonQtSlotFunction_Type);
172 172
173 173 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
174 174 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
175 175 // add our own python object types for classes
176 176 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
177 177 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
178 178 }
179 179 Py_INCREF(&PythonQtClassWrapper_Type);
180 180
181 181 // add our own python object types for CPP instances
182 182 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
183 183 PythonQt::handleError();
184 184 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
185 185 }
186 186 Py_INCREF(&PythonQtInstanceWrapper_Type);
187 187
188 188 // add our own python object types for redirection of stdout
189 189 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
190 190 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
191 191 }
192 192 Py_INCREF(&PythonQtStdOutRedirectType);
193 193
194 194 initPythonQtModule(flags & RedirectStdOut);
195 195
196 196 }
197 197
198 198 PythonQt::~PythonQt() {
199 199 delete _p;
200 200 _p = NULL;
201 201 }
202 202
203 203 PythonQtPrivate::~PythonQtPrivate() {
204 204 delete _defaultImporter;
205 205 _defaultImporter = NULL;
206 206
207 207 {
208 208 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
209 209 while (i.hasNext()) {
210 210 delete i.next().value();
211 211 }
212 212 }
213 213 PythonQtConv::global_valueStorage.clear();
214 214 PythonQtConv::global_ptrStorage.clear();
215 215 PythonQtConv::global_variantStorage.clear();
216 216
217 217 PythonQtMethodInfo::cleanupCachedMethodInfos();
218 218 }
219 219
220 220 PythonQtImportFileInterface* PythonQt::importInterface()
221 221 {
222 222 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
223 223 }
224 224
225 225 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
226 226 {
227 227 if (_self->_p->_noLongerWrappedCB) {
228 228 (*_self->_p->_noLongerWrappedCB)(o);
229 229 };
230 230 }
231 231
232 232 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
233 233 {
234 234 _p->registerClass(metaobject, package, wrapperCreator, shell);
235 235 }
236 236
237 237 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
238 238 {
239 239 // we register all classes in the hierarchy
240 240 const QMetaObject* m = metaobject;
241 241 bool first = true;
242 242 while (m) {
243 243 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
244 244 if (!info->pythonQtClassWrapper()) {
245 245 info->setupQObject(m);
246 246 createPythonQtClassWrapper(info, package);
247 247 if (m->superClass()) {
248 248 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
249 249 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
250 250 }
251 251 }
252 252 if (first) {
253 253 first = false;
254 254 if (wrapperCreator) {
255 255 info->setDecoratorProvider(wrapperCreator);
256 256 }
257 257 if (shell) {
258 258 info->setShellSetInstanceWrapperCB(shell);
259 259 }
260 260 }
261 261 m = m->superClass();
262 262 }
263 263 }
264 264
265 265 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package)
266 266 {
267 267 PyObject* pack = packageByName(package);
268 268 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, package);
269 269 PyModule_AddObject(pack, info->className(), pyobj);
270 270 if (package && strncmp(package,"Qt",2)==0) {
271 271 // since PyModule_AddObject steals the reference, we need a incref once more...
272 272 Py_INCREF(pyobj);
273 273 // put all qt objects into Qt as well
274 274 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
275 275 }
276 276 info->setPythonQtClassWrapper(pyobj);
277 277 }
278 278
279 279 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
280 280 {
281 281 if (!obj) {
282 282 Py_INCREF(Py_None);
283 283 return Py_None;
284 284 }
285 285 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
286 286 if (!wrap) {
287 287 // smuggling it in...
288 288 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
289 289 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
290 290 registerClass(obj->metaObject());
291 291 classInfo = _knownClassInfos.value(obj->metaObject()->className());
292 292 }
293 293 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
294 294 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
295 295 } else {
296 296 Py_INCREF(wrap);
297 297 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
298 298 }
299 299 return (PyObject*)wrap;
300 300 }
301 301
302 302 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
303 303 {
304 304 if (!ptr) {
305 305 Py_INCREF(Py_None);
306 306 return Py_None;
307 307 }
308 308
309 309 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
310 310 if (!wrap) {
311 311 PythonQtClassInfo* info = _knownClassInfos.value(name);
312 312 if (!info) {
313 313 // maybe it is a PyObject, which we can return directly
314 314 if (name == "PyObject") {
315 315 PyObject* p = (PyObject*)ptr;
316 316 Py_INCREF(p);
317 317 return p;
318 318 }
319 319
320 320 // we do not know the metaobject yet, but we might know it by it's name:
321 321 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
322 322 // yes, we know it, so we can convert to QObject
323 323 QObject* qptr = (QObject*)ptr;
324 324 registerClass(qptr->metaObject());
325 325 info = _knownClassInfos.value(qptr->metaObject()->className());
326 326 }
327 327 }
328 328 if (info && info->isQObject()) {
329 329 QObject* qptr = (QObject*)ptr;
330 330 // if the object is a derived object, we want to switch the class info to the one of the derived class:
331 331 if (name!=(qptr->metaObject()->className())) {
332 332 registerClass(qptr->metaObject());
333 333 info = _knownClassInfos.value(qptr->metaObject()->className());
334 334 }
335 335 wrap = createNewPythonQtInstanceWrapper(qptr, info);
336 336 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
337 337 return (PyObject*)wrap;
338 338 }
339 339
340 340 // not a known QObject, so try our wrapper factory:
341 341 QObject* wrapper = NULL;
342 342 for (int i=0; i<_cppWrapperFactories.size(); i++) {
343 343 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
344 344 if (wrapper) {
345 345 break;
346 346 }
347 347 }
348 348
349 349 if (info) {
350 350 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
351 351 ptr = info->castDownIfPossible(ptr, &info);
352 352 }
353 353
354 354 if (!info || info->pythonQtClassWrapper()==NULL) {
355 355 // still unknown, register as CPP class
356 356 registerCPPClass(name.constData());
357 357 info = _knownClassInfos.value(name);
358 358 }
359 359 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
360 360 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
361 361 info->setMetaObject(wrapper->metaObject());
362 362 }
363 363 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
364 364 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
365 365 } else {
366 366 Py_INCREF(wrap);
367 367 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
368 368 }
369 369 return (PyObject*)wrap;
370 370 }
371 371
372 372 PyObject* PythonQtPrivate::dummyTuple() {
373 373 static PyObject* dummyTuple = NULL;
374 374 if (dummyTuple==NULL) {
375 375 dummyTuple = PyTuple_New(1);
376 376 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
377 377 }
378 378 return dummyTuple;
379 379 }
380 380
381 381
382 382 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
383 383 // call the associated class type to create a new instance...
384 384 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
385 385
386 386 result->setQObject(obj);
387 387 result->_wrappedPtr = wrappedPtr;
388 388 result->_ownedByPythonQt = false;
389 389 result->_useQMetaTypeDestroy = false;
390 390
391 391 if (wrappedPtr) {
392 392 _wrappedObjects.insert(wrappedPtr, result);
393 393 } else {
394 394 _wrappedObjects.insert(obj, result);
395 395 if (obj->parent()== NULL && _wrappedCB) {
396 396 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
397 397 (*_wrappedCB)(obj);
398 398 }
399 399 }
400 400 return result;
401 401 }
402 402
403 403 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package) {
404 404 PythonQtClassWrapper* result;
405 405
406 406 PyObject* className = PyString_FromString(info->className());
407 407
408 408 PyObject* baseClasses = PyTuple_New(1);
409 409 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
410 410
411 411 PyObject* typeDict = PyDict_New();
412 412 QByteArray moduleName("PythonQt");
413 413 if (package && strcmp(package, "")!=0) {
414 414 moduleName += ".";
415 415 moduleName += package;
416 416 }
417 417 PyDict_SetItemString(typeDict, "__module__", PyString_FromString(moduleName.constData()));
418 418
419 419 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
420 420
421 421 // set the class info so that PythonQtClassWrapper_new can read it
422 422 _currentClassInfoForClassWrapperCreation = info;
423 423 // create the new type object by calling the type
424 424 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
425 425
426 426 Py_DECREF(baseClasses);
427 427 Py_DECREF(typeDict);
428 428 Py_DECREF(args);
429 429 Py_DECREF(className);
430 430
431 431 return result;
432 432 }
433 433
434 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
435 {
436 PyObject* args = Py_BuildValue("(i)", enumValue);
437 PyObject* result = PyObject_Call(enumType, args, NULL);
438 Py_DECREF(args);
439 return result;
440 }
441
434 442 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
435 443 PyObject* result;
436 444
437 445 PyObject* className = PyString_FromString(enumName);
438 446
439 447 PyObject* baseClasses = PyTuple_New(1);
440 448 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
441 449
442 450 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
443 451 PyObject* typeDict = PyDict_New();
444 452 PyDict_SetItemString(typeDict, "__module__", module);
445 453
446 454 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
447 455
448 456 // create the new int derived type object by calling the core type
449 457 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
450 458
451 459 Py_DECREF(baseClasses);
452 460 Py_DECREF(typeDict);
453 461 Py_DECREF(args);
454 462 Py_DECREF(className);
455 463
456 464 return result;
457 465 }
458 466
459 467 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
460 468 {
461 469 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
462 470 if (!r) {
463 471 r = new PythonQtSignalReceiver(obj);
464 472 _p->_signalReceivers.insert(obj, r);
465 473 }
466 474 return r;
467 475 }
468 476
469 477 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
470 478 {
471 479 bool flag = false;
472 480 PythonQtObjectPtr callable = lookupCallable(module, objectname);
473 481 if (callable) {
474 482 PythonQtSignalReceiver* r = getSignalReceiver(obj);
475 483 flag = r->addSignalHandler(signal, callable);
476 484 if (!flag) {
477 485 // signal not found
478 486 }
479 487 } else {
480 488 // callable not found
481 489 }
482 490 return flag;
483 491 }
484 492
485 493 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
486 494 {
487 495 bool flag = false;
488 496 PythonQtSignalReceiver* r = getSignalReceiver(obj);
489 497 if (r) {
490 498 flag = r->addSignalHandler(signal, receiver);
491 499 }
492 500 return flag;
493 501 }
494 502
495 503 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
496 504 {
497 505 bool flag = false;
498 506 PythonQtObjectPtr callable = lookupCallable(module, objectname);
499 507 if (callable) {
500 508 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
501 509 if (r) {
502 510 flag = r->removeSignalHandler(signal, callable);
503 511 }
504 512 } else {
505 513 // callable not found
506 514 }
507 515 return flag;
508 516 }
509 517
510 518 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
511 519 {
512 520 bool flag = false;
513 521 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
514 522 if (r) {
515 523 flag = r->removeSignalHandler(signal, receiver);
516 524 }
517 525 return flag;
518 526 }
519 527
520 528 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
521 529 {
522 530 PythonQtObjectPtr p = lookupObject(module, name);
523 531 if (p) {
524 532 if (PyCallable_Check(p)) {
525 533 return p;
526 534 }
527 535 }
528 536 PyErr_Clear();
529 537 return NULL;
530 538 }
531 539
532 540 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
533 541 {
534 542 QStringList l = name.split('.');
535 543 PythonQtObjectPtr p = module;
536 544 PythonQtObjectPtr prev;
537 545 QString s;
538 546 QByteArray b;
539 547 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
540 548 prev = p;
541 549 b = (*i).toLatin1();
542 550 if (PyDict_Check(p)) {
543 551 p = PyDict_GetItemString(p, b.data());
544 552 } else {
545 553 p.setNewRef(PyObject_GetAttrString(p, b.data()));
546 554 }
547 555 }
548 556 PyErr_Clear();
549 557 return p;
550 558 }
551 559
552 560 PythonQtObjectPtr PythonQt::getMainModule() {
553 561 //both borrowed
554 562 PythonQtObjectPtr dict = PyImport_GetModuleDict();
555 563 return PyDict_GetItemString(dict, "__main__");
556 564 }
557 565
558 566 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
559 567 QVariant result;
560 568 if (pycode) {
561 569 PyObject* dict = NULL;
562 570 if (PyModule_Check(object)) {
563 571 dict = PyModule_GetDict(object);
564 572 } else if (PyDict_Check(object)) {
565 573 dict = object;
566 574 }
567 575 PyObject* r = NULL;
568 576 if (dict) {
569 577 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
570 578 }
571 579 if (r) {
572 580 result = PythonQtConv::PyObjToQVariant(r);
573 581 Py_DECREF(r);
574 582 } else {
575 583 handleError();
576 584 }
577 585 } else {
578 586 handleError();
579 587 }
580 588 return result;
581 589 }
582 590
583 591 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
584 592 {
585 593 QVariant result;
586 594 PythonQtObjectPtr p;
587 595 PyObject* dict = NULL;
588 596 if (PyModule_Check(object)) {
589 597 dict = PyModule_GetDict(object);
590 598 } else if (PyDict_Check(object)) {
591 599 dict = object;
592 600 }
593 601 if (dict) {
594 602 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
595 603 }
596 604 if (p) {
597 605 result = PythonQtConv::PyObjToQVariant(p);
598 606 } else {
599 607 handleError();
600 608 }
601 609 return result;
602 610 }
603 611
604 612 void PythonQt::evalFile(PyObject* module, const QString& filename)
605 613 {
606 614 PythonQtObjectPtr code = parseFile(filename);
607 615 if (code) {
608 616 evalCode(module, code);
609 617 } else {
610 618 handleError();
611 619 }
612 620 }
613 621
614 622 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
615 623 {
616 624 PythonQtObjectPtr p;
617 625 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
618 626 if (!p) {
619 627 handleError();
620 628 }
621 629 return p;
622 630 }
623 631
624 632 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
625 633 {
626 634 PythonQtObjectPtr code = parseFile(filename);
627 635 PythonQtObjectPtr module = _p->createModule(name, code);
628 636 return module;
629 637 }
630 638
631 639 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
632 640 {
633 641 PyErr_Clear();
634 642 QString scriptCode = script;
635 643 if (scriptCode.isEmpty()) {
636 644 // we always need at least a linefeed
637 645 scriptCode = "\n";
638 646 }
639 647 PythonQtObjectPtr pycode;
640 648 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
641 649 PythonQtObjectPtr module = _p->createModule(name, pycode);
642 650 return module;
643 651 }
644 652
645 653 PythonQtObjectPtr PythonQt::createUniqueModule()
646 654 {
647 655 static QString pyQtStr("PythonQt_module");
648 656 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
649 657 return createModuleFromScript(moduleName);
650 658 }
651 659
652 660 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
653 661 {
654 662 if (PyModule_Check(object)) {
655 663 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
656 664 } else if (PyDict_Check(object)) {
657 665 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
658 666 } else {
659 667 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
660 668 }
661 669 }
662 670
663 671 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
664 672 {
665 673 if (PyModule_Check(object)) {
666 674 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
667 675 } else if (PyDict_Check(object)) {
668 676 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
669 677 } else {
670 678 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
671 679 }
672 680 }
673 681
674 682 void PythonQt::removeVariable(PyObject* object, const QString& name)
675 683 {
676 684 if (PyDict_Check(object)) {
677 685 PyDict_DelItemString(object, name.toLatin1().data());
678 686 } else {
679 687 PyObject_DelAttrString(object, name.toLatin1().data());
680 688 }
681 689 }
682 690
683 691 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
684 692 {
685 693 QVariant result;
686 694 PythonQtObjectPtr obj = lookupObject(object, objectname);
687 695 if (obj) {
688 696 result = PythonQtConv::PyObjToQVariant(obj);
689 697 }
690 698 return result;
691 699 }
692 700
693 701 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
694 702 {
695 703 QStringList results;
696 704
697 705 PythonQtObjectPtr object;
698 706 if (objectname.isEmpty()) {
699 707 object = module;
700 708 } else {
701 709 object = lookupObject(module, objectname);
702 710 if (!object && type == CallOverloads) {
703 711 PyObject* dict = lookupObject(module, "__builtins__");
704 712 if (dict) {
705 713 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
706 714 }
707 715 }
708 716 }
709 717
710 718 if (object) {
711 719 if (type == CallOverloads) {
712 720 if (PythonQtSlotFunction_Check(object)) {
713 721 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
714 722 PythonQtSlotInfo* info = o->m_ml;
715 723
716 724 while (info) {
717 725 results << info->fullSignature();
718 726 info = info->nextInfo();
719 727 }
720 728 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
721 729 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
722 730 PythonQtSlotInfo* info = o->classInfo()->constructors();
723 731
724 732 while (info) {
725 733 results << info->fullSignature();
726 734 info = info->nextInfo();
727 735 }
728 736 } else {
729 737 //TODO: use pydoc!
730 738 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
731 739 if (doc) {
732 740 results << PyString_AsString(doc);
733 741 Py_DECREF(doc);
734 742 }
735 743 }
736 744 } else {
737 745 PyObject* keys = NULL;
738 746 bool isDict = false;
739 747 if (PyDict_Check(object)) {
740 748 keys = PyDict_Keys(object);
741 749 isDict = true;
742 750 } else {
743 751 keys = PyObject_Dir(object);
744 752 }
745 753 if (keys) {
746 754 int count = PyList_Size(keys);
747 755 PyObject* key;
748 756 PyObject* value;
749 757 QString keystr;
750 758 for (int i = 0;i<count;i++) {
751 759 key = PyList_GetItem(keys,i);
752 760 if (isDict) {
753 761 value = PyDict_GetItem(object, key);
754 762 Py_INCREF(value);
755 763 } else {
756 764 value = PyObject_GetAttr(object, key);
757 765 }
758 766 if (!value) continue;
759 767 keystr = PyString_AsString(key);
760 768 static const QString underscoreStr("__tmp");
761 769 if (!keystr.startsWith(underscoreStr)) {
762 770 switch (type) {
763 771 case Anything:
764 772 results << keystr;
765 773 break;
766 774 case Class:
767 775 if (value->ob_type == &PyClass_Type) {
768 776 results << keystr;
769 777 }
770 778 break;
771 779 case Variable:
772 780 if (value->ob_type != &PyClass_Type
773 781 && value->ob_type != &PyCFunction_Type
774 782 && value->ob_type != &PyFunction_Type
775 783 && value->ob_type != &PyModule_Type
776 784 ) {
777 785 results << keystr;
778 786 }
779 787 break;
780 788 case Function:
781 789 if (value->ob_type == &PyFunction_Type ||
782 790 value->ob_type == &PyMethod_Type
783 791 ) {
784 792 results << keystr;
785 793 }
786 794 break;
787 795 case Module:
788 796 if (value->ob_type == &PyModule_Type) {
789 797 results << keystr;
790 798 }
791 799 break;
792 800 default:
793 801 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
794 802 }
795 803 }
796 804 Py_DECREF(value);
797 805 }
798 806 Py_DECREF(keys);
799 807 }
800 808 }
801 809 }
802 810 return results;
803 811 }
804 812
805 813 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
806 814 {
807 815 PythonQtObjectPtr callable = lookupCallable(object, name);
808 816 if (callable) {
809 817 return call(callable, args);
810 818 } else {
811 819 return QVariant();
812 820 }
813 821 }
814 822
815 823 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
816 824 {
817 825 QVariant r;
818 826 if (callable) {
819 827 PythonQtObjectPtr pargs;
820 828 int count = args.size();
821 829 if (count>0) {
822 830 pargs.setNewRef(PyTuple_New(count));
823 831 }
824 832 bool err = false;
825 833 // transform QVariants to Python
826 834 for (int i = 0; i < count; i++) {
827 835 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
828 836 if (arg) {
829 837 // steals reference, no unref
830 838 PyTuple_SetItem(pargs, i,arg);
831 839 } else {
832 840 err = true;
833 841 break;
834 842 }
835 843 }
836 844
837 845 if (!err) {
838 846 PyErr_Clear();
839 847 PythonQtObjectPtr result;
840 848 result.setNewRef(PyObject_CallObject(callable, pargs));
841 849 if (result) {
842 850 // ok
843 851 r = PythonQtConv::PyObjToQVariant(result);
844 852 } else {
845 853 PythonQt::self()->handleError();
846 854 }
847 855 }
848 856 }
849 857 return r;
850 858 }
851 859
852 860 void PythonQt::addInstanceDecorators(QObject* o)
853 861 {
854 862 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
855 863 }
856 864
857 865 void PythonQt::addClassDecorators(QObject* o)
858 866 {
859 867 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
860 868 }
861 869
862 870 void PythonQt::addDecorators(QObject* o)
863 871 {
864 872 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
865 873 }
866 874
867 875 void PythonQt::registerQObjectClassNames(const QStringList& names)
868 876 {
869 877 _p->registerQObjectClassNames(names);
870 878 }
871 879
872 880 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
873 881 {
874 882 PythonQtImport::init();
875 883 _p->_importInterface = importInterface;
876 884 }
877 885
878 886 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
879 887 {
880 888 _p->_importIgnorePaths = paths;
881 889 }
882 890
883 891 const QStringList& PythonQt::getImporterIgnorePaths()
884 892 {
885 893 return _p->_importIgnorePaths;
886 894 }
887 895
888 896 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
889 897 {
890 898 _p->_cppWrapperFactories.append(factory);
891 899 }
892 900
893 901 //---------------------------------------------------------------------------------------------------
894 902 PythonQtPrivate::PythonQtPrivate()
895 903 {
896 904 _importInterface = NULL;
897 905 _defaultImporter = new PythonQtQFileImporter;
898 906 _noLongerWrappedCB = NULL;
899 907 _wrappedCB = NULL;
900 908 _currentClassInfoForClassWrapperCreation = NULL;
901 909 }
902 910
903 911 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
904 912 {
905 913 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
906 914 _currentClassInfoForClassWrapperCreation = NULL;
907 915 return info;
908 916 }
909 917
910 918 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
911 919 {
912 920 o->setParent(this);
913 921 int numMethods = o->metaObject()->methodCount();
914 922 for (int i = 0; i < numMethods; i++) {
915 923 QMetaMethod m = o->metaObject()->method(i);
916 924 if ((m.methodType() == QMetaMethod::Method ||
917 925 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
918 926 if (qstrncmp(m.signature(), "new_", 4)==0) {
919 927 if ((decoTypes & ConstructorDecorator) == 0) continue;
920 928 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
921 929 if (info->parameters().at(0).isPointer) {
922 930 QByteArray signature = m.signature();
923 931 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
924 932 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
925 933 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
926 934 classInfo->addConstructor(newSlot);
927 935 }
928 936 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
929 937 if ((decoTypes & DestructorDecorator) == 0) continue;
930 938 QByteArray signature = m.signature();
931 939 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
932 940 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
933 941 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
934 942 classInfo->setDestructor(newSlot);
935 943 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
936 944 if ((decoTypes & StaticDecorator) == 0) continue;
937 945 QByteArray signature = m.signature();
938 946 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
939 947 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
940 948 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
941 949 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
942 950 classInfo->addDecoratorSlot(newSlot);
943 951 } else {
944 952 if ((decoTypes & InstanceDecorator) == 0) continue;
945 953 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
946 954 if (info->parameters().count()>1) {
947 955 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
948 956 if (p.isPointer) {
949 957 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
950 958 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
951 959 classInfo->addDecoratorSlot(newSlot);
952 960 }
953 961 }
954 962 }
955 963 }
956 964 }
957 965 }
958 966
959 967 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
960 968 {
961 969 foreach(QString name, names) {
962 970 _knownQObjectClassNames.insert(name.toLatin1(), true);
963 971 }
964 972 }
965 973
966 974 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
967 975 {
968 976 _signalReceivers.remove(obj);
969 977 }
970 978
971 979 bool PythonQt::handleError()
972 980 {
973 981 bool flag = false;
974 982 if (PyErr_Occurred()) {
975 983
976 984 // currently we just print the error and the stderr handler parses the errors
977 985 PyErr_Print();
978 986
979 987 /*
980 988 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
981 989 PyObject *ptype;
982 990 PyObject *pvalue;
983 991 PyObject *ptraceback;
984 992 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
985 993
986 994 Py_XDECREF(ptype);
987 995 Py_XDECREF(pvalue);
988 996 Py_XDECREF(ptraceback);
989 997 */
990 998 PyErr_Clear();
991 999 flag = true;
992 1000 }
993 1001 return flag;
994 1002 }
995 1003
996 1004 void PythonQt::addSysPath(const QString& path)
997 1005 {
998 1006 PythonQtObjectPtr sys;
999 1007 sys.setNewRef(PyImport_ImportModule("sys"));
1000 1008 PythonQtObjectPtr obj = lookupObject(sys, "path");
1001 1009 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1002 1010 }
1003 1011
1004 1012 void PythonQt::overwriteSysPath(const QStringList& paths)
1005 1013 {
1006 1014 PythonQtObjectPtr sys;
1007 1015 sys.setNewRef(PyImport_ImportModule("sys"));
1008 1016 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1009 1017 }
1010 1018
1011 1019 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1012 1020 {
1013 1021 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1014 1022 }
1015 1023
1016 1024 void PythonQt::stdOutRedirectCB(const QString& str)
1017 1025 {
1018 1026 emit PythonQt::self()->pythonStdOut(str);
1019 1027 }
1020 1028
1021 1029 void PythonQt::stdErrRedirectCB(const QString& str)
1022 1030 {
1023 1031 emit PythonQt::self()->pythonStdErr(str);
1024 1032 }
1025 1033
1026 1034 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1027 1035 {
1028 1036 _p->_wrappedCB = cb;
1029 1037 }
1030 1038
1031 1039 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1032 1040 {
1033 1041 _p->_noLongerWrappedCB = cb;
1034 1042 }
1035 1043
1036 1044
1037 1045
1038 1046 static PyMethodDef PythonQtMethods[] = {
1039 1047 {NULL, NULL, 0, NULL}
1040 1048 };
1041 1049
1042 1050 void PythonQt::initPythonQtModule(bool redirectStdOut)
1043 1051 {
1044 1052 _p->_pythonQtModule = Py_InitModule("PythonQt", PythonQtMethods);
1045 1053
1046 1054 if (redirectStdOut) {
1047 1055 PythonQtObjectPtr sys;
1048 1056 PythonQtObjectPtr out;
1049 1057 PythonQtObjectPtr err;
1050 1058 sys.setNewRef(PyImport_ImportModule("sys"));
1051 1059 // create a redirection object for stdout and stderr
1052 1060 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1053 1061 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1054 1062 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1055 1063 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1056 1064 // replace the built in file objects with our own objects
1057 1065 PyModule_AddObject(sys, "stdout", out);
1058 1066 PyModule_AddObject(sys, "stderr", err);
1059 1067 }
1060 1068 }
1061 1069
1062 1070 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1063 1071 {
1064 1072 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1065 1073 }
1066 1074
1067 1075
1068 1076 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1069 1077 {
1070 1078 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1071 1079 if (!info) {
1072 1080 info = new PythonQtClassInfo();
1073 1081 info->setupCPPObject(typeName);
1074 1082 _knownClassInfos.insert(typeName, info);
1075 1083 }
1076 1084 return info;
1077 1085 }
1078 1086
1079 1087 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1080 1088 {
1081 1089 _p->addPolymorphicHandler(typeName, cb);
1082 1090 }
1083 1091
1084 1092 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1085 1093 {
1086 1094 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1087 1095 info->addPolymorphicHandler(cb);
1088 1096 }
1089 1097
1090 1098 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1091 1099 {
1092 1100 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1093 1101 }
1094 1102
1095 1103 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1096 1104 {
1097 1105 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1098 1106 if (info) {
1099 1107 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1100 1108 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1101 1109 return true;
1102 1110 } else {
1103 1111 return false;
1104 1112 }
1105 1113 }
1106 1114
1107 1115 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1108 1116 {
1109 1117 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1110 1118 if (!info->pythonQtClassWrapper()) {
1111 1119 info->setupCPPObject(typeName);
1112 1120 createPythonQtClassWrapper(info, package);
1113 1121 }
1114 1122 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1115 1123 addParentClass(typeName, parentTypeName, 0);
1116 1124 }
1117 1125 if (wrapperCreator) {
1118 1126 info->setDecoratorProvider(wrapperCreator);
1119 1127 }
1120 1128 if (shell) {
1121 1129 info->setShellSetInstanceWrapperCB(shell);
1122 1130 }
1123 1131 }
1124 1132
1125 1133 PyObject* PythonQtPrivate::packageByName(const char* name)
1126 1134 {
1127 1135 if (name==NULL || name[0]==0) {
1128 1136 return _pythonQtModule;
1129 1137 }
1130 1138 PyObject* v = _packages.value(name);
1131 1139 if (!v) {
1132 1140 v = PyImport_AddModule((QByteArray("PythonQt.") + name).constData());
1133 1141 _packages.insert(name, v);
1134 1142 // AddObject steals the reference, so increment it!
1135 1143 Py_INCREF(v);
1136 1144 PyModule_AddObject(_pythonQtModule, name, v);
1137 1145 }
1138 1146 return v;
1139 1147 }
1140 1148
1141 1149
1142 1150 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1143 1151 {
1144 1152 if (_p->_initFlags & ExternalHelp) {
1145 1153 emit pythonHelpRequest(QByteArray(info->className()));
1146 1154 return Py_BuildValue("");
1147 1155 } else {
1148 1156 return PyString_FromString(info->help().toLatin1().data());
1149 1157 }
1150 1158 }
1151 1159
1152 1160 void PythonQtPrivate::removeWrapperPointer(void* obj)
1153 1161 {
1154 1162 _wrappedObjects.remove(obj);
1155 1163 }
1156 1164
1157 1165 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1158 1166 {
1159 1167 _wrappedObjects.insert(obj, wrapper);
1160 1168 }
1161 1169
1162 1170 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1163 1171 {
1164 1172 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1165 1173 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1166 1174 // this is a wrapper whose QObject was already removed due to destruction
1167 1175 // so the obj pointer has to be a new QObject with the same address...
1168 1176 // we remove the old one and set the copy to NULL
1169 1177 wrap->_objPointerCopy = NULL;
1170 1178 removeWrapperPointer(obj);
1171 1179 wrap = NULL;
1172 1180 }
1173 1181 return wrap;
1174 1182 }
1175 1183
1176 1184 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1177 1185 {
1178 1186 PythonQtObjectPtr result;
1179 1187 if (pycode) {
1180 1188 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1181 1189 } else {
1182 1190 PythonQt::self()->handleError();
1183 1191 }
1184 1192 return result;
1185 1193 }
@@ -1,520 +1,523
1 1 #ifndef _PYTHONQT_H
2 2 #define _PYTHONQT_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQt.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46 #include "PythonQtInstanceWrapper.h"
47 47 #include "PythonQtClassWrapper.h"
48 48 #include "PythonQtSlot.h"
49 49 #include "PythonQtObjectPtr.h"
50 50 #include <QObject>
51 51 #include <QVariant>
52 52 #include <QList>
53 53 #include <QHash>
54 54 #include <QByteArray>
55 55 #include <QStringList>
56 56 #include <QtDebug>
57 57 #include <iostream>
58 58
59 59
60 60 class PythonQtClassInfo;
61 61 class PythonQtPrivate;
62 62 class PythonQtMethodInfo;
63 63 class PythonQtSignalReceiver;
64 64 class PythonQtImportFileInterface;
65 65 class PythonQtCppWrapperFactory;
66 66 class PythonQtQFileImporter;
67 67
68 68 typedef void PythonQtQObjectWrappedCB(QObject* object);
69 69 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
70 70 typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, char **class_name);
71 71
72 72 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
73 73
74 74 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) { ((T*)object)->_wrapper = wrapper; };
75 75
76 76 //! returns the offset that needs to be added to upcast an object of type T1 to T2
77 77 template<class T1, class T2> int PythonQtUpcastingOffset() {
78 78 return (((char*)(static_cast<T2*>(reinterpret_cast<T1*>(0x100)))) - ((char*)reinterpret_cast<T1*>(0x100)));
79 79 }
80 80
81 81 //! callback to create a QObject lazily
82 82 typedef QObject* PythonQtQObjectCreatorFunctionCB();
83 83
84 84 //! helper template to create a derived QObject class
85 85 template<class T> QObject* PythonQtCreateObject() { return new T(); };
86 86
87 87 //! the main interface to the Python Qt binding, realized as a singleton
88 88 class PYTHONQT_EXPORT PythonQt : public QObject {
89 89
90 90 Q_OBJECT
91 91
92 92 public:
93 93 enum InitFlags {
94 94 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
95 95 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
96 96 ExternalHelp = 4 //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
97 97 };
98 98
99 99 //! initialize the python qt binding (flags are a or combination of InitFlags)
100 100 static void init(int flags = IgnoreSiteModule | RedirectStdOut);
101 101
102 102 //! cleanup
103 103 static void cleanup();
104 104
105 105 //! get the singleton instance
106 106 static PythonQt* self() { return _self; }
107 107
108 108 //-----------------------------------------------------------------------------
109 109 // Public API:
110 110
111 111 //! defines the object types for introspection
112 112 enum ObjectType {
113 113 Class,
114 114 Function,
115 115 Variable,
116 116 Module,
117 117 Anything,
118 118 CallOverloads
119 119 };
120 120
121 121 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
122 122 void overwriteSysPath(const QStringList& paths);
123 123
124 124 //! prepend a path to sys.path to allow importing from it
125 125 void addSysPath(const QString& path);
126 126
127 127 //! sets the __path__ list of a module to the given list (important for local imports)
128 128 void setModuleImportPath(PyObject* module, const QStringList& paths);
129 129
130 130 //! get the __main__ module of python
131 131 PythonQtObjectPtr getMainModule();
132 132
133 133 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
134 134 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
135 135 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
136 136 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
137 137
138 138 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
139 139 //! (ownership of wrapper is passed to PythonQt)
140 140 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
141 141
142 142 This will add a wrapper object that is used to make calls to the given classname \c typeName.
143 143 All slots that take a pointer to typeName as the first argument will be callable from Python on
144 144 a variant object that contains such a type.
145 145 */
146 146 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
147 147
148 148 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
149 149 //! and it will register the classes when it first sees a pointer to such a derived class
150 150 void registerQObjectClassNames(const QStringList& names);
151 151
152 152 //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance
153 153 //! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that
154 154 //! type is really derived from parentType.
155 155 //! Returns false if the typeName was not yet registered.
156 156 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
157 157
158 158 //! add a handler for polymorphic downcasting
159 159 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
160 160
161 161 //! parses the given file and returns the python code object, this can then be used to call evalCode()
162 162 PythonQtObjectPtr parseFile(const QString& filename);
163 163
164 164 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
165 165 //! If pycode is NULL, a python error is printed.
166 166 QVariant evalCode(PyObject* object, PyObject* pycode);
167 167
168 168 //! evaluates the given script code and returns the result value
169 169 QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input);
170 170
171 171 //! evaluates the given script code from file
172 172 void evalFile(PyObject* object, const QString& filename);
173 173
174 174 //! creates the new module \c name and evaluates the given file in the context of that module
175 175 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
176 176 //! to a module later on.
177 177 //! The user needs to make sure that the \c name is unique in the python module dictionary.
178 178 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
179 179
180 180 //! creates the new module \c name and evaluates the given script in the context of that module.
181 181 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
182 182 //! to a module later on.
183 183 //! The user needs to make sure that the \c name is unique in the python module dictionary.
184 184 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
185 185
186 186 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
187 187 //! script code
188 188 PythonQtObjectPtr createUniqueModule();
189 189
190 190 //@{ Signal handlers
191 191
192 192 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
193 193 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
194 194
195 195 //! remove a signal handler from the given \c signal of \c obj
196 196 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
197 197
198 198 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
199 199 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
200 200
201 201 //! remove a signal handler from the given \c signal of \c obj
202 202 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
203 203
204 204 //@}
205 205
206 206 //@{ Variable access
207 207
208 208 //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable)
209 209 void addObject(PyObject* object, const QString& name, QObject* qObject);
210 210
211 211 //! add the given variable to the object
212 212 void addVariable(PyObject* object, const QString& name, const QVariant& v);
213 213
214 214 //! remove the given variable
215 215 void removeVariable(PyObject* module, const QString& name);
216 216
217 217 //! get the variable with the \c name of the \c object, returns an invalid QVariant on error
218 218 QVariant getVariable(PyObject* object, const QString& name);
219 219
220 220 //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname
221 221 QStringList introspection(PyObject* object, const QString& objectname, ObjectType type);
222 222
223 223 //! returns the found callable object or NULL
224 224 //! @return new reference
225 225 PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
226 226
227 227 //@}
228 228
229 229 //@{ Calling of python callables
230 230
231 231 //! call the given python \c callable in the scope of object, returns the result converted to a QVariant
232 232 QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList());
233 233
234 234 //! call the given python object, returns the result converted to a QVariant
235 235 QVariant call(PyObject* callable, const QVariantList& args = QVariantList());
236 236
237 237 //@}
238 238
239 239 //@{ Decorations, constructors, wrappers...
240 240
241 241
242 242 //! add an object whose slots will be used as decorator slots for
243 243 //! other QObjects or CPP classes. The slots need to follow the
244 244 //! convention that the first argument is a pointer to the wrapped object.
245 245 //! (ownership is passed to PythonQt)
246 246 /*!
247 247 Example:
248 248
249 249 A slot with the signature
250 250
251 251 \code
252 252 bool doSomething(QWidget* w, int a)
253 253 \endcode
254 254
255 255 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
256 256 that will be called with the concrete instance as first argument.
257 257 So in Python you can now e.g. call
258 258
259 259 \code
260 260 someWidget.doSomething(12)
261 261 \endcode
262 262
263 263 without QWidget really having this method. This allows to easily make normal methods
264 264 of Qt classes callable by forwarding them with such decorator slots
265 265 or to make CPP classes (which are not derived from QObject) callable from Python.
266 266 */
267 267 void addInstanceDecorators(QObject* o);
268 268
269 269 //! add an object whose slots will be used as decorator slots for
270 270 //! class objects (ownership is passed to PythonQt)
271 271 /*!
272 272 The slots need to follow the following convention:
273 273 - SomeClass* new_SomeClass(...)
274 274 - QVariant new_SomeClass(...)
275 275 - void delete_SomeClass(SomeClass*)
276 276 - ... static_SomeClass_someName(...)
277 277
278 278 This will add:
279 279 - a constructor
280 280 - a constructor which generates a QVariant
281 281 - a destructor (only useful for CPP objects)
282 282 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
283 283
284 284 */
285 285 void addClassDecorators(QObject* o);
286 286
287 287 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
288 288 void addDecorators(QObject* o);
289 289
290 290 //! add the given factory to PythonQt (ownership stays with caller)
291 291 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
292 292
293 293 //@}
294 294
295 295 //@{ Custom importer (to replace internal import implementation of python)
296 296
297 297 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
298 298 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
299 299 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
300 300 //! This is not reversible, so even setting setImporter(NULL) afterwards will
301 301 //! keep the custom PythonQt importer with a QFile default import interface.
302 302 //! Subsequent python import calls will make use of the passed importInterface
303 303 //! which forwards all import calls to the given \c importInterface.
304 304 //! Passing NULL will install a default QFile importer.
305 305 //! (\c importInterface ownership stays with caller)
306 306 void setImporter(PythonQtImportFileInterface* importInterface);
307 307
308 308 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
309 309 //! (without calling setImporter or installDefaultImporter at least once, the default python import
310 310 //! mechanism is in place)
311 311 //! the default importer allows to import files from anywhere QFile can read from,
312 312 //! including the Qt resource system using ":". Keep in mind that you need to extend
313 313 //! "sys.path" with ":" to be able to import from the Qt resources.
314 314 void installDefaultImporter() { setImporter(NULL); }
315 315
316 316 //! set paths that the importer should ignore
317 317 void setImporterIgnorePaths(const QStringList& paths);
318 318
319 319 //! get paths that the importer should ignore
320 320 const QStringList& getImporterIgnorePaths();
321 321
322 322 //@}
323 323
324 324 //! get access to internal data (should not be used on the public API, but is used by some C functions)
325 325 static PythonQtPrivate* priv() { return _self->_p; }
326 326
327 327 //! get access to the file importer (if set)
328 328 static PythonQtImportFileInterface* importInterface();
329 329
330 330 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
331 331 //! The error is currently just output to the python stderr, future version might implement better trace printing
332 332 bool handleError();
333 333
334 334 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
335 335 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
336 336 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
337 337 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
338 338
339 339 //! call the callback if it is set
340 340 static void qObjectNoLongerWrappedCB(QObject* o);
341 341
342 342 signals:
343 343 //! emitted when python outputs something to stdout (and redirection is turned on)
344 344 void pythonStdOut(const QString& str);
345 345 //! emitted when python outputs something to stderr (and redirection is turned on)
346 346 void pythonStdErr(const QString& str);
347 347
348 348 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
349 349 void pythonHelpRequest(const QByteArray& cppClassName);
350 350
351 351
352 352 public:
353 353 //! called by internal help methods
354 354 PyObject* helpCalled(PythonQtClassInfo* info);
355 355
356 356 //! returns the found object or NULL
357 357 //! @return new reference
358 358 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
359 359
360 360 private:
361 361 void initPythonQtModule(bool redirectStdOut);
362 362
363 363 //! callback for stdout redirection, emits pythonStdOut signal
364 364 static void stdOutRedirectCB(const QString& str);
365 365 //! callback for stderr redirection, emits pythonStdErr signal
366 366 static void stdErrRedirectCB(const QString& str);
367 367
368 368 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
369 369 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
370 370
371 371 PythonQt(int flags);
372 372 ~PythonQt();
373 373
374 374 static PythonQt* _self;
375 375 static int _uniqueModuleCount;
376 376
377 377 PythonQtPrivate* _p;
378 378
379 379 };
380 380
381 381 //! internal PythonQt details
382 382 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
383 383
384 384 Q_OBJECT
385 385
386 386 public:
387 387 PythonQtPrivate();
388 388 ~PythonQtPrivate();
389 389
390 390 enum DecoratorTypes {
391 391 StaticDecorator = 1,
392 392 ConstructorDecorator = 2,
393 393 DestructorDecorator = 4,
394 394 InstanceDecorator = 8,
395 395 AllDecorators = 0xffff
396 396 };
397 397
398 398 //! returns if the id is the id for PythonQtObjectPtr
399 399 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
400 400
401 401 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
402 402 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
403 403 //! remove the wrapper ptr again
404 404 void removeWrapperPointer(void* obj);
405 405
406 406 //! add parent class relation
407 407 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
408 408
409 409 //! add a handler for polymorphic downcasting
410 410 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
411 411
412 412 //! lookup existing classinfo and return new if not yet present
413 413 PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
414 414
415 415 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
416 416 void removeSignalEmitter(QObject* obj);
417 417
418 418 //! wrap the given QObject into a Python object (or return existing wrapper!)
419 419 PyObject* wrapQObject(QObject* obj);
420 420
421 421 //! 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
422 422 PyObject* wrapPtr(void* ptr, const QByteArray& name);
423 423
424 424 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
425 425 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
426 426 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
427 427 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
428 428
429 429 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
430 430 //! (ownership of wrapper is passed to PythonQt)
431 431 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
432 432
433 433 This will add a wrapper object that is used to make calls to the given classname \c typeName.
434 434 All slots that take a pointer to typeName as the first argument will be callable from Python on
435 435 a variant object that contains such a type.
436 436 */
437 437 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
438 438
439 439 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
440 440 //! and it will register the classes when it first sees a pointer to such a derived class
441 441 void registerQObjectClassNames(const QStringList& names);
442 442
443 443 //! add a decorator object
444 444 void addDecorators(QObject* o, int decoTypes);
445 445
446 //! helper method that creates a PythonQtClassWrapper object
446 //! helper method that creates a PythonQtClassWrapper object (returns a new reference)
447 447 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package = NULL);
448 448
449 //! helper that creates a new int derived class that represents the enum of the given name
450 PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
449 //! create a new instance of the given enum type with given value (returns a new reference)
450 static PyObject* createEnumValueInstance(PyObject* enumType, unsigned int enumValue);
451
452 //! helper that creates a new int derived class that represents the enum of the given name (returns a new reference)
453 static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
451 454
452 455 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
453 456 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
454 457
455 458 //! get the class info for a meta object (if available)
456 459 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
457 460
458 461 //! get the class info for a meta object (if available)
459 462 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
460 463
461 464 //! creates the new module from the given pycode
462 465 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
463 466
464 467 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
465 468 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
466 469
467 470 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
468 471 static PyObject* dummyTuple();
469 472
470 473 private:
471 474
472 475 //! create a new pythonqt class wrapper and place it in the pythonqt module
473 476 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package);
474 477
475 478 //! get/create new package module (the returned object is a borrowed reference)
476 479 PyObject* packageByName(const char* name);
477 480
478 481 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
479 482 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
480 483
481 484 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
482 485 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
483 486
484 487 //! stores the meta info of known Qt classes
485 488 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
486 489
487 490 //! names of qobject derived classes that can be casted to qobject savely
488 491 QHash<QByteArray, bool> _knownQObjectClassNames;
489 492
490 493 //! stores signal receivers for QObjects
491 494 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
492 495
493 496 //! the PythonQt python module
494 497 PythonQtObjectPtr _pythonQtModule;
495 498
496 499 //! the importer interface (if set)
497 500 PythonQtImportFileInterface* _importInterface;
498 501
499 502 //! the default importer
500 503 PythonQtQFileImporter* _defaultImporter;
501 504
502 505 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
503 506 PythonQtQObjectWrappedCB* _wrappedCB;
504 507
505 508 QStringList _importIgnorePaths;
506 509
507 510 //! the cpp object wrapper factories
508 511 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
509 512
510 513 QHash<QByteArray, PyObject*> _packages;
511 514
512 515 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
513 516
514 517 int _initFlags;
515 518 int _PythonQtObjectPtr_metaId;
516 519
517 520 friend class PythonQt;
518 521 };
519 522
520 523 #endif
@@ -1,821 +1,822
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtClassInfo.h"
43 43 #include "PythonQtMethodInfo.h"
44 44 #include "PythonQt.h"
45 45 #include <QMetaMethod>
46 46 #include <QMetaObject>
47 47 #include <QMetaEnum>
48 48
49 49 QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;
50 50
51 51 PythonQtClassInfo::PythonQtClassInfo() {
52 52 _meta = NULL;
53 53 _constructors = NULL;
54 54 _destructor = NULL;
55 55 _decoratorProvider = NULL;
56 56 _decoratorProviderCB = NULL;
57 57 _pythonQtClassWrapper = NULL;
58 58 _shellSetInstanceWrapperCB = NULL;
59 59 _metaTypeId = -1;
60 60 _isQObject = false;
61 61 _enumsCreated = false;
62 62 }
63 63
64 64 PythonQtClassInfo::~PythonQtClassInfo()
65 65 {
66 66 clearCachedMembers();
67 67
68 68 if (_constructors) {
69 69 _constructors->deleteOverloadsAndThis();
70 70 }
71 71 if (_destructor) {
72 72 _destructor->deleteOverloadsAndThis();
73 73 }
74 74 foreach(PythonQtSlotInfo* info, _decoratorSlots) {
75 75 info->deleteOverloadsAndThis();
76 76 }
77 77 }
78 78
79 79 void PythonQtClassInfo::setupQObject(const QMetaObject* meta)
80 80 {
81 81 // _wrappedClassName is already set earlier in the class setup
82 82 _isQObject = true;
83 83 _meta = meta;
84 84 }
85 85
86 86 void PythonQtClassInfo::setupCPPObject(const QByteArray& classname)
87 87 {
88 88 _isQObject = false;
89 89 _wrappedClassName = classname;
90 90 _metaTypeId = QMetaType::type(classname);
91 91 }
92 92
93 93 void PythonQtClassInfo::clearCachedMembers()
94 94 {
95 95 QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers);
96 96 while (i.hasNext()) {
97 97 PythonQtMemberInfo member = i.next().value();
98 98 if (member._type== PythonQtMemberInfo::Slot) {
99 99 PythonQtSlotInfo* info = member._slot;
100 100 while (info) {
101 101 PythonQtSlotInfo* next = info->nextInfo();
102 102 delete info;
103 103 info = next;
104 104 }
105 105 }
106 106 }
107 107 }
108 108
109 109 int PythonQtClassInfo::findCharOffset(const char* sigStart, char someChar)
110 110 {
111 111 const char* sigEnd = sigStart;
112 112 char c;
113 113 do {
114 114 c = *sigEnd++;
115 115 } while (c!=someChar && c!=0);
116 116 return sigEnd-sigStart-1;
117 117 }
118 118
119 119 bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName)
120 120 {
121 121 bool found = false;
122 122 bool nameMapped = false;
123 123 const char* attributeName = memberName;
124 124 // look for properties
125 125 int i = _meta->indexOfProperty(attributeName);
126 126 if (i==-1) {
127 127 // try to map name to objectName
128 128 if (qstrcmp(attributeName, "name")==0) {
129 129 attributeName = "objectName";
130 130 nameMapped = true;
131 131 i = _meta->indexOfProperty(attributeName);
132 132 }
133 133 }
134 134 if (i!=-1) {
135 135 PythonQtMemberInfo newInfo(_meta->property(i));
136 136 _cachedMembers.insert(attributeName, newInfo);
137 137 if (nameMapped) {
138 138 _cachedMembers.insert(memberName, newInfo);
139 139 }
140 140 #ifdef PYTHONQT_DEBUG
141 141 std::cout << "caching property " << memberName << " on " << _meta->className() << std::endl;
142 142 #endif
143 143 found = true;
144 144 }
145 145 return found;
146 146 }
147 147
148 148 PythonQtSlotInfo* PythonQtClassInfo::recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
149 149 {
150 150 inputInfo = findDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset);
151 151 foreach(const ParentClassInfo& info, _parentClasses) {
152 152 inputInfo = info._parent->recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset+info._upcastingOffset);
153 153 }
154 154 return inputInfo;
155 155 }
156 156
157 157 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset) {
158 158 QObject* decoratorProvider = decorator();
159 159 int memberNameLen = strlen(memberName);
160 160 if (decoratorProvider) {
161 161 //qDebug()<< "looking " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
162 162 const QMetaObject* meta = decoratorProvider->metaObject();
163 163 int numMethods = meta->methodCount();
164 164 int startFrom = QObject::staticMetaObject.methodCount();
165 165 for (int i = startFrom; i < numMethods; i++) {
166 166 QMetaMethod m = meta->method(i);
167 167 if ((m.methodType() == QMetaMethod::Method ||
168 168 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
169 169
170 170 const char* sigStart = m.signature();
171 171 bool isClassDeco = false;
172 172 if (qstrncmp(sigStart, "static_", 7)==0) {
173 173 // skip the static_classname_ part of the string
174 174 sigStart += 7 + 1 + strlen(className());
175 175 isClassDeco = true;
176 176 } else if (qstrncmp(sigStart, "new_", 4)==0) {
177 177 isClassDeco = true;
178 178 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
179 179 isClassDeco = true;
180 180 }
181 181 // find the first '('
182 182 int offset = findCharOffset(sigStart, '(');
183 183
184 184 // XXX no checking is currently done if the slots have correct first argument or not...
185 185
186 186 // check if same length and same name
187 187 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
188 188 found = true;
189 189 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i, decoratorProvider, isClassDeco?PythonQtSlotInfo::ClassDecorator:PythonQtSlotInfo::InstanceDecorator);
190 190 info->setUpcastingOffset(upcastingOffset);
191 191 //qDebug()<< "adding " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
192 192 if (tail) {
193 193 tail->setNextInfo(info);
194 194 } else {
195 195 PythonQtMemberInfo newInfo(info);
196 196 memberCache.insert(memberName, newInfo);
197 197 }
198 198 tail = info;
199 199 }
200 200 }
201 201 }
202 202 }
203 203
204 204 tail = findDecoratorSlots(memberName, memberNameLen, tail, found, memberCache, upcastingOffset);
205 205
206 206 return tail;
207 207 }
208 208
209 209 bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName)
210 210 {
211 211 bool found = false;
212 212 int memberNameLen = strlen(memberName);
213 213 PythonQtSlotInfo* tail = NULL;
214 214 if (_meta) {
215 215 int numMethods = _meta->methodCount();
216 216 for (int i = 0; i < numMethods; i++) {
217 217 QMetaMethod m = _meta->method(i);
218 218 if ((m.methodType() == QMetaMethod::Method ||
219 219 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
220 220
221 221 const char* sigStart = m.signature();
222 222 // find the first '('
223 223 int offset = findCharOffset(sigStart, '(');
224 224
225 225 // check if same length and same name
226 226 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
227 227 found = true;
228 228 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i);
229 229 if (tail) {
230 230 tail->setNextInfo(info);
231 231 } else {
232 232 PythonQtMemberInfo newInfo(info);
233 233 _cachedMembers.insert(memberName, newInfo);
234 234 }
235 235 tail = info;
236 236 }
237 237 }
238 238 }
239 239 }
240 240
241 241 // look for dynamic decorators in this class and in derived classes
242 242 tail = recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, tail, found, _cachedMembers, 0);
243 243
244 244 return found;
245 245 }
246 246
247 247 bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* memberName)
248 248 {
249 249 bool found = false;
250 250 // look for enum values
251 251 int enumCount = meta->enumeratorCount();
252 252 for (int i=0;i<enumCount; i++) {
253 253 QMetaEnum e = meta->enumerator(i);
254 254 // we do not want flags, they will cause our values to appear two times
255 255 if (e.isFlag()) continue;
256 256
257 257 for (int j=0; j < e.keyCount(); j++) {
258 258 if (qstrcmp(e.key(j), memberName)==0) {
259 259 PyObject* enumType = findEnumWrapper(e.name());
260 260 if (enumType) {
261 PyObject* args = Py_BuildValue("(i)", e.value(j));
262 PyObject* enumValue = PyObject_Call(enumType, args, NULL);
263 Py_DECREF(args);
264 261 PythonQtObjectPtr enumValuePtr;
265 enumValuePtr.setNewRef(enumValue);
262 enumValuePtr.setNewRef(PythonQtPrivate::createEnumValueInstance(enumType, e.value(j)));
266 263 PythonQtMemberInfo newInfo(enumValuePtr);
267 264 _cachedMembers.insert(memberName, newInfo);
268 265 #ifdef PYTHONQT_DEBUG
269 266 std::cout << "caching enum " << memberName << " on " << meta->className() << std::endl;
270 267 #endif
271 268 found = true;
272 269 break;
273 270 } else {
274 271 std::cout << "enum " << e.name() << " not found on " << className() << std::endl;
275 272 }
276 273 }
277 274 }
278 275 }
279 276 return found;
280 277 }
281 278
282 279 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
283 280 {
284 281 PythonQtMemberInfo info = _cachedMembers.value(memberName);
285 282 if (info._type != PythonQtMemberInfo::Invalid) {
286 283 return info;
287 284 } else {
288 285 bool found = false;
289 286
290 287 found = lookForPropertyAndCache(memberName);
291 288 if (!found) {
292 289 found = lookForMethodAndCache(memberName);
293 290 }
294 291 if (!found) {
295 292 if (_meta) {
296 293 // check enums in our meta object directly
297 294 found = lookForEnumAndCache(_meta, memberName);
298 295 }
299 296 if (!found) {
300 297 // check enums in the class hierachy of CPP classes
301 298 // look for dynamic decorators in this class and in derived classes
302 299 QList<QObject*> decoObjects;
303 300 recursiveCollectDecoratorObjects(decoObjects);
304 301 foreach(QObject* deco, decoObjects) {
305 302 // call on ourself for caching, but with different metaObject():
306 303 found = lookForEnumAndCache(deco->metaObject(), memberName);
307 304 if (found) {
308 305 break;
309 306 }
310 307 }
311 308 }
312 309 }
313 310 if (!found) {
314 311 PyObject* p = findEnumWrapper(memberName);
315 312 if (p) {
316 313 info._type = PythonQtMemberInfo::EnumWrapper;
317 314 info._enumWrapper = p;
318 315 _cachedMembers.insert(memberName, info);
319 316 found = true;
320 317 }
321 318 }
322 319 if (!found) {
323 320 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
324 321 info._type = PythonQtMemberInfo::NotFound;
325 322 _cachedMembers.insert(memberName, info);
326 323 }
327 324 }
328 325
329 326 return _cachedMembers.value(memberName);
330 327 }
331 328
332 329 void PythonQtClassInfo::recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects) {
333 330 QObject* deco = decorator();
334 331 if (deco) {
335 332 decoratorObjects.append(deco);
336 333 }
337 334 foreach(const ParentClassInfo& info, _parentClasses) {
338 335 info._parent->recursiveCollectDecoratorObjects(decoratorObjects);
339 336 }
340 337 }
341 338
342 339 void PythonQtClassInfo::recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects) {
343 340 classInfoObjects.append(this);
344 341 foreach(const ParentClassInfo& info, _parentClasses) {
345 342 info._parent->recursiveCollectClassInfos(classInfoObjects);
346 343 }
347 344 }
348 345
349 346 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
350 347 {
351 348 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
352 349 while (it.hasNext()) {
353 350
354 351 PythonQtSlotInfo* infoOrig = it.next();
355 352
356 353 const char* sigStart = infoOrig->metaMethod()->signature();
357 354 if (qstrncmp("static_", sigStart, 7)==0) {
358 355 sigStart += 7;
359 356 sigStart += findCharOffset(sigStart, '_')+1;
360 357 }
361 358 int offset = findCharOffset(sigStart, '(');
362 359 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
363 360 //make a copy, otherwise we will have trouble on overloads!
364 361 PythonQtSlotInfo* info = new PythonQtSlotInfo(*infoOrig);
365 362 info->setUpcastingOffset(upcastingOffset);
366 363 found = true;
367 364 if (tail) {
368 365 tail->setNextInfo(info);
369 366 } else {
370 367 PythonQtMemberInfo newInfo(info);
371 368 memberCache.insert(memberName, newInfo);
372 369 }
373 370 tail = info;
374 371 }
375 372 }
376 373 return tail;
377 374 }
378 375
379 376 void PythonQtClassInfo::listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly) {
380 377 QObject* decoratorProvider = decorator();
381 378 if (decoratorProvider) {
382 379 const QMetaObject* meta = decoratorProvider->metaObject();
383 380 int numMethods = meta->methodCount();
384 381 int startFrom = QObject::staticMetaObject.methodCount();
385 382 for (int i = startFrom; i < numMethods; i++) {
386 383 QMetaMethod m = meta->method(i);
387 384 if ((m.methodType() == QMetaMethod::Method ||
388 385 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
389 386
390 387 const char* sigStart = m.signature();
391 388 bool isClassDeco = false;
392 389 if (qstrncmp(sigStart, "static_", 7)==0) {
393 390 // skip the static_classname_ part of the string
394 391 sigStart += 7 + 1 + strlen(className());
395 392 isClassDeco = true;
396 393 } else if (qstrncmp(sigStart, "new_", 4)==0) {
397 394 continue;
398 395 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
399 396 continue;
400 397 }
401 398 // find the first '('
402 399 int offset = findCharOffset(sigStart, '(');
403 400
404 401 // XXX no checking is currently done if the slots have correct first argument or not...
405 402 if (!metaOnly || isClassDeco) {
406 403 list << QString::fromLatin1(sigStart, offset);
407 404 }
408 405 }
409 406 }
410 407 }
411 408
412 409 // look for global decorator slots
413 410 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
414 411 while (it.hasNext()) {
415 412 PythonQtSlotInfo* slot = it.next();
416 413 if (metaOnly) {
417 414 if (slot->isClassDecorator()) {
418 415 QByteArray first = slot->slotName();
419 416 if (first.startsWith("static_")) {
420 417 int idx = first.indexOf('_');
421 418 idx = first.indexOf('_', idx+1);
422 419 first = first.mid(idx+1);
423 420 }
424 421 list << first;
425 422 }
426 423 } else {
427 424 list << slot->slotName();
428 425 }
429 426 }
430 427 }
431 428
432 429 QStringList PythonQtClassInfo::propertyList()
433 430 {
434 431 QStringList l;
435 432 if (_isQObject && _meta) {
436 433 int i;
437 434 int numProperties = _meta->propertyCount();
438 435 for (i = 0; i < numProperties; i++) {
439 436 QMetaProperty p = _meta->property(i);
440 437 l << QString(p.name());
441 438 }
442 439 }
443 440 return l;
444 441 }
445 442
446 443 QStringList PythonQtClassInfo::memberList(bool metaOnly)
447 444 {
448 445 decorator();
449 446
450 447 QStringList l;
451 448 QString h;
452 449 if (_isQObject && _meta && !metaOnly) {
453 450 l = propertyList();
454 451 }
455 452
456 453 // normal slots of QObject (or wrapper QObject)
457 454 if (!metaOnly && _meta) {
458 455 int numMethods = _meta->methodCount();
459 456 bool skipQObj = !_isQObject;
460 457 for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) {
461 458 QMetaMethod m = _meta->method(i);
462 459 if ((m.methodType() == QMetaMethod::Method ||
463 460 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
464 461 QByteArray signa(m.signature());
465 462 signa = signa.left(signa.indexOf('('));
466 463 l << signa;
467 464 }
468 465 }
469 466 }
470 467
471 468 {
472 469 // look for dynamic decorators in this class and in derived classes
473 470 QList<PythonQtClassInfo*> infos;
474 471 recursiveCollectClassInfos(infos);
475 472 foreach(PythonQtClassInfo* info, infos) {
476 473 info->listDecoratorSlotsFromDecoratorProvider(l, metaOnly);
477 474 }
478 475 }
479 476
480 477 // List enumerator keys...
481 478 QList<const QMetaObject*> enumMetaObjects;
482 479 if (_meta) {
483 480 enumMetaObjects << _meta;
484 481 }
485 482 // check enums in the class hierachy of CPP classes
486 483 QList<QObject*> decoObjects;
487 484 recursiveCollectDecoratorObjects(decoObjects);
488 485 foreach(QObject* deco, decoObjects) {
489 486 enumMetaObjects << deco->metaObject();
490 487 }
491 488
492 489 foreach(const QMetaObject* meta, enumMetaObjects) {
493 490 for (int i = 0; i<meta->enumeratorCount(); i++) {
494 491 QMetaEnum e = meta->enumerator(i);
495 492 l << e.name();
496 493 // we do not want flags, they will cause our values to appear two times
497 494 if (e.isFlag()) continue;
498 495
499 496 for (int j=0; j < e.keyCount(); j++) {
500 497 l << QString(e.key(j));
501 498 }
502 499 }
503 500 }
504 501
505 502 return QSet<QString>::fromList(l).toList();
506 503 }
507 504
508 505 const char* PythonQtClassInfo::className()
509 506 {
510 507 return _wrappedClassName.constData();
511 508 }
512 509
513 510 void* PythonQtClassInfo::castTo(void* ptr, const char* classname)
514 511 {
515 512 if (ptr==NULL) {
516 513 return NULL;
517 514 }
518 515 if (_wrappedClassName == classname) {
519 516 return ptr;
520 517 }
521 518 foreach(const ParentClassInfo& info, _parentClasses) {
522 519 void* result = info._parent->castTo((char*)ptr + info._upcastingOffset, classname);
523 520 if (result) {
524 521 return result;
525 522 }
526 523 }
527 524 return NULL;
528 525 }
529 526
530 527 bool PythonQtClassInfo::inherits(const char* name)
531 528 {
532 529 if (_wrappedClassName == name) {
533 530 return true;
534 531 }
535 532 foreach(const ParentClassInfo& info, _parentClasses) {
536 533 if (info._parent->inherits(name)) {
537 534 return true;
538 535 }
539 536 }
540 537 return false;
541 538 }
542 539
543 540 bool PythonQtClassInfo::inherits(PythonQtClassInfo* classInfo)
544 541 {
545 542 if (classInfo == this) {
546 543 return true;
547 544 }
548 545 foreach(const ParentClassInfo& info, _parentClasses) {
549 546 if (info._parent->inherits(classInfo)) {
550 547 return true;
551 548 }
552 549 }
553 550 return false;
554 551 }
555 552
556 553 QString PythonQtClassInfo::help()
557 554 {
558 555 decorator();
559 556 QString h;
560 557 h += QString("--- ") + QString(className()) + QString(" ---\n");
561 558
562 559 if (_isQObject) {
563 560 h += "Properties:\n";
564 561
565 562 int i;
566 563 int numProperties = _meta->propertyCount();
567 564 for (i = 0; i < numProperties; i++) {
568 565 QMetaProperty p = _meta->property(i);
569 566 h += QString(p.name()) + " (" + QString(p.typeName()) + " )\n";
570 567 }
571 568 }
572 569
573 570 if (constructors()) {
574 571 h += "Constructors:\n";
575 572 PythonQtSlotInfo* constr = constructors();
576 573 while (constr) {
577 574 h += constr->fullSignature() + "\n";
578 575 constr = constr->nextInfo();
579 576 }
580 577 }
581 578
582 579 h += "Slots:\n";
583 580 h += "QString help()\n";
584 581 h += "QString className()\n";
585 582
586 583 if (_meta) {
587 584 int numMethods = _meta->methodCount();
588 585 for (int i = 0; i < numMethods; i++) {
589 586 QMetaMethod m = _meta->method(i);
590 587 if ((m.methodType() == QMetaMethod::Method ||
591 588 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
592 589 PythonQtSlotInfo slot(this, m, i);
593 590 h += slot.fullSignature()+ "\n";
594 591 }
595 592 }
596 593 }
597 594
598 595 // TODO xxx : decorators and enums from decorator() are missing...
599 596 // maybe we can reuse memberlist()?
600 597
601 598 if (_meta && _meta->enumeratorCount()) {
602 599 h += "Enums:\n";
603 600 for (int i = 0; i<_meta->enumeratorCount(); i++) {
604 601 QMetaEnum e = _meta->enumerator(i);
605 602 h += QString(e.name()) + " {";
606 603 for (int j=0; j < e.keyCount(); j++) {
607 604 if (j) { h+= ", "; }
608 605 h += e.key(j);
609 606 }
610 607 h += " }\n";
611 608 }
612 609 }
613 610
614 611 if (_isQObject && _meta) {
615 612 int numMethods = _meta->methodCount();
616 613 if (numMethods>0) {
617 614 h += "Signals:\n";
618 615 for (int i = 0; i < numMethods; i++) {
619 616 QMetaMethod m = _meta->method(i);
620 617 if (m.methodType() == QMetaMethod::Signal) {
621 618 h += QString(m.signature()) + "\n";
622 619 }
623 620 }
624 621 }
625 622 }
626 623 return h;
627 624 }
628 625
629 626 PythonQtSlotInfo* PythonQtClassInfo::constructors()
630 627 {
631 628 if (!_constructors) {
632 629 // force creation of lazy decorator, which will register the decorators
633 630 decorator();
634 631 }
635 632 return _constructors;
636 633 }
637 634
638 635 PythonQtSlotInfo* PythonQtClassInfo::destructor()
639 636 {
640 637 if (!_destructor) {
641 638 // force creation of lazy decorator, which will register the decorators
642 639 decorator();
643 640 }
644 641 return _destructor;
645 642 }
646 643
647 644 void PythonQtClassInfo::addConstructor(PythonQtSlotInfo* info)
648 645 {
649 646 PythonQtSlotInfo* prev = constructors();
650 647 if (prev) {
651 648 info->setNextInfo(prev->nextInfo());
652 649 prev->setNextInfo(info);
653 650 } else {
654 651 _constructors = info;
655 652 }
656 653 }
657 654
658 655 void PythonQtClassInfo::addDecoratorSlot(PythonQtSlotInfo* info)
659 656 {
660 657 _decoratorSlots.append(info);
661 658 }
662 659
663 660 void PythonQtClassInfo::setDestructor(PythonQtSlotInfo* info)
664 661 {
665 662 if (_destructor) {
666 663 _destructor->deleteOverloadsAndThis();
667 664 }
668 665 _destructor = info;
669 666 }
670 667
671 668 void PythonQtClassInfo::setMetaObject(const QMetaObject* meta)
672 669 {
673 670 _meta = meta;
674 671 clearCachedMembers();
675 672 }
676 673
677 674 QObject* PythonQtClassInfo::decorator()
678 675 {
679 676 if (!_decoratorProvider && _decoratorProviderCB) {
680 677 _decoratorProvider = (*_decoratorProviderCB)();
681 678 if (_decoratorProvider) {
682 679 _decoratorProvider->setParent(PythonQt::priv());
683 680 // setup enums early, since they might be needed by the constructor decorators:
684 681 if (!_enumsCreated) {
685 682 createEnumWrappers();
686 683 }
687 684 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
688 685 }
689 686 }
690 687 // check if enums need to be created and create them if they are not yet created
691 688 if (!_enumsCreated) {
692 689 createEnumWrappers();
693 690 }
694 691 return _decoratorProvider;
695 692 }
696 693
697 694 bool PythonQtClassInfo::hasOwnerMethodButNoOwner(void* object)
698 695 {
699 696 PythonQtMemberInfo info = member("hasOwner");
700 697 if (info._type == PythonQtMemberInfo::Slot) {
701 698 void* obj = object;
702 699 bool result = false;
703 700 void* args[2];
704 701 args[0] = &result;
705 702 args[1] = &obj;
706 703 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
707 704 return !result;
708 705 } else {
709 706 return false;
710 707 }
711 708 }
712 709
713 710 void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, char** resultClassName)
714 711 {
715 712 if (!_polymorphicHandlers.isEmpty()) {
716 713 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
717 714 void* resultPtr = (*cb)(ptr, resultClassName);
718 715 if (resultPtr) {
719 716 return resultPtr;
720 717 }
721 718 }
722 719 }
723 720 foreach(const ParentClassInfo& info, _parentClasses) {
724 721 if (!info._parent->isQObject()) {
725 722 void* resultPtr = info._parent->recursiveCastDownIfPossible((char*)ptr + info._upcastingOffset, resultClassName);
726 723 if (resultPtr) {
727 724 return resultPtr;
728 725 }
729 726 }
730 727 }
731 728 return NULL;
732 729 }
733 730
734 731 void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo)
735 732 {
736 733 char* className;
737 734 // this would do downcasting recursively...
738 735 // void* resultPtr = recursiveCastDownIfPossible(ptr, &className);
739 736
740 737 // we only do downcasting on the base object, not on the whole inheritance tree...
741 738 void* resultPtr = NULL;
742 739 if (!_polymorphicHandlers.isEmpty()) {
743 740 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
744 741 resultPtr = (*cb)(ptr, &className);
745 742 if (resultPtr) {
746 743 break;
747 744 }
748 745 }
749 746 }
750 747 if (resultPtr) {
751 748 *resultClassInfo = PythonQt::priv()->getClassInfo(className);
752 749 } else {
753 750 *resultClassInfo = this;
754 751 resultPtr = ptr;
755 752 }
756 753 return resultPtr;
757 754 }
758 755
759 756 PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool& isLocalEnum)
760 757 {
761 758 isLocalEnum = true;
762 759 int scopePos = name.lastIndexOf("::");
763 760 if (scopePos != -1) {
764 761 isLocalEnum = false;
765 762 // slit into scope and enum name
766 763 QByteArray enumScope = name.mid(0,scopePos);
767 764 QByteArray enumName = name.mid(scopePos+2);
768 765 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(enumScope);
769 766 if (info) {
770 767 return info->findEnumWrapper(enumName);
771 768 } else{
772 769 return NULL;
773 770 }
774 771 }
775 772 if (localScope) {
776 773 return localScope->findEnumWrapper(name);
777 774 } else {
778 775 return NULL;
779 776 }
780 777 }
781 778
782 779 void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta)
783 780 {
784 781 for (int i = meta->enumeratorOffset();i<meta->enumeratorCount();i++) {
785 782 QMetaEnum e = meta->enumerator(i);
786 783 PythonQtObjectPtr p;
787 p.setNewRef(PythonQt::priv()->createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper));
784 p.setNewRef(PythonQtPrivate::createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper));
788 785 _enumWrappers.append(p);
789 786 }
790 787 }
791 788
792 789 void PythonQtClassInfo::createEnumWrappers()
793 790 {
794 791 if (!_enumsCreated) {
795 792 _enumsCreated = true;
796 793 if (_meta) {
797 794 createEnumWrappers(_meta);
798 795 }
799 796 if (decorator()) {
800 797 createEnumWrappers(decorator()->metaObject());
801 798 }
802 799 foreach(const ParentClassInfo& info, _parentClasses) {
803 800 info._parent->createEnumWrappers();
804 801 }
805 802 }
806 803 }
807 804
808 805 PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) {
806 // force enum creation
807 if (!_enumsCreated) {
808 createEnumWrappers();
809 }
809 810 foreach(const PythonQtObjectPtr& p, _enumWrappers) {
810 811 const char* className = ((PyTypeObject*)p.object())->tp_name;
811 812 if (qstrcmp(className, name)==0) {
812 813 return p.object();
813 814 }
814 815 }
815 816 foreach(const ParentClassInfo& info, _parentClasses) {
816 817 PyObject* p = info._parent->findEnumWrapper(name);
817 818 if (p) return p;
818 819 }
819 820 return NULL;
820 821 }
821 822
@@ -1,1115 +1,1129
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtConversion.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtConversion.h"
43 43 #include "PythonQtVariants.h"
44 44 #include <QDateTime>
45 45 #include <QTime>
46 46 #include <QDate>
47 47
48 48 PythonQtValueStorage<qint64, 128> PythonQtConv::global_valueStorage;
49 49 PythonQtValueStorage<void*, 128> PythonQtConv::global_ptrStorage;
50 50 PythonQtValueStorage<QVariant, 32> PythonQtConv::global_variantStorage;
51 51
52 52 QHash<int, PythonQtConvertMetaTypeToPythonCB*> PythonQtConv::_metaTypeToPythonConverters;
53 53 QHash<int, PythonQtConvertPythonToMetaTypeCB*> PythonQtConv::_pythonToMetaTypeConverters;
54 54
55 55 PyObject* PythonQtConv::GetPyBool(bool val)
56 56 {
57 57 PyObject* r = val?Py_True:Py_False;
58 58 Py_INCREF(r);
59 59 return r;
60 60 }
61 61
62 62 PyObject* PythonQtConv::ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data) {
63 // is it an enum value?
64 if (info.enumWrapper) {
65 if (!info.isPointer) {
66 return PythonQtPrivate::createEnumValueInstance(info.enumWrapper, *((unsigned int*)data));
67 } else {
68 // we do not support pointers to enums (who needs them?)
69 Py_INCREF(Py_None);
70 return Py_None;
71 }
72 }
73
63 74 if (info.typeId == QMetaType::Void) {
64 75 Py_INCREF(Py_None);
65 76 return Py_None;
66 77 } else if (info.isPointer && (info.typeId == QMetaType::Char)) {
67 78 // a char ptr will probably be a null terminated string, so we support that:
68 79 return PyString_FromString(*((char**)data));
69 80 } else if ((info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) &&
70 81 info.name.startsWith("QList<")) {
71 82 // it is a QList template:
72 83 // (TODO: check what happens if this is a pointer type?!)
73 84 QByteArray innerType = info.name.mid(6,info.name.length()-7);
74 85 if (innerType.endsWith("*")) {
75 86 innerType.truncate(innerType.length()-1);
76 87 return ConvertQListOfPointerTypeToPythonList((QList<void*>*)data, innerType);
77 88 }
78 89 }
79 90
80 91 if (info.typeId >= QMetaType::User) {
81 92 // if a converter is registered, we use is:
82 93 PythonQtConvertMetaTypeToPythonCB* converter = _metaTypeToPythonConverters.value(info.typeId);
83 94 if (converter) {
84 95 return (*converter)(data, info.typeId);
85 96 }
86 97 }
87 98
88 99 // special handling did not match, so we convert the usual way (either pointer or value version):
89 100 if (info.isPointer) {
90 101 // 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)
91 102 return PythonQt::priv()->wrapPtr(*((void**)data), info.name);
92 103 } else {
93 104 // handle values that are not yet handled and not pointers
94 105 return ConvertQtValueToPythonInternal(info.typeId, data);
95 106 }
96 107 }
97 108
98 109 PyObject* PythonQtConv::ConvertQtValueToPythonInternal(int type, const void* data) {
99 110 switch (type) {
100 111 case QMetaType::Void:
101 112 Py_INCREF(Py_None);
102 113 return Py_None;
103 114 case QMetaType::Char:
104 115 return PyInt_FromLong(*((char*)data));
105 116 case QMetaType::UChar:
106 117 return PyInt_FromLong(*((unsigned char*)data));
107 118 case QMetaType::Short:
108 119 return PyInt_FromLong(*((short*)data));
109 120 case QMetaType::UShort:
110 121 return PyInt_FromLong(*((unsigned short*)data));
111 122 case QMetaType::Long:
112 123 return PyInt_FromLong(*((long*)data));
113 124 case QMetaType::ULong:
114 125 // does not fit into simple int of python
115 126 return PyLong_FromUnsignedLong(*((unsigned long*)data));
116 127 case QMetaType::Bool:
117 128 return PythonQtConv::GetPyBool(*((bool*)data));
118 129 case QMetaType::Int:
119 130 return PyInt_FromLong(*((int*)data));
120 131 case QMetaType::UInt:
121 132 return PyInt_FromLong(*((unsigned int*)data));
122 133 case QMetaType::QChar:
123 134 return PyInt_FromLong(*((short*)data));
124 135 case QMetaType::Float:
125 136 return PyFloat_FromDouble(*((float*)data));
126 137 case QMetaType::Double:
127 138 return PyFloat_FromDouble(*((double*)data));
128 139 case QMetaType::LongLong:
129 140 return PyLong_FromLongLong(*((qint64*)data));
130 141 case QMetaType::ULongLong:
131 142 return PyLong_FromUnsignedLongLong(*((quint64*)data));
132 143 case QMetaType::QByteArray: {
133 144 QByteArray* v = (QByteArray*) data;
134 145 return PyString_FromStringAndSize(*v, v->size());
135 146 }
136 147 case QMetaType::QVariantMap:
137 148 return PythonQtConv::QVariantMapToPyObject(*((QVariantMap*)data));
138 149 case QMetaType::QVariantList:
139 150 return PythonQtConv::QVariantListToPyObject(*((QVariantList*)data));
140 151 case QMetaType::QString:
141 152 return PythonQtConv::QStringToPyObject(*((QString*)data));
142 153 case QMetaType::QStringList:
143 154 return PythonQtConv::QStringListToPyObject(*((QStringList*)data));
144 155
145 156 case PythonQtMethodInfo::Variant:
146 157 return PythonQtConv::QVariantToPyObject(*((QVariant*)data));
147 158 case QMetaType::QObjectStar:
148 159 case QMetaType::QWidgetStar:
149 160 return PythonQt::priv()->wrapQObject(*((QObject**)data));
150 161
151 162 default:
152 163 if (PythonQt::priv()->isPythonQtObjectPtrMetaId(type)) {
153 164 // special case, it is a PythonQtObjectPtr which contains a PyObject, take it directly:
154 165 PyObject* o = ((PythonQtObjectPtr*)data)->object();
155 166 Py_INCREF(o);
156 167 return o;
157 168 } else {
158 169 if (type > 0) {
159 170 // if the type is known, we can construct it via QMetaType::construct
160 171 void* newCPPObject = QMetaType::construct(type, data);
161 172 // XXX this could be optimized by using metatypeid directly
162 173 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)PythonQt::priv()->wrapPtr(newCPPObject, QMetaType::typeName(type));
163 174 wrap->_ownedByPythonQt = true;
164 175 wrap->_useQMetaTypeDestroy = true;
165 176 return (PyObject*)wrap;
166 177 }
167 178 std::cerr << "Unknown type that can not be converted to Python: " << type << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
168 179 }
169 180 }
170 181 Py_INCREF(Py_None);
171 182 return Py_None;
172 183 }
173 184
174 185 void* PythonQtConv::CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info) {
175 186 void* ptr = NULL;
176 187 if (info.isPointer) {
177 188 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
189 } else if (info.enumWrapper) {
190 // create enum return value
191 PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, ptr);
178 192 } else {
179 193 switch (info.typeId) {
180 194 case QMetaType::Char:
181 195 case QMetaType::UChar:
182 196 case QMetaType::Short:
183 197 case QMetaType::UShort:
184 198 case QMetaType::Long:
185 199 case QMetaType::ULong:
186 200 case QMetaType::Bool:
187 201 case QMetaType::Int:
188 202 case QMetaType::UInt:
189 203 case QMetaType::QChar:
190 204 case QMetaType::Float:
191 205 case QMetaType::Double:
192 206 PythonQtValueStorage_ADD_VALUE(global_valueStorage, long, 0, ptr);
193 207 break;
194 208 case PythonQtMethodInfo::Variant:
195 209 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, 0, ptr);
196 210 // return the ptr to the variant
197 211 break;
198 212 default:
199 213 if (info.typeId == PythonQtMethodInfo::Unknown) {
200 214 // check if we have a QList of pointers, which we can circumvent with a QList<void*>
201 215 if (info.name.startsWith("QList<")) {
202 216 QByteArray innerType = info.name.mid(6,info.name.length()-7);
203 217 if (innerType.endsWith("*")) {
204 218 static int id = QMetaType::type("QList<void*>");
205 219 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr);
206 220 // return the constData pointer that will be filled with the result value later on
207 221 ptr = (void*)((QVariant*)ptr)->constData();
208 222 }
209 223 }
210 224 }
211 225
212 226 if (!ptr && info.typeId!=PythonQtMethodInfo::Unknown) {
213 227 // everything else is stored in a QVariant, if we know the meta type...
214 228 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
215 229 // return the constData pointer that will be filled with the result value later on
216 230 ptr = (void*)((QVariant*)ptr)->constData();
217 231 }
218 232 }
219 233 }
220 234 return ptr;
221 235 }
222 236
223 237 void* PythonQtConv::castWrapperTo(PythonQtInstanceWrapper* wrapper, const QByteArray& className, bool& ok)
224 238 {
225 239 void* object;
226 240 if (wrapper->classInfo()->isCPPWrapper()) {
227 241 object = wrapper->_wrappedPtr;
228 242 } else {
229 243 QObject* tmp = wrapper->_obj;
230 244 object = tmp;
231 245 }
232 246 if (object) {
233 247 // if we can be upcasted to the given name, we pass the casted pointer in:
234 248 object = wrapper->classInfo()->castTo(object, className);
235 249 ok = object!=NULL;
236 250 } else {
237 251 // if it is a NULL ptr, we need to check if it inherits, so that we might pass the NULL ptr
238 252 ok = wrapper->classInfo()->inherits(className);
239 253 }
240 254 return object;
241 255 }
242 256
243 257 void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* /*classInfo*/, void* alreadyAllocatedCPPObject)
244 258 {
245 259 bool ok;
246 260 void* ptr = NULL;
247 261 if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) && info.typeId != PythonQtMethodInfo::Variant) {
248 262 // if we have a Qt wrapper object and if we do not need a QVariant, we do the following:
249 263 // (the Variant case is handled below in a switch)
250 264
251 265 // a C++ wrapper (can be passed as pointer or reference)
252 266 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)obj;
253 267 bool ok;
254 268 void* object = castWrapperTo(wrap, info.name, ok);
255 269 if (ok) {
256 270 if (info.isPointer) {
257 271 // store the wrapped pointer in an extra pointer and let ptr point to the extra pointer
258 272 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, object, ptr);
259 273 } else {
260 274 // store the wrapped pointer directly, since we are a reference
261 275 ptr = object;
262 276 }
263 277 } else {
264 278 // not matching
265 279 }
266 280 } else if (info.isPointer) {
267 281 // a pointer
268 282 if (info.typeId == QMetaType::Char || info.typeId == QMetaType::UChar)
269 283 {
270 284 QString str = PyObjGetString(obj, strict, ok);
271 285 if (ok) {
272 286 void* ptr2 = NULL;
273 287 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str.toUtf8()), ptr2);
274 288 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr);
275 289 }
276 290 } else if (info.name == "PyObject") {
277 291 // handle low level PyObject directly
278 292 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, obj, ptr);
279 293 } else if (obj == Py_None) {
280 294 // None is treated as a NULL ptr
281 295 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
282 296 } else {
283 297 // if we are not strict, we try if we are passed a 0 integer
284 298 if (!strict) {
285 299 bool ok;
286 300 int value = PyObjGetInt(obj, true, ok);
287 301 if (ok && value==0) {
288 302 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
289 303 }
290 304 }
291 305 }
292 306 } else {
293 307 // not a pointer
294 308 switch (info.typeId) {
295 309 case QMetaType::Char:
296 310 {
297 311 int val = PyObjGetInt(obj, strict, ok);
298 312 if (ok) {
299 313 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, char, val, ptr);
300 314 }
301 315 }
302 316 break;
303 317 case QMetaType::UChar:
304 318 {
305 319 int val = PyObjGetInt(obj, strict, ok);
306 320 if (ok) {
307 321 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned char, val, ptr);
308 322 }
309 323 }
310 324 break;
311 325 case QMetaType::Short:
312 326 {
313 327 int val = PyObjGetInt(obj, strict, ok);
314 328 if (ok) {
315 329 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
316 330 }
317 331 }
318 332 break;
319 333 case QMetaType::UShort:
320 334 {
321 335 int val = PyObjGetInt(obj, strict, ok);
322 336 if (ok) {
323 337 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned short, val, ptr);
324 338 }
325 339 }
326 340 break;
327 341 case QMetaType::Long:
328 342 {
329 343 long val = (long)PyObjGetLongLong(obj, strict, ok);
330 344 if (ok) {
331 345 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, long, val, ptr);
332 346 }
333 347 }
334 348 break;
335 349 case QMetaType::ULong:
336 350 {
337 351 unsigned long val = (unsigned long)PyObjGetLongLong(obj, strict, ok);
338 352 if (ok) {
339 353 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned long, val, ptr);
340 354 }
341 355 }
342 356 break;
343 357 case QMetaType::Bool:
344 358 {
345 359 bool val = PyObjGetBool(obj, strict, ok);
346 360 if (ok) {
347 361 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, bool, val, ptr);
348 362 }
349 363 }
350 364 break;
351 365 case QMetaType::Int:
352 366 {
353 367 int val = PyObjGetInt(obj, strict, ok);
354 368 if (ok) {
355 369 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, int, val, ptr);
356 370 }
357 371 }
358 372 break;
359 373 case QMetaType::UInt:
360 374 {
361 375 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
362 376 if (ok) {
363 377 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
364 378 }
365 379 }
366 380 break;
367 381 case QMetaType::QChar:
368 382 {
369 383 int val = PyObjGetInt(obj, strict, ok);
370 384 if (ok) {
371 385 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
372 386 }
373 387 }
374 388 break;
375 389 case QMetaType::Float:
376 390 {
377 391 float val = (float)PyObjGetDouble(obj, strict, ok);
378 392 if (ok) {
379 393 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, float, val, ptr);
380 394 }
381 395 }
382 396 break;
383 397 case QMetaType::Double:
384 398 {
385 399 double val = (double)PyObjGetDouble(obj, strict, ok);
386 400 if (ok) {
387 401 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, double, val, ptr);
388 402 }
389 403 }
390 404 break;
391 405 case QMetaType::LongLong:
392 406 {
393 407 qint64 val = PyObjGetLongLong(obj, strict, ok);
394 408 if (ok) {
395 409 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, qint64, val, ptr);
396 410 }
397 411 }
398 412 break;
399 413 case QMetaType::ULongLong:
400 414 {
401 415 quint64 val = PyObjGetULongLong(obj, strict, ok);
402 416 if (ok) {
403 417 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, quint64, val, ptr);
404 418 }
405 419 }
406 420 break;
407 421 case QMetaType::QByteArray:
408 422 {
409 423 QByteArray bytes = PyObjGetBytes(obj, strict, ok);
410 424 if (ok) {
411 425 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(bytes), ptr);
412 426 ptr = (void*)((QVariant*)ptr)->constData();
413 427 }
414 428 }
415 429 break;
416 430 case QMetaType::QString:
417 431 {
418 432 QString str = PyObjGetString(obj, strict, ok);
419 433 if (ok) {
420 434 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str), ptr);
421 435 ptr = (void*)((QVariant*)ptr)->constData();
422 436 }
423 437 }
424 438 break;
425 439 case QMetaType::QStringList:
426 440 {
427 441 QStringList l = PyObjToStringList(obj, strict, ok);
428 442 if (ok) {
429 443 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(l), ptr);
430 444 ptr = (void*)((QVariant*)ptr)->constData();
431 445 }
432 446 }
433 447 break;
434 448
435 449 case PythonQtMethodInfo::Variant:
436 450 {
437 451 QVariant v = PyObjToQVariant(obj);
438 452 if (v.isValid()) {
439 453 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
440 454 }
441 455 }
442 456 break;
443 457 default:
444 458 {
445 459 // check for enum case
446 460 if (info.enumWrapper) {
447 461 unsigned int val;
448 462 if ((PyObject*)obj->ob_type == info.enumWrapper) {
449 463 // we have a direct enum type match:
450 464 val = PyInt_AS_LONG(obj);
451 465 ok = true;
452 466 } else {
453 467 // we try to get an integer, and in strict mode, it may not be a derived int class, so that no other enum can be taken as an int
454 468 val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
455 469 }
456 470 if (ok) {
457 471 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
458 472 return ptr;
459 473 } else {
460 474 return NULL;
461 475 }
462 476 }
463 477
464 478 if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
465 479 // check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant
466 480 if (info.name.startsWith("QList<")) {
467 481 QByteArray innerType = info.name.mid(6,info.name.length()-7);
468 482 if (innerType.endsWith("*")) {
469 483 innerType.truncate(innerType.length()-1);
470 484 static int id = QMetaType::type("QList<void*>");
471 485 if (!alreadyAllocatedCPPObject) {
472 486 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(id), ptr);
473 487 ptr = (void*)((QVariant*)ptr)->constData();
474 488 } else {
475 489 ptr = alreadyAllocatedCPPObject;
476 490 }
477 491 ok = ConvertPythonListToQListOfPointerType(obj, (QList<void*>*)ptr, innerType, strict);
478 492 if (ok) {
479 493 return ptr;
480 494 } else {
481 495 return NULL;
482 496 }
483 497 }
484 498 }
485 499 }
486 500
487 501 // We only do this for registered type > QMetaType::User for performance reasons.
488 502 if (info.typeId >= QMetaType::User) {
489 503 // Maybe we have a special converter that is registered for that type:
490 504 PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(info.typeId);
491 505 if (converter) {
492 506 if (!alreadyAllocatedCPPObject) {
493 507 // create a new empty variant of concrete type:
494 508 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
495 509 ptr = (void*)((QVariant*)ptr)->constData();
496 510 } else {
497 511 ptr = alreadyAllocatedCPPObject;
498 512 }
499 513 // now call the converter, passing the internal object of the variant
500 514 ok = (*converter)(obj, ptr, info.typeId, strict);
501 515 if (ok) {
502 516 return ptr;
503 517 } else {
504 518 return NULL;
505 519 }
506 520 }
507 521 }
508 522 // if no type id is available, conversion to a QVariant makes no sense/is not possible
509 523 if (info.typeId != PythonQtMethodInfo::Unknown) {
510 524 // for all other types, we use the same qvariant conversion and pass out the constData of the variant:
511 525 QVariant v = PyObjToQVariant(obj, info.typeId);
512 526 if (v.isValid()) {
513 527 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
514 528 ptr = (void*)((QVariant*)ptr)->constData();
515 529 }
516 530 }
517 531 }
518 532 }
519 533 }
520 534 return ptr;
521 535 }
522 536
523 537
524 538 QStringList PythonQtConv::PyObjToStringList(PyObject* val, bool strict, bool& ok) {
525 539 QStringList v;
526 540 ok = false;
527 541 // if we are strict, we do not want to convert a string to a stringlist
528 542 // (strings in python are detected to be sequences)
529 543 if (strict &&
530 544 (val->ob_type == &PyString_Type ||
531 545 PyUnicode_Check(val))) {
532 546 ok = false;
533 547 return v;
534 548 }
535 549 if (PySequence_Check(val)) {
536 550 int count = PySequence_Size(val);
537 551 for (int i = 0;i<count;i++) {
538 552 PyObject* value = PySequence_GetItem(val,i);
539 553 v.append(PyObjGetString(value,false,ok));
540 554 }
541 555 ok = true;
542 556 }
543 557 return v;
544 558 }
545 559
546 560 QString PythonQtConv::PyObjGetRepresentation(PyObject* val)
547 561 {
548 562 QString r;
549 563 PyObject* str = PyObject_Repr(val);
550 564 if (str) {
551 565 r = QString(PyString_AS_STRING(str));
552 566 Py_DECREF(str);
553 567 }
554 568 return r;
555 569 }
556 570
557 571 QString PythonQtConv::PyObjGetString(PyObject* val, bool strict, bool& ok) {
558 572 QString r;
559 573 ok = true;
560 574 if (val->ob_type == &PyString_Type) {
561 575 r = QString(PyString_AS_STRING(val));
562 576 } else if (PyUnicode_Check(val)) {
563 577 #ifdef WIN32
564 578 r = QString::fromUtf16(PyUnicode_AS_UNICODE(val));
565 579 #else
566 580 PyObject *ptmp = PyUnicode_AsUTF8String(val);
567 581 if(ptmp) {
568 582 r = QString::fromUtf8(PyString_AS_STRING(ptmp));
569 583 Py_DECREF(ptmp);
570 584 }
571 585 #endif
572 586 } else if (!strict) {
573 587 // EXTRA: could also use _Unicode, but why should we?
574 588 PyObject* str = PyObject_Str(val);
575 589 if (str) {
576 590 r = QString(PyString_AS_STRING(str));
577 591 Py_DECREF(str);
578 592 } else {
579 593 ok = false;
580 594 }
581 595 } else {
582 596 ok = false;
583 597 }
584 598 return r;
585 599 }
586 600
587 601 QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) {
588 602 QByteArray r;
589 603 ok = true;
590 604 if (val->ob_type == &PyString_Type) {
591 605 long size = PyString_GET_SIZE(val);
592 606 r = QByteArray(PyString_AS_STRING(val), size);
593 607 } else {
594 608 ok = false;
595 609 }
596 610 return r;
597 611 }
598 612
599 613 bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) {
600 614 bool d = false;
601 615 ok = false;
602 616 if (val == Py_False) {
603 617 d = false;
604 618 ok = true;
605 619 } else if (val == Py_True) {
606 620 d = true;
607 621 ok = true;
608 622 } else if (!strict) {
609 623 d = PyObjGetInt(val, false, ok)!=0;
610 624 ok = true;
611 625 }
612 626 return d;
613 627 }
614 628
615 629 int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) {
616 630 int d = 0;
617 631 ok = true;
618 632 if (val->ob_type == &PyInt_Type) {
619 633 d = PyInt_AS_LONG(val);
620 634 } else if (!strict) {
621 635 if (PyObject_TypeCheck(val, &PyInt_Type)) {
622 636 // support for derived int classes, e.g. for our enums
623 637 d = PyInt_AS_LONG(val);
624 638 } else if (val->ob_type == &PyFloat_Type) {
625 639 d = floor(PyFloat_AS_DOUBLE(val));
626 640 } else if (val->ob_type == &PyLong_Type) {
627 641 // handle error on overflow!
628 642 d = PyLong_AsLong(val);
629 643 } else if (val == Py_False) {
630 644 d = 0;
631 645 } else if (val == Py_True) {
632 646 d = 1;
633 647 } else {
634 648 ok = false;
635 649 }
636 650 } else {
637 651 ok = false;
638 652 }
639 653 return d;
640 654 }
641 655
642 656 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
643 657 qint64 d = 0;
644 658 ok = true;
645 659 if (val->ob_type == &PyInt_Type) {
646 660 d = PyInt_AS_LONG(val);
647 661 } else if (val->ob_type == &PyLong_Type) {
648 662 d = PyLong_AsLongLong(val);
649 663 } else if (!strict) {
650 664 if (PyObject_TypeCheck(val, &PyInt_Type)) {
651 665 // support for derived int classes, e.g. for our enums
652 666 d = PyInt_AS_LONG(val);
653 667 } else if (val->ob_type == &PyFloat_Type) {
654 668 d = floor(PyFloat_AS_DOUBLE(val));
655 669 } else if (val == Py_False) {
656 670 d = 0;
657 671 } else if (val == Py_True) {
658 672 d = 1;
659 673 } else {
660 674 ok = false;
661 675 }
662 676 } else {
663 677 ok = false;
664 678 }
665 679 return d;
666 680 }
667 681
668 682 quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) {
669 683 quint64 d = 0;
670 684 ok = true;
671 685 if (PyObject_TypeCheck(val, &PyInt_Type)) {
672 686 d = PyInt_AS_LONG(val);
673 687 } else if (val->ob_type == &PyLong_Type) {
674 688 d = PyLong_AsLongLong(val);
675 689 } else if (!strict) {
676 690 if (PyObject_TypeCheck(val, &PyInt_Type)) {
677 691 // support for derived int classes, e.g. for our enums
678 692 d = PyInt_AS_LONG(val);
679 693 } else if (val->ob_type == &PyFloat_Type) {
680 694 d = floor(PyFloat_AS_DOUBLE(val));
681 695 } else if (val == Py_False) {
682 696 d = 0;
683 697 } else if (val == Py_True) {
684 698 d = 1;
685 699 } else {
686 700 ok = false;
687 701 }
688 702 } else {
689 703 ok = false;
690 704 }
691 705 return d;
692 706 }
693 707
694 708 double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) {
695 709 double d = 0;
696 710 ok = true;
697 711 if (val->ob_type == &PyFloat_Type) {
698 712 d = PyFloat_AS_DOUBLE(val);
699 713 } else if (!strict) {
700 714 if (PyObject_TypeCheck(val, &PyInt_Type)) {
701 715 d = PyInt_AS_LONG(val);
702 716 } else if (val->ob_type == &PyLong_Type) {
703 717 d = PyLong_AsLong(val);
704 718 } else if (val == Py_False) {
705 719 d = 0;
706 720 } else if (val == Py_True) {
707 721 d = 1;
708 722 } else {
709 723 ok = false;
710 724 }
711 725 } else {
712 726 ok = false;
713 727 }
714 728 return d;
715 729 }
716 730
717 731 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
718 732 {
719 733 QVariant v;
720 734 bool ok = true;
721 735
722 736 if (type==-1) {
723 737 // no special type requested
724 738 if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) {
725 739 type = QVariant::String;
726 740 } else if (PyObject_TypeCheck(val, &PyInt_Type)) {
727 741 type = QVariant::Int;
728 742 } else if (val->ob_type==&PyLong_Type) {
729 743 type = QVariant::LongLong;
730 744 } else if (val->ob_type==&PyFloat_Type) {
731 745 type = QVariant::Double;
732 746 } else if (val == Py_False || val == Py_True) {
733 747 type = QVariant::Bool;
734 748 } else if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
735 749 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
736 750 // c++ wrapper, check if the class names of the c++ objects match
737 751 if (wrap->classInfo()->isCPPWrapper()) {
738 752 if (wrap->classInfo()->metaTypeId()>0) {
739 753 // construct a new variant from the C++ object if it has a meta type (this will COPY the object!)
740 754 v = QVariant(wrap->classInfo()->metaTypeId(), wrap->_wrappedPtr);
741 755 } else {
742 756 // TODOXXX we could as well check if there is a registered meta type for "classname*", so that we may pass
743 757 // the pointer here...
744 758 // is this worth anything? we loose the knowledge of the cpp object type
745 759 v = qVariantFromValue(wrap->_wrappedPtr);
746 760 }
747 761 } else {
748 762 // this gives us a QObject pointer
749 763 QObject* myObject = wrap->_obj;
750 764 v = qVariantFromValue(myObject);
751 765 }
752 766 return v;
753 767 } else if (val->ob_type==&PyDict_Type) {
754 768 type = QVariant::Map;
755 769 } else if (val->ob_type==&PyList_Type || val->ob_type==&PyTuple_Type || PySequence_Check(val)) {
756 770 type = QVariant::List;
757 771 } else if (val == Py_None) {
758 772 // none is invalid
759 773 type = QVariant::Invalid;
760 774 } else {
761 775 // this used to be:
762 776 // type = QVariant::String;
763 777 // but now we want to transport the Python Objects directly:
764 778 PythonQtObjectPtr o(val);
765 779 v = qVariantFromValue(o);
766 780 return v;
767 781 }
768 782 }
769 783 // special type request:
770 784 switch (type) {
771 785 case QVariant::Invalid:
772 786 return v;
773 787 break;
774 788 case QVariant::Int:
775 789 {
776 790 int d = PyObjGetInt(val, false, ok);
777 791 if (ok) return QVariant(d);
778 792 }
779 793 break;
780 794 case QVariant::UInt:
781 795 {
782 796 int d = PyObjGetInt(val, false,ok);
783 797 if (ok) v = QVariant((unsigned int)d);
784 798 }
785 799 break;
786 800 case QVariant::Bool:
787 801 {
788 802 int d = PyObjGetBool(val,false,ok);
789 803 if (ok) v = QVariant((bool)(d!=0));
790 804 }
791 805 break;
792 806 case QVariant::Double:
793 807 {
794 808 double d = PyObjGetDouble(val,false,ok);
795 809 if (ok) v = QVariant(d);
796 810 break;
797 811 }
798 812 case QMetaType::Float:
799 813 {
800 814 float d = (float) PyObjGetDouble(val,false,ok);
801 815 if (ok) v = qVariantFromValue(d);
802 816 break;
803 817 }
804 818 case QMetaType::Long:
805 819 {
806 820 long d = (long) PyObjGetLongLong(val,false,ok);
807 821 if (ok) v = qVariantFromValue(d);
808 822 break;
809 823 }
810 824 case QMetaType::ULong:
811 825 {
812 826 unsigned long d = (unsigned long) PyObjGetLongLong(val,false,ok);
813 827 if (ok) v = qVariantFromValue(d);
814 828 break;
815 829 }
816 830 case QMetaType::Short:
817 831 {
818 832 short d = (short) PyObjGetInt(val,false,ok);
819 833 if (ok) v = qVariantFromValue(d);
820 834 break;
821 835 }
822 836 case QMetaType::UShort:
823 837 {
824 838 unsigned short d = (unsigned short) PyObjGetInt(val,false,ok);
825 839 if (ok) v = qVariantFromValue(d);
826 840 break;
827 841 }
828 842 case QMetaType::Char:
829 843 {
830 844 char d = (char) PyObjGetInt(val,false,ok);
831 845 if (ok) v = qVariantFromValue(d);
832 846 break;
833 847 }
834 848 case QMetaType::UChar:
835 849 {
836 850 unsigned char d = (unsigned char) PyObjGetInt(val,false,ok);
837 851 if (ok) v = qVariantFromValue(d);
838 852 break;
839 853 }
840 854
841 855 case QVariant::ByteArray:
842 856 case QVariant::String:
843 857 {
844 858 bool ok;
845 859 v = QVariant(PyObjGetString(val, false, ok));
846 860 }
847 861 break;
848 862
849 863 // these are important for MeVisLab
850 864 case QVariant::Map:
851 865 {
852 866 if (PyMapping_Check(val)) {
853 867 QMap<QString,QVariant> map;
854 868 PyObject* items = PyMapping_Items(val);
855 869 if (items) {
856 870 int count = PyList_Size(items);
857 871 PyObject* value;
858 872 PyObject* key;
859 873 PyObject* tuple;
860 874 for (int i = 0;i<count;i++) {
861 875 tuple = PyList_GetItem(items,i);
862 876 key = PyTuple_GetItem(tuple, 0);
863 877 value = PyTuple_GetItem(tuple, 1);
864 878 map.insert(PyObjGetString(key), PyObjToQVariant(value,-1));
865 879 }
866 880 Py_DECREF(items);
867 881 v = map;
868 882 }
869 883 }
870 884 }
871 885 break;
872 886 case QVariant::List:
873 887 if (PySequence_Check(val)) {
874 888 QVariantList list;
875 889 int count = PySequence_Size(val);
876 890 PyObject* value;
877 891 for (int i = 0;i<count;i++) {
878 892 value = PySequence_GetItem(val,i);
879 893 list.append(PyObjToQVariant(value, -1));
880 894 }
881 895 v = list;
882 896 }
883 897 break;
884 898 case QVariant::StringList:
885 899 {
886 900 bool ok;
887 901 QStringList l = PyObjToStringList(val, false, ok);
888 902 if (ok) {
889 903 v = l;
890 904 }
891 905 }
892 906 break;
893 907
894 908 default:
895 909 if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
896 910 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
897 911 if (wrap->classInfo()->isCPPWrapper() && wrap->classInfo()->metaTypeId() == type) {
898 912 // construct a new variant from the C++ object if it has the same meta type
899 913 v = QVariant(type, wrap->_wrappedPtr);
900 914 } else {
901 915 v = QVariant();
902 916 }
903 917 } else {
904 918 v = QVariant();
905 919 }
906 920 }
907 921 return v;
908 922 }
909 923
910 924 PyObject* PythonQtConv::QStringToPyObject(const QString& str)
911 925 {
912 926 if (str.isNull()) {
913 927 return PyString_FromString("");
914 928 } else {
915 929 #ifdef WIN32
916 930 // return PyString_FromString(str.toLatin1().data());
917 931 return PyUnicode_FromUnicode(str.utf16(), str.length());
918 932 #else
919 933 return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, NULL, NULL);
920 934 #endif
921 935 }
922 936 }
923 937
924 938 PyObject* PythonQtConv::QStringListToPyObject(const QStringList& list)
925 939 {
926 940 PyObject* result = PyTuple_New(list.count());
927 941 int i = 0;
928 942 QString str;
929 943 foreach (str, list) {
930 944 PyTuple_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(str));
931 945 i++;
932 946 }
933 947 // why is the error state bad after this?
934 948 PyErr_Clear();
935 949 return result;
936 950 }
937 951
938 952 PyObject* PythonQtConv::QStringListToPyList(const QStringList& list)
939 953 {
940 954 PyObject* result = PyList_New(list.count());
941 955 int i = 0;
942 956 for (QStringList::ConstIterator it = list.begin(); it!=list.end(); ++it) {
943 957 PyList_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(*it));
944 958 i++;
945 959 }
946 960 return result;
947 961 }
948 962
949 963 PyObject* PythonQtConv::QVariantToPyObject(const QVariant& v)
950 964 {
951 965 return ConvertQtValueToPythonInternal(v.userType(), (void*)v.constData());
952 966 }
953 967
954 968 PyObject* PythonQtConv::QVariantMapToPyObject(const QVariantMap& m) {
955 969 PyObject* result = PyDict_New();
956 970 QVariantMap::const_iterator t = m.constBegin();
957 971 PyObject* key;
958 972 PyObject* val;
959 973 for (;t!=m.end();t++) {
960 974 key = QStringToPyObject(t.key());
961 975 val = QVariantToPyObject(t.value());
962 976 PyDict_SetItem(result, key, val);
963 977 Py_DECREF(key);
964 978 Py_DECREF(val);
965 979 }
966 980 return result;
967 981 }
968 982
969 983 PyObject* PythonQtConv::QVariantListToPyObject(const QVariantList& l) {
970 984 PyObject* result = PyTuple_New(l.count());
971 985 int i = 0;
972 986 QVariant v;
973 987 foreach (v, l) {
974 988 PyTuple_SET_ITEM(result, i, PythonQtConv::QVariantToPyObject(v));
975 989 i++;
976 990 }
977 991 // why is the error state bad after this?
978 992 PyErr_Clear();
979 993 return result;
980 994 }
981 995
982 996 PyObject* PythonQtConv::ConvertQListOfPointerTypeToPythonList(QList<void*>* list, const QByteArray& typeName)
983 997 {
984 998 PyObject* result = PyTuple_New(list->count());
985 999 int i = 0;
986 1000 foreach (void* value, *list) {
987 1001 PyTuple_SET_ITEM(result, i, PythonQt::priv()->wrapPtr(value, typeName));
988 1002 i++;
989 1003 }
990 1004 return result;
991 1005 }
992 1006
993 1007 bool PythonQtConv::ConvertPythonListToQListOfPointerType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool /*strict*/)
994 1008 {
995 1009 bool result = false;
996 1010 if (PySequence_Check(obj)) {
997 1011 result = true;
998 1012 int count = PySequence_Size(obj);
999 1013 PyObject* value;
1000 1014 for (int i = 0;i<count;i++) {
1001 1015 value = PySequence_GetItem(obj,i);
1002 1016 if (PyObject_TypeCheck(value, &PythonQtInstanceWrapper_Type)) {
1003 1017 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)value;
1004 1018 bool ok;
1005 1019 void* object = castWrapperTo(wrap, type, ok);
1006 1020 if (ok) {
1007 1021 list->append(object);
1008 1022 } else {
1009 1023 result = false;
1010 1024 break;
1011 1025 }
1012 1026 }
1013 1027 }
1014 1028 }
1015 1029 return result;
1016 1030 }
1017 1031
1018 1032 int PythonQtConv::getInnerTemplateMetaType(const QByteArray& typeName)
1019 1033 {
1020 1034 int idx = typeName.indexOf("<");
1021 1035 if (idx>0) {
1022 1036 int idx2 = typeName.indexOf(">");
1023 1037 if (idx2>0) {
1024 1038 QByteArray innerType = typeName.mid(idx+1,idx2-idx-1);
1025 1039 return QMetaType::type(innerType.constData());
1026 1040 }
1027 1041 }
1028 1042 return QMetaType::Void;
1029 1043 }
1030 1044
1031 1045
1032 1046
1033 1047 QString PythonQtConv::qVariantToString(const QVariant& v) {
1034 1048 return CPPObjectToString(v.userType(), v.constData());
1035 1049 }
1036 1050
1037 1051 QString PythonQtConv::CPPObjectToString(int type, const void* data) {
1038 1052 QString r;
1039 1053 switch (type) {
1040 1054 case QVariant::Size: {
1041 1055 const QSize* s = static_cast<const QSize*>(data);
1042 1056 r = QString::number(s->width()) + ", " + QString::number(s->height());
1043 1057 }
1044 1058 break;
1045 1059 case QVariant::SizeF: {
1046 1060 const QSizeF* s = static_cast<const QSizeF*>(data);
1047 1061 r = QString::number(s->width()) + ", " + QString::number(s->height());
1048 1062 }
1049 1063 break;
1050 1064 case QVariant::Point: {
1051 1065 const QPoint* s = static_cast<const QPoint*>(data);
1052 1066 r = QString::number(s->x()) + ", " + QString::number(s->y());
1053 1067 }
1054 1068 break;
1055 1069 case QVariant::PointF: {
1056 1070 const QPointF* s = static_cast<const QPointF*>(data);
1057 1071 r = QString::number(s->x()) + ", " + QString::number(s->y());
1058 1072 }
1059 1073 break;
1060 1074 case QVariant::Rect: {
1061 1075 const QRect* s = static_cast<const QRect*>(data);
1062 1076 r = QString::number(s->x()) + ", " + QString::number(s->y());
1063 1077 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1064 1078 }
1065 1079 break;
1066 1080 case QVariant::RectF: {
1067 1081 const QRectF* s = static_cast<const QRectF*>(data);
1068 1082 r = QString::number(s->x()) + ", " + QString::number(s->y());
1069 1083 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1070 1084 }
1071 1085 break;
1072 1086 case QVariant::Date: {
1073 1087 const QDate* s = static_cast<const QDate*>(data);
1074 1088 r = s->toString(Qt::ISODate);
1075 1089 }
1076 1090 break;
1077 1091 case QVariant::DateTime: {
1078 1092 const QDateTime* s = static_cast<const QDateTime*>(data);
1079 1093 r = s->toString(Qt::ISODate);
1080 1094 }
1081 1095 break;
1082 1096 case QVariant::Time: {
1083 1097 const QTime* s = static_cast<const QTime*>(data);
1084 1098 r = s->toString(Qt::ISODate);
1085 1099 }
1086 1100 break;
1087 1101 case QVariant::Pixmap:
1088 1102 {
1089 1103 const QPixmap* s = static_cast<const QPixmap*>(data);
1090 1104 r = QString("Pixmap ") + QString::number(s->width()) + ", " + QString::number(s->height());
1091 1105 }
1092 1106 break;
1093 1107 case QVariant::Image:
1094 1108 {
1095 1109 const QImage* s = static_cast<const QImage*>(data);
1096 1110 r = QString("Image ") + QString::number(s->width()) + ", " + QString::number(s->height());
1097 1111 }
1098 1112 break;
1099 1113 case QVariant::Url:
1100 1114 {
1101 1115 const QUrl* s = static_cast<const QUrl*>(data);
1102 1116 r = s->toString();
1103 1117 }
1104 1118 break;
1105 1119 //TODO: add more printing for other variant types
1106 1120 default:
1107 1121 // this creates a copy, but that should not be expensive for typical simple variants
1108 1122 // (but we do not want to do this for our won user types!
1109 1123 if (type>0 && type < (int)QVariant::UserType) {
1110 1124 QVariant v(type, data);
1111 1125 r = v.toString();
1112 1126 }
1113 1127 }
1114 1128 return r;
1115 1129 }
@@ -1,513 +1,500
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtSlot.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtSlot.h"
44 44 #include "PythonQtInstanceWrapper.h"
45 45 #include "PythonQtClassInfo.h"
46 46 #include "PythonQtMisc.h"
47 47 #include "PythonQtConversion.h"
48 48 #include <iostream>
49 49
50 50 #define PYTHONQT_MAX_ARGS 32
51 51
52 52
53 53 bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer)
54 54 {
55 55 static unsigned int recursiveEntry = 0;
56 56
57 57 if (directReturnValuePointer) {
58 58 *directReturnValuePointer = NULL;
59 59 }
60 60 // store the current storage position, so that we can get back to this state after a slot is called
61 61 // (do this locally, so that we have all positions on the stack
62 62 PythonQtValueStoragePosition globalValueStoragePos;
63 63 PythonQtValueStoragePosition globalPtrStoragePos;
64 64 PythonQtValueStoragePosition globalVariantStoragePos;
65 65 PythonQtConv::global_valueStorage.getPos(globalValueStoragePos);
66 66 PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos);
67 67 PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos);
68 68
69 69 recursiveEntry++;
70 70
71 71 // the arguments that are passed to qt_metacall
72 72 void* argList[PYTHONQT_MAX_ARGS];
73 73 PyObject* result = NULL;
74 74 int argc = info->parameterCount();
75 75 const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters();
76 76
77 77 const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);
78 78 // set return argument to NULL
79 79 argList[0] = NULL;
80 80
81 81 bool ok = true;
82 82 bool skipFirst = false;
83 83 if (info->isInstanceDecorator()) {
84 84 skipFirst = true;
85 85
86 86 // for decorators on CPP objects, we take the cpp ptr, for QObjects we take the QObject pointer
87 87 void* arg1 = firstArgument;
88 88 if (!arg1) {
89 89 arg1 = objectToCall;
90 90 }
91 91 if (arg1) {
92 92 // upcast to correct parent class
93 93 arg1 = ((char*)arg1)+info->upcastingOffset();
94 94 }
95 95
96 96 argList[1] = &arg1;
97 97 if (ok) {
98 98 for (int i = 2; i<argc && ok; i++) {
99 99 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
100 100 //std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
101 101 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, classInfo);
102 102 if (argList[i]==NULL) {
103 103 ok = false;
104 104 break;
105 105 }
106 106 }
107 107 }
108 108 } else {
109 109 for (int i = 1; i<argc && ok; i++) {
110 110 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
111 111 //std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
112 112 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, classInfo);
113 113 if (argList[i]==NULL) {
114 114 ok = false;
115 115 break;
116 116 }
117 117 }
118 118 }
119 119
120 120 if (ok) {
121 bool returnValueIsEnum = false;
122
123 121 // parameters are ok, now create the qt return value which is assigned to by metacall
124 122 if (returnValueParam.typeId != QMetaType::Void) {
125 // extra handling of enum return value
126 if (!returnValueParam.isPointer && returnValueParam.enumWrapper) {
127 // create enum return value
128 PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, argList[0]);
129 returnValueIsEnum = true;
130 } else {
131 123 // create empty default value for the return value
132 124 if (!directReturnValuePointer) {
133 125 // create empty default value for the return value
134 126 argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);
135 127 if (argList[0]==NULL) {
136 128 // 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
137 129 // pass its internal pointer
138 130 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(returnValueParam.name);
139 131 if (info && info->pythonQtClassWrapper()) {
140 132 PyObject* emptyTuple = PyTuple_New(0);
141 133 // 1) default construct an empty object as python object (owned by PythonQt), by calling the meta class with empty arguments
142 134 result = PyObject_Call((PyObject*)info->pythonQtClassWrapper(), emptyTuple, NULL);
143 135 if (result) {
144 136 argList[0] = ((PythonQtInstanceWrapper*)result)->_wrappedPtr;
145 137 }
146 138 Py_DECREF(emptyTuple);
147 139 }
148 140 }
149 141 } else {
150 142 // we can use our pointer directly!
151 143 argList[0] = directReturnValuePointer;
152 144 }
153 145 }
154 }
155 146
156 147 // invoke the slot via metacall
157 148 (info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
158 149
159 150 // handle the return value (which in most cases still needs to be converted to a Python object)
160 151 if (argList[0] || returnValueParam.typeId == QMetaType::Void) {
161 152 if (directReturnValuePointer) {
162 153 result = NULL;
163 154 } else {
164 if (!returnValueIsEnum) {
165 155 // the resulting object maybe present already, because we created it above at 1)...
166 156 if (!result) {
167 157 result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]);
168 158 }
169 } else {
170 result = PyInt_FromLong(*((unsigned int*)argList[0]));
171 }
172 159 }
173 160 } else {
174 161 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.";
175 162 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
176 163 result = NULL;
177 164 }
178 165 }
179 166 recursiveEntry--;
180 167
181 168 // reset the parameter storage position to the stored pos to "pop" the parameter stack
182 169 PythonQtConv::global_valueStorage.setPos(globalValueStoragePos);
183 170 PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos);
184 171 PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos);
185 172
186 173 *pythonReturnValue = result;
187 174 // NOTE: it is important to only return here, otherwise the stack will not be popped!!!
188 175 return result || (directReturnValuePointer && *directReturnValuePointer);
189 176 }
190 177
191 178 //-----------------------------------------------------------------------------------
192 179
193 180 static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL;
194 181
195 182 PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw)
196 183 {
197 184 PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func;
198 185 PythonQtSlotInfo* info = f->m_ml;
199 186 if (PyObject_TypeCheck(f->m_self, &PythonQtInstanceWrapper_Type)) {
200 187 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self;
201 188 return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr);
202 189 } else if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
203 190 PythonQtClassWrapper* type = (PythonQtClassWrapper*) f->m_self;
204 191 if (info->isClassDecorator()) {
205 192 return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw);
206 193 } else {
207 194 // otherwise, it is an unbound call and we have an instanceDecorator or normal slot...
208 195 Py_ssize_t argc = PyTuple_Size(args);
209 196 if (argc>0) {
210 197 PyObject* firstArg = PyTuple_GET_ITEM(args, 0);
211 198 if (PyObject_TypeCheck(firstArg, (PyTypeObject*)&PythonQtInstanceWrapper_Type)
212 199 && ((PythonQtInstanceWrapper*)firstArg)->classInfo()->inherits(type->classInfo())) {
213 200 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg;
214 201 // strip the first argument...
215 202 PyObject* newargs = PyTuple_GetSlice(args, 1, argc);
216 203 PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, newargs, kw, self->_wrappedPtr);
217 204 Py_DECREF(newargs);
218 205 return result;
219 206 } else {
220 207 // first arg is not of correct type!
221 208 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument, got " + firstArg->ob_type->tp_name;
222 209 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
223 210 return NULL;
224 211 }
225 212 } else {
226 213 // wrong number of args
227 214 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument.";
228 215 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
229 216 return NULL;
230 217 }
231 218 }
232 219 }
233 220 return NULL;
234 221 }
235 222
236 223 PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg, void** directReturnValuePointer)
237 224 {
238 225 int argc = PyTuple_Size(args);
239 226
240 227 #ifdef PYTHONQT_DEBUG
241 228 std::cout << "called " << info->metaMethod()->typeName() << " " << info->metaMethod()->signature() << std::endl;
242 229 #endif
243 230
244 231 PyObject* r = NULL;
245 232 bool ok = false;
246 233 if (directReturnValuePointer) {
247 234 *directReturnValuePointer = NULL;
248 235 }
249 236 if (info->nextInfo()) {
250 237 // overloaded slot call, try on all slots with strict conversion first
251 238 bool strict = true;
252 239 PythonQtSlotInfo* i = info;
253 240 while (i) {
254 241 bool skipFirst = i->isInstanceDecorator();
255 242 if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
256 243 PyErr_Clear();
257 244 ok = PythonQtCallSlot(classInfo, objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer);
258 245 if (PyErr_Occurred() || ok) break;
259 246 }
260 247 i = i->nextInfo();
261 248 if (!i) {
262 249 if (strict) {
263 250 // one more run without being strict
264 251 strict = false;
265 252 i = info;
266 253 }
267 254 }
268 255 }
269 256 if (!ok && !PyErr_Occurred()) {
270 257 QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n");
271 258 PythonQtSlotInfo* i = info;
272 259 while (i) {
273 260 e += QString(i->fullSignature()) + "\n";
274 261 i = i->nextInfo();
275 262 }
276 263 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
277 264 }
278 265 } else {
279 266 // simple (non-overloaded) slot call
280 267 bool skipFirst = info->isInstanceDecorator();
281 268 if (info->parameterCount()-1-(skipFirst?1:0) == argc) {
282 269 PyErr_Clear();
283 270 ok = PythonQtCallSlot(classInfo, objectToCall, args, false, info, firstArg, &r, directReturnValuePointer);
284 271 if (!ok && !PyErr_Occurred()) {
285 272 QString e = QString("Called ") + info->fullSignature() + " with wrong arguments: " + PythonQtConv::PyObjGetString(args);
286 273 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
287 274 }
288 275 } else {
289 276 QString e = QString("Called ") + info->fullSignature() + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args);
290 277 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
291 278 }
292 279 }
293 280
294 281 return r;
295 282 }
296 283
297 284 PyObject *
298 285 PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module)
299 286 {
300 287 PythonQtSlotFunctionObject *op;
301 288 op = pythonqtslot_free_list;
302 289 if (op != NULL) {
303 290 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self);
304 291 PyObject_INIT(op, &PythonQtSlotFunction_Type);
305 292 }
306 293 else {
307 294 op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type);
308 295 if (op == NULL)
309 296 return NULL;
310 297 }
311 298 op->m_ml = ml;
312 299 Py_XINCREF(self);
313 300 op->m_self = self;
314 301 Py_XINCREF(module);
315 302 op->m_module = module;
316 303 PyObject_GC_Track(op);
317 304 return (PyObject *)op;
318 305 }
319 306
320 307 PythonQtSlotInfo*
321 308 PythonQtSlotFunction_GetSlotInfo(PyObject *op)
322 309 {
323 310 if (!PythonQtSlotFunction_Check(op)) {
324 311 PyErr_BadInternalCall();
325 312 return NULL;
326 313 }
327 314 return ((PythonQtSlotFunctionObject *)op) -> m_ml;
328 315 }
329 316
330 317 PyObject *
331 318 PythonQtSlotFunction_GetSelf(PyObject *op)
332 319 {
333 320 if (!PythonQtSlotFunction_Check(op)) {
334 321 PyErr_BadInternalCall();
335 322 return NULL;
336 323 }
337 324 return ((PythonQtSlotFunctionObject *)op) -> m_self;
338 325 }
339 326
340 327 /* Methods (the standard built-in methods, that is) */
341 328
342 329 static void
343 330 meth_dealloc(PythonQtSlotFunctionObject *m)
344 331 {
345 332 PyObject_GC_UnTrack(m);
346 333 Py_XDECREF(m->m_self);
347 334 Py_XDECREF(m->m_module);
348 335 m->m_self = (PyObject *)pythonqtslot_free_list;
349 336 pythonqtslot_free_list = m;
350 337 }
351 338
352 339 static PyObject *
353 340 meth_get__doc__(PythonQtSlotFunctionObject * /*m*/, void * /*closure*/)
354 341 {
355 342 Py_INCREF(Py_None);
356 343 return Py_None;
357 344 }
358 345
359 346 static PyObject *
360 347 meth_get__name__(PythonQtSlotFunctionObject *m, void * /*closure*/)
361 348 {
362 349 return PyString_FromString(m->m_ml->metaMethod()->signature());
363 350 }
364 351
365 352 static int
366 353 meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg)
367 354 {
368 355 int err;
369 356 if (m->m_self != NULL) {
370 357 err = visit(m->m_self, arg);
371 358 if (err)
372 359 return err;
373 360 }
374 361 if (m->m_module != NULL) {
375 362 err = visit(m->m_module, arg);
376 363 if (err)
377 364 return err;
378 365 }
379 366 return 0;
380 367 }
381 368
382 369 static PyObject *
383 370 meth_get__self__(PythonQtSlotFunctionObject *m, void * /*closure*/)
384 371 {
385 372 PyObject *self;
386 373 if (PyEval_GetRestricted()) {
387 374 PyErr_SetString(PyExc_RuntimeError,
388 375 "method.__self__ not accessible in restricted mode");
389 376 return NULL;
390 377 }
391 378 self = m->m_self;
392 379 if (self == NULL)
393 380 self = Py_None;
394 381 Py_INCREF(self);
395 382 return self;
396 383 }
397 384
398 385 static PyGetSetDef meth_getsets [] = {
399 386 {"__doc__", (getter)meth_get__doc__, NULL, NULL},
400 387 {"__name__", (getter)meth_get__name__, NULL, NULL},
401 388 {"__self__", (getter)meth_get__self__, NULL, NULL},
402 389 {NULL, NULL, NULL,NULL},
403 390 };
404 391
405 392 #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6
406 393 #define PY_WRITE_RESTRICTED WRITE_RESTRICTED
407 394 #endif
408 395
409 396 #define OFF(x) offsetof(PythonQtSlotFunctionObject, x)
410 397
411 398 static PyMemberDef meth_members[] = {
412 399 {"__module__", T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED},
413 400 {NULL}
414 401 };
415 402
416 403 static PyObject *
417 404 meth_repr(PythonQtSlotFunctionObject *f)
418 405 {
419 406 if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
420 407 PythonQtClassWrapper* self = (PythonQtClassWrapper*) f->m_self;
421 408 return PyString_FromFormat("<unbound qt slot %s of %s type>",
422 409 f->m_ml->slotName().data(),
423 410 self->classInfo()->className());
424 411 } else {
425 412 return PyString_FromFormat("<qt slot %s of %s instance at %p>",
426 413 f->m_ml->slotName().data(),
427 414 f->m_self->ob_type->tp_name,
428 415 f->m_self);
429 416 }
430 417 }
431 418
432 419 static int
433 420 meth_compare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b)
434 421 {
435 422 if (a->m_self != b->m_self)
436 423 return (a->m_self < b->m_self) ? -1 : 1;
437 424 if (a->m_ml == b->m_ml)
438 425 return 0;
439 426 if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0)
440 427 return -1;
441 428 else
442 429 return 1;
443 430 }
444 431
445 432 static long
446 433 meth_hash(PythonQtSlotFunctionObject *a)
447 434 {
448 435 long x,y;
449 436 if (a->m_self == NULL)
450 437 x = 0;
451 438 else {
452 439 x = PyObject_Hash(a->m_self);
453 440 if (x == -1)
454 441 return -1;
455 442 }
456 443 y = _Py_HashPointer((void*)(a->m_ml));
457 444 if (y == -1)
458 445 return -1;
459 446 x ^= y;
460 447 if (x == -1)
461 448 x = -2;
462 449 return x;
463 450 }
464 451
465 452
466 453 PyTypeObject PythonQtSlotFunction_Type = {
467 454 PyObject_HEAD_INIT(&PyType_Type)
468 455 0,
469 456 "builtin_qt_slot",
470 457 sizeof(PythonQtSlotFunctionObject),
471 458 0,
472 459 (destructor)meth_dealloc, /* tp_dealloc */
473 460 0, /* tp_print */
474 461 0, /* tp_getattr */
475 462 0, /* tp_setattr */
476 463 (cmpfunc)meth_compare, /* tp_compare */
477 464 (reprfunc)meth_repr, /* tp_repr */
478 465 0, /* tp_as_number */
479 466 0, /* tp_as_sequence */
480 467 0, /* tp_as_mapping */
481 468 (hashfunc)meth_hash, /* tp_hash */
482 469 PythonQtSlotFunction_Call, /* tp_call */
483 470 0, /* tp_str */
484 471 PyObject_GenericGetAttr, /* tp_getattro */
485 472 0, /* tp_setattro */
486 473 0, /* tp_as_buffer */
487 474 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
488 475 0, /* tp_doc */
489 476 (traverseproc)meth_traverse, /* tp_traverse */
490 477 0, /* tp_clear */
491 478 0, /* tp_richcompare */
492 479 0, /* tp_weaklistoffset */
493 480 0, /* tp_iter */
494 481 0, /* tp_iternext */
495 482 0, /* tp_methods */
496 483 meth_members, /* tp_members */
497 484 meth_getsets, /* tp_getset */
498 485 0, /* tp_base */
499 486 0, /* tp_dict */
500 487 };
501 488
502 489 /* Clear out the free list */
503 490
504 491 void
505 492 PythonQtSlotFunction_Fini(void)
506 493 {
507 494 while (pythonqtslot_free_list) {
508 495 PythonQtSlotFunctionObject *v = pythonqtslot_free_list;
509 496 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(v->m_self);
510 497 PyObject_GC_Del(v);
511 498 }
512 499 }
513 500
General Comments 0
You need to be logged in to leave comments. Login now