##// END OF EJS Templates
added error handling for virtual method overloads, added more global functions (qsrand etc.), added support for exec_ etc (python keyword overlap resolution), change virtual method handling, this will require code regeneration (I will do that tomorrow)...
florianlink -
r67:57d78f859ef3
parent child
Show More
@@ -1,1227 +1,1215
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
144 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
145 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
146 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
147 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
148 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
149 for (unsigned int i = 0;i<16; i++) {
150 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
151 if (obj) {
152 PyModule_AddObject(pack, names[i], obj);
153 Py_INCREF(obj);
154 PyModule_AddObject(pack2, names[i], obj);
155 } else {
156 std::cerr << "method not found " << names[i];
157 }
158 }
143 159 }
144 160
145 161 void PythonQt::cleanup()
146 162 {
147 163 if (_self) {
148 164 delete _self;
149 165 _self = NULL;
150 166 }
151 167 }
152 168
153 169 PythonQt::PythonQt(int flags)
154 170 {
155 171 _p = new PythonQtPrivate;
156 172 _p->_initFlags = flags;
157 173
158 174 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
159 175
160 176 Py_SetProgramName("PythonQt");
161 177 if (flags & IgnoreSiteModule) {
162 178 // this prevents the automatic importing of Python site files
163 179 Py_NoSiteFlag = 1;
164 180 }
165 181 Py_Initialize();
166 182
167 183 // add our own python object types for qt object slots
168 184 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
169 185 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
170 186 }
171 187 Py_INCREF(&PythonQtSlotFunction_Type);
172 188
173 189 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
174 190 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
175 191 // add our own python object types for classes
176 192 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
177 193 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
178 194 }
179 195 Py_INCREF(&PythonQtClassWrapper_Type);
180 196
181 197 // add our own python object types for CPP instances
182 198 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
183 199 PythonQt::handleError();
184 200 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
185 201 }
186 202 Py_INCREF(&PythonQtInstanceWrapper_Type);
187 203
188 204 // add our own python object types for redirection of stdout
189 205 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
190 206 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
191 207 }
192 208 Py_INCREF(&PythonQtStdOutRedirectType);
193 209
194 210 initPythonQtModule(flags & RedirectStdOut);
195 211
196 212 }
197 213
198 214 PythonQt::~PythonQt() {
199 215 delete _p;
200 216 _p = NULL;
201 217 }
202 218
203 219 PythonQtPrivate::~PythonQtPrivate() {
204 220 delete _defaultImporter;
205 221 _defaultImporter = NULL;
206 222
207 223 {
208 224 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
209 225 while (i.hasNext()) {
210 226 delete i.next().value();
211 227 }
212 228 }
213 229 PythonQtConv::global_valueStorage.clear();
214 230 PythonQtConv::global_ptrStorage.clear();
215 231 PythonQtConv::global_variantStorage.clear();
216 232
217 233 PythonQtMethodInfo::cleanupCachedMethodInfos();
218 234 }
219 235
220 236 PythonQtImportFileInterface* PythonQt::importInterface()
221 237 {
222 238 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
223 239 }
224 240
225 241 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
226 242 {
227 243 if (_self->_p->_noLongerWrappedCB) {
228 244 (*_self->_p->_noLongerWrappedCB)(o);
229 245 };
230 246 }
231 247
232 248 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
233 249 {
234 250 _p->registerClass(metaobject, package, wrapperCreator, shell);
235 251 }
236 252
237 253 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
238 254 {
239 255 // we register all classes in the hierarchy
240 256 const QMetaObject* m = metaobject;
241 257 bool first = true;
242 258 while (m) {
243 259 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
244 260 if (!info->pythonQtClassWrapper()) {
245 261 info->setupQObject(m);
246 262 createPythonQtClassWrapper(info, package);
247 263 if (m->superClass()) {
248 264 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
249 265 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
250 266 }
251 267 }
252 268 if (first) {
253 269 first = false;
254 270 if (wrapperCreator) {
255 271 info->setDecoratorProvider(wrapperCreator);
256 272 }
257 273 if (shell) {
258 274 info->setShellSetInstanceWrapperCB(shell);
259 275 }
260 276 }
261 277 m = m->superClass();
262 278 }
263 279 }
264 280
265 281 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package)
266 282 {
267 283 PyObject* pack = packageByName(package);
268 284 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, package);
269 285 PyModule_AddObject(pack, info->className(), pyobj);
270 286 if (package && strncmp(package,"Qt",2)==0) {
271 287 // since PyModule_AddObject steals the reference, we need a incref once more...
272 288 Py_INCREF(pyobj);
273 289 // put all qt objects into Qt as well
274 290 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
275 291 }
276 292 info->setPythonQtClassWrapper(pyobj);
277 293 }
278 294
279 295 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
280 296 {
281 297 if (!obj) {
282 298 Py_INCREF(Py_None);
283 299 return Py_None;
284 300 }
285 301 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
286 302 if (!wrap) {
287 303 // smuggling it in...
288 304 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
289 305 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
290 306 registerClass(obj->metaObject());
291 307 classInfo = _knownClassInfos.value(obj->metaObject()->className());
292 308 }
293 309 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
294 310 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
295 311 } else {
296 312 Py_INCREF(wrap);
297 313 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
298 314 }
299 315 return (PyObject*)wrap;
300 316 }
301 317
302 318 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
303 319 {
304 320 if (!ptr) {
305 321 Py_INCREF(Py_None);
306 322 return Py_None;
307 323 }
308 324
309 325 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
310 326 if (!wrap) {
311 327 PythonQtClassInfo* info = _knownClassInfos.value(name);
312 328 if (!info) {
313 329 // maybe it is a PyObject, which we can return directly
314 330 if (name == "PyObject") {
315 331 PyObject* p = (PyObject*)ptr;
316 332 Py_INCREF(p);
317 333 return p;
318 334 }
319 335
320 336 // we do not know the metaobject yet, but we might know it by it's name:
321 337 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
322 338 // yes, we know it, so we can convert to QObject
323 339 QObject* qptr = (QObject*)ptr;
324 340 registerClass(qptr->metaObject());
325 341 info = _knownClassInfos.value(qptr->metaObject()->className());
326 342 }
327 343 }
328 344 if (info && info->isQObject()) {
329 345 QObject* qptr = (QObject*)ptr;
330 346 // if the object is a derived object, we want to switch the class info to the one of the derived class:
331 347 if (name!=(qptr->metaObject()->className())) {
332 348 registerClass(qptr->metaObject());
333 349 info = _knownClassInfos.value(qptr->metaObject()->className());
334 350 }
335 351 wrap = createNewPythonQtInstanceWrapper(qptr, info);
336 352 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
337 353 return (PyObject*)wrap;
338 354 }
339 355
340 356 // not a known QObject, so try our wrapper factory:
341 357 QObject* wrapper = NULL;
342 358 for (int i=0; i<_cppWrapperFactories.size(); i++) {
343 359 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
344 360 if (wrapper) {
345 361 break;
346 362 }
347 363 }
348 364
349 365 if (info) {
350 366 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
351 367 ptr = info->castDownIfPossible(ptr, &info);
352 368 }
353 369
354 370 if (!info || info->pythonQtClassWrapper()==NULL) {
355 371 // still unknown, register as CPP class
356 372 registerCPPClass(name.constData());
357 373 info = _knownClassInfos.value(name);
358 374 }
359 375 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
360 376 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
361 377 info->setMetaObject(wrapper->metaObject());
362 378 }
363 379 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
364 380 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
365 381 } else {
366 382 Py_INCREF(wrap);
367 383 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
368 384 }
369 385 return (PyObject*)wrap;
370 386 }
371 387
372 388 PyObject* PythonQtPrivate::dummyTuple() {
373 389 static PyObject* dummyTuple = NULL;
374 390 if (dummyTuple==NULL) {
375 391 dummyTuple = PyTuple_New(1);
376 392 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
377 393 }
378 394 return dummyTuple;
379 395 }
380 396
381 397
382 398 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
383 399 // call the associated class type to create a new instance...
384 400 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
385 401
386 402 result->setQObject(obj);
387 403 result->_wrappedPtr = wrappedPtr;
388 404 result->_ownedByPythonQt = false;
389 405 result->_useQMetaTypeDestroy = false;
390 406
391 407 if (wrappedPtr) {
392 408 _wrappedObjects.insert(wrappedPtr, result);
393 409 } else {
394 410 _wrappedObjects.insert(obj, result);
395 411 if (obj->parent()== NULL && _wrappedCB) {
396 412 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
397 413 (*_wrappedCB)(obj);
398 414 }
399 415 }
400 416 return result;
401 417 }
402 418
403 419 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package) {
404 420 PythonQtClassWrapper* result;
405 421
406 422 PyObject* className = PyString_FromString(info->className());
407 423
408 424 PyObject* baseClasses = PyTuple_New(1);
409 425 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
410 426
411 427 PyObject* typeDict = PyDict_New();
412 428 QByteArray moduleName("PythonQt");
413 429 if (package && strcmp(package, "")!=0) {
414 430 moduleName += ".";
415 431 moduleName += package;
416 432 }
417 433 PyDict_SetItemString(typeDict, "__module__", PyString_FromString(moduleName.constData()));
418 434
419 435 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
420 436
421 437 // set the class info so that PythonQtClassWrapper_new can read it
422 438 _currentClassInfoForClassWrapperCreation = info;
423 439 // create the new type object by calling the type
424 440 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
425 441
426 442 Py_DECREF(baseClasses);
427 443 Py_DECREF(typeDict);
428 444 Py_DECREF(args);
429 445 Py_DECREF(className);
430 446
431 447 return result;
432 448 }
433 449
434 450 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
435 451 {
436 452 PyObject* args = Py_BuildValue("(i)", enumValue);
437 453 PyObject* result = PyObject_Call(enumType, args, NULL);
438 454 Py_DECREF(args);
439 455 return result;
440 456 }
441 457
442 458 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
443 459 PyObject* result;
444 460
445 461 PyObject* className = PyString_FromString(enumName);
446 462
447 463 PyObject* baseClasses = PyTuple_New(1);
448 464 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
449 465
450 466 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
451 467 PyObject* typeDict = PyDict_New();
452 468 PyDict_SetItemString(typeDict, "__module__", module);
453 469
454 470 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
455 471
456 472 // create the new int derived type object by calling the core type
457 473 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
458 474
459 475 Py_DECREF(baseClasses);
460 476 Py_DECREF(typeDict);
461 477 Py_DECREF(args);
462 478 Py_DECREF(className);
463 479
464 480 return result;
465 481 }
466 482
467 483 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
468 484 {
469 485 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
470 486 if (!r) {
471 487 r = new PythonQtSignalReceiver(obj);
472 488 _p->_signalReceivers.insert(obj, r);
473 489 }
474 490 return r;
475 491 }
476 492
477 493 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
478 494 {
479 495 bool flag = false;
480 496 PythonQtObjectPtr callable = lookupCallable(module, objectname);
481 497 if (callable) {
482 498 PythonQtSignalReceiver* r = getSignalReceiver(obj);
483 499 flag = r->addSignalHandler(signal, callable);
484 500 if (!flag) {
485 501 // signal not found
486 502 }
487 503 } else {
488 504 // callable not found
489 505 }
490 506 return flag;
491 507 }
492 508
493 509 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
494 510 {
495 511 bool flag = false;
496 512 PythonQtSignalReceiver* r = getSignalReceiver(obj);
497 513 if (r) {
498 514 flag = r->addSignalHandler(signal, receiver);
499 515 }
500 516 return flag;
501 517 }
502 518
503 519 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
504 520 {
505 521 bool flag = false;
506 522 PythonQtObjectPtr callable = lookupCallable(module, objectname);
507 523 if (callable) {
508 524 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
509 525 if (r) {
510 526 flag = r->removeSignalHandler(signal, callable);
511 527 }
512 528 } else {
513 529 // callable not found
514 530 }
515 531 return flag;
516 532 }
517 533
518 534 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
519 535 {
520 536 bool flag = false;
521 537 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
522 538 if (r) {
523 539 flag = r->removeSignalHandler(signal, receiver);
524 540 }
525 541 return flag;
526 542 }
527 543
528 544 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
529 545 {
530 546 PythonQtObjectPtr p = lookupObject(module, name);
531 547 if (p) {
532 548 if (PyCallable_Check(p)) {
533 549 return p;
534 550 }
535 551 }
536 552 PyErr_Clear();
537 553 return NULL;
538 554 }
539 555
540 556 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
541 557 {
542 558 QStringList l = name.split('.');
543 559 PythonQtObjectPtr p = module;
544 560 PythonQtObjectPtr prev;
545 561 QString s;
546 562 QByteArray b;
547 563 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
548 564 prev = p;
549 565 b = (*i).toLatin1();
550 566 if (PyDict_Check(p)) {
551 567 p = PyDict_GetItemString(p, b.data());
552 568 } else {
553 569 p.setNewRef(PyObject_GetAttrString(p, b.data()));
554 570 }
555 571 }
556 572 PyErr_Clear();
557 573 return p;
558 574 }
559 575
560 576 PythonQtObjectPtr PythonQt::getMainModule() {
561 577 //both borrowed
562 578 PythonQtObjectPtr dict = PyImport_GetModuleDict();
563 579 return PyDict_GetItemString(dict, "__main__");
564 580 }
565 581
566 582 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
567 583 QVariant result;
568 584 if (pycode) {
569 585 PyObject* dict = NULL;
570 586 if (PyModule_Check(object)) {
571 587 dict = PyModule_GetDict(object);
572 588 } else if (PyDict_Check(object)) {
573 589 dict = object;
574 590 }
575 591 PyObject* r = NULL;
576 592 if (dict) {
577 593 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
578 594 }
579 595 if (r) {
580 596 result = PythonQtConv::PyObjToQVariant(r);
581 597 Py_DECREF(r);
582 598 } else {
583 599 handleError();
584 600 }
585 601 } else {
586 602 handleError();
587 603 }
588 604 return result;
589 605 }
590 606
591 607 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
592 608 {
593 609 QVariant result;
594 610 PythonQtObjectPtr p;
595 611 PyObject* dict = NULL;
596 612 if (PyModule_Check(object)) {
597 613 dict = PyModule_GetDict(object);
598 614 } else if (PyDict_Check(object)) {
599 615 dict = object;
600 616 }
601 617 if (dict) {
602 618 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
603 619 }
604 620 if (p) {
605 621 result = PythonQtConv::PyObjToQVariant(p);
606 622 } else {
607 623 handleError();
608 624 }
609 625 return result;
610 626 }
611 627
612 628 void PythonQt::evalFile(PyObject* module, const QString& filename)
613 629 {
614 630 PythonQtObjectPtr code = parseFile(filename);
615 631 if (code) {
616 632 evalCode(module, code);
617 633 } else {
618 634 handleError();
619 635 }
620 636 }
621 637
622 638 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
623 639 {
624 640 PythonQtObjectPtr p;
625 641 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
626 642 if (!p) {
627 643 handleError();
628 644 }
629 645 return p;
630 646 }
631 647
632 648 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
633 649 {
634 650 PythonQtObjectPtr code = parseFile(filename);
635 651 PythonQtObjectPtr module = _p->createModule(name, code);
636 652 return module;
637 653 }
638 654
639 655 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
640 656 {
641 657 PyErr_Clear();
642 658 QString scriptCode = script;
643 659 if (scriptCode.isEmpty()) {
644 660 // we always need at least a linefeed
645 661 scriptCode = "\n";
646 662 }
647 663 PythonQtObjectPtr pycode;
648 664 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
649 665 PythonQtObjectPtr module = _p->createModule(name, pycode);
650 666 return module;
651 667 }
652 668
653 669 PythonQtObjectPtr PythonQt::createUniqueModule()
654 670 {
655 671 static QString pyQtStr("PythonQt_module");
656 672 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
657 673 return createModuleFromScript(moduleName);
658 674 }
659 675
660 676 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
661 677 {
662 678 if (PyModule_Check(object)) {
663 679 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
664 680 } else if (PyDict_Check(object)) {
665 681 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
666 682 } else {
667 683 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
668 684 }
669 685 }
670 686
671 687 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
672 688 {
673 689 if (PyModule_Check(object)) {
674 690 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
675 691 } else if (PyDict_Check(object)) {
676 692 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
677 693 } else {
678 694 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
679 695 }
680 696 }
681 697
682 698 void PythonQt::removeVariable(PyObject* object, const QString& name)
683 699 {
684 700 if (PyDict_Check(object)) {
685 701 PyDict_DelItemString(object, name.toLatin1().data());
686 702 } else {
687 703 PyObject_DelAttrString(object, name.toLatin1().data());
688 704 }
689 705 }
690 706
691 707 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
692 708 {
693 709 QVariant result;
694 710 PythonQtObjectPtr obj = lookupObject(object, objectname);
695 711 if (obj) {
696 712 result = PythonQtConv::PyObjToQVariant(obj);
697 713 }
698 714 return result;
699 715 }
700 716
701 717 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
702 718 {
703 719 QStringList results;
704 720
705 721 PythonQtObjectPtr object;
706 722 if (objectname.isEmpty()) {
707 723 object = module;
708 724 } else {
709 725 object = lookupObject(module, objectname);
710 726 if (!object && type == CallOverloads) {
711 727 PyObject* dict = lookupObject(module, "__builtins__");
712 728 if (dict) {
713 729 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
714 730 }
715 731 }
716 732 }
717 733
718 734 if (object) {
719 735 if (type == CallOverloads) {
720 736 if (PythonQtSlotFunction_Check(object)) {
721 737 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
722 738 PythonQtSlotInfo* info = o->m_ml;
723 739
724 740 while (info) {
725 741 results << info->fullSignature();
726 742 info = info->nextInfo();
727 743 }
728 744 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
729 745 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
730 746 PythonQtSlotInfo* info = o->classInfo()->constructors();
731 747
732 748 while (info) {
733 749 results << info->fullSignature();
734 750 info = info->nextInfo();
735 751 }
736 752 } else {
737 753 //TODO: use pydoc!
738 754 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
739 755 if (doc) {
740 756 results << PyString_AsString(doc);
741 757 Py_DECREF(doc);
742 758 }
743 759 }
744 760 } else {
745 761 PyObject* keys = NULL;
746 762 bool isDict = false;
747 763 if (PyDict_Check(object)) {
748 764 keys = PyDict_Keys(object);
749 765 isDict = true;
750 766 } else {
751 767 keys = PyObject_Dir(object);
752 768 }
753 769 if (keys) {
754 770 int count = PyList_Size(keys);
755 771 PyObject* key;
756 772 PyObject* value;
757 773 QString keystr;
758 774 for (int i = 0;i<count;i++) {
759 775 key = PyList_GetItem(keys,i);
760 776 if (isDict) {
761 777 value = PyDict_GetItem(object, key);
762 778 Py_INCREF(value);
763 779 } else {
764 780 value = PyObject_GetAttr(object, key);
765 781 }
766 782 if (!value) continue;
767 783 keystr = PyString_AsString(key);
768 784 static const QString underscoreStr("__tmp");
769 785 if (!keystr.startsWith(underscoreStr)) {
770 786 switch (type) {
771 787 case Anything:
772 788 results << keystr;
773 789 break;
774 790 case Class:
775 791 if (value->ob_type == &PyClass_Type) {
776 792 results << keystr;
777 793 }
778 794 break;
779 795 case Variable:
780 796 if (value->ob_type != &PyClass_Type
781 797 && value->ob_type != &PyCFunction_Type
782 798 && value->ob_type != &PyFunction_Type
783 799 && value->ob_type != &PyModule_Type
784 800 ) {
785 801 results << keystr;
786 802 }
787 803 break;
788 804 case Function:
789 805 if (value->ob_type == &PyFunction_Type ||
790 806 value->ob_type == &PyMethod_Type
791 807 ) {
792 808 results << keystr;
793 809 }
794 810 break;
795 811 case Module:
796 812 if (value->ob_type == &PyModule_Type) {
797 813 results << keystr;
798 814 }
799 815 break;
800 816 default:
801 817 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
802 818 }
803 819 }
804 820 Py_DECREF(value);
805 821 }
806 822 Py_DECREF(keys);
807 823 }
808 824 }
809 825 }
810 826 return results;
811 827 }
812 828
813 829 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
814 830 {
815 831 PythonQtObjectPtr callable = lookupCallable(object, name);
816 832 if (callable) {
817 833 return call(callable, args);
818 834 } else {
819 835 return QVariant();
820 836 }
821 837 }
822 838
823 839 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
824 840 {
825 841 QVariant r;
826 842 if (callable) {
827 843 PythonQtObjectPtr pargs;
828 844 int count = args.size();
829 845 if (count>0) {
830 846 pargs.setNewRef(PyTuple_New(count));
831 847 }
832 848 bool err = false;
833 849 // transform QVariants to Python
834 850 for (int i = 0; i < count; i++) {
835 851 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
836 852 if (arg) {
837 853 // steals reference, no unref
838 854 PyTuple_SetItem(pargs, i,arg);
839 855 } else {
840 856 err = true;
841 857 break;
842 858 }
843 859 }
844 860
845 861 if (!err) {
846 862 PyErr_Clear();
847 863 PythonQtObjectPtr result;
848 864 result.setNewRef(PyObject_CallObject(callable, pargs));
849 865 if (result) {
850 866 // ok
851 867 r = PythonQtConv::PyObjToQVariant(result);
852 868 } else {
853 869 PythonQt::self()->handleError();
854 870 }
855 871 }
856 872 }
857 873 return r;
858 874 }
859 875
860 876 void PythonQt::addInstanceDecorators(QObject* o)
861 877 {
862 878 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
863 879 }
864 880
865 881 void PythonQt::addClassDecorators(QObject* o)
866 882 {
867 883 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
868 884 }
869 885
870 886 void PythonQt::addDecorators(QObject* o)
871 887 {
872 888 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
873 889 }
874 890
875 891 void PythonQt::registerQObjectClassNames(const QStringList& names)
876 892 {
877 893 _p->registerQObjectClassNames(names);
878 894 }
879 895
880 896 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
881 897 {
882 898 PythonQtImport::init();
883 899 _p->_importInterface = importInterface;
884 900 }
885 901
886 902 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
887 903 {
888 904 _p->_importIgnorePaths = paths;
889 905 }
890 906
891 907 const QStringList& PythonQt::getImporterIgnorePaths()
892 908 {
893 909 return _p->_importIgnorePaths;
894 910 }
895 911
896 912 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
897 913 {
898 914 _p->_cppWrapperFactories.append(factory);
899 915 }
900 916
901 917 //---------------------------------------------------------------------------------------------------
902 918 PythonQtPrivate::PythonQtPrivate()
903 919 {
904 920 _importInterface = NULL;
905 921 _defaultImporter = new PythonQtQFileImporter;
906 922 _noLongerWrappedCB = NULL;
907 923 _wrappedCB = NULL;
908 924 _currentClassInfoForClassWrapperCreation = NULL;
909 925 }
910 926
911 927 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
912 928 {
913 929 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
914 930 _currentClassInfoForClassWrapperCreation = NULL;
915 931 return info;
916 932 }
917 933
918 934 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
919 935 {
920 936 o->setParent(this);
921 937 int numMethods = o->metaObject()->methodCount();
922 938 for (int i = 0; i < numMethods; i++) {
923 939 QMetaMethod m = o->metaObject()->method(i);
924 940 if ((m.methodType() == QMetaMethod::Method ||
925 941 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
926 942 if (qstrncmp(m.signature(), "new_", 4)==0) {
927 943 if ((decoTypes & ConstructorDecorator) == 0) continue;
928 944 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
929 945 if (info->parameters().at(0).isPointer) {
930 946 QByteArray signature = m.signature();
931 947 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
932 948 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
933 949 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
934 950 classInfo->addConstructor(newSlot);
935 951 }
936 952 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
937 953 if ((decoTypes & DestructorDecorator) == 0) continue;
938 954 QByteArray signature = m.signature();
939 955 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
940 956 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
941 957 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
942 958 classInfo->setDestructor(newSlot);
943 959 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
944 960 if ((decoTypes & StaticDecorator) == 0) continue;
945 961 QByteArray signature = m.signature();
946 962 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
947 963 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
948 964 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
949 965 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
950 966 classInfo->addDecoratorSlot(newSlot);
951 967 } else {
952 968 if ((decoTypes & InstanceDecorator) == 0) continue;
953 969 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
954 970 if (info->parameters().count()>1) {
955 971 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
956 972 if (p.isPointer) {
957 973 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
958 974 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
959 975 classInfo->addDecoratorSlot(newSlot);
960 976 }
961 977 }
962 978 }
963 979 }
964 980 }
965 981 }
966 982
967 983 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
968 984 {
969 985 foreach(QString name, names) {
970 986 _knownQObjectClassNames.insert(name.toLatin1(), true);
971 987 }
972 988 }
973 989
974 990 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
975 991 {
976 992 _signalReceivers.remove(obj);
977 993 }
978 994
979 995 bool PythonQt::handleError()
980 996 {
981 997 bool flag = false;
982 998 if (PyErr_Occurred()) {
983 999
984 1000 // currently we just print the error and the stderr handler parses the errors
985 1001 PyErr_Print();
986 1002
987 1003 /*
988 1004 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
989 1005 PyObject *ptype;
990 1006 PyObject *pvalue;
991 1007 PyObject *ptraceback;
992 1008 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
993 1009
994 1010 Py_XDECREF(ptype);
995 1011 Py_XDECREF(pvalue);
996 1012 Py_XDECREF(ptraceback);
997 1013 */
998 1014 PyErr_Clear();
999 1015 flag = true;
1000 1016 }
1001 1017 return flag;
1002 1018 }
1003 1019
1004 1020 void PythonQt::addSysPath(const QString& path)
1005 1021 {
1006 1022 PythonQtObjectPtr sys;
1007 1023 sys.setNewRef(PyImport_ImportModule("sys"));
1008 1024 PythonQtObjectPtr obj = lookupObject(sys, "path");
1009 1025 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1010 1026 }
1011 1027
1012 1028 void PythonQt::overwriteSysPath(const QStringList& paths)
1013 1029 {
1014 1030 PythonQtObjectPtr sys;
1015 1031 sys.setNewRef(PyImport_ImportModule("sys"));
1016 1032 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1017 1033 }
1018 1034
1019 1035 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1020 1036 {
1021 1037 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1022 1038 }
1023 1039
1024 1040 void PythonQt::stdOutRedirectCB(const QString& str)
1025 1041 {
1026 1042 emit PythonQt::self()->pythonStdOut(str);
1027 1043 }
1028 1044
1029 1045 void PythonQt::stdErrRedirectCB(const QString& str)
1030 1046 {
1031 1047 emit PythonQt::self()->pythonStdErr(str);
1032 1048 }
1033 1049
1034 1050 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1035 1051 {
1036 1052 _p->_wrappedCB = cb;
1037 1053 }
1038 1054
1039 1055 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1040 1056 {
1041 1057 _p->_noLongerWrappedCB = cb;
1042 1058 }
1043 1059
1044 1060
1045 1061
1046 1062 static PyMethodDef PythonQtMethods[] = {
1047 1063 {NULL, NULL, 0, NULL}
1048 1064 };
1049 1065
1050 1066 void PythonQt::initPythonQtModule(bool redirectStdOut)
1051 1067 {
1052 1068 _p->_pythonQtModule = Py_InitModule("PythonQt", PythonQtMethods);
1053 1069
1054 1070 if (redirectStdOut) {
1055 1071 PythonQtObjectPtr sys;
1056 1072 PythonQtObjectPtr out;
1057 1073 PythonQtObjectPtr err;
1058 1074 sys.setNewRef(PyImport_ImportModule("sys"));
1059 1075 // create a redirection object for stdout and stderr
1060 1076 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1061 1077 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1062 1078 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1063 1079 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1064 1080 // replace the built in file objects with our own objects
1065 1081 PyModule_AddObject(sys, "stdout", out);
1066 1082 PyModule_AddObject(sys, "stderr", err);
1067 1083 }
1068 1084 }
1069 1085
1070 1086 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1071 1087 {
1072 1088 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1073 1089 }
1074 1090
1075 1091
1076 1092 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1077 1093 {
1078 1094 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1079 1095 if (!info) {
1080 1096 info = new PythonQtClassInfo();
1081 1097 info->setupCPPObject(typeName);
1082 1098 _knownClassInfos.insert(typeName, info);
1083 1099 }
1084 1100 return info;
1085 1101 }
1086 1102
1087 1103 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1088 1104 {
1089 1105 _p->addPolymorphicHandler(typeName, cb);
1090 1106 }
1091 1107
1092 1108 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1093 1109 {
1094 1110 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1095 1111 info->addPolymorphicHandler(cb);
1096 1112 }
1097 1113
1098 1114 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1099 1115 {
1100 1116 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1101 1117 }
1102 1118
1103 1119 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1104 1120 {
1105 1121 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1106 1122 if (info) {
1107 1123 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1108 1124 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1109 1125 return true;
1110 1126 } else {
1111 1127 return false;
1112 1128 }
1113 1129 }
1114 1130
1115 1131 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1116 1132 {
1117 1133 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1118 1134 if (!info->pythonQtClassWrapper()) {
1119 1135 info->setupCPPObject(typeName);
1120 1136 createPythonQtClassWrapper(info, package);
1121 1137 }
1122 1138 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1123 1139 addParentClass(typeName, parentTypeName, 0);
1124 1140 }
1125 1141 if (wrapperCreator) {
1126 1142 info->setDecoratorProvider(wrapperCreator);
1127 1143 }
1128 1144 if (shell) {
1129 1145 info->setShellSetInstanceWrapperCB(shell);
1130 1146 }
1131 1147 }
1132 1148
1133 static PyObject *PythonQt_SIGNAL(PyObject * /*type*/, PyObject *args)
1134 {
1135 const char* value;
1136 if (!PyArg_ParseTuple(args, "s", &value)) {
1137 return NULL;
1138 }
1139 // we do not prepend 0,1 or 2, why should we?
1140 return PyString_FromString(QByteArray("2") + value);
1141 }
1142
1143 static PyObject *PythonQt_SLOT(PyObject * /*type*/, PyObject *args)
1144 {
1145 const char* value;
1146 if (!PyArg_ParseTuple(args, "s", &value)) {
1147 return NULL;
1148 }
1149 // we do not prepend 0,1 or 2, why should we?
1150 return PyString_FromString(QByteArray("1") + value);
1151 }
1152
1153 static PyMethodDef PythonQt_Qt_methods[] = {
1154 {"SIGNAL", (PyCFunction)PythonQt_SIGNAL, METH_VARARGS,
1155 "Returns a signal string"
1156 },
1157 {"SLOT", (PyCFunction)PythonQt_SLOT, METH_VARARGS,
1158 "Returns a slot string"
1159 }
1160 };
1161
1162 1149 PyObject* PythonQtPrivate::packageByName(const char* name)
1163 1150 {
1164 1151 if (name==NULL || name[0]==0) {
1165 1152 return _pythonQtModule;
1166 1153 }
1167 1154 PyObject* v = _packages.value(name);
1168 1155 if (!v) {
1169 1156 v = PyImport_AddModule((QByteArray("PythonQt.") + name).constData());
1170 if (strcmp(name,"Qt")==0 || strcmp(name,"QtCore")==0) {
1171 // add SIGNAL and SLOT functions
1172 PyModule_AddObject(v, "SIGNAL", PyCFunction_New(PythonQt_Qt_methods, v));
1173 PyModule_AddObject(v, "SLOT", PyCFunction_New(PythonQt_Qt_methods+1, v));
1174 }
1175 1157 _packages.insert(name, v);
1176 1158 // AddObject steals the reference, so increment it!
1177 1159 Py_INCREF(v);
1178 1160 PyModule_AddObject(_pythonQtModule, name, v);
1179 1161 }
1180 1162 return v;
1181 1163 }
1182 1164
1165 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1166 {
1167 QString error = "Return value '" + PythonQtConv::PyObjGetString(result) + "' can not be converted to expected C++ type '" + methodInfo->parameters().at(0).name + "' as return value of virtual method " + signature;
1168 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1169 PythonQt::self()->handleError();
1170 }
1183 1171
1184 1172 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1185 1173 {
1186 1174 if (_p->_initFlags & ExternalHelp) {
1187 1175 emit pythonHelpRequest(QByteArray(info->className()));
1188 1176 return Py_BuildValue("");
1189 1177 } else {
1190 1178 return PyString_FromString(info->help().toLatin1().data());
1191 1179 }
1192 1180 }
1193 1181
1194 1182 void PythonQtPrivate::removeWrapperPointer(void* obj)
1195 1183 {
1196 1184 _wrappedObjects.remove(obj);
1197 1185 }
1198 1186
1199 1187 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1200 1188 {
1201 1189 _wrappedObjects.insert(obj, wrapper);
1202 1190 }
1203 1191
1204 1192 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1205 1193 {
1206 1194 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1207 1195 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1208 1196 // this is a wrapper whose QObject was already removed due to destruction
1209 1197 // so the obj pointer has to be a new QObject with the same address...
1210 1198 // we remove the old one and set the copy to NULL
1211 1199 wrap->_objPointerCopy = NULL;
1212 1200 removeWrapperPointer(obj);
1213 1201 wrap = NULL;
1214 1202 }
1215 1203 return wrap;
1216 1204 }
1217 1205
1218 1206 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1219 1207 {
1220 1208 PythonQtObjectPtr result;
1221 1209 if (pycode) {
1222 1210 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1223 1211 } else {
1224 1212 PythonQt::self()->handleError();
1225 1213 }
1226 1214 return result;
1227 1215 }
@@ -1,523 +1,526
1 1 #ifndef _PYTHONQT_H
2 2 #define _PYTHONQT_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQt.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46 #include "PythonQtInstanceWrapper.h"
47 47 #include "PythonQtClassWrapper.h"
48 48 #include "PythonQtSlot.h"
49 49 #include "PythonQtObjectPtr.h"
50 50 #include <QObject>
51 51 #include <QVariant>
52 52 #include <QList>
53 53 #include <QHash>
54 54 #include <QByteArray>
55 55 #include <QStringList>
56 56 #include <QtDebug>
57 57 #include <iostream>
58 58
59 59
60 60 class PythonQtClassInfo;
61 61 class PythonQtPrivate;
62 62 class PythonQtMethodInfo;
63 63 class PythonQtSignalReceiver;
64 64 class PythonQtImportFileInterface;
65 65 class PythonQtCppWrapperFactory;
66 66 class PythonQtQFileImporter;
67 67
68 68 typedef void PythonQtQObjectWrappedCB(QObject* object);
69 69 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
70 70 typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, char **class_name);
71 71
72 72 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
73 73
74 74 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) { ((T*)object)->_wrapper = wrapper; };
75 75
76 76 //! returns the offset that needs to be added to upcast an object of type T1 to T2
77 77 template<class T1, class T2> int PythonQtUpcastingOffset() {
78 78 return (((char*)(static_cast<T2*>(reinterpret_cast<T1*>(0x100)))) - ((char*)reinterpret_cast<T1*>(0x100)));
79 79 }
80 80
81 81 //! callback to create a QObject lazily
82 82 typedef QObject* PythonQtQObjectCreatorFunctionCB();
83 83
84 84 //! helper template to create a derived QObject class
85 85 template<class T> QObject* PythonQtCreateObject() { return new T(); };
86 86
87 87 //! the main interface to the Python Qt binding, realized as a singleton
88 88 class PYTHONQT_EXPORT PythonQt : public QObject {
89 89
90 90 Q_OBJECT
91 91
92 92 public:
93 93 enum InitFlags {
94 94 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
95 95 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
96 96 ExternalHelp = 4 //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
97 97 };
98 98
99 99 //! initialize the python qt binding (flags are a or combination of InitFlags)
100 100 static void init(int flags = IgnoreSiteModule | RedirectStdOut);
101 101
102 102 //! cleanup
103 103 static void cleanup();
104 104
105 105 //! get the singleton instance
106 106 static PythonQt* self() { return _self; }
107 107
108 108 //-----------------------------------------------------------------------------
109 109 // Public API:
110 110
111 111 //! defines the object types for introspection
112 112 enum ObjectType {
113 113 Class,
114 114 Function,
115 115 Variable,
116 116 Module,
117 117 Anything,
118 118 CallOverloads
119 119 };
120 120
121 121 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
122 122 void overwriteSysPath(const QStringList& paths);
123 123
124 124 //! prepend a path to sys.path to allow importing from it
125 125 void addSysPath(const QString& path);
126 126
127 127 //! sets the __path__ list of a module to the given list (important for local imports)
128 128 void setModuleImportPath(PyObject* module, const QStringList& paths);
129 129
130 130 //! get the __main__ module of python
131 131 PythonQtObjectPtr getMainModule();
132 132
133 133 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
134 134 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
135 135 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
136 136 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
137 137
138 138 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
139 139 //! (ownership of wrapper is passed to PythonQt)
140 140 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
141 141
142 142 This will add a wrapper object that is used to make calls to the given classname \c typeName.
143 143 All slots that take a pointer to typeName as the first argument will be callable from Python on
144 144 a variant object that contains such a type.
145 145 */
146 146 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
147 147
148 148 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
149 149 //! and it will register the classes when it first sees a pointer to such a derived class
150 150 void registerQObjectClassNames(const QStringList& names);
151 151
152 152 //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance
153 153 //! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that
154 154 //! type is really derived from parentType.
155 155 //! Returns false if the typeName was not yet registered.
156 156 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
157 157
158 158 //! add a handler for polymorphic downcasting
159 159 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
160 160
161 161 //! parses the given file and returns the python code object, this can then be used to call evalCode()
162 162 PythonQtObjectPtr parseFile(const QString& filename);
163 163
164 164 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
165 165 //! If pycode is NULL, a python error is printed.
166 166 QVariant evalCode(PyObject* object, PyObject* pycode);
167 167
168 168 //! evaluates the given script code and returns the result value
169 169 QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input);
170 170
171 171 //! evaluates the given script code from file
172 172 void evalFile(PyObject* object, const QString& filename);
173 173
174 174 //! creates the new module \c name and evaluates the given file in the context of that module
175 175 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
176 176 //! to a module later on.
177 177 //! The user needs to make sure that the \c name is unique in the python module dictionary.
178 178 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
179 179
180 180 //! creates the new module \c name and evaluates the given script in the context of that module.
181 181 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
182 182 //! to a module later on.
183 183 //! The user needs to make sure that the \c name is unique in the python module dictionary.
184 184 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
185 185
186 186 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
187 187 //! script code
188 188 PythonQtObjectPtr createUniqueModule();
189 189
190 190 //@{ Signal handlers
191 191
192 192 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
193 193 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
194 194
195 195 //! remove a signal handler from the given \c signal of \c obj
196 196 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
197 197
198 198 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
199 199 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
200 200
201 201 //! remove a signal handler from the given \c signal of \c obj
202 202 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
203 203
204 204 //@}
205 205
206 206 //@{ Variable access
207 207
208 208 //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable)
209 209 void addObject(PyObject* object, const QString& name, QObject* qObject);
210 210
211 211 //! add the given variable to the object
212 212 void addVariable(PyObject* object, const QString& name, const QVariant& v);
213 213
214 214 //! remove the given variable
215 215 void removeVariable(PyObject* module, const QString& name);
216 216
217 217 //! get the variable with the \c name of the \c object, returns an invalid QVariant on error
218 218 QVariant getVariable(PyObject* object, const QString& name);
219 219
220 220 //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname
221 221 QStringList introspection(PyObject* object, const QString& objectname, ObjectType type);
222 222
223 223 //! returns the found callable object or NULL
224 224 //! @return new reference
225 225 PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
226 226
227 227 //@}
228 228
229 229 //@{ Calling of python callables
230 230
231 231 //! call the given python \c callable in the scope of object, returns the result converted to a QVariant
232 232 QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList());
233 233
234 234 //! call the given python object, returns the result converted to a QVariant
235 235 QVariant call(PyObject* callable, const QVariantList& args = QVariantList());
236 236
237 237 //@}
238 238
239 239 //@{ Decorations, constructors, wrappers...
240 240
241 241
242 242 //! add an object whose slots will be used as decorator slots for
243 243 //! other QObjects or CPP classes. The slots need to follow the
244 244 //! convention that the first argument is a pointer to the wrapped object.
245 245 //! (ownership is passed to PythonQt)
246 246 /*!
247 247 Example:
248 248
249 249 A slot with the signature
250 250
251 251 \code
252 252 bool doSomething(QWidget* w, int a)
253 253 \endcode
254 254
255 255 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
256 256 that will be called with the concrete instance as first argument.
257 257 So in Python you can now e.g. call
258 258
259 259 \code
260 260 someWidget.doSomething(12)
261 261 \endcode
262 262
263 263 without QWidget really having this method. This allows to easily make normal methods
264 264 of Qt classes callable by forwarding them with such decorator slots
265 265 or to make CPP classes (which are not derived from QObject) callable from Python.
266 266 */
267 267 void addInstanceDecorators(QObject* o);
268 268
269 269 //! add an object whose slots will be used as decorator slots for
270 270 //! class objects (ownership is passed to PythonQt)
271 271 /*!
272 272 The slots need to follow the following convention:
273 273 - SomeClass* new_SomeClass(...)
274 274 - QVariant new_SomeClass(...)
275 275 - void delete_SomeClass(SomeClass*)
276 276 - ... static_SomeClass_someName(...)
277 277
278 278 This will add:
279 279 - a constructor
280 280 - a constructor which generates a QVariant
281 281 - a destructor (only useful for CPP objects)
282 282 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
283 283
284 284 */
285 285 void addClassDecorators(QObject* o);
286 286
287 287 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
288 288 void addDecorators(QObject* o);
289 289
290 290 //! add the given factory to PythonQt (ownership stays with caller)
291 291 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
292 292
293 293 //@}
294 294
295 295 //@{ Custom importer (to replace internal import implementation of python)
296 296
297 297 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
298 298 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
299 299 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
300 300 //! This is not reversible, so even setting setImporter(NULL) afterwards will
301 301 //! keep the custom PythonQt importer with a QFile default import interface.
302 302 //! Subsequent python import calls will make use of the passed importInterface
303 303 //! which forwards all import calls to the given \c importInterface.
304 304 //! Passing NULL will install a default QFile importer.
305 305 //! (\c importInterface ownership stays with caller)
306 306 void setImporter(PythonQtImportFileInterface* importInterface);
307 307
308 308 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
309 309 //! (without calling setImporter or installDefaultImporter at least once, the default python import
310 310 //! mechanism is in place)
311 311 //! the default importer allows to import files from anywhere QFile can read from,
312 312 //! including the Qt resource system using ":". Keep in mind that you need to extend
313 313 //! "sys.path" with ":" to be able to import from the Qt resources.
314 314 void installDefaultImporter() { setImporter(NULL); }
315 315
316 316 //! set paths that the importer should ignore
317 317 void setImporterIgnorePaths(const QStringList& paths);
318 318
319 319 //! get paths that the importer should ignore
320 320 const QStringList& getImporterIgnorePaths();
321 321
322 322 //@}
323 323
324 324 //! get access to internal data (should not be used on the public API, but is used by some C functions)
325 325 static PythonQtPrivate* priv() { return _self->_p; }
326 326
327 327 //! get access to the file importer (if set)
328 328 static PythonQtImportFileInterface* importInterface();
329 329
330 330 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
331 331 //! The error is currently just output to the python stderr, future version might implement better trace printing
332 332 bool handleError();
333 333
334 334 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
335 335 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
336 336 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
337 337 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
338 338
339 339 //! call the callback if it is set
340 340 static void qObjectNoLongerWrappedCB(QObject* o);
341 341
342 342 signals:
343 343 //! emitted when python outputs something to stdout (and redirection is turned on)
344 344 void pythonStdOut(const QString& str);
345 345 //! emitted when python outputs something to stderr (and redirection is turned on)
346 346 void pythonStdErr(const QString& str);
347 347
348 348 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
349 349 void pythonHelpRequest(const QByteArray& cppClassName);
350 350
351 351
352 352 public:
353 353 //! called by internal help methods
354 354 PyObject* helpCalled(PythonQtClassInfo* info);
355 355
356 356 //! returns the found object or NULL
357 357 //! @return new reference
358 358 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
359 359
360 360 private:
361 361 void initPythonQtModule(bool redirectStdOut);
362 362
363 363 //! callback for stdout redirection, emits pythonStdOut signal
364 364 static void stdOutRedirectCB(const QString& str);
365 365 //! callback for stderr redirection, emits pythonStdErr signal
366 366 static void stdErrRedirectCB(const QString& str);
367 367
368 368 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
369 369 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
370 370
371 371 PythonQt(int flags);
372 372 ~PythonQt();
373 373
374 374 static PythonQt* _self;
375 375 static int _uniqueModuleCount;
376 376
377 377 PythonQtPrivate* _p;
378 378
379 379 };
380 380
381 381 //! internal PythonQt details
382 382 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
383 383
384 384 Q_OBJECT
385 385
386 386 public:
387 387 PythonQtPrivate();
388 388 ~PythonQtPrivate();
389 389
390 390 enum DecoratorTypes {
391 391 StaticDecorator = 1,
392 392 ConstructorDecorator = 2,
393 393 DestructorDecorator = 4,
394 394 InstanceDecorator = 8,
395 395 AllDecorators = 0xffff
396 396 };
397 397
398 398 //! returns if the id is the id for PythonQtObjectPtr
399 399 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
400 400
401 401 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
402 402 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
403 403 //! remove the wrapper ptr again
404 404 void removeWrapperPointer(void* obj);
405 405
406 406 //! add parent class relation
407 407 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
408 408
409 409 //! add a handler for polymorphic downcasting
410 410 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
411 411
412 412 //! lookup existing classinfo and return new if not yet present
413 413 PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
414 414
415 415 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
416 416 void removeSignalEmitter(QObject* obj);
417 417
418 418 //! wrap the given QObject into a Python object (or return existing wrapper!)
419 419 PyObject* wrapQObject(QObject* obj);
420 420
421 421 //! wrap the given ptr into a Python object (or return existing wrapper!) if there is a known QObject of that name or a known wrapper in the factory
422 422 PyObject* wrapPtr(void* ptr, const QByteArray& name);
423 423
424 424 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
425 425 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
426 426 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
427 427 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
428 428
429 429 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
430 430 //! (ownership of wrapper is passed to PythonQt)
431 431 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
432 432
433 433 This will add a wrapper object that is used to make calls to the given classname \c typeName.
434 434 All slots that take a pointer to typeName as the first argument will be callable from Python on
435 435 a variant object that contains such a type.
436 436 */
437 437 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
438 438
439 439 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
440 440 //! and it will register the classes when it first sees a pointer to such a derived class
441 441 void registerQObjectClassNames(const QStringList& names);
442 442
443 443 //! add a decorator object
444 444 void addDecorators(QObject* o, int decoTypes);
445 445
446 446 //! helper method that creates a PythonQtClassWrapper object (returns a new reference)
447 447 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package = NULL);
448 448
449 449 //! create a new instance of the given enum type with given value (returns a new reference)
450 450 static PyObject* createEnumValueInstance(PyObject* enumType, unsigned int enumValue);
451 451
452 452 //! helper that creates a new int derived class that represents the enum of the given name (returns a new reference)
453 453 static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
454 454
455 455 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
456 456 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
457 457
458 458 //! get the class info for a meta object (if available)
459 459 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
460 460
461 461 //! get the class info for a meta object (if available)
462 462 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
463 463
464 464 //! creates the new module from the given pycode
465 465 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
466 466
467 467 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
468 468 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
469 469
470 470 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
471 471 static PyObject* dummyTuple();
472 472
473 //! called by virtual overloads when a python return value can not be converted to the required Qt type
474 void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result);
475
473 476 private:
474 477
475 478 //! create a new pythonqt class wrapper and place it in the pythonqt module
476 479 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package);
477 480
478 481 //! get/create new package module (the returned object is a borrowed reference)
479 482 PyObject* packageByName(const char* name);
480 483
481 484 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
482 485 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
483 486
484 487 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
485 488 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
486 489
487 490 //! stores the meta info of known Qt classes
488 491 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
489 492
490 493 //! names of qobject derived classes that can be casted to qobject savely
491 494 QHash<QByteArray, bool> _knownQObjectClassNames;
492 495
493 496 //! stores signal receivers for QObjects
494 497 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
495 498
496 499 //! the PythonQt python module
497 500 PythonQtObjectPtr _pythonQtModule;
498 501
499 502 //! the importer interface (if set)
500 503 PythonQtImportFileInterface* _importInterface;
501 504
502 505 //! the default importer
503 506 PythonQtQFileImporter* _defaultImporter;
504 507
505 508 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
506 509 PythonQtQObjectWrappedCB* _wrappedCB;
507 510
508 511 QStringList _importIgnorePaths;
509 512
510 513 //! the cpp object wrapper factories
511 514 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
512 515
513 516 QHash<QByteArray, PyObject*> _packages;
514 517
515 518 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
516 519
517 520 int _initFlags;
518 521 int _PythonQtObjectPtr_metaId;
519 522
520 523 friend class PythonQt;
521 524 };
522 525
523 526 #endif
@@ -1,826 +1,841
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtClassInfo.h"
43 43 #include "PythonQtMethodInfo.h"
44 44 #include "PythonQt.h"
45 45 #include <QMetaMethod>
46 46 #include <QMetaObject>
47 47 #include <QMetaEnum>
48 48
49 49 QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;
50 50
51 51 PythonQtClassInfo::PythonQtClassInfo() {
52 52 _meta = NULL;
53 53 _constructors = NULL;
54 54 _destructor = NULL;
55 55 _decoratorProvider = NULL;
56 56 _decoratorProviderCB = NULL;
57 57 _pythonQtClassWrapper = NULL;
58 58 _shellSetInstanceWrapperCB = NULL;
59 59 _metaTypeId = -1;
60 60 _isQObject = false;
61 61 _enumsCreated = false;
62 62 }
63 63
64 64 PythonQtClassInfo::~PythonQtClassInfo()
65 65 {
66 66 clearCachedMembers();
67 67
68 68 if (_constructors) {
69 69 _constructors->deleteOverloadsAndThis();
70 70 }
71 71 if (_destructor) {
72 72 _destructor->deleteOverloadsAndThis();
73 73 }
74 74 foreach(PythonQtSlotInfo* info, _decoratorSlots) {
75 75 info->deleteOverloadsAndThis();
76 76 }
77 77 }
78 78
79 79 void PythonQtClassInfo::setupQObject(const QMetaObject* meta)
80 80 {
81 81 // _wrappedClassName is already set earlier in the class setup
82 82 _isQObject = true;
83 83 _meta = meta;
84 84 }
85 85
86 86 void PythonQtClassInfo::setupCPPObject(const QByteArray& classname)
87 87 {
88 88 _isQObject = false;
89 89 _wrappedClassName = classname;
90 90 _metaTypeId = QMetaType::type(classname);
91 91 }
92 92
93 93 void PythonQtClassInfo::clearCachedMembers()
94 94 {
95 95 QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers);
96 96 while (i.hasNext()) {
97 97 PythonQtMemberInfo member = i.next().value();
98 98 if (member._type== PythonQtMemberInfo::Slot) {
99 99 PythonQtSlotInfo* info = member._slot;
100 100 while (info) {
101 101 PythonQtSlotInfo* next = info->nextInfo();
102 102 delete info;
103 103 info = next;
104 104 }
105 105 }
106 106 }
107 107 }
108 108
109 109 int PythonQtClassInfo::findCharOffset(const char* sigStart, char someChar)
110 110 {
111 111 const char* sigEnd = sigStart;
112 112 char c;
113 113 do {
114 114 c = *sigEnd++;
115 115 } while (c!=someChar && c!=0);
116 116 return sigEnd-sigStart-1;
117 117 }
118 118
119 119 bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName)
120 120 {
121 121 bool found = false;
122 122 bool nameMapped = false;
123 123 const char* attributeName = memberName;
124 124 // look for properties
125 125 int i = _meta->indexOfProperty(attributeName);
126 126 if (i==-1) {
127 127 // try to map name to objectName
128 128 if (qstrcmp(attributeName, "name")==0) {
129 129 attributeName = "objectName";
130 130 nameMapped = true;
131 131 i = _meta->indexOfProperty(attributeName);
132 132 }
133 133 }
134 134 if (i!=-1) {
135 135 PythonQtMemberInfo newInfo(_meta->property(i));
136 136 _cachedMembers.insert(attributeName, newInfo);
137 137 if (nameMapped) {
138 138 _cachedMembers.insert(memberName, newInfo);
139 139 }
140 140 #ifdef PYTHONQT_DEBUG
141 141 std::cout << "caching property " << memberName << " on " << _meta->className() << std::endl;
142 142 #endif
143 143 found = true;
144 144 }
145 145 return found;
146 146 }
147 147
148 148 PythonQtSlotInfo* PythonQtClassInfo::recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
149 149 {
150 150 inputInfo = findDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset);
151 151 foreach(const ParentClassInfo& info, _parentClasses) {
152 152 inputInfo = info._parent->recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset+info._upcastingOffset);
153 153 }
154 154 return inputInfo;
155 155 }
156 156
157 157 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset) {
158 158 QObject* decoratorProvider = decorator();
159 159 int memberNameLen = strlen(memberName);
160 160 if (decoratorProvider) {
161 161 //qDebug()<< "looking " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
162 162 const QMetaObject* meta = decoratorProvider->metaObject();
163 163 int numMethods = meta->methodCount();
164 164 int startFrom = QObject::staticMetaObject.methodCount();
165 165 for (int i = startFrom; i < numMethods; i++) {
166 166 QMetaMethod m = meta->method(i);
167 167 if ((m.methodType() == QMetaMethod::Method ||
168 168 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
169 169
170 170 const char* sigStart = m.signature();
171 171 bool isClassDeco = false;
172 172 if (qstrncmp(sigStart, "static_", 7)==0) {
173 173 // skip the static_classname_ part of the string
174 174 sigStart += 7 + 1 + strlen(className());
175 175 isClassDeco = true;
176 176 } else if (qstrncmp(sigStart, "new_", 4)==0) {
177 177 isClassDeco = true;
178 178 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
179 179 isClassDeco = true;
180 180 }
181 181 // find the first '('
182 182 int offset = findCharOffset(sigStart, '(');
183 183
184 184 // XXX no checking is currently done if the slots have correct first argument or not...
185 185
186 186 // check if same length and same name
187 187 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
188 188 found = true;
189 189 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i, decoratorProvider, isClassDeco?PythonQtSlotInfo::ClassDecorator:PythonQtSlotInfo::InstanceDecorator);
190 190 info->setUpcastingOffset(upcastingOffset);
191 191 //qDebug()<< "adding " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
192 192 if (tail) {
193 193 tail->setNextInfo(info);
194 194 } else {
195 195 PythonQtMemberInfo newInfo(info);
196 196 memberCache.insert(memberName, newInfo);
197 197 }
198 198 tail = info;
199 199 }
200 200 }
201 201 }
202 202 }
203 203
204 204 tail = findDecoratorSlots(memberName, memberNameLen, tail, found, memberCache, upcastingOffset);
205 205
206 206 return tail;
207 207 }
208 208
209 209 bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName)
210 210 {
211 211 bool found = false;
212 212 int memberNameLen = strlen(memberName);
213 213 PythonQtSlotInfo* tail = NULL;
214 214 if (_meta) {
215 215 int numMethods = _meta->methodCount();
216 216 for (int i = 0; i < numMethods; i++) {
217 217 QMetaMethod m = _meta->method(i);
218 218 if ((m.methodType() == QMetaMethod::Method ||
219 219 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
220 220
221 221 const char* sigStart = m.signature();
222 222 // find the first '('
223 223 int offset = findCharOffset(sigStart, '(');
224 224
225 225 // check if same length and same name
226 226 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
227 227 found = true;
228 228 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i);
229 229 if (tail) {
230 230 tail->setNextInfo(info);
231 231 } else {
232 232 PythonQtMemberInfo newInfo(info);
233 233 _cachedMembers.insert(memberName, newInfo);
234 234 }
235 235 tail = info;
236 236 }
237 237 }
238 238 }
239 239 }
240 240
241 241 // look for dynamic decorators in this class and in derived classes
242 242 tail = recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, tail, found, _cachedMembers, 0);
243 243
244 244 return found;
245 245 }
246 246
247 247 bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* memberName)
248 248 {
249 249 bool found = false;
250 250 // look for enum values
251 251 int enumCount = meta->enumeratorCount();
252 252 for (int i=0;i<enumCount; i++) {
253 253 QMetaEnum e = meta->enumerator(i);
254 254 // we do not want flags, they will cause our values to appear two times
255 255 if (e.isFlag()) continue;
256 256
257 257 for (int j=0; j < e.keyCount(); j++) {
258 258 if (qstrcmp(e.key(j), memberName)==0) {
259 259 PyObject* enumType = findEnumWrapper(e.name());
260 260 if (enumType) {
261 261 PythonQtObjectPtr enumValuePtr;
262 262 enumValuePtr.setNewRef(PythonQtPrivate::createEnumValueInstance(enumType, e.value(j)));
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 // maybe it is an enum wrapper?
311 312 PyObject* p = findEnumWrapper(memberName);
312 313 if (p) {
313 314 info._type = PythonQtMemberInfo::EnumWrapper;
314 315 info._enumWrapper = p;
315 316 _cachedMembers.insert(memberName, info);
316 317 found = true;
317 318 }
318 319 }
319 320 if (!found) {
321 // since python keywords can not be looked up, we check if the name contains a single trailing _
322 // and remove that and look again, so that we e.g. find exec on an exec_ lookup
323 QByteArray mbrName(memberName);
324 if ((mbrName.length()>2) &&
325 (mbrName.at(mbrName.length()-1) == '_') &&
326 (mbrName.at(mbrName.length()-2) != '_')) {
327 mbrName = mbrName.mid(0,mbrName.length()-1);
328 found = lookForMethodAndCache(mbrName.constData());
329 if (found) {
330 return _cachedMembers.value(mbrName);
331 }
332 }
333 }
334 if (!found) {
320 335 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
321 336 info._type = PythonQtMemberInfo::NotFound;
322 337 _cachedMembers.insert(memberName, info);
323 338 }
324 339 }
325 340
326 341 return _cachedMembers.value(memberName);
327 342 }
328 343
329 344 void PythonQtClassInfo::recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects) {
330 345 QObject* deco = decorator();
331 346 if (deco) {
332 347 decoratorObjects.append(deco);
333 348 }
334 349 foreach(const ParentClassInfo& info, _parentClasses) {
335 350 info._parent->recursiveCollectDecoratorObjects(decoratorObjects);
336 351 }
337 352 }
338 353
339 354 void PythonQtClassInfo::recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects) {
340 355 classInfoObjects.append(this);
341 356 foreach(const ParentClassInfo& info, _parentClasses) {
342 357 info._parent->recursiveCollectClassInfos(classInfoObjects);
343 358 }
344 359 }
345 360
346 361 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
347 362 {
348 363 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
349 364 while (it.hasNext()) {
350 365
351 366 PythonQtSlotInfo* infoOrig = it.next();
352 367
353 368 const char* sigStart = infoOrig->metaMethod()->signature();
354 369 if (qstrncmp("static_", sigStart, 7)==0) {
355 370 sigStart += 7;
356 371 sigStart += findCharOffset(sigStart, '_')+1;
357 372 }
358 373 int offset = findCharOffset(sigStart, '(');
359 374 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
360 375 //make a copy, otherwise we will have trouble on overloads!
361 376 PythonQtSlotInfo* info = new PythonQtSlotInfo(*infoOrig);
362 377 info->setUpcastingOffset(upcastingOffset);
363 378 found = true;
364 379 if (tail) {
365 380 tail->setNextInfo(info);
366 381 } else {
367 382 PythonQtMemberInfo newInfo(info);
368 383 memberCache.insert(memberName, newInfo);
369 384 }
370 385 tail = info;
371 386 }
372 387 }
373 388 return tail;
374 389 }
375 390
376 391 void PythonQtClassInfo::listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly) {
377 392 QObject* decoratorProvider = decorator();
378 393 if (decoratorProvider) {
379 394 const QMetaObject* meta = decoratorProvider->metaObject();
380 395 int numMethods = meta->methodCount();
381 396 int startFrom = QObject::staticMetaObject.methodCount();
382 397 for (int i = startFrom; i < numMethods; i++) {
383 398 QMetaMethod m = meta->method(i);
384 399 if ((m.methodType() == QMetaMethod::Method ||
385 400 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
386 401
387 402 const char* sigStart = m.signature();
388 403 bool isClassDeco = false;
389 404 if (qstrncmp(sigStart, "static_", 7)==0) {
390 405 // skip the static_classname_ part of the string
391 406 sigStart += 7 + 1 + strlen(className());
392 407 isClassDeco = true;
393 408 } else if (qstrncmp(sigStart, "new_", 4)==0) {
394 409 continue;
395 410 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
396 411 continue;
397 412 }
398 413 // find the first '('
399 414 int offset = findCharOffset(sigStart, '(');
400 415
401 416 // XXX no checking is currently done if the slots have correct first argument or not...
402 417 if (!metaOnly || isClassDeco) {
403 418 list << QString::fromLatin1(sigStart, offset);
404 419 }
405 420 }
406 421 }
407 422 }
408 423
409 424 // look for global decorator slots
410 425 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
411 426 while (it.hasNext()) {
412 427 PythonQtSlotInfo* slot = it.next();
413 428 if (metaOnly) {
414 429 if (slot->isClassDecorator()) {
415 430 QByteArray first = slot->slotName();
416 431 if (first.startsWith("static_")) {
417 432 int idx = first.indexOf('_');
418 433 idx = first.indexOf('_', idx+1);
419 434 first = first.mid(idx+1);
420 435 }
421 436 list << first;
422 437 }
423 438 } else {
424 439 list << slot->slotName();
425 440 }
426 441 }
427 442 }
428 443
429 444 QStringList PythonQtClassInfo::propertyList()
430 445 {
431 446 QStringList l;
432 447 if (_isQObject && _meta) {
433 448 int i;
434 449 int numProperties = _meta->propertyCount();
435 450 for (i = 0; i < numProperties; i++) {
436 451 QMetaProperty p = _meta->property(i);
437 452 l << QString(p.name());
438 453 }
439 454 }
440 455 return l;
441 456 }
442 457
443 458 QStringList PythonQtClassInfo::memberList(bool metaOnly)
444 459 {
445 460 decorator();
446 461
447 462 QStringList l;
448 463 QString h;
449 464 if (_isQObject && _meta && !metaOnly) {
450 465 l = propertyList();
451 466 }
452 467
453 468 // normal slots of QObject (or wrapper QObject)
454 469 if (!metaOnly && _meta) {
455 470 int numMethods = _meta->methodCount();
456 471 bool skipQObj = !_isQObject;
457 472 for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) {
458 473 QMetaMethod m = _meta->method(i);
459 474 if ((m.methodType() == QMetaMethod::Method ||
460 475 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
461 476 QByteArray signa(m.signature());
462 477 signa = signa.left(signa.indexOf('('));
463 478 l << signa;
464 479 }
465 480 }
466 481 }
467 482
468 483 {
469 484 // look for dynamic decorators in this class and in derived classes
470 485 QList<PythonQtClassInfo*> infos;
471 486 recursiveCollectClassInfos(infos);
472 487 foreach(PythonQtClassInfo* info, infos) {
473 488 info->listDecoratorSlotsFromDecoratorProvider(l, metaOnly);
474 489 }
475 490 }
476 491
477 492 // List enumerator keys...
478 493 QList<const QMetaObject*> enumMetaObjects;
479 494 if (_meta) {
480 495 enumMetaObjects << _meta;
481 496 }
482 497 // check enums in the class hierachy of CPP classes
483 498 QList<QObject*> decoObjects;
484 499 recursiveCollectDecoratorObjects(decoObjects);
485 500 foreach(QObject* deco, decoObjects) {
486 501 enumMetaObjects << deco->metaObject();
487 502 }
488 503
489 504 foreach(const QMetaObject* meta, enumMetaObjects) {
490 505 for (int i = 0; i<meta->enumeratorCount(); i++) {
491 506 QMetaEnum e = meta->enumerator(i);
492 507 l << e.name();
493 508 // we do not want flags, they will cause our values to appear two times
494 509 if (e.isFlag()) continue;
495 510
496 511 for (int j=0; j < e.keyCount(); j++) {
497 512 l << QString(e.key(j));
498 513 }
499 514 }
500 515 }
501 516
502 517 return QSet<QString>::fromList(l).toList();
503 518 }
504 519
505 520 const char* PythonQtClassInfo::className()
506 521 {
507 522 return _wrappedClassName.constData();
508 523 }
509 524
510 525 void* PythonQtClassInfo::castTo(void* ptr, const char* classname)
511 526 {
512 527 if (ptr==NULL) {
513 528 return NULL;
514 529 }
515 530 if (_wrappedClassName == classname) {
516 531 return ptr;
517 532 }
518 533 foreach(const ParentClassInfo& info, _parentClasses) {
519 534 void* result = info._parent->castTo((char*)ptr + info._upcastingOffset, classname);
520 535 if (result) {
521 536 return result;
522 537 }
523 538 }
524 539 return NULL;
525 540 }
526 541
527 542 bool PythonQtClassInfo::inherits(const char* name)
528 543 {
529 544 if (_wrappedClassName == name) {
530 545 return true;
531 546 }
532 547 foreach(const ParentClassInfo& info, _parentClasses) {
533 548 if (info._parent->inherits(name)) {
534 549 return true;
535 550 }
536 551 }
537 552 return false;
538 553 }
539 554
540 555 bool PythonQtClassInfo::inherits(PythonQtClassInfo* classInfo)
541 556 {
542 557 if (classInfo == this) {
543 558 return true;
544 559 }
545 560 foreach(const ParentClassInfo& info, _parentClasses) {
546 561 if (info._parent->inherits(classInfo)) {
547 562 return true;
548 563 }
549 564 }
550 565 return false;
551 566 }
552 567
553 568 QString PythonQtClassInfo::help()
554 569 {
555 570 decorator();
556 571 QString h;
557 572 h += QString("--- ") + QString(className()) + QString(" ---\n");
558 573
559 574 if (_isQObject) {
560 575 h += "Properties:\n";
561 576
562 577 int i;
563 578 int numProperties = _meta->propertyCount();
564 579 for (i = 0; i < numProperties; i++) {
565 580 QMetaProperty p = _meta->property(i);
566 581 h += QString(p.name()) + " (" + QString(p.typeName()) + " )\n";
567 582 }
568 583 }
569 584
570 585 if (constructors()) {
571 586 h += "Constructors:\n";
572 587 PythonQtSlotInfo* constr = constructors();
573 588 while (constr) {
574 589 h += constr->fullSignature() + "\n";
575 590 constr = constr->nextInfo();
576 591 }
577 592 }
578 593
579 594 h += "Slots:\n";
580 595 h += "QString help()\n";
581 596 h += "QString className()\n";
582 597
583 598 if (_meta) {
584 599 int numMethods = _meta->methodCount();
585 600 for (int i = 0; i < numMethods; i++) {
586 601 QMetaMethod m = _meta->method(i);
587 602 if ((m.methodType() == QMetaMethod::Method ||
588 603 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
589 604 PythonQtSlotInfo slot(this, m, i);
590 605 h += slot.fullSignature()+ "\n";
591 606 }
592 607 }
593 608 }
594 609
595 610 // TODO xxx : decorators and enums from decorator() are missing...
596 611 // maybe we can reuse memberlist()?
597 612
598 613 if (_meta && _meta->enumeratorCount()) {
599 614 h += "Enums:\n";
600 615 for (int i = 0; i<_meta->enumeratorCount(); i++) {
601 616 QMetaEnum e = _meta->enumerator(i);
602 617 h += QString(e.name()) + " {";
603 618 for (int j=0; j < e.keyCount(); j++) {
604 619 if (j) { h+= ", "; }
605 620 h += e.key(j);
606 621 }
607 622 h += " }\n";
608 623 }
609 624 }
610 625
611 626 if (_isQObject && _meta) {
612 627 int numMethods = _meta->methodCount();
613 628 if (numMethods>0) {
614 629 h += "Signals:\n";
615 630 for (int i = 0; i < numMethods; i++) {
616 631 QMetaMethod m = _meta->method(i);
617 632 if (m.methodType() == QMetaMethod::Signal) {
618 633 h += QString(m.signature()) + "\n";
619 634 }
620 635 }
621 636 }
622 637 }
623 638 return h;
624 639 }
625 640
626 641 PythonQtSlotInfo* PythonQtClassInfo::constructors()
627 642 {
628 643 if (!_constructors) {
629 644 // force creation of lazy decorator, which will register the decorators
630 645 decorator();
631 646 }
632 647 return _constructors;
633 648 }
634 649
635 650 PythonQtSlotInfo* PythonQtClassInfo::destructor()
636 651 {
637 652 if (!_destructor) {
638 653 // force creation of lazy decorator, which will register the decorators
639 654 decorator();
640 655 }
641 656 return _destructor;
642 657 }
643 658
644 659 void PythonQtClassInfo::addConstructor(PythonQtSlotInfo* info)
645 660 {
646 661 PythonQtSlotInfo* prev = constructors();
647 662 if (prev) {
648 663 info->setNextInfo(prev->nextInfo());
649 664 prev->setNextInfo(info);
650 665 } else {
651 666 _constructors = info;
652 667 }
653 668 }
654 669
655 670 void PythonQtClassInfo::addDecoratorSlot(PythonQtSlotInfo* info)
656 671 {
657 672 _decoratorSlots.append(info);
658 673 }
659 674
660 675 void PythonQtClassInfo::setDestructor(PythonQtSlotInfo* info)
661 676 {
662 677 if (_destructor) {
663 678 _destructor->deleteOverloadsAndThis();
664 679 }
665 680 _destructor = info;
666 681 }
667 682
668 683 void PythonQtClassInfo::setMetaObject(const QMetaObject* meta)
669 684 {
670 685 _meta = meta;
671 686 clearCachedMembers();
672 687 }
673 688
674 689 QObject* PythonQtClassInfo::decorator()
675 690 {
676 691 if (!_decoratorProvider && _decoratorProviderCB) {
677 692 _decoratorProvider = (*_decoratorProviderCB)();
678 693 if (_decoratorProvider) {
679 694 _decoratorProvider->setParent(PythonQt::priv());
680 695 // setup enums early, since they might be needed by the constructor decorators:
681 696 if (!_enumsCreated) {
682 697 createEnumWrappers();
683 698 }
684 699 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
685 700 }
686 701 }
687 702 // check if enums need to be created and create them if they are not yet created
688 703 if (!_enumsCreated) {
689 704 createEnumWrappers();
690 705 }
691 706 return _decoratorProvider;
692 707 }
693 708
694 709 bool PythonQtClassInfo::hasOwnerMethodButNoOwner(void* object)
695 710 {
696 711 PythonQtMemberInfo info = member("hasOwner");
697 712 if (info._type == PythonQtMemberInfo::Slot) {
698 713 void* obj = object;
699 714 bool result = false;
700 715 void* args[2];
701 716 args[0] = &result;
702 717 args[1] = &obj;
703 718 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
704 719 return !result;
705 720 } else {
706 721 return false;
707 722 }
708 723 }
709 724
710 725 void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, char** resultClassName)
711 726 {
712 727 if (!_polymorphicHandlers.isEmpty()) {
713 728 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
714 729 void* resultPtr = (*cb)(ptr, resultClassName);
715 730 if (resultPtr) {
716 731 return resultPtr;
717 732 }
718 733 }
719 734 }
720 735 foreach(const ParentClassInfo& info, _parentClasses) {
721 736 if (!info._parent->isQObject()) {
722 737 void* resultPtr = info._parent->recursiveCastDownIfPossible((char*)ptr + info._upcastingOffset, resultClassName);
723 738 if (resultPtr) {
724 739 return resultPtr;
725 740 }
726 741 }
727 742 }
728 743 return NULL;
729 744 }
730 745
731 746 void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo)
732 747 {
733 748 char* className;
734 749 // this would do downcasting recursively...
735 750 // void* resultPtr = recursiveCastDownIfPossible(ptr, &className);
736 751
737 752 // we only do downcasting on the base object, not on the whole inheritance tree...
738 753 void* resultPtr = NULL;
739 754 if (!_polymorphicHandlers.isEmpty()) {
740 755 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
741 756 resultPtr = (*cb)(ptr, &className);
742 757 if (resultPtr) {
743 758 break;
744 759 }
745 760 }
746 761 }
747 762 if (resultPtr) {
748 763 *resultClassInfo = PythonQt::priv()->getClassInfo(className);
749 764 } else {
750 765 *resultClassInfo = this;
751 766 resultPtr = ptr;
752 767 }
753 768 return resultPtr;
754 769 }
755 770
756 771 PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum)
757 772 {
758 773 if (isLocalEnum) {
759 774 *isLocalEnum = true;
760 775 }
761 776 int scopePos = name.lastIndexOf("::");
762 777 if (scopePos != -1) {
763 778 if (isLocalEnum) {
764 779 *isLocalEnum = false;
765 780 }
766 781 // split into scope and enum name
767 782 QByteArray enumScope = name.mid(0,scopePos);
768 783 QByteArray enumName = name.mid(scopePos+2);
769 784 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(enumScope);
770 785 if (info) {
771 786 return info->findEnumWrapper(enumName);
772 787 } else{
773 788 return NULL;
774 789 }
775 790 }
776 791 if (localScope) {
777 792 return localScope->findEnumWrapper(name);
778 793 } else {
779 794 return NULL;
780 795 }
781 796 }
782 797
783 798 void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta)
784 799 {
785 800 for (int i = meta->enumeratorOffset();i<meta->enumeratorCount();i++) {
786 801 QMetaEnum e = meta->enumerator(i);
787 802 PythonQtObjectPtr p;
788 803 p.setNewRef(PythonQtPrivate::createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper));
789 804 _enumWrappers.append(p);
790 805 }
791 806 }
792 807
793 808 void PythonQtClassInfo::createEnumWrappers()
794 809 {
795 810 if (!_enumsCreated) {
796 811 _enumsCreated = true;
797 812 if (_meta) {
798 813 createEnumWrappers(_meta);
799 814 }
800 815 if (decorator()) {
801 816 createEnumWrappers(decorator()->metaObject());
802 817 }
803 818 foreach(const ParentClassInfo& info, _parentClasses) {
804 819 info._parent->createEnumWrappers();
805 820 }
806 821 }
807 822 }
808 823
809 824 PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) {
810 825 // force enum creation
811 826 if (!_enumsCreated) {
812 827 createEnumWrappers();
813 828 }
814 829 foreach(const PythonQtObjectPtr& p, _enumWrappers) {
815 830 const char* className = ((PyTypeObject*)p.object())->tp_name;
816 831 if (qstrcmp(className, name)==0) {
817 832 return p.object();
818 833 }
819 834 }
820 835 foreach(const ParentClassInfo& info, _parentClasses) {
821 836 PyObject* p = info._parent->findEnumWrapper(name);
822 837 if (p) return p;
823 838 }
824 839 return NULL;
825 840 }
826 841
@@ -1,510 +1,510
1 1 #ifndef _PYTHONQTDOC_H
2 2 #define _PYTHONQTDOC_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 PythonQtDoc.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-10
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 /*!
46 46 \if USE_GLOBAL_DOXYGEN_DOC
47 47 \page PythonQtPage PythonQt Overview
48 48 \else
49 49 \mainpage PythonQt Overview
50 50 \endif
51 51
52 52 \section Introduction
53 53
54 54 \b PythonQt is a dynamic Python (http://www.python.org) binding for Qt (http://www.qtsoftware.com).
55 55 It offers an easy way to embed the Python scripting language into
56 56 your Qt applications. It makes heavy use of the QMetaObject system and thus requires Qt4.x.
57 57
58 58 The focus of PythonQt is on embedding Python into an existing C++ application, not on writing the whole
59 59 application completely in Python. If you want to write your whole application in Python,
60 60 you should use <a href="http://www.riverbankcomputing.co.uk/pyqt/">PyQt</a> instead.
61 61
62 62 If you are looking for a simple way to embed Python objects into your C++/Qt Application
63 63 and to script parts of your application via Python, PythonQt is the way to go!
64 64
65 65 PythonQt is a stable library that was developed to make the
66 66 Image Processing and Visualization platform MeVisLab (http://www.mevislab.de)
67 67 scriptable from Python.
68 68
69 69 \section Download
70 70
71 71 PythonQt is hosted on SourceForge at http://sourceforge.net/projects/pythonqt , you can access it via SVN
72 72 or download a tarball.
73 73
74 74 \section Licensing
75 75
76 76 PythonQt is distributed under the LGPL license, so it pairs well with the LGPL of the Qt 4.5 release and allows
77 77 to be used in commercial applications when following the LGPL 2.1 obligations.
78 78
79 79 \section LicensingWrapper Licensing of Wrapper Generator
80 80
81 81 The build system of PythonQt makes use of a modified version of the GPL'ed QtScript generator,
82 82 located in the "generator" directory.
83 83
84 84 See http://labs.trolltech.com/page/Projects/QtScript/Generator for details on the original project.
85 85 Thanks a lot to the QtJambi guys and the QtScript Generator project for the C++ parser and
86 86 Qt typesystem files!
87 87
88 88 The PythonQt wrappers generated by the generator located in the "generated_cpp" directory are distributed under the LGPL,
89 89 they are not restriced by the GPL.
90 90
91 91 The generated wrappers are pre-generated and checked-in for Qt 4.4.3, so you only need to build and run the
92 92 generator when you want to build additional wrappers or you want to upgrade/downgrade to an newer Qt version.
93 93 You may use the generator to generate C++ bindings for your own C++ classes (e.g. to make them deriveable in Python),
94 94 , but this is currently not documented and involves creating your own typesystem files.
95 95
96 96 \section Features
97 97
98 98 The following are the built-in features of the PythonQt library:
99 99
100 100 - Access all \b slots, \b properties, children and registered enums of any QObject derived class from Python
101 101 - Connecting Qt Signals to Python functions (both from within Python and from C++)
102 102 - Easy wrapping of Python objects from C++ with smart, reference-counting PythonQtObjectPtr.
103 103 - Convenient conversions to/from QVariant for PythonQtObjectPtr.
104 104 - Wrapping of C++ objects (which are not derived from QObject) via PythonQtCppWrapperFactory
105 105 - Extending C++ and QObject derived classes with additional slots, static methods and constructors (see Decorators)
106 106 - StdOut/Err redirection to Qt signals instead of cout
107 107 - Interface for creating your own \c import replacement, so that Python scripts can be e.g. signed/verified before they are executed (PythonQtImportFileInterface)
108 108 - Mapping of plain-old-datatypes and ALL QVariant types to and from Python
109 109 - Support for wrapping of user QVariant types which are registerd via QMetaType
110 110 - Support for Qt namespace (with all enumerators)
111 111 - All PythonQt wrapped objects support the dir() statement, so that you can see easily which attributes a QObject, CPP object or QVariant has
112 112 - No preprocessing/wrapping tool needs to be started, PythonQt can script any QObject without prior knowledge about it (except for the MetaObject information from the \b moc)
113 113 - Multiple inheritance for C++ objects (e.g. a QWidget is derived from QObject and QPaintDevice, PythonQt will automatically cast a QWidget to a QPaintDevice when needed)
114 114 - Polymorphic downcasting (if e.g. PythonQt sees a QEvent, it can downcast it depending on the type(), so the Python e.g. sees a QPaintEvent instead of a plain QEvent)
115 115 - Deriving C++ objects from Python and overwriting virtual method with a Python implementation (requires usage of wrapper generator or manual work!)
116 116 - Extensible handler for Python/C++ conversion of complex types, e.g. mapping of QVector<SomeObject> to/from a Python array
117 117
118 118 \section FeaturesQtAll Features (with PythonQt_QtAll linked in)
119 119
120 120 Thanks to the new wrapper generator, PythonQt now offers the additional PythonQt_QtAll library which wraps the complete Qt API, including all C++ classes and all non-slots on QObject derived classes.
121 121 This offers the following features:
122 122
123 123 - Complete Qt API wrapped and accessible
124 124 - The following modules are available as submodule of the PythonQt module:
125 125 - QtCore
126 126 - QtGui
127 127 - QtNetwork
128 128 - QtOpenGL
129 129 - QtSql
130 130 - QtSvg
131 131 - QtUiTools
132 132 - QtWebKit
133 133 - QtXml
134 134 - QtXmlPatterns
135 135 - (phonon, QtHelp, assistant, designer are currently not supported, this would require some additional effort on the code generator)
136 136 - For convenience, all classes are also available in the PythonQt.Qt module, for people who do not care in which module a class is located
137 137 - Any Qt class that has virtual methods can be easily derived from Python and the virtual methods can be reimplemented in Python
138 138 - Polymorphic downcasting on QEvent, QGraphicsItem, QStyleOption, ...
139 139 - Multiple inheritance support (e.g. QGraphicsTextItem is a QObject AND a QGraphicsItem, PythonQt will handle this well)
140 140
141 141 \section Comparision Comparision with PyQt
142 142
143 143 - PythonQt is not as Pythonic as PyQt in many details (e.g. operator mapping, pickling, translation support, ...) and it is mainly thought for embedding and intercommunication between Qt/Cpp and Python
144 144 - PythonQt allows to communicate in both directions, e.g. calling a Python object from C++ AND calling a C++ method from Python, while PyQt only handles the Python->C++ direction
145 145 - PythonQt offers properties as Python attributes, while PyQt offers them as setter/getter methods (e.g. QWidget.width is a property in PythonQt and a method in PyQt)
146 146 - PythonQt does not support instanceof checks for Qt classes, except for the exact match and derived Python classes
147 - QObject.emit to emit Qt signals from Python is not yet implemented
147 - QObject.emit to emit Qt signals from Python is not yet implemented but PythonQt allows to just emit a signal by calling it
148 148 - PythonQt does not offer to add new signals to Python/C++ objects
149 149 - Ownership of objects is a bit different in PythonQt, currently Python classes derived from a C++ class need to be manually references in PythonQt to not get deleted too early (this will be fixed)
150 150 - Probably there are lots of details that differ, I do not know PyQt that well to list them all.
151 151
152 152
153 153 \section Interface
154 154
155 155 The main interface to PythonQt is the PythonQt singleton.
156 156 PythonQt needs to be initialized via PythonQt::init() once.
157 157 Afterwards you communicate with the singleton via PythonQt::self().
158 158 PythonQt offers a complete Qt binding, which
159 159 needs to be enabled via PythonQt_QtAll::init().
160 160
161 161
162 162 \section Datatype Datatype Mapping
163 163
164 164 The following table shows the mapping between Python and Qt objects:
165 165 <table>
166 166 <tr><th>Qt/C++</th><th>Python</th></tr>
167 167 <tr><td>bool</td><td>bool</td></tr>
168 168 <tr><td>double</td><td>float</td></tr>
169 169 <tr><td>float</td><td>float</td></tr>
170 170 <tr><td>char/uchar,int/uint,short,ushort,QChar</td><td>integer</td></tr>
171 171 <tr><td>long</td><td>integer</td></tr>
172 172 <tr><td>ulong,longlong,ulonglong</td><td>long</td></tr>
173 173 <tr><td>QString</td><td>unicode string</td></tr>
174 174 <tr><td>QByteArray</td><td>str</td></tr>
175 175 <tr><td>char*</td><td>str</td></tr>
176 176 <tr><td>QStringList</td><td>tuple of unicode strings</td></tr>
177 177 <tr><td>QVariantList</td><td>tuple of objects</td></tr>
178 178 <tr><td>QVariantMap</td><td>dict of objects</td></tr>
179 179 <tr><td>QVariant</td><td>depends on type, see below</td></tr>
180 180 <tr><td>QSize, QRect and all other standard Qt QVariants</td><td>variant wrapper that supports complete API of the respective Qt classes</td></tr>
181 181 <tr><td>OwnRegisteredMetaType</td><td>C++ wrapper, optionally with additional information/wrapping provided by registerCPPClass()</td></tr>
182 182 <tr><td>QList<AnyObject*></td><td>converts to a list of CPP wrappers</td></tr>
183 183 <tr><td>EnumType</td><td>integer (all enums that are known via the moc and the Qt namespace are supported)</td></tr>
184 184 <tr><td>QObject (and derived classes)</td><td>QObject wrapper</td></tr>
185 185 <tr><td>C++ object</td><td>CPP wrapper, either wrapped via PythonQtCppWrapperFactory or just decorated with decorators</td></tr>
186 186 <tr><td>PyObject</td><td>PyObject</td></tr>
187 187 </table>
188 188
189 189 PyObject is passed as simple pointer, which allows to pass/return any Python Object directly to/from
190 190 a Qt slot.
191 191 QVariants are mapped recursively as given above, e.g. a dictionary can
192 192 contain lists of dictionaries of doubles.
193 193 For example a QVariant of type "String" is mapped to a python unicode string.
194 194 All Qt QVariant types are implemented, PythonQt supports the complete Qt API for these object.
195 195
196 196 \section QObject QObject Wrapping
197 197
198 198 All classes derived from QObject are automatically wrapped with a python wrapper class
199 199 when they become visible to the Python interpreter. This can happen via
200 200 - the PythonQt::addObject() method
201 201 - when a Qt \b slot returns a QObject derived object to python
202 202 - when a Qt \b signal contains a QObject and is connected to a python function
203 203
204 204 It is important that you call PythonQt::registerClass() for any QObject derived class
205 205 that may become visible to Python, except when you add it via PythonQt::addObject().
206 206 This will register the complete parent hierachy of the registered class, so that
207 207 when you register e.g. a QPushButton, QWidget will be registered as well (and all intermediate
208 208 parents).
209 209
210 210 From Python, you can talk to the returned QObjects in a natural way by calling
211 211 their slots and receiving the return values. You can also read/write all
212 212 properties of the objects as if they where normal python properties.
213 213
214 214 In addition to this, the wrapped objects support
215 215 - className() - returns a string that reprents the classname of the QObject
216 216 - help() - shows all properties, slots, enums, decorator slots and constructors of the object, in a printable form
217 217 - delete() - deletes the object (use with care, especially if you passed the ownership to C++)
218 218 - connect(signal, function) - connect the signal of the given object to a python function
219 219 - connect(signal, qobject, slot) - connect the signal of the given object to a slot of another QObject
220 220 - disconnect(signal, function) - disconnect the signal of the given object from a python function
221 221 - disconnect(signal, qobject, slot) - disconnect the signal of the given object from a slot of another QObject
222 222 - children() - returns the children of the object
223 223 - setParent(QObject) - set the parent
224 224 - QObject* parent() - get the parent
225 225
226 226 The below example shows how to connect signals in Python:
227 227
228 228 \code
229 229 # define a signal handler function
230 230 def someFunction(flag):
231 231 print flag
232 232
233 233 # button1 is a QPushButton that has been added to Python via addObject()
234 234 # connect the clicked signal to a python function:
235 235 button1.connect("clicked(bool)", someFunction)
236 236
237 237 \endcode
238 238
239 239 \section CPP CPP Wrapping
240 240
241 241 You can create dedicated wrapper QObjects for any C++ class. This is done by deriving from PythonQtCppWrapperFactory
242 242 and adding your factory via addWrapperFactory().
243 243 Whenever PythonQt encounters a CPP pointer (e.g. on a slot or signal)
244 244 and it does not known it as a QObject derived class, it will create a generic CPP wrapper. So even unknown C++ objects
245 245 can be passed through Python. If the wrapper factory supports the CPP class, a QObject wrapper will be created for each
246 246 instance that enters Python. An alternative to a complete wrapper via the wrapper factory are decorators, see \ref Decorators
247 247
248 248 \section MetaObject Meta Object/Class access
249 249
250 250 For each known C++ class, PythonQt provides a Python class. These classes are visible
251 251 inside of the "PythonQt" python module or in subpackages if a package is given when the class is registered.
252 252
253 253 A Meta class supports:
254 254
255 255 - access to all declared enum values
256 256 - constructors
257 257 - static methods
258 258 - unbound non-static methods
259 259 - help() and className()
260 260
261 261 From within Python, you can import the module "PythonQt" to access these classes and the Qt namespace.
262 262
263 263 \code
264 264 from PythonQt import QtCore
265 265
266 266 # namespace access:
267 267 print QtCore.Qt.AlignLeft
268 268
269 269 # constructors
270 270 a = QtCore.QSize(12,13)
271 271 b = QtCore.QFont()
272 272
273 273 # static method
274 274 QtCore.QDate.currentDate()
275 275
276 276 # enum value
277 277 QtCore.QFont.UltraCondensed
278 278
279 279 \endcode
280 280
281 281 \section Decorators Decorator slots
282 282
283 283 PythonQt introduces a new generic approach to extend any wrapped QObject or CPP object with
284 284
285 285 - constructors
286 286 - destructors (for CPP objects)
287 287 - additional slots
288 288 - static slots (callable on both the Meta object and the instances)
289 289
290 290 The idea behind decorators is that we wanted to make it as easy as possible to extend
291 291 wrapped objects. Since we already have an implementation for invoking any Qt Slot from
292 292 Python, it looked promising to use this approach for the extension of wrapped objects as well.
293 293 This avoids that the PythonQt user needs to care about how Python arguments are mapped from/to
294 294 Qt when he wants to create static methods, constructors and additional member functions.
295 295
296 296 The basic idea about decorators is to create a QObject derived class that implements slots
297 297 which take one of the above roles (e.g. constructor, destructor etc.) via a naming convention.
298 298 These slots are then assigned to other classes via the naming convention.
299 299
300 300 - SomeClassName* new_SomeClassName(...) - defines a constructor for "SomeClassName" that returns a new object of type SomeClassName (where SomeClassName can be any CPP class, not just QObject classes)
301 301 - void delete_SomeClassName(SomeClassName* o) - defines a destructor, which should delete the passed in object o
302 302 - anything static_SomeClassName_someMethodName(...) - defines a static method that is callable on instances and the meta class
303 303 - anything someMethodName(SomeClassName* o, ...) - defines a slot that will be available on SomeClassName instances (and derived instances). When such a slot is called the first argument is the pointer to the instance and the rest of the arguments can be used to make a call on the instance.
304 304
305 305 The below example shows all kinds of decorators in action:
306 306
307 307 \code
308 308
309 309 // an example CPP object
310 310 class YourCPPObject {
311 311 public:
312 312 YourCPPObject(int arg1, float arg2) { a = arg1; b = arg2; }
313 313
314 314 float doSomething(int arg1) { return arg1*a*b; };
315 315
316 316 private:
317 317
318 318 int a;
319 319 float b;
320 320 };
321 321
322 322 // an example decorator
323 323 class ExampleDecorator : public QObject
324 324 {
325 325 Q_OBJECT
326 326
327 327 public slots:
328 328 // add a constructor to QSize that takes a QPoint
329 329 QSize* new_QSize(const QPoint& p) { return new QSize(p.x(), p.y()); }
330 330
331 331 // add a constructor for QPushButton that takes a text and a parent widget
332 332 QPushButton* new_QPushButton(const QString& text, QWidget* parent=NULL) { return new QPushButton(text, parent); }
333 333
334 334 // add a constructor for a CPP object
335 335 YourCPPObject* new_YourCPPObject(int arg1, float arg2) { return new YourCPPObject(arg1, arg2); }
336 336
337 337 // add a destructor for a CPP object
338 338 void delete_YourCPPObject(YourCPPObject* obj) { delete obj; }
339 339
340 340 // add a static method to QWidget
341 341 QWidget* static_QWidget_mouseGrabber() { return QWidget::mouseGrabber(); }
342 342
343 343 // add an additional slot to QWidget (make move() callable, which is not declared as a slot in QWidget)
344 344 void move(QWidget* w, const QPoint& p) { w->move(p); }
345 345
346 346 // add an additional slot to QWidget, overloading the above move method
347 347 void move(QWidget* w, int x, int y) { w->move(x,y); }
348 348
349 349 // add a method to your own CPP object
350 350 int doSomething(YourCPPObject* obj, int arg1) { return obj->doSomething(arg1); }
351 351 };
352 352
353 353 ...
354 354
355 355 PythonQt::self()->addDecorators(new ExampleDecorator());
356 356 PythonQt::self()->registerCPPClass("YourCPPObject");
357 357
358 358 \endcode
359 359
360 360 After you have registered an instance of the above ExampleDecorator, you can do the following from Python
361 361 (all these calls are mapped to the above decorator slots):
362 362
363 363 \code
364 364 from PythonQt import QtCore, QtGui, YourCPPObject
365 365
366 366 # call our new constructor of QSize
367 367 size = QtCore.QSize(QPoint(1,2));
368 368
369 369 # call our new QPushButton constructor
370 370 button = QtGui.QPushButton("sometext");
371 371
372 372 # call the move slot (overload1)
373 373 button.move(QPoint(0,0))
374 374
375 375 # call the move slot (overload2)
376 376 button.move(0,0)
377 377
378 378 # call the static method
379 379 grabber = QtGui.QWidget.mouseWrapper();
380 380
381 381 # create a CPP object via constructor
382 382 yourCpp = YourCPPObject(1,11.5)
383 383
384 384 # call the wrapped method on CPP object
385 385 print yourCpp.doSomething(1);
386 386
387 387 # destructor will be called:
388 388 yourCpp = None
389 389
390 390 \endcode
391 391
392 392 \section Building
393 393
394 394 PythonQt requires at least Qt 4.2.2 (or higher) and Python 2.3, 2.4, 2.5 or 2.6 on Windows, Linux and MacOS X. It has not yet been tested with Python 3.x, but it should only require minor changes.
395 395 To compile PythonQt, you will need a python developer installation which includes Python's header files and
396 396 the python2x.[lib | dll | so | dynlib].
397 397 The build scripts a currently set to use Python 2.5.
398 398 You may need to tweak the \b build/python.prf file to set the correct Python includes and libs on your system.
399 399
400 400 \subsection Windows
401 401
402 402 On Windows, the (non-source) Python Windows installer can be used.
403 403 Make sure that you use the same compiler, the current Python distribution is built
404 404 with Visual Studio 2003. If you want to use another compiler, you will need to build
405 405 Python yourself, using your compiler.
406 406
407 407 To build PythonQt, you need to set the environment variable \b PYTHON_PATH to point to the root
408 408 dir of the python installation and \b PYTHON_LIB to point to
409 409 the directory where the python lib file is located.
410 410
411 411 When using the prebuild Python installer, this will be:
412 412
413 413 \code
414 414 > set PYTHON_PATH = c:\Python25
415 415 > set PYTHON_LIB = c:\Python25\libs
416 416 \endcode
417 417
418 418 When using the python sources, this will be something like:
419 419
420 420 \code
421 421 > set PYTHON_PATH = c:\yourDir\Python-2.5.1\
422 422 > set PYTHON_LIB = c:\yourDir\Python-2.5.1\PCbuild8\Win32
423 423 \endcode
424 424
425 425 To build all, do the following (after setting the above variables):
426 426
427 427 \code
428 428 > cd PythonQtRoot
429 429 > vcvars32
430 430 > qmake
431 431 > nmake
432 432 \endcode
433 433
434 434 This should build everything. If Python can not be linked or include files can not be found,
435 435 you probably need to tweak \b build/python.prf
436 436
437 437 The tests and examples are located in PythonQt/lib.
438 438
439 439 \subsection Linux
440 440
441 441 On Linux, you need to install a Python-dev package.
442 442 If Python can not be linked or include files can not be found,
443 443 you probably need to tweak \b build/python.prf
444 444
445 445 To build PythonQt, just do a:
446 446
447 447 \code
448 448 > cd PythonQtRoot
449 449 > qmake
450 450 > make all
451 451 \endcode
452 452
453 453 The tests and examples are located in PythonQt/lib.
454 454 You should add PythonQt/lib to your LD_LIBRARY_PATH so that the runtime
455 455 linker can find the *.so files.
456 456
457 457 \subsection MacOsX
458 458
459 459 On Mac, Python is installed as a Framework, so you should not need to install it.
460 460 To build PythonQt, just do a:
461 461
462 462 \code
463 463 > cd PythonQtRoot
464 464 > qmake
465 465 > make all
466 466 \endcode
467 467
468 468 \section Tests
469 469
470 470 There is a unit test that tests most features of PythonQt, see the \b tests subdirectory for details.
471 471
472 472 \section Examples
473 473
474 474 Examples are available in the \b examples directory. The PyScriptingConsole implements a simple
475 475 interactive scripting console that shows how to script a simple application.
476 476
477 477 The following shows how to integrate PythonQt into you Qt application:
478 478
479 479 \code
480 480 #include "PythonQt.h"
481 481 #include <QApplication>
482 482 ...
483 483
484 484 int main( int argc, char **argv )
485 485 {
486 486
487 487 QApplication qapp(argc, argv);
488 488
489 489 // init PythonQt and Python itself
490 490 PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
491 491
492 492
493 493 // get a smart pointer to the __main__ module of the Python interpreter
494 494 PythonQtObjectPtr mainContext = PythonQt::self()->getMainModule();
495 495
496 496 // add a QObject as variable of name "example" to the namespace of the __main__ module
497 497 PyExampleObject example;
498 498 PythonQt::self()->addObject(mainContext, "example", &example);
499 499
500 500 // do something
501 501 PythonQt::self()->runScript(mainContext, "print example\n");
502 502 PythonQt::self()->runScript(mainContext, "def multiply(a,b):\n return a*b;\n");
503 503 QVariantList args;
504 504 args << 42 << 47;
505 505 QVariant result = PythonQt::self()->call(mainContext,"multiply", args);
506 506 ...
507 507 \endcode
508 508
509 509
510 510 */
@@ -1,328 +1,351
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtMethodInfo.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtMethodInfo.h"
43 43 #include "PythonQtClassInfo.h"
44 44 #include <iostream>
45 45
46 46 QHash<QByteArray, PythonQtMethodInfo*> PythonQtMethodInfo::_cachedSignatures;
47 47 QHash<QByteArray, QByteArray> PythonQtMethodInfo::_parameterNameAliases;
48 48
49 49 PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo)
50 50 {
51 51 #ifdef PYTHONQT_DEBUG
52 52 QByteArray sig(meta.signature());
53 53 sig = sig.mid(sig.indexOf('('));
54 54 QByteArray fullSig = QByteArray(meta.typeName()) + " " + sig;
55 55 std::cout << "caching " << fullSig.data() << std::endl;
56 56 #endif
57 57
58 58 ParameterInfo type;
59 59 fillParameterInfo(type, QByteArray(meta.typeName()), classInfo);
60 60 _parameters.append(type);
61 QByteArray name;
62 61 QList<QByteArray> names = meta.parameterTypes();
63 foreach (name, names) {
62 foreach (const QByteArray& name, names) {
64 63 fillParameterInfo(type, name, classInfo);
65 64 _parameters.append(type);
66 65 }
67 66 }
68 67
68 PythonQtMethodInfo::PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args)
69 {
70 ParameterInfo type;
71 fillParameterInfo(type, typeName, NULL);
72 _parameters.append(type);
73 foreach (const QByteArray& name, args) {
74 fillParameterInfo(type, name, NULL);
75 _parameters.append(type);
76 }
77 }
78
69 79 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo)
70 80 {
71 81 QByteArray sig(signal.signature());
72 82 sig = sig.mid(sig.indexOf('('));
73 83 QByteArray fullSig = QByteArray(signal.typeName()) + " " + sig;
74 84 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
75 85 if (!result) {
76 86 result = new PythonQtMethodInfo(signal, classInfo);
77 87 _cachedSignatures.insert(fullSig, result);
78 88 }
79 89 return result;
80 90 }
81 91
82 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromMetaObjectAndSignature(const QMetaObject* metaObject, const char* signature)
92 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(int numArgs, const char** args)
83 93 {
84 QByteArray sig = QMetaObject::normalizedSignature(signature);
85 int idx = metaObject->indexOfMethod(sig);
86 QMetaMethod meta = metaObject->method(idx);
87 return PythonQtMethodInfo::getCachedMethodInfo(meta, NULL);
94 QByteArray typeName = args[0];
95 QList<QByteArray> arguments;
96 QByteArray fullSig = typeName;
97 fullSig += "(";
98 for (int i =1;i<numArgs; i++) {
99 if (i>1) {
100 fullSig += ",";
101 }
102 arguments << QByteArray(args[i]);
103 }
104 fullSig += ")";
105 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
106 if (!result) {
107 result = new PythonQtMethodInfo(typeName, arguments);
108 _cachedSignatures.insert(fullSig, result);
109 }
110 return result;
88 111 }
89 112
90 113 void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo)
91 114 {
92 115 QByteArray name = orgName;
93 116
94 117 type.enumWrapper = NULL;
95 118
96 119 int len = name.length();
97 120 if (len>0) {
98 121 if (strncmp(name.constData(), "const ", 6)==0) {
99 122 name = name.mid(6);
100 123 len -= 6;
101 124 type.isConst = true;
102 125 } else {
103 126 type.isConst = false;
104 127 }
105 128 bool hadPointer = false;
106 129 bool hadReference = false;
107 130 // remove * and & from the end of the string, handle & and * the same way
108 131 while (name.at(len-1) == '*') {
109 132 len--;
110 133 hadPointer = true;
111 134 }
112 135 while (name.at(len-1) == '&') {
113 136 len--;
114 137 hadReference = true;
115 138 }
116 139 if (len!=name.length()) {
117 140 name = name.left(len);
118 141 }
119 142 type.isPointer = hadPointer;
120 143
121 144 QByteArray alias = _parameterNameAliases.value(name);
122 145 if (!alias.isEmpty()) {
123 146 name = alias;
124 147 }
125 148
126 149 type.typeId = nameToType(name);
127 150 if (!type.isPointer && type.typeId == Unknown) {
128 151 type.typeId = QMetaType::type(name.constData());
129 152 if (type.typeId == QMetaType::Void) {
130 153 type.typeId = Unknown;
131 154 }
132 155 }
133 156 type.name = name;
134 157
135 158 if (type.typeId == PythonQtMethodInfo::Unknown || type.typeId >= QMetaType::User) {
136 159 bool isLocalEnum;
137 160 // TODOXXX: make use of this flag!
138 161 type.enumWrapper = PythonQtClassInfo::findEnumWrapper(type.name, classInfo, &isLocalEnum);
139 162 }
140 163 } else {
141 164 type.typeId = QMetaType::Void;
142 165 type.isPointer = false;
143 166 type.isConst = false;
144 167 }
145 168 }
146 169
147 170 int PythonQtMethodInfo::nameToType(const char* name)
148 171 {
149 172 if (_parameterTypeDict.isEmpty()) {
150 173 // we could also use QMetaType::nameToType, but that does a string compare search
151 174 // and does not support QVariant
152 175
153 176 // QMetaType names
154 177 _parameterTypeDict.insert("long", QMetaType::Long);
155 178 _parameterTypeDict.insert("int", QMetaType::Int);
156 179 _parameterTypeDict.insert("short", QMetaType::Short);
157 180 _parameterTypeDict.insert("char", QMetaType::Char);
158 181 _parameterTypeDict.insert("ulong", QMetaType::ULong);
159 182 _parameterTypeDict.insert("unsigned long", QMetaType::ULong);
160 183 _parameterTypeDict.insert("uint", QMetaType::UInt);
161 184 _parameterTypeDict.insert("unsigned int", QMetaType::UInt);
162 185 _parameterTypeDict.insert("ushort", QMetaType::UShort);
163 186 _parameterTypeDict.insert("unsigned short", QMetaType::UShort);
164 187 _parameterTypeDict.insert("uchar", QMetaType::UChar);
165 188 _parameterTypeDict.insert("unsigned char", QMetaType::UChar);
166 189 _parameterTypeDict.insert("bool", QMetaType::Bool);
167 190 _parameterTypeDict.insert("float", QMetaType::Float);
168 191 _parameterTypeDict.insert("double", QMetaType::Double);
169 192 _parameterTypeDict.insert("qreal", QMetaType::Double);
170 193 _parameterTypeDict.insert("QChar", QMetaType::QChar);
171 194 _parameterTypeDict.insert("QByteArray", QMetaType::QByteArray);
172 195 _parameterTypeDict.insert("Q3CString", QMetaType::QByteArray);
173 196 _parameterTypeDict.insert("QString", QMetaType::QString);
174 197 _parameterTypeDict.insert("", QMetaType::Void);
175 198 _parameterTypeDict.insert("void", QMetaType::Void);
176 199 // QVariant names
177 200 _parameterTypeDict.insert("Q_LLONG", QMetaType::LongLong);
178 201 _parameterTypeDict.insert("Q_ULLONG", QMetaType::ULongLong);
179 202 _parameterTypeDict.insert("qlonglong", QMetaType::LongLong);
180 203 _parameterTypeDict.insert("qulonglong", QMetaType::ULongLong);
181 204 _parameterTypeDict.insert("qint64", QMetaType::LongLong);
182 205 _parameterTypeDict.insert("quint64", QMetaType::ULongLong);
183 206 _parameterTypeDict.insert("QIconSet", QMetaType::QIcon);
184 207 _parameterTypeDict.insert("QVariantMap", QMetaType::QVariantMap);
185 208 _parameterTypeDict.insert("QVariantList", QMetaType::QVariantList);
186 209 _parameterTypeDict.insert("QMap<QString,QVariant>", QMetaType::QVariantMap);
187 210 _parameterTypeDict.insert("QList<QVariant>", QMetaType::QVariantList);
188 211 _parameterTypeDict.insert("QStringList", QMetaType::QStringList);
189 212 _parameterTypeDict.insert("QBitArray", QMetaType::QBitArray);
190 213 _parameterTypeDict.insert("QDate", QMetaType::QDate);
191 214 _parameterTypeDict.insert("QTime", QMetaType::QTime);
192 215 _parameterTypeDict.insert("QDateTime", QMetaType::QDateTime);
193 216 _parameterTypeDict.insert("QUrl", QMetaType::QUrl);
194 217 _parameterTypeDict.insert("QLocale", QMetaType::QLocale);
195 218 _parameterTypeDict.insert("QRect", QMetaType::QRect);
196 219 _parameterTypeDict.insert("QRectf", QMetaType::QRectF);
197 220 _parameterTypeDict.insert("QSize", QMetaType::QSize);
198 221 _parameterTypeDict.insert("QSizef", QMetaType::QSizeF);
199 222 _parameterTypeDict.insert("QLine", QMetaType::QLine);
200 223 _parameterTypeDict.insert("QLinef", QMetaType::QLineF);
201 224 _parameterTypeDict.insert("QPoint", QMetaType::QPoint);
202 225 _parameterTypeDict.insert("QPointf", QMetaType::QPointF);
203 226 _parameterTypeDict.insert("QRegExp", QMetaType::QRegExp);
204 227 // _parameterTypeDict.insert("QColorGroup", QMetaType::QColorGroup);
205 228 _parameterTypeDict.insert("QFont", QMetaType::QFont);
206 229 _parameterTypeDict.insert("QPixmap", QMetaType::QPixmap);
207 230 _parameterTypeDict.insert("QBrush", QMetaType::QBrush);
208 231 _parameterTypeDict.insert("QColor", QMetaType::QColor);
209 232 _parameterTypeDict.insert("QCursor", QMetaType::QCursor);
210 233 _parameterTypeDict.insert("QPalette", QMetaType::QPalette);
211 234 _parameterTypeDict.insert("QIcon", QMetaType::QIcon);
212 235 _parameterTypeDict.insert("QImage", QMetaType::QPolygon);
213 236 _parameterTypeDict.insert("QRegion", QMetaType::QRegion);
214 237 _parameterTypeDict.insert("QBitmap", QMetaType::QBitmap);
215 238 _parameterTypeDict.insert("QSizePolicy", QMetaType::QSizePolicy);
216 239 _parameterTypeDict.insert("QKeySequence", QMetaType::QKeySequence);
217 240 _parameterTypeDict.insert("QPen", QMetaType::QPen);
218 241 _parameterTypeDict.insert("QTextLength", QMetaType::QTextLength);
219 242 _parameterTypeDict.insert("QTextFormat", QMetaType::QTextFormat);
220 243 _parameterTypeDict.insert("QMatrix", QMetaType::QMatrix);
221 244 _parameterTypeDict.insert("QVariant", PythonQtMethodInfo::Variant);
222 245 // own special types... (none so far, could be e.g. ObjectList
223 246 }
224 247 QHash<QByteArray, int>::const_iterator it = _parameterTypeDict.find(name);
225 248 if (it!=_parameterTypeDict.end()) {
226 249 return it.value();
227 250 } else {
228 251 return PythonQtMethodInfo::Unknown;
229 252 }
230 253 }
231 254
232 255 void PythonQtMethodInfo::cleanupCachedMethodInfos()
233 256 {
234 257 QHashIterator<QByteArray, PythonQtMethodInfo *> i(_cachedSignatures);
235 258 while (i.hasNext()) {
236 259 delete i.next().value();
237 260 }
238 261 }
239 262
240 263 void PythonQtMethodInfo::addParameterTypeAlias(const QByteArray& alias, const QByteArray& name)
241 264 {
242 265 _parameterNameAliases.insert(alias, name);
243 266 }
244 267
245 268 //-------------------------------------------------------------------------------------------------
246 269
247 270 void PythonQtSlotInfo::deleteOverloadsAndThis()
248 271 {
249 272 PythonQtSlotInfo* cur = this;
250 273 while(cur->nextInfo()) {
251 274 PythonQtSlotInfo* next = cur->nextInfo();
252 275 delete cur;
253 276 cur = next;
254 277 }
255 278 }
256 279
257 280
258 281 QString PythonQtSlotInfo::fullSignature()
259 282 {
260 283 bool skipFirstArg = isInstanceDecorator();
261 284 QString result = _meta.typeName();
262 285 QByteArray sig = slotName();
263 286 QList<QByteArray> names = _meta.parameterNames();
264 287
265 288 bool isStatic = false;
266 289 bool isConstructor = false;
267 290 bool isDestructor = false;
268 291
269 292 if (_type == ClassDecorator) {
270 293 if (sig.startsWith("new_")) {
271 294 sig = sig.mid(strlen("new_"));
272 295 isConstructor = true;
273 296 } else if (sig.startsWith("delete_")) {
274 297 sig = sig.mid(strlen("delete_"));
275 298 isDestructor = true;
276 299 } else if(sig.startsWith("static_")) {
277 300 isStatic = true;
278 301 sig = sig.mid(strlen("static_"));
279 302 int idx = sig.indexOf("_");
280 303 if (idx>=0) {
281 304 sig = sig.mid(idx+1);
282 305 }
283 306 }
284 307 }
285 308
286 309 result += QByteArray(" ") + sig;
287 310 result += "(";
288 311
289 312 int lastEntry = _parameters.count()-1;
290 313 for (int i = skipFirstArg?2:1; i<_parameters.count(); i++) {
291 314 if (_parameters.at(i).isConst) {
292 315 result += "const ";
293 316 }
294 317 result += _parameters.at(i).name;
295 318 if (_parameters.at(i).isPointer) {
296 319 result += "*";
297 320 }
298 321 if (!names.at(i-1).isEmpty()) {
299 322 result += " ";
300 323 result += names.at(i-1);
301 324 }
302 325 if (i!=lastEntry) {
303 326 result += ", ";
304 327 }
305 328 }
306 329 result += ")";
307 330
308 331 if (isStatic) {
309 332 result = QString("static ") + result;
310 333 }
311 334 if (isConstructor) {
312 335 // result = QString("constructor ") + result;
313 336 }
314 337 if (isDestructor) {
315 338 result = QString("~") + result;
316 339 }
317 340 return result;
318 341 }
319 342
320 343
321 344 QByteArray PythonQtSlotInfo::slotName()
322 345 {
323 346 QByteArray sig(_meta.signature());
324 347 int idx = sig.indexOf('(');
325 348 sig = sig.left(idx);
326 349 return sig;
327 350 }
328 351
@@ -1,189 +1,190
1 1 #ifndef _PYTHONQTMETHODINFO_H
2 2 #define _PYTHONQTMETHODINFO_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtMethodInfo.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46
47 47 #include <QByteArray>
48 48 #include <QHash>
49 49 #include <QList>
50 50 #include <QMetaMethod>
51 51
52 52 class PythonQtClassInfo;
53 53 struct _object;
54 54 typedef struct _object PyObject;
55 55
56 56 //! stores information about a specific signal/slot/method
57 57 class PYTHONQT_EXPORT PythonQtMethodInfo
58 58 {
59 59 public:
60 60 enum ParameterType {
61 61 Unknown = -1,
62 62 Variant = -2
63 63 };
64 64
65 65 //! stores the QVariant id (if available) and the name of the type
66 66 struct ParameterInfo {
67 67 QByteArray name;
68 68 PyObject* enumWrapper; // if it is an enum, a pointer to the enum wrapper
69 69 int typeId; // a mixture from QMetaType and ParameterType
70 70 bool isPointer;
71 71 bool isConst;
72 72 };
73 73
74 74 PythonQtMethodInfo() {};
75 75 ~PythonQtMethodInfo() {};
76 76 PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo);
77 PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args);
77 78 PythonQtMethodInfo(const PythonQtMethodInfo& other) {
78 79 _parameters = other._parameters;
79 80 }
80 81
81 82 //! returns the method info of the signature, uses a cache internally to speed up
82 83 //! multiple requests for the same method, classInfo is passed to allow local enum resolution (if NULL is passed, no local enums are recognized)
83 84 static const PythonQtMethodInfo* getCachedMethodInfo(const QMetaMethod& method, PythonQtClassInfo* classInfo);
84 85
85 //! get the cached method info by finding the meta method on the meta object via its signature, enums are only supported with leading namespace::
86 static const PythonQtMethodInfo* getCachedMethodInfoFromMetaObjectAndSignature(const QMetaObject* metaObject, const char* signature);
86 //! get the cached method info using the passed in list of return value and arguments, return value needs to be passed as first arg
87 static const PythonQtMethodInfo* getCachedMethodInfoFromArgumentList(int numArgs, const char** args);
87 88
88 89 //! cleanup the cache
89 90 static void cleanupCachedMethodInfos();
90 91
91 92 //! returns the number of parameters including the return value
92 93 int parameterCount() const { return _parameters.size(); };
93 94
94 95 //! returns the id for the given type (using an internal dictionary)
95 96 static int nameToType(const char* name);
96 97
97 98 //! get the parameter infos
98 99 const QList<ParameterInfo>& parameters() const { return _parameters; }
99 100
100 101 //! add an alias for a typename, e.g. QObjectList and QList<QObject*>.
101 102 static void addParameterTypeAlias(const QByteArray& alias, const QByteArray& name);
102 103
103 104 protected:
104 105 static void fillParameterInfo(ParameterInfo& type, const QByteArray& name, PythonQtClassInfo* classInfo);
105 106
106 107 static QHash<QByteArray, int> _parameterTypeDict;
107 108 static QHash<QByteArray, QByteArray> _parameterNameAliases;
108 109
109 110 //! stores the cached signatures of methods to speedup mapping from Qt to Python types
110 111 static QHash<QByteArray, PythonQtMethodInfo*> _cachedSignatures;
111 112
112 113 QList<ParameterInfo> _parameters;
113 114 };
114 115
115 116 //! stores information about a slot, including a next pointer to overloaded slots
116 117 class PythonQtSlotInfo : public PythonQtMethodInfo
117 118 {
118 119 public:
119 120 enum Type {
120 121 MemberSlot, InstanceDecorator, ClassDecorator
121 122 };
122 123
123 124 PythonQtSlotInfo(const PythonQtSlotInfo& info):PythonQtMethodInfo() {
124 125 _meta = info._meta;
125 126 _parameters = info._parameters;
126 127 _slotIndex = info._slotIndex;
127 128 _next = NULL;
128 129 _decorator = info._decorator;
129 130 _type = info._type;
130 131 _upcastingOffset = 0;
131 132 }
132 133
133 134 PythonQtSlotInfo(PythonQtClassInfo* classInfo, const QMetaMethod& meta, int slotIndex, QObject* decorator = NULL, Type type = MemberSlot ):PythonQtMethodInfo()
134 135 {
135 136 const PythonQtMethodInfo* info = getCachedMethodInfo(meta, classInfo);
136 137 _meta = meta;
137 138 _parameters = info->parameters();
138 139 _slotIndex = slotIndex;
139 140 _next = NULL;
140 141 _decorator = decorator;
141 142 _type = type;
142 143 _upcastingOffset = 0;
143 144 }
144 145
145 146
146 147 public:
147 148
148 149 void deleteOverloadsAndThis();
149 150
150 151 const QMetaMethod* metaMethod() const { return &_meta; }
151 152
152 153 void setUpcastingOffset(int upcastingOffset) { _upcastingOffset = upcastingOffset; }
153 154
154 155 int upcastingOffset() const { return _upcastingOffset; }
155 156
156 157 //! get the index of the slot (needed for qt_metacall)
157 158 int slotIndex() const { return _slotIndex; }
158 159
159 160 //! get next overloaded slot (which has the same name)
160 161 PythonQtSlotInfo* nextInfo() const { return _next; }
161 162
162 163 //! set the next overloaded slot
163 164 void setNextInfo(PythonQtSlotInfo* next) { _next = next; }
164 165
165 166 //! returns if the slot is a decorator slot
166 167 bool isInstanceDecorator() { return _decorator!=NULL && _type == InstanceDecorator; }
167 168
168 169 //! returns if the slot is a constructor slot
169 170 bool isClassDecorator() { return _decorator!=NULL && _type == ClassDecorator; }
170 171
171 172 QObject* decorator() { return _decorator; }
172 173
173 174 //! get the full signature including return type
174 175 QString fullSignature();
175 176
176 177 //! get the short slot name
177 178 QByteArray slotName();
178 179
179 180 private:
180 181 int _slotIndex;
181 182 PythonQtSlotInfo* _next;
182 183 QObject* _decorator;
183 184 Type _type;
184 185 QMetaMethod _meta;
185 186 int _upcastingOffset;
186 187 };
187 188
188 189
189 190 #endif
@@ -1,233 +1,226
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 PyObject* result = call(_callable, methodInfo(), arguments, false);
51 PyObject* result = call(_callable, methodInfo(), arguments);
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 if (skipFirstArgumentOfMethodInfo) {
90 count--;
91 }
92 89 if (numPythonArgs!=-1) {
93 90 if (count>numPythonArgs+1) {
94 91 // take less arguments
95 92 count = numPythonArgs+1;
96 93 }
97 94 }
98 95
99 96 PyObject* pargs = NULL;
100 97 if (count>1) {
101 98 pargs = PyTuple_New(count-1);
102 99 }
103 100 bool err = false;
104 101 // transform Qt values to Python
105 102 const QList<PythonQtMethodInfo::ParameterInfo>& params = m->parameters();
106 int skipFirstOffset = 0;
107 if (skipFirstArgumentOfMethodInfo) {
108 skipFirstOffset = 1;
109 }
110 103 for (int i = 1; i < count; i++) {
111 const PythonQtMethodInfo::ParameterInfo& param = params.at(i + skipFirstOffset);
104 const PythonQtMethodInfo::ParameterInfo& param = params.at(i);
112 105 PyObject* arg = PythonQtConv::ConvertQtValueToPython(param, arguments[i]);
113 106 if (arg) {
114 107 // steals reference, no unref
115 108 PyTuple_SetItem(pargs, i-1,arg);
116 109 } else {
117 110 err = true;
118 111 break;
119 112 }
120 113 }
121 114
122 115 PyObject* result = NULL;
123 116 if (!err) {
124 117 PyErr_Clear();
125 118 result = PyObject_CallObject(callable, pargs);
126 119 if (result) {
127 120 // ok
128 121 } else {
129 122 PythonQt::self()->handleError();
130 123 }
131 124 }
132 125 if (pargs) {
133 126 // free the arguments again
134 127 Py_DECREF(pargs);
135 128 }
136 129
137 130 return result;
138 131 }
139 132
140 133 //------------------------------------------------------------------------------
141 134
142 135 PythonQtSignalReceiver::PythonQtSignalReceiver(QObject* obj):PythonQtSignalReceiverBase(obj)
143 136 {
144 137 _obj = obj;
145 138
146 139 // fetch the class info for object, since we will need to for correct enum resolution in
147 140 // signals
148 141 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
149 142 if (!_objClassInfo || !_objClassInfo->isQObject()) {
150 143 PythonQt::self()->registerClass(obj->metaObject());
151 144 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
152 145 }
153 146 // force decorator/enum creation
154 147 _objClassInfo->decorator();
155 148
156 149 _slotCount = staticMetaObject.methodOffset();
157 150 }
158 151
159 152 PythonQtSignalReceiver::~PythonQtSignalReceiver()
160 153 {
161 154 PythonQt::priv()->removeSignalEmitter(_obj);
162 155 }
163 156
164 157
165 158 bool PythonQtSignalReceiver::addSignalHandler(const char* signal, PyObject* callable)
166 159 {
167 160 bool flag = false;
168 161 int sigId = getSignalIndex(signal);
169 162 if (sigId>=0) {
170 163 // create PythonQtMethodInfo from signal
171 164 QMetaMethod meta = _obj->metaObject()->method(sigId);
172 165 const PythonQtMethodInfo* signalInfo = PythonQtMethodInfo::getCachedMethodInfo(meta, _objClassInfo);
173 166 PythonQtSignalTarget t(sigId, signalInfo, _slotCount, callable);
174 167 _targets.append(t);
175 168 // now connect to ourselves with the new slot id
176 169 QMetaObject::connect(_obj, sigId, this, _slotCount, Qt::AutoConnection, 0);
177 170
178 171 _slotCount++;
179 172 flag = true;
180 173 }
181 174 return flag;
182 175 }
183 176
184 177 bool PythonQtSignalReceiver::removeSignalHandler(const char* signal, PyObject* callable)
185 178 {
186 179 bool found = false;
187 180 int sigId = getSignalIndex(signal);
188 181 if (sigId>=0) {
189 182 QMutableListIterator<PythonQtSignalTarget> i(_targets);
190 183 while (i.hasNext()) {
191 184 if (i.next().isSame(sigId, callable)) {
192 185 i.remove();
193 186 found = true;
194 187 break;
195 188 }
196 189 }
197 190 }
198 191 return found;
199 192 }
200 193
201 194 void PythonQtSignalReceiver::removeSignalHandlers()
202 195 {
203 196 _targets.clear();
204 197 }
205 198
206 199 int PythonQtSignalReceiver::getSignalIndex(const char* signal)
207 200 {
208 201 int sigId = _obj->metaObject()->indexOfSignal(signal+1);
209 202 if (sigId<0) {
210 203 QByteArray tmpSig = QMetaObject::normalizedSignature(signal+1);
211 204 sigId = _obj->metaObject()->indexOfSignal(tmpSig);
212 205 }
213 206 return sigId;
214 207 }
215 208
216 209 int PythonQtSignalReceiver::qt_metacall(QMetaObject::Call c, int id, void **arguments)
217 210 {
218 211 // mlabDebugConst("PythonQt", "PythonQtSignalReceiver invoke " << _obj->className() << " " << _obj->name() << " " << id);
219 212 if (c != QMetaObject::InvokeMetaMethod) {
220 213 QObject::qt_metacall(c, id, arguments);
221 214 }
222 215
223 216 bool found = false;
224 217 foreach(const PythonQtSignalTarget& t, _targets) {
225 218 if (t.slotId() == id) {
226 219 found = true;
227 220 t.call(arguments);
228 221 break;
229 222 }
230 223 }
231 224 return 0;
232 225 }
233 226
@@ -1,79 +1,101
1 1 #ifndef _PYTHONQTSTDDECORATORS_H
2 2 #define _PYTHONQTSTDDECORATORS_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 PythonQtStdDecorators.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2007-04
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46 #include <Python.h>
47 47 #include <QObject>
48 48 #include <QVariantList>
49 49 #include <QTextDocument>
50 50 #include <QColor>
51 51 #include <QDateTime>
52 52 #include <QDate>
53 53 #include <QTime>
54 54
55 55 class PYTHONQT_EXPORT PythonQtStdDecorators : public QObject
56 56 {
57 57 Q_OBJECT
58 58
59 59 public slots:
60 60 bool connect(QObject* sender, const QByteArray& signal, PyObject* callable);
61 61 bool connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot);
62 62 bool disconnect(QObject* sender, const QByteArray& signal, PyObject* callable);
63 63 bool disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot);
64 64
65 65 #undef emit
66 66 void emit(QObject* sender, const QByteArray& signal, PyObject* arg1 = NULL,PyObject* arg2 = NULL,
67 67 PyObject* arg3 = NULL,PyObject* arg4 = NULL,PyObject* arg5 = NULL,PyObject* arg6 = NULL,PyObject* arg7 = NULL);
68 68 #define emit
69 69
70 70 QObject* parent(QObject* o);
71 71 void setParent(QObject* o, QObject* parent);
72 72
73 73 QVariantList children(QObject* o);
74 74
75 double static_Qt_qAbs(double a) { return qAbs(a); }
76 double static_Qt_qBound(double a,double b,double c) { return qBound(a,b,c); }
77 void static_Qt_qDebug(const QByteArray& msg) { qDebug(msg.constData()); }
78 // TODO: multi arg qDebug...
79 void static_Qt_qWarning(const QByteArray& msg) { qWarning(msg.constData()); }
80 // TODO: multi arg qWarning...
81 void static_Qt_qCritical(const QByteArray& msg) { qCritical(msg.constData()); }
82 // TODO: multi arg qCritical...
83 void static_Qt_qFatal(const QByteArray& msg) { qFatal(msg.constData()); }
84 // TODO: multi arg qFatal...
85 bool static_Qt_qFuzzyCompare(double a, double b) { return qFuzzyCompare(a, b); }
86 double static_Qt_qMax(double a, double b) { return qMax(a, b); }
87 double static_Qt_qMin(double a, double b) { return qMin(a, b); }
88 int static_Qt_qRound(double a) { return qRound(a); }
89 qint64 static_Qt_qRound64(double a) { return qRound64(a); }
90 const char* static_Qt_qVersion() { return qVersion(); }
91 int static_Qt_qrand() { return qrand(); }
92 void static_Qt_qsrand(uint a) { qsrand(a); }
93
94 QByteArray static_Qt_SIGNAL(const QByteArray& s) { return QByteArray("2") + s; }
95 QByteArray static_Qt_SLOT(const QByteArray& s) { return QByteArray("1") + s; }
96
75 97 //TODO: add findChild/findChildren/children/...
76 98 };
77 99
78 100
79 101 #endif
General Comments 0
You need to be logged in to leave comments. Login now