##// END OF EJS Templates
cleanup of code and addition of (yet unused) classinfo passed to method/slot info to allow local enum support on creation...
florianlink -
r54:8f57e6dac237
parent child
Show More
@@ -1,1186 +1,1184
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtImporter.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include "PythonQtMethodInfo.h"
46 46 #include "PythonQtSignalReceiver.h"
47 47 #include "PythonQtConversion.h"
48 48 #include "PythonQtStdOut.h"
49 49 #include "PythonQtCppWrapperFactory.h"
50 50 #include "PythonQtVariants.h"
51 51 #include "PythonQtStdDecorators.h"
52 52 #include "PythonQtQFileImporter.h"
53 53 #include <pydebug.h>
54 54 #include <vector>
55 55
56 56 PythonQt* PythonQt::_self = NULL;
57 57 int PythonQt::_uniqueModuleCount = 0;
58 58
59 59 void PythonQt::init(int flags)
60 60 {
61 61 if (!_self) {
62 62 _self = new PythonQt(flags);
63 63 }
64 64
65 65 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
66 66 qRegisterMetaType<QList<QObject*> >("QList<void*>");
67 67
68 68 PythonQtRegisterToolClassesTemplateConverter(int);
69 69 PythonQtRegisterToolClassesTemplateConverter(float);
70 70 PythonQtRegisterToolClassesTemplateConverter(double);
71 71 // TODO: which other POD types should be available for QList etc.
72 72
73 73 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
74 74
75 75 PythonQt::self()->registerCPPClass("Qt", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_Qt>);
76 76 PythonQt::self()->registerCPPClass("QBitArray", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QBitArray>);
77 77 PythonQt::self()->registerCPPClass("QDate", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QDate>);
78 78 PythonQt::self()->registerCPPClass("QTime", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QTime>);
79 79 PythonQt::self()->registerCPPClass("QDateTime", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QDateTime>);
80 80 PythonQt::self()->registerCPPClass("QUrl", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QUrl>);
81 81 PythonQt::self()->registerCPPClass("QLocale", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLocale>);
82 82 PythonQt::self()->registerCPPClass("QRect", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRect>);
83 83 PythonQt::self()->registerCPPClass("QRectF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRectF>);
84 84 PythonQt::self()->registerCPPClass("QSize", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QSize>);
85 85 PythonQt::self()->registerCPPClass("QSizeF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QSizeF>);
86 86 PythonQt::self()->registerCPPClass("QLine", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLine>);
87 87 PythonQt::self()->registerCPPClass("QLineF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLineF>);
88 88 PythonQt::self()->registerCPPClass("QPoint", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QPoint>);
89 89 PythonQt::self()->registerCPPClass("QPointF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QPointF>);
90 90 PythonQt::self()->registerCPPClass("QRegExp", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRegExp>);
91 91
92 92 PythonQtRegisterToolClassesTemplateConverter(QDate);
93 93 PythonQtRegisterToolClassesTemplateConverter(QTime);
94 94 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
95 95 PythonQtRegisterToolClassesTemplateConverter(QUrl);
96 96 PythonQtRegisterToolClassesTemplateConverter(QLocale);
97 97 PythonQtRegisterToolClassesTemplateConverter(QRect);
98 98 PythonQtRegisterToolClassesTemplateConverter(QRectF);
99 99 PythonQtRegisterToolClassesTemplateConverter(QSize);
100 100 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
101 101 PythonQtRegisterToolClassesTemplateConverter(QLine);
102 102 PythonQtRegisterToolClassesTemplateConverter(QLineF);
103 103 PythonQtRegisterToolClassesTemplateConverter(QPoint);
104 104 PythonQtRegisterToolClassesTemplateConverter(QPointF);
105 105 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
106 106
107 107 PythonQt::self()->registerCPPClass("QFont", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QFont>);
108 108 PythonQt::self()->registerCPPClass("QPixmap", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPixmap>);
109 109 PythonQt::self()->registerCPPClass("QBrush", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QBrush>);
110 110 PythonQt::self()->registerCPPClass("QColor", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QColor>);
111 111 PythonQt::self()->registerCPPClass("QPalette", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPalette>);
112 112 PythonQt::self()->registerCPPClass("QIcon", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QIcon>);
113 113 PythonQt::self()->registerCPPClass("QImage", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QImage>);
114 114 PythonQt::self()->registerCPPClass("QPolygon", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPolygon>);
115 115 PythonQt::self()->registerCPPClass("QRegion", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QRegion>);
116 116 PythonQt::self()->registerCPPClass("QBitmap", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QBitmap>);
117 117 PythonQt::self()->registerCPPClass("QCursor", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QCursor>);
118 118 PythonQt::self()->registerCPPClass("QSizePolicy", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QSizePolicy>);
119 119 PythonQt::self()->registerCPPClass("QKeySequence", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QKeySequence>);
120 120 PythonQt::self()->registerCPPClass("QPen", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPen>);
121 121 PythonQt::self()->registerCPPClass("QTextLength", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QTextLength>);
122 122 PythonQt::self()->registerCPPClass("QTextFormat", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QTextFormat>);
123 123 PythonQt::self()->registerCPPClass("QMatrix", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QMatrix>);
124 124
125 125 PythonQtRegisterToolClassesTemplateConverter(QFont);
126 126 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
127 127 PythonQtRegisterToolClassesTemplateConverter(QBrush);
128 128 PythonQtRegisterToolClassesTemplateConverter(QColor);
129 129 PythonQtRegisterToolClassesTemplateConverter(QPalette);
130 130 PythonQtRegisterToolClassesTemplateConverter(QIcon);
131 131 PythonQtRegisterToolClassesTemplateConverter(QImage);
132 132 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
133 133 PythonQtRegisterToolClassesTemplateConverter(QRegion);
134 134 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
135 135 PythonQtRegisterToolClassesTemplateConverter(QCursor);
136 136 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
137 137 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
138 138 PythonQtRegisterToolClassesTemplateConverter(QPen);
139 139 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
140 140 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
141 141 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
142 142
143 143 }
144 144
145 145 void PythonQt::cleanup()
146 146 {
147 147 if (_self) {
148 148 delete _self;
149 149 _self = NULL;
150 150 }
151 151 }
152 152
153 153 PythonQt::PythonQt(int flags)
154 154 {
155 155 _p = new PythonQtPrivate;
156 156 _p->_initFlags = flags;
157 157
158 158 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
159 159
160 160 Py_SetProgramName("PythonQt");
161 161 if (flags & IgnoreSiteModule) {
162 162 // this prevents the automatic importing of Python site files
163 163 Py_NoSiteFlag = 1;
164 164 }
165 165 Py_Initialize();
166 166
167 167 // add our own python object types for qt object slots
168 168 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
169 169 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
170 170 }
171 171 Py_INCREF(&PythonQtSlotFunction_Type);
172 172
173 173 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
174 174 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
175 175 // add our own python object types for classes
176 176 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
177 177 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
178 178 }
179 179 Py_INCREF(&PythonQtClassWrapper_Type);
180 180
181 181 // add our own python object types for CPP instances
182 182 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
183 183 PythonQt::handleError();
184 184 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
185 185 }
186 186 Py_INCREF(&PythonQtInstanceWrapper_Type);
187 187
188 188 // add our own python object types for redirection of stdout
189 189 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
190 190 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
191 191 }
192 192 Py_INCREF(&PythonQtStdOutRedirectType);
193 193
194 194 initPythonQtModule(flags & RedirectStdOut);
195 195
196 196 }
197 197
198 198 PythonQt::~PythonQt() {
199 199 delete _p;
200 200 _p = NULL;
201 201 }
202 202
203 203 PythonQtPrivate::~PythonQtPrivate() {
204 204 delete _defaultImporter;
205 205 _defaultImporter = NULL;
206 206
207 207 {
208 208 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
209 209 while (i.hasNext()) {
210 210 delete i.next().value();
211 211 }
212 212 }
213 213 PythonQtConv::global_valueStorage.clear();
214 214 PythonQtConv::global_ptrStorage.clear();
215 215 PythonQtConv::global_variantStorage.clear();
216 216
217 217 PythonQtMethodInfo::cleanupCachedMethodInfos();
218 218 }
219 219
220 220 PythonQtImportFileInterface* PythonQt::importInterface()
221 221 {
222 222 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
223 223 }
224 224
225 225 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
226 226 {
227 227 if (_self->_p->_noLongerWrappedCB) {
228 228 (*_self->_p->_noLongerWrappedCB)(o);
229 229 };
230 230 }
231 231
232 232 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
233 233 {
234 234 _p->registerClass(metaobject, package, wrapperCreator, shell);
235 235 }
236 236
237 237 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
238 238 {
239 239 // we register all classes in the hierarchy
240 240 const QMetaObject* m = metaobject;
241 241 bool first = true;
242 242 while (m) {
243 243 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
244 244 if (!info->pythonQtClassWrapper()) {
245 245 info->setupQObject(m);
246 246 createPythonQtClassWrapper(info, package);
247 247 if (m->superClass()) {
248 248 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
249 249 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
250 250 }
251 251 }
252 252 if (first) {
253 253 first = false;
254 254 if (wrapperCreator) {
255 255 info->setDecoratorProvider(wrapperCreator);
256 256 }
257 257 if (shell) {
258 258 info->setShellSetInstanceWrapperCB(shell);
259 259 }
260 260 }
261 261 m = m->superClass();
262 262 }
263 263 }
264 264
265 265 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package)
266 266 {
267 267 PyObject* pack = packageByName(package);
268 268 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, package);
269 269 PyModule_AddObject(pack, info->className(), pyobj);
270 270 if (package && strncmp(package,"Qt",2)==0) {
271 271 // since PyModule_AddObject steals the reference, we need a incref once more...
272 272 Py_INCREF(pyobj);
273 273 // put all qt objects into Qt as well
274 274 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
275 275 }
276 276 info->setPythonQtClassWrapper(pyobj);
277 277 }
278 278
279 279 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
280 280 {
281 281 if (!obj) {
282 282 Py_INCREF(Py_None);
283 283 return Py_None;
284 284 }
285 285 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
286 286 if (!wrap) {
287 287 // smuggling it in...
288 288 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
289 289 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
290 290 registerClass(obj->metaObject());
291 291 classInfo = _knownClassInfos.value(obj->metaObject()->className());
292 292 }
293 293 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
294 294 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
295 295 } else {
296 296 Py_INCREF(wrap);
297 297 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
298 298 }
299 299 return (PyObject*)wrap;
300 300 }
301 301
302 302 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
303 303 {
304 304 if (!ptr) {
305 305 Py_INCREF(Py_None);
306 306 return Py_None;
307 307 }
308 308
309 309 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
310 310 if (!wrap) {
311 311 PythonQtClassInfo* info = _knownClassInfos.value(name);
312 312 if (!info) {
313 313 // maybe it is a PyObject, which we can return directly
314 314 if (name == "PyObject") {
315 315 PyObject* p = (PyObject*)ptr;
316 316 Py_INCREF(p);
317 317 return p;
318 318 }
319 319
320 320 // we do not know the metaobject yet, but we might know it by it's name:
321 321 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
322 322 // yes, we know it, so we can convert to QObject
323 323 QObject* qptr = (QObject*)ptr;
324 324 registerClass(qptr->metaObject());
325 325 info = _knownClassInfos.value(qptr->metaObject()->className());
326 326 }
327 327 }
328 328 if (info && info->isQObject()) {
329 329 QObject* qptr = (QObject*)ptr;
330 330 // if the object is a derived object, we want to switch the class info to the one of the derived class:
331 331 if (name!=(qptr->metaObject()->className())) {
332 332 registerClass(qptr->metaObject());
333 333 info = _knownClassInfos.value(qptr->metaObject()->className());
334 334 }
335 335 wrap = createNewPythonQtInstanceWrapper(qptr, info);
336 336 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
337 337 return (PyObject*)wrap;
338 338 }
339 339
340 340 // not a known QObject, so try our wrapper factory:
341 341 QObject* wrapper = NULL;
342 342 for (int i=0; i<_cppWrapperFactories.size(); i++) {
343 343 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
344 344 if (wrapper) {
345 345 break;
346 346 }
347 347 }
348 348
349 349 if (info) {
350 350 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
351 351 ptr = info->castDownIfPossible(ptr, &info);
352 352 }
353 353
354 354 if (!info || info->pythonQtClassWrapper()==NULL) {
355 355 // still unknown, register as CPP class
356 356 registerCPPClass(name.constData());
357 357 info = _knownClassInfos.value(name);
358 358 }
359 359 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
360 360 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
361 361 info->setMetaObject(wrapper->metaObject());
362 362 }
363 363 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
364 364 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
365 365 } else {
366 366 Py_INCREF(wrap);
367 367 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
368 368 }
369 369 return (PyObject*)wrap;
370 370 }
371 371
372 372 PyObject* PythonQtPrivate::dummyTuple() {
373 373 static PyObject* dummyTuple = NULL;
374 374 if (dummyTuple==NULL) {
375 375 dummyTuple = PyTuple_New(1);
376 376 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
377 377 }
378 378 return dummyTuple;
379 379 }
380 380
381 381
382 382 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
383 383 // call the associated class type to create a new instance...
384 384 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
385 385
386 386 result->setQObject(obj);
387 387 result->_wrappedPtr = wrappedPtr;
388 388 result->_ownedByPythonQt = false;
389 389 result->_useQMetaTypeDestroy = false;
390 390
391 391 if (wrappedPtr) {
392 392 _wrappedObjects.insert(wrappedPtr, result);
393 393 } else {
394 394 _wrappedObjects.insert(obj, result);
395 395 if (obj->parent()== NULL && _wrappedCB) {
396 396 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
397 397 (*_wrappedCB)(obj);
398 398 }
399 399 }
400 400 return result;
401 401 }
402 402
403 403 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package) {
404 404 PythonQtClassWrapper* result;
405 405
406 406 PyObject* className = PyString_FromString(info->className());
407 407
408 408 PyObject* baseClasses = PyTuple_New(1);
409 409 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
410 410
411 411 PyObject* typeDict = PyDict_New();
412 412 QByteArray moduleName("PythonQt");
413 413 if (package && strcmp(package, "")!=0) {
414 414 moduleName += ".";
415 415 moduleName += package;
416 416 }
417 417 PyDict_SetItemString(typeDict, "__module__", PyString_FromString(moduleName.constData()));
418 418
419 419 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
420 420
421 421 // set the class info so that PythonQtClassWrapper_new can read it
422 422 _currentClassInfoForClassWrapperCreation = info;
423 423 // create the new type object by calling the type
424 424 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
425 425
426 426 Py_DECREF(baseClasses);
427 427 Py_DECREF(typeDict);
428 428 Py_DECREF(args);
429 429 Py_DECREF(className);
430 430
431 431 return result;
432 432 }
433 433
434 434 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
435 435 PyObject* result;
436 436
437 437 PyObject* className = PyString_FromString(enumName);
438 438
439 439 PyObject* baseClasses = PyTuple_New(1);
440 440 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
441 441
442 442 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
443 443 PyObject* typeDict = PyDict_New();
444 444 PyDict_SetItemString(typeDict, "__module__", module);
445 445
446 446 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
447 447
448 448 // create the new int derived type object by calling the core type
449 449 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
450 450
451 451 Py_DECREF(baseClasses);
452 452 Py_DECREF(typeDict);
453 453 Py_DECREF(args);
454 454 Py_DECREF(className);
455 455
456 456 return result;
457 457 }
458 458
459 459 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
460 460 {
461 461 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
462 462 if (!r) {
463 463 r = new PythonQtSignalReceiver(obj);
464 464 _p->_signalReceivers.insert(obj, r);
465 465 }
466 466 return r;
467 467 }
468 468
469 469 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
470 470 {
471 471 bool flag = false;
472 472 PythonQtObjectPtr callable = lookupCallable(module, objectname);
473 473 if (callable) {
474 474 PythonQtSignalReceiver* r = getSignalReceiver(obj);
475 475 flag = r->addSignalHandler(signal, callable);
476 476 if (!flag) {
477 477 // signal not found
478 478 }
479 479 } else {
480 480 // callable not found
481 481 }
482 482 return flag;
483 483 }
484 484
485 485 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
486 486 {
487 487 bool flag = false;
488 488 PythonQtSignalReceiver* r = getSignalReceiver(obj);
489 489 if (r) {
490 490 flag = r->addSignalHandler(signal, receiver);
491 491 }
492 492 return flag;
493 493 }
494 494
495 495 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
496 496 {
497 497 bool flag = false;
498 498 PythonQtObjectPtr callable = lookupCallable(module, objectname);
499 499 if (callable) {
500 500 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
501 501 if (r) {
502 502 flag = r->removeSignalHandler(signal, callable);
503 503 }
504 504 } else {
505 505 // callable not found
506 506 }
507 507 return flag;
508 508 }
509 509
510 510 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
511 511 {
512 512 bool flag = false;
513 513 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
514 514 if (r) {
515 515 flag = r->removeSignalHandler(signal, receiver);
516 516 }
517 517 return flag;
518 518 }
519 519
520 520 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
521 521 {
522 522 PythonQtObjectPtr p = lookupObject(module, name);
523 523 if (p) {
524 524 if (PyCallable_Check(p)) {
525 525 return p;
526 526 }
527 527 }
528 528 PyErr_Clear();
529 529 return NULL;
530 530 }
531 531
532 532 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
533 533 {
534 534 QStringList l = name.split('.');
535 535 PythonQtObjectPtr p = module;
536 536 PythonQtObjectPtr prev;
537 537 QString s;
538 538 QByteArray b;
539 539 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
540 540 prev = p;
541 541 b = (*i).toLatin1();
542 542 if (PyDict_Check(p)) {
543 543 p = PyDict_GetItemString(p, b.data());
544 544 } else {
545 545 p.setNewRef(PyObject_GetAttrString(p, b.data()));
546 546 }
547 547 }
548 548 PyErr_Clear();
549 549 return p;
550 550 }
551 551
552 552 PythonQtObjectPtr PythonQt::getMainModule() {
553 553 //both borrowed
554 554 PythonQtObjectPtr dict = PyImport_GetModuleDict();
555 555 return PyDict_GetItemString(dict, "__main__");
556 556 }
557 557
558 558 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
559 559 QVariant result;
560 560 if (pycode) {
561 561 PyObject* dict = NULL;
562 562 if (PyModule_Check(object)) {
563 563 dict = PyModule_GetDict(object);
564 564 } else if (PyDict_Check(object)) {
565 565 dict = object;
566 566 }
567 567 PyObject* r = NULL;
568 568 if (dict) {
569 569 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
570 570 }
571 571 if (r) {
572 572 result = PythonQtConv::PyObjToQVariant(r);
573 573 Py_DECREF(r);
574 574 } else {
575 575 handleError();
576 576 }
577 577 } else {
578 578 handleError();
579 579 }
580 580 return result;
581 581 }
582 582
583 583 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
584 584 {
585 585 QVariant result;
586 586 PythonQtObjectPtr p;
587 587 PyObject* dict = NULL;
588 588 if (PyModule_Check(object)) {
589 589 dict = PyModule_GetDict(object);
590 590 } else if (PyDict_Check(object)) {
591 591 dict = object;
592 592 }
593 593 if (dict) {
594 594 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
595 595 }
596 596 if (p) {
597 597 result = PythonQtConv::PyObjToQVariant(p);
598 598 } else {
599 599 handleError();
600 600 }
601 601 return result;
602 602 }
603 603
604 604 void PythonQt::evalFile(PyObject* module, const QString& filename)
605 605 {
606 606 PythonQtObjectPtr code = parseFile(filename);
607 607 if (code) {
608 608 evalCode(module, code);
609 609 } else {
610 610 handleError();
611 611 }
612 612 }
613 613
614 614 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
615 615 {
616 616 PythonQtObjectPtr p;
617 617 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
618 618 if (!p) {
619 619 handleError();
620 620 }
621 621 return p;
622 622 }
623 623
624 624 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
625 625 {
626 626 PythonQtObjectPtr code = parseFile(filename);
627 627 PythonQtObjectPtr module = _p->createModule(name, code);
628 628 return module;
629 629 }
630 630
631 631 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
632 632 {
633 633 PyErr_Clear();
634 634 QString scriptCode = script;
635 635 if (scriptCode.isEmpty()) {
636 636 // we always need at least a linefeed
637 637 scriptCode = "\n";
638 638 }
639 639 PythonQtObjectPtr pycode;
640 640 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
641 641 PythonQtObjectPtr module = _p->createModule(name, pycode);
642 642 return module;
643 643 }
644 644
645 645 PythonQtObjectPtr PythonQt::createUniqueModule()
646 646 {
647 647 static QString pyQtStr("PythonQt_module");
648 648 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
649 649 return createModuleFromScript(moduleName);
650 650 }
651 651
652 652 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
653 653 {
654 654 if (PyModule_Check(object)) {
655 655 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
656 656 } else if (PyDict_Check(object)) {
657 657 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
658 658 } else {
659 659 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
660 660 }
661 661 }
662 662
663 663 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
664 664 {
665 665 if (PyModule_Check(object)) {
666 666 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
667 667 } else if (PyDict_Check(object)) {
668 668 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
669 669 } else {
670 670 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
671 671 }
672 672 }
673 673
674 674 void PythonQt::removeVariable(PyObject* object, const QString& name)
675 675 {
676 676 if (PyDict_Check(object)) {
677 677 PyDict_DelItemString(object, name.toLatin1().data());
678 678 } else {
679 679 PyObject_DelAttrString(object, name.toLatin1().data());
680 680 }
681 681 }
682 682
683 683 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
684 684 {
685 685 QVariant result;
686 686 PythonQtObjectPtr obj = lookupObject(object, objectname);
687 687 if (obj) {
688 688 result = PythonQtConv::PyObjToQVariant(obj);
689 689 }
690 690 return result;
691 691 }
692 692
693 693 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
694 694 {
695 695 QStringList results;
696 696
697 697 PythonQtObjectPtr object;
698 698 if (objectname.isEmpty()) {
699 699 object = module;
700 700 } else {
701 701 object = lookupObject(module, objectname);
702 702 if (!object && type == CallOverloads) {
703 703 PyObject* dict = lookupObject(module, "__builtins__");
704 704 if (dict) {
705 705 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
706 706 }
707 707 }
708 708 }
709 709
710 710 if (object) {
711 711 if (type == CallOverloads) {
712 712 if (PythonQtSlotFunction_Check(object)) {
713 713 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
714 714 PythonQtSlotInfo* info = o->m_ml;
715 715
716 716 while (info) {
717 717 results << info->fullSignature();
718 718 info = info->nextInfo();
719 719 }
720 720 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
721 721 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
722 722 PythonQtSlotInfo* info = o->classInfo()->constructors();
723 723
724 724 while (info) {
725 725 results << info->fullSignature();
726 726 info = info->nextInfo();
727 727 }
728 728 } else {
729 729 //TODO: use pydoc!
730 730 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
731 731 if (doc) {
732 732 results << PyString_AsString(doc);
733 733 Py_DECREF(doc);
734 734 }
735 735 }
736 736 } else {
737 737 PyObject* keys = NULL;
738 738 bool isDict = false;
739 739 if (PyDict_Check(object)) {
740 740 keys = PyDict_Keys(object);
741 741 isDict = true;
742 742 } else {
743 743 keys = PyObject_Dir(object);
744 744 }
745 745 if (keys) {
746 746 int count = PyList_Size(keys);
747 747 PyObject* key;
748 748 PyObject* value;
749 749 QString keystr;
750 750 for (int i = 0;i<count;i++) {
751 751 key = PyList_GetItem(keys,i);
752 752 if (isDict) {
753 753 value = PyDict_GetItem(object, key);
754 754 Py_INCREF(value);
755 755 } else {
756 756 value = PyObject_GetAttr(object, key);
757 757 }
758 758 if (!value) continue;
759 759 keystr = PyString_AsString(key);
760 760 static const QString underscoreStr("__tmp");
761 761 if (!keystr.startsWith(underscoreStr)) {
762 762 switch (type) {
763 763 case Anything:
764 764 results << keystr;
765 765 break;
766 766 case Class:
767 767 if (value->ob_type == &PyClass_Type) {
768 768 results << keystr;
769 769 }
770 770 break;
771 771 case Variable:
772 772 if (value->ob_type != &PyClass_Type
773 773 && value->ob_type != &PyCFunction_Type
774 774 && value->ob_type != &PyFunction_Type
775 775 && value->ob_type != &PyModule_Type
776 776 ) {
777 777 results << keystr;
778 778 }
779 779 break;
780 780 case Function:
781 781 if (value->ob_type == &PyFunction_Type ||
782 782 value->ob_type == &PyMethod_Type
783 783 ) {
784 784 results << keystr;
785 785 }
786 786 break;
787 787 case Module:
788 788 if (value->ob_type == &PyModule_Type) {
789 789 results << keystr;
790 790 }
791 791 break;
792 792 default:
793 793 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
794 794 }
795 795 }
796 796 Py_DECREF(value);
797 797 }
798 798 Py_DECREF(keys);
799 799 }
800 800 }
801 801 }
802 802 return results;
803 803 }
804 804
805 805 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
806 806 {
807 807 PythonQtObjectPtr callable = lookupCallable(object, name);
808 808 if (callable) {
809 809 return call(callable, args);
810 810 } else {
811 811 return QVariant();
812 812 }
813 813 }
814 814
815 815 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
816 816 {
817 817 QVariant r;
818 818 if (callable) {
819 819 PythonQtObjectPtr pargs;
820 820 int count = args.size();
821 821 if (count>0) {
822 822 pargs.setNewRef(PyTuple_New(count));
823 823 }
824 824 bool err = false;
825 825 // transform QVariants to Python
826 826 for (int i = 0; i < count; i++) {
827 827 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
828 828 if (arg) {
829 829 // steals reference, no unref
830 830 PyTuple_SetItem(pargs, i,arg);
831 831 } else {
832 832 err = true;
833 833 break;
834 834 }
835 835 }
836 836
837 837 if (!err) {
838 838 PyErr_Clear();
839 839 PythonQtObjectPtr result;
840 840 result.setNewRef(PyObject_CallObject(callable, pargs));
841 841 if (result) {
842 842 // ok
843 843 r = PythonQtConv::PyObjToQVariant(result);
844 844 } else {
845 845 PythonQt::self()->handleError();
846 846 }
847 847 }
848 848 }
849 849 return r;
850 850 }
851 851
852 852 void PythonQt::addInstanceDecorators(QObject* o)
853 853 {
854 854 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
855 855 }
856 856
857 857 void PythonQt::addClassDecorators(QObject* o)
858 858 {
859 859 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
860 860 }
861 861
862 862 void PythonQt::addDecorators(QObject* o)
863 863 {
864 864 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
865 865 }
866 866
867 867 void PythonQt::registerQObjectClassNames(const QStringList& names)
868 868 {
869 869 _p->registerQObjectClassNames(names);
870 870 }
871 871
872 872 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
873 873 {
874 874 PythonQtImport::init();
875 875 _p->_importInterface = importInterface;
876 876 }
877 877
878 878 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
879 879 {
880 880 _p->_importIgnorePaths = paths;
881 881 }
882 882
883 883 const QStringList& PythonQt::getImporterIgnorePaths()
884 884 {
885 885 return _p->_importIgnorePaths;
886 886 }
887 887
888 888 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
889 889 {
890 890 _p->_cppWrapperFactories.append(factory);
891 891 }
892 892
893 893 //---------------------------------------------------------------------------------------------------
894 894 PythonQtPrivate::PythonQtPrivate()
895 895 {
896 896 _importInterface = NULL;
897 897 _defaultImporter = new PythonQtQFileImporter;
898 898 _noLongerWrappedCB = NULL;
899 899 _wrappedCB = NULL;
900 900 _currentClassInfoForClassWrapperCreation = NULL;
901 901 }
902 902
903 903 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
904 904 {
905 905 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
906 906 _currentClassInfoForClassWrapperCreation = NULL;
907 907 return info;
908 908 }
909 909
910 910 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
911 911 {
912 912 o->setParent(this);
913 913 int numMethods = o->metaObject()->methodCount();
914 914 for (int i = 0; i < numMethods; i++) {
915 915 QMetaMethod m = o->metaObject()->method(i);
916 916 if ((m.methodType() == QMetaMethod::Method ||
917 917 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
918 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m);
918 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
919 919 if (qstrncmp(m.signature(), "new_", 4)==0) {
920 920 if ((decoTypes & ConstructorDecorator) == 0) continue;
921 // either it returns a * or a QVariant and the name starts with "new_"
922 bool isVariantReturn = info->parameters().at(0).typeId == PythonQtMethodInfo::Variant;
923 if ((info->parameters().at(0).isPointer || isVariantReturn)) {
921 if (info->parameters().at(0).isPointer) {
924 922 QByteArray signature = m.signature();
925 923 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
926 924 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
927 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
925 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
928 926 classInfo->addConstructor(newSlot);
929 927 }
930 928 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
931 929 if ((decoTypes & DestructorDecorator) == 0) continue;
932 930 QByteArray signature = m.signature();
933 931 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
934 932 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
935 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
933 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
936 934 classInfo->setDestructor(newSlot);
937 935 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
938 936 if ((decoTypes & StaticDecorator) == 0) continue;
939 937 QByteArray signature = m.signature();
940 938 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
941 939 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
942 940 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
943 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
941 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
944 942 classInfo->addDecoratorSlot(newSlot);
945 943 } else {
946 944 if ((decoTypes & InstanceDecorator) == 0) continue;
947 945 if (info->parameters().count()>1) {
948 946 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
949 947 if (p.isPointer) {
950 948 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
951 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::InstanceDecorator);
949 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
952 950 classInfo->addDecoratorSlot(newSlot);
953 951 }
954 952 }
955 953 }
956 954 }
957 955 }
958 956 }
959 957
960 958 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
961 959 {
962 960 foreach(QString name, names) {
963 961 _knownQObjectClassNames.insert(name.toLatin1(), true);
964 962 }
965 963 }
966 964
967 965 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
968 966 {
969 967 _signalReceivers.remove(obj);
970 968 }
971 969
972 970 bool PythonQt::handleError()
973 971 {
974 972 bool flag = false;
975 973 if (PyErr_Occurred()) {
976 974
977 975 // currently we just print the error and the stderr handler parses the errors
978 976 PyErr_Print();
979 977
980 978 /*
981 979 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
982 980 PyObject *ptype;
983 981 PyObject *pvalue;
984 982 PyObject *ptraceback;
985 983 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
986 984
987 985 Py_XDECREF(ptype);
988 986 Py_XDECREF(pvalue);
989 987 Py_XDECREF(ptraceback);
990 988 */
991 989 PyErr_Clear();
992 990 flag = true;
993 991 }
994 992 return flag;
995 993 }
996 994
997 995 void PythonQt::addSysPath(const QString& path)
998 996 {
999 997 PythonQtObjectPtr sys;
1000 998 sys.setNewRef(PyImport_ImportModule("sys"));
1001 999 PythonQtObjectPtr obj = lookupObject(sys, "path");
1002 1000 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1003 1001 }
1004 1002
1005 1003 void PythonQt::overwriteSysPath(const QStringList& paths)
1006 1004 {
1007 1005 PythonQtObjectPtr sys;
1008 1006 sys.setNewRef(PyImport_ImportModule("sys"));
1009 1007 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1010 1008 }
1011 1009
1012 1010 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1013 1011 {
1014 1012 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1015 1013 }
1016 1014
1017 1015 void PythonQt::stdOutRedirectCB(const QString& str)
1018 1016 {
1019 1017 emit PythonQt::self()->pythonStdOut(str);
1020 1018 }
1021 1019
1022 1020 void PythonQt::stdErrRedirectCB(const QString& str)
1023 1021 {
1024 1022 emit PythonQt::self()->pythonStdErr(str);
1025 1023 }
1026 1024
1027 1025 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1028 1026 {
1029 1027 _p->_wrappedCB = cb;
1030 1028 }
1031 1029
1032 1030 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1033 1031 {
1034 1032 _p->_noLongerWrappedCB = cb;
1035 1033 }
1036 1034
1037 1035
1038 1036
1039 1037 static PyMethodDef PythonQtMethods[] = {
1040 1038 {NULL, NULL, 0, NULL}
1041 1039 };
1042 1040
1043 1041 void PythonQt::initPythonQtModule(bool redirectStdOut)
1044 1042 {
1045 1043 _p->_pythonQtModule = Py_InitModule("PythonQt", PythonQtMethods);
1046 1044
1047 1045 if (redirectStdOut) {
1048 1046 PythonQtObjectPtr sys;
1049 1047 PythonQtObjectPtr out;
1050 1048 PythonQtObjectPtr err;
1051 1049 sys.setNewRef(PyImport_ImportModule("sys"));
1052 1050 // create a redirection object for stdout and stderr
1053 1051 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1054 1052 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1055 1053 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1056 1054 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1057 1055 // replace the built in file objects with our own objects
1058 1056 PyModule_AddObject(sys, "stdout", out);
1059 1057 PyModule_AddObject(sys, "stderr", err);
1060 1058 }
1061 1059 }
1062 1060
1063 1061 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1064 1062 {
1065 1063 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1066 1064 }
1067 1065
1068 1066
1069 1067 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1070 1068 {
1071 1069 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1072 1070 if (!info) {
1073 1071 info = new PythonQtClassInfo();
1074 1072 info->setupCPPObject(typeName);
1075 1073 _knownClassInfos.insert(typeName, info);
1076 1074 }
1077 1075 return info;
1078 1076 }
1079 1077
1080 1078 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1081 1079 {
1082 1080 _p->addPolymorphicHandler(typeName, cb);
1083 1081 }
1084 1082
1085 1083 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1086 1084 {
1087 1085 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1088 1086 info->addPolymorphicHandler(cb);
1089 1087 }
1090 1088
1091 1089 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1092 1090 {
1093 1091 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1094 1092 }
1095 1093
1096 1094 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1097 1095 {
1098 1096 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1099 1097 if (info) {
1100 1098 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1101 1099 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1102 1100 return true;
1103 1101 } else {
1104 1102 return false;
1105 1103 }
1106 1104 }
1107 1105
1108 1106 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1109 1107 {
1110 1108 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1111 1109 if (!info->pythonQtClassWrapper()) {
1112 1110 info->setupCPPObject(typeName);
1113 1111 createPythonQtClassWrapper(info, package);
1114 1112 }
1115 1113 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1116 1114 addParentClass(typeName, parentTypeName, 0);
1117 1115 }
1118 1116 if (wrapperCreator) {
1119 1117 info->setDecoratorProvider(wrapperCreator);
1120 1118 }
1121 1119 if (shell) {
1122 1120 info->setShellSetInstanceWrapperCB(shell);
1123 1121 }
1124 1122 }
1125 1123
1126 1124 PyObject* PythonQtPrivate::packageByName(const char* name)
1127 1125 {
1128 1126 if (name==NULL || name[0]==0) {
1129 1127 return _pythonQtModule;
1130 1128 }
1131 1129 PyObject* v = _packages.value(name);
1132 1130 if (!v) {
1133 1131 v = PyImport_AddModule((QByteArray("PythonQt.") + name).constData());
1134 1132 _packages.insert(name, v);
1135 1133 // AddObject steals the reference, so increment it!
1136 1134 Py_INCREF(v);
1137 1135 PyModule_AddObject(_pythonQtModule, name, v);
1138 1136 }
1139 1137 return v;
1140 1138 }
1141 1139
1142 1140
1143 1141 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1144 1142 {
1145 1143 if (_p->_initFlags & ExternalHelp) {
1146 1144 emit pythonHelpRequest(QByteArray(info->className()));
1147 1145 return Py_BuildValue("");
1148 1146 } else {
1149 1147 return PyString_FromString(info->help().toLatin1().data());
1150 1148 }
1151 1149 }
1152 1150
1153 1151 void PythonQtPrivate::removeWrapperPointer(void* obj)
1154 1152 {
1155 1153 _wrappedObjects.remove(obj);
1156 1154 }
1157 1155
1158 1156 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1159 1157 {
1160 1158 _wrappedObjects.insert(obj, wrapper);
1161 1159 }
1162 1160
1163 1161 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1164 1162 {
1165 1163 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1166 1164 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1167 1165 // this is a wrapper whose QObject was already removed due to destruction
1168 1166 // so the obj pointer has to be a new QObject with the same address...
1169 1167 // we remove the old one and set the copy to NULL
1170 1168 wrap->_objPointerCopy = NULL;
1171 1169 removeWrapperPointer(obj);
1172 1170 wrap = NULL;
1173 1171 }
1174 1172 return wrap;
1175 1173 }
1176 1174
1177 1175 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1178 1176 {
1179 1177 PythonQtObjectPtr result;
1180 1178 if (pycode) {
1181 1179 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1182 1180 } else {
1183 1181 PythonQt::self()->handleError();
1184 1182 }
1185 1183 return result;
1186 1184 }
@@ -1,836 +1,834
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtClassInfo.h"
43 43 #include "PythonQtMethodInfo.h"
44 44 #include "PythonQt.h"
45 45 #include <QMetaMethod>
46 46 #include <QMetaObject>
47 47 #include <QMetaEnum>
48 48
49 49 QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;
50 50
51 51 PythonQtClassInfo::PythonQtClassInfo() {
52 52 _meta = NULL;
53 53 _constructors = NULL;
54 54 _destructor = NULL;
55 55 _decoratorProvider = NULL;
56 56 _decoratorProviderCB = NULL;
57 57 _pythonQtClassWrapper = NULL;
58 58 _shellSetInstanceWrapperCB = NULL;
59 59 _metaTypeId = -1;
60 60 _isQObject = false;
61 61 _enumsCreated = false;
62 62 }
63 63
64 64 PythonQtClassInfo::~PythonQtClassInfo()
65 65 {
66 66 clearCachedMembers();
67 67
68 68 if (_constructors) {
69 69 _constructors->deleteOverloadsAndThis();
70 70 }
71 71 if (_destructor) {
72 72 _destructor->deleteOverloadsAndThis();
73 73 }
74 74 foreach(PythonQtSlotInfo* info, _decoratorSlots) {
75 75 info->deleteOverloadsAndThis();
76 76 }
77 77 }
78 78
79 79 void PythonQtClassInfo::setupQObject(const QMetaObject* meta)
80 80 {
81 81 // _wrappedClassName is already set earlier in the class setup
82 82 _isQObject = true;
83 83 _meta = meta;
84 84 }
85 85
86 86 void PythonQtClassInfo::setupCPPObject(const QByteArray& classname)
87 87 {
88 88 _isQObject = false;
89 89 _wrappedClassName = classname;
90 90 _metaTypeId = QMetaType::type(classname);
91 91 }
92 92
93 93 void PythonQtClassInfo::clearCachedMembers()
94 94 {
95 95 QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers);
96 96 while (i.hasNext()) {
97 97 PythonQtMemberInfo member = i.next().value();
98 98 if (member._type== PythonQtMemberInfo::Slot) {
99 99 PythonQtSlotInfo* info = member._slot;
100 100 while (info) {
101 101 PythonQtSlotInfo* next = info->nextInfo();
102 102 delete info;
103 103 info = next;
104 104 }
105 105 }
106 106 }
107 107 }
108 108
109 109 int PythonQtClassInfo::findCharOffset(const char* sigStart, char someChar)
110 110 {
111 111 const char* sigEnd = sigStart;
112 112 char c;
113 113 do {
114 114 c = *sigEnd++;
115 115 } while (c!=someChar && c!=0);
116 116 return sigEnd-sigStart-1;
117 117 }
118 118
119 119 bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName)
120 120 {
121 121 bool found = false;
122 122 bool nameMapped = false;
123 123 const char* attributeName = memberName;
124 124 // look for properties
125 125 int i = _meta->indexOfProperty(attributeName);
126 126 if (i==-1) {
127 127 // try to map name to objectName
128 128 if (qstrcmp(attributeName, "name")==0) {
129 129 attributeName = "objectName";
130 130 nameMapped = true;
131 131 i = _meta->indexOfProperty(attributeName);
132 132 }
133 133 }
134 134 if (i!=-1) {
135 135 PythonQtMemberInfo newInfo(_meta->property(i));
136 136 _cachedMembers.insert(attributeName, newInfo);
137 137 if (nameMapped) {
138 138 _cachedMembers.insert(memberName, newInfo);
139 139 }
140 140 #ifdef PYTHONQT_DEBUG
141 141 std::cout << "caching property " << memberName << " on " << _meta->className() << std::endl;
142 142 #endif
143 143 found = true;
144 144 }
145 145 return found;
146 146 }
147 147
148 148 PythonQtSlotInfo* PythonQtClassInfo::recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
149 149 {
150 150 inputInfo = findDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset);
151 151 foreach(const ParentClassInfo& info, _parentClasses) {
152 152 inputInfo = info._parent->recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset+info._upcastingOffset);
153 153 }
154 154 return inputInfo;
155 155 }
156 156
157 157 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset) {
158 158 QObject* decoratorProvider = decorator();
159 159 int memberNameLen = strlen(memberName);
160 160 if (decoratorProvider) {
161 161 //qDebug()<< "looking " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
162 162 const QMetaObject* meta = decoratorProvider->metaObject();
163 163 int numMethods = meta->methodCount();
164 164 int startFrom = QObject::staticMetaObject.methodCount();
165 165 for (int i = startFrom; i < numMethods; i++) {
166 166 QMetaMethod m = meta->method(i);
167 167 if ((m.methodType() == QMetaMethod::Method ||
168 168 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
169 169
170 170 const char* sigStart = m.signature();
171 171 bool isClassDeco = false;
172 172 if (qstrncmp(sigStart, "static_", 7)==0) {
173 173 // skip the static_classname_ part of the string
174 174 sigStart += 7 + 1 + strlen(className());
175 175 isClassDeco = true;
176 176 } else if (qstrncmp(sigStart, "new_", 4)==0) {
177 177 isClassDeco = true;
178 178 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
179 179 isClassDeco = true;
180 180 }
181 181 // find the first '('
182 182 int offset = findCharOffset(sigStart, '(');
183 183
184 184 // XXX no checking is currently done if the slots have correct first argument or not...
185 185
186 186 // check if same length and same name
187 187 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
188 188 found = true;
189 PythonQtSlotInfo* info = new PythonQtSlotInfo(m, i, decoratorProvider, isClassDeco?PythonQtSlotInfo::ClassDecorator:PythonQtSlotInfo::InstanceDecorator);
189 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i, decoratorProvider, isClassDeco?PythonQtSlotInfo::ClassDecorator:PythonQtSlotInfo::InstanceDecorator);
190 190 info->setUpcastingOffset(upcastingOffset);
191 191 //qDebug()<< "adding " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
192 192 if (tail) {
193 193 tail->setNextInfo(info);
194 194 } else {
195 195 PythonQtMemberInfo newInfo(info);
196 196 memberCache.insert(memberName, newInfo);
197 197 }
198 198 tail = info;
199 199 }
200 200 }
201 201 }
202 202 }
203 203
204 204 tail = findDecoratorSlots(memberName, memberNameLen, tail, found, memberCache, upcastingOffset);
205 205
206 206 return tail;
207 207 }
208 208
209 209 bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName)
210 210 {
211 211 bool found = false;
212 212 int memberNameLen = strlen(memberName);
213 213 PythonQtSlotInfo* tail = NULL;
214 214 if (_meta) {
215 215 int numMethods = _meta->methodCount();
216 216 for (int i = 0; i < numMethods; i++) {
217 217 QMetaMethod m = _meta->method(i);
218 218 if ((m.methodType() == QMetaMethod::Method ||
219 219 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
220 220
221 221 const char* sigStart = m.signature();
222 222 // find the first '('
223 223 int offset = findCharOffset(sigStart, '(');
224 224
225 225 // check if same length and same name
226 226 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
227 227 found = true;
228 PythonQtSlotInfo* info = new PythonQtSlotInfo(m, i);
228 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i);
229 229 if (tail) {
230 230 tail->setNextInfo(info);
231 231 } else {
232 232 PythonQtMemberInfo newInfo(info);
233 233 _cachedMembers.insert(memberName, newInfo);
234 234 }
235 235 tail = info;
236 236 }
237 237 }
238 238 }
239 239 }
240 240
241 241 // look for dynamic decorators in this class and in derived classes
242 242 tail = recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, tail, found, _cachedMembers, 0);
243 243
244 244 return found;
245 245 }
246 246
247 247 bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* memberName)
248 248 {
249 249 bool found = false;
250 250 // look for enum values
251 251 int enumCount = meta->enumeratorCount();
252 252 for (int i=0;i<enumCount; i++) {
253 253 QMetaEnum e = meta->enumerator(i);
254 254 for (int j=0; j < e.keyCount(); j++) {
255 255 if (qstrcmp(e.key(j), memberName)==0) {
256 256 PyObject* enumType = findEnumWrapper(e.name());
257 257 if (enumType) {
258 258 PyObject* args = Py_BuildValue("(i)", e.value(j));
259 259 PyObject* enumValue = PyObject_Call(enumType, args, NULL);
260 260 Py_DECREF(args);
261 261 PythonQtObjectPtr enumValuePtr;
262 262 enumValuePtr.setNewRef(enumValue);
263 263 PythonQtMemberInfo newInfo(enumValuePtr);
264 264 _cachedMembers.insert(memberName, newInfo);
265 265 #ifdef PYTHONQT_DEBUG
266 266 std::cout << "caching enum " << memberName << " on " << meta->className() << std::endl;
267 267 #endif
268 268 found = true;
269 269 break;
270 270 } else {
271 271 std::cout << "enum " << e.name() << " not found on " << className() << std::endl;
272 272 }
273 273 }
274 274 }
275 275 }
276 276 return found;
277 277 }
278 278
279 279 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
280 280 {
281 281 PythonQtMemberInfo info = _cachedMembers.value(memberName);
282 282 if (info._type != PythonQtMemberInfo::Invalid) {
283 283 return info;
284 284 } else {
285 285 bool found = false;
286 286
287 287 found = lookForPropertyAndCache(memberName);
288 288 if (!found) {
289 289 found = lookForMethodAndCache(memberName);
290 290 }
291 291 if (!found) {
292 292 if (_meta) {
293 293 // check enums in our meta object directly
294 294 found = lookForEnumAndCache(_meta, memberName);
295 295 }
296 296 if (!found) {
297 297 // check enums in the class hierachy of CPP classes
298 298 // look for dynamic decorators in this class and in derived classes
299 299 QList<QObject*> decoObjects;
300 300 recursiveCollectDecoratorObjects(decoObjects);
301 301 foreach(QObject* deco, decoObjects) {
302 302 // call on ourself for caching, but with different metaObject():
303 303 found = lookForEnumAndCache(deco->metaObject(), memberName);
304 304 if (found) {
305 305 break;
306 306 }
307 307 }
308 308 }
309 309 }
310 310 if (!found) {
311 311 PyObject* p = findEnumWrapper(memberName);
312 312 if (p) {
313 313 info._type = PythonQtMemberInfo::EnumWrapper;
314 314 info._enumWrapper = p;
315 315 _cachedMembers.insert(memberName, info);
316 316 found = true;
317 317 }
318 318 }
319 319 if (!found) {
320 320 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
321 321 info._type = PythonQtMemberInfo::NotFound;
322 322 _cachedMembers.insert(memberName, info);
323 323 }
324 324 }
325 325
326 326 return _cachedMembers.value(memberName);
327 327 }
328 328
329 329 void PythonQtClassInfo::recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects) {
330 330 QObject* deco = decorator();
331 331 if (deco) {
332 332 decoratorObjects.append(deco);
333 333 }
334 334 foreach(const ParentClassInfo& info, _parentClasses) {
335 335 info._parent->recursiveCollectDecoratorObjects(decoratorObjects);
336 336 }
337 337 }
338 338
339 339 void PythonQtClassInfo::recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects) {
340 340 classInfoObjects.append(this);
341 341 foreach(const ParentClassInfo& info, _parentClasses) {
342 342 info._parent->recursiveCollectClassInfos(classInfoObjects);
343 343 }
344 344 }
345 345
346 346 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
347 347 {
348 348 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
349 349 while (it.hasNext()) {
350 350
351 351 PythonQtSlotInfo* infoOrig = it.next();
352 352
353 353 const char* sigStart = infoOrig->metaMethod()->signature();
354 354 if (qstrncmp("static_", sigStart, 7)==0) {
355 355 sigStart += 7;
356 356 sigStart += findCharOffset(sigStart, '_')+1;
357 357 }
358 358 int offset = findCharOffset(sigStart, '(');
359 359 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
360 360 //make a copy, otherwise we will have trouble on overloads!
361 361 PythonQtSlotInfo* info = new PythonQtSlotInfo(*infoOrig);
362 362 info->setUpcastingOffset(upcastingOffset);
363 363 found = true;
364 364 if (tail) {
365 365 tail->setNextInfo(info);
366 366 } else {
367 367 PythonQtMemberInfo newInfo(info);
368 368 memberCache.insert(memberName, newInfo);
369 369 }
370 370 tail = info;
371 371 }
372 372 }
373 373 return tail;
374 374 }
375 375
376 376 void PythonQtClassInfo::listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly) {
377 377 QObject* decoratorProvider = decorator();
378 378 if (decoratorProvider) {
379 379 const QMetaObject* meta = decoratorProvider->metaObject();
380 380 int numMethods = meta->methodCount();
381 381 int startFrom = QObject::staticMetaObject.methodCount();
382 382 for (int i = startFrom; i < numMethods; i++) {
383 383 QMetaMethod m = meta->method(i);
384 384 if ((m.methodType() == QMetaMethod::Method ||
385 385 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
386 386
387 387 const char* sigStart = m.signature();
388 388 bool isClassDeco = false;
389 389 if (qstrncmp(sigStart, "static_", 7)==0) {
390 390 // skip the static_classname_ part of the string
391 391 sigStart += 7 + 1 + strlen(className());
392 392 isClassDeco = true;
393 393 } else if (qstrncmp(sigStart, "new_", 4)==0) {
394 394 continue;
395 395 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
396 396 continue;
397 397 }
398 398 // find the first '('
399 399 int offset = findCharOffset(sigStart, '(');
400 400
401 401 // XXX no checking is currently done if the slots have correct first argument or not...
402 402 if (!metaOnly || isClassDeco) {
403 403 list << QString::fromLatin1(sigStart, offset);
404 404 }
405 405 }
406 406 }
407 407 }
408 408
409 409 // look for global decorator slots
410 410 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
411 411 while (it.hasNext()) {
412 412 PythonQtSlotInfo* slot = it.next();
413 413 if (metaOnly) {
414 414 if (slot->isClassDecorator()) {
415 415 QByteArray first = slot->slotName();
416 416 if (first.startsWith("static_")) {
417 417 int idx = first.indexOf('_');
418 418 idx = first.indexOf('_', idx+1);
419 419 first = first.mid(idx+1);
420 420 }
421 421 list << first;
422 422 }
423 423 } else {
424 424 list << slot->slotName();
425 425 }
426 426 }
427 427 }
428 428
429 429 QStringList PythonQtClassInfo::propertyList()
430 430 {
431 431 QStringList l;
432 432 if (_isQObject && _meta) {
433 433 int i;
434 434 int numProperties = _meta->propertyCount();
435 435 for (i = 0; i < numProperties; i++) {
436 436 QMetaProperty p = _meta->property(i);
437 437 l << QString(p.name());
438 438 }
439 439 }
440 440 return l;
441 441 }
442 442
443 443 QStringList PythonQtClassInfo::memberList(bool metaOnly)
444 444 {
445 445 decorator();
446 446
447 447 QStringList l;
448 448 QString h;
449 449 if (_isQObject && _meta && !metaOnly) {
450 450 l = propertyList();
451 451 }
452 452
453 453 // normal slots of QObject (or wrapper QObject)
454 454 if (!metaOnly && _meta) {
455 455 int numMethods = _meta->methodCount();
456 456 bool skipQObj = !_isQObject;
457 457 for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) {
458 458 QMetaMethod m = _meta->method(i);
459 459 if ((m.methodType() == QMetaMethod::Method ||
460 460 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
461 461 QByteArray signa(m.signature());
462 if (signa.startsWith("new_")) continue;
463 if (signa.startsWith("delete_")) continue;
464 if (signa.startsWith("static_")) continue;
465 PythonQtSlotInfo slot(m, i);
466 l << slot.slotName();
462 signa = signa.left(signa.indexOf('('));
463 l << signa;
467 464 }
468 465 }
469 466 }
470 467
471 468 {
472 469 // look for dynamic decorators in this class and in derived classes
473 470 QList<PythonQtClassInfo*> infos;
474 471 recursiveCollectClassInfos(infos);
475 472 foreach(PythonQtClassInfo* info, infos) {
476 473 info->listDecoratorSlotsFromDecoratorProvider(l, metaOnly);
477 474 }
478 475 }
479 476
480 477 // List enumerator keys...
481 478 QList<const QMetaObject*> enumMetaObjects;
482 479 if (_meta) {
483 480 enumMetaObjects << _meta;
484 481 }
485 482 // check enums in the class hierachy of CPP classes
486 483 QList<QObject*> decoObjects;
487 484 recursiveCollectDecoratorObjects(decoObjects);
488 485 foreach(QObject* deco, decoObjects) {
489 486 enumMetaObjects << deco->metaObject();
490 487 }
491 488
492 489 foreach(const QMetaObject* meta, enumMetaObjects) {
493 490 for (int i = 0; i<meta->enumeratorCount(); i++) {
494 491 QMetaEnum e = meta->enumerator(i);
495 492 l << e.name();
496 493 for (int j=0; j < e.keyCount(); j++) {
497 494 l << QString(e.key(j));
498 495 }
499 496 }
500 497 }
501 498
502 499 return QSet<QString>::fromList(l).toList();
503 500 }
504 501
505 502 const char* PythonQtClassInfo::className()
506 503 {
507 504 return _wrappedClassName.constData();
508 505 }
509 506
510 507 void* PythonQtClassInfo::castTo(void* ptr, const char* classname)
511 508 {
512 509 if (ptr==NULL) {
513 510 return NULL;
514 511 }
515 512 if (_wrappedClassName == classname) {
516 513 return ptr;
517 514 }
518 515 foreach(const ParentClassInfo& info, _parentClasses) {
519 516 void* result = info._parent->castTo((char*)ptr + info._upcastingOffset, classname);
520 517 if (result) {
521 518 return result;
522 519 }
523 520 }
524 521 return NULL;
525 522 }
526 523
527 524 bool PythonQtClassInfo::inherits(const char* name)
528 525 {
529 526 if (_wrappedClassName == name) {
530 527 return true;
531 528 }
532 529 foreach(const ParentClassInfo& info, _parentClasses) {
533 530 if (info._parent->inherits(name)) {
534 531 return true;
535 532 }
536 533 }
537 534 return false;
538 535 }
539 536
540 537 bool PythonQtClassInfo::inherits(PythonQtClassInfo* classInfo)
541 538 {
542 539 if (classInfo == this) {
543 540 return true;
544 541 }
545 542 foreach(const ParentClassInfo& info, _parentClasses) {
546 543 if (info._parent->inherits(classInfo)) {
547 544 return true;
548 545 }
549 546 }
550 547 return false;
551 548 }
552 549
553 550 QString PythonQtClassInfo::help()
554 551 {
555 552 decorator();
556 553 QString h;
557 554 h += QString("--- ") + QString(className()) + QString(" ---\n");
558 555
559 556 if (_isQObject) {
560 557 h += "Properties:\n";
561 558
562 559 int i;
563 560 int numProperties = _meta->propertyCount();
564 561 for (i = 0; i < numProperties; i++) {
565 562 QMetaProperty p = _meta->property(i);
566 563 h += QString(p.name()) + " (" + QString(p.typeName()) + " )\n";
567 564 }
568 565 }
569 566
570 567 if (constructors()) {
571 568 h += "Constructors:\n";
572 569 PythonQtSlotInfo* constr = constructors();
573 570 while (constr) {
574 571 h += constr->fullSignature() + "\n";
575 572 constr = constr->nextInfo();
576 573 }
577 574 }
578 575
579 576 h += "Slots:\n";
580 577 h += "QString help()\n";
581 578 h += "QString className()\n";
582 579
583 580 if (_meta) {
584 581 int numMethods = _meta->methodCount();
585 582 for (int i = 0; i < numMethods; i++) {
586 583 QMetaMethod m = _meta->method(i);
587 584 if ((m.methodType() == QMetaMethod::Method ||
588 585 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
589 QByteArray signa(m.signature());
590 if (signa.startsWith("new_")) continue;
591 if (signa.startsWith("delete_")) continue;
592 if (signa.startsWith("static_")) continue;
593 PythonQtSlotInfo slot(m, i);
586 PythonQtSlotInfo slot(this, m, i);
594 587 h += slot.fullSignature()+ "\n";
595 588 }
596 589 }
597 590 }
598 591
599 592 // TODO xxx : decorators and enums from decorator() are missing...
600 593 // maybe we can reuse memberlist()?
601 594
602 595 if (_meta && _meta->enumeratorCount()) {
603 596 h += "Enums:\n";
604 597 for (int i = 0; i<_meta->enumeratorCount(); i++) {
605 598 QMetaEnum e = _meta->enumerator(i);
606 599 h += QString(e.name()) + " {";
607 600 for (int j=0; j < e.keyCount(); j++) {
608 601 if (j) { h+= ", "; }
609 602 h += e.key(j);
610 603 }
611 604 h += " }\n";
612 605 }
613 606 }
614 607
615 608 if (_isQObject && _meta) {
616 609 int numMethods = _meta->methodCount();
617 610 if (numMethods>0) {
618 611 h += "Signals:\n";
619 612 for (int i = 0; i < numMethods; i++) {
620 613 QMetaMethod m = _meta->method(i);
621 614 if (m.methodType() == QMetaMethod::Signal) {
622 615 h += QString(m.signature()) + "\n";
623 616 }
624 617 }
625 618 }
626 619 }
627 620 return h;
628 621 }
629 622
630 623 PythonQtSlotInfo* PythonQtClassInfo::constructors()
631 624 {
632 625 if (!_constructors) {
633 626 // force creation of lazy decorator, which will register the decorators
634 627 decorator();
635 628 }
636 629 return _constructors;
637 630 }
638 631
639 632 PythonQtSlotInfo* PythonQtClassInfo::destructor()
640 633 {
641 634 if (!_destructor) {
642 635 // force creation of lazy decorator, which will register the decorators
643 636 decorator();
644 637 }
645 638 return _destructor;
646 639 }
647 640
648 641 void PythonQtClassInfo::addConstructor(PythonQtSlotInfo* info)
649 642 {
650 643 PythonQtSlotInfo* prev = constructors();
651 644 if (prev) {
652 645 info->setNextInfo(prev->nextInfo());
653 646 prev->setNextInfo(info);
654 647 } else {
655 648 _constructors = info;
656 649 }
657 650 }
658 651
659 652 void PythonQtClassInfo::addDecoratorSlot(PythonQtSlotInfo* info)
660 653 {
661 654 _decoratorSlots.append(info);
662 655 }
663 656
664 657 void PythonQtClassInfo::setDestructor(PythonQtSlotInfo* info)
665 658 {
666 659 if (_destructor) {
667 660 _destructor->deleteOverloadsAndThis();
668 661 }
669 662 _destructor = info;
670 663 }
671 664
672 665 void PythonQtClassInfo::setMetaObject(const QMetaObject* meta)
673 666 {
674 667 _meta = meta;
675 668 clearCachedMembers();
676 669 }
677 670
678 671 QObject* PythonQtClassInfo::decorator()
679 672 {
680 673 if (!_decoratorProvider && _decoratorProviderCB) {
681 674 _decoratorProvider = (*_decoratorProviderCB)();
682 675 if (_decoratorProvider) {
683 676 _decoratorProvider->setParent(PythonQt::priv());
677 // setup enums early, since they might be needed by the constructor decorators:
678 if (!_enumsCreated) {
679 createEnumWrappers();
680 }
684 681 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
685 682 }
686 683 }
684 // check if enums need to be created and create them if they are not yet created
687 685 if (!_enumsCreated) {
688 686 createEnumWrappers();
689 687 }
690 688 return _decoratorProvider;
691 689 }
692 690
693 691 bool PythonQtClassInfo::hasOwnerMethodButNoOwner(void* object)
694 692 {
695 693 PythonQtMemberInfo info = member("hasOwner");
696 694 if (info._type == PythonQtMemberInfo::Slot) {
697 695 void* obj = object;
698 696 bool result = false;
699 697 void* args[2];
700 698 args[0] = &result;
701 699 args[1] = &obj;
702 700 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
703 701 return !result;
704 702 } else {
705 703 return false;
706 704 }
707 705 }
708 706
709 707 void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, char** resultClassName)
710 708 {
711 709 if (!_polymorphicHandlers.isEmpty()) {
712 710 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
713 711 void* resultPtr = (*cb)(ptr, resultClassName);
714 712 if (resultPtr) {
715 713 return resultPtr;
716 714 }
717 715 }
718 716 }
719 717 foreach(const ParentClassInfo& info, _parentClasses) {
720 718 if (!info._parent->isQObject()) {
721 719 void* resultPtr = info._parent->recursiveCastDownIfPossible((char*)ptr + info._upcastingOffset, resultClassName);
722 720 if (resultPtr) {
723 721 return resultPtr;
724 722 }
725 723 }
726 724 }
727 725 return NULL;
728 726 }
729 727
730 728 void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo)
731 729 {
732 730 char* className;
733 731 // this would do downcasting recursively...
734 732 // void* resultPtr = recursiveCastDownIfPossible(ptr, &className);
735 733
736 734 // we only do downcasting on the base object, not on the whole inheritance tree...
737 735 void* resultPtr = NULL;
738 736 if (!_polymorphicHandlers.isEmpty()) {
739 737 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
740 738 resultPtr = (*cb)(ptr, &className);
741 739 if (resultPtr) {
742 740 break;
743 741 }
744 742 }
745 743 }
746 744 if (resultPtr) {
747 745 *resultClassInfo = PythonQt::priv()->getClassInfo(className);
748 746 } else {
749 747 *resultClassInfo = this;
750 748 resultPtr = ptr;
751 749 }
752 750 return resultPtr;
753 751 }
754 752
755 753 bool PythonQtClassInfo::hasEnum(const QByteArray& name, PythonQtClassInfo* localScope)
756 754 {
757 755 int scopePos = name.lastIndexOf("::");
758 756 if (scopePos != -1) {
759 757 // slit into scope and enum name
760 758 QByteArray enumScope = name.mid(0,scopePos);
761 759 QByteArray enumName = name.mid(scopePos+2);
762 760 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(enumScope);
763 761 if (info) {
764 762 return info->hasEnum(enumName);
765 763 } else{
766 764 return false;
767 765 }
768 766 }
769 767 if (localScope) {
770 768 return localScope->hasEnum(name);
771 769 } else {
772 770 return false;
773 771 }
774 772 }
775 773
776 774 bool PythonQtClassInfo::hasEnum(const QByteArray& name)
777 775 {
778 776 bool found = false;
779 777 if (_meta) {
780 778 found = _meta->indexOfEnumerator(name)!=-1;
781 779 }
782 780 if (!found) {
783 781 // check enums in the class hierachy of CPP classes
784 782 // look for dynamic decorators in this class and in derived classes
785 783 QList<QObject*> decoObjects;
786 784 recursiveCollectDecoratorObjects(decoObjects);
787 785 foreach(QObject* deco, decoObjects) {
788 786 found = deco->metaObject()->indexOfEnumerator(name)!=-1;
789 787 if (found) {
790 788 break;
791 789 }
792 790 }
793 791 }
794 792 return found;
795 793 }
796 794
797 795 void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta)
798 796 {
799 797 for (int i = meta->enumeratorOffset();i<meta->enumeratorCount();i++) {
800 798 QMetaEnum e = meta->enumerator(i);
801 799 PythonQtObjectPtr p;
802 800 p.setNewRef(PythonQt::priv()->createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper));
803 801 _enumWrappers.append(p);
804 802 }
805 803 }
806 804
807 805 void PythonQtClassInfo::createEnumWrappers()
808 806 {
809 807 if (!_enumsCreated) {
810 808 _enumsCreated = true;
811 809 if (_meta) {
812 810 createEnumWrappers(_meta);
813 811 }
814 812 if (decorator()) {
815 813 createEnumWrappers(decorator()->metaObject());
816 814 }
817 815 foreach(const ParentClassInfo& info, _parentClasses) {
818 816 info._parent->createEnumWrappers();
819 817 }
820 818 }
821 819 }
822 820
823 821 PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) {
824 822 foreach(const PythonQtObjectPtr& p, _enumWrappers) {
825 823 const char* className = ((PyTypeObject*)p.object())->tp_name;
826 824 if (qstrcmp(className, name)==0) {
827 825 return p.object();
828 826 }
829 827 }
830 828 foreach(const ParentClassInfo& info, _parentClasses) {
831 829 PyObject* p = info._parent->findEnumWrapper(name);
832 830 if (p) return p;
833 831 }
834 832 return NULL;
835 833 }
836 834
@@ -1,319 +1,320
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 #include "PythonQtClassInfo.h"
43 44 #include <iostream>
44 45
45 46 QHash<QByteArray, PythonQtMethodInfo*> PythonQtMethodInfo::_cachedSignatures;
46 47 QHash<QByteArray, QByteArray> PythonQtMethodInfo::_parameterNameAliases;
47 48
48 PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta)
49 PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo)
49 50 {
50 51 #ifdef PYTHONQT_DEBUG
51 52 QByteArray sig(meta.signature());
52 53 sig = sig.mid(sig.indexOf('('));
53 54 QByteArray fullSig = QByteArray(meta.typeName()) + " " + sig;
54 55 std::cout << "caching " << fullSig.data() << std::endl;
55 56 #endif
56 57
57 58 ParameterInfo type;
58 59 fillParameterInfo(type, QByteArray(meta.typeName()));
59 60 _parameters.append(type);
60 61 QByteArray name;
61 62 QList<QByteArray> names = meta.parameterTypes();
62 63 foreach (name, names) {
63 64 fillParameterInfo(type, name);
64 65 _parameters.append(type);
65 66 }
66 67 }
67 68
68 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal)
69 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo)
69 70 {
70 71 QByteArray sig(signal.signature());
71 72 sig = sig.mid(sig.indexOf('('));
72 73 QByteArray fullSig = QByteArray(signal.typeName()) + " " + sig;
73 74 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
74 75 if (!result) {
75 result = new PythonQtMethodInfo(signal);
76 result = new PythonQtMethodInfo(signal, classInfo);
76 77 _cachedSignatures.insert(fullSig, result);
77 78 }
78 79 return result;
79 80 }
80 81
81 82 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromMetaObjectAndSignature(const QMetaObject* metaObject, const char* signature)
82 83 {
83 84 QByteArray sig = QMetaObject::normalizedSignature(signature);
84 85 int idx = metaObject->indexOfMethod(sig);
85 86 QMetaMethod meta = metaObject->method(idx);
86 return PythonQtMethodInfo::getCachedMethodInfo(meta);
87 return PythonQtMethodInfo::getCachedMethodInfo(meta, NULL);
87 88 }
88 89
89 90 void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName)
90 91 {
91 92 QByteArray name = orgName;
92 93
93 94 int len = name.length();
94 95 if (len>0) {
95 96 if (strncmp(name.constData(), "const ", 6)==0) {
96 97 name = name.mid(6);
97 98 len -= 6;
98 99 type.isConst = true;
99 100 } else {
100 101 type.isConst = false;
101 102 }
102 103 bool hadPointer = false;
103 104 bool hadReference = false;
104 105 // remove * and & from the end of the string, handle & and * the same way
105 106 while (name.at(len-1) == '*') {
106 107 len--;
107 108 hadPointer = true;
108 109 }
109 110 while (name.at(len-1) == '&') {
110 111 len--;
111 112 hadReference = true;
112 113 }
113 114 if (len!=name.length()) {
114 115 name = name.left(len);
115 116 }
116 117 type.isPointer = hadPointer;
117 118
118 119 QByteArray alias = _parameterNameAliases.value(name);
119 120 if (!alias.isEmpty()) {
120 121 name = alias;
121 122 }
122 123
123 124 type.typeId = nameToType(name);
124 125 if (!type.isPointer && type.typeId == Unknown) {
125 126 type.typeId = QMetaType::type(name.constData());
126 127 if (type.typeId == QMetaType::Void) {
127 128 type.typeId = Unknown;
128 129 }
129 130 }
130 131 type.name = name;
131 132 } else {
132 133 type.typeId = QMetaType::Void;
133 134 type.isPointer = false;
134 135 type.isConst = false;
135 136 }
136 137 }
137 138
138 139 int PythonQtMethodInfo::nameToType(const char* name)
139 140 {
140 141 if (_parameterTypeDict.isEmpty()) {
141 142 // we could also use QMetaType::nameToType, but that does a string compare search
142 143 // and does not support QVariant
143 144
144 145 // QMetaType names
145 146 _parameterTypeDict.insert("long", QMetaType::Long);
146 147 _parameterTypeDict.insert("int", QMetaType::Int);
147 148 _parameterTypeDict.insert("short", QMetaType::Short);
148 149 _parameterTypeDict.insert("char", QMetaType::Char);
149 150 _parameterTypeDict.insert("ulong", QMetaType::ULong);
150 151 _parameterTypeDict.insert("unsigned long", QMetaType::ULong);
151 152 _parameterTypeDict.insert("uint", QMetaType::UInt);
152 153 _parameterTypeDict.insert("unsigned int", QMetaType::UInt);
153 154 _parameterTypeDict.insert("ushort", QMetaType::UShort);
154 155 _parameterTypeDict.insert("unsigned short", QMetaType::UShort);
155 156 _parameterTypeDict.insert("uchar", QMetaType::UChar);
156 157 _parameterTypeDict.insert("unsigned char", QMetaType::UChar);
157 158 _parameterTypeDict.insert("bool", QMetaType::Bool);
158 159 _parameterTypeDict.insert("float", QMetaType::Float);
159 160 _parameterTypeDict.insert("double", QMetaType::Double);
160 161 _parameterTypeDict.insert("qreal", QMetaType::Double);
161 162 _parameterTypeDict.insert("QChar", QMetaType::QChar);
162 163 _parameterTypeDict.insert("QByteArray", QMetaType::QByteArray);
163 164 _parameterTypeDict.insert("Q3CString", QMetaType::QByteArray);
164 165 _parameterTypeDict.insert("QString", QMetaType::QString);
165 166 _parameterTypeDict.insert("", QMetaType::Void);
166 167 _parameterTypeDict.insert("void", QMetaType::Void);
167 168 // QVariant names
168 169 _parameterTypeDict.insert("Q_LLONG", QMetaType::LongLong);
169 170 _parameterTypeDict.insert("Q_ULLONG", QMetaType::ULongLong);
170 171 _parameterTypeDict.insert("qlonglong", QMetaType::LongLong);
171 172 _parameterTypeDict.insert("qulonglong", QMetaType::ULongLong);
172 173 _parameterTypeDict.insert("qint64", QMetaType::LongLong);
173 174 _parameterTypeDict.insert("quint64", QMetaType::ULongLong);
174 175 _parameterTypeDict.insert("QIconSet", QMetaType::QIcon);
175 176 _parameterTypeDict.insert("QVariantMap", QMetaType::QVariantMap);
176 177 _parameterTypeDict.insert("QVariantList", QMetaType::QVariantList);
177 178 _parameterTypeDict.insert("QMap<QString,QVariant>", QMetaType::QVariantMap);
178 179 _parameterTypeDict.insert("QList<QVariant>", QMetaType::QVariantList);
179 180 _parameterTypeDict.insert("QStringList", QMetaType::QStringList);
180 181 _parameterTypeDict.insert("QBitArray", QMetaType::QBitArray);
181 182 _parameterTypeDict.insert("QDate", QMetaType::QDate);
182 183 _parameterTypeDict.insert("QTime", QMetaType::QTime);
183 184 _parameterTypeDict.insert("QDateTime", QMetaType::QDateTime);
184 185 _parameterTypeDict.insert("QUrl", QMetaType::QUrl);
185 186 _parameterTypeDict.insert("QLocale", QMetaType::QLocale);
186 187 _parameterTypeDict.insert("QRect", QMetaType::QRect);
187 188 _parameterTypeDict.insert("QRectf", QMetaType::QRectF);
188 189 _parameterTypeDict.insert("QSize", QMetaType::QSize);
189 190 _parameterTypeDict.insert("QSizef", QMetaType::QSizeF);
190 191 _parameterTypeDict.insert("QLine", QMetaType::QLine);
191 192 _parameterTypeDict.insert("QLinef", QMetaType::QLineF);
192 193 _parameterTypeDict.insert("QPoint", QMetaType::QPoint);
193 194 _parameterTypeDict.insert("QPointf", QMetaType::QPointF);
194 195 _parameterTypeDict.insert("QRegExp", QMetaType::QRegExp);
195 196 // _parameterTypeDict.insert("QColorGroup", QMetaType::QColorGroup);
196 197 _parameterTypeDict.insert("QFont", QMetaType::QFont);
197 198 _parameterTypeDict.insert("QPixmap", QMetaType::QPixmap);
198 199 _parameterTypeDict.insert("QBrush", QMetaType::QBrush);
199 200 _parameterTypeDict.insert("QColor", QMetaType::QColor);
200 201 _parameterTypeDict.insert("QCursor", QMetaType::QCursor);
201 202 _parameterTypeDict.insert("QPalette", QMetaType::QPalette);
202 203 _parameterTypeDict.insert("QIcon", QMetaType::QIcon);
203 204 _parameterTypeDict.insert("QImage", QMetaType::QPolygon);
204 205 _parameterTypeDict.insert("QRegion", QMetaType::QRegion);
205 206 _parameterTypeDict.insert("QBitmap", QMetaType::QBitmap);
206 207 _parameterTypeDict.insert("QSizePolicy", QMetaType::QSizePolicy);
207 208 _parameterTypeDict.insert("QKeySequence", QMetaType::QKeySequence);
208 209 _parameterTypeDict.insert("QPen", QMetaType::QPen);
209 210 _parameterTypeDict.insert("QTextLength", QMetaType::QTextLength);
210 211 _parameterTypeDict.insert("QTextFormat", QMetaType::QTextFormat);
211 212 _parameterTypeDict.insert("QMatrix", QMetaType::QMatrix);
212 213 _parameterTypeDict.insert("QVariant", PythonQtMethodInfo::Variant);
213 214 // own special types... (none so far, could be e.g. ObjectList
214 215 }
215 216 QHash<QByteArray, int>::const_iterator it = _parameterTypeDict.find(name);
216 217 if (it!=_parameterTypeDict.end()) {
217 218 return it.value();
218 219 } else {
219 220 return PythonQtMethodInfo::Unknown;
220 221 }
221 222 }
222 223
223 224 void PythonQtMethodInfo::cleanupCachedMethodInfos()
224 225 {
225 226 QHashIterator<QByteArray, PythonQtMethodInfo *> i(_cachedSignatures);
226 227 while (i.hasNext()) {
227 228 delete i.next().value();
228 229 }
229 230 }
230 231
231 232 void PythonQtMethodInfo::addParameterTypeAlias(const QByteArray& alias, const QByteArray& name)
232 233 {
233 234 _parameterNameAliases.insert(alias, name);
234 235 }
235 236
236 237 //-------------------------------------------------------------------------------------------------
237 238
238 239 void PythonQtSlotInfo::deleteOverloadsAndThis()
239 240 {
240 241 PythonQtSlotInfo* cur = this;
241 242 while(cur->nextInfo()) {
242 243 PythonQtSlotInfo* next = cur->nextInfo();
243 244 delete cur;
244 245 cur = next;
245 246 }
246 247 }
247 248
248 249
249 250 QString PythonQtSlotInfo::fullSignature()
250 251 {
251 252 bool skipFirstArg = isInstanceDecorator();
252 253 QString result = _meta.typeName();
253 254 QByteArray sig = slotName();
254 255 QList<QByteArray> names = _meta.parameterNames();
255 256
256 257 bool isStatic = false;
257 258 bool isConstructor = false;
258 259 bool isDestructor = false;
259 260
260 261 if (_type == ClassDecorator) {
261 262 if (sig.startsWith("new_")) {
262 263 sig = sig.mid(strlen("new_"));
263 264 isConstructor = true;
264 265 } else if (sig.startsWith("delete_")) {
265 266 sig = sig.mid(strlen("delete_"));
266 267 isDestructor = true;
267 268 } else if(sig.startsWith("static_")) {
268 269 isStatic = true;
269 270 sig = sig.mid(strlen("static_"));
270 271 int idx = sig.indexOf("_");
271 272 if (idx>=0) {
272 273 sig = sig.mid(idx+1);
273 274 }
274 275 }
275 276 }
276 277
277 278 result += QByteArray(" ") + sig;
278 279 result += "(";
279 280
280 281 int lastEntry = _parameters.count()-1;
281 282 for (int i = skipFirstArg?2:1; i<_parameters.count(); i++) {
282 283 if (_parameters.at(i).isConst) {
283 284 result += "const ";
284 285 }
285 286 result += _parameters.at(i).name;
286 287 if (_parameters.at(i).isPointer) {
287 288 result += "*";
288 289 }
289 290 if (!names.at(i-1).isEmpty()) {
290 291 result += " ";
291 292 result += names.at(i-1);
292 293 }
293 294 if (i!=lastEntry) {
294 295 result += ", ";
295 296 }
296 297 }
297 298 result += ")";
298 299
299 300 if (isStatic) {
300 301 result = QString("static ") + result;
301 302 }
302 303 if (isConstructor) {
303 304 // result = QString("constructor ") + result;
304 305 }
305 306 if (isDestructor) {
306 307 result = QString("~") + result;
307 308 }
308 309 return result;
309 310 }
310 311
311 312
312 313 QByteArray PythonQtSlotInfo::slotName()
313 314 {
314 315 QByteArray sig(_meta.signature());
315 316 int idx = sig.indexOf('(');
316 317 sig = sig.left(idx);
317 318 return sig;
318 319 }
319 320
@@ -1,184 +1,186
1 1 #ifndef _PYTHONQTMETHODINFO_H
2 2 #define _PYTHONQTMETHODINFO_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtMethodInfo.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46
47 47 #include <QByteArray>
48 48 #include <QHash>
49 49 #include <QList>
50 50 #include <QMetaMethod>
51 51
52 class PythonQtClassInfo;
53
52 54 //! stores information about a specific signal/slot/method
53 55 class PYTHONQT_EXPORT PythonQtMethodInfo
54 56 {
55 57 public:
56 58 enum ParameterType {
57 59 Unknown = -1,
58 60 Variant = -2
59 61 };
60 62
61 63 //! stores the QVariant id (if available) and the name of the type
62 64 struct ParameterInfo {
63 65 int typeId; // a mixture from QMetaType and ParameterType
64 66 QByteArray name;
65 67 bool isPointer;
66 68 bool isConst;
67 69 };
68 70
69 71 PythonQtMethodInfo() {};
70 72 ~PythonQtMethodInfo() {};
71 PythonQtMethodInfo(const QMetaMethod& meta);
73 PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo);
72 74 PythonQtMethodInfo(const PythonQtMethodInfo& other) {
73 75 _parameters = other._parameters;
74 76 }
75 77
76 78 //! returns the method info of the signature, uses a cache internally to speed up
77 //! multiple requests for the same method
78 static const PythonQtMethodInfo* getCachedMethodInfo(const QMetaMethod& method);
79 //! multiple requests for the same method, classInfo is passed to allow local enum resolution (if NULL is passed, no local enums are recognized)
80 static const PythonQtMethodInfo* getCachedMethodInfo(const QMetaMethod& method, PythonQtClassInfo* classInfo);
79 81
80 //! get the cached method info by finding the meta method on the meta object via its signature
82 //! get the cached method info by finding the meta method on the meta object via its signature, enums are only supported with leading namespace::
81 83 static const PythonQtMethodInfo* getCachedMethodInfoFromMetaObjectAndSignature(const QMetaObject* metaObject, const char* signature);
82 84
83 85 //! cleanup the cache
84 86 static void cleanupCachedMethodInfos();
85 87
86 88 //! returns the number of parameters including the return value
87 89 int parameterCount() const { return _parameters.size(); };
88 90
89 91 //! returns the id for the given type (using an internal dictionary)
90 92 static int nameToType(const char* name);
91 93
92 94 //! get the parameter infos
93 95 const QList<ParameterInfo>& parameters() const { return _parameters; }
94 96
95 97 //! add an alias for a typename, e.g. QObjectList and QList<QObject*>.
96 98 static void addParameterTypeAlias(const QByteArray& alias, const QByteArray& name);
97 99
98 100 protected:
99 101 static void fillParameterInfo(ParameterInfo& type, const QByteArray& name);
100 102
101 103 static QHash<QByteArray, int> _parameterTypeDict;
102 104 static QHash<QByteArray, QByteArray> _parameterNameAliases;
103 105
104 106 //! stores the cached signatures of methods to speedup mapping from Qt to Python types
105 107 static QHash<QByteArray, PythonQtMethodInfo*> _cachedSignatures;
106 108
107 109 QList<ParameterInfo> _parameters;
108 110 };
109 111
110 112 //! stores information about a slot, including a next pointer to overloaded slots
111 113 class PythonQtSlotInfo : public PythonQtMethodInfo
112 114 {
113 115 public:
114 116 enum Type {
115 117 MemberSlot, InstanceDecorator, ClassDecorator
116 118 };
117 119
118 120 PythonQtSlotInfo(const PythonQtSlotInfo& info):PythonQtMethodInfo() {
119 121 _meta = info._meta;
120 122 _parameters = info._parameters;
121 123 _slotIndex = info._slotIndex;
122 124 _next = NULL;
123 125 _decorator = info._decorator;
124 126 _type = info._type;
125 127 _upcastingOffset = 0;
126 128 }
127 129
128 PythonQtSlotInfo(const QMetaMethod& meta, int slotIndex, QObject* decorator = NULL, Type type = MemberSlot ):PythonQtMethodInfo()
130 PythonQtSlotInfo(PythonQtClassInfo* classInfo, const QMetaMethod& meta, int slotIndex, QObject* decorator = NULL, Type type = MemberSlot ):PythonQtMethodInfo()
129 131 {
130 const PythonQtMethodInfo* info = getCachedMethodInfo(meta);
132 const PythonQtMethodInfo* info = getCachedMethodInfo(meta, classInfo);
131 133 _meta = meta;
132 134 _parameters = info->parameters();
133 135 _slotIndex = slotIndex;
134 136 _next = NULL;
135 137 _decorator = decorator;
136 138 _type = type;
137 139 _upcastingOffset = 0;
138 140 }
139 141
140 142
141 143 public:
142 144
143 145 void deleteOverloadsAndThis();
144 146
145 147 const QMetaMethod* metaMethod() const { return &_meta; }
146 148
147 149 void setUpcastingOffset(int upcastingOffset) { _upcastingOffset = upcastingOffset; }
148 150
149 151 int upcastingOffset() const { return _upcastingOffset; }
150 152
151 153 //! get the index of the slot (needed for qt_metacall)
152 154 int slotIndex() const { return _slotIndex; }
153 155
154 156 //! get next overloaded slot (which has the same name)
155 157 PythonQtSlotInfo* nextInfo() const { return _next; }
156 158
157 159 //! set the next overloaded slot
158 160 void setNextInfo(PythonQtSlotInfo* next) { _next = next; }
159 161
160 162 //! returns if the slot is a decorator slot
161 163 bool isInstanceDecorator() { return _decorator!=NULL && _type == InstanceDecorator; }
162 164
163 165 //! returns if the slot is a constructor slot
164 166 bool isClassDecorator() { return _decorator!=NULL && _type == ClassDecorator; }
165 167
166 168 QObject* decorator() { return _decorator; }
167 169
168 170 //! get the full signature including return type
169 171 QString fullSignature();
170 172
171 173 //! get the short slot name
172 174 QByteArray slotName();
173 175
174 176 private:
175 177 int _slotIndex;
176 178 PythonQtSlotInfo* _next;
177 179 QObject* _decorator;
178 180 Type _type;
179 181 QMetaMethod _meta;
180 182 int _upcastingOffset;
181 183 };
182 184
183 185
184 186 #endif
@@ -1,222 +1,233
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 PythonQtSignalReceiver.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 "PythonQtSignalReceiver.h"
43 43 #include "PythonQtClassInfo.h"
44 44 #include "PythonQtMethodInfo.h"
45 45 #include "PythonQtConversion.h"
46 46 #include <QMetaObject>
47 47 #include <QMetaMethod>
48 48 #include "funcobject.h"
49 49
50 50 void PythonQtSignalTarget::call(void **arguments) const {
51 51 PyObject* result = call(_callable, methodInfo(), arguments, false);
52 52 if (result) {
53 53 Py_DECREF(result);
54 54 }
55 55 }
56 56
57 57 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInfo* methodInfos, void **arguments, bool skipFirstArgumentOfMethodInfo)
58 58 {
59 59 // Note: we check if the callable is a PyFunctionObject and has a fixed number of arguments
60 60 // if that is the case, we only pass these arguments to python and skip the additional arguments from the signal
61 61
62 62 int numPythonArgs = -1;
63 63 if (PyFunction_Check(callable)) {
64 64 PyObject* o = callable;
65 65 PyFunctionObject* func = (PyFunctionObject*)o;
66 66 PyCodeObject* code = (PyCodeObject*)func->func_code;
67 67 if (!(code->co_flags & 0x04)) {
68 68 numPythonArgs = code->co_argcount;
69 69 } else {
70 70 // variable numbers of arguments allowed
71 71 }
72 72 } else if (PyMethod_Check(callable)) {
73 73 PyObject* o = callable;
74 74 PyMethodObject* method = (PyMethodObject*)o;
75 75 if (PyFunction_Check(method->im_func)) {
76 76 PyFunctionObject* func = (PyFunctionObject*)method->im_func;
77 77 PyCodeObject* code = (PyCodeObject*)func->func_code;
78 78 if (!(code->co_flags & 0x04)) {
79 79 numPythonArgs = code->co_argcount - 1; // we subtract one because the first is "self"
80 80 } else {
81 81 // variable numbers of arguments allowed
82 82 }
83 83 }
84 84 }
85 85
86 86 const PythonQtMethodInfo* m = methodInfos;
87 87 // parameterCount includes return value:
88 88 int count = m->parameterCount();
89 89 if (skipFirstArgumentOfMethodInfo) {
90 90 count--;
91 91 }
92 92 if (numPythonArgs!=-1) {
93 93 if (count>numPythonArgs+1) {
94 94 // take less arguments
95 95 count = numPythonArgs+1;
96 96 }
97 97 }
98 98
99 99 PyObject* pargs = NULL;
100 100 if (count>1) {
101 101 pargs = PyTuple_New(count-1);
102 102 }
103 103 bool err = false;
104 104 // transform Qt values to Python
105 105 const QList<PythonQtMethodInfo::ParameterInfo>& params = m->parameters();
106 106 int skipFirstOffset = 0;
107 107 if (skipFirstArgumentOfMethodInfo) {
108 108 skipFirstOffset = 1;
109 109 }
110 110 for (int i = 1; i < count; i++) {
111 111 const PythonQtMethodInfo::ParameterInfo& param = params.at(i + skipFirstOffset);
112 112 PyObject* arg = PythonQtConv::ConvertQtValueToPython(param, arguments[i]);
113 113 if (arg) {
114 114 // steals reference, no unref
115 115 PyTuple_SetItem(pargs, i-1,arg);
116 116 } else {
117 117 err = true;
118 118 break;
119 119 }
120 120 }
121 121
122 122 PyObject* result = NULL;
123 123 if (!err) {
124 124 PyErr_Clear();
125 125 result = PyObject_CallObject(callable, pargs);
126 126 if (result) {
127 127 // ok
128 128 } else {
129 129 PythonQt::self()->handleError();
130 130 }
131 131 }
132 132 if (pargs) {
133 133 // free the arguments again
134 134 Py_DECREF(pargs);
135 135 }
136 136
137 137 return result;
138 138 }
139 139
140 140 //------------------------------------------------------------------------------
141 141
142 142 PythonQtSignalReceiver::PythonQtSignalReceiver(QObject* obj):PythonQtSignalReceiverBase(obj)
143 143 {
144 144 _obj = obj;
145
146 // fetch the class info for object, since we will need to for correct enum resolution in
147 // signals
148 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
149 if (!_objClassInfo || !_objClassInfo->isQObject()) {
150 PythonQt::self()->registerClass(obj->metaObject());
151 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
152 }
153 // force decorator/enum creation
154 _objClassInfo->decorator();
155
145 156 _slotCount = staticMetaObject.methodOffset();
146 157 }
147 158
148 159 PythonQtSignalReceiver::~PythonQtSignalReceiver()
149 160 {
150 161 PythonQt::priv()->removeSignalEmitter(_obj);
151 162 }
152 163
153 164
154 165 bool PythonQtSignalReceiver::addSignalHandler(const char* signal, PyObject* callable)
155 166 {
156 167 bool flag = false;
157 168 int sigId = getSignalIndex(signal);
158 169 if (sigId>=0) {
159 170 // create PythonQtMethodInfo from signal
160 171 QMetaMethod meta = _obj->metaObject()->method(sigId);
161 const PythonQtMethodInfo* signalInfo = PythonQtMethodInfo::getCachedMethodInfo(meta);
172 const PythonQtMethodInfo* signalInfo = PythonQtMethodInfo::getCachedMethodInfo(meta, _objClassInfo);
162 173 PythonQtSignalTarget t(sigId, signalInfo, _slotCount, callable);
163 174 _targets.append(t);
164 175 // now connect to ourselves with the new slot id
165 176 QMetaObject::connect(_obj, sigId, this, _slotCount, Qt::AutoConnection, 0);
166 177
167 178 _slotCount++;
168 179 flag = true;
169 180 }
170 181 return flag;
171 182 }
172 183
173 184 bool PythonQtSignalReceiver::removeSignalHandler(const char* signal, PyObject* callable)
174 185 {
175 186 bool found = false;
176 187 int sigId = getSignalIndex(signal);
177 188 if (sigId>=0) {
178 189 QMutableListIterator<PythonQtSignalTarget> i(_targets);
179 190 while (i.hasNext()) {
180 191 if (i.next().isSame(sigId, callable)) {
181 192 i.remove();
182 193 found = true;
183 194 break;
184 195 }
185 196 }
186 197 }
187 198 return found;
188 199 }
189 200
190 201 void PythonQtSignalReceiver::removeSignalHandlers()
191 202 {
192 203 _targets.clear();
193 204 }
194 205
195 206 int PythonQtSignalReceiver::getSignalIndex(const char* signal)
196 207 {
197 208 int sigId = _obj->metaObject()->indexOfSignal(signal+1);
198 209 if (sigId<0) {
199 210 QByteArray tmpSig = QMetaObject::normalizedSignature(signal+1);
200 211 sigId = _obj->metaObject()->indexOfSignal(tmpSig);
201 212 }
202 213 return sigId;
203 214 }
204 215
205 216 int PythonQtSignalReceiver::qt_metacall(QMetaObject::Call c, int id, void **arguments)
206 217 {
207 218 // mlabDebugConst("PythonQt", "PythonQtSignalReceiver invoke " << _obj->className() << " " << _obj->name() << " " << id);
208 219 if (c != QMetaObject::InvokeMetaMethod) {
209 220 QObject::qt_metacall(c, id, arguments);
210 221 }
211 222
212 223 bool found = false;
213 224 foreach(const PythonQtSignalTarget& t, _targets) {
214 225 if (t.slotId() == id) {
215 226 found = true;
216 227 t.call(arguments);
217 228 break;
218 229 }
219 230 }
220 231 return 0;
221 232 }
222 233
@@ -1,139 +1,141
1 1 #ifndef _PYTHONQTSIGNALRECEIVER_H
2 2 #define _PYTHONQTSIGNALRECEIVER_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 PythonQtSignalReceiver.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include <Python.h>
46 46 #include "PythonQtSystem.h"
47 47 #include "PythonQtObjectPtr.h"
48 48
49 49 class PythonQtMethodInfo;
50 class PythonQtClassInfo;
50 51
51 52 //! stores information about a signal target
52 53 /*! copy construction and assignment works fine with the C++ standard behaviour and are thus not implemented
53 54 */
54 55 class PYTHONQT_EXPORT PythonQtSignalTarget {
55 56 public:
56 57 PythonQtSignalTarget() {
57 58 _signalId = -1;
58 59 _methodInfo = NULL;
59 60 _slotId = -1;
60 61 }
61 62
62 63 PythonQtSignalTarget(int signalId,const PythonQtMethodInfo* methodInfo, int slotId, PyObject* callable)
63 64 {
64 65 _signalId = signalId;
65 66 _slotId = slotId;
66 67 _methodInfo = methodInfo;
67 68 _callable = callable;
68 69 };
69 70
70 71 ~PythonQtSignalTarget() {
71 72 };
72 73
73 74 //! get the id of the original signal
74 75 int signalId() const { return _signalId; }
75 76
76 77 //! get the id that was assigned to this simulated slot
77 78 int slotId() const { return _slotId; }
78 79
79 80 //! get the signals parameter info
80 81 const PythonQtMethodInfo* methodInfo() const { return _methodInfo; }
81 82
82 83 //! call the python callable with the given arguments (as defined in methodInfo)
83 84 void call(void **arguments) const;
84 85
85 86 //! check if it is the same signal target
86 87 bool isSame(int signalId, PyObject* callable) const { return callable==_callable && signalId==_signalId; }
87 88
88 89 //! call the given callable with arguments described by PythonQtMethodInfo, returns a new reference as result value (or NULL)
89 90 static PyObject* call(PyObject* callable, const PythonQtMethodInfo* methodInfo, void **arguments, bool skipFirstArgumentOfMethodInfo = false);
90 91
91 92 private:
92 93 int _signalId;
93 94 int _slotId;
94 95 const PythonQtMethodInfo* _methodInfo;
95 96 PythonQtObjectPtr _callable;
96 97 };
97 98
98 99 //! base class for signal receivers
99 100 /*!
100 101 */
101 102 class PythonQtSignalReceiverBase : public QObject {
102 103 Q_OBJECT
103 104 public:
104 105 PythonQtSignalReceiverBase(QObject* obj):QObject(obj) {};
105 106 };
106 107
107 108 //! receives all signals for one QObject
108 109 /*! we derive from our base but do not declare the QObject macro because we want to reimplement qt_metacall only.
109 110 */
110 111 class PythonQtSignalReceiver : public PythonQtSignalReceiverBase {
111 112
112 113 public:
113 114 PythonQtSignalReceiver(QObject* obj);
114 115 ~PythonQtSignalReceiver();
115 116
116 117 //! add a signal handler
117 118 bool addSignalHandler(const char* signal, PyObject* callable);
118 119
119 120 //! remove a signal handler
120 121 bool removeSignalHandler(const char* signal, PyObject* callable);
121 122
122 123 //! remove all signal handlers
123 124 void removeSignalHandlers();
124 125
125 126 //! we implement this method to simulate a number of slots that match the ids in _targets
126 127 virtual int qt_metacall(QMetaObject::Call c, int id, void **arguments);
127 128
128 129 private:
129 130 //! get the index of the signal
130 131 int getSignalIndex(const char* signal);
131 132
132 133 QObject* _obj;
134 PythonQtClassInfo* _objClassInfo;
133 135 int _slotCount;
134 136 // linear list may get slow on multiple targets, but I think typically we have many objects and just a few signals
135 137 QList<PythonQtSignalTarget> _targets;
136 138 };
137 139
138 140
139 141 #endif
General Comments 0
You need to be logged in to leave comments. Login now