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