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