##// END OF EJS Templates
merged in features from the MeVisLab repository...
florianlink -
r4:41816e302524
parent child
Show More
@@ -1,946 +1,1011
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 <pydebug.h>
53 53
54 54 PythonQt* PythonQt::_self = NULL;
55 int PythonQt::_uniqueModuleCount = 0;
55 56
56 57
57 58 void PythonQt::init(int flags)
58 59 {
59 60 if (!_self) {
60 61 _self = new PythonQt(flags);
61 62 }
62 63
63 64 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
64 65 qRegisterMetaType<QList<QObject*> >("QList<void*>");
65 66
66 67 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
67 68
68 69 PythonQt::priv()->addVariantWrapper("QBitArray", new PythonQtQBitArrayWrapper);
69 70 PythonQt::priv()->addVariantWrapper("QDate", new PythonQtQDateWrapper);
70 71 PythonQt::priv()->addVariantWrapper("QTime", new PythonQtQTimeWrapper);
71 72 PythonQt::priv()->addVariantWrapper("QDateTime", new PythonQtQDateTimeWrapper);
72 73 PythonQt::priv()->addVariantWrapper("QUrl", new PythonQtQUrlWrapper);
73 74 PythonQt::priv()->addVariantWrapper("QLocale", new PythonQtQLocaleWrapper);
74 75 PythonQt::priv()->addVariantWrapper("QRect", new PythonQtQRectWrapper);
75 76 PythonQt::priv()->addVariantWrapper("QRectF", new PythonQtQRectFWrapper);
76 77 PythonQt::priv()->addVariantWrapper("QSize", new PythonQtQSizeWrapper);
77 78 PythonQt::priv()->addVariantWrapper("QSizeF", new PythonQtQSizeFWrapper);
78 79 PythonQt::priv()->addVariantWrapper("QLine", new PythonQtQLineWrapper);
79 80 PythonQt::priv()->addVariantWrapper("QLineF", new PythonQtQLineFWrapper);
80 81 PythonQt::priv()->addVariantWrapper("QPoint", new PythonQtQPointWrapper);
81 82 PythonQt::priv()->addVariantWrapper("QPointF", new PythonQtQPointFWrapper);
82 83 PythonQt::priv()->addVariantWrapper("QRegExp", new PythonQtQRegExpWrapper);
83 84 PythonQt::priv()->addVariantWrapper("QFont", new PythonQtQFontWrapper);
84 85 PythonQt::priv()->addVariantWrapper("QPixmap", new PythonQtQPixmapWrapper);
85 86 PythonQt::priv()->addVariantWrapper("QBrush", new PythonQtQBrushWrapper);
86 87 PythonQt::priv()->addVariantWrapper("QColor", new PythonQtQColorWrapper);
87 88 PythonQt::priv()->addVariantWrapper("QPalette", new PythonQtQPaletteWrapper);
88 89 PythonQt::priv()->addVariantWrapper("QIcon", new PythonQtQIconWrapper);
89 90 PythonQt::priv()->addVariantWrapper("QImage", new PythonQtQImageWrapper);
90 91 PythonQt::priv()->addVariantWrapper("QPolygon", new PythonQtQPolygonWrapper);
91 92 PythonQt::priv()->addVariantWrapper("QRegion", new PythonQtQRegionWrapper);
92 93 PythonQt::priv()->addVariantWrapper("QBitmap", new PythonQtQBitmapWrapper);
93 94 PythonQt::priv()->addVariantWrapper("QCursor", new PythonQtQCursorWrapper);
94 95 PythonQt::priv()->addVariantWrapper("QSizePolicy", new PythonQtQSizePolicyWrapper);
95 96 PythonQt::priv()->addVariantWrapper("QKeySequence", new PythonQtQKeySequenceWrapper);
96 97 PythonQt::priv()->addVariantWrapper("QPen", new PythonQtQPenWrapper);
97 98 PythonQt::priv()->addVariantWrapper("QTextLength", new PythonQtQTextLengthWrapper);
98 99 PythonQt::priv()->addVariantWrapper("QTextFormat", new PythonQtQTextFormatWrapper);
99 100 PythonQt::priv()->addVariantWrapper("QMatrix", new PythonQtQMatrixWrapper);
100 101
101 102 }
102 103
103 104 void PythonQt::cleanup()
104 105 {
105 106 if (_self) {
106 107 delete _self;
107 108 _self = NULL;
108 109 }
109 110 }
110 111
111 112 PythonQt::PythonQt(int flags)
112 113 {
113 114 _p = new PythonQtPrivate;
114 115 _p->_initFlags = flags;
115 116
116 117 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
117 118
118 119 Py_SetProgramName("PythonQt");
119 120 if (flags & IgnoreSiteModule) {
120 121 // this prevents the automatic importing of Python site files
121 122 Py_NoSiteFlag = 1;
122 123 }
123 124 Py_Initialize();
124 125
125 126 // add our own python object types for qt object slots
126 127 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
127 128 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
128 129 }
129 130 Py_INCREF(&PythonQtSlotFunction_Type);
130 131
131 132 // add our own python object types for qt objects
132 133 if (PyType_Ready(&PythonQtWrapper_Type) < 0) {
133 134 std::cerr << "could not initialize PythonQtWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
134 135 }
135 136 Py_INCREF(&PythonQtWrapper_Type);
136 137
137 138 // add our own python object types for qt objects
138 139 if (PyType_Ready(&PythonQtVariantWrapper_Type) < 0) {
139 140 std::cerr << "could not initialize PythonQtVariantWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
140 141 }
141 142 Py_INCREF(&PythonQtVariantWrapper_Type);
142 143
143 144 // add our own python object types for qt objects
144 145 if (PyType_Ready(&PythonQtMetaObjectWrapper_Type) < 0) {
145 146 std::cerr << "could not initialize PythonQtMetaObjectWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
146 147 }
147 148 Py_INCREF(&PythonQtMetaObjectWrapper_Type);
148 149
149 150 // add our own python object types for redirection of stdout
150 151 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
151 152 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
152 153 }
153 154 Py_INCREF(&PythonQtStdOutRedirectType);
154 155
155 156 initPythonQtModule(flags & RedirectStdOut);
156 157
157 158 }
158 159
159 160 PythonQt::~PythonQt() {
160 161 delete _p;
161 162 _p = NULL;
162 163 }
163 164
164 165 PythonQtPrivate::~PythonQtPrivate() {
165 166 {
166 167 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownQtClasses);
167 168 while (i.hasNext()) {
168 169 delete i.next().value();
169 170 }
170 171 }
171 172 {
172 173 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownQtWrapperClasses);
173 174 while (i.hasNext()) {
174 175 delete i.next().value();
175 176 }
176 177 }
177 178 {
178 179 QHashIterator<int , QPair<PythonQtClassInfo*, QObject*> > i(_knownVariantWrappers);
179 180 while (i.hasNext()) {
180 181 delete i.next().value().first;
181 182 }
182 183 }
183 184 {
184 185 QHashIterator<QByteArray, PythonQtSlotInfo *> i(_constructorSlots);
185 186 while (i.hasNext()) {
186 187 delete i.next().value();
187 188 }
188 189 }
189 190 {
190 191 QHashIterator<QByteArray, PythonQtSlotInfo *> i(_destructorSlots);
191 192 while (i.hasNext()) {
192 193 delete i.next().value();
193 194 }
194 195 }
195 196 PythonQtConv::global_valueStorage.clear();
196 197 PythonQtConv::global_ptrStorage.clear();
197 198 PythonQtConv::global_variantStorage.clear();
198 199
199 200 PythonQtMethodInfo::cleanupCachedMethodInfos();
200 201
201 202 delete _qtNamespace;
202 203 }
203 204
204 205 PythonQtImportFileInterface* PythonQt::importInterface()
205 206 {
206 207 return _self->_p->_importInterface;
207 208 }
208 209
209 210 void PythonQt::registerClass(const QMetaObject* metaobject)
210 211 {
211 212 _p->registerClass(metaobject);
212 213 }
213 214
215 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
216 {
217 if (_self->_p->_noLongerWrappedCB) {
218 (*_self->_p->_noLongerWrappedCB)(o);
219 };
220 }
221
214 222 void PythonQtPrivate::registerClass(const QMetaObject* metaobject)
215 223 {
216 224 // we register all classes in the hierarchy
217 225 const QMetaObject* m = metaobject;
218 226 while (m) {
219 227 PythonQtClassInfo* info = _knownQtClasses.value(m->className());
220 228 if (!info) {
221 229 info = new PythonQtClassInfo(m);
222 230 _knownQtClasses.insert(m->className(), info);
223 231 PyModule_AddObject(_pythonQtModule, m->className(), (PyObject*)createNewPythonQtMetaObjectWrapper(info));
224 232 }
225 233 m = m->superClass();
226 234 }
227 235 }
228 236
229 237 bool PythonQtPrivate::isEnumType(const QMetaObject* meta, const QByteArray& name) {
230 238 int i = meta?meta->indexOfEnumerator(name.constData()):-1;
231 239 if (i!=-1) {
232 240 return true;
233 241 } else {
234 242 // look for scope
235 243 int scopePos = name.indexOf("::");
236 244 if (scopePos != -1) {
237 245 // slit into scope and enum name
238 246 QByteArray enumScope = name.mid(0,scopePos);
239 247 QByteArray enumName = name.mid(scopePos+2);
240 248 if (enumScope == "Qt") {
241 249 // special qt namespace case
242 250 return isEnumType(&staticQtMetaObject, enumName);
243 251 } else {
244 252 // look for known classes as scope
245 253 // TODO: Q_GADGETS are not yet handled
246 254 PythonQtClassInfo* info = _knownQtClasses.value(enumScope);
247 255 if (info) {
248 256 return isEnumType(info->metaObject(), enumName);
249 257 }
250 258 }
251 259 }
252 260 }
253 261 return false;
254 262 }
255 263
256 264 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
257 265 {
258 266 if (!obj) {
259 267 Py_INCREF(Py_None);
260 268 return Py_None;
261 269 }
262 PythonQtWrapper* wrap = _wrappedObjects.value(obj);
270 PythonQtWrapper* wrap = findWrapperAndRemoveUnused(obj);
263 271 if (!wrap) {
264 272 // smuggling it in...
265 273 PythonQtClassInfo* classInfo = _knownQtClasses.value(obj->metaObject()->className());
266 274 if (!classInfo) {
267 275 registerClass(obj->metaObject());
268 276 classInfo = _knownQtClasses.value(obj->metaObject()->className());
269 277 }
270 278 wrap = createNewPythonQtWrapper(obj, classInfo);
271 // insert destroyed handler
272 connect(obj, SIGNAL(destroyed(QObject*)), this, SLOT(wrappedObjectDestroyed(QObject*)));
273 279 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
274 280 } else {
275 281 Py_INCREF(wrap);
276 282 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
277 283 }
278 284 return (PyObject*)wrap;
279 285 }
280 286
281 287 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
282 288 {
283 289 if (!ptr) {
284 290 Py_INCREF(Py_None);
285 291 return Py_None;
286 292 }
287 PythonQtWrapper* wrap = _wrappedObjects.value(ptr);
293 PythonQtWrapper* wrap = findWrapperAndRemoveUnused(ptr);
288 294 if (!wrap) {
289 295 PythonQtClassInfo* info = _knownQtClasses.value(name);
290 296 if (!info) {
291 297 // we do not know the metaobject yet, but we might know it by it's name:
292 298 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
293 299 // yes, we know it, so we can convert to QObject
294 300 QObject* qptr = (QObject*)ptr;
295 301 registerClass(qptr->metaObject());
296 302 info = _knownQtClasses.value(qptr->metaObject()->className());
297 303 }
298 304 }
299 305 if (info) {
300 306 QObject* qptr = (QObject*)ptr;
301 307 // if the object is a derived object, we want to switch the class info to the one of the derived class:
302 308 if (name!=(qptr->metaObject()->className())) {
303 309 registerClass(qptr->metaObject());
304 310 info = _knownQtClasses.value(qptr->metaObject()->className());
305 311 }
306 312 wrap = createNewPythonQtWrapper(qptr, info);
307 // insert destroyed handler
308 connect(qptr, SIGNAL(destroyed(QObject*)), this, SLOT(wrappedObjectDestroyed(QObject*)));
309 313 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
310 314 } else {
311 315 // maybe it is a PyObject, which we can return directly
312 316 if (name == "PyObject") {
313 317 PyObject* p = (PyObject*)ptr;
314 318 Py_INCREF(p);
315 319 return p;
316 320 }
317 321 // not a known QObject, so try our wrapper factory:
318 322 QObject* wrapper = NULL;
319 323 for (int i=0; i<_cppWrapperFactories.size(); i++) {
320 324 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
321 325 if (wrapper) {
322 326 break;
323 327 }
324 328 }
325 329 PythonQtClassInfo* info = _knownQtWrapperClasses.value(name);
326 330 if (!info) {
327 331 info = new PythonQtClassInfo(wrapper?wrapper->metaObject():&QObject::staticQtMetaObject, name);
328 332 _knownQtWrapperClasses.insert(name, info);
329 333 PyModule_AddObject(_pythonQtModule, name, (PyObject*)createNewPythonQtMetaObjectWrapper(info));
330 334 } else {
331 335 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
332 336 info->setMetaObject(wrapper->metaObject());
333 337 }
334 338 }
335 339 wrap = createNewPythonQtWrapper(wrapper, info, ptr);
336 340 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
337 341 }
338 342 } else {
339 343 Py_INCREF(wrap);
340 344 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
341 345 }
342 346 return (PyObject*)wrap;
343 347 }
344 348
345 349 void PythonQt::registerCPPClassNames(const QStringList& names)
346 350 {
347 351 foreach ( QString n, names) {
348 352 QByteArray name = n.toLatin1();
349 353 PythonQtClassInfo* info = _p->_knownQtWrapperClasses.value(name);
350 354 if (!info) {
351 355 info = new PythonQtClassInfo(&QObject::staticMetaObject, name);
352 356 _p->_knownQtWrapperClasses.insert(name, info);
353 357 PyModule_AddObject(_p->_pythonQtModule, name.data(), (PyObject*)_p->createNewPythonQtMetaObjectWrapper(info));
354 358 }
355 359 }
356 360 }
357 361
358 362 PythonQtWrapper* PythonQtPrivate::createNewPythonQtWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
359 363 PythonQtWrapper* result;
360 364 result = (PythonQtWrapper *)PythonQtWrapper_Type.tp_new(&PythonQtWrapper_Type,
361 365 NULL, NULL);
362 366
363 result->_obj = obj;
367 result->setQObject(obj);
364 368 result->_info = info;
365 369 result->_wrappedPtr = wrappedPtr;
366 370 result->_ownedByPythonQt = false;
367 371
368 372 if (wrappedPtr) {
369 373 _wrappedObjects.insert(wrappedPtr, result);
370 374 } else {
371 375 _wrappedObjects.insert(obj, result);
376 if (obj->parent()== NULL && _wrappedCB) {
377 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
378 (*_wrappedCB)(obj);
379 }
372 380 }
373 381 return result;
374 382 }
375 383
376 384 PythonQtVariantWrapper* PythonQtPrivate::createNewPythonQtVariantWrapper(const QVariant& variant) {
377 385 PythonQtVariantWrapper* result;
378 386 result = (PythonQtVariantWrapper *)PythonQtVariantWrapper_Type.tp_new(&PythonQtVariantWrapper_Type,
379 387 NULL, NULL);
380 388
381 389 *result->_variant = variant;
382 390 QPair<PythonQtClassInfo*, QObject*> pair = _knownVariantWrappers.value(variant.userType());
383 391 result->_wrapper = pair.second;
384 392 result->_info = pair.first;
385 393 return result;
386 394 }
387 395
388 396 PythonQtMetaObjectWrapper* PythonQtPrivate::createNewPythonQtMetaObjectWrapper(PythonQtClassInfo* info) {
389 397 PythonQtMetaObjectWrapper* result;
390 398 result = (PythonQtMetaObjectWrapper *)PythonQtMetaObjectWrapper_Type.tp_new(&PythonQtMetaObjectWrapper_Type,
391 399 NULL, NULL);
392 400 result->_info = info;
393 401 return result;
394 402 }
395 403
396 404
397 405 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
398 406 {
399 407 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
400 408 if (!r) {
401 409 r = new PythonQtSignalReceiver(obj);
402 410 _p->_signalReceivers.insert(obj, r);
403 // insert destroyed handler
404 connect(obj, SIGNAL(destroyed(QObject*)), _p ,SLOT(destroyedSignalEmitter(QObject*)));
405 411 }
406 412 return r;
407 413 }
408 414
409 415 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
410 416 {
411 417 bool flag = false;
412 418 PythonQtObjectPtr callable = lookupCallable(module, objectname);
413 419 if (callable) {
414 420 PythonQtSignalReceiver* r = getSignalReceiver(obj);
415 421 flag = r->addSignalHandler(signal, callable);
416 422 if (!flag) {
417 423 // signal not found
418 424 }
419 425 } else {
420 426 // callable not found
421 427 }
422 428 return flag;
423 429 }
424 430
425 431 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
426 432 {
427 433 bool flag = false;
428 434 PythonQtSignalReceiver* r = getSignalReceiver(obj);
429 435 if (r) {
430 436 flag = r->addSignalHandler(signal, receiver);
431 437 }
432 438 return flag;
433 439 }
434 440
435 441 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
436 442 {
437 443 bool flag = false;
438 444 PythonQtObjectPtr callable = lookupCallable(module, objectname);
439 445 if (callable) {
440 446 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
441 447 if (r) {
442 448 flag = r->removeSignalHandler(signal, callable);
443 449 }
444 450 } else {
445 451 // callable not found
446 452 }
447 453 return flag;
448 454 }
449 455
450 456 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
451 457 {
452 458 bool flag = false;
453 459 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
454 460 if (r) {
455 461 flag = r->removeSignalHandler(signal, receiver);
456 462 }
457 463 return flag;
458 464 }
459 465
460 466 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
461 467 {
462 468 PythonQtObjectPtr p = lookupObject(module, name);
463 469 if (p) {
464 470 if (PyCallable_Check(p)) {
465 471 return p;
466 472 }
467 473 }
468 474 PyErr_Clear();
469 475 return NULL;
470 476 }
471 477
472 478 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
473 479 {
474 480 QStringList l = name.split('.');
475 481 PythonQtObjectPtr p = module;
476 482 PythonQtObjectPtr prev;
477 483 QString s;
478 484 QByteArray b;
479 485 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
480 486 prev = p;
481 487 b = (*i).toLatin1();
482 488 p.setNewRef(PyObject_GetAttrString(p, b.data()));
483 489 }
484 490 PyErr_Clear();
485 491 return p;
486 492 }
487 493
488 494 PythonQtObjectPtr PythonQt::getMainModule() {
489 495 //both borrowed
490 496 PythonQtObjectPtr dict = PyImport_GetModuleDict();
491 497 return PyDict_GetItemString(dict, "__main__");
492 498 }
493 499
494 500 QVariant PythonQt::evalCode(PyObject* module, PyObject* pycode) {
495 501 QVariant result;
496 502 if (pycode) {
497 503 PyObject* r = PyEval_EvalCode((PyCodeObject*)pycode, PyModule_GetDict((PyObject*)module) , PyModule_GetDict((PyObject*)module));
498 504 if (r) {
499 505 result = PythonQtConv::PyObjToQVariant(r);
500 506 Py_DECREF(r);
501 507 } else {
502 508 handleError();
503 509 }
504 510 } else {
505 511 handleError();
506 512 }
507 513 return result;
508 514 }
509 515
510 516 QVariant PythonQt::evalScript(PyObject* module, const QString& script, int start)
511 517 {
512 518 QVariant result;
513 519 PythonQtObjectPtr p;
514 520 p.setNewRef(PyRun_String(script.toLatin1().data(), start, PyModule_GetDict(module), PyModule_GetDict(module)));
515 521 if (p) {
516 522 result = PythonQtConv::PyObjToQVariant(p);
517 523 } else {
518 524 handleError();
519 525 }
520 526 return result;
521 527 }
522 528
523 529 void PythonQt::evalFile(PyObject* module, const QString& filename)
524 530 {
525 531 PythonQtObjectPtr code = parseFile(filename);
526 532 if (code) {
527 533 evalCode(module, code);
528 534 } else {
529 535 handleError();
530 536 }
531 537 }
532 538
533 539 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
534 540 {
535 541 PythonQtObjectPtr p;
536 542 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
537 543 if (!p) {
538 544 handleError();
539 545 }
540 546 return p;
541 547 }
542 548
549 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
550 {
551 PythonQtObjectPtr code = parseFile(filename);
552 PythonQtObjectPtr module = _p->createModule(name, code);
553 return module;
554 }
555
556 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
557 {
558 PyErr_Clear();
559 QString scriptCode = script;
560 if (scriptCode.isEmpty()) {
561 // we always need at least a linefeed
562 scriptCode = "\n";
563 }
564 PythonQtObjectPtr pycode;
565 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
566 PythonQtObjectPtr module = _p->createModule(name, pycode);
567 return module;
568 }
569
570 PythonQtObjectPtr PythonQt::createUniqueModule()
571 {
572 static QString pyQtStr("PythonQt_module");
573 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
574 return createModuleFromScript(moduleName);
575 }
576
543 577 void PythonQt::addObject(PyObject* module, const QString& name, QObject* object)
544 578 {
545 579 PyModule_AddObject(module, name.toLatin1().data(), _p->wrapQObject(object));
546 580 }
547 581
548 582 void PythonQt::addVariable(PyObject* module, const QString& name, const QVariant& v)
549 583 {
550 584 PyModule_AddObject(module, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
551 585 }
552 586
553 587 void PythonQt::removeVariable(PyObject* module, const QString& name)
554 588 {
555 589 PyObject_DelAttrString(module, name.toLatin1().data());
556 590 }
557 591
558 592 QVariant PythonQt::getVariable(PyObject* module, const QString& objectname)
559 593 {
560 594 QVariant result;
561 595 PythonQtObjectPtr obj = lookupObject(module, objectname);
562 596 if (obj) {
563 597 result = PythonQtConv::PyObjToQVariant(obj);
564 598 }
565 599 return result;
566 600 }
567 601
568 602 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
569 603 {
570 604 QStringList results;
571 605
572 606 PythonQtObjectPtr object;
573 607 if (objectname.isEmpty()) {
574 608 object = module;
575 609 } else {
576 610 object = lookupObject(module, objectname);
577 611 if (!object && type == CallOverloads) {
578 612 PyObject* dict = lookupObject(module, "__builtins__");
579 613 if (dict) {
580 614 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
581 615 }
582 616 }
583 617 }
584 618
585 619 if (object) {
586 620 if (type == CallOverloads) {
587 621 if (PythonQtSlotFunction_Check(object)) {
588 622 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
589 623 PythonQtSlotInfo* info = o->m_ml;
590 624
591 625 while (info) {
592 626 results << info->fullSignature(info->isInstanceDecorator() || o->m_self->ob_type == &PythonQtVariantWrapper_Type);
593 627 info = info->nextInfo();
594 628 }
595 629 } else if (object->ob_type == &PythonQtMetaObjectWrapper_Type) {
596 630 PythonQtMetaObjectWrapper* o = (PythonQtMetaObjectWrapper*)object.object();
597 631 PythonQtSlotInfo* info = o->_info->constructors();
598 632
599 633 while (info) {
600 634 results << info->fullSignature(false);
601 635 info = info->nextInfo();
602 636 }
603 637 } else {
604 638 //TODO: use pydoc!
605 639 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
606 640 if (doc) {
607 641 results << PyString_AsString(doc);
608 642 Py_DECREF(doc);
609 643 }
610 644 }
611 645 } else {
612 646 PyObject* keys = PyObject_Dir(object);
613 647 if (keys) {
614 648 int count = PyList_Size(keys);
615 649 PyObject* key;
616 650 PyObject* value;
617 651 QString keystr;
618 652 for (int i = 0;i<count;i++) {
619 653 key = PyList_GetItem(keys,i);
620 654 value = PyObject_GetAttr(object, key);
621 655 if (!value) continue;
622 656 keystr = PyString_AsString(key);
623 657 static const QString underscoreStr("__tmp");
624 658 if (!keystr.startsWith(underscoreStr)) {
625 659 switch (type) {
626 660 case Anything:
627 661 results << keystr;
628 662 break;
629 663 case Class:
630 664 if (value->ob_type == &PyClass_Type) {
631 665 results << keystr;
632 666 }
633 667 break;
634 668 case Variable:
635 669 if (value->ob_type != &PyClass_Type
636 670 && value->ob_type != &PyCFunction_Type
637 671 && value->ob_type != &PyFunction_Type
638 672 && value->ob_type != &PyModule_Type
639 673 ) {
640 674 results << keystr;
641 675 }
642 676 break;
643 677 case Function:
644 678 if (value->ob_type == &PyFunction_Type ||
645 679 value->ob_type == &PyMethod_Type
646 680 ) {
647 681 results << keystr;
648 682 }
649 683 break;
650 684 case Module:
651 685 if (value->ob_type == &PyModule_Type) {
652 686 results << keystr;
653 687 }
654 688 break;
655 689 default:
656 690 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
657 691 }
658 692 }
659 693 Py_DECREF(value);
660 694 }
661 695 Py_DECREF(keys);
662 696 }
663 697 }
664 698 }
665 699 return results;
666 700 }
667 701
668 702 QVariant PythonQt::call(PyObject* module, const QString& name, const QVariantList& args)
669 703 {
670 704 QVariant r;
671 705
672 706 PythonQtObjectPtr callable = lookupCallable(module, name);
673 707 if (callable) {
674 708 PythonQtObjectPtr pargs;
675 709 int count = args.size();
676 710 if (count>0) {
677 711 pargs.setNewRef(PyTuple_New(count));
678 712 }
679 713 bool err = false;
680 714 // transform QVariants to Python
681 715 for (int i = 0; i < count; i++) {
682 716 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
683 717 if (arg) {
684 718 // steals reference, no unref
685 719 PyTuple_SetItem(pargs, i,arg);
686 720 } else {
687 721 err = true;
688 722 break;
689 723 }
690 724 }
691 725
692 726 if (!err) {
693 727 PyErr_Clear();
694 728 PythonQtObjectPtr result;
695 729 result.setNewRef(PyObject_CallObject(callable, pargs));
696 730 if (result) {
697 731 // ok
698 732 r = PythonQtConv::PyObjToQVariant(result);
699 733 } else {
700 734 PythonQt::self()->handleError();
701 735 }
702 736 }
703 737 }
704 738 return r;
705 739 }
706 740
707 741 void PythonQt::addInstanceDecorators(QObject* o)
708 742 {
709 743 _p->addDecorators(o, true, false);
710 744 }
711 745
712 746 void PythonQt::addClassDecorators(QObject* o)
713 747 {
714 748 _p->addDecorators(o, false, true);
715 749 }
716 750
717 751 void PythonQt::addDecorators(QObject* o)
718 752 {
719 753 _p->addDecorators(o, true, true);
720 754 }
721 755
722 756 void PythonQt::registerQObjectClassNames(const QStringList& names)
723 757 {
724 758 _p->registerQObjectClassNames(names);
725 759 }
726 760
727 761 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
728 762 {
729 763 static bool first = true;
730 764 if (first) {
731 765 first = false;
732 766 _p->_importInterface = importInterface;
733 767 PythonQtImport::init();
734 768 }
735 769 }
736 770
737 771 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
738 772 {
739 773 _p->_importIgnorePaths = paths;
740 774 }
741 775
742 776 const QStringList& PythonQt::getImporterIgnorePaths()
743 777 {
744 778 return _p->_importIgnorePaths;
745 779 }
746 780
747 781 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
748 782 {
749 783 _p->_cppWrapperFactories.append(factory);
750 784 }
751 785
752 786 void PythonQt::addConstructorHandler(PythonQtConstructorHandler* factory)
753 787 {
754 788 _p->_constructorHandlers.append(factory);
755 789 }
756 790
757 791 const QList<PythonQtConstructorHandler*>& PythonQt::constructorHandlers()
758 792 {
759 793 return _p->_constructorHandlers;
760 794 };
761 795
762 796 //---------------------------------------------------------------------------------------------------
763 797 PythonQtPrivate::PythonQtPrivate()
764 798 {
765 799 _importInterface = NULL;
800 _noLongerWrappedCB = NULL;
801 _wrappedCB = NULL;
766 802 }
767 803
768 804 void PythonQtPrivate::addDecorators(QObject* o, bool instanceDeco, bool classDeco)
769 805 {
770 806 o->setParent(this);
771 807 int numMethods = o->metaObject()->methodCount();
772 808 for (int i = 0; i < numMethods; i++) {
773 809 QMetaMethod m = o->metaObject()->method(i);
774 810 if ((m.methodType() == QMetaMethod::Method ||
775 811 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
776 812 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m);
777 813 if (qstrncmp(m.signature(), "new_", 4)==0) {
778 814 if (!classDeco) continue;
779 815 // either it returns a * or a QVariant and the name starts with "new_"
780 816 bool isVariantReturn = info->parameters().at(0).typeId == PythonQtMethodInfo::Variant;
781 817 if ((info->parameters().at(0).isPointer || isVariantReturn)) {
782 818 QByteArray signature = m.signature();
783 819 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
784 820 PythonQtSlotInfo* prev = _constructorSlots.value(nameOfClass);
785 821 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
786 822 if (prev) {
787 823 newSlot->setNextInfo(prev->nextInfo());
788 824 prev->setNextInfo(newSlot);
789 825 } else {
790 826 _constructorSlots.insert(nameOfClass, newSlot);
791 827 }
792 828 }
793 829 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
794 830 if (!classDeco) continue;
795 831 QByteArray signature = m.signature();
796 832 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
797 833 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
798 834 _destructorSlots.insert(nameOfClass, newSlot);
799 835 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
800 836 if (!classDeco) continue;
801 837 QByteArray signature = m.signature();
802 838 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
803 839 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
804 840 PythonQtSlotInfo* slotCopy = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
805 841 _knownQtDecoratorSlots.insert(nameOfClass, slotCopy);
806 842 } else {
807 843 if (!instanceDeco) continue;
808 844 if (info->parameters().count()>1) {
809 845 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
810 846 if (p.isPointer) {
811 847 PythonQtSlotInfo* slotCopy = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::InstanceDecorator);
812 848 _knownQtDecoratorSlots.insert(p.name, slotCopy);
813 849 }
814 850 }
815 851 }
816 852 }
817 853 }
818 854 }
819 855
820 856 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
821 857 {
822 858 foreach(QString name, names) {
823 859 _knownQObjectClassNames.insert(name.toLatin1(), true);
824 860 }
825 861 }
826 862
827 863 QList<PythonQtSlotInfo*> PythonQtPrivate::getDecoratorSlots(const QByteArray& className)
828 864 {
829 865 return _knownQtDecoratorSlots.values(className);
830 866 }
831 867
832 void PythonQtPrivate::wrappedObjectDestroyed(QObject* obj)
833 {
834 // mlabDebugConst("MLABPython","PyWrapper QObject destroyed " << o << " " << o->name() << " " << o->className());
835 PythonQtWrapper* wrap = _wrappedObjects[obj];
836 if (wrap) {
837 _wrappedObjects.remove(obj);
838 // remove the pointer but keep the wrapper alive in python
839 wrap->_obj = NULL;
840 }
841 }
842
843 void PythonQtPrivate::destroyedSignalEmitter(QObject* obj)
868 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
844 869 {
845 _signalReceivers.take(obj);
870 _signalReceivers.remove(obj);
846 871 }
847 872
848 873 bool PythonQt::handleError()
849 874 {
850 875 bool flag = false;
851 876 if (PyErr_Occurred()) {
852 877
853 878 // currently we just print the error and the stderr handler parses the errors
854 879 PyErr_Print();
855 880
856 881 /*
857 882 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
858 883 PyObject *ptype;
859 884 PyObject *pvalue;
860 885 PyObject *ptraceback;
861 886 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
862 887
863 888 Py_XDECREF(ptype);
864 889 Py_XDECREF(pvalue);
865 890 Py_XDECREF(ptraceback);
866 891 */
867 892 PyErr_Clear();
868 893 flag = true;
869 894 }
870 895 return flag;
871 896 }
872 897
873 898 void PythonQt::overwriteSysPath(const QStringList& paths)
874 899 {
875 900 PythonQtObjectPtr sys;
876 901 sys.setNewRef(PyImport_ImportModule("sys"));
877 902 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
878 903 }
879 904
880 905 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
881 906 {
882 907 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
883 908 }
884 909
885 910 void PythonQt::stdOutRedirectCB(const QString& str)
886 911 {
887 912 emit PythonQt::self()->pythonStdOut(str);
888 913 }
889 914
890 915 void PythonQt::stdErrRedirectCB(const QString& str)
891 916 {
892 917 emit PythonQt::self()->pythonStdErr(str);
893 918 }
894 919
920 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
921 {
922 _p->_wrappedCB = cb;
923 }
924
925 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
926 {
927 _p->_noLongerWrappedCB = cb;
928 }
929
895 930
896 931
897 932 static PyMethodDef PythonQtMethods[] = {
898 933 {NULL, NULL, 0, NULL}
899 934 };
900 935
901 936 void PythonQt::initPythonQtModule(bool redirectStdOut)
902 937 {
903 938 _p->_pythonQtModule.setNewRef(Py_InitModule("PythonQt", PythonQtMethods));
904 939 _p->_qtNamespace = new PythonQtClassInfo(&staticQtMetaObject);
905 940 PyModule_AddObject(_p->_pythonQtModule, "Qt", (PyObject*)_p->createNewPythonQtMetaObjectWrapper(_p->_qtNamespace));
906 941
907 942 if (redirectStdOut) {
908 943 PythonQtObjectPtr sys;
909 944 PythonQtObjectPtr out;
910 945 PythonQtObjectPtr err;
911 946 sys.setNewRef(PyImport_ImportModule("sys"));
912 947 // create a redirection object for stdout and stderr
913 948 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
914 949 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
915 950 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
916 951 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
917 952 // replace the built in file objects with our own objects
918 953 PyModule_AddObject(sys, "stdout", out);
919 954 PyModule_AddObject(sys, "stderr", err);
920 955 }
921 956 }
922 957
923 958 void PythonQt::addVariantWrapper(const char* typeName, QObject* wrapper)
924 959 {
925 960 _p->addVariantWrapper(typeName, wrapper);
926 961 }
927 962
928 963
929 964 void PythonQtPrivate::addVariantWrapper(const char* typeName, QObject* wrapper)
930 965 {
931 966 int type = QMetaType::type(typeName);
932 967 PythonQtClassInfo* info = new PythonQtClassInfo(wrapper->metaObject(), typeName);
933 968 _knownVariantWrappers.insert(type, qMakePair(info, wrapper));
934 969 addDecorators(wrapper, false, true);
935 970 PyModule_AddObject(_pythonQtModule, typeName, (PyObject*)createNewPythonQtMetaObjectWrapper(info));
936 971 }
937 972
938 973 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
939 974 {
940 975 if (_p->_initFlags & ExternalHelp) {
941 976 emit pythonHelpRequest(QByteArray(info->className()));
942 977 return Py_BuildValue("");
943 978 } else {
944 979 return PyString_FromString(info->help().toLatin1().data());
945 980 }
946 981 }
982
983 void PythonQtPrivate::removeWrapperPointer(void* obj)
984 {
985 _wrappedObjects.remove(obj);
986 }
987
988 PythonQtWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
989 {
990 PythonQtWrapper* wrap = _wrappedObjects.value(obj);
991 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
992 // this is a wrapper whose QObject was already removed due to destruction
993 // so the obj pointer has to be a new QObject with the same address...
994 // we remove the old one and set the copy to NULL
995 wrap->_objPointerCopy = NULL;
996 removeWrapperPointer(obj);
997 wrap = NULL;
998 }
999 return wrap;
1000 }
1001
1002 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1003 {
1004 PythonQtObjectPtr result;
1005 if (pycode) {
1006 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1007 } else {
1008 PythonQt::self()->handleError();
1009 }
1010 return result;
1011 }
@@ -1,436 +1,469
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 "PythonQtWrapper.h"
47 47 #include "PythonQtVariantWrapper.h"
48 48 #include "PythonQtMetaObjectWrapper.h"
49 49 #include "PythonQtSlot.h"
50 50 #include "PythonQtObjectPtr.h"
51 51 #include <QObject>
52 52 #include <QVariant>
53 53 #include <QList>
54 54 #include <QHash>
55 55 #include <QByteArray>
56 56 #include <QStringList>
57 57 #include <QtDebug>
58 58 #include <iostream>
59 59
60 60
61 61 class PythonQtClassInfo;
62 62 class PythonQtPrivate;
63 63 class PythonQtMethodInfo;
64 64 class PythonQtSignalReceiver;
65 65 class PythonQtImportFileInterface;
66 66 class PythonQtCppWrapperFactory;
67 67 class PythonQtConstructorHandler;
68 68
69 typedef void PythonQtQObjectWrappedCB(QObject* object);
70 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
71
69 72 //! the main interface to the Python Qt binding, realized as a singleton
70 73 class PYTHONQT_EXPORT PythonQt : public QObject {
71 74
72 75 Q_OBJECT
73 76
74 77 public:
75 78 enum InitFlags {
76 79 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
77 80 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
78 81 ExternalHelp = 4 //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
79 82 };
80 83
81 84 //! initialize the python qt binding (flags are a or combination of InitFlags)
82 85 static void init(int flags = IgnoreSiteModule | RedirectStdOut);
83 86
84 87 //! cleanup
85 88 static void cleanup();
86 89
87 90 //! get the singleton instance
88 91 static PythonQt* self() { return _self; }
89 92
90 93 //-----------------------------------------------------------------------------
91 94 // Public API:
92 95
93 96 //! defines the object types for introspection
94 97 enum ObjectType {
95 98 Class,
96 99 Function,
97 100 Variable,
98 101 Module,
99 102 Anything,
100 103 CallOverloads
101 104 };
102 105
103 106 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
104 107 void overwriteSysPath(const QStringList& paths);
105 108
106 109 //! sets the __path__ list of a module to the given list (important for local imports)
107 110 void setModuleImportPath(PyObject* module, const QStringList& paths);
108 111
109 112 //! get the __main__ module of python
110 113 PythonQtObjectPtr getMainModule();
111 114
112 115 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
113 116 //! All added metaobjects will be visible under the className in the PythonQt module as MetaObjectWrappers and the enums
114 117 //! and constructors (added by addConstructors) will be available.
115 118 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
116 119 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
117 120 void registerClass(const QMetaObject* metaobject);
118 121
119 122 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
120 123 //! and it will register the classes when it first sees a pointer to such a derived class
121 124 void registerQObjectClassNames(const QStringList& names);
122 125
123 126 //! this will register CPP classnames as known CPP classes (NOT QObjects) and make their MetaObjectWrapper available in
124 127 //! the PythonQt module. In combination with addConstuctors(), this can be used to create CPP objects from PythonQt
125 128 void registerCPPClassNames(const QStringList& names);
126 129
127 130 //! parses the given file and returns the python code object, this can then be used to call evalCode()
128 131 PythonQtObjectPtr parseFile(const QString& filename);
129 132
130 133 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
131 134 //! If pycode is NULL, a python error is printed.
132 135 QVariant evalCode(PyObject* module, PyObject* pycode);
133 136
134 137 //! evaluates the given script code and returns the result value
135 138 QVariant evalScript(PyObject* module, const QString& script, int start = Py_file_input);
136 139
137 140 //! evaluates the given script code from file
138 141 void evalFile(PyObject* module, const QString& filename);
139 142
143 //! creates the new module \c name and evaluates the given file in the context of that module
144 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
145 //! to a module later on.
146 //! The user needs to make sure that the \c name is unique in the python module dictionary.
147 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
148
149 //! creates the new module \c name and evaluates the given script in the context of that module.
150 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
151 //! to a module later on.
152 //! The user needs to make sure that the \c name is unique in the python module dictionary.
153 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
154
155 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
156 //! script code
157 PythonQtObjectPtr createUniqueModule();
158
140 159 //@{ Signal handlers
141 160
142 161 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
143 162 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
144 163
145 164 //! remove a signal handler from the given \c signal of \c obj
146 165 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
147 166
148 167 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
149 168 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
150 169
151 170 //! remove a signal handler from the given \c signal of \c obj
152 171 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
153 172
154 173 //@}
155 174
156 175 //@{ Variable access
157 176
158 177 //! add the given \c object to the \c module as a variable with \c name (it can be removed via clearVariable)
159 178 void addObject(PyObject* module, const QString& name, QObject* object);
160 179
161 180 //! add the given variable to the module
162 181 void addVariable(PyObject* module, const QString& name, const QVariant& v);
163 182
164 183 //! remove the given variable
165 184 void removeVariable(PyObject* module, const QString& name);
166 185
167 186 //! get the variable with the \c name of the \c module, returns an invalid QVariant on error
168 187 QVariant getVariable(PyObject* module, const QString& name);
169 188
170 189 //! read vars etc. in scope of a module, optional looking inside of an object \c objectname
171 190 QStringList introspection(PyObject* module, const QString& objectname, ObjectType type);
172 191
173 192 //! returns the found callable object or NULL
174 193 //! @return new reference
175 194 PythonQtObjectPtr lookupCallable(PyObject* module, const QString& name);
176 195
177 196 //@}
178 197
179 198 //@{ Calling of python callables
180 199
181 200 //! call the given python method, returns the result converted to a QVariant
182 201 QVariant call(PyObject* module, const QString& callable, const QVariantList& args);
183 202
184 203 //@}
185 204
186 205 //@{ Decorations, constructors, wrappers...
187 206
188 207
189 208 //! add an object whose slots will be used as decorator slots for
190 209 //! other QObjects or CPP classes. The slots need to follow the
191 210 //! convention that the first argument is a pointer to the wrapped object.
192 211 //! (ownership is passed to PythonQt)
193 212 /*!
194 213 Example:
195 214
196 215 A slot with the signature
197 216
198 217 \code
199 218 bool doSomething(QWidget* w, int a)
200 219 \endcode
201 220
202 221 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
203 222 that will be called with the concrete instance as first argument.
204 223 So in Python you can now e.g. call
205 224
206 225 \code
207 226 someWidget.doSomething(12)
208 227 \endcode
209 228
210 229 without QWidget really having this method. This allows to easily make normal methods
211 230 of Qt classes callable by forwarding them with such decorator slots
212 231 or to make CPP classes (which are not derived from QObject) callable from Python.
213 232 */
214 233 void addInstanceDecorators(QObject* o);
215 234
216 235 //! add an object whose slots will be used as decorator slots for
217 236 //! class objects (ownership is passed to PythonQt)
218 237 /*!
219 238 The slots need to follow the following convention:
220 239 - SomeClass* new_SomeClass(...)
221 240 - QVariant new_SomeClass(...)
222 241 - void delete_SomeClass(SomeClass*)
223 242 - ... static_SomeClass_someName(...)
224 243
225 244 This will add:
226 245 - a constructor
227 246 - a constructor which generates a QVariant
228 247 - a destructor (only useful for CPP objects)
229 248 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
230 249
231 250 */
232 251 void addClassDecorators(QObject* o);
233 252
234 253 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
235 254 void addDecorators(QObject* o);
236 255
237 256 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
238 257 //! (ownership of wrapper is passed to PythonQt)
239 258 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
240 259
241 260 This will add a wrapper object that is used to make calls to the given classname \c typeName.
242 261 All slots that take a pointer to typeName as the first argument will be callable from Python on
243 262 a variant object that contains such a type.
244 263 */
245 264 void addVariantWrapper(const char* typeName, QObject* wrapper);
246 265
247 266 //! add the given factory to PythonQt (ownership stays with caller)
248 267 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
249 268
250 269 //! add the given constructor handler to PythonQt (ownership stays with caller)
251 270 void addConstructorHandler(PythonQtConstructorHandler* handler);
252 271
253 272 //! get list of constructor handlers
254 273 const QList<PythonQtConstructorHandler*>& constructorHandlers();
255 274
256 275 //@}
257 276
258 277 //@{ Custom importer (to replace internal import implementation of python)
259 278
260 279 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
261 280 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
262 281 //! It can only be called once, further calls will be ignored silently. (ownership stays with caller)
263 282 void setImporter(PythonQtImportFileInterface* importInterface);
264 283
265 284 //! set paths that the importer should ignore
266 285 void setImporterIgnorePaths(const QStringList& paths);
267 286
268 287 //! get paths that the importer should ignore
269 288 const QStringList& getImporterIgnorePaths();
270 289
271 290 //@}
272 291
273 292 //! get access to internal data (should not be used on the public API, but is used by some C functions)
274 293 static PythonQtPrivate* priv() { return _self->_p; }
275 294
276 295 //! get access to the file importer (if set)
277 296 static PythonQtImportFileInterface* importInterface();
278 297
279 298 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
280 299 //! The error is currently just output to the python stderr, future version might implement better trace printing
281 300 bool handleError();
282 301
302 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
303 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
304 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
305 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
306
307 //! call the callback if it is set
308 static void qObjectNoLongerWrappedCB(QObject* o);
309
283 310 signals:
284 311 //! emitted when python outputs something to stdout (and redirection is turned on)
285 312 void pythonStdOut(const QString& str);
286 313 //! emitted when python outputs something to stderr (and redirection is turned on)
287 314 void pythonStdErr(const QString& str);
288 315
289 316 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
290 317 void pythonHelpRequest(const QByteArray& cppClassName);
291 318
292 319
293 320 public:
294 321 //! called by internal help methods
295 322 PyObject* helpCalled(PythonQtClassInfo* info);
296 323
297 324 //! returns the found object or NULL
298 325 //! @return new reference
299 326 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
300 327
301 328 private:
302 329 void initPythonQtModule(bool redirectStdOut);
303 330
304 331 //! callback for stdout redirection, emits pythonStdOut signal
305 332 static void stdOutRedirectCB(const QString& str);
306 333 //! callback for stderr redirection, emits pythonStdErr signal
307 334 static void stdErrRedirectCB(const QString& str);
308 335
309 336 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
310 337 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
311 338
312 339 PythonQt(int flags);
313 340 ~PythonQt();
314 341
315 342 static PythonQt* _self;
343 static int _uniqueModuleCount;
316 344
317 345 PythonQtPrivate* _p;
318 346
319 347 };
320 348
321 349 //! internal PythonQt details
322 350 class PythonQtPrivate : public QObject {
323 351
324 352 Q_OBJECT
325 353
326 354 public:
327 355 PythonQtPrivate();
328 356 ~PythonQtPrivate();
329 357
330 358 //! returns if the id is the id for PythonQtObjectPtr
331 359 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
332 360
333 361 //! remove the wrapper ptr again
334 void removeWrapperPointer(void* obj) { _wrappedObjects.take(obj); }
362 void removeWrapperPointer(void* obj);
363
364 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
365 void removeSignalEmitter(QObject* obj);
335 366
336 367 //! wrap the given QObject into a Python object (or return existing wrapper!)
337 368 PyObject* wrapQObject(QObject* obj);
338 369
339 370 //! 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
340 371 PyObject* wrapPtr(void* ptr, const QByteArray& name);
341 372
342 373 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
343 374 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
344 375 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
345 376 void registerClass(const QMetaObject* metaobject);
346 377
347 378 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
348 379 //! and it will register the classes when it first sees a pointer to such a derived class
349 380 void registerQObjectClassNames(const QStringList& names);
350 381
351 382 //! add a decorator object
352 383 void addDecorators(QObject* o, bool instanceDeco, bool classDeco);
353 384
354 385 //! add a wrapper object for the given qvariant, also does an addConstructors() to add constructors for variants
355 386 void addVariantWrapper(const char* typeName, QObject* wrapper);
356 387
357 388 //! get list of all slots that are available as decorator slots
358 389 QList<PythonQtSlotInfo*> getDecoratorSlots(const QByteArray& className);
359 390
360 391 //! check if the enum is either part of the \c meta class or contains a scope and is
361 392 //! an enum of another known metaobject (and as last resort, of the Qt namespace)
362 393 bool isEnumType(const QMetaObject* meta, const QByteArray& name);
363 394
364 395 //! helper method that creates a PythonQtMetaObjectWrapper object
365 396 PythonQtMetaObjectWrapper* createNewPythonQtMetaObjectWrapper(PythonQtClassInfo* info);
366 397
367 398 //! helper method that creates a PythonQtWrapper object and registers it in the object map
368 399 PythonQtWrapper* createNewPythonQtWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
369 400
370 401 //! helper method that creates a PythonQtVariantWrapper object
371 402 PythonQtVariantWrapper* createNewPythonQtVariantWrapper(const QVariant& variant);
372 403
373 404 //! get the class info for a meta object (if available)
374 405 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownQtClasses.value(meta->className()); }
375 406
376 407 //! get the constructor slot for the given classname
377 408 PythonQtSlotInfo* getConstructorSlot(const QByteArray& className) { return _constructorSlots.value(className); }
378 409
379 410 //! get the destructor slot for the given classname
380 411 PythonQtSlotInfo* getDestructorSlot(const QByteArray& className) { return _destructorSlots.value(className); }
381 412
382 protected slots:
383 //! called when a wrapped QObject is destroyed
384 void wrappedObjectDestroyed(QObject* obj);
385
386 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
387 void destroyedSignalEmitter(QObject* obj);
413 //! creates the new module from the given pycode
414 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
388 415
389 416 private:
390 417
418 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
419 PythonQtWrapper* findWrapperAndRemoveUnused(void* obj);
420
391 421 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
392 422 QHash<void* , PythonQtWrapper *> _wrappedObjects;
393 423
394 424 //! stores the meta info of known Qt classes
395 425 QHash<QByteArray, PythonQtClassInfo *> _knownQtClasses;
396 426
397 427 //! stores the meta info of known Qt classes
398 428 QHash<QByteArray, PythonQtClassInfo *> _knownQtWrapperClasses;
399 429
400 430 //! stores the meta info of known Qt C++ wrapper classes
401 431 QMultiHash<QByteArray, PythonQtSlotInfo *> _knownQtDecoratorSlots;
402 432
403 433 //! names of qobject derived classes that can be casted to qobject savely
404 434 QHash<QByteArray, bool> _knownQObjectClassNames;
405 435
406 436 //! stores signal receivers for QObjects
407 437 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
408 438
409 439 //! the PythonQt python module
410 440 PythonQtObjectPtr _pythonQtModule;
411 441
412 442 //! the importer interface (if set)
413 443 PythonQtImportFileInterface* _importInterface;
414 444
445 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
446 PythonQtQObjectWrappedCB* _wrappedCB;
447
415 448 QStringList _importIgnorePaths;
416 449
417 450 //! the cpp object wrapper factories
418 451 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
419 452
420 453 //! the cpp object wrapper factories
421 454 QList<PythonQtConstructorHandler*> _constructorHandlers;
422 455
423 456 QHash<QByteArray , PythonQtSlotInfo *> _constructorSlots;
424 457 QHash<QByteArray , PythonQtSlotInfo *> _destructorSlots;
425 458
426 459 QHash<int , QPair<PythonQtClassInfo*, QObject*> > _knownVariantWrappers;
427 460
428 461 PythonQtClassInfo* _qtNamespace;
429 462
430 463 int _initFlags;
431 464 int _PythonQtObjectPtr_metaId;
432 465
433 466 friend class PythonQt;
434 467 };
435 468
436 469 #endif
@@ -1,1012 +1,1017
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 "PythonQtVariantWrapper.h"
45 45 #include <QDateTime>
46 46 #include <QTime>
47 47 #include <QDate>
48 48
49 49 PythonQtValueStorage<qint64, 128> PythonQtConv::global_valueStorage;
50 50 PythonQtValueStorage<void*, 128> PythonQtConv::global_ptrStorage;
51 51 PythonQtValueStorage<QVariant, 32> PythonQtConv::global_variantStorage;
52 52
53 53
54 54 PyObject* PythonQtConv::GetPyBool(bool val)
55 55 {
56 56 PyObject* r = val?Py_True:Py_False;
57 57 Py_INCREF(r);
58 58 return r;
59 59 }
60 60
61 61 PyObject* PythonQtConv::ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, void* data) {
62 62 if (info.typeId == QMetaType::Void) {
63 63 Py_INCREF(Py_None);
64 64 return Py_None;
65 65 } else {
66 66 if (info.isPointer && (info.typeId == PythonQtMethodInfo::Unknown)) {
67 67 // try to convert the pointer to a Python Object
68 68 PyObject* pyObj = PythonQt::priv()->wrapPtr(*((void**)data), info.name);
69 69 if (pyObj) {
70 70 return pyObj;
71 71 } else {
72 72 std::cerr << "unknown pointer type " << info.name.data() << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
73 73 Py_INCREF(Py_None);
74 74 return Py_None;
75 75 }
76 76 } else if (info.isPointer && (info.typeId == QMetaType::Char)) {
77 77 // a char ptr will probably be a null terminated string, so we support that:
78 78 return PyString_FromString(*((char**)data));
79 79 } else {
80 80 if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
81 81 if (info.name.startsWith("QList<")) {
82 82 QByteArray innerType = info.name.mid(6,info.name.length()-7);
83 83 if (innerType.endsWith("*")) {
84 84 innerType.truncate(innerType.length()-1);
85 85 return ConvertQListWithPointersToPython((QList<void*>*)data, innerType);
86 86 }
87 87 }
88 88 }
89 89 // handle values that are not yet handled and not pointers
90 90 return ConvertQtValueToPythonInternal(info.typeId, data);
91 91 }
92 92 }
93 93 }
94 94
95 95 PyObject* PythonQtConv::ConvertQtValueToPythonInternal(int type, void* data) {
96 96 switch (type) {
97 97 case QMetaType::Void:
98 98 Py_INCREF(Py_None);
99 99 return Py_None;
100 100 case QMetaType::Char:
101 101 return PyInt_FromLong(*((char*)data));
102 102 case QMetaType::UChar:
103 103 return PyInt_FromLong(*((unsigned char*)data));
104 104 case QMetaType::Short:
105 105 return PyInt_FromLong(*((short*)data));
106 106 case QMetaType::UShort:
107 107 return PyInt_FromLong(*((unsigned short*)data));
108 108 case QMetaType::Long:
109 109 return PyInt_FromLong(*((long*)data));
110 110 case QMetaType::ULong:
111 111 // does not fit into simple int of python
112 112 return PyLong_FromUnsignedLong(*((unsigned long*)data));
113 113 case QMetaType::Bool:
114 114 return PythonQtConv::GetPyBool(*((bool*)data));
115 115 case QMetaType::Int:
116 116 return PyInt_FromLong(*((int*)data));
117 117 case QMetaType::UInt:
118 118 return PyInt_FromLong(*((unsigned int*)data));
119 119 case QMetaType::QChar:
120 120 return PyInt_FromLong(*((short*)data));
121 121 case QMetaType::Float:
122 122 return PyFloat_FromDouble(*((float*)data));
123 123 case QMetaType::Double:
124 124 return PyFloat_FromDouble(*((double*)data));
125 125 case QMetaType::LongLong:
126 126 return PyLong_FromLongLong(*((qint64*)data));
127 127 case QMetaType::ULongLong:
128 128 return PyLong_FromUnsignedLongLong(*((quint64*)data));
129 129 case QMetaType::QByteArray: {
130 130 QByteArray* v = (QByteArray*) data;
131 131 return PyString_FromStringAndSize(*v, v->size());
132 132 }
133 133 case QMetaType::QVariantMap:
134 134 return PythonQtConv::QVariantMapToPyObject(*((QVariantMap*)data));
135 135 case QMetaType::QVariantList:
136 136 return PythonQtConv::QVariantListToPyObject(*((QVariantList*)data));
137 137 case QMetaType::QString:
138 138 return PythonQtConv::QStringToPyObject(*((QString*)data));
139 139 case QMetaType::QStringList:
140 140 return PythonQtConv::QStringListToPyObject(*((QStringList*)data));
141 141
142 142 case PythonQtMethodInfo::Variant:
143 143 return PythonQtConv::QVariantToPyObject(*((QVariant*)data));
144 144 case QMetaType::QObjectStar:
145 145 case QMetaType::QWidgetStar:
146 146 return PythonQt::priv()->wrapQObject(*((QObject**)data));
147 147
148 148 // the following cases could be handled by the default case, but it is faster to do it with
149 149 // direct casts:
150 150 case QMetaType::QDate:
151 151 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QDate*)data)));
152 152 case QMetaType::QTime:
153 153 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QTime*)data)));
154 154 case QMetaType::QDateTime:
155 155 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QDateTime*)data)));
156 156 case QMetaType::QRect:
157 157 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QRect*)data)));
158 158 case QMetaType::QSize:
159 159 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QSize*)data)));
160 160 case QMetaType::QPoint:
161 161 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QPoint*)data)));
162 162 case QMetaType::QColor:
163 163 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QColor*)data)));
164 164 case QMetaType::QPixmap:
165 165 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QPixmap*)data)));
166 166 case QMetaType::QUrl:
167 167 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QUrl*)data)));
168 168 case QMetaType::QRectF:
169 169 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QRectF*)data)));
170 170 case QMetaType::QSizeF:
171 171 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QSizeF*)data)));
172 172 case QMetaType::QLine:
173 173 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QLine*)data)));
174 174 case QMetaType::QLineF:
175 175 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QLineF*)data)));
176 176 case QMetaType::QPointF:
177 177 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QPointF*)data)));
178 178 case QMetaType::QRegExp:
179 179 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QRegExp*)data)));
180 180 case QMetaType::QBitArray:
181 181 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QBitArray*)data)));
182 182 case QMetaType::QLocale:
183 183 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QLocale*)data)));
184 184 case QMetaType::QFont:
185 185 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QFont*)data)));
186 186 case QMetaType::QBrush:
187 187 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QBrush*)data)));
188 188 case QMetaType::QPalette:
189 189 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QPalette*)data)));
190 190 case QMetaType::QIcon:
191 191 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(qVariantFromValue(*((QIcon*)data)));
192 192 case QMetaType::QImage:
193 193 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QImage*)data)));
194 194 case QMetaType::QPolygon:
195 195 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QPolygon*)data)));
196 196 case QMetaType::QRegion:
197 197 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QRegion*)data)));
198 198 case QMetaType::QBitmap:
199 199 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(qVariantFromValue(*((QBitmap*)data)));
200 200 case QMetaType::QCursor:
201 201 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QCursor*)data)));
202 202 case QMetaType::QSizePolicy:
203 203 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QSizePolicy*)data)));
204 204 case QMetaType::QKeySequence:
205 205 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(qVariantFromValue(*((QKeySequence*)data)));
206 206 case QMetaType::QPen:
207 207 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(qVariantFromValue(*((QPen*)data)));
208 208 case QMetaType::QTextLength:
209 209 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(qVariantFromValue(*((QTextLength*)data)));
210 210 case QMetaType::QTextFormat:
211 211 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(qVariantFromValue(*((QTextFormat*)data)));
212 212 case QMetaType::QMatrix:
213 213 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(qVariantFromValue(*((QMatrix*)data)));
214 214 default:
215 215 if (PythonQt::priv()->isPythonQtObjectPtrMetaId(type)) {
216 216 PyObject* o = ((PythonQtObjectPtr*)data)->object();
217 217 Py_INCREF(o);
218 218 return o;
219 219 } else {
220 220 if (type != PythonQtMethodInfo::Unknown) {
221 221 QVariant v(type, data);
222 222 if (v.isValid()) {
223 223 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(v);
224 224 }
225 225 }
226 226 std::cerr << "Unknown type that can not be converted to Python: " << type << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
227 227 }
228 228 }
229 229 Py_INCREF(Py_None);
230 230 return Py_None;
231 231 }
232 232
233 233 void* PythonQtConv::CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info) {
234 234 void* ptr = NULL;
235 235 if (info.isPointer) {
236 236 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
237 237 } else {
238 238 switch (info.typeId) {
239 239 case QMetaType::Char:
240 240 case QMetaType::UChar:
241 241 case QMetaType::Short:
242 242 case QMetaType::UShort:
243 243 case QMetaType::Long:
244 244 case QMetaType::ULong:
245 245 case QMetaType::Bool:
246 246 case QMetaType::Int:
247 247 case QMetaType::UInt:
248 248 case QMetaType::QChar:
249 249 case QMetaType::Float:
250 250 case QMetaType::Double:
251 251 PythonQtValueStorage_ADD_VALUE(global_valueStorage, long, 0, ptr);
252 252 break;
253 253 case PythonQtMethodInfo::Variant:
254 254 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, 0, ptr);
255 255 // return the ptr to the variant
256 256 break;
257 257 default:
258 258 if (info.typeId == PythonQtMethodInfo::Unknown) {
259 259 // check if we have a QList of pointers, which we can circumvent with a QList<void*>
260 260 if (info.name.startsWith("QList<")) {
261 261 QByteArray innerType = info.name.mid(6,info.name.length()-7);
262 262 if (innerType.endsWith("*")) {
263 263 static int id = QMetaType::type("QList<void*>");
264 264 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr);
265 265 // return the constData pointer that will be filled with the result value later on
266 266 ptr = (void*)((QVariant*)ptr)->constData();
267 267 }
268 268 }
269 269 }
270 270
271 271 if (!ptr) {
272 272 // everything else is stored in a QVariant...
273 273 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
274 274 // return the constData pointer that will be filled with the result value later on
275 275 ptr = (void*)((QVariant*)ptr)->constData();
276 276 }
277 277 }
278 278 }
279 279 return ptr;
280 280 }
281 281
282 282 void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, const QMetaObject* meta)
283 283 {
284 284 bool ok;
285 285 void* ptr = NULL;
286 286 if (info.isPointer) {
287 287 if (obj->ob_type == &PythonQtWrapper_Type) {
288 288 PythonQtWrapper* wrap = (PythonQtWrapper*)obj;
289 289 // c++ wrapper, check if the class names of the c++ objects match
290 290 if (wrap->_info->isCPPWrapper()) {
291 291 //TODO: we could support inheritance on cpp wrappers as well
292 292 if (wrap->_info->wrappedCPPClassName() == info.name) {
293 293 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, wrap->_wrappedPtr, ptr);
294 294 } else {
295 295 // not matching
296 296 }
297 297 } else {
298 298 if (wrap->_info->inherits(info.name)) {
299 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, wrap->_obj, ptr);
299 QObject* myObject = wrap->_obj;
300 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, myObject, ptr);
300 301 } else {
301 302 // not matching
302 303 }
303 304 }
304 305 } else
305 306 if (info.typeId == QMetaType::Char || info.typeId == QMetaType::UChar) {
306 307 QString str = PyObjGetString(obj, strict, ok);
307 308 if (ok) {
308 309 void* ptr2 = NULL;
309 310 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant(str.toUtf8()), ptr2);
310 311 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr);
311 312 }
312 313 } else if (info.name == "PyObject") {
313 314 // handle low level PyObject directly
314 315 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, obj, ptr);
315 316 } else if (obj == Py_None) {
316 317 // None is treated as a NULL ptr
317 318 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
318 319 } else {
319 320 // if we are not strict, we try if we are passed a 0 integer
320 321 if (!strict) {
321 322 bool ok;
322 323 int value = PyObjGetInt(obj, true, ok);
323 324 if (ok && value==0) {
324 325 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
325 326 }
326 327 }
327 328 // EXTRA: we could support pointers to other simple types, but this would not make sense in most situations
328 329 }
329 330
330 331 } else {
331 332 // not a pointer
332 333 switch (info.typeId) {
333 334 case QMetaType::Char:
334 335 {
335 336 int val = PyObjGetInt(obj, strict, ok);
336 337 if (ok) {
337 338 PythonQtValueStorage_ADD_VALUE(global_valueStorage, char, val, ptr);
338 339 }
339 340 }
340 341 break;
341 342 case QMetaType::UChar:
342 343 {
343 344 int val = PyObjGetInt(obj, strict, ok);
344 345 if (ok) {
345 346 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned char, val, ptr);
346 347 }
347 348 }
348 349 break;
349 350 case QMetaType::Short:
350 351 {
351 352 int val = PyObjGetInt(obj, strict, ok);
352 353 if (ok) {
353 354 PythonQtValueStorage_ADD_VALUE(global_valueStorage, short, val, ptr);
354 355 }
355 356 }
356 357 break;
357 358 case QMetaType::UShort:
358 359 {
359 360 int val = PyObjGetInt(obj, strict, ok);
360 361 if (ok) {
361 362 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned short, val, ptr);
362 363 }
363 364 }
364 365 break;
365 366 case QMetaType::Long:
366 367 {
367 368 long val = (long)PyObjGetLongLong(obj, strict, ok);
368 369 if (ok) {
369 370 PythonQtValueStorage_ADD_VALUE(global_valueStorage, long, val, ptr);
370 371 }
371 372 }
372 373 break;
373 374 case QMetaType::ULong:
374 375 {
375 376 unsigned long val = (unsigned long)PyObjGetLongLong(obj, strict, ok);
376 377 if (ok) {
377 378 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned long, val, ptr);
378 379 }
379 380 }
380 381 break;
381 382 case QMetaType::Bool:
382 383 {
383 384 bool val = PyObjGetBool(obj, strict, ok);
384 385 if (ok) {
385 386 PythonQtValueStorage_ADD_VALUE(global_valueStorage, bool, val, ptr);
386 387 }
387 388 }
388 389 break;
389 390 case QMetaType::Int:
390 391 {
391 392 int val = PyObjGetInt(obj, strict, ok);
392 393 if (ok) {
393 394 PythonQtValueStorage_ADD_VALUE(global_valueStorage, int, val, ptr);
394 395 }
395 396 }
396 397 break;
397 398 case QMetaType::UInt:
398 399 {
399 400 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
400 401 if (ok) {
401 402 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned int, val, ptr);
402 403 }
403 404 }
404 405 break;
405 406 case QMetaType::QChar:
406 407 {
407 408 int val = PyObjGetInt(obj, strict, ok);
408 409 if (ok) {
409 410 PythonQtValueStorage_ADD_VALUE(global_valueStorage, short, val, ptr);
410 411 }
411 412 }
412 413 break;
413 414 case QMetaType::Float:
414 415 {
415 416 float val = (float)PyObjGetDouble(obj, strict, ok);
416 417 if (ok) {
417 418 PythonQtValueStorage_ADD_VALUE(global_valueStorage, float, val, ptr);
418 419 }
419 420 }
420 421 break;
421 422 case QMetaType::Double:
422 423 {
423 424 double val = (double)PyObjGetDouble(obj, strict, ok);
424 425 if (ok) {
425 426 PythonQtValueStorage_ADD_VALUE(global_valueStorage, double, val, ptr);
426 427 }
427 428 }
428 429 break;
429 430 case QMetaType::LongLong:
430 431 {
431 432 qint64 val = PyObjGetLongLong(obj, strict, ok);
432 433 if (ok) {
433 434 PythonQtValueStorage_ADD_VALUE(global_valueStorage, qint64, val, ptr);
434 435 }
435 436 }
436 437 break;
437 438 case QMetaType::ULongLong:
438 439 {
439 440 quint64 val = PyObjGetULongLong(obj, strict, ok);
440 441 if (ok) {
441 442 PythonQtValueStorage_ADD_VALUE(global_valueStorage, quint64, val, ptr);
442 443 }
443 444 }
444 445 break;
445 446 case QMetaType::QByteArray:
446 447 {
447 448 QByteArray bytes = PyObjGetBytes(obj, strict, ok);
448 449 if (ok) {
449 450 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant(bytes), ptr);
450 451 ptr = (void*)((QVariant*)ptr)->constData();
451 452 }
452 453 }
453 454 break;
454 455 case QMetaType::QString:
455 456 {
456 457 QString str = PyObjGetString(obj, strict, ok);
457 458 if (ok) {
458 459 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant(str), ptr);
459 460 ptr = (void*)((QVariant*)ptr)->constData();
460 461 }
461 462 }
462 463 break;
463 464 case QMetaType::QStringList:
464 465 {
465 466 QStringList l = PyObjToStringList(obj, strict, ok);
466 467 if (ok) {
467 468 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant(l), ptr);
468 469 ptr = (void*)((QVariant*)ptr)->constData();
469 470 }
470 471 }
471 472 break;
472 473
473 474 case PythonQtMethodInfo::Variant:
474 475 {
475 476 QVariant v = PyObjToQVariant(obj);
476 477 if (v.isValid()) {
477 478 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, v, ptr);
478 479 }
479 480 }
480 481 break;
481 482 default:
482 483 {
483 484 if (info.typeId == PythonQtMethodInfo::Unknown) {
484 485 // check for enum case
485 486 if (PythonQt::priv()->isEnumType(meta, info.name)) {
486 487 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
487 488 if (ok) {
488 489 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned int, val, ptr);
489 490 return ptr;
491 } else {
492 return NULL;
490 493 }
491 494 }
492 495 }
493 496 if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
494 497 // check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant
495 498 if (info.name.startsWith("QList<")) {
496 499 QByteArray innerType = info.name.mid(6,info.name.length()-7);
497 500 if (innerType.endsWith("*")) {
498 501 innerType.truncate(innerType.length()-1);
499 502 static int id = QMetaType::type("QList<void*>");
500 503 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr);
501 504 ptr = (void*)((QVariant*)ptr)->constData();
502 505 ok = ConvertPythonListToQListOfType(obj, (QList<void*>*)ptr, innerType, strict);
503 506 if (ok) {
504 507 return ptr;
505 508 } else {
506 509 return NULL;
507 510 }
508 511 }
509 512 }
510 513 }
511 514
512 515 // for all other types, we use the same qvariant conversion and pass out the constData of the variant:
513 516 QVariant v = PyObjToQVariant(obj, info.typeId);
514 517 if (v.isValid()) {
515 518 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, v, ptr);
516 519 ptr = (void*)((QVariant*)ptr)->constData();
517 520 }
518 521 }
519 522 }
520 523 }
521 524 return ptr;
522 525 }
523 526
524 527
525 528 QStringList PythonQtConv::PyObjToStringList(PyObject* val, bool strict, bool& ok) {
526 529 QStringList v;
527 530 ok = false;
528 531 // if we are strict, we do not want to convert a string to a stringlist
529 532 // (strings in python are detected to be sequences)
530 533 if (strict &&
531 534 (val->ob_type == &PyString_Type ||
532 535 PyUnicode_Check(val))) {
533 536 ok = false;
534 537 return v;
535 538 }
536 539 if (PySequence_Check(val)) {
537 540 int count = PySequence_Size(val);
538 541 for (int i = 0;i<count;i++) {
539 542 PyObject* value = PySequence_GetItem(val,i);
540 543 v.append(PyObjGetString(value,false,ok));
541 544 }
542 545 ok = true;
543 546 }
544 547 return v;
545 548 }
546 549
547 550 QString PythonQtConv::PyObjGetRepresentation(PyObject* val)
548 551 {
549 552 QString r;
550 553 PyObject* str = PyObject_Repr(val);
551 554 if (str) {
552 555 r = QString(PyString_AS_STRING(str));
553 556 Py_DECREF(str);
554 557 }
555 558 return r;
556 559 }
557 560
558 561 QString PythonQtConv::PyObjGetString(PyObject* val, bool strict, bool& ok) {
559 562 QString r;
560 563 ok = true;
561 564 if (val->ob_type == &PyString_Type) {
562 565 r = QString(PyString_AS_STRING(val));
563 566 } else if (PyUnicode_Check(val)) {
564 567 #ifdef WIN32
565 568 r = QString::fromUtf16(PyUnicode_AS_UNICODE(val));
566 569 #else
567 570 PyObject *ptmp = PyUnicode_AsUTF8String(val);
568 571 if(ptmp) {
569 572 r = QString::fromUtf8(PyString_AS_STRING(ptmp));
570 573 Py_DECREF(ptmp);
571 574 }
572 575 #endif
573 576 } else if (!strict) {
574 577 // EXTRA: could also use _Unicode, but why should we?
575 578 PyObject* str = PyObject_Str(val);
576 579 if (str) {
577 580 r = QString(PyString_AS_STRING(str));
578 581 Py_DECREF(str);
579 582 } else {
580 583 ok = false;
581 584 }
582 585 } else {
583 586 ok = false;
584 587 }
585 588 return r;
586 589 }
587 590
588 591 QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool strict, bool& ok) {
589 592 QByteArray r;
590 593 ok = true;
591 594 if (val->ob_type == &PyString_Type) {
592 595 long size = PyString_GET_SIZE(val);
593 596 r = QByteArray(PyString_AS_STRING(val), size);
594 597 } else {
595 598 ok = false;
596 599 }
597 600 return r;
598 601 }
599 602
600 603 bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) {
601 604 bool d = false;
602 605 ok = false;
603 606 if (val == Py_False) {
604 607 d = false;
605 608 ok = true;
606 609 } else if (val == Py_True) {
607 610 d = true;
608 611 ok = true;
609 612 } else if (!strict) {
610 613 d = PyObjGetInt(val, false, ok)!=0;
611 614 ok = true;
612 615 }
613 616 return d;
614 617 }
615 618
616 619 int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) {
617 620 int d = 0;
618 621 ok = true;
619 622 if (val->ob_type == &PyInt_Type) {
620 623 d = PyInt_AS_LONG(val);
621 624 } else if (!strict) {
622 625 if (val->ob_type == &PyFloat_Type) {
623 626 d = floor(PyFloat_AS_DOUBLE(val));
624 627 } else if (val->ob_type == &PyLong_Type) {
625 628 // handle error on overflow!
626 629 d = PyLong_AsLong(val);
627 630 } else if (val == Py_False) {
628 631 d = 0;
629 632 } else if (val == Py_True) {
630 633 d = 1;
631 634 } else {
632 635 ok = false;
633 636 }
634 637 } else {
635 638 ok = false;
636 639 }
637 640 return d;
638 641 }
639 642
640 643 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
641 644 qint64 d = 0;
642 645 ok = true;
643 646 if (val->ob_type == &PyInt_Type) {
644 647 d = PyInt_AS_LONG(val);
645 648 } else if (val->ob_type == &PyLong_Type) {
646 649 d = PyLong_AsLongLong(val);
647 650 } else if (!strict) {
648 651 if (val->ob_type == &PyFloat_Type) {
649 652 d = floor(PyFloat_AS_DOUBLE(val));
650 653 } else if (val == Py_False) {
651 654 d = 0;
652 655 } else if (val == Py_True) {
653 656 d = 1;
654 657 } else {
655 658 ok = false;
656 659 }
657 660 } else {
658 661 ok = false;
659 662 }
660 663 return d;
661 664 }
662 665
663 666 quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) {
664 667 quint64 d = 0;
665 668 ok = true;
666 669 if (val->ob_type == &PyInt_Type) {
667 670 d = PyInt_AS_LONG(val);
668 671 } else if (val->ob_type == &PyLong_Type) {
669 672 d = PyLong_AsLongLong(val);
670 673 } else if (!strict) {
671 674 if (val->ob_type == &PyFloat_Type) {
672 675 d = floor(PyFloat_AS_DOUBLE(val));
673 676 } else if (val == Py_False) {
674 677 d = 0;
675 678 } else if (val == Py_True) {
676 679 d = 1;
677 680 } else {
678 681 ok = false;
679 682 }
680 683 } else {
681 684 ok = false;
682 685 }
683 686 return d;
684 687 }
685 688
686 689 double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) {
687 690 double d = 0;
688 691 ok = true;
689 692 if (val->ob_type == &PyFloat_Type) {
690 693 d = PyFloat_AS_DOUBLE(val);
691 694 } else if (!strict) {
692 695 if (val->ob_type == &PyInt_Type) {
693 696 d = PyInt_AS_LONG(val);
694 697 } else if (val->ob_type == &PyLong_Type) {
695 698 d = PyLong_AsLong(val);
696 699 } else if (val == Py_False) {
697 700 d = 0;
698 701 } else if (val == Py_True) {
699 702 d = 1;
700 703 } else {
701 704 ok = false;
702 705 }
703 706 } else {
704 707 ok = false;
705 708 }
706 709 return d;
707 710 }
708 711
709 712 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
710 713 {
711 714 QVariant v;
712 715 bool ok = true;
713 716
714 717 if (type==-1) {
715 718 // no special type requested
716 719 if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) {
717 720 type = QVariant::String;
718 721 } else if (val->ob_type==&PyInt_Type) {
719 722 type = QVariant::Int;
720 723 } else if (val->ob_type==&PyLong_Type) {
721 724 type = QVariant::LongLong;
722 725 } else if (val->ob_type==&PyFloat_Type) {
723 726 type = QVariant::Double;
724 727 } else if (val == Py_False || val == Py_True) {
725 728 type = QVariant::Bool;
726 729 } else if (val->ob_type == &PythonQtWrapper_Type) {
727 730 PythonQtWrapper* wrap = (PythonQtWrapper*)val;
728 731 // c++ wrapper, check if the class names of the c++ objects match
729 732 if (wrap->_info->isCPPWrapper()) {
730 733 // is this worth anything? we loose the knowledge of the cpp object type
731 734 v = qVariantFromValue(wrap->_wrappedPtr);
732 735 } else {
733 v = qVariantFromValue(wrap->_obj);
736 QObject* myObject = wrap->_obj;
737 v = qVariantFromValue(myObject);
734 738 }
735 739 return v;
736 740 } else if (val->ob_type==&PyDict_Type) {
737 741 type = QVariant::Map;
738 742 } else if (val->ob_type==&PyList_Type || val->ob_type==&PyTuple_Type || PySequence_Check(val)) {
739 743 type = QVariant::List;
740 744 } else if (val == Py_None) {
741 745 // none is invalid
742 746 type = QVariant::Invalid;
743 747 } else if (val->ob_type == &PythonQtVariantWrapper_Type) {
744 748 PythonQtVariantWrapper* varWrap = (PythonQtVariantWrapper*)val;
745 749 if (varWrap->_variant->userType() == type) {
746 750 v = *varWrap->_variant;
747 751 return v;
748 752 }
749 753 } else {
750 754 // this used to be:
751 755 // type = QVariant::String;
752 756 // but now we want to transport the Python Objects directly:
753 757 PythonQtObjectPtr o(val);
754 758 v = qVariantFromValue(o);
755 759 return v;
756 760 }
757 761 }
758 762 // special type request:
759 763 switch (type) {
760 764 case QVariant::Invalid:
761 765 return v;
762 766 break;
763 767 case QVariant::Int:
764 768 {
765 769 int d = PyObjGetInt(val, false, ok);
766 770 if (ok) return QVariant(d);
767 771 }
768 772 break;
769 773 case QVariant::UInt:
770 774 {
771 775 int d = PyObjGetInt(val, false,ok);
772 776 if (ok) v = QVariant((unsigned int)d);
773 777 }
774 778 break;
775 779 case QVariant::Bool:
776 780 {
777 781 int d = PyObjGetBool(val,false,ok);
778 782 if (ok) v = QVariant((bool)(d!=0));
779 783 }
780 784 break;
781 785 case QVariant::Double:
782 786 {
783 787 double d = PyObjGetDouble(val,false,ok);
784 788 if (ok) v = QVariant(d);
785 789 break;
786 790 }
787 791 case QMetaType::Float:
788 792 {
789 793 float d = (float) PyObjGetDouble(val,false,ok);
790 794 if (ok) v = qVariantFromValue(d);
791 795 break;
792 796 }
793 797 case QMetaType::Long:
794 798 {
795 799 long d = (long) PyObjGetLongLong(val,false,ok);
796 800 if (ok) v = qVariantFromValue(d);
797 801 break;
798 802 }
799 803 case QMetaType::ULong:
800 804 {
801 805 unsigned long d = (unsigned long) PyObjGetLongLong(val,false,ok);
802 806 if (ok) v = qVariantFromValue(d);
803 807 break;
804 808 }
805 809 case QMetaType::Short:
806 810 {
807 811 short d = (short) PyObjGetInt(val,false,ok);
808 812 if (ok) v = qVariantFromValue(d);
809 813 break;
810 814 }
811 815 case QMetaType::UShort:
812 816 {
813 817 unsigned short d = (unsigned short) PyObjGetInt(val,false,ok);
814 818 if (ok) v = qVariantFromValue(d);
815 819 break;
816 820 }
817 821 case QMetaType::Char:
818 822 {
819 823 char d = (char) PyObjGetInt(val,false,ok);
820 824 if (ok) v = qVariantFromValue(d);
821 825 break;
822 826 }
823 827 case QMetaType::UChar:
824 828 {
825 829 unsigned char d = (unsigned char) PyObjGetInt(val,false,ok);
826 830 if (ok) v = qVariantFromValue(d);
827 831 break;
828 832 }
829 833
830 834 case QVariant::ByteArray:
831 835 case QVariant::String:
832 836 {
833 837 bool ok;
834 838 v = QVariant(PyObjGetString(val, false, ok));
835 839 }
836 840 break;
837 841
838 842 // these are important for MeVisLab
839 843 case QVariant::Map:
840 844 {
841 845 if (PyMapping_Check(val)) {
842 846 QMap<QString,QVariant> map;
843 847 PyObject* items = PyMapping_Items(val);
844 848 if (items) {
845 849 int count = PyList_Size(items);
846 850 PyObject* value;
847 851 PyObject* key;
848 852 PyObject* tuple;
849 853 for (int i = 0;i<count;i++) {
850 854 tuple = PyList_GetItem(items,i);
851 855 key = PyTuple_GetItem(tuple, 0);
852 856 value = PyTuple_GetItem(tuple, 1);
853 857 map.insert(PyObjGetString(key), PyObjToQVariant(value,-1));
854 858 }
855 859 Py_DECREF(items);
856 860 v = map;
857 861 }
858 862 }
859 863 }
860 864 break;
861 865 case QVariant::List:
862 866 if (PySequence_Check(val)) {
863 867 QVariantList list;
864 868 int count = PySequence_Size(val);
865 869 PyObject* value;
866 870 for (int i = 0;i<count;i++) {
867 871 value = PySequence_GetItem(val,i);
868 872 list.append(PyObjToQVariant(value, -1));
869 873 }
870 874 v = list;
871 875 }
872 876 break;
873 877 case QVariant::StringList:
874 878 {
875 879 bool ok;
876 880 QStringList l = PyObjToStringList(val, false, ok);
877 881 if (ok) {
878 882 v = l;
879 883 }
880 884 }
881 885 break;
882 886
883 887 default:
884 888 if (val->ob_type == &PythonQtVariantWrapper_Type) {
885 889 PythonQtVariantWrapper* varWrap = (PythonQtVariantWrapper*)val;
886 890 if (varWrap->_variant->userType() == type) {
887 891 v = *varWrap->_variant;
888 892 }
889 893 } else {
890 894 v = QVariant();
891 895 }
892 896 }
893 897 return v;
894 898 }
895 899
896 900 PyObject* PythonQtConv::QStringToPyObject(const QString& str)
897 901 {
898 902 if (str.isNull()) {
899 903 return PyString_FromString("");
900 904 } else {
901 905 #ifdef WIN32
902 906 // return PyString_FromString(str.toLatin1().data());
903 907 return PyUnicode_FromUnicode(str.utf16(), str.length());
904 908 #else
905 909 return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, NULL, NULL);
906 910 #endif
907 911 }
908 912 }
909 913
910 914 PyObject* PythonQtConv::QStringListToPyObject(const QStringList& list)
911 915 {
912 916 PyObject* result = PyTuple_New(list.count());
913 917 int i = 0;
914 918 QString str;
915 919 foreach (str, list) {
916 920 PyTuple_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(str));
917 921 i++;
918 922 }
919 923 // why is the error state bad after this?
920 924 PyErr_Clear();
921 925 return result;
922 926 }
923 927
924 928 PyObject* PythonQtConv::QStringListToPyList(const QStringList& list)
925 929 {
926 930 PyObject* result = PyList_New(list.count());
927 931 int i = 0;
928 932 for (QStringList::ConstIterator it = list.begin(); it!=list.end(); ++it) {
929 933 PyList_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(*it));
930 934 i++;
931 935 }
932 936 return result;
933 937 }
934 938
935 939 PyObject* PythonQtConv::QVariantToPyObject(const QVariant& v)
936 940 {
937 941 return ConvertQtValueToPythonInternal(v.userType(), (void*)v.constData());
938 942 }
939 943
940 944 PyObject* PythonQtConv::QVariantMapToPyObject(const QVariantMap& m) {
941 945 PyObject* result = PyDict_New();
942 946 QVariantMap::const_iterator t = m.constBegin();
943 947 PyObject* key;
944 948 PyObject* val;
945 949 for (;t!=m.end();t++) {
946 950 key = QStringToPyObject(t.key());
947 951 val = QVariantToPyObject(t.value());
948 952 PyDict_SetItem(result, key, val);
949 953 Py_DECREF(key);
950 954 Py_DECREF(val);
951 955 }
952 956 return result;
953 957 }
954 958
955 959 PyObject* PythonQtConv::QVariantListToPyObject(const QVariantList& l) {
956 960 PyObject* result = PyTuple_New(l.count());
957 961 int i = 0;
958 962 QVariant v;
959 963 foreach (v, l) {
960 964 PyTuple_SET_ITEM(result, i, PythonQtConv::QVariantToPyObject(v));
961 965 i++;
962 966 }
963 967 // why is the error state bad after this?
964 968 PyErr_Clear();
965 969 return result;
966 970 }
967 971
968 972 PyObject* PythonQtConv::ConvertQListWithPointersToPython(QList<void*>* list, const QByteArray& type)
969 973 {
970 974 PyObject* result = PyTuple_New(list->count());
971 975 int i = 0;
972 976 foreach (void* value, *list) {
973 977 PyTuple_SET_ITEM(result, i, PythonQt::priv()->wrapPtr(value, type));
974 978 i++;
975 979 }
976 980 return result;
977 981 }
978 982
979 983 bool PythonQtConv::ConvertPythonListToQListOfType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool strict)
980 984 {
981 985 bool result = false;
982 986 if (PySequence_Check(obj)) {
983 987 result = true;
984 988 int count = PySequence_Size(obj);
985 989 PyObject* value;
986 990 for (int i = 0;i<count;i++) {
987 991 value = PySequence_GetItem(obj,i);
988 992 if (value->ob_type == &PythonQtWrapper_Type) {
989 993 PythonQtWrapper* wrap = (PythonQtWrapper*)value;
990 994 // c++ wrapper, check if the class names of the c++ objects match
991 995 if (wrap->_info->isCPPWrapper()) {
992 996 //TODO: we could support inheritance on cpp wrappers as well
993 997 if (wrap->_info->wrappedCPPClassName() == type) {
994 998 list->append(wrap->_wrappedPtr);
995 999 } else {
996 1000 result = false;
997 1001 break;
998 1002 }
999 1003 } else {
1000 1004 if (wrap->_info->inherits(type)) {
1001 list->append((void*)wrap->_obj);
1005 QObject* myObject = wrap->_obj;
1006 list->append((void*)myObject);
1002 1007 } else {
1003 1008 result = false;
1004 1009 break;
1005 1010 }
1006 1011 }
1007 1012 }
1008 1013 }
1009 1014 }
1010 1015 return result;
1011 1016 }
1012 1017
@@ -1,788 +1,790
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 PythonQtImporter.h
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 // This module was inspired by the zipimport.c module of the original
41 41 // Python distribution. Most of the functions are identical or slightly
42 42 // modified to do all the loading of Python files via an external file interface.
43 43 // In contrast to zipimport.c, this module also writes *.pyc files
44 44 // automatically if it has write access/is not inside of a zip file.
45 45 //----------------------------------------------------------------------------------
46 46
47 47 #include "PythonQtImporter.h"
48 48 #include "PythonQtImportFileInterface.h"
49 49 #include "PythonQt.h"
50 50 #include <QFile>
51 51 #include <QFileInfo>
52 52
53 53 #define IS_SOURCE 0x0
54 54 #define IS_BYTECODE 0x1
55 55 #define IS_PACKAGE 0x2
56 56
57 57 struct st_mlab_searchorder {
58 58 char suffix[14];
59 59 int type;
60 60 };
61 61
62 62 /* mlab_searchorder defines how we search for a module in the Zip
63 63 archive: we first search for a package __init__, then for
64 64 non-package .pyc, .pyo and .py entries. The .pyc and .pyo entries
65 65 are swapped by initmlabimport() if we run in optimized mode. Also,
66 66 '/' is replaced by SEP there. */
67 67 struct st_mlab_searchorder mlab_searchorder[] = {
68 68 {"/__init__.pyc", IS_PACKAGE | IS_BYTECODE},
69 69 {"/__init__.pyo", IS_PACKAGE | IS_BYTECODE},
70 70 {"/__init__.py", IS_PACKAGE | IS_SOURCE},
71 71 {".pyc", IS_BYTECODE},
72 72 {".pyo", IS_BYTECODE},
73 73 {".py", IS_SOURCE},
74 74 {"", 0}
75 75 };
76 76
77 77 extern PyTypeObject PythonQtImporter_Type;
78 78 PyObject *PythonQtImportError;
79 79
80 80 QString PythonQtImport::getSubName(const QString& str)
81 81 {
82 82 int idx = str.lastIndexOf('.');
83 83 if (idx!=-1) {
84 84 return str.mid(idx+1);
85 85 } else {
86 86 return str;
87 87 }
88 88 }
89 89
90 90 PythonQtImport::module_info PythonQtImport::getModuleInfo(PythonQtImporter* self, const QString& fullname)
91 91 {
92 92 QString subname;
93 93 struct st_mlab_searchorder *zso;
94 94
95 95 subname = getSubName(fullname);
96 96 QString path = *self->_path + "/" + subname;
97 97
98 98 QString test;
99 99 for (zso = mlab_searchorder; *zso->suffix; zso++) {
100 100 test = path + zso->suffix;
101 101 if (PythonQt::importInterface()->exists(test)) {
102 102 if (zso->type & IS_PACKAGE)
103 103 return MI_PACKAGE;
104 104 else
105 105 return MI_MODULE;
106 106 }
107 107 }
108 108 return MI_NOT_FOUND;
109 109 }
110 110
111 111
112 112 /* PythonQtImporter.__init__
113 113 Just store the path argument
114 114 */
115 115 int PythonQtImporter_init(PythonQtImporter *self, PyObject *args, PyObject *kwds)
116 116 {
117 117 self->_path = NULL;
118 118
119 119 const char* path;
120 120 if (!PyArg_ParseTuple(args, "s",
121 121 &path))
122 122 return -1;
123 123
124 124 if (PythonQt::importInterface()->exists(path)) {
125 125 //qDebug("path %s", path);
126 126 QString p(path);
127 127 const QStringList& ignorePaths = PythonQt::self()->getImporterIgnorePaths();
128 128 foreach(QString a, ignorePaths) {
129 129 if (a==p) {
130 130 PyErr_SetString(PythonQtImportError,
131 131 "path ignored");
132 132 return -1;
133 133 }
134 134 }
135 135
136 136 self->_path = new QString(p);
137 137
138 138 //mlabDebugConst("MLABPython", "PythonQtImporter init: " << *self->_path);
139 139
140 140 return 0;
141 141 } else {
142 142 PyErr_SetString(PythonQtImportError,
143 143 "path does not exist error");
144 144 return -1;
145 145 }
146 146 }
147 147
148 148 void
149 149 PythonQtImporter_dealloc(PythonQtImporter *self)
150 150 {
151 151 // free the stored path
152 152 if (self->_path) delete self->_path;
153 153 // free ourself
154 154 self->ob_type->tp_free((PyObject *)self);
155 155 }
156 156
157 157
158 158 /* Check whether we can satisfy the import of the module named by
159 159 'fullname'. Return self if we can, None if we can't. */
160 160 PyObject *
161 161 PythonQtImporter_find_module(PyObject *obj, PyObject *args)
162 162 {
163 163 PythonQtImporter *self = (PythonQtImporter *)obj;
164 164 PyObject *path = NULL;
165 165 char *fullname;
166 166
167 167 if (!PyArg_ParseTuple(args, "s|O:PythonQtImporter.find_module",
168 168 &fullname, &path))
169 169 return NULL;
170 170
171 171 // mlabDebugConst("MLABPython", "FindModule " << fullname << " in " << *self->_path);
172 172
173 173 PythonQtImport::module_info info = PythonQtImport::getModuleInfo(self, fullname);
174 174 if (info == PythonQtImport::MI_MODULE || info == PythonQtImport::MI_PACKAGE) {
175 175 Py_INCREF(self);
176 176 return (PyObject *)self;
177 177 } else {
178 178 Py_INCREF(Py_None);
179 179 return Py_None;
180 180 }
181 181 }
182 182
183 183 /* Load and return the module named by 'fullname'. */
184 184 PyObject *
185 185 PythonQtImporter_load_module(PyObject *obj, PyObject *args)
186 186 {
187 187 PythonQtImporter *self = (PythonQtImporter *)obj;
188 188 PyObject *code, *mod, *dict;
189 189 char *fullname;
190 190 QString modpath;
191 191 int ispackage;
192 192
193 193 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.load_module",
194 194 &fullname))
195 195 return NULL;
196 196
197 197 code = PythonQtImport::getModuleCode(self, fullname, &ispackage, modpath);
198 198 if (code == NULL)
199 199 return NULL;
200 200
201 201 mod = PyImport_AddModule(fullname);
202 202 if (mod == NULL) {
203 203 Py_DECREF(code);
204 204 return NULL;
205 205 }
206 206 dict = PyModule_GetDict(mod);
207 207
208 208 if (PyDict_SetItemString(dict, "__loader__", (PyObject *)self) != 0)
209 209 goto error;
210 210
211 211 if (ispackage) {
212 212 PyObject *pkgpath, *fullpath;
213 213 QString subname = PythonQtImport::getSubName(fullname);
214 214 int err;
215 215
216 216 fullpath = PyString_FromFormat("%s%c%s",
217 217 self->_path->toLatin1().constData(),
218 218 SEP,
219 219 subname.toLatin1().constData());
220 220 if (fullpath == NULL)
221 221 goto error;
222 222
223 223 pkgpath = Py_BuildValue("[O]", fullpath);
224 224 Py_DECREF(fullpath);
225 225 if (pkgpath == NULL)
226 226 goto error;
227 227 err = PyDict_SetItemString(dict, "__path__", pkgpath);
228 228 Py_DECREF(pkgpath);
229 229 if (err != 0)
230 230 goto error;
231 231 }
232 232 mod = PyImport_ExecCodeModuleEx(fullname, code, (char*)modpath.toLatin1().data());
233 233 Py_DECREF(code);
234 234 if (Py_VerboseFlag)
235 235 PySys_WriteStderr("import %s # loaded from %s\n",
236 236 fullname, modpath);
237 237 return mod;
238 238 error:
239 239 Py_DECREF(code);
240 240 Py_DECREF(mod);
241 241 return NULL;
242 242 }
243 243
244 244
245 245 PyObject *
246 246 PythonQtImporter_get_data(PyObject *obj, PyObject *args)
247 247 {
248 248 // EXTRA, NOT YET IMPLEMENTED
249 249 return NULL;
250 250 }
251 251
252 252 PyObject *
253 253 PythonQtImporter_get_code(PyObject *obj, PyObject *args)
254 254 {
255 255 PythonQtImporter *self = (PythonQtImporter *)obj;
256 256 char *fullname;
257 257
258 258 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.get_code", &fullname))
259 259 return NULL;
260 260
261 261 QString notused;
262 262 return PythonQtImport::getModuleCode(self, fullname, NULL, notused);
263 263 }
264 264
265 265 PyObject *
266 266 PythonQtImporter_get_source(PyObject *obj, PyObject *args)
267 267 {
268 268 // EXTRA, NOT YET IMPLEMENTED
269 269 /*
270 270 PythonQtImporter *self = (PythonQtImporter *)obj;
271 271 PyObject *toc_entry;
272 272 char *fullname, *subname, path[MAXPATHLEN+1];
273 273 int len;
274 274 enum module_info mi;
275 275
276 276 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.get_source", &fullname))
277 277 return NULL;
278 278
279 279 mi = get_module_info(self, fullname);
280 280 if (mi == MI_ERROR)
281 281 return NULL;
282 282 if (mi == MI_NOT_FOUND) {
283 283 PyErr_Format(PythonQtImportError, "can't find module '%.200s'",
284 284 fullname);
285 285 return NULL;
286 286 }
287 287 subname = get_subname(fullname);
288 288
289 289 len = make_filename(PyString_AsString(self->prefix), subname, path);
290 290 if (len < 0)
291 291 return NULL;
292 292
293 293 if (mi == MI_PACKAGE) {
294 294 path[len] = SEP;
295 295 strcpy(path + len + 1, "__init__.py");
296 296 }
297 297 else
298 298 strcpy(path + len, ".py");
299 299
300 300 toc_entry = PyDict_GetItemString(self->files, path);
301 301 if (toc_entry != NULL)
302 302 return get_data(PyString_AsString(self->archive), toc_entry);
303 303
304 304 Py_INCREF(Py_None);
305 305 return Py_None;
306 306 */
307 307 return NULL;
308 308 }
309 309
310 310 PyDoc_STRVAR(doc_find_module,
311 311 "find_module(fullname, path=None) -> self or None.\n\
312 312 \n\
313 313 Search for a module specified by 'fullname'. 'fullname' must be the\n\
314 314 fully qualified (dotted) module name. It returns the PythonQtImporter\n\
315 315 instance itself if the module was found, or None if it wasn't.\n\
316 316 The optional 'path' argument is ignored -- it's there for compatibility\n\
317 317 with the importer protocol.");
318 318
319 319 PyDoc_STRVAR(doc_load_module,
320 320 "load_module(fullname) -> module.\n\
321 321 \n\
322 322 Load the module specified by 'fullname'. 'fullname' must be the\n\
323 323 fully qualified (dotted) module name. It returns the imported\n\
324 324 module, or raises PythonQtImportError if it wasn't found.");
325 325
326 326 PyDoc_STRVAR(doc_get_data,
327 327 "get_data(pathname) -> string with file data.\n\
328 328 \n\
329 329 Return the data associated with 'pathname'. Raise IOError if\n\
330 330 the file wasn't found.");
331 331
332 332 PyDoc_STRVAR(doc_get_code,
333 333 "get_code(fullname) -> code object.\n\
334 334 \n\
335 335 Return the code object for the specified module. Raise PythonQtImportError\n\
336 336 is the module couldn't be found.");
337 337
338 338 PyDoc_STRVAR(doc_get_source,
339 339 "get_source(fullname) -> source string.\n\
340 340 \n\
341 341 Return the source code for the specified module. Raise PythonQtImportError\n\
342 342 is the module couldn't be found, return None if the archive does\n\
343 343 contain the module, but has no source for it.");
344 344
345 345 PyMethodDef PythonQtImporter_methods[] = {
346 346 {"find_module", PythonQtImporter_find_module, METH_VARARGS,
347 347 doc_find_module},
348 348 {"load_module", PythonQtImporter_load_module, METH_VARARGS,
349 349 doc_load_module},
350 350 {"get_data", PythonQtImporter_get_data, METH_VARARGS,
351 351 doc_get_data},
352 352 {"get_code", PythonQtImporter_get_code, METH_VARARGS,
353 353 doc_get_code},
354 354 {"get_source", PythonQtImporter_get_source, METH_VARARGS,
355 355 doc_get_source},
356 356 {NULL, NULL} /* sentinel */
357 357 };
358 358
359 359
360 360 PyDoc_STRVAR(PythonQtImporter_doc,
361 361 "PythonQtImporter(path) -> PythonQtImporter object\n\
362 362 \n\
363 363 Create a new PythonQtImporter instance. 'path' must be a valid path on disk/or inside of a zip file known to MeVisLab\n\
364 364 . Every path is accepted.");
365 365
366 366 #define DEFERRED_ADDRESS(ADDR) 0
367 367
368 368 PyTypeObject PythonQtImporter_Type = {
369 369 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
370 370 0,
371 371 "PythonQtImport.PythonQtImporter",
372 372 sizeof(PythonQtImporter),
373 373 0, /* tp_itemsize */
374 374 (destructor)PythonQtImporter_dealloc, /* tp_dealloc */
375 375 0, /* tp_print */
376 376 0, /* tp_getattr */
377 377 0, /* tp_setattr */
378 378 0, /* tp_compare */
379 379 0, /* tp_repr */
380 380 0, /* tp_as_number */
381 381 0, /* tp_as_sequence */
382 382 0, /* tp_as_mapping */
383 383 0, /* tp_hash */
384 384 0, /* tp_call */
385 385 0, /* tp_str */
386 386 PyObject_GenericGetAttr, /* tp_getattro */
387 387 0, /* tp_setattro */
388 388 0, /* tp_as_buffer */
389 389 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE , /* tp_flags */
390 390 PythonQtImporter_doc, /* tp_doc */
391 391 0, /* tp_traverse */
392 392 0, /* tp_clear */
393 393 0, /* tp_richcompare */
394 394 0, /* tp_weaklistoffset */
395 395 0, /* tp_iter */
396 396 0, /* tp_iternext */
397 397 PythonQtImporter_methods, /* tp_methods */
398 398 0, /* tp_members */
399 399 0, /* tp_getset */
400 400 0, /* tp_base */
401 401 0, /* tp_dict */
402 402 0, /* tp_descr_get */
403 403 0, /* tp_descr_set */
404 404 0, /* tp_dictoffset */
405 405 (initproc)PythonQtImporter_init, /* tp_init */
406 406 PyType_GenericAlloc, /* tp_alloc */
407 407 PyType_GenericNew, /* tp_new */
408 408 PyObject_Del, /* tp_free */
409 409 };
410 410
411 411
412 412 /* Given a buffer, return the long that is represented by the first
413 413 4 bytes, encoded as little endian. This partially reimplements
414 414 marshal.c:r_long() */
415 415 long
416 416 PythonQtImport::getLong(unsigned char *buf)
417 417 {
418 418 long x;
419 419 x = buf[0];
420 420 x |= (long)buf[1] << 8;
421 421 x |= (long)buf[2] << 16;
422 422 x |= (long)buf[3] << 24;
423 423 #if SIZEOF_LONG > 4
424 424 /* Sign extension for 64-bit machines */
425 425 x |= -(x & 0x80000000L);
426 426 #endif
427 427 return x;
428 428 }
429 429
430 430 FILE *
431 431 open_exclusive(const QString& filename)
432 432 {
433 433 #if defined(O_EXCL)&&defined(O_CREAT)&&defined(O_WRONLY)&&defined(O_TRUNC)
434 434 /* Use O_EXCL to avoid a race condition when another process tries to
435 435 write the same file. When that happens, our open() call fails,
436 436 which is just fine (since it's only a cache).
437 437 XXX If the file exists and is writable but the directory is not
438 438 writable, the file will never be written. Oh well.
439 439 */
440 440 QFile::remove(filename);
441 441
442 442 int fd;
443 443 int flags = O_EXCL|O_CREAT|O_WRONLY|O_TRUNC;
444 444 #ifdef O_BINARY
445 445 flags |= O_BINARY; /* necessary for Windows */
446 446 #endif
447 447 #ifdef WIN32
448 448 fd = _wopen(filename.ucs2(), flags, 0666);
449 449 #else
450 450 fd = open(filename.local8Bit(), flags, 0666);
451 451 #endif
452 452 if (fd < 0)
453 453 return NULL;
454 454 return fdopen(fd, "wb");
455 455 #else
456 456 /* Best we can do -- on Windows this can't happen anyway */
457 457 return fopen(filename.toLocal8Bit().constData(), "wb");
458 458 #endif
459 459 }
460 460
461 461
462 462 void PythonQtImport::writeCompiledModule(PyCodeObject *co, const QString& filename, long mtime)
463 463 {
464 464 FILE *fp;
465 465
466 466 fp = open_exclusive(filename);
467 467 if (fp == NULL) {
468 468 if (Py_VerboseFlag)
469 469 PySys_WriteStderr(
470 470 "# can't create %s\n", filename.toLatin1().constData());
471 471 return;
472 472 }
473 473 #if PY_VERSION_HEX < 0x02040000
474 474 PyMarshal_WriteLongToFile(PyImport_GetMagicNumber(), fp);
475 475 #else
476 476 PyMarshal_WriteLongToFile(PyImport_GetMagicNumber(), fp, Py_MARSHAL_VERSION);
477 477 #endif
478 478 /* First write a 0 for mtime */
479 479 #if PY_VERSION_HEX < 0x02040000
480 480 PyMarshal_WriteLongToFile(0L, fp);
481 481 #else
482 482 PyMarshal_WriteLongToFile(0L, fp, Py_MARSHAL_VERSION);
483 483 #endif
484 484 #if PY_VERSION_HEX < 0x02040000
485 485 PyMarshal_WriteObjectToFile((PyObject *)co, fp);
486 486 #else
487 487 PyMarshal_WriteObjectToFile((PyObject *)co, fp, Py_MARSHAL_VERSION);
488 488 #endif
489 489 if (ferror(fp)) {
490 490 if (Py_VerboseFlag)
491 491 PySys_WriteStderr("# can't write %s\n", filename.toLatin1().constData());
492 492 /* Don't keep partial file */
493 493 fclose(fp);
494 494 QFile::remove(filename);
495 495 return;
496 496 }
497 497 /* Now write the true mtime */
498 498 fseek(fp, 4L, 0);
499 499 #if PY_VERSION_HEX < 0x02040000
500 500 PyMarshal_WriteLongToFile(mtime, fp);
501 501 #else
502 502 PyMarshal_WriteLongToFile(mtime, fp, Py_MARSHAL_VERSION);
503 503 #endif
504 504 fflush(fp);
505 505 fclose(fp);
506 506 if (Py_VerboseFlag)
507 507 PySys_WriteStderr("# wrote %s\n", filename.toLatin1().constData());
508 508 //#ifdef macintosh
509 509 // PyMac_setfiletype(cpathname, 'Pyth', 'PYC ');
510 510 //#endif
511 511 }
512 512
513 513 /* Given the contents of a .py[co] file in a buffer, unmarshal the data
514 514 and return the code object. Return None if it the magic word doesn't
515 515 match (we do this instead of raising an exception as we fall back
516 516 to .py if available and we don't want to mask other errors).
517 517 Returns a new reference. */
518 518 PyObject *
519 519 PythonQtImport::unmarshalCode(const QString& path, const QByteArray& data, time_t mtime)
520 520 {
521 521 PyObject *code;
522 522 // ugly cast, but Python API is not const safe
523 523 char *buf = (char*) data.constData();
524 524 int size = data.size();
525 525
526 526 if (size <= 9) {
527 527 PySys_WriteStderr("# %s has bad pyc data\n",
528 528 path.toLatin1().constData());
529 529 Py_INCREF(Py_None);
530 530 return Py_None;
531 531 }
532 532
533 533 if (getLong((unsigned char *)buf) != PyImport_GetMagicNumber()) {
534 534 if (Py_VerboseFlag)
535 535 PySys_WriteStderr("# %s has bad magic\n",
536 536 path.toLatin1().constData());
537 537 Py_INCREF(Py_None);
538 538 return Py_None;
539 539 }
540 540
541 541 if (mtime != 0 && !(getLong((unsigned char *)buf + 4) == mtime)) {
542 542 if (Py_VerboseFlag)
543 543 PySys_WriteStderr("# %s has bad mtime\n",
544 544 path.toLatin1().constData());
545 545 Py_INCREF(Py_None);
546 546 return Py_None;
547 547 }
548 548
549 549 code = PyMarshal_ReadObjectFromString(buf + 8, size - 8);
550 550 if (code == NULL)
551 551 return NULL;
552 552 if (!PyCode_Check(code)) {
553 553 Py_DECREF(code);
554 554 PyErr_Format(PyExc_TypeError,
555 555 "compiled module %.200s is not a code object",
556 556 path.toLatin1().constData());
557 557 return NULL;
558 558 }
559 559 return code;
560 560 }
561 561
562 562
563 563 /* Given a string buffer containing Python source code, compile it
564 564 return and return a code object as a new reference. */
565 565 PyObject *
566 566 PythonQtImport::compileSource(const QString& path, const QByteArray& data)
567 567 {
568 568 PyObject *code;
569 569 QByteArray data1 = data;
570 570 // in qt4, data is null terminated
571 571 // data1.resize(data.size()+1);
572 572 // data1.data()[data.size()-1] = 0;
573 573 code = Py_CompileString(data.data(), path.toLatin1().constData(),
574 574 Py_file_input);
575 575 return code;
576 576 }
577 577
578 578
579 579 /* Return the code object for the module named by 'fullname' from the
580 580 Zip archive as a new reference. */
581 581 PyObject *
582 582 PythonQtImport::getCodeFromData(const QString& path, int isbytecode,int ispackage, time_t mtime)
583 583 {
584 584 bool hasImporter = PythonQt::importInterface()!=NULL;
585 585
586 586 PyObject *code;
587 587
588 588 QByteArray qdata;
589 589 if (!hasImporter) {
590 590 QFile file(path);
591 591 QIODevice::OpenMode flags = QIODevice::ReadOnly;
592 592 if (!isbytecode) {
593 593 flags |= QIODevice::Text;
594 594 }
595 595 if (!file.open(flags)) {
596 596 return NULL;
597 597 }
598 598 qdata = file.readAll();
599 599 } else {
600 600 if (!isbytecode) {
601 601 // mlabDebugConst("MLABPython", "reading source " << path);
602 602 bool ok;
603 603 qdata = PythonQt::importInterface()->readSourceFile(path, ok);
604 604 if (!ok) {
605 605 // mlabErrorConst("PythonQtImporter","File could not be verified" << path);
606 606 return NULL;
607 607 }
608 608 if (qdata == " ") {
609 609 qdata.clear();
610 610 }
611 611 } else {
612 612 qdata = PythonQt::importInterface()->readFileAsBytes(path);
613 613 }
614 614 }
615 615
616 616 if (isbytecode) {
617 617 // mlabDebugConst("MLABPython", "reading bytecode " << path);
618 618 code = unmarshalCode(path, qdata, mtime);
619 619 }
620 620 else {
621 621 // mlabDebugConst("MLABPython", "compiling source " << path);
622 622 code = compileSource(path, qdata);
623 // save a pyc file if possible
624 QDateTime time;
625 time = hasImporter?PythonQt::importInterface()->lastModifiedDate(path):QFileInfo(path).lastModified();
626 writeCompiledModule((PyCodeObject*)code, path+"c", time.toTime_t());
623 if (code) {
624 // save a pyc file if possible
625 QDateTime time;
626 time = hasImporter?PythonQt::importInterface()->lastModifiedDate(path):QFileInfo(path).lastModified();
627 writeCompiledModule((PyCodeObject*)code, path+"c", time.toTime_t());
628 }
627 629 }
628 630 return code;
629 631 }
630 632
631 633 time_t
632 634 PythonQtImport::getMTimeOfSource(const QString& path)
633 635 {
634 636 time_t mtime = 0;
635 637 QString path2 = path;
636 638 path2.truncate(path.length()-1);
637 639
638 640 bool hasImporter = PythonQt::importInterface()!=NULL;
639 641 if (hasImporter) {
640 642 if (PythonQt::importInterface()->exists(path2)) {
641 643 mtime = PythonQt::importInterface()->lastModifiedDate(path2).toTime_t();
642 644 }
643 645 } else {
644 646 if (QFile::exists(path2)) {
645 647 mtime = QFileInfo(path2).lastModified().toTime_t();
646 648 }
647 649 }
648 650 return mtime;
649 651 }
650 652
651 653 /* Get the code object associated with the module specified by
652 654 'fullname'. */
653 655 PyObject *
654 656 PythonQtImport::getModuleCode(PythonQtImporter *self, char *fullname,
655 657 int *p_ispackage, QString& modpath)
656 658 {
657 659 QString subname;
658 660 struct st_mlab_searchorder *zso;
659 661
660 662 subname = getSubName(fullname);
661 663 QString path = *self->_path + "/" + subname;
662 664
663 665 QString test;
664 666 for (zso = mlab_searchorder; *zso->suffix; zso++) {
665 667 PyObject *code = NULL;
666 668 test = path + zso->suffix;
667 669
668 670 if (Py_VerboseFlag > 1)
669 671 PySys_WriteStderr("# trying %s\n",
670 672 test.toLatin1().constData());
671 673 if (PythonQt::importInterface()->exists(test)) {
672 674 time_t mtime = 0;
673 675 int ispackage = zso->type & IS_PACKAGE;
674 676 int isbytecode = zso->type & IS_BYTECODE;
675 677
676 678 if (isbytecode)
677 679 mtime = getMTimeOfSource(test);
678 680 if (p_ispackage != NULL)
679 681 *p_ispackage = ispackage;
680 682 code = getCodeFromData(test, isbytecode, ispackage, mtime);
681 683 if (code == Py_None) {
682 684 Py_DECREF(code);
683 685 continue;
684 686 }
685 687 if (code != NULL)
686 688 modpath = test;
687 689 return code;
688 690 }
689 691 }
690 692 PyErr_Format(PythonQtImportError, "can't find module '%.200s'", fullname);
691 693
692 694 return NULL;
693 695 }
694 696
695 697 QString PythonQtImport::replaceExtension(const QString& str, const QString& ext)
696 698 {
697 699 QString r;
698 700 int i = str.lastIndexOf('.');
699 701 if (i!=-1) {
700 702 r = str.mid(0,i) + "." + ext;
701 703 } else {
702 704 r = str + "." + ext;
703 705 }
704 706 return r;
705 707 }
706 708
707 709 PyObject* PythonQtImport::getCodeFromPyc(const QString& file)
708 710 {
709 711 bool hasImporter = PythonQt::importInterface()!=NULL;
710 712
711 713 PyObject* code;
712 714 const static QString pycStr("pyc");
713 715 QString pyc = replaceExtension(file, pycStr);
714 716 if ((hasImporter && PythonQt::importInterface()->exists(pyc)) ||
715 717 (!hasImporter && QFile::exists(pyc))) {
716 718 time_t mtime = 0;
717 719 mtime = getMTimeOfSource(pyc);
718 720 code = getCodeFromData(pyc, true, false, mtime);
719 721 if (code != Py_None && code != NULL) {
720 722 return code;
721 723 }
722 724 if (code) {
723 725 Py_DECREF(code);
724 726 }
725 727 }
726 728 code = getCodeFromData(file,false,false,0);
727 729 return code;
728 730 }
729 731
730 732 /* Module init */
731 733
732 734 PyDoc_STRVAR(mlabimport_doc,
733 735 "Imports python files into MeVisLab, completely replaces internal python import");
734 736
735 737 void PythonQtImport::init()
736 738 {
737 739 PyObject *mod;
738 740
739 741 if (PyType_Ready(&PythonQtImporter_Type) < 0)
740 742 return;
741 743
742 744 /* Correct directory separator */
743 745 mlab_searchorder[0].suffix[0] = SEP;
744 746 mlab_searchorder[1].suffix[0] = SEP;
745 747 mlab_searchorder[2].suffix[0] = SEP;
746 748 if (Py_OptimizeFlag) {
747 749 /* Reverse *.pyc and *.pyo */
748 750 struct st_mlab_searchorder tmp;
749 751 tmp = mlab_searchorder[0];
750 752 mlab_searchorder[0] = mlab_searchorder[1];
751 753 mlab_searchorder[1] = tmp;
752 754 tmp = mlab_searchorder[3];
753 755 mlab_searchorder[3] = mlab_searchorder[4];
754 756 mlab_searchorder[4] = tmp;
755 757 }
756 758
757 759 mod = Py_InitModule4("PythonQtImport", NULL, mlabimport_doc,
758 760 NULL, PYTHON_API_VERSION);
759 761
760 762 PythonQtImportError = PyErr_NewException("PythonQtImport.PythonQtImportError",
761 763 PyExc_ImportError, NULL);
762 764 if (PythonQtImportError == NULL)
763 765 return;
764 766
765 767 Py_INCREF(PythonQtImportError);
766 768 if (PyModule_AddObject(mod, "PythonQtImportError",
767 769 PythonQtImportError) < 0)
768 770 return;
769 771
770 772 Py_INCREF(&PythonQtImporter_Type);
771 773 if (PyModule_AddObject(mod, "PythonQtImporter",
772 774 (PyObject *)&PythonQtImporter_Type) < 0)
773 775 return;
774 776
775 777 // set our importer into the path_hooks to handle all path on sys.path
776 778 PyObject* classobj = PyDict_GetItemString(PyModule_GetDict(mod), "PythonQtImporter");
777 779 PyObject* path_hooks = PySys_GetObject("path_hooks");
778 780 PyList_Append(path_hooks, classobj);
779
781
780 782 #ifndef WIN32
781 783 // reload the encodings module, because it might fail to custom import requirements (e.g. encryption).
782 784 PyObject* modules = PyImport_GetModuleDict();
783 785 PyObject* encodingsModule = PyDict_GetItemString(modules, "encodings");
784 786 if (encodingsModule != NULL) {
785 787 PyImport_ReloadModule(encodingsModule);
786 788 }
787 789 #endif
788 790 }
@@ -1,240 +1,245
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 PythonQtMetaObjectWrapper.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 "PythonQtMetaObjectWrapper.h"
43 43 #include <QObject>
44 44
45 45 #include "PythonQt.h"
46 46 #include "PythonQtSlot.h"
47 47 #include "PythonQtClassInfo.h"
48 48 #include "PythonQtConversion.h"
49 49
50 50 static void PythonQtMetaObjectWrapper_dealloc(PythonQtMetaObjectWrapper* self)
51 51 {
52 52 self->ob_type->tp_free((PyObject*)self);
53 53 }
54 54
55 55 static PyObject* PythonQtMetaObjectWrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
56 56 {
57 57 PythonQtMetaObjectWrapper *self;
58 58
59 59 self = (PythonQtMetaObjectWrapper *)type->tp_alloc(type, 0);
60 60 if (self != NULL) {
61 61 self->_info = NULL;
62 62 }
63 63 return (PyObject *)self;
64 64 }
65 65
66 66 static int PythonQtMetaObjectWrapper_init(PythonQtMetaObjectWrapper *self, PyObject *args, PyObject *kwds)
67 67 {
68 68 return 0;
69 69 }
70 70
71 71 PyObject *PythonQtMetaObjectWrapper_call(PyObject *func, PyObject *args, PyObject *kw) {
72 72 PythonQtMetaObjectWrapper* wrapper = (PythonQtMetaObjectWrapper*)func;
73 73 PyObject* result = NULL;
74 74 QString error;
75 75 PyObject* err = NULL;
76 76 if (wrapper->_info->constructors()) {
77 77 result = PythonQtSlotFunction_CallImpl(NULL, wrapper->_info->constructors(), args, kw);
78 78 err = PyErr_Occurred();
79 79 }
80 80 if (!result) {
81 81 QObject* v = NULL;
82 82 QListIterator<PythonQtConstructorHandler*> it(PythonQt::self()->constructorHandlers());
83 83 while (!v && it.hasNext()) {
84 84 v = it.next()->create(wrapper->_info->metaObject(), args, kw, error);
85 85 }
86 86 if (v) {
87 87 result = PythonQt::priv()->wrapQObject(v);
88 88 }
89 89 }
90 90 if (result) {
91 91 // change ownershipflag to be owned by PythonQt
92 92 if (result->ob_type == &PythonQtWrapper_Type) {
93 93 ((PythonQtWrapper*)result)->_ownedByPythonQt = true;
94 94 }
95 95 } else {
96 96 if (!wrapper->_info->constructors()) {
97 97 if (!err) {
98 98 if (error.isEmpty()) {
99 99 error = QString("No constructors available for ") + wrapper->_info->className();
100 100 }
101 101 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
102 102 }
103 103 }
104 104 }
105 105 return result;
106 106 }
107 107
108 108 static PyObject *PythonQtMetaObjectWrapper_classname(PythonQtMetaObjectWrapper* type)
109 109 {
110 110 return PyString_FromString((QString("Meta_") + type->_info->className()).toLatin1().data());
111 111 }
112 112
113 113 static PyObject *PythonQtMetaObjectWrapper_help(PythonQtMetaObjectWrapper* type)
114 114 {
115 115 return PythonQt::self()->helpCalled(type->_info);
116 116 }
117 117
118 118
119 119 static PyMethodDef PythonQtMetaObjectWrapper_methods[] = {
120 120 {"className", (PyCFunction)PythonQtMetaObjectWrapper_classname, METH_NOARGS,
121 121 "Return the classname of the object"
122 122 },
123 123 {"help", (PyCFunction)PythonQtMetaObjectWrapper_help, METH_NOARGS,
124 124 "Shows the help of available methods for this class"
125 125 },
126 126 {NULL} /* Sentinel */
127 127 };
128 128
129 129
130 130 static PyObject *PythonQtMetaObjectWrapper_getattro(PyObject *obj,PyObject *name)
131 131 {
132 132 const char *attributeName;
133 133 PythonQtMetaObjectWrapper *wt = (PythonQtMetaObjectWrapper *)obj;
134 134
135 135 if ((attributeName = PyString_AsString(name)) == NULL) {
136 136 return NULL;
137 137 }
138 138
139 139 PythonQtMemberInfo member = wt->_info->member(attributeName);
140 140 if (member._type == PythonQtMemberInfo::EnumValue) {
141 141 return PyInt_FromLong(member._enumValue);
142 142 }
143 143 if (member._type == PythonQtMemberInfo::Slot && member._slot->isClassDecorator()) {
144 144 return PythonQtSlotFunction_New(member._slot, obj, NULL);
145 145 }
146
146
147 147 // look for the interal methods (className(), help())
148 148 PyObject* internalMethod = Py_FindMethod( PythonQtMetaObjectWrapper_methods, obj, (char*)attributeName);
149 149 if (internalMethod) {
150 150 return internalMethod;
151 151 }
152 152 PyErr_Clear();
153 153
154 154 if (qstrcmp(attributeName, "__dict__")==0) {
155 155 QStringList l = wt->_info->memberList(true);
156 156 PyObject* dict = PyDict_New();
157 157 foreach (QString name, l) {
158 158 //PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
159 159 PyDict_SetItemString(dict, name.toLatin1().data(), Py_None);
160 160 //Py_DECREF(o);
161 161 }
162 162 return dict;
163 163 }
164 164
165 165 QString error = QString(wt->_info->className()) + " has no attribute named '" + QString(attributeName) + "'";
166 166 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
167 167 return NULL;
168 168 }
169 169
170 170 static PyObject * PythonQtMetaObjectWrapper_repr(PyObject * obj)
171 171 {
172 172 PythonQtMetaObjectWrapper* wt = (PythonQtMetaObjectWrapper*)obj;
173 173 if (wt->_info->isCPPWrapper()) {
174 174 return PyString_FromFormat("%s Class (C++ wrapped by %s)", wt->_info->className(), wt->_info->metaObject()->className());
175 175 } else {
176 176 return PyString_FromFormat("%s Class", wt->_info->className());
177 177 }
178 178 }
179 179
180 180 static int PythonQtMetaObjectWrapper_compare(PyObject * obj1, PyObject * obj2)
181 181 {
182 182 if (obj1->ob_type == &PythonQtMetaObjectWrapper_Type &&
183 183 obj2->ob_type == &PythonQtMetaObjectWrapper_Type) {
184 184
185 185 PythonQtMetaObjectWrapper* w1 = (PythonQtMetaObjectWrapper*)obj1;
186 186 PythonQtMetaObjectWrapper* w2 = (PythonQtMetaObjectWrapper*)obj2;
187 187 if (w1->_info == w2->_info) {
188 188 return 0;
189 189 } else {
190 190 return -1;
191 191 }
192 192 } else {
193 193 return -1;
194 194 }
195 195 }
196 196
197 static long PythonQtMetaObjectWrapper_hash(PythonQtMetaObjectWrapper *obj)
198 {
199 return reinterpret_cast<long>(obj->_info);
200 }
201
197 202 PyTypeObject PythonQtMetaObjectWrapper_Type = {
198 203 PyObject_HEAD_INIT(NULL)
199 204 0, /*ob_size*/
200 205 "PythonQt.PythonQtMetaObjectWrapper", /*tp_name*/
201 206 sizeof(PythonQtMetaObjectWrapper), /*tp_basicsize*/
202 207 0, /*tp_itemsize*/
203 208 (destructor)PythonQtMetaObjectWrapper_dealloc, /*tp_dealloc*/
204 209 0, /*tp_print*/
205 210 0, /*tp_getattr*/
206 211 0, /*tp_setattr*/
207 212 PythonQtMetaObjectWrapper_compare, /*tp_compare*/
208 213 PythonQtMetaObjectWrapper_repr, /*tp_repr*/
209 214 0, /*tp_as_number*/
210 215 0, /*tp_as_sequence*/
211 216 0, /*tp_as_mapping*/
212 0, /*tp_hash */
217 (hashfunc)PythonQtMetaObjectWrapper_hash, /*tp_hash */
213 218 PythonQtMetaObjectWrapper_call, /*tp_call*/
214 219 0, /*tp_str*/
215 220 PythonQtMetaObjectWrapper_getattro, /*tp_getattro*/
216 221 0, /*tp_setattro*/
217 222 0, /*tp_as_buffer*/
218 223 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
219 224 "PythonQtMetaObjectWrapper object", /* tp_doc */
220 225 0, /* tp_traverse */
221 226 0, /* tp_clear */
222 227 0, /* tp_richcompare */
223 228 0, /* tp_weaklistoffset */
224 229 0, /* tp_iter */
225 230 0, /* tp_iternext */
226 231 0, /* tp_methods */
227 232 0, /* tp_members */
228 233 0, /* tp_getset */
229 234 0, /* tp_base */
230 235 0, /* tp_dict */
231 236 0, /* tp_descr_get */
232 237 0, /* tp_descr_set */
233 238 0, /* tp_dictoffset */
234 239 (initproc)PythonQtMetaObjectWrapper_init, /* tp_init */
235 240 0, /* tp_alloc */
236 241 PythonQtMetaObjectWrapper_new, /* tp_new */
237 242 };
238 243
239 244 //-------------------------------------------------------
240 245
@@ -1,171 +1,206
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtSignalReceiver.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtSignalReceiver.h"
43 43 #include "PythonQtClassInfo.h"
44 44 #include "PythonQtMethodInfo.h"
45 45 #include "PythonQtConversion.h"
46 46 #include <QMetaObject>
47 47 #include <QMetaMethod>
48 #include "funcobject.h"
48 49
49 50 void PythonQtSignalTarget::call(void **arguments) const
50 51 {
52 // Note: we check if the callable is a PyFunctionObject and has a fixed number of arguments
53 // if that is the case, we only pass these arguments to python and skip the additional arguments from the signal
54
55 int numPythonArgs = -1;
56 if (PyFunction_Check(_callable)) {
57 PyObject* o = _callable;
58 PyFunctionObject* func = (PyFunctionObject*)o;
59 PyCodeObject* code = (PyCodeObject*)func->func_code;
60 if (!(code->co_flags & 0x04)) {
61 numPythonArgs = code->co_argcount;
62 } else {
63 // variable numbers of arguments allowed
64 }
65 } else if (PyMethod_Check(_callable)) {
66 PyObject* o = _callable;
67 PyMethodObject* method = (PyMethodObject*)o;
68 if (PyFunction_Check(method->im_func)) {
69 PyFunctionObject* func = (PyFunctionObject*)method->im_func;
70 PyCodeObject* code = (PyCodeObject*)func->func_code;
71 if (!(code->co_flags & 0x04)) {
72 numPythonArgs = code->co_argcount - 1; // we subtract one because the first is "self"
73 } else {
74 // variable numbers of arguments allowed
75 }
76 }
77 }
78
51 79 const PythonQtMethodInfo* m = methodInfo();
52 // paramterCount includes return value:
80 // parameterCount includes return value:
53 81 int count = m->parameterCount();
82 if (numPythonArgs!=-1) {
83 if (count>numPythonArgs+1) {
84 // take less arguments
85 count = numPythonArgs+1;
86 }
87 }
54 88
55 89 PyObject* pargs = NULL;
56 90 if (count>1) {
57 91 pargs = PyTuple_New(count-1);
58 92 }
59 93 bool err = false;
60 94 // transform Qt values to Python
61 95 const QList<PythonQtMethodInfo::ParameterInfo>& params = m->parameters();
62 96 for (int i = 1; i < count; i++) {
63 97 const PythonQtMethodInfo::ParameterInfo& param = params.at(i);
64 98 PyObject* arg = PythonQtConv::ConvertQtValueToPython(param, arguments[i]);
65 99 if (arg) {
66 100 // steals reference, no unref
67 101 PyTuple_SetItem(pargs, i-1,arg);
68 102 } else {
69 103 err = true;
70 104 break;
71 105 }
72 106 }
73 107
74 108 if (!err) {
75 109 PyErr_Clear();
76 110 PyObject* result = PyObject_CallObject(_callable, pargs);
77 111 if (result) {
78 112 // ok
79 113 Py_DECREF(result);
80 114 } else {
81 115 PythonQt::self()->handleError();
82 116 }
83 117 }
84 118 if (pargs) {
85 119 // free the arguments again
86 120 Py_DECREF(pargs);
87 121 }
88 122 }
89 123
90 124 //------------------------------------------------------------------------------
91 125
92 126 PythonQtSignalReceiver::PythonQtSignalReceiver(QObject* obj):PythonQtSignalReceiverBase(obj)
93 127 {
94 128 _obj = obj;
95 129 _slotCount = staticMetaObject.methodOffset();
96 130 }
97 131
98 132 PythonQtSignalReceiver::~PythonQtSignalReceiver()
99 133 {
134 PythonQt::priv()->removeSignalEmitter(_obj);
100 135 }
101 136
102 137
103 138 bool PythonQtSignalReceiver::addSignalHandler(const char* signal, PyObject* callable)
104 139 {
105 140 bool flag = false;
106 141 int sigId = getSignalIndex(signal);
107 142 if (sigId>=0) {
108 143 // create PythonQtMethodInfo from signal
109 144 QMetaMethod meta = _obj->metaObject()->method(sigId);
110 145 const PythonQtMethodInfo* signalInfo = PythonQtMethodInfo::getCachedMethodInfo(meta);
111 146 PythonQtSignalTarget t(sigId, signalInfo, _slotCount, callable);
112 147 _targets.append(t);
113 148 // now connect to ourselves with the new slot id
114 149 QMetaObject::connect(_obj, sigId, this, _slotCount, Qt::AutoConnection, 0);
115 150
116 151 _slotCount++;
117 152 flag = true;
118 153 }
119 154 return flag;
120 155 }
121 156
122 157 bool PythonQtSignalReceiver::removeSignalHandler(const char* signal, PyObject* callable)
123 158 {
124 159 bool found = false;
125 160 int sigId = getSignalIndex(signal);
126 161 if (sigId>=0) {
127 162 QMutableListIterator<PythonQtSignalTarget> i(_targets);
128 163 while (i.hasNext()) {
129 164 if (i.next().isSame(sigId, callable)) {
130 165 i.remove();
131 166 found = true;
132 167 break;
133 168 }
134 169 }
135 170 }
136 171 return found;
137 172 }
138 173
139 174 void PythonQtSignalReceiver::removeSignalHandlers()
140 175 {
141 176 _targets.clear();
142 177 }
143 178
144 179 int PythonQtSignalReceiver::getSignalIndex(const char* signal)
145 180 {
146 181 int sigId = _obj->metaObject()->indexOfSignal(signal+1);
147 182 if (sigId<0) {
148 183 QByteArray tmpSig = QMetaObject::normalizedSignature(signal+1);
149 184 sigId = _obj->metaObject()->indexOfSignal(tmpSig);
150 185 }
151 186 return sigId;
152 187 }
153 188
154 189 int PythonQtSignalReceiver::qt_metacall(QMetaObject::Call c, int id, void **arguments)
155 190 {
156 191 // mlabDebugConst("PythonQt", "PythonQtSignalReceiver invoke " << _obj->className() << " " << _obj->name() << " " << id);
157 192 if (c != QMetaObject::InvokeMetaMethod) {
158 193 QObject::qt_metacall(c, id, arguments);
159 194 }
160 195
161 196 bool found = false;
162 197 foreach(const PythonQtSignalTarget& t, _targets) {
163 198 if (t.slotId() == id) {
164 199 found = true;
165 200 t.call(arguments);
166 201 break;
167 202 }
168 203 }
169 204 return 0;
170 205 }
171 206
@@ -1,128 +1,136
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 PythonQtStdOut.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 "PythonQtStdOut.h"
43 43
44 44 static PyObject *PythonQtStdOutRedirect_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
45 45 {
46 46 PythonQtStdOutRedirect *self;
47 47 self = (PythonQtStdOutRedirect *)type->tp_alloc(type, 0);
48 48
49 49 self->softspace = 0;
50 50 self->_cb = NULL;
51 51
52 52 return (PyObject *)self;
53 53 }
54 54
55 55 static PyObject *PythonQtStdOutRedirect_write(PyObject *self, PyObject *args)
56 56 {
57 57 PythonQtStdOutRedirect* s = (PythonQtStdOutRedirect*)self;
58 58 if (s->_cb) {
59 59 char *string;
60 60 if (!PyArg_ParseTuple(args, "s", &string))
61 61 return NULL;
62 62
63 63 if (s->softspace > 0) {
64 64 (*s->_cb)(QString(""));
65 65 s->softspace = 0;
66 66 }
67 67
68 68 (*s->_cb)(QString(string));
69 69 }
70 70 return Py_BuildValue("");
71 71 }
72 72
73 static PyObject *PythonQtStdOutRedirect_flush(PyObject *self, PyObject *args)
74 {
75 return Py_BuildValue("");
76 }
77
78
73 79
74 80 static PyMethodDef PythonQtStdOutRedirect_methods[] = {
75 81 {"write", (PyCFunction)PythonQtStdOutRedirect_write, METH_VARARGS,
76 "redirect the writing to a callback"
82 "redirect the writing to a callback"},
83 {"flush", (PyCFunction)PythonQtStdOutRedirect_flush, METH_VARARGS,
84 "flush the output, currently not implemented but needed for logging framework"
77 85 },
78 86 {NULL} /* Sentinel */
79 87 };
80 88
81 89 static PyMemberDef PythonQtStdOutRedirect_members[] = {
82 90 {"softspace", T_INT, offsetof(PythonQtStdOutRedirect, softspace), 0,
83 91 "soft space flag"
84 92 },
85 93 {NULL} /* Sentinel */
86 94 };
87 95
88 96 PyTypeObject PythonQtStdOutRedirectType = {
89 97 PyObject_HEAD_INIT(NULL)
90 98 0, /*ob_size*/
91 99 "PythonQtStdOutRedirect", /*tp_name*/
92 100 sizeof(PythonQtStdOutRedirect), /*tp_basicsize*/
93 101 0, /*tp_itemsize*/
94 102 0, /*tp_dealloc*/
95 103 0, /*tp_print*/
96 104 0, /*tp_getattr*/
97 105 0, /*tp_setattr*/
98 106 0, /*tp_compare*/
99 107 0, /*tp_repr*/
100 108 0, /*tp_as_number*/
101 109 0, /*tp_as_sequence*/
102 110 0, /*tp_as_mapping*/
103 111 0, /*tp_hash */
104 112 0, /*tp_call*/
105 113 0, /*tp_str*/
106 114 0, /*tp_getattro*/
107 115 0, /*tp_setattro*/
108 116 0, /*tp_as_buffer*/
109 117 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
110 118 "PythonQtStdOutRedirect", /* tp_doc */
111 119 0, /* tp_traverse */
112 120 0, /* tp_clear */
113 121 0, /* tp_richcompare */
114 122 0, /* tp_weaklistoffset */
115 123 0, /* tp_iter */
116 124 0, /* tp_iternext */
117 125 PythonQtStdOutRedirect_methods, /* tp_methods */
118 126 PythonQtStdOutRedirect_members, /* tp_members */
119 127 0, /* tp_getset */
120 128 0, /* tp_base */
121 129 0, /* tp_dict */
122 130 0, /* tp_descr_get */
123 131 0, /* tp_descr_set */
124 132 0, /* tp_dictoffset */
125 133 0, /* tp_init */
126 134 0, /* tp_alloc */
127 135 PythonQtStdOutRedirect_new, /* tp_new */
128 136 };
@@ -1,256 +1,271
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 PythonQtVariantWrapper.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 "PythonQtVariantWrapper.h"
43 43 #include <QObject>
44 44 #include <QDate>
45 45 #include <QDateTime>
46 46 #include <QTime>
47 47 #include "PythonQt.h"
48 48 #include "PythonQtSlot.h"
49 49 #include "PythonQtClassInfo.h"
50 50 #include "PythonQtConversion.h"
51 51
52 52 static void PythonQtVariantWrapper_dealloc(PythonQtVariantWrapper* self)
53 53 {
54 54 if (self->_variant) {
55 55 delete self->_variant;
56 56 self->_variant = NULL;
57 57 }
58 58 self->ob_type->tp_free((PyObject*)self);
59 59 }
60 60
61 61 static PyObject* PythonQtVariantWrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
62 62 {
63 63 PythonQtVariantWrapper *self;
64 64
65 65 self = (PythonQtVariantWrapper *)type->tp_alloc(type, 0);
66 66 if (self != NULL) {
67 67 self->_variant = new QVariant();
68 68 self->_info = NULL;
69 69 }
70 70 return (PyObject *)self;
71 71 }
72 72
73 73 static int PythonQtVariantWrapper_init(PythonQtVariantWrapper *self, PyObject *args, PyObject *kwds)
74 74 {
75 75 return 0;
76 76 }
77 77
78 78 static PyObject *PythonQtVariantWrapper_classname(PythonQtVariantWrapper* type)
79 79 {
80 80 return PyString_FromString(type->_info->className());
81 81 }
82 82
83 83 static PyObject *PythonQtVariantWrapper_help(PythonQtVariantWrapper* type)
84 84 {
85 85 return PythonQt::self()->helpCalled(type->_info);
86 86 }
87 87
88 88
89 89 static PyMethodDef PythonQtVariantWrapper_methods[] = {
90 90 {"className", (PyCFunction)PythonQtVariantWrapper_classname, METH_NOARGS,
91 91 "Return the classname of the object"
92 92 },
93 93 {"help", (PyCFunction)PythonQtVariantWrapper_help, METH_NOARGS,
94 94 "Shows the help of available methods for this class"
95 95 },
96 96 {NULL} /* Sentinel */
97 97 };
98 98
99 99
100 100 static PyObject *PythonQtVariantWrapper_getattro(PyObject *obj,PyObject *name)
101 101 {
102 102 const char *attributeName;
103 103 PythonQtVariantWrapper *wt = (PythonQtVariantWrapper *)obj;
104 104
105 105 if ((attributeName = PyString_AsString(name)) == NULL) {
106 106 return NULL;
107 107 }
108 108
109 109 if (wt->_wrapper && wt->_info) {
110 110 PythonQtMemberInfo member = wt->_info->member(attributeName);
111 111 if (member._type == PythonQtMemberInfo::Slot) {
112 112 return PythonQtSlotFunction_New(member._slot, obj, NULL);
113 113 } else if (member._type == PythonQtMemberInfo::EnumValue) {
114 114 return PyInt_FromLong(member._enumValue);
115 115 }
116 116 }
117 117
118 118 // look for the interal methods (className(), help())
119 119 PyObject* internalMethod = Py_FindMethod( PythonQtVariantWrapper_methods, obj, (char*)attributeName);
120 120 if (internalMethod) {
121 121 return internalMethod;
122 122 }
123 123 PyErr_Clear();
124 124
125 125 if (qstrcmp(attributeName, "__dict__")==0) {
126 126 QStringList l = wt->_info->memberList(false);
127 127 PyObject* dict = PyDict_New();
128 128 foreach (QString name, l) {
129 129 //PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
130 130 PyDict_SetItemString(dict, name.toLatin1().data(), Py_None);
131 131 //Py_DECREF(o);
132 132 }
133 133 return dict;
134 134 }
135 135
136 136 QString error = QString(wt->_variant->typeName()) + " has no attribute named '" + QString(attributeName) + "'";
137 137 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
138 138
139 139 return NULL;
140 140 }
141 141
142 142 QString qVariantToString(const QVariant& v) {
143 143 QString r;
144 144 switch (v.type()) {
145 145 case QVariant::Size:
146 146 r = QString::number(v.toSize().width()) + ", " + QString::number(v.toSize().height());
147 147 break;
148 148 case QVariant::SizeF:
149 149 r = QString::number(v.toSizeF().width()) + ", " + QString::number(v.toSizeF().height());
150 150 break;
151 151 case QVariant::Point:
152 152 r = QString::number(v.toPoint().x()) + ", " + QString::number(v.toPoint().y());
153 153 break;
154 154 case QVariant::PointF:
155 155 r = QString::number(v.toPointF().x()) + ", " + QString::number(v.toPointF().y());
156 156 break;
157 157 case QVariant::Rect:
158 158 r = QString::number(v.toRect().x()) + ", " + QString::number(v.toRect().y());
159 159 r += ", " + QString::number(v.toRect().width()) + ", " + QString::number(v.toRect().height());
160 160 break;
161 161 case QVariant::RectF:
162 162 r = QString::number(v.toRectF().x()) + ", " + QString::number(v.toRectF().y());
163 163 r += ", " + QString::number(v.toRectF().width()) + ", " + QString::number(v.toRectF().height());
164 164 break;
165 165 case QVariant::Date:
166 166 r = v.toDate().toString(Qt::ISODate);
167 167 break;
168 168 case QVariant::DateTime:
169 169 r = v.toDateTime().toString(Qt::ISODate);
170 170 break;
171 171 case QVariant::Time:
172 172 r = v.toTime().toString(Qt::ISODate);
173 173 break;
174 case QVariant::Pixmap:
175 {
176 QPixmap p = qvariant_cast<QPixmap>(v);
177 r = QString("Pixmap ") + QString::number(p.width()) + ", " + QString::number(p.height());
178 }
179 break;
180 case QVariant::Image:
181 {
182 QImage img = qvariant_cast<QImage>(v);
183 r = QString("Image ") + QString::number(img.width()) + ", " + QString::number(img.height());
184 }
185 break;
174 186 //TODO: add more printing for other variant types
175 187 default:
176 188 r = v.toString();
177 189 }
178 190 return r;
179 191 }
180 192
181 193 static PyObject * PythonQtVariantWrapper_str(PyObject * obj)
182 194 {
183 195 PythonQtVariantWrapper* wt = (PythonQtVariantWrapper*)obj;
184 196 QString val = qVariantToString(*wt->_variant);
197 if (val.isEmpty()) {
198 val = wt->_variant->typeName();
199 }
185 200 return PyString_FromFormat("%s", val.toLatin1().constData());
186 201 }
187 202
188 203 static PyObject * PythonQtVariantWrapper_repr(PyObject * obj)
189 204 {
190 205 PythonQtVariantWrapper* wt = (PythonQtVariantWrapper*)obj;
191 206 QString val = qVariantToString(*wt->_variant);
192 207 return PyString_FromFormat("%s(%s)", wt->_variant->typeName(), val.toLatin1().constData());
193 208 }
194 209
195 210 static int PythonQtVariantWrapper_compare(PyObject * obj1, PyObject * obj2)
196 211 {
197 212 if (obj1->ob_type == &PythonQtVariantWrapper_Type &&
198 213 obj2->ob_type == &PythonQtVariantWrapper_Type) {
199 214
200 215 PythonQtVariantWrapper* w1 = (PythonQtVariantWrapper*)obj1;
201 216 PythonQtVariantWrapper* w2 = (PythonQtVariantWrapper*)obj2;
202 217 if (*w1->_variant == *w2->_variant) {
203 218 return 0;
204 219 } else {
205 220 return -1;
206 221 }
207 222 } else {
208 223 return -1;
209 224 }
210 225 }
211 226
212 227
213 228 PyTypeObject PythonQtVariantWrapper_Type = {
214 229 PyObject_HEAD_INIT(NULL)
215 230 0, /*ob_size*/
216 231 "PythonQt.PythonQtVariantWrapper", /*tp_name*/
217 232 sizeof(PythonQtVariantWrapper), /*tp_basicsize*/
218 233 0, /*tp_itemsize*/
219 234 (destructor)PythonQtVariantWrapper_dealloc, /*tp_dealloc*/
220 235 0, /*tp_print*/
221 236 0, /*tp_getattr*/
222 237 0, /*tp_setattr*/
223 238 PythonQtVariantWrapper_compare, /*tp_compare*/
224 239 PythonQtVariantWrapper_repr, /*tp_repr*/
225 240 0, /*tp_as_number*/
226 241 0, /*tp_as_sequence*/
227 242 0, /*tp_as_mapping*/
228 243 0, /*tp_hash */
229 244 0, /*tp_call*/
230 245 PythonQtVariantWrapper_str, /*tp_str*/
231 246 PythonQtVariantWrapper_getattro, /*tp_getattro*/
232 247 0, /*tp_setattro*/
233 248 0, /*tp_as_buffer*/
234 249 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
235 250 "PythonQtVariantWrapper object", /* tp_doc */
236 251 0, /* tp_traverse */
237 252 0, /* tp_clear */
238 253 0, /* tp_richcompare */
239 254 0, /* tp_weaklistoffset */
240 255 0, /* tp_iter */
241 256 0, /* tp_iternext */
242 257 0, /* tp_methods */
243 258 0, /* tp_members */
244 259 0, /* tp_getset */
245 260 0, /* tp_base */
246 261 0, /* tp_dict */
247 262 0, /* tp_descr_get */
248 263 0, /* tp_descr_set */
249 264 0, /* tp_dictoffset */
250 265 (initproc)PythonQtVariantWrapper_init, /* tp_init */
251 266 0, /* tp_alloc */
252 267 PythonQtVariantWrapper_new, /* tp_new */
253 268 };
254 269
255 270 //-------------------------------------------------------
256 271
@@ -1,376 +1,400
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 PythonQtWrapper.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 "PythonQtWrapper.h"
43 43 #include <QObject>
44 44 #include "PythonQt.h"
45 45 #include "PythonQtSlot.h"
46 46 #include "PythonQtClassInfo.h"
47 47 #include "PythonQtConversion.h"
48 48
49 49 static void PythonQtWrapper_dealloc(PythonQtWrapper* self)
50 50 {
51 51 if (self->_wrappedPtr) {
52
52
53 53 //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->_info->wrappedClassName().latin1());
54
54
55 55 PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr);
56 56 // we own our qobject, so we delete it now:
57 57 delete self->_obj;
58 58 self->_obj = NULL;
59 59 if (self->_ownedByPythonQt) {
60 60 PythonQtSlotInfo* slot = PythonQt::priv()->getDestructorSlot(self->_info->wrappedCPPClassName());
61 61 if (slot) {
62 62 void* args[2];
63 63 args[0] = NULL;
64 64 args[1] = &self->_wrappedPtr;
65 65 slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, slot->slotIndex(), args);
66 66 self->_wrappedPtr = NULL;
67 67 } else {
68 68 // TODO: print a warning? we can not destroy that object
69 69 }
70 70 }
71 } else if (self->_obj) {
71 } else {
72 72 //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->_info->wrappedClassName().latin1());
73 PythonQt::priv()->removeWrapperPointer(self->_obj);
74 if (self->_ownedByPythonQt) {
75 if (!self->_obj->parent()) {
76 delete self->_obj;
77 self->_obj = NULL;
73 if (self->_objPointerCopy) {
74 PythonQt::priv()->removeWrapperPointer(self->_objPointerCopy);
75 }
76 if (self->_obj) {
77 if (self->_ownedByPythonQt) {
78 if (!self->_obj->parent()) {
79 delete self->_obj;
80 }
81 } else {
82 if (self->_obj->parent()==NULL) {
83 // tell someone who is interested that the qobject is no longer wrapped, if it has no parent
84 PythonQt::qObjectNoLongerWrappedCB(self->_obj);
85 }
78 86 }
79 87 }
80 88 }
89 self->_obj = NULL;
90 self->_obj.~QPointer<QObject>();
81 91 self->ob_type->tp_free((PyObject*)self);
82 92 }
83 93
84 94 static PyObject* PythonQtWrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
85 95 {
86 96 PythonQtWrapper *self;
87
97
88 98 self = (PythonQtWrapper *)type->tp_alloc(type, 0);
89 99 if (self != NULL) {
90 100 self->_info = NULL;
91 self->_obj = NULL;
101 new (&self->_obj) QPointer<QObject>();
92 102 self->_wrappedPtr = NULL;
93 103 self->_ownedByPythonQt = false;
94 104 }
95 105 return (PyObject *)self;
96 106 }
97 107
98 108 static int PythonQtWrapper_init(PythonQtWrapper *self, PyObject *args, PyObject *kwds)
99 109 {
100 110 return 0;
101 111 }
102 112
103 113 static PyObject *PythonQtWrapper_classname(PythonQtWrapper* type)
104 114 {
105 115 return PyString_FromString(type->_info->className());
106 116 }
107 117
108 118 static PyObject *PythonQtWrapper_help(PythonQtWrapper* type)
109 119 {
110 120 return PythonQt::self()->helpCalled(type->_info);
111 121 }
112 122
113 123
114 124 static PyMethodDef PythonQtWrapper_methods[] = {
115 125 {"className", (PyCFunction)PythonQtWrapper_classname, METH_NOARGS,
116 126 "Return the classname of the object"
117 127 },
118 128 {"help", (PyCFunction)PythonQtWrapper_help, METH_NOARGS,
119 129 "Shows the help of available methods for this class"
120 130 },
121 131 {NULL} /* Sentinel */
122 132 };
123 133
124 134
125 135 static PyObject *PythonQtWrapper_getattro(PyObject *obj,PyObject *name)
126 136 {
127 137 const char *attributeName;
128 138 PythonQtWrapper *wt = (PythonQtWrapper *)obj;
129
139
130 140 if ((attributeName = PyString_AsString(name)) == NULL) {
131 141 return NULL;
132 142 }
133
143
134 144 if (!wt->_obj && !wt->_wrappedPtr) {
135 145 QString error = QString("Trying to read attribute '") + attributeName + "' from a destroyed " + wt->_info->className() + " object";
136 146 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
137 147 return NULL;
138 148 }
139
149
140 150 // mlabDebugConst("Python","get " << attributeName);
141
151
142 152 // TODO: dynamic properties are missing
143
153
144 154 PythonQtMemberInfo member = wt->_info->member(attributeName);
145 155 switch (member._type) {
146 156 case PythonQtMemberInfo::Property:
147 157 if (wt->_obj) {
148 158 return PythonQtConv::QVariantToPyObject(member._property.read(wt->_obj));
149 159 }
150 160 break;
151 161 case PythonQtMemberInfo::Slot:
152 162 return PythonQtSlotFunction_New(member._slot, obj, NULL);
153 163 break;
154 164 case PythonQtMemberInfo::EnumValue:
155 165 return PyInt_FromLong(member._enumValue);
156 166 break;
157 167 }
158
168
159 169 // look for the interal methods (className(), help())
160 170 PyObject* internalMethod = Py_FindMethod( PythonQtWrapper_methods, obj, (char*)attributeName);
161 171 if (internalMethod) {
162 172 return internalMethod;
163 173 }
164 174 PyErr_Clear();
165 175
166 176 if (wt->_obj) {
167 177 // look for a child
168 178 QObjectList children = wt->_obj->children();
169 179 for (int i = 0; i < children.count(); i++) {
170 180 QObject *child = children.at(i);
171 181 if (child->objectName() == attributeName) {
172 182 return PythonQt::self()->priv()->wrapQObject(child);
173 183 }
174 184 }
175 185 }
176 186
177 187 if (qstrcmp(attributeName, "__dict__")==0) {
178 188 QStringList l = wt->_info->memberList(false);
179 189 PyObject* dict = PyDict_New();
180 190 foreach (QString name, l) {
181 191 //PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
182 192 PyDict_SetItemString(dict, name.toLatin1().data(), Py_None);
183 193 //Py_DECREF(o);
184 194 }
185 195 // Note: we do not put children into the dict, is would look confusing?!
186 196 return dict;
187 197 }
188 198
189
199
190 200 QString error = QString(wt->_info->className()) + " has no attribute named '" + QString(attributeName) + "'";
191 201 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
192 202 return NULL;
193 203 }
194 204
195 205 static int PythonQtWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
196 206 {
197 207 QString error;
198 208 char *attributeName;
199 209 PythonQtWrapper *wt = (PythonQtWrapper *)obj;
200
210
201 211 if ((attributeName = PyString_AsString(name)) == NULL)
202 212 return -1;
203
213
204 214 if (!wt->_obj) {
205 215 error = QString("Trying to set attribute '") + attributeName + "' on a destroyed " + wt->_info->className() + " object";
206 216 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
207 217 return -1;
208 218 }
209
219
210 220 PythonQtMemberInfo member = wt->_info->member(attributeName);
211 221 if (member._type == PythonQtMemberInfo::Property) {
212 222 QMetaProperty prop = member._property;
213 223 if (prop.isWritable()) {
214 224 QVariant v;
215 225 if (prop.isEnumType()) {
216 226 // this will give us either a string or an int, everything else will probably be an error
217 227 v = PythonQtConv::PyObjToQVariant(value);
218 228 } else {
219 229 int t = prop.userType();
220 230 v = PythonQtConv::PyObjToQVariant(value, t);
221 231 }
222 232 bool success = false;
223 233 if (v.isValid()) {
224 234 success = prop.write(wt->_obj, v);
225 235 }
226 236 if (success) {
227 237 return 0;
228 238 } else {
229 239 error = QString("Property '") + attributeName + "' of type '" +
230 240 prop.typeName() + "' does not accept an object of type "
231 241 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
232 242 }
233 243 } else {
234 244 error = QString("Property '") + attributeName + "' of " + wt->_info->className() + " object is not writable";
235 245 }
236 246 } else {
237 247 if (member._type == PythonQtMemberInfo::Slot) {
238 248 error = QString("Slot '") + attributeName + "' can not be overwritten on " + wt->_info->className() + " object";
239 249 } else if (member._type == PythonQtMemberInfo::EnumValue) {
240 250 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + wt->_info->className() + " object";
241 251 }
242 252 }
243
253
244 254 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
245 255 return -1;
246 256 }
247 257
248 258 static PyObject * PythonQtWrapper_repr(PyObject * obj)
249 259 {
250 260 PythonQtWrapper* wt = (PythonQtWrapper*)obj;
261 QObject *qobj = wt->_obj;
251 262 if (wt->_wrappedPtr) {
252 263 if (wt->_obj) {
253 return PyString_FromFormat("%s (C++ Object 0x%x wrapped by %s 0x%x))", wt->_info->className(), wt->_wrappedPtr, wt->_obj->metaObject()->className(), wt->_obj);
264 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", wt->_info->className(), wt->_wrappedPtr, wt->_obj->metaObject()->className(), qobj);
254 265 } else {
255 return PyString_FromFormat("%s (C++ Object 0x%x unwrapped)", wt->_info->className(), wt->_wrappedPtr);
266 return PyString_FromFormat("%s (C++ Object %p unwrapped)", wt->_info->className(), wt->_wrappedPtr);
256 267 }
257 268 } else {
258 return PyString_FromFormat("%s (QObject 0x%x)", wt->_info->className(), wt->_obj, wt->_wrappedPtr);
269 return PyString_FromFormat("%s (QObject %p)", wt->_info->className(), qobj);
259 270 }
260 271 }
261 272
262 273 static int PythonQtWrapper_compare(PyObject * obj1, PyObject * obj2)
263 274 {
264 275 if (obj1->ob_type == &PythonQtWrapper_Type &&
265 276 obj2->ob_type == &PythonQtWrapper_Type) {
266
277
267 278 PythonQtWrapper* w1 = (PythonQtWrapper*)obj1;
268 279 PythonQtWrapper* w2 = (PythonQtWrapper*)obj2;
269 280 if (w1->_wrappedPtr != NULL) {
270 281 if (w1->_wrappedPtr == w1->_wrappedPtr) {
271 282 return 0;
272 283 } else {
273 284 return -1;
274 285 }
275 286 } else if (w1->_obj == w2->_obj) {
276 287 return 0;
277 288 } else {
278 289 return -1;
279 290 }
280 291 } else {
281 292 return -1;
282 293 }
283 294 }
284 295
285 296 static int PythonQtWrapper_nonzero(PyObject *obj)
286 297 {
287 298 PythonQtWrapper* wt = (PythonQtWrapper*)obj;
288 299 return (wt->_wrappedPtr == NULL && wt->_obj == NULL)?0:1;
289 300 }
290 301
302
303 static long PythonQtWrapper_hash(PythonQtWrapper *obj)
304 {
305 if (obj->_wrappedPtr != NULL) {
306 return reinterpret_cast<long>(obj->_wrappedPtr);
307 } else {
308 QObject* qobj = obj->_obj; // get pointer from QPointer wrapper
309 return reinterpret_cast<long>(qobj);
310 }
311 }
312
313
314
291 315 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
292 316 static PyNumberMethods PythonQtWrapper_as_number = {
293 317 0, /* nb_add */
294 318 0, /* nb_subtract */
295 319 0, /* nb_multiply */
296 320 0, /* nb_divide */
297 321 0, /* nb_remainder */
298 322 0, /* nb_divmod */
299 323 0, /* nb_power */
300 324 0, /* nb_negative */
301 325 0, /* nb_positive */
302 326 0, /* nb_absolute */
303 327 PythonQtWrapper_nonzero, /* nb_nonzero */
304 328 0, /* nb_invert */
305 329 0, /* nb_lshift */
306 330 0, /* nb_rshift */
307 331 0, /* nb_and */
308 332 0, /* nb_xor */
309 333 0, /* nb_or */
310 334 0, /* nb_coerce */
311 335 0, /* nb_int */
312 336 0, /* nb_long */
313 337 0, /* nb_float */
314 338 0, /* nb_oct */
315 339 0, /* nb_hex */
316 340 0, /* nb_inplace_add */
317 341 0, /* nb_inplace_subtract */
318 342 0, /* nb_inplace_multiply */
319 343 0, /* nb_inplace_divide */
320 344 0, /* nb_inplace_remainder */
321 345 0, /* nb_inplace_power */
322 346 0, /* nb_inplace_lshift */
323 347 0, /* nb_inplace_rshift */
324 348 0, /* nb_inplace_and */
325 349 0, /* nb_inplace_xor */
326 350 0, /* nb_inplace_or */
327 351 0, /* nb_floor_divide */
328 352 0, /* nb_true_divide */
329 353 0, /* nb_inplace_floor_divide */
330 354 0, /* nb_inplace_true_divide */
331 355 };
332 356
333 357 PyTypeObject PythonQtWrapper_Type = {
334 358 PyObject_HEAD_INIT(NULL)
335 359 0, /*ob_size*/
336 360 "PythonQt.PythonQtWrapper", /*tp_name*/
337 361 sizeof(PythonQtWrapper), /*tp_basicsize*/
338 362 0, /*tp_itemsize*/
339 363 (destructor)PythonQtWrapper_dealloc, /*tp_dealloc*/
340 364 0, /*tp_print*/
341 365 0, /*tp_getattr*/
342 366 0, /*tp_setattr*/
343 367 PythonQtWrapper_compare, /*tp_compare*/
344 368 PythonQtWrapper_repr, /*tp_repr*/
345 369 &PythonQtWrapper_as_number, /*tp_as_number*/
346 370 0, /*tp_as_sequence*/
347 371 0, /*tp_as_mapping*/
348 0, /*tp_hash */
372 (hashfunc)PythonQtWrapper_hash, /*tp_hash */
349 373 0, /*tp_call*/
350 374 0, /*tp_str*/
351 375 PythonQtWrapper_getattro, /*tp_getattro*/
352 376 PythonQtWrapper_setattro, /*tp_setattro*/
353 377 0, /*tp_as_buffer*/
354 378 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
355 379 "PythonQtWrapper object", /* tp_doc */
356 380 0, /* tp_traverse */
357 381 0, /* tp_clear */
358 382 0, /* tp_richcompare */
359 383 0, /* tp_weaklistoffset */
360 384 0, /* tp_iter */
361 385 0, /* tp_iternext */
362 386 0, /* tp_methods */
363 387 0, /* tp_members */
364 388 0, /* tp_getset */
365 389 0, /* tp_base */
366 390 0, /* tp_dict */
367 391 0, /* tp_descr_get */
368 392 0, /* tp_descr_set */
369 393 0, /* tp_dictoffset */
370 394 (initproc)PythonQtWrapper_init, /* tp_init */
371 395 0, /* tp_alloc */
372 396 PythonQtWrapper_new, /* tp_new */
373 397 };
374 398
375 399 //-------------------------------------------------------
376 400
@@ -1,78 +1,89
1 1 #ifndef _PYTHONQTWRAPPER_H
2 2 #define _PYTHONQTWRAPPER_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 PythonQtWrapper.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
47 47 #include "PythonQtSystem.h"
48 #include <QPointer>
48 49
49 50 #include "structmember.h"
50 51 #include "methodobject.h"
51 52 #include "compile.h"
52 53 #include "eval.h"
53 54
54 55 class PythonQtClassInfo;
55 56 class QObject;
56 57
57 58 extern PYTHONQT_EXPORT PyTypeObject PythonQtWrapper_Type;
58 59
59 60 //---------------------------------------------------------------
60 61 //! a Python wrapper object for Qt objects and C++ objects (that are themselves wrapped by wrapper QObjects)
61 62 typedef struct {
62 63 PyObject_HEAD
63 64
65 //! set the QObject pointer
66 void setQObject(QObject* object) {
67 _obj = object;
68 _objPointerCopy = object;
69 }
70
64 71 //! pointer to the wrapped Qt object or if _wrappedPtr is set, the Qt object that wraps the C++ Ptr
65 QObject* _obj;
72 QPointer<QObject> _obj;
73 //! a copy of the _obj pointer, which is required because the wrapper needs to
74 //! deregister itself via the _obj pointer, even when the QPointer<QObject> object was destroyed
75 void* _objPointerCopy;
76
66 77 //! optional C++ object Ptr that is wrapped by the above _obj
67 78 void* _wrappedPtr;
68 79
69 80 //! the class information, this is set even if the _obj or _wrappedPtr is NULL to support typed NULL pointers
70 81 PythonQtClassInfo* _info;
71 82
72 83 //! flag that stores if the object is owned by pythonQt
73 84 bool _ownedByPythonQt;
74 85
75 86 } PythonQtWrapper;
76 87
77 88
78 89 #endif No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now