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