##// END OF EJS Templates
added static connect/disconnect and dummy emit implementation, added dummy SIGNAL/SLOT functions to namespace...
florianlink -
r61:d314d06796c4
parent child
Show More
@@ -1,1193 +1,1227
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtImporter.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include "PythonQtMethodInfo.h"
46 46 #include "PythonQtSignalReceiver.h"
47 47 #include "PythonQtConversion.h"
48 48 #include "PythonQtStdOut.h"
49 49 #include "PythonQtCppWrapperFactory.h"
50 50 #include "PythonQtVariants.h"
51 51 #include "PythonQtStdDecorators.h"
52 52 #include "PythonQtQFileImporter.h"
53 53 #include <pydebug.h>
54 54 #include <vector>
55 55
56 56 PythonQt* PythonQt::_self = NULL;
57 57 int PythonQt::_uniqueModuleCount = 0;
58 58
59 59 void PythonQt::init(int flags)
60 60 {
61 61 if (!_self) {
62 62 _self = new PythonQt(flags);
63 63 }
64 64
65 65 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
66 66 qRegisterMetaType<QList<QObject*> >("QList<void*>");
67 67
68 68 PythonQtRegisterToolClassesTemplateConverter(int);
69 69 PythonQtRegisterToolClassesTemplateConverter(float);
70 70 PythonQtRegisterToolClassesTemplateConverter(double);
71 71 // TODO: which other POD types should be available for QList etc.
72 72
73 73 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
74 74
75 75 PythonQt::self()->registerCPPClass("Qt", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_Qt>);
76 76 PythonQt::self()->registerCPPClass("QBitArray", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QBitArray>);
77 77 PythonQt::self()->registerCPPClass("QDate", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QDate>);
78 78 PythonQt::self()->registerCPPClass("QTime", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QTime>);
79 79 PythonQt::self()->registerCPPClass("QDateTime", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QDateTime>);
80 80 PythonQt::self()->registerCPPClass("QUrl", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QUrl>);
81 81 PythonQt::self()->registerCPPClass("QLocale", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLocale>);
82 82 PythonQt::self()->registerCPPClass("QRect", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRect>);
83 83 PythonQt::self()->registerCPPClass("QRectF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRectF>);
84 84 PythonQt::self()->registerCPPClass("QSize", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QSize>);
85 85 PythonQt::self()->registerCPPClass("QSizeF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QSizeF>);
86 86 PythonQt::self()->registerCPPClass("QLine", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLine>);
87 87 PythonQt::self()->registerCPPClass("QLineF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLineF>);
88 88 PythonQt::self()->registerCPPClass("QPoint", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QPoint>);
89 89 PythonQt::self()->registerCPPClass("QPointF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QPointF>);
90 90 PythonQt::self()->registerCPPClass("QRegExp", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRegExp>);
91 91
92 92 PythonQtRegisterToolClassesTemplateConverter(QDate);
93 93 PythonQtRegisterToolClassesTemplateConverter(QTime);
94 94 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
95 95 PythonQtRegisterToolClassesTemplateConverter(QUrl);
96 96 PythonQtRegisterToolClassesTemplateConverter(QLocale);
97 97 PythonQtRegisterToolClassesTemplateConverter(QRect);
98 98 PythonQtRegisterToolClassesTemplateConverter(QRectF);
99 99 PythonQtRegisterToolClassesTemplateConverter(QSize);
100 100 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
101 101 PythonQtRegisterToolClassesTemplateConverter(QLine);
102 102 PythonQtRegisterToolClassesTemplateConverter(QLineF);
103 103 PythonQtRegisterToolClassesTemplateConverter(QPoint);
104 104 PythonQtRegisterToolClassesTemplateConverter(QPointF);
105 105 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
106 106
107 107 PythonQt::self()->registerCPPClass("QFont", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QFont>);
108 108 PythonQt::self()->registerCPPClass("QPixmap", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPixmap>);
109 109 PythonQt::self()->registerCPPClass("QBrush", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QBrush>);
110 110 PythonQt::self()->registerCPPClass("QColor", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QColor>);
111 111 PythonQt::self()->registerCPPClass("QPalette", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPalette>);
112 112 PythonQt::self()->registerCPPClass("QIcon", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QIcon>);
113 113 PythonQt::self()->registerCPPClass("QImage", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QImage>);
114 114 PythonQt::self()->registerCPPClass("QPolygon", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPolygon>);
115 115 PythonQt::self()->registerCPPClass("QRegion", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QRegion>);
116 116 PythonQt::self()->registerCPPClass("QBitmap", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QBitmap>);
117 117 PythonQt::self()->registerCPPClass("QCursor", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QCursor>);
118 118 PythonQt::self()->registerCPPClass("QSizePolicy", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QSizePolicy>);
119 119 PythonQt::self()->registerCPPClass("QKeySequence", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QKeySequence>);
120 120 PythonQt::self()->registerCPPClass("QPen", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPen>);
121 121 PythonQt::self()->registerCPPClass("QTextLength", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QTextLength>);
122 122 PythonQt::self()->registerCPPClass("QTextFormat", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QTextFormat>);
123 123 PythonQt::self()->registerCPPClass("QMatrix", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QMatrix>);
124 124
125 125 PythonQtRegisterToolClassesTemplateConverter(QFont);
126 126 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
127 127 PythonQtRegisterToolClassesTemplateConverter(QBrush);
128 128 PythonQtRegisterToolClassesTemplateConverter(QColor);
129 129 PythonQtRegisterToolClassesTemplateConverter(QPalette);
130 130 PythonQtRegisterToolClassesTemplateConverter(QIcon);
131 131 PythonQtRegisterToolClassesTemplateConverter(QImage);
132 132 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
133 133 PythonQtRegisterToolClassesTemplateConverter(QRegion);
134 134 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
135 135 PythonQtRegisterToolClassesTemplateConverter(QCursor);
136 136 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
137 137 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
138 138 PythonQtRegisterToolClassesTemplateConverter(QPen);
139 139 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
140 140 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
141 141 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
142 142
143 143 }
144 144
145 145 void PythonQt::cleanup()
146 146 {
147 147 if (_self) {
148 148 delete _self;
149 149 _self = NULL;
150 150 }
151 151 }
152 152
153 153 PythonQt::PythonQt(int flags)
154 154 {
155 155 _p = new PythonQtPrivate;
156 156 _p->_initFlags = flags;
157 157
158 158 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
159 159
160 160 Py_SetProgramName("PythonQt");
161 161 if (flags & IgnoreSiteModule) {
162 162 // this prevents the automatic importing of Python site files
163 163 Py_NoSiteFlag = 1;
164 164 }
165 165 Py_Initialize();
166 166
167 167 // add our own python object types for qt object slots
168 168 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
169 169 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
170 170 }
171 171 Py_INCREF(&PythonQtSlotFunction_Type);
172 172
173 173 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
174 174 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
175 175 // add our own python object types for classes
176 176 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
177 177 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
178 178 }
179 179 Py_INCREF(&PythonQtClassWrapper_Type);
180 180
181 181 // add our own python object types for CPP instances
182 182 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
183 183 PythonQt::handleError();
184 184 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
185 185 }
186 186 Py_INCREF(&PythonQtInstanceWrapper_Type);
187 187
188 188 // add our own python object types for redirection of stdout
189 189 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
190 190 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
191 191 }
192 192 Py_INCREF(&PythonQtStdOutRedirectType);
193 193
194 194 initPythonQtModule(flags & RedirectStdOut);
195 195
196 196 }
197 197
198 198 PythonQt::~PythonQt() {
199 199 delete _p;
200 200 _p = NULL;
201 201 }
202 202
203 203 PythonQtPrivate::~PythonQtPrivate() {
204 204 delete _defaultImporter;
205 205 _defaultImporter = NULL;
206 206
207 207 {
208 208 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
209 209 while (i.hasNext()) {
210 210 delete i.next().value();
211 211 }
212 212 }
213 213 PythonQtConv::global_valueStorage.clear();
214 214 PythonQtConv::global_ptrStorage.clear();
215 215 PythonQtConv::global_variantStorage.clear();
216 216
217 217 PythonQtMethodInfo::cleanupCachedMethodInfos();
218 218 }
219 219
220 220 PythonQtImportFileInterface* PythonQt::importInterface()
221 221 {
222 222 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
223 223 }
224 224
225 225 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
226 226 {
227 227 if (_self->_p->_noLongerWrappedCB) {
228 228 (*_self->_p->_noLongerWrappedCB)(o);
229 229 };
230 230 }
231 231
232 232 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
233 233 {
234 234 _p->registerClass(metaobject, package, wrapperCreator, shell);
235 235 }
236 236
237 237 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
238 238 {
239 239 // we register all classes in the hierarchy
240 240 const QMetaObject* m = metaobject;
241 241 bool first = true;
242 242 while (m) {
243 243 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
244 244 if (!info->pythonQtClassWrapper()) {
245 245 info->setupQObject(m);
246 246 createPythonQtClassWrapper(info, package);
247 247 if (m->superClass()) {
248 248 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
249 249 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
250 250 }
251 251 }
252 252 if (first) {
253 253 first = false;
254 254 if (wrapperCreator) {
255 255 info->setDecoratorProvider(wrapperCreator);
256 256 }
257 257 if (shell) {
258 258 info->setShellSetInstanceWrapperCB(shell);
259 259 }
260 260 }
261 261 m = m->superClass();
262 262 }
263 263 }
264 264
265 265 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package)
266 266 {
267 267 PyObject* pack = packageByName(package);
268 268 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, package);
269 269 PyModule_AddObject(pack, info->className(), pyobj);
270 270 if (package && strncmp(package,"Qt",2)==0) {
271 271 // since PyModule_AddObject steals the reference, we need a incref once more...
272 272 Py_INCREF(pyobj);
273 273 // put all qt objects into Qt as well
274 274 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
275 275 }
276 276 info->setPythonQtClassWrapper(pyobj);
277 277 }
278 278
279 279 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
280 280 {
281 281 if (!obj) {
282 282 Py_INCREF(Py_None);
283 283 return Py_None;
284 284 }
285 285 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
286 286 if (!wrap) {
287 287 // smuggling it in...
288 288 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
289 289 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
290 290 registerClass(obj->metaObject());
291 291 classInfo = _knownClassInfos.value(obj->metaObject()->className());
292 292 }
293 293 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
294 294 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
295 295 } else {
296 296 Py_INCREF(wrap);
297 297 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
298 298 }
299 299 return (PyObject*)wrap;
300 300 }
301 301
302 302 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
303 303 {
304 304 if (!ptr) {
305 305 Py_INCREF(Py_None);
306 306 return Py_None;
307 307 }
308 308
309 309 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
310 310 if (!wrap) {
311 311 PythonQtClassInfo* info = _knownClassInfos.value(name);
312 312 if (!info) {
313 313 // maybe it is a PyObject, which we can return directly
314 314 if (name == "PyObject") {
315 315 PyObject* p = (PyObject*)ptr;
316 316 Py_INCREF(p);
317 317 return p;
318 318 }
319 319
320 320 // we do not know the metaobject yet, but we might know it by it's name:
321 321 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
322 322 // yes, we know it, so we can convert to QObject
323 323 QObject* qptr = (QObject*)ptr;
324 324 registerClass(qptr->metaObject());
325 325 info = _knownClassInfos.value(qptr->metaObject()->className());
326 326 }
327 327 }
328 328 if (info && info->isQObject()) {
329 329 QObject* qptr = (QObject*)ptr;
330 330 // if the object is a derived object, we want to switch the class info to the one of the derived class:
331 331 if (name!=(qptr->metaObject()->className())) {
332 332 registerClass(qptr->metaObject());
333 333 info = _knownClassInfos.value(qptr->metaObject()->className());
334 334 }
335 335 wrap = createNewPythonQtInstanceWrapper(qptr, info);
336 336 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
337 337 return (PyObject*)wrap;
338 338 }
339 339
340 340 // not a known QObject, so try our wrapper factory:
341 341 QObject* wrapper = NULL;
342 342 for (int i=0; i<_cppWrapperFactories.size(); i++) {
343 343 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
344 344 if (wrapper) {
345 345 break;
346 346 }
347 347 }
348 348
349 349 if (info) {
350 350 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
351 351 ptr = info->castDownIfPossible(ptr, &info);
352 352 }
353 353
354 354 if (!info || info->pythonQtClassWrapper()==NULL) {
355 355 // still unknown, register as CPP class
356 356 registerCPPClass(name.constData());
357 357 info = _knownClassInfos.value(name);
358 358 }
359 359 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
360 360 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
361 361 info->setMetaObject(wrapper->metaObject());
362 362 }
363 363 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
364 364 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
365 365 } else {
366 366 Py_INCREF(wrap);
367 367 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
368 368 }
369 369 return (PyObject*)wrap;
370 370 }
371 371
372 372 PyObject* PythonQtPrivate::dummyTuple() {
373 373 static PyObject* dummyTuple = NULL;
374 374 if (dummyTuple==NULL) {
375 375 dummyTuple = PyTuple_New(1);
376 376 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
377 377 }
378 378 return dummyTuple;
379 379 }
380 380
381 381
382 382 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
383 383 // call the associated class type to create a new instance...
384 384 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
385 385
386 386 result->setQObject(obj);
387 387 result->_wrappedPtr = wrappedPtr;
388 388 result->_ownedByPythonQt = false;
389 389 result->_useQMetaTypeDestroy = false;
390 390
391 391 if (wrappedPtr) {
392 392 _wrappedObjects.insert(wrappedPtr, result);
393 393 } else {
394 394 _wrappedObjects.insert(obj, result);
395 395 if (obj->parent()== NULL && _wrappedCB) {
396 396 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
397 397 (*_wrappedCB)(obj);
398 398 }
399 399 }
400 400 return result;
401 401 }
402 402
403 403 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package) {
404 404 PythonQtClassWrapper* result;
405 405
406 406 PyObject* className = PyString_FromString(info->className());
407 407
408 408 PyObject* baseClasses = PyTuple_New(1);
409 409 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
410 410
411 411 PyObject* typeDict = PyDict_New();
412 412 QByteArray moduleName("PythonQt");
413 413 if (package && strcmp(package, "")!=0) {
414 414 moduleName += ".";
415 415 moduleName += package;
416 416 }
417 417 PyDict_SetItemString(typeDict, "__module__", PyString_FromString(moduleName.constData()));
418 418
419 419 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
420 420
421 421 // set the class info so that PythonQtClassWrapper_new can read it
422 422 _currentClassInfoForClassWrapperCreation = info;
423 423 // create the new type object by calling the type
424 424 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
425 425
426 426 Py_DECREF(baseClasses);
427 427 Py_DECREF(typeDict);
428 428 Py_DECREF(args);
429 429 Py_DECREF(className);
430 430
431 431 return result;
432 432 }
433 433
434 434 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
435 435 {
436 436 PyObject* args = Py_BuildValue("(i)", enumValue);
437 437 PyObject* result = PyObject_Call(enumType, args, NULL);
438 438 Py_DECREF(args);
439 439 return result;
440 440 }
441 441
442 442 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
443 443 PyObject* result;
444 444
445 445 PyObject* className = PyString_FromString(enumName);
446 446
447 447 PyObject* baseClasses = PyTuple_New(1);
448 448 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
449 449
450 450 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
451 451 PyObject* typeDict = PyDict_New();
452 452 PyDict_SetItemString(typeDict, "__module__", module);
453 453
454 454 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
455 455
456 456 // create the new int derived type object by calling the core type
457 457 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
458 458
459 459 Py_DECREF(baseClasses);
460 460 Py_DECREF(typeDict);
461 461 Py_DECREF(args);
462 462 Py_DECREF(className);
463 463
464 464 return result;
465 465 }
466 466
467 467 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
468 468 {
469 469 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
470 470 if (!r) {
471 471 r = new PythonQtSignalReceiver(obj);
472 472 _p->_signalReceivers.insert(obj, r);
473 473 }
474 474 return r;
475 475 }
476 476
477 477 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
478 478 {
479 479 bool flag = false;
480 480 PythonQtObjectPtr callable = lookupCallable(module, objectname);
481 481 if (callable) {
482 482 PythonQtSignalReceiver* r = getSignalReceiver(obj);
483 483 flag = r->addSignalHandler(signal, callable);
484 484 if (!flag) {
485 485 // signal not found
486 486 }
487 487 } else {
488 488 // callable not found
489 489 }
490 490 return flag;
491 491 }
492 492
493 493 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
494 494 {
495 495 bool flag = false;
496 496 PythonQtSignalReceiver* r = getSignalReceiver(obj);
497 497 if (r) {
498 498 flag = r->addSignalHandler(signal, receiver);
499 499 }
500 500 return flag;
501 501 }
502 502
503 503 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
504 504 {
505 505 bool flag = false;
506 506 PythonQtObjectPtr callable = lookupCallable(module, objectname);
507 507 if (callable) {
508 508 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
509 509 if (r) {
510 510 flag = r->removeSignalHandler(signal, callable);
511 511 }
512 512 } else {
513 513 // callable not found
514 514 }
515 515 return flag;
516 516 }
517 517
518 518 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
519 519 {
520 520 bool flag = false;
521 521 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
522 522 if (r) {
523 523 flag = r->removeSignalHandler(signal, receiver);
524 524 }
525 525 return flag;
526 526 }
527 527
528 528 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
529 529 {
530 530 PythonQtObjectPtr p = lookupObject(module, name);
531 531 if (p) {
532 532 if (PyCallable_Check(p)) {
533 533 return p;
534 534 }
535 535 }
536 536 PyErr_Clear();
537 537 return NULL;
538 538 }
539 539
540 540 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
541 541 {
542 542 QStringList l = name.split('.');
543 543 PythonQtObjectPtr p = module;
544 544 PythonQtObjectPtr prev;
545 545 QString s;
546 546 QByteArray b;
547 547 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
548 548 prev = p;
549 549 b = (*i).toLatin1();
550 550 if (PyDict_Check(p)) {
551 551 p = PyDict_GetItemString(p, b.data());
552 552 } else {
553 553 p.setNewRef(PyObject_GetAttrString(p, b.data()));
554 554 }
555 555 }
556 556 PyErr_Clear();
557 557 return p;
558 558 }
559 559
560 560 PythonQtObjectPtr PythonQt::getMainModule() {
561 561 //both borrowed
562 562 PythonQtObjectPtr dict = PyImport_GetModuleDict();
563 563 return PyDict_GetItemString(dict, "__main__");
564 564 }
565 565
566 566 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
567 567 QVariant result;
568 568 if (pycode) {
569 569 PyObject* dict = NULL;
570 570 if (PyModule_Check(object)) {
571 571 dict = PyModule_GetDict(object);
572 572 } else if (PyDict_Check(object)) {
573 573 dict = object;
574 574 }
575 575 PyObject* r = NULL;
576 576 if (dict) {
577 577 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
578 578 }
579 579 if (r) {
580 580 result = PythonQtConv::PyObjToQVariant(r);
581 581 Py_DECREF(r);
582 582 } else {
583 583 handleError();
584 584 }
585 585 } else {
586 586 handleError();
587 587 }
588 588 return result;
589 589 }
590 590
591 591 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
592 592 {
593 593 QVariant result;
594 594 PythonQtObjectPtr p;
595 595 PyObject* dict = NULL;
596 596 if (PyModule_Check(object)) {
597 597 dict = PyModule_GetDict(object);
598 598 } else if (PyDict_Check(object)) {
599 599 dict = object;
600 600 }
601 601 if (dict) {
602 602 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
603 603 }
604 604 if (p) {
605 605 result = PythonQtConv::PyObjToQVariant(p);
606 606 } else {
607 607 handleError();
608 608 }
609 609 return result;
610 610 }
611 611
612 612 void PythonQt::evalFile(PyObject* module, const QString& filename)
613 613 {
614 614 PythonQtObjectPtr code = parseFile(filename);
615 615 if (code) {
616 616 evalCode(module, code);
617 617 } else {
618 618 handleError();
619 619 }
620 620 }
621 621
622 622 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
623 623 {
624 624 PythonQtObjectPtr p;
625 625 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
626 626 if (!p) {
627 627 handleError();
628 628 }
629 629 return p;
630 630 }
631 631
632 632 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
633 633 {
634 634 PythonQtObjectPtr code = parseFile(filename);
635 635 PythonQtObjectPtr module = _p->createModule(name, code);
636 636 return module;
637 637 }
638 638
639 639 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
640 640 {
641 641 PyErr_Clear();
642 642 QString scriptCode = script;
643 643 if (scriptCode.isEmpty()) {
644 644 // we always need at least a linefeed
645 645 scriptCode = "\n";
646 646 }
647 647 PythonQtObjectPtr pycode;
648 648 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
649 649 PythonQtObjectPtr module = _p->createModule(name, pycode);
650 650 return module;
651 651 }
652 652
653 653 PythonQtObjectPtr PythonQt::createUniqueModule()
654 654 {
655 655 static QString pyQtStr("PythonQt_module");
656 656 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
657 657 return createModuleFromScript(moduleName);
658 658 }
659 659
660 660 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
661 661 {
662 662 if (PyModule_Check(object)) {
663 663 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
664 664 } else if (PyDict_Check(object)) {
665 665 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
666 666 } else {
667 667 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
668 668 }
669 669 }
670 670
671 671 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
672 672 {
673 673 if (PyModule_Check(object)) {
674 674 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
675 675 } else if (PyDict_Check(object)) {
676 676 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
677 677 } else {
678 678 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
679 679 }
680 680 }
681 681
682 682 void PythonQt::removeVariable(PyObject* object, const QString& name)
683 683 {
684 684 if (PyDict_Check(object)) {
685 685 PyDict_DelItemString(object, name.toLatin1().data());
686 686 } else {
687 687 PyObject_DelAttrString(object, name.toLatin1().data());
688 688 }
689 689 }
690 690
691 691 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
692 692 {
693 693 QVariant result;
694 694 PythonQtObjectPtr obj = lookupObject(object, objectname);
695 695 if (obj) {
696 696 result = PythonQtConv::PyObjToQVariant(obj);
697 697 }
698 698 return result;
699 699 }
700 700
701 701 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
702 702 {
703 703 QStringList results;
704 704
705 705 PythonQtObjectPtr object;
706 706 if (objectname.isEmpty()) {
707 707 object = module;
708 708 } else {
709 709 object = lookupObject(module, objectname);
710 710 if (!object && type == CallOverloads) {
711 711 PyObject* dict = lookupObject(module, "__builtins__");
712 712 if (dict) {
713 713 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
714 714 }
715 715 }
716 716 }
717 717
718 718 if (object) {
719 719 if (type == CallOverloads) {
720 720 if (PythonQtSlotFunction_Check(object)) {
721 721 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
722 722 PythonQtSlotInfo* info = o->m_ml;
723 723
724 724 while (info) {
725 725 results << info->fullSignature();
726 726 info = info->nextInfo();
727 727 }
728 728 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
729 729 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
730 730 PythonQtSlotInfo* info = o->classInfo()->constructors();
731 731
732 732 while (info) {
733 733 results << info->fullSignature();
734 734 info = info->nextInfo();
735 735 }
736 736 } else {
737 737 //TODO: use pydoc!
738 738 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
739 739 if (doc) {
740 740 results << PyString_AsString(doc);
741 741 Py_DECREF(doc);
742 742 }
743 743 }
744 744 } else {
745 745 PyObject* keys = NULL;
746 746 bool isDict = false;
747 747 if (PyDict_Check(object)) {
748 748 keys = PyDict_Keys(object);
749 749 isDict = true;
750 750 } else {
751 751 keys = PyObject_Dir(object);
752 752 }
753 753 if (keys) {
754 754 int count = PyList_Size(keys);
755 755 PyObject* key;
756 756 PyObject* value;
757 757 QString keystr;
758 758 for (int i = 0;i<count;i++) {
759 759 key = PyList_GetItem(keys,i);
760 760 if (isDict) {
761 761 value = PyDict_GetItem(object, key);
762 762 Py_INCREF(value);
763 763 } else {
764 764 value = PyObject_GetAttr(object, key);
765 765 }
766 766 if (!value) continue;
767 767 keystr = PyString_AsString(key);
768 768 static const QString underscoreStr("__tmp");
769 769 if (!keystr.startsWith(underscoreStr)) {
770 770 switch (type) {
771 771 case Anything:
772 772 results << keystr;
773 773 break;
774 774 case Class:
775 775 if (value->ob_type == &PyClass_Type) {
776 776 results << keystr;
777 777 }
778 778 break;
779 779 case Variable:
780 780 if (value->ob_type != &PyClass_Type
781 781 && value->ob_type != &PyCFunction_Type
782 782 && value->ob_type != &PyFunction_Type
783 783 && value->ob_type != &PyModule_Type
784 784 ) {
785 785 results << keystr;
786 786 }
787 787 break;
788 788 case Function:
789 789 if (value->ob_type == &PyFunction_Type ||
790 790 value->ob_type == &PyMethod_Type
791 791 ) {
792 792 results << keystr;
793 793 }
794 794 break;
795 795 case Module:
796 796 if (value->ob_type == &PyModule_Type) {
797 797 results << keystr;
798 798 }
799 799 break;
800 800 default:
801 801 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
802 802 }
803 803 }
804 804 Py_DECREF(value);
805 805 }
806 806 Py_DECREF(keys);
807 807 }
808 808 }
809 809 }
810 810 return results;
811 811 }
812 812
813 813 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
814 814 {
815 815 PythonQtObjectPtr callable = lookupCallable(object, name);
816 816 if (callable) {
817 817 return call(callable, args);
818 818 } else {
819 819 return QVariant();
820 820 }
821 821 }
822 822
823 823 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
824 824 {
825 825 QVariant r;
826 826 if (callable) {
827 827 PythonQtObjectPtr pargs;
828 828 int count = args.size();
829 829 if (count>0) {
830 830 pargs.setNewRef(PyTuple_New(count));
831 831 }
832 832 bool err = false;
833 833 // transform QVariants to Python
834 834 for (int i = 0; i < count; i++) {
835 835 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
836 836 if (arg) {
837 837 // steals reference, no unref
838 838 PyTuple_SetItem(pargs, i,arg);
839 839 } else {
840 840 err = true;
841 841 break;
842 842 }
843 843 }
844 844
845 845 if (!err) {
846 846 PyErr_Clear();
847 847 PythonQtObjectPtr result;
848 848 result.setNewRef(PyObject_CallObject(callable, pargs));
849 849 if (result) {
850 850 // ok
851 851 r = PythonQtConv::PyObjToQVariant(result);
852 852 } else {
853 853 PythonQt::self()->handleError();
854 854 }
855 855 }
856 856 }
857 857 return r;
858 858 }
859 859
860 860 void PythonQt::addInstanceDecorators(QObject* o)
861 861 {
862 862 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
863 863 }
864 864
865 865 void PythonQt::addClassDecorators(QObject* o)
866 866 {
867 867 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
868 868 }
869 869
870 870 void PythonQt::addDecorators(QObject* o)
871 871 {
872 872 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
873 873 }
874 874
875 875 void PythonQt::registerQObjectClassNames(const QStringList& names)
876 876 {
877 877 _p->registerQObjectClassNames(names);
878 878 }
879 879
880 880 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
881 881 {
882 882 PythonQtImport::init();
883 883 _p->_importInterface = importInterface;
884 884 }
885 885
886 886 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
887 887 {
888 888 _p->_importIgnorePaths = paths;
889 889 }
890 890
891 891 const QStringList& PythonQt::getImporterIgnorePaths()
892 892 {
893 893 return _p->_importIgnorePaths;
894 894 }
895 895
896 896 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
897 897 {
898 898 _p->_cppWrapperFactories.append(factory);
899 899 }
900 900
901 901 //---------------------------------------------------------------------------------------------------
902 902 PythonQtPrivate::PythonQtPrivate()
903 903 {
904 904 _importInterface = NULL;
905 905 _defaultImporter = new PythonQtQFileImporter;
906 906 _noLongerWrappedCB = NULL;
907 907 _wrappedCB = NULL;
908 908 _currentClassInfoForClassWrapperCreation = NULL;
909 909 }
910 910
911 911 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
912 912 {
913 913 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
914 914 _currentClassInfoForClassWrapperCreation = NULL;
915 915 return info;
916 916 }
917 917
918 918 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
919 919 {
920 920 o->setParent(this);
921 921 int numMethods = o->metaObject()->methodCount();
922 922 for (int i = 0; i < numMethods; i++) {
923 923 QMetaMethod m = o->metaObject()->method(i);
924 924 if ((m.methodType() == QMetaMethod::Method ||
925 925 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
926 926 if (qstrncmp(m.signature(), "new_", 4)==0) {
927 927 if ((decoTypes & ConstructorDecorator) == 0) continue;
928 928 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
929 929 if (info->parameters().at(0).isPointer) {
930 930 QByteArray signature = m.signature();
931 931 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
932 932 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
933 933 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
934 934 classInfo->addConstructor(newSlot);
935 935 }
936 936 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
937 937 if ((decoTypes & DestructorDecorator) == 0) continue;
938 938 QByteArray signature = m.signature();
939 939 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
940 940 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
941 941 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
942 942 classInfo->setDestructor(newSlot);
943 943 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
944 944 if ((decoTypes & StaticDecorator) == 0) continue;
945 945 QByteArray signature = m.signature();
946 946 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
947 947 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
948 948 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
949 949 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
950 950 classInfo->addDecoratorSlot(newSlot);
951 951 } else {
952 952 if ((decoTypes & InstanceDecorator) == 0) continue;
953 953 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
954 954 if (info->parameters().count()>1) {
955 955 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
956 956 if (p.isPointer) {
957 957 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
958 958 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
959 959 classInfo->addDecoratorSlot(newSlot);
960 960 }
961 961 }
962 962 }
963 963 }
964 964 }
965 965 }
966 966
967 967 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
968 968 {
969 969 foreach(QString name, names) {
970 970 _knownQObjectClassNames.insert(name.toLatin1(), true);
971 971 }
972 972 }
973 973
974 974 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
975 975 {
976 976 _signalReceivers.remove(obj);
977 977 }
978 978
979 979 bool PythonQt::handleError()
980 980 {
981 981 bool flag = false;
982 982 if (PyErr_Occurred()) {
983 983
984 984 // currently we just print the error and the stderr handler parses the errors
985 985 PyErr_Print();
986 986
987 987 /*
988 988 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
989 989 PyObject *ptype;
990 990 PyObject *pvalue;
991 991 PyObject *ptraceback;
992 992 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
993 993
994 994 Py_XDECREF(ptype);
995 995 Py_XDECREF(pvalue);
996 996 Py_XDECREF(ptraceback);
997 997 */
998 998 PyErr_Clear();
999 999 flag = true;
1000 1000 }
1001 1001 return flag;
1002 1002 }
1003 1003
1004 1004 void PythonQt::addSysPath(const QString& path)
1005 1005 {
1006 1006 PythonQtObjectPtr sys;
1007 1007 sys.setNewRef(PyImport_ImportModule("sys"));
1008 1008 PythonQtObjectPtr obj = lookupObject(sys, "path");
1009 1009 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1010 1010 }
1011 1011
1012 1012 void PythonQt::overwriteSysPath(const QStringList& paths)
1013 1013 {
1014 1014 PythonQtObjectPtr sys;
1015 1015 sys.setNewRef(PyImport_ImportModule("sys"));
1016 1016 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1017 1017 }
1018 1018
1019 1019 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1020 1020 {
1021 1021 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1022 1022 }
1023 1023
1024 1024 void PythonQt::stdOutRedirectCB(const QString& str)
1025 1025 {
1026 1026 emit PythonQt::self()->pythonStdOut(str);
1027 1027 }
1028 1028
1029 1029 void PythonQt::stdErrRedirectCB(const QString& str)
1030 1030 {
1031 1031 emit PythonQt::self()->pythonStdErr(str);
1032 1032 }
1033 1033
1034 1034 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1035 1035 {
1036 1036 _p->_wrappedCB = cb;
1037 1037 }
1038 1038
1039 1039 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1040 1040 {
1041 1041 _p->_noLongerWrappedCB = cb;
1042 1042 }
1043 1043
1044 1044
1045 1045
1046 1046 static PyMethodDef PythonQtMethods[] = {
1047 1047 {NULL, NULL, 0, NULL}
1048 1048 };
1049 1049
1050 1050 void PythonQt::initPythonQtModule(bool redirectStdOut)
1051 1051 {
1052 1052 _p->_pythonQtModule = Py_InitModule("PythonQt", PythonQtMethods);
1053 1053
1054 1054 if (redirectStdOut) {
1055 1055 PythonQtObjectPtr sys;
1056 1056 PythonQtObjectPtr out;
1057 1057 PythonQtObjectPtr err;
1058 1058 sys.setNewRef(PyImport_ImportModule("sys"));
1059 1059 // create a redirection object for stdout and stderr
1060 1060 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1061 1061 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1062 1062 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1063 1063 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1064 1064 // replace the built in file objects with our own objects
1065 1065 PyModule_AddObject(sys, "stdout", out);
1066 1066 PyModule_AddObject(sys, "stderr", err);
1067 1067 }
1068 1068 }
1069 1069
1070 1070 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1071 1071 {
1072 1072 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1073 1073 }
1074 1074
1075 1075
1076 1076 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1077 1077 {
1078 1078 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1079 1079 if (!info) {
1080 1080 info = new PythonQtClassInfo();
1081 1081 info->setupCPPObject(typeName);
1082 1082 _knownClassInfos.insert(typeName, info);
1083 1083 }
1084 1084 return info;
1085 1085 }
1086 1086
1087 1087 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1088 1088 {
1089 1089 _p->addPolymorphicHandler(typeName, cb);
1090 1090 }
1091 1091
1092 1092 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1093 1093 {
1094 1094 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1095 1095 info->addPolymorphicHandler(cb);
1096 1096 }
1097 1097
1098 1098 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1099 1099 {
1100 1100 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1101 1101 }
1102 1102
1103 1103 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1104 1104 {
1105 1105 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1106 1106 if (info) {
1107 1107 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1108 1108 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1109 1109 return true;
1110 1110 } else {
1111 1111 return false;
1112 1112 }
1113 1113 }
1114 1114
1115 1115 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1116 1116 {
1117 1117 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1118 1118 if (!info->pythonQtClassWrapper()) {
1119 1119 info->setupCPPObject(typeName);
1120 1120 createPythonQtClassWrapper(info, package);
1121 1121 }
1122 1122 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1123 1123 addParentClass(typeName, parentTypeName, 0);
1124 1124 }
1125 1125 if (wrapperCreator) {
1126 1126 info->setDecoratorProvider(wrapperCreator);
1127 1127 }
1128 1128 if (shell) {
1129 1129 info->setShellSetInstanceWrapperCB(shell);
1130 1130 }
1131 1131 }
1132 1132
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(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(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
1133 1162 PyObject* PythonQtPrivate::packageByName(const char* name)
1134 1163 {
1135 1164 if (name==NULL || name[0]==0) {
1136 1165 return _pythonQtModule;
1137 1166 }
1138 1167 PyObject* v = _packages.value(name);
1139 1168 if (!v) {
1140 1169 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 }
1141 1175 _packages.insert(name, v);
1142 1176 // AddObject steals the reference, so increment it!
1143 1177 Py_INCREF(v);
1144 1178 PyModule_AddObject(_pythonQtModule, name, v);
1145 1179 }
1146 1180 return v;
1147 1181 }
1148 1182
1149 1183
1150 1184 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1151 1185 {
1152 1186 if (_p->_initFlags & ExternalHelp) {
1153 1187 emit pythonHelpRequest(QByteArray(info->className()));
1154 1188 return Py_BuildValue("");
1155 1189 } else {
1156 1190 return PyString_FromString(info->help().toLatin1().data());
1157 1191 }
1158 1192 }
1159 1193
1160 1194 void PythonQtPrivate::removeWrapperPointer(void* obj)
1161 1195 {
1162 1196 _wrappedObjects.remove(obj);
1163 1197 }
1164 1198
1165 1199 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1166 1200 {
1167 1201 _wrappedObjects.insert(obj, wrapper);
1168 1202 }
1169 1203
1170 1204 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1171 1205 {
1172 1206 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1173 1207 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1174 1208 // this is a wrapper whose QObject was already removed due to destruction
1175 1209 // so the obj pointer has to be a new QObject with the same address...
1176 1210 // we remove the old one and set the copy to NULL
1177 1211 wrap->_objPointerCopy = NULL;
1178 1212 removeWrapperPointer(obj);
1179 1213 wrap = NULL;
1180 1214 }
1181 1215 return wrap;
1182 1216 }
1183 1217
1184 1218 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1185 1219 {
1186 1220 PythonQtObjectPtr result;
1187 1221 if (pycode) {
1188 1222 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1189 1223 } else {
1190 1224 PythonQt::self()->handleError();
1191 1225 }
1192 1226 return result;
1193 1227 }
@@ -1,509 +1,511
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 - PythonQt is not as Pythonic as PyQt in many details (e.g. operator mapping, pickling, translation support, ...) and it is maily thought for embedding and intercommunication between Qt/Cpp and Python
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 - PythonQt does not (yet?) offer QtCore.SIGNAL() and QtCore.SLOT() methods, connect and disconnect just take strings for signals and slots
147 - QObject.emit to emit Qt signals from Python is not yet possible
146 - PythonQt offer QtCore.SIGNAL() and QtCore.SLOT() methods for compability, but no 0/1/3 is prepended
147 - PythonQt does not support instanceof checks for Qt classes, except for the exact match and derived Python classes
148 - QObject.emit to emit Qt signals from Python is not yet implemented
149 - PythonQt does not offer to add new signals to Python/C++ objects
148 150 - 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)
149 151 - Probably there are lots of details that differ, I do not know PyQt that well to list them all.
150 152
151 153
152 154 \section Interface
153 155
154 156 The main interface to PythonQt is the PythonQt singleton.
155 157 PythonQt needs to be initialized via PythonQt::init() once.
156 158 Afterwards you communicate with the singleton via PythonQt::self().
157 159 PythonQt offers a complete Qt binding, which
158 160 needs to be enabled via PythonQt_QtAll::init().
159 161
160 162
161 163 \section Datatype Datatype Mapping
162 164
163 165 The following table shows the mapping between Python and Qt objects:
164 166 <table>
165 167 <tr><th>Qt/C++</th><th>Python</th></tr>
166 168 <tr><td>bool</td><td>bool</td></tr>
167 169 <tr><td>double</td><td>float</td></tr>
168 170 <tr><td>float</td><td>float</td></tr>
169 171 <tr><td>char/uchar,int/uint,short,ushort,QChar</td><td>integer</td></tr>
170 172 <tr><td>long</td><td>integer</td></tr>
171 173 <tr><td>ulong,longlong,ulonglong</td><td>long</td></tr>
172 174 <tr><td>QString</td><td>unicode string</td></tr>
173 175 <tr><td>QByteArray</td><td>str</td></tr>
174 176 <tr><td>char*</td><td>str</td></tr>
175 177 <tr><td>QStringList</td><td>tuple of unicode strings</td></tr>
176 178 <tr><td>QVariantList</td><td>tuple of objects</td></tr>
177 179 <tr><td>QVariantMap</td><td>dict of objects</td></tr>
178 180 <tr><td>QVariant</td><td>depends on type, see below</td></tr>
179 181 <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>
180 182 <tr><td>OwnRegisteredMetaType</td><td>C++ wrapper, optionally with additional information/wrapping provided by registerCPPClass()</td></tr>
181 183 <tr><td>QList<AnyObject*></td><td>converts to a list of CPP wrappers</td></tr>
182 184 <tr><td>EnumType</td><td>integer (all enums that are known via the moc and the Qt namespace are supported)</td></tr>
183 185 <tr><td>QObject (and derived classes)</td><td>QObject wrapper</td></tr>
184 186 <tr><td>C++ object</td><td>CPP wrapper, either wrapped via PythonQtCppWrapperFactory or just decorated with decorators</td></tr>
185 187 <tr><td>PyObject</td><td>PyObject</td></tr>
186 188 </table>
187 189
188 190 PyObject is passed as simple pointer, which allows to pass/return any Python Object directly to/from
189 191 a Qt slot.
190 192 QVariants are mapped recursively as given above, e.g. a dictionary can
191 193 contain lists of dictionaries of doubles.
192 194 For example a QVariant of type "String" is mapped to a python unicode string.
193 195 All Qt QVariant types are implemented, PythonQt supports the complete Qt API for these object.
194 196
195 197 \section QObject QObject Wrapping
196 198
197 199 All classes derived from QObject are automatically wrapped with a python wrapper class
198 200 when they become visible to the Python interpreter. This can happen via
199 201 - the PythonQt::addObject() method
200 202 - when a Qt \b slot returns a QObject derived object to python
201 203 - when a Qt \b signal contains a QObject and is connected to a python function
202 204
203 205 It is important that you call PythonQt::registerClass() for any QObject derived class
204 206 that may become visible to Python, except when you add it via PythonQt::addObject().
205 207 This will register the complete parent hierachy of the registered class, so that
206 208 when you register e.g. a QPushButton, QWidget will be registered as well (and all intermediate
207 209 parents).
208 210
209 211 From Python, you can talk to the returned QObjects in a natural way by calling
210 212 their slots and receiving the return values. You can also read/write all
211 213 properties of the objects as if they where normal python properties.
212 214
213 215 In addition to this, the wrapped objects support
214 216 - className() - returns a string that reprents the classname of the QObject
215 217 - help() - shows all properties, slots, enums, decorator slots and constructors of the object, in a printable form
216 218 - delete() - deletes the object (use with care, especially if you passed the ownership to C++)
217 219 - connect(signal, function) - connect the signal of the given object to a python function
218 220 - connect(signal, qobject, slot) - connect the signal of the given object to a slot of another QObject
219 221 - disconnect(signal, function) - disconnect the signal of the given object from a python function
220 222 - disconnect(signal, qobject, slot) - disconnect the signal of the given object from a slot of another QObject
221 223 - children() - returns the children of the object
222 224 - setParent(QObject) - set the parent
223 225 - QObject* parent() - get the parent
224 226
225 227 The below example shows how to connect signals in Python:
226 228
227 229 \code
228 230 # define a signal handler function
229 231 def someFunction(flag):
230 232 print flag
231 233
232 234 # button1 is a QPushButton that has been added to Python via addObject()
233 235 # connect the clicked signal to a python function:
234 236 button1.connect("clicked(bool)", someFunction)
235 237
236 238 \endcode
237 239
238 240 \section CPP CPP Wrapping
239 241
240 242 You can create dedicated wrapper QObjects for any C++ class. This is done by deriving from PythonQtCppWrapperFactory
241 243 and adding your factory via addWrapperFactory().
242 244 Whenever PythonQt encounters a CPP pointer (e.g. on a slot or signal)
243 245 and it does not known it as a QObject derived class, it will create a generic CPP wrapper. So even unknown C++ objects
244 246 can be passed through Python. If the wrapper factory supports the CPP class, a QObject wrapper will be created for each
245 247 instance that enters Python. An alternative to a complete wrapper via the wrapper factory are decorators, see \ref Decorators
246 248
247 249 \section MetaObject Meta Object/Class access
248 250
249 251 For each known C++ class, PythonQt provides a Python class. These classes are visible
250 252 inside of the "PythonQt" python module or in subpackages if a package is given when the class is registered.
251 253
252 254 A Meta class supports:
253 255
254 256 - access to all declared enum values
255 257 - constructors
256 258 - static methods
257 259 - unbound non-static methods
258 260 - help() and className()
259 261
260 262 From within Python, you can import the module "PythonQt" to access these classes and the Qt namespace.
261 263
262 264 \code
263 265 from PythonQt import QtCore
264 266
265 267 # namespace access:
266 268 print QtCore.Qt.AlignLeft
267 269
268 270 # constructors
269 271 a = QtCore.QSize(12,13)
270 272 b = QtCore.QFont()
271 273
272 274 # static method
273 275 QtCore.QDate.currentDate()
274 276
275 277 # enum value
276 278 QtCore.QFont.UltraCondensed
277 279
278 280 \endcode
279 281
280 282 \section Decorators Decorator slots
281 283
282 284 PythonQt introduces a new generic approach to extend any wrapped QObject or CPP object with
283 285
284 286 - constructors
285 287 - destructors (for CPP objects)
286 288 - additional slots
287 289 - static slots (callable on both the Meta object and the instances)
288 290
289 291 The idea behind decorators is that we wanted to make it as easy as possible to extend
290 292 wrapped objects. Since we already have an implementation for invoking any Qt Slot from
291 293 Python, it looked promising to use this approach for the extension of wrapped objects as well.
292 294 This avoids that the PythonQt user needs to care about how Python arguments are mapped from/to
293 295 Qt when he wants to create static methods, constructors and additional member functions.
294 296
295 297 The basic idea about decorators is to create a QObject derived class that implements slots
296 298 which take one of the above roles (e.g. constructor, destructor etc.) via a naming convention.
297 299 These slots are then assigned to other classes via the naming convention.
298 300
299 301 - 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)
300 302 - void delete_SomeClassName(SomeClassName* o) - defines a destructor, which should delete the passed in object o
301 303 - anything static_SomeClassName_someMethodName(...) - defines a static method that is callable on instances and the meta class
302 304 - 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.
303 305
304 306 The below example shows all kinds of decorators in action:
305 307
306 308 \code
307 309
308 310 // an example CPP object
309 311 class YourCPPObject {
310 312 public:
311 313 YourCPPObject(int arg1, float arg2) { a = arg1; b = arg2; }
312 314
313 315 float doSomething(int arg1) { return arg1*a*b; };
314 316
315 317 private:
316 318
317 319 int a;
318 320 float b;
319 321 };
320 322
321 323 // an example decorator
322 324 class ExampleDecorator : public QObject
323 325 {
324 326 Q_OBJECT
325 327
326 328 public slots:
327 329 // add a constructor to QSize that takes a QPoint
328 330 QSize* new_QSize(const QPoint& p) { return new QSize(p.x(), p.y()); }
329 331
330 332 // add a constructor for QPushButton that takes a text and a parent widget
331 333 QPushButton* new_QPushButton(const QString& text, QWidget* parent=NULL) { return new QPushButton(text, parent); }
332 334
333 335 // add a constructor for a CPP object
334 336 YourCPPObject* new_YourCPPObject(int arg1, float arg2) { return new YourCPPObject(arg1, arg2); }
335 337
336 338 // add a destructor for a CPP object
337 339 void delete_YourCPPObject(YourCPPObject* obj) { delete obj; }
338 340
339 341 // add a static method to QWidget
340 342 QWidget* static_QWidget_mouseGrabber() { return QWidget::mouseGrabber(); }
341 343
342 344 // add an additional slot to QWidget (make move() callable, which is not declared as a slot in QWidget)
343 345 void move(QWidget* w, const QPoint& p) { w->move(p); }
344 346
345 347 // add an additional slot to QWidget, overloading the above move method
346 348 void move(QWidget* w, int x, int y) { w->move(x,y); }
347 349
348 350 // add a method to your own CPP object
349 351 int doSomething(YourCPPObject* obj, int arg1) { return obj->doSomething(arg1); }
350 352 };
351 353
352 354 ...
353 355
354 356 PythonQt::self()->addDecorators(new ExampleDecorator());
355 357 PythonQt::self()->registerCPPClass("YourCPPObject");
356 358
357 359 \endcode
358 360
359 361 After you have registered an instance of the above ExampleDecorator, you can do the following from Python
360 362 (all these calls are mapped to the above decorator slots):
361 363
362 364 \code
363 365 from PythonQt import QtCore, QtGui, YourCPPObject
364 366
365 367 # call our new constructor of QSize
366 368 size = QtCore.QSize(QPoint(1,2));
367 369
368 370 # call our new QPushButton constructor
369 371 button = QtGui.QPushButton("sometext");
370 372
371 373 # call the move slot (overload1)
372 374 button.move(QPoint(0,0))
373 375
374 376 # call the move slot (overload2)
375 377 button.move(0,0)
376 378
377 379 # call the static method
378 380 grabber = QtGui.QWidget.mouseWrapper();
379 381
380 382 # create a CPP object via constructor
381 383 yourCpp = YourCPPObject(1,11.5)
382 384
383 385 # call the wrapped method on CPP object
384 386 print yourCpp.doSomething(1);
385 387
386 388 # destructor will be called:
387 389 yourCpp = None
388 390
389 391 \endcode
390 392
391 393 \section Building
392 394
393 395 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.
394 396 To compile PythonQt, you will need a python developer installation which includes Python's header files and
395 397 the python2x.[lib | dll | so | dynlib].
396 398 The build scripts a currently set to use Python 2.5.
397 399 You may need to tweak the \b build/python.prf file to set the correct Python includes and libs on your system.
398 400
399 401 \subsection Windows
400 402
401 403 On Windows, the (non-source) Python Windows installer can be used.
402 404 Make sure that you use the same compiler, the current Python distribution is built
403 405 with Visual Studio 2003. If you want to use another compiler, you will need to build
404 406 Python yourself, using your compiler.
405 407
406 408 To build PythonQt, you need to set the environment variable \b PYTHON_PATH to point to the root
407 409 dir of the python installation and \b PYTHON_LIB to point to
408 410 the directory where the python lib file is located.
409 411
410 412 When using the prebuild Python installer, this will be:
411 413
412 414 \code
413 415 > set PYTHON_PATH = c:\Python25
414 416 > set PYTHON_LIB = c:\Python25\libs
415 417 \endcode
416 418
417 419 When using the python sources, this will be something like:
418 420
419 421 \code
420 422 > set PYTHON_PATH = c:\yourDir\Python-2.5.1\
421 423 > set PYTHON_LIB = c:\yourDir\Python-2.5.1\PCbuild8\Win32
422 424 \endcode
423 425
424 426 To build all, do the following (after setting the above variables):
425 427
426 428 \code
427 429 > cd PythonQtRoot
428 430 > vcvars32
429 431 > qmake
430 432 > nmake
431 433 \endcode
432 434
433 435 This should build everything. If Python can not be linked or include files can not be found,
434 436 you probably need to tweak \b build/python.prf
435 437
436 438 The tests and examples are located in PythonQt/lib.
437 439
438 440 \subsection Linux
439 441
440 442 On Linux, you need to install a Python-dev package.
441 443 If Python can not be linked or include files can not be found,
442 444 you probably need to tweak \b build/python.prf
443 445
444 446 To build PythonQt, just do a:
445 447
446 448 \code
447 449 > cd PythonQtRoot
448 450 > qmake
449 451 > make all
450 452 \endcode
451 453
452 454 The tests and examples are located in PythonQt/lib.
453 455 You should add PythonQt/lib to your LD_LIBRARY_PATH so that the runtime
454 456 linker can find the *.so files.
455 457
456 458 \subsection MacOsX
457 459
458 460 On Mac, Python is installed as a Framework, so you should not need to install it.
459 461 To build PythonQt, just do a:
460 462
461 463 \code
462 464 > cd PythonQtRoot
463 465 > qmake
464 466 > make all
465 467 \endcode
466 468
467 469 \section Tests
468 470
469 471 There is a unit test that tests most features of PythonQt, see the \b tests subdirectory for details.
470 472
471 473 \section Examples
472 474
473 475 Examples are available in the \b examples directory. The PyScriptingConsole implements a simple
474 476 interactive scripting console that shows how to script a simple application.
475 477
476 478 The following shows how to integrate PythonQt into you Qt application:
477 479
478 480 \code
479 481 #include "PythonQt.h"
480 482 #include <QApplication>
481 483 ...
482 484
483 485 int main( int argc, char **argv )
484 486 {
485 487
486 488 QApplication qapp(argc, argv);
487 489
488 490 // init PythonQt and Python itself
489 491 PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
490 492
491 493
492 494 // get a smart pointer to the __main__ module of the Python interpreter
493 495 PythonQtObjectPtr mainContext = PythonQt::self()->getMainModule();
494 496
495 497 // add a QObject as variable of name "example" to the namespace of the __main__ module
496 498 PyExampleObject example;
497 499 PythonQt::self()->addObject(mainContext, "example", &example);
498 500
499 501 // do something
500 502 PythonQt::self()->runScript(mainContext, "print example\n");
501 503 PythonQt::self()->runScript(mainContext, "def multiply(a,b):\n return a*b;\n");
502 504 QVariantList args;
503 505 args << 42 << 47;
504 506 QVariant result = PythonQt::self()->call(mainContext,"multiply", args);
505 507 ...
506 508 \endcode
507 509
508 510
509 511 */
@@ -1,116 +1,125
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 PythonQtStdDecorators.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2007-04
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtStdDecorators.h"
43 43 #include "PythonQt.h"
44 44 #include "PythonQtClassInfo.h"
45 45
46 46
47 47 bool PythonQtStdDecorators::connect(QObject* sender, const QByteArray& signal, PyObject* callable)
48 48 {
49 49 QByteArray signalTmp("2");
50 50 signalTmp += signal;
51 51 if (sender) {
52 52 return PythonQt::self()->addSignalHandler(sender, signalTmp, callable);
53 53 } else {
54 54 return false;
55 55 }
56 56 }
57 57
58 58 bool PythonQtStdDecorators::connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot)
59 59 {
60 60 bool r = false;
61 61 if (sender && receiver) {
62 62 QByteArray signalTmp("2");
63 63 signalTmp += signal;
64 64 QByteArray slotTmp("1");
65 65 slotTmp += slot;
66 66 if (receiver) {
67 67 r = QObject::connect(sender, signalTmp, receiver, slotTmp);
68 68 }
69 69 }
70 70 return r;
71 71 }
72 72
73 73 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal, PyObject* callable)
74 74 {
75 75 QByteArray signalTmp("2");
76 76 signalTmp += signal;
77 77 if (sender) {
78 78 return PythonQt::self()->removeSignalHandler(sender, signalTmp, callable);
79 79 } else {
80 80 return false;
81 81 }
82 82 }
83 83
84 84 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot)
85 85 {
86 86 bool r = false;
87 87 if (sender && receiver) {
88 88 QByteArray signalTmp("2");
89 89 signalTmp += signal;
90 90 QByteArray slotTmp("1");
91 91 slotTmp += slot;
92 92 if (receiver) {
93 93 r = QObject::disconnect(sender, signalTmp, receiver, slotTmp);
94 94 }
95 95 }
96 96 return r;
97 97 }
98 98
99 #undef emit
100 void PythonQtStdDecorators::emit(QObject* sender, const QByteArray& signal, PyObject* arg1 ,PyObject* arg2 ,
101 PyObject* arg3 ,PyObject* arg4 ,PyObject* arg5 ,PyObject* arg6 ,PyObject* arg7 )
102 {
103 // TODO xxx
104 // use normal PythonQtSlot calling code, add "allowSignal" to member lookup?!
105 }
106 #define emit
107
99 108 QObject* PythonQtStdDecorators::parent(QObject* o) {
100 109 return o->parent();
101 110 }
102 111
103 112 void PythonQtStdDecorators::setParent(QObject* o, QObject* parent)
104 113 {
105 114 o->setParent(parent);
106 115 }
107 116
108 117 QVariantList PythonQtStdDecorators::children(QObject* o)
109 118 {
110 119 QVariantList v;
111 120 QListIterator<QObject*> it(o->children());
112 121 while (it.hasNext()) {
113 122 v << qVariantFromValue(it.next());
114 123 }
115 124 return v;
116 125 }
@@ -1,79 +1,84
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 #undef emit
66 void emit(QObject* sender, const QByteArray& signal, PyObject* arg1 = NULL,PyObject* arg2 = NULL,
67 PyObject* arg3 = NULL,PyObject* arg4 = NULL,PyObject* arg5 = NULL,PyObject* arg6 = NULL,PyObject* arg7 = NULL);
68 #define emit
69
65 70 bool static_QObject_connect(QObject* sender, const QByteArray& signal, PyObject* callable) { return connect(sender, signal, callable); }
66 71 bool static_QObject_connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot) { return connect(sender, signal, receiver, slot); }
67 72 bool static_QObject_disconnect(QObject* sender, const QByteArray& signal, PyObject* callable) { return disconnect(sender, signal, callable); }
68 73 bool static_QObject_disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot) { return disconnect(sender, signal, receiver, slot); };
69 74
70 75 QObject* parent(QObject* o);
71 76 void setParent(QObject* o, QObject* parent);
72 77
73 78 QVariantList children(QObject* o);
74 79
75 80 //TODO: add findChild/findChildren/children/...
76 81 };
77 82
78 83
79 84 #endif
General Comments 0
You need to be logged in to leave comments. Login now