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