##// END OF EJS Templates
- wrapped instances are now wrapped by class specific subtypes to facilitate future deriving from python...
florianlink -
r18:44e5ff2700cb
parent child
Show More
@@ -1,1081 +1,1116
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtImporter.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include "PythonQtMethodInfo.h"
46 46 #include "PythonQtSignalReceiver.h"
47 47 #include "PythonQtConversion.h"
48 48 #include "PythonQtStdOut.h"
49 49 #include "PythonQtCppWrapperFactory.h"
50 50 #include "PythonQtVariants.h"
51 51 #include "PythonQtStdDecorators.h"
52 52 #include "PythonQtQFileImporter.h"
53 53 #include <pydebug.h>
54 54 #include <vector>
55 55
56 56 PythonQt* PythonQt::_self = NULL;
57 57 int PythonQt::_uniqueModuleCount = 0;
58 58
59 59 void PythonQt::init(int flags)
60 60 {
61 61 if (!_self) {
62 62 _self = new PythonQt(flags);
63 63 }
64 64
65 65 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
66 66 qRegisterMetaType<QList<QObject*> >("QList<void*>");
67 67
68 68 PythonQtRegisterToolClassesTemplateConverter(int);
69 69 PythonQtRegisterToolClassesTemplateConverter(float);
70 70 PythonQtRegisterToolClassesTemplateConverter(double);
71 71 // TODO: which other POD types should be available for QList etc.
72 72
73 73 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
74 74
75 75 PythonQt::self()->registerCPPClass("Qt", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_Qt>);
76 76 PythonQt::self()->registerCPPClass("QBitArray", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QBitArray>);
77 77 PythonQt::self()->registerCPPClass("QDate", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QDate>);
78 78 PythonQt::self()->registerCPPClass("QTime", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QTime>);
79 79 PythonQt::self()->registerCPPClass("QDateTime", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QDateTime>);
80 80 PythonQt::self()->registerCPPClass("QUrl", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QUrl>);
81 81 PythonQt::self()->registerCPPClass("QLocale", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLocale>);
82 82 PythonQt::self()->registerCPPClass("QRect", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRect>);
83 83 PythonQt::self()->registerCPPClass("QRectF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRectF>);
84 84 PythonQt::self()->registerCPPClass("QSize", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QSize>);
85 85 PythonQt::self()->registerCPPClass("QSizeF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QSizeF>);
86 86 PythonQt::self()->registerCPPClass("QLine", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLine>);
87 87 PythonQt::self()->registerCPPClass("QLineF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLineF>);
88 88 PythonQt::self()->registerCPPClass("QPoint", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QPoint>);
89 89 PythonQt::self()->registerCPPClass("QPointF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QPointF>);
90 90 PythonQt::self()->registerCPPClass("QRegExp", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRegExp>);
91 91
92 92 PythonQtRegisterToolClassesTemplateConverter(QDate);
93 93 PythonQtRegisterToolClassesTemplateConverter(QTime);
94 94 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
95 95 PythonQtRegisterToolClassesTemplateConverter(QUrl);
96 96 PythonQtRegisterToolClassesTemplateConverter(QLocale);
97 97 PythonQtRegisterToolClassesTemplateConverter(QRect);
98 98 PythonQtRegisterToolClassesTemplateConverter(QRectF);
99 99 PythonQtRegisterToolClassesTemplateConverter(QSize);
100 100 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
101 101 PythonQtRegisterToolClassesTemplateConverter(QLine);
102 102 PythonQtRegisterToolClassesTemplateConverter(QLineF);
103 103 PythonQtRegisterToolClassesTemplateConverter(QPoint);
104 104 PythonQtRegisterToolClassesTemplateConverter(QPointF);
105 105 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
106 106
107 107 PythonQt::self()->registerCPPClass("QFont", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QFont>);
108 108 PythonQt::self()->registerCPPClass("QPixmap", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPixmap>);
109 109 PythonQt::self()->registerCPPClass("QBrush", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QBrush>);
110 110 PythonQt::self()->registerCPPClass("QColor", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QColor>);
111 111 PythonQt::self()->registerCPPClass("QPalette", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPalette>);
112 112 PythonQt::self()->registerCPPClass("QIcon", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QIcon>);
113 113 PythonQt::self()->registerCPPClass("QImage", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QImage>);
114 114 PythonQt::self()->registerCPPClass("QPolygon", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPolygon>);
115 115 PythonQt::self()->registerCPPClass("QRegion", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QRegion>);
116 116 PythonQt::self()->registerCPPClass("QBitmap", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QBitmap>);
117 117 PythonQt::self()->registerCPPClass("QCursor", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QCursor>);
118 118 PythonQt::self()->registerCPPClass("QSizePolicy", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QSizePolicy>);
119 119 PythonQt::self()->registerCPPClass("QKeySequence", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QKeySequence>);
120 120 PythonQt::self()->registerCPPClass("QPen", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPen>);
121 121 PythonQt::self()->registerCPPClass("QTextLength", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QTextLength>);
122 122 PythonQt::self()->registerCPPClass("QTextFormat", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QTextFormat>);
123 123 PythonQt::self()->registerCPPClass("QMatrix", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QMatrix>);
124 124
125 125 PythonQtRegisterToolClassesTemplateConverter(QFont);
126 126 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
127 127 PythonQtRegisterToolClassesTemplateConverter(QBrush);
128 128 PythonQtRegisterToolClassesTemplateConverter(QColor);
129 129 PythonQtRegisterToolClassesTemplateConverter(QPalette);
130 130 PythonQtRegisterToolClassesTemplateConverter(QIcon);
131 131 PythonQtRegisterToolClassesTemplateConverter(QImage);
132 132 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
133 133 PythonQtRegisterToolClassesTemplateConverter(QRegion);
134 134 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
135 135 PythonQtRegisterToolClassesTemplateConverter(QCursor);
136 136 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
137 137 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
138 138 PythonQtRegisterToolClassesTemplateConverter(QPen);
139 139 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
140 140 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
141 141 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
142 142
143 143 }
144 144
145 145 void PythonQt::cleanup()
146 146 {
147 147 if (_self) {
148 148 delete _self;
149 149 _self = NULL;
150 150 }
151 151 }
152 152
153 153 PythonQt::PythonQt(int flags)
154 154 {
155 155 _p = new PythonQtPrivate;
156 156 _p->_initFlags = flags;
157 157
158 158 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
159 159
160 160 Py_SetProgramName("PythonQt");
161 161 if (flags & IgnoreSiteModule) {
162 162 // this prevents the automatic importing of Python site files
163 163 Py_NoSiteFlag = 1;
164 164 }
165 165 Py_Initialize();
166 166
167 167 // add our own python object types for qt object slots
168 168 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
169 169 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
170 170 }
171 171 Py_INCREF(&PythonQtSlotFunction_Type);
172 172
173 // add our own python object types for qt objects
174 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
175 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
176 }
177 Py_INCREF(&PythonQtInstanceWrapper_Type);
178
179 // add our own python object types for qt objects
173 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
174 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
175 // add our own python object types for classes
180 176 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
181 177 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
182 178 }
183 179 Py_INCREF(&PythonQtClassWrapper_Type);
184 180
181 // add our own python object types for CPP instances
182 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
183 PythonQt::handleError();
184 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
185 }
186 Py_INCREF(&PythonQtInstanceWrapper_Type);
187
185 188 // add our own python object types for redirection of stdout
186 189 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
187 190 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
188 191 }
189 192 Py_INCREF(&PythonQtStdOutRedirectType);
190 193
191 194 initPythonQtModule(flags & RedirectStdOut);
192 195
193 196 }
194 197
195 198 PythonQt::~PythonQt() {
196 199 delete _p;
197 200 _p = NULL;
198 201 }
199 202
200 203 PythonQtPrivate::~PythonQtPrivate() {
201 204 delete _defaultImporter;
202 205 _defaultImporter = NULL;
203 206 {
204 207 QHashIterator<QByteArray, PythonQtSlotInfo *> i(_knownQtDecoratorSlots);
205 208 while (i.hasNext()) {
206 209 delete i.next().value();
207 210 }
208 211 }
209 212 {
210 213 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownQtClasses);
211 214 while (i.hasNext()) {
212 215 delete i.next().value();
213 216 }
214 217 }
215 218 {
216 219 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownQtWrapperClasses);
217 220 while (i.hasNext()) {
218 221 delete i.next().value();
219 222 }
220 223 }
221 224 {
222 225 QHashIterator<QByteArray, PythonQtSlotInfo *> i(_constructorSlots);
223 226 while (i.hasNext()) {
224 227 PythonQtSlotInfo* cur = i.next().value();
225 228 while(cur->nextInfo()) {
226 229 PythonQtSlotInfo* next = cur->nextInfo();
227 230 delete cur;
228 231 cur = next;
229 232 }
230 233 delete cur;
231 234 }
232 235 }
233 236 {
234 237 QHashIterator<QByteArray, PythonQtSlotInfo *> i(_destructorSlots);
235 238 while (i.hasNext()) {
236 239 PythonQtSlotInfo* cur = i.next().value();
237 240 while(cur->nextInfo()) {
238 241 PythonQtSlotInfo* next = cur->nextInfo();
239 242 delete cur;
240 243 cur = next;
241 244 }
242 245 delete cur;
243 246 }
244 247 }
245 248 PythonQtConv::global_valueStorage.clear();
246 249 PythonQtConv::global_ptrStorage.clear();
247 250 PythonQtConv::global_variantStorage.clear();
248 251
249 252 PythonQtMethodInfo::cleanupCachedMethodInfos();
250 253 }
251 254
252 255 PythonQtImportFileInterface* PythonQt::importInterface()
253 256 {
254 257 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
255 258 }
256 259
257 260 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
258 261 {
259 262 if (_self->_p->_noLongerWrappedCB) {
260 263 (*_self->_p->_noLongerWrappedCB)(o);
261 264 };
262 265 }
263 266
264 267 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator)
265 268 {
266 269 _p->registerClass(metaobject, package, wrapperCreator);
267 270 }
268 271
269 272 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator)
270 273 {
271 274 // we register all classes in the hierarchy
272 275 const QMetaObject* m = metaobject;
273 276 bool first = true;
274 277 while (m) {
275 278 PythonQtClassInfo* info = _knownQtClasses.value(m->className());
276 279 if (!info) {
277 info = new PythonQtClassInfo(m);
280 info = createPythonQtClassInfo(m, NULL, package);
278 281 _knownQtClasses.insert(m->className(), info);
279 PythonQtObjectPtr pack = packageByName(package);
280 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info);
281 PyModule_AddObject(pack, m->className(), pyobj);
282 if (package && strncmp(package,"Qt",2)==0) {
283 // put all qt objects into Qt as well
284 PythonQtObjectPtr pack = packageByName("Qt");
285 PyModule_AddObject(pack, m->className(), pyobj);
286 }
287 282 }
288 283 if (first) {
289 284 first = false;
290 285 if (wrapperCreator) {
291 286 info->setDecoratorProvider(wrapperCreator);
292 287 }
293 288 }
294 289 m = m->superClass();
295 290 }
296 291 }
297 292
293 PythonQtClassInfo* PythonQtPrivate::createPythonQtClassInfo(const QMetaObject* meta, const char* cppClassName, const char* package)
294 {
295 PythonQtClassInfo* info = new PythonQtClassInfo(meta, cppClassName);
296 PythonQtObjectPtr pack = packageByName(package);
297 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, package);
298 PyModule_AddObject(pack, meta?meta->className():cppClassName, pyobj);
299 if (package && strncmp(package,"Qt",2)==0) {
300 // put all qt objects into Qt as well
301 PythonQtObjectPtr pack = packageByName("Qt");
302 PyModule_AddObject(pack, meta?meta->className():cppClassName, pyobj);
303 }
304 info->setPythonQtClassWrapper(pyobj);
305 return info;
306 }
307
298 308 bool PythonQtPrivate::isEnumType(const QMetaObject* meta, const QByteArray& name) {
299 309 int i = meta?meta->indexOfEnumerator(name.constData()):-1;
300 310 if (i!=-1) {
301 311 return true;
302 312 } else {
303 313 // look for scope
304 314 int scopePos = name.indexOf("::");
305 315 if (scopePos != -1) {
306 316 // slit into scope and enum name
307 317 QByteArray enumScope = name.mid(0,scopePos);
308 318 QByteArray enumName = name.mid(scopePos+2);
309 319 if (enumScope == "Qt") {
310 320 // special qt namespace case
311 321 return isEnumType(&staticQtMetaObject, enumName);
312 322 } else {
313 323 // look for known classes as scope
314 324 // TODO: Q_GADGETS are not yet handled
315 325 PythonQtClassInfo* info = _knownQtClasses.value(enumScope);
316 326 if (info) {
317 327 return isEnumType(info->metaObject(), enumName);
318 328 }
319 329 }
320 330 }
321 331 }
322 332 return false;
323 333 }
324 334
325 335 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
326 336 {
327 337 if (!obj) {
328 338 Py_INCREF(Py_None);
329 339 return Py_None;
330 340 }
331 341 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
332 342 if (!wrap) {
333 343 // smuggling it in...
334 344 PythonQtClassInfo* classInfo = _knownQtClasses.value(obj->metaObject()->className());
335 345 if (!classInfo) {
336 346 registerClass(obj->metaObject());
337 347 classInfo = _knownQtClasses.value(obj->metaObject()->className());
338 348 }
339 349 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
340 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
350 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
341 351 } else {
342 352 Py_INCREF(wrap);
343 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
353 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
344 354 }
345 355 return (PyObject*)wrap;
346 356 }
347 357
348 358 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
349 359 {
350 360 if (!ptr) {
351 361 Py_INCREF(Py_None);
352 362 return Py_None;
353 363 }
354 364 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
355 365 if (!wrap) {
356 366 PythonQtClassInfo* info = _knownQtClasses.value(name);
357 367 if (!info) {
358 368 // we do not know the metaobject yet, but we might know it by it's name:
359 369 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
360 370 // yes, we know it, so we can convert to QObject
361 371 QObject* qptr = (QObject*)ptr;
362 372 registerClass(qptr->metaObject());
363 373 info = _knownQtClasses.value(qptr->metaObject()->className());
364 374 }
365 375 }
366 376 if (info) {
367 377 QObject* qptr = (QObject*)ptr;
368 378 // if the object is a derived object, we want to switch the class info to the one of the derived class:
369 379 if (name!=(qptr->metaObject()->className())) {
370 380 registerClass(qptr->metaObject());
371 381 info = _knownQtClasses.value(qptr->metaObject()->className());
372 382 }
373 383 wrap = createNewPythonQtInstanceWrapper(qptr, info);
374 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
384 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
375 385 } else {
376 386 // maybe it is a PyObject, which we can return directly
377 387 if (name == "PyObject") {
378 388 PyObject* p = (PyObject*)ptr;
379 389 Py_INCREF(p);
380 390 return p;
381 391 }
382 392 // not a known QObject, so try our wrapper factory:
383 393 QObject* wrapper = NULL;
384 394 for (int i=0; i<_cppWrapperFactories.size(); i++) {
385 395 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
386 396 if (wrapper) {
387 397 break;
388 398 }
389 399 }
390 400 PythonQtClassInfo* info = _knownQtWrapperClasses.value(name);
391 401 if (!info) {
392 info = new PythonQtClassInfo(wrapper?wrapper->metaObject():NULL, name);
393 _knownQtWrapperClasses.insert(name, info);
394 PyModule_AddObject(_pythonQtModule, name, (PyObject*)createNewPythonQtClassWrapper(info));
395 } else {
402 registerCPPClass(name.constData());
403 info = _knownQtWrapperClasses.value(name);
404 }
396 405 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
397 406 info->setMetaObject(wrapper->metaObject());
398 407 }
399 }
400 408 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
401 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
409 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
402 410 }
403 411 } else {
404 412 Py_INCREF(wrap);
405 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
413 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
406 414 }
407 415 return (PyObject*)wrap;
408 416 }
409 417
418 PyObject* PythonQtPrivate::dummyTuple() {
419 static PyObject* dummyTuple = NULL;
420 if (dummyTuple==NULL) {
421 dummyTuple = PyTuple_New(1);
422 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
423 }
424 return dummyTuple;
425 }
426
410 427
411 428 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
412 PythonQtInstanceWrapper* result;
413 result = (PythonQtInstanceWrapper *)PythonQtInstanceWrapper_Type.tp_new(&PythonQtInstanceWrapper_Type,
414 NULL, NULL);
429 // call the associated class type to create a new instance...
430 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
415 431
416 432 result->setQObject(obj);
417 result->_info = info;
418 433 result->_wrappedPtr = wrappedPtr;
419 434 result->_ownedByPythonQt = false;
420 435 result->_useQMetaTypeDestroy = false;
421 436
422 437 if (wrappedPtr) {
423 438 _wrappedObjects.insert(wrappedPtr, result);
424 439 } else {
425 440 _wrappedObjects.insert(obj, result);
426 441 if (obj->parent()== NULL && _wrappedCB) {
427 442 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
428 443 (*_wrappedCB)(obj);
429 444 }
430 445 }
431 446 return result;
432 447 }
433 448
434 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info) {
449 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package) {
435 450 PythonQtClassWrapper* result;
436 result = (PythonQtClassWrapper *)PythonQtClassWrapper_Type.tp_new(&PythonQtClassWrapper_Type,
437 NULL, NULL);
438 result->_info = info;
451
452 PyObject* className = PyString_FromString(info->className());
453
454 PyObject* baseClasses = PyTuple_New(1);
455 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
456
457 PyObject* typeDict = PyDict_New();
458 QByteArray moduleName("PythonQt");
459 if (package && strcmp(package, "")!=0) {
460 moduleName += ".";
461 moduleName += package;
462 }
463 PyDict_SetItemString(typeDict, "__module__", PyString_FromString(moduleName.constData()));
464
465 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
466
467 // set the class info so that PythonQtClassWrapper_new can read it
468 _currentClassInfoForClassWrapperCreation = info;
469 // create the new type object by calling the type
470 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
471
472 Py_DECREF(baseClasses);
473 Py_DECREF(typeDict);
474 Py_DECREF(args);
475 Py_DECREF(className);
476
477 //TODO XXX why is this incref needed? It looks like the types get garbage collected somehow?!
478 Py_INCREF((PyObject*)result);
439 479 return result;
440 480 }
441 481
442 482
443 483 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
444 484 {
445 485 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
446 486 if (!r) {
447 487 r = new PythonQtSignalReceiver(obj);
448 488 _p->_signalReceivers.insert(obj, r);
449 489 }
450 490 return r;
451 491 }
452 492
453 493 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
454 494 {
455 495 bool flag = false;
456 496 PythonQtObjectPtr callable = lookupCallable(module, objectname);
457 497 if (callable) {
458 498 PythonQtSignalReceiver* r = getSignalReceiver(obj);
459 499 flag = r->addSignalHandler(signal, callable);
460 500 if (!flag) {
461 501 // signal not found
462 502 }
463 503 } else {
464 504 // callable not found
465 505 }
466 506 return flag;
467 507 }
468 508
469 509 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
470 510 {
471 511 bool flag = false;
472 512 PythonQtSignalReceiver* r = getSignalReceiver(obj);
473 513 if (r) {
474 514 flag = r->addSignalHandler(signal, receiver);
475 515 }
476 516 return flag;
477 517 }
478 518
479 519 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
480 520 {
481 521 bool flag = false;
482 522 PythonQtObjectPtr callable = lookupCallable(module, objectname);
483 523 if (callable) {
484 524 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
485 525 if (r) {
486 526 flag = r->removeSignalHandler(signal, callable);
487 527 }
488 528 } else {
489 529 // callable not found
490 530 }
491 531 return flag;
492 532 }
493 533
494 534 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
495 535 {
496 536 bool flag = false;
497 537 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
498 538 if (r) {
499 539 flag = r->removeSignalHandler(signal, receiver);
500 540 }
501 541 return flag;
502 542 }
503 543
504 544 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
505 545 {
506 546 PythonQtObjectPtr p = lookupObject(module, name);
507 547 if (p) {
508 548 if (PyCallable_Check(p)) {
509 549 return p;
510 550 }
511 551 }
512 552 PyErr_Clear();
513 553 return NULL;
514 554 }
515 555
516 556 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
517 557 {
518 558 QStringList l = name.split('.');
519 559 PythonQtObjectPtr p = module;
520 560 PythonQtObjectPtr prev;
521 561 QString s;
522 562 QByteArray b;
523 563 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
524 564 prev = p;
525 565 b = (*i).toLatin1();
526 566 p.setNewRef(PyObject_GetAttrString(p, b.data()));
527 567 }
528 568 PyErr_Clear();
529 569 return p;
530 570 }
531 571
532 572 PythonQtObjectPtr PythonQt::getMainModule() {
533 573 //both borrowed
534 574 PythonQtObjectPtr dict = PyImport_GetModuleDict();
535 575 return PyDict_GetItemString(dict, "__main__");
536 576 }
537 577
538 578 QVariant PythonQt::evalCode(PyObject* module, PyObject* pycode) {
539 579 QVariant result;
540 580 if (pycode) {
541 581 PyObject* r = PyEval_EvalCode((PyCodeObject*)pycode, PyModule_GetDict((PyObject*)module) , PyModule_GetDict((PyObject*)module));
542 582 if (r) {
543 583 result = PythonQtConv::PyObjToQVariant(r);
544 584 Py_DECREF(r);
545 585 } else {
546 586 handleError();
547 587 }
548 588 } else {
549 589 handleError();
550 590 }
551 591 return result;
552 592 }
553 593
554 594 QVariant PythonQt::evalScript(PyObject* module, const QString& script, int start)
555 595 {
556 596 QVariant result;
557 597 PythonQtObjectPtr p;
558 598 p.setNewRef(PyRun_String(script.toLatin1().data(), start, PyModule_GetDict(module), PyModule_GetDict(module)));
559 599 if (p) {
560 600 result = PythonQtConv::PyObjToQVariant(p);
561 601 } else {
562 602 handleError();
563 603 }
564 604 return result;
565 605 }
566 606
567 607 void PythonQt::evalFile(PyObject* module, const QString& filename)
568 608 {
569 609 PythonQtObjectPtr code = parseFile(filename);
570 610 if (code) {
571 611 evalCode(module, code);
572 612 } else {
573 613 handleError();
574 614 }
575 615 }
576 616
577 617 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
578 618 {
579 619 PythonQtObjectPtr p;
580 620 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
581 621 if (!p) {
582 622 handleError();
583 623 }
584 624 return p;
585 625 }
586 626
587 627 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
588 628 {
589 629 PythonQtObjectPtr code = parseFile(filename);
590 630 PythonQtObjectPtr module = _p->createModule(name, code);
591 631 return module;
592 632 }
593 633
594 634 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
595 635 {
596 636 PyErr_Clear();
597 637 QString scriptCode = script;
598 638 if (scriptCode.isEmpty()) {
599 639 // we always need at least a linefeed
600 640 scriptCode = "\n";
601 641 }
602 642 PythonQtObjectPtr pycode;
603 643 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
604 644 PythonQtObjectPtr module = _p->createModule(name, pycode);
605 645 return module;
606 646 }
607 647
608 648 PythonQtObjectPtr PythonQt::createUniqueModule()
609 649 {
610 650 static QString pyQtStr("PythonQt_module");
611 651 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
612 652 return createModuleFromScript(moduleName);
613 653 }
614 654
615 655 void PythonQt::addObject(PyObject* module, const QString& name, QObject* object)
616 656 {
617 657 PyModule_AddObject(module, name.toLatin1().data(), _p->wrapQObject(object));
618 658 }
619 659
620 660 void PythonQt::addVariable(PyObject* module, const QString& name, const QVariant& v)
621 661 {
622 662 PyModule_AddObject(module, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
623 663 }
624 664
625 665 void PythonQt::removeVariable(PyObject* module, const QString& name)
626 666 {
627 667 PyObject_DelAttrString(module, name.toLatin1().data());
628 668 }
629 669
630 670 QVariant PythonQt::getVariable(PyObject* module, const QString& objectname)
631 671 {
632 672 QVariant result;
633 673 PythonQtObjectPtr obj = lookupObject(module, objectname);
634 674 if (obj) {
635 675 result = PythonQtConv::PyObjToQVariant(obj);
636 676 }
637 677 return result;
638 678 }
639 679
640 680 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
641 681 {
642 682 QStringList results;
643 683
644 684 PythonQtObjectPtr object;
645 685 if (objectname.isEmpty()) {
646 686 object = module;
647 687 } else {
648 688 object = lookupObject(module, objectname);
649 689 if (!object && type == CallOverloads) {
650 690 PyObject* dict = lookupObject(module, "__builtins__");
651 691 if (dict) {
652 692 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
653 693 }
654 694 }
655 695 }
656 696
657 697 if (object) {
658 698 if (type == CallOverloads) {
659 699 if (PythonQtSlotFunction_Check(object)) {
660 700 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
661 701 PythonQtSlotInfo* info = o->m_ml;
662 702
663 703 while (info) {
664 704 results << info->fullSignature(info->isInstanceDecorator());
665 705 info = info->nextInfo();
666 706 }
667 707 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
668 708 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
669 PythonQtSlotInfo* info = o->_info->constructors();
709 PythonQtSlotInfo* info = o->classInfo()->constructors();
670 710
671 711 while (info) {
672 712 results << info->fullSignature(false);
673 713 info = info->nextInfo();
674 714 }
675 715 } else {
676 716 //TODO: use pydoc!
677 717 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
678 718 if (doc) {
679 719 results << PyString_AsString(doc);
680 720 Py_DECREF(doc);
681 721 }
682 722 }
683 723 } else {
684 724 PyObject* keys = PyObject_Dir(object);
685 725 if (keys) {
686 726 int count = PyList_Size(keys);
687 727 PyObject* key;
688 728 PyObject* value;
689 729 QString keystr;
690 730 for (int i = 0;i<count;i++) {
691 731 key = PyList_GetItem(keys,i);
692 732 value = PyObject_GetAttr(object, key);
693 733 if (!value) continue;
694 734 keystr = PyString_AsString(key);
695 735 static const QString underscoreStr("__tmp");
696 736 if (!keystr.startsWith(underscoreStr)) {
697 737 switch (type) {
698 738 case Anything:
699 739 results << keystr;
700 740 break;
701 741 case Class:
702 742 if (value->ob_type == &PyClass_Type) {
703 743 results << keystr;
704 744 }
705 745 break;
706 746 case Variable:
707 747 if (value->ob_type != &PyClass_Type
708 748 && value->ob_type != &PyCFunction_Type
709 749 && value->ob_type != &PyFunction_Type
710 750 && value->ob_type != &PyModule_Type
711 751 ) {
712 752 results << keystr;
713 753 }
714 754 break;
715 755 case Function:
716 756 if (value->ob_type == &PyFunction_Type ||
717 757 value->ob_type == &PyMethod_Type
718 758 ) {
719 759 results << keystr;
720 760 }
721 761 break;
722 762 case Module:
723 763 if (value->ob_type == &PyModule_Type) {
724 764 results << keystr;
725 765 }
726 766 break;
727 767 default:
728 768 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
729 769 }
730 770 }
731 771 Py_DECREF(value);
732 772 }
733 773 Py_DECREF(keys);
734 774 }
735 775 }
736 776 }
737 777 return results;
738 778 }
739 779
740 780 QVariant PythonQt::call(PyObject* module, const QString& name, const QVariantList& args)
741 781 {
742 782 QVariant r;
743 783
744 784 PythonQtObjectPtr callable = lookupCallable(module, name);
745 785 if (callable) {
746 786 PythonQtObjectPtr pargs;
747 787 int count = args.size();
748 788 if (count>0) {
749 789 pargs.setNewRef(PyTuple_New(count));
750 790 }
751 791 bool err = false;
752 792 // transform QVariants to Python
753 793 for (int i = 0; i < count; i++) {
754 794 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
755 795 if (arg) {
756 796 // steals reference, no unref
757 797 PyTuple_SetItem(pargs, i,arg);
758 798 } else {
759 799 err = true;
760 800 break;
761 801 }
762 802 }
763 803
764 804 if (!err) {
765 805 PyErr_Clear();
766 806 PythonQtObjectPtr result;
767 807 result.setNewRef(PyObject_CallObject(callable, pargs));
768 808 if (result) {
769 809 // ok
770 810 r = PythonQtConv::PyObjToQVariant(result);
771 811 } else {
772 812 PythonQt::self()->handleError();
773 813 }
774 814 }
775 815 }
776 816 return r;
777 817 }
778 818
779 819 void PythonQt::addInstanceDecorators(QObject* o)
780 820 {
781 821 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
782 822 }
783 823
784 824 void PythonQt::addClassDecorators(QObject* o)
785 825 {
786 826 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
787 827 }
788 828
789 829 void PythonQt::addDecorators(QObject* o)
790 830 {
791 831 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
792 832 }
793 833
794 834 void PythonQt::registerQObjectClassNames(const QStringList& names)
795 835 {
796 836 _p->registerQObjectClassNames(names);
797 837 }
798 838
799 839 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
800 840 {
801 841 PythonQtImport::init();
802 842 _p->_importInterface = importInterface;
803 843 }
804 844
805 845 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
806 846 {
807 847 _p->_importIgnorePaths = paths;
808 848 }
809 849
810 850 const QStringList& PythonQt::getImporterIgnorePaths()
811 851 {
812 852 return _p->_importIgnorePaths;
813 853 }
814 854
815 855 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
816 856 {
817 857 _p->_cppWrapperFactories.append(factory);
818 858 }
819 859
820 void PythonQt::addConstructorHandler(PythonQtConstructorHandler* factory)
821 {
822 _p->_constructorHandlers.append(factory);
823 }
824
825 const QList<PythonQtConstructorHandler*>& PythonQt::constructorHandlers()
826 {
827 return _p->_constructorHandlers;
828 };
829
830 860 //---------------------------------------------------------------------------------------------------
831 861 PythonQtPrivate::PythonQtPrivate()
832 862 {
833 863 _importInterface = NULL;
834 864 _defaultImporter = new PythonQtQFileImporter;
835 865 _noLongerWrappedCB = NULL;
836 866 _wrappedCB = NULL;
867 _currentClassInfoForClassWrapperCreation = NULL;
868 }
869
870 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
871 {
872 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
873 _currentClassInfoForClassWrapperCreation = NULL;
874 return info;
837 875 }
838 876
839 877 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
840 878 {
841 879 o->setParent(this);
842 880 int numMethods = o->metaObject()->methodCount();
843 881 for (int i = 0; i < numMethods; i++) {
844 882 QMetaMethod m = o->metaObject()->method(i);
845 883 if ((m.methodType() == QMetaMethod::Method ||
846 884 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
847 885 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m);
848 886 if (qstrncmp(m.signature(), "new_", 4)==0) {
849 887 if ((decoTypes & ConstructorDecorator) == 0) continue;
850 888 // either it returns a * or a QVariant and the name starts with "new_"
851 889 bool isVariantReturn = info->parameters().at(0).typeId == PythonQtMethodInfo::Variant;
852 890 if ((info->parameters().at(0).isPointer || isVariantReturn)) {
853 891 QByteArray signature = m.signature();
854 892 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
855 893 PythonQtSlotInfo* prev = _constructorSlots.value(nameOfClass);
856 894 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
857 895 if (prev) {
858 896 newSlot->setNextInfo(prev->nextInfo());
859 897 prev->setNextInfo(newSlot);
860 898 } else {
861 899 _constructorSlots.insert(nameOfClass, newSlot);
862 900 }
863 901 }
864 902 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
865 903 if ((decoTypes & DestructorDecorator) == 0) continue;
866 904 QByteArray signature = m.signature();
867 905 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
868 906 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
869 907 _destructorSlots.insert(nameOfClass, newSlot);
870 908 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
871 909 if ((decoTypes & StaticDecorator) == 0) continue;
872 910 QByteArray signature = m.signature();
873 911 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
874 912 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
875 913 PythonQtSlotInfo* slotCopy = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
876 914 _knownQtDecoratorSlots.insert(nameOfClass, slotCopy);
877 915 } else {
878 916 if ((decoTypes & InstanceDecorator) == 0) continue;
879 917 if (info->parameters().count()>1) {
880 918 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
881 919 if (p.isPointer) {
882 920 PythonQtSlotInfo* slotCopy = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::InstanceDecorator);
883 921 _knownQtDecoratorSlots.insert(p.name, slotCopy);
884 922 }
885 923 }
886 924 }
887 925 }
888 926 }
889 927 }
890 928
891 929 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
892 930 {
893 931 foreach(QString name, names) {
894 932 _knownQObjectClassNames.insert(name.toLatin1(), true);
895 933 }
896 934 }
897 935
898 936 QList<PythonQtSlotInfo*> PythonQtPrivate::getDecoratorSlots(const QByteArray& className)
899 937 {
900 938 return _knownQtDecoratorSlots.values(className);
901 939 }
902 940
903 941 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
904 942 {
905 943 _signalReceivers.remove(obj);
906 944 }
907 945
908 946 bool PythonQt::handleError()
909 947 {
910 948 bool flag = false;
911 949 if (PyErr_Occurred()) {
912 950
913 951 // currently we just print the error and the stderr handler parses the errors
914 952 PyErr_Print();
915 953
916 954 /*
917 955 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
918 956 PyObject *ptype;
919 957 PyObject *pvalue;
920 958 PyObject *ptraceback;
921 959 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
922 960
923 961 Py_XDECREF(ptype);
924 962 Py_XDECREF(pvalue);
925 963 Py_XDECREF(ptraceback);
926 964 */
927 965 PyErr_Clear();
928 966 flag = true;
929 967 }
930 968 return flag;
931 969 }
932 970
933 971 void PythonQt::addSysPath(const QString& path)
934 972 {
935 973 PythonQtObjectPtr sys;
936 974 sys.setNewRef(PyImport_ImportModule("sys"));
937 975 PythonQtObjectPtr obj = lookupObject(sys, "path");
938 976 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
939 977 }
940 978
941 979 void PythonQt::overwriteSysPath(const QStringList& paths)
942 980 {
943 981 PythonQtObjectPtr sys;
944 982 sys.setNewRef(PyImport_ImportModule("sys"));
945 983 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
946 984 }
947 985
948 986 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
949 987 {
950 988 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
951 989 }
952 990
953 991 void PythonQt::stdOutRedirectCB(const QString& str)
954 992 {
955 993 emit PythonQt::self()->pythonStdOut(str);
956 994 }
957 995
958 996 void PythonQt::stdErrRedirectCB(const QString& str)
959 997 {
960 998 emit PythonQt::self()->pythonStdErr(str);
961 999 }
962 1000
963 1001 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
964 1002 {
965 1003 _p->_wrappedCB = cb;
966 1004 }
967 1005
968 1006 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
969 1007 {
970 1008 _p->_noLongerWrappedCB = cb;
971 1009 }
972 1010
973 1011
974 1012
975 1013 static PyMethodDef PythonQtMethods[] = {
976 1014 {NULL, NULL, 0, NULL}
977 1015 };
978 1016
979 1017 void PythonQt::initPythonQtModule(bool redirectStdOut)
980 1018 {
981 1019 _p->_pythonQtModule.setNewRef(Py_InitModule("PythonQt", PythonQtMethods));
982 1020
983 1021 if (redirectStdOut) {
984 1022 PythonQtObjectPtr sys;
985 1023 PythonQtObjectPtr out;
986 1024 PythonQtObjectPtr err;
987 1025 sys.setNewRef(PyImport_ImportModule("sys"));
988 1026 // create a redirection object for stdout and stderr
989 1027 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
990 1028 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
991 1029 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
992 1030 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
993 1031 // replace the built in file objects with our own objects
994 1032 PyModule_AddObject(sys, "stdout", out);
995 1033 PyModule_AddObject(sys, "stderr", err);
996 1034 }
997 1035 }
998 1036
999 1037 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator)
1000 1038 {
1001 1039 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator);
1002 1040 }
1003 1041
1004 1042
1005 1043 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator)
1006 1044 {
1007 1045 PythonQtClassInfo* info = _knownQtWrapperClasses.value(typeName);
1008 1046 if (!info) {
1009 info = new PythonQtClassInfo(NULL, typeName);
1047 info = createPythonQtClassInfo(NULL, typeName, package);
1010 1048 _knownQtWrapperClasses.insert(typeName, info);
1011 PythonQtObjectPtr pack = packageByName(package);
1012 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info);
1013 PyModule_AddObject(pack, typeName, pyobj);
1014 if (package && strncmp(package,"Qt",2)==0) {
1015 // put all qt objects into Qt as well
1016 PythonQtObjectPtr pack = packageByName("Qt");
1017 PyModule_AddObject(pack, typeName, pyobj);
1018 }
1019 1049 }
1020 1050 if (parentTypeName) {
1021 1051 info->setWrappedParentClassName(parentTypeName);
1022 1052 }
1023 1053 if (wrapperCreator) {
1024 1054 info->setDecoratorProvider(wrapperCreator);
1025 1055 }
1026 1056 }
1027 1057
1028 1058 PythonQtObjectPtr PythonQtPrivate::packageByName(const char* name)
1029 1059 {
1030 1060 if (name==NULL || name[0]==0) {
1031 1061 return _pythonQtModule;
1032 1062 }
1033 1063 PythonQtObjectPtr v = _packages.value(name);
1034 1064 if (!v) {
1035 1065 v.setNewRef(PyImport_AddModule((QByteArray("PythonQt.") + name).constData()));
1036 1066 _packages.insert(name, v);
1037 1067 PyModule_AddObject(_pythonQtModule, name, v);
1038 1068 }
1039 1069 return v;
1040 1070 }
1041 1071
1042 1072
1043 1073 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1044 1074 {
1045 1075 if (_p->_initFlags & ExternalHelp) {
1046 1076 emit pythonHelpRequest(QByteArray(info->className()));
1047 1077 return Py_BuildValue("");
1048 1078 } else {
1049 1079 return PyString_FromString(info->help().toLatin1().data());
1050 1080 }
1051 1081 }
1052 1082
1053 1083 void PythonQtPrivate::removeWrapperPointer(void* obj)
1054 1084 {
1055 1085 _wrappedObjects.remove(obj);
1056 1086 }
1057 1087
1088 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1089 {
1090 _wrappedObjects.insert(obj, wrapper);
1091 }
1092
1058 1093 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1059 1094 {
1060 1095 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1061 1096 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1062 1097 // this is a wrapper whose QObject was already removed due to destruction
1063 1098 // so the obj pointer has to be a new QObject with the same address...
1064 1099 // we remove the old one and set the copy to NULL
1065 1100 wrap->_objPointerCopy = NULL;
1066 1101 removeWrapperPointer(obj);
1067 1102 wrap = NULL;
1068 1103 }
1069 1104 return wrap;
1070 1105 }
1071 1106
1072 1107 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1073 1108 {
1074 1109 PythonQtObjectPtr result;
1075 1110 if (pycode) {
1076 1111 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1077 1112 } else {
1078 1113 PythonQt::self()->handleError();
1079 1114 }
1080 1115 return result;
1081 1116 }
@@ -1,504 +1,508
1 1 #ifndef _PYTHONQT_H
2 2 #define _PYTHONQT_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQt.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46 #include "PythonQtInstanceWrapper.h"
47 47 #include "PythonQtClassWrapper.h"
48 48 #include "PythonQtSlot.h"
49 49 #include "PythonQtObjectPtr.h"
50 50 #include <QObject>
51 51 #include <QVariant>
52 52 #include <QList>
53 53 #include <QHash>
54 54 #include <QByteArray>
55 55 #include <QStringList>
56 56 #include <QtDebug>
57 57 #include <iostream>
58 58
59 59
60 60 class PythonQtClassInfo;
61 61 class PythonQtPrivate;
62 62 class PythonQtMethodInfo;
63 63 class PythonQtSignalReceiver;
64 64 class PythonQtImportFileInterface;
65 65 class PythonQtCppWrapperFactory;
66 class PythonQtConstructorHandler;
67 66 class PythonQtQFileImporter;
68 67
69 68 typedef void PythonQtQObjectWrappedCB(QObject* object);
70 69 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
71 70
72 71 //! callback to create a QObject lazyly
73 72 typedef QObject* PythonQtQObjectCreatorFunctionCB();
74 73
75 74 //! helper template to create a derived QObject class
76 75 template<class T> QObject* PythonQtCreateObject() { return new T(); };
77 76
78 77 //! the main interface to the Python Qt binding, realized as a singleton
79 78 class PYTHONQT_EXPORT PythonQt : public QObject {
80 79
81 80 Q_OBJECT
82 81
83 82 public:
84 83 enum InitFlags {
85 84 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
86 85 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
87 86 ExternalHelp = 4 //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
88 87 };
89 88
90 89 //! initialize the python qt binding (flags are a or combination of InitFlags)
91 90 static void init(int flags = IgnoreSiteModule | RedirectStdOut);
92 91
93 92 //! cleanup
94 93 static void cleanup();
95 94
96 95 //! get the singleton instance
97 96 static PythonQt* self() { return _self; }
98 97
99 98 //-----------------------------------------------------------------------------
100 99 // Public API:
101 100
102 101 //! defines the object types for introspection
103 102 enum ObjectType {
104 103 Class,
105 104 Function,
106 105 Variable,
107 106 Module,
108 107 Anything,
109 108 CallOverloads
110 109 };
111 110
112 111 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
113 112 void overwriteSysPath(const QStringList& paths);
114 113
115 114 //! prepend a path to sys.path to allow importing from it
116 115 void addSysPath(const QString& path);
117 116
118 117 //! sets the __path__ list of a module to the given list (important for local imports)
119 118 void setModuleImportPath(PyObject* module, const QStringList& paths);
120 119
121 120 //! get the __main__ module of python
122 121 PythonQtObjectPtr getMainModule();
123 122
124 123 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
125 124 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
126 125 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
127 126 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL);
128 127
129 128 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
130 129 //! (ownership of wrapper is passed to PythonQt)
131 130 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
132 131
133 132 This will add a wrapper object that is used to make calls to the given classname \c typeName.
134 133 All slots that take a pointer to typeName as the first argument will be callable from Python on
135 134 a variant object that contains such a type.
136 135 */
137 136 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL);
138 137
139 138 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
140 139 //! and it will register the classes when it first sees a pointer to such a derived class
141 140 void registerQObjectClassNames(const QStringList& names);
142 141
143 142 //! parses the given file and returns the python code object, this can then be used to call evalCode()
144 143 PythonQtObjectPtr parseFile(const QString& filename);
145 144
146 145 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
147 146 //! If pycode is NULL, a python error is printed.
148 147 QVariant evalCode(PyObject* module, PyObject* pycode);
149 148
150 149 //! evaluates the given script code and returns the result value
151 150 QVariant evalScript(PyObject* module, const QString& script, int start = Py_file_input);
152 151
153 152 //! evaluates the given script code from file
154 153 void evalFile(PyObject* module, const QString& filename);
155 154
156 155 //! creates the new module \c name and evaluates the given file in the context of that module
157 156 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
158 157 //! to a module later on.
159 158 //! The user needs to make sure that the \c name is unique in the python module dictionary.
160 159 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
161 160
162 161 //! creates the new module \c name and evaluates the given script in the context of that module.
163 162 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
164 163 //! to a module later on.
165 164 //! The user needs to make sure that the \c name is unique in the python module dictionary.
166 165 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
167 166
168 167 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
169 168 //! script code
170 169 PythonQtObjectPtr createUniqueModule();
171 170
172 171 //@{ Signal handlers
173 172
174 173 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
175 174 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
176 175
177 176 //! remove a signal handler from the given \c signal of \c obj
178 177 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
179 178
180 179 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
181 180 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
182 181
183 182 //! remove a signal handler from the given \c signal of \c obj
184 183 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
185 184
186 185 //@}
187 186
188 187 //@{ Variable access
189 188
190 189 //! add the given \c object to the \c module as a variable with \c name (it can be removed via clearVariable)
191 190 void addObject(PyObject* module, const QString& name, QObject* object);
192 191
193 192 //! add the given variable to the module
194 193 void addVariable(PyObject* module, const QString& name, const QVariant& v);
195 194
196 195 //! remove the given variable
197 196 void removeVariable(PyObject* module, const QString& name);
198 197
199 198 //! get the variable with the \c name of the \c module, returns an invalid QVariant on error
200 199 QVariant getVariable(PyObject* module, const QString& name);
201 200
202 201 //! read vars etc. in scope of a module, optional looking inside of an object \c objectname
203 202 QStringList introspection(PyObject* module, const QString& objectname, ObjectType type);
204 203
205 204 //! returns the found callable object or NULL
206 205 //! @return new reference
207 206 PythonQtObjectPtr lookupCallable(PyObject* module, const QString& name);
208 207
209 208 //@}
210 209
211 210 //@{ Calling of python callables
212 211
213 212 //! call the given python method, returns the result converted to a QVariant
214 213 QVariant call(PyObject* module, const QString& callable, const QVariantList& args = QVariantList());
215 214
216 215 //@}
217 216
218 217 //@{ Decorations, constructors, wrappers...
219 218
220 219
221 220 //! add an object whose slots will be used as decorator slots for
222 221 //! other QObjects or CPP classes. The slots need to follow the
223 222 //! convention that the first argument is a pointer to the wrapped object.
224 223 //! (ownership is passed to PythonQt)
225 224 /*!
226 225 Example:
227 226
228 227 A slot with the signature
229 228
230 229 \code
231 230 bool doSomething(QWidget* w, int a)
232 231 \endcode
233 232
234 233 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
235 234 that will be called with the concrete instance as first argument.
236 235 So in Python you can now e.g. call
237 236
238 237 \code
239 238 someWidget.doSomething(12)
240 239 \endcode
241 240
242 241 without QWidget really having this method. This allows to easily make normal methods
243 242 of Qt classes callable by forwarding them with such decorator slots
244 243 or to make CPP classes (which are not derived from QObject) callable from Python.
245 244 */
246 245 void addInstanceDecorators(QObject* o);
247 246
248 247 //! add an object whose slots will be used as decorator slots for
249 248 //! class objects (ownership is passed to PythonQt)
250 249 /*!
251 250 The slots need to follow the following convention:
252 251 - SomeClass* new_SomeClass(...)
253 252 - QVariant new_SomeClass(...)
254 253 - void delete_SomeClass(SomeClass*)
255 254 - ... static_SomeClass_someName(...)
256 255
257 256 This will add:
258 257 - a constructor
259 258 - a constructor which generates a QVariant
260 259 - a destructor (only useful for CPP objects)
261 260 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
262 261
263 262 */
264 263 void addClassDecorators(QObject* o);
265 264
266 265 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
267 266 void addDecorators(QObject* o);
268 267
269 268 //! add the given factory to PythonQt (ownership stays with caller)
270 269 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
271 270
272 //! add the given constructor handler to PythonQt (ownership stays with caller)
273 void addConstructorHandler(PythonQtConstructorHandler* handler);
274
275 //! get list of constructor handlers
276 const QList<PythonQtConstructorHandler*>& constructorHandlers();
277
278 271 //@}
279 272
280 273 //@{ Custom importer (to replace internal import implementation of python)
281 274
282 275 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
283 276 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
284 277 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
285 278 //! This is not reversible, so even setting setImporter(NULL) afterwards will
286 279 //! keep the custom PythonQt importer with a QFile default import interface.
287 280 //! Subsequent python import calls will make use of the passed importInterface
288 281 //! which forwards all import calls to the given \c importInterface.
289 282 //! Passing NULL will install a default QFile importer.
290 283 //! (\c importInterface ownership stays with caller)
291 284 void setImporter(PythonQtImportFileInterface* importInterface);
292 285
293 286 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
294 287 //! (without calling setImporter or installDefaultImporter at least once, the default python import
295 288 //! mechanism is in place)
296 289 //! the default importer allows to import files from anywhere QFile can read from,
297 290 //! including the Qt resource system using ":". Keep in mind that you need to extend
298 291 //! "sys.path" with ":" to be able to import from the Qt resources.
299 292 void installDefaultImporter() { setImporter(NULL); }
300 293
301 294 //! set paths that the importer should ignore
302 295 void setImporterIgnorePaths(const QStringList& paths);
303 296
304 297 //! get paths that the importer should ignore
305 298 const QStringList& getImporterIgnorePaths();
306 299
307 300 //@}
308 301
309 302 //! get access to internal data (should not be used on the public API, but is used by some C functions)
310 303 static PythonQtPrivate* priv() { return _self->_p; }
311 304
312 305 //! get access to the file importer (if set)
313 306 static PythonQtImportFileInterface* importInterface();
314 307
315 308 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
316 309 //! The error is currently just output to the python stderr, future version might implement better trace printing
317 310 bool handleError();
318 311
319 312 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
320 313 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
321 314 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
322 315 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
323 316
324 317 //! call the callback if it is set
325 318 static void qObjectNoLongerWrappedCB(QObject* o);
326 319
327 320 signals:
328 321 //! emitted when python outputs something to stdout (and redirection is turned on)
329 322 void pythonStdOut(const QString& str);
330 323 //! emitted when python outputs something to stderr (and redirection is turned on)
331 324 void pythonStdErr(const QString& str);
332 325
333 326 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
334 327 void pythonHelpRequest(const QByteArray& cppClassName);
335 328
336 329
337 330 public:
338 331 //! called by internal help methods
339 332 PyObject* helpCalled(PythonQtClassInfo* info);
340 333
341 334 //! returns the found object or NULL
342 335 //! @return new reference
343 336 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
344 337
345 338 private:
346 339 void initPythonQtModule(bool redirectStdOut);
347 340
348 341 //! callback for stdout redirection, emits pythonStdOut signal
349 342 static void stdOutRedirectCB(const QString& str);
350 343 //! callback for stderr redirection, emits pythonStdErr signal
351 344 static void stdErrRedirectCB(const QString& str);
352 345
353 346 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
354 347 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
355 348
356 349 PythonQt(int flags);
357 350 ~PythonQt();
358 351
359 352 static PythonQt* _self;
360 353 static int _uniqueModuleCount;
361 354
362 355 PythonQtPrivate* _p;
363 356
364 357 };
365 358
366 359 //! internal PythonQt details
367 360 class PythonQtPrivate : public QObject {
368 361
369 362 Q_OBJECT
370 363
371 364 public:
372 365 PythonQtPrivate();
373 366 ~PythonQtPrivate();
374 367
375 368 enum DecoratorTypes {
376 369 StaticDecorator = 1,
377 370 ConstructorDecorator = 2,
378 371 DestructorDecorator = 4,
379 372 InstanceDecorator = 8,
380 373 AllDecorators = 0xffff
381 374 };
382 375
383 376 //! returns if the id is the id for PythonQtObjectPtr
384 377 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
385 378
379 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
380 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
386 381 //! remove the wrapper ptr again
387 382 void removeWrapperPointer(void* obj);
388 383
389 384 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
390 385 void removeSignalEmitter(QObject* obj);
391 386
392 387 //! wrap the given QObject into a Python object (or return existing wrapper!)
393 388 PyObject* wrapQObject(QObject* obj);
394 389
395 390 //! 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
396 391 PyObject* wrapPtr(void* ptr, const QByteArray& name);
397 392
398 393 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
399 394 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
400 395 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
401 396 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL);
402 397
403 398 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
404 399 //! (ownership of wrapper is passed to PythonQt)
405 400 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
406 401
407 402 This will add a wrapper object that is used to make calls to the given classname \c typeName.
408 403 All slots that take a pointer to typeName as the first argument will be callable from Python on
409 404 a variant object that contains such a type.
410 405 */
411 406 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL);
412 407
413 408 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
414 409 //! and it will register the classes when it first sees a pointer to such a derived class
415 410 void registerQObjectClassNames(const QStringList& names);
416 411
417 412 //! add a decorator object
418 413 void addDecorators(QObject* o, int decoTypes);
419 414
420 415 //! get list of all slots that are available as decorator slots
421 416 QList<PythonQtSlotInfo*> getDecoratorSlots(const QByteArray& className);
422 417
423 418 //! check if the enum is either part of the \c meta class or contains a scope and is
424 419 //! an enum of another known metaobject (and as last resort, of the Qt namespace)
425 420 bool isEnumType(const QMetaObject* meta, const QByteArray& name);
426 421
427 422 //! helper method that creates a PythonQtClassWrapper object
428 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info);
423 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package = NULL);
429 424
430 425 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
431 426 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
432 427
433 428 //! get the class info for a meta object (if available)
434 429 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownQtClasses.value(meta->className()); }
435 430
436 431 //! get the class info for a meta object (if available)
437 432 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownQtClasses.value(className); }
438 433
439 434 //! get the constructor slot for the given classname
440 435 PythonQtSlotInfo* getConstructorSlot(const QByteArray& className) { return _constructorSlots.value(className); }
441 436
442 437 //! get the destructor slot for the given classname
443 438 PythonQtSlotInfo* getDestructorSlot(const QByteArray& className) { return _destructorSlots.value(className); }
444 439
445 440 //! creates the new module from the given pycode
446 441 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
447 442
443 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
444 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
445
446 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
447 static PyObject* dummyTuple();
448
448 449 private:
450
451 //! create a new class info and python wrapper type
452 PythonQtClassInfo* createPythonQtClassInfo(const QMetaObject* meta, const char* cppClassName, const char* package);
453
449 454 //! get/create new package module
450 455 PythonQtObjectPtr packageByName(const char* name);
451 456
452 457 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
453 458 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
454 459
455 460 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
456 461 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
457 462
458 463 //! stores the meta info of known Qt classes
459 464 QHash<QByteArray, PythonQtClassInfo *> _knownQtClasses;
460 465
461 466 //! stores the meta info of known Qt classes
462 467 QHash<QByteArray, PythonQtClassInfo *> _knownQtWrapperClasses;
463 468
464 469 //! stores the meta info of known Qt C++ wrapper classes
465 470 QMultiHash<QByteArray, PythonQtSlotInfo *> _knownQtDecoratorSlots;
466 471
467 472 //! names of qobject derived classes that can be casted to qobject savely
468 473 QHash<QByteArray, bool> _knownQObjectClassNames;
469 474
470 475 //! stores signal receivers for QObjects
471 476 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
472 477
473 478 //! the PythonQt python module
474 479 PythonQtObjectPtr _pythonQtModule;
475 480
476 481 //! the importer interface (if set)
477 482 PythonQtImportFileInterface* _importInterface;
478 483
479 484 //! the default importer
480 485 PythonQtQFileImporter* _defaultImporter;
481 486
482 487 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
483 488 PythonQtQObjectWrappedCB* _wrappedCB;
484 489
485 490 QStringList _importIgnorePaths;
486 491
487 492 //! the cpp object wrapper factories
488 493 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
489 494
490 //! the cpp object wrapper factories
491 QList<PythonQtConstructorHandler*> _constructorHandlers;
492
493 495 QHash<QByteArray , PythonQtSlotInfo *> _constructorSlots;
494 496 QHash<QByteArray , PythonQtSlotInfo *> _destructorSlots;
495 497
496 498 QHash<QByteArray, PythonQtObjectPtr> _packages;
497 499
500 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
501
498 502 int _initFlags;
499 503 int _PythonQtObjectPtr_metaId;
500 504
501 505 friend class PythonQt;
502 506 };
503 507
504 508 #endif
@@ -1,657 +1,658
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtClassInfo.h"
43 43 #include "PythonQtMethodInfo.h"
44 44 #include "PythonQt.h"
45 45 #include <QMetaMethod>
46 46
47 47 QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;
48 48
49 49 PythonQtClassInfo::PythonQtClassInfo(const QMetaObject* meta, const QByteArray& wrappedClassName) {
50 50 _meta = meta;
51 51 _wrappedClassName = wrappedClassName;
52 52 _constructors = NULL;
53 53 _parentClassInfo = NULL;
54 54 _parentClassInfoResolved = false;
55 55 _decoratorProvider = NULL;
56 56 _decoratorProviderCB = NULL;
57 _pythonQtClassWrapper = NULL;
57 58 if (wrappedClassName.isEmpty()) {
58 59 _metaTypeId = -1;
59 60 } else {
60 61 _metaTypeId = QMetaType::type(wrappedClassName);
61 62 }
62 63 }
63 64
64 65 PythonQtClassInfo::~PythonQtClassInfo()
65 66 {
66 67 clearCachedMembers();
67 68 }
68 69
69 70 void PythonQtClassInfo::clearCachedMembers()
70 71 {
71 72 QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers);
72 73 while (i.hasNext()) {
73 74 PythonQtMemberInfo member = i.next().value();
74 75 if (member._type== PythonQtMemberInfo::Slot) {
75 76 PythonQtSlotInfo* info = member._slot;
76 77 while (info) {
77 78 PythonQtSlotInfo* next = info->nextInfo();
78 79 delete info;
79 80 info = next;
80 81 }
81 82 }
82 83 }
83 84 }
84 85
85 86 void PythonQtClassInfo::resolveParentClassInfo()
86 87 {
87 88 if (!_parentClassInfoResolved) {
88 89 _parentClassInfoResolved = true;
89 90 if (isCPPWrapper()) {
90 91 if (!_wrappedClassName.isEmpty()) {
91 92 _parentClassInfo = PythonQt::priv()->getClassInfo(_wrappedParentClassName);
92 93 }
93 94 } else {
94 95 if (_meta->superClass()) {
95 96 _parentClassInfo = PythonQt::priv()->getClassInfo(_meta->superClass());
96 97 }
97 98 }
98 99 }
99 100 }
100 101
101 102 int PythonQtClassInfo::findCharOffset(const char* sigStart, char someChar)
102 103 {
103 104 const char* sigEnd = sigStart;
104 105 char c;
105 106 do {
106 107 c = *sigEnd++;
107 108 } while (c!=someChar && c!=0);
108 109 return sigEnd-sigStart-1;
109 110 }
110 111
111 112 bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName)
112 113 {
113 114 bool found = false;
114 115 bool nameMapped = false;
115 116 const char* attributeName = memberName;
116 117 // look for properties
117 118 int i = _meta->indexOfProperty(attributeName);
118 119 if (i==-1) {
119 120 // try to map name to objectName
120 121 if (qstrcmp(attributeName, "name")==0) {
121 122 attributeName = "objectName";
122 123 nameMapped = true;
123 124 i = _meta->indexOfProperty(attributeName);
124 125 }
125 126 }
126 127 if (i!=-1) {
127 128 PythonQtMemberInfo newInfo(_meta->property(i));
128 129 _cachedMembers.insert(attributeName, newInfo);
129 130 if (nameMapped) {
130 131 _cachedMembers.insert(memberName, newInfo);
131 132 }
132 133 #ifdef PYTHONQT_DEBUG
133 134 std::cout << "caching property " << memberName << " on " << _meta->className() << std::endl;
134 135 #endif
135 136 found = true;
136 137 }
137 138 return found;
138 139 }
139 140
140 141 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache) {
141 142 QObject* decoratorProvider = decorator();
142 143 if (decoratorProvider) {
143 144 const QMetaObject* meta = decoratorProvider->metaObject();
144 145 int memberNameLen = strlen(memberName);
145 146 int numMethods = meta->methodCount();
146 147 int startFrom = QObject::staticMetaObject.methodCount();
147 148 for (int i = startFrom; i < numMethods; i++) {
148 149 QMetaMethod m = meta->method(i);
149 150 if ((m.methodType() == QMetaMethod::Method ||
150 151 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
151 152
152 153 const char* sigStart = m.signature();
153 154 bool isClassDeco = false;
154 155 if (qstrncmp(sigStart, "static_", 7)==0) {
155 156 // skip the static_classname_ part of the string
156 157 sigStart += 7 + 1 + strlen(className());
157 158 isClassDeco = true;
158 159 } else if (qstrncmp(sigStart, "new_", 4)==0) {
159 160 isClassDeco = true;
160 161 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
161 162 isClassDeco = true;
162 163 }
163 164 // find the first '('
164 165 int offset = findCharOffset(sigStart, '(');
165 166
166 167 // XXX no checking is currently done if the slots have correct first argument or not...
167 168
168 169 // check if same length and same name
169 170 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
170 171 found = true;
171 172 PythonQtSlotInfo* info = new PythonQtSlotInfo(m, i, decoratorProvider, isClassDeco?PythonQtSlotInfo::ClassDecorator:PythonQtSlotInfo::InstanceDecorator);
172 173 if (tail) {
173 174 tail->setNextInfo(info);
174 175 } else {
175 176 PythonQtMemberInfo newInfo(info);
176 177 memberCache.insert(memberName, newInfo);
177 178 }
178 179 tail = info;
179 180 }
180 181 }
181 182 }
182 183 }
183 184 return tail;
184 185 }
185 186
186 187 bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName)
187 188 {
188 189 bool found = false;
189 190 int memberNameLen = strlen(memberName);
190 191 PythonQtSlotInfo* tail = NULL;
191 192 if (_meta) {
192 193 int numMethods = _meta->methodCount();
193 194 for (int i = 0; i < numMethods; i++) {
194 195 QMetaMethod m = _meta->method(i);
195 196 if ((m.methodType() == QMetaMethod::Method ||
196 197 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
197 198
198 199 const char* sigStart = m.signature();
199 200 // find the first '('
200 201 int offset = findCharOffset(sigStart, '(');
201 202
202 203 // check if same length and same name
203 204 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
204 205 found = true;
205 206 PythonQtSlotInfo* info = new PythonQtSlotInfo(m, i);
206 207 if (tail) {
207 208 tail->setNextInfo(info);
208 209 } else {
209 210 PythonQtMemberInfo newInfo(info);
210 211 _cachedMembers.insert(memberName, newInfo);
211 212 }
212 213 tail = info;
213 214 }
214 215 }
215 216 }
216 217 }
217 218
218 219 // look for dynamic decorators in this class and in derived classes
219 220 PythonQtClassInfo* info = this;
220 221 while (info) {
221 222 tail = info->findDecoratorSlotsFromDecoratorProvider(memberName, tail, found, _cachedMembers);
222 223 if (!info->_parentClassInfoResolved) {
223 224 info->resolveParentClassInfo();
224 225 }
225 226 info = info->_parentClassInfo;
226 227 }
227 228
228 229 // look for decorators
229 230 if (!_wrappedClassName.isEmpty()) {
230 231 tail = findDecoratorSlots(_wrappedClassName.constData(), memberName, memberNameLen, tail, found);
231 232 }
232 233
233 234 const QMetaObject* meta = _meta;
234 235 while (meta) {
235 236 tail = findDecoratorSlots(meta->className(), memberName, memberNameLen, tail, found);
236 237 meta = meta->superClass();
237 238 }
238 239 return found;
239 240 }
240 241
241 242 bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* memberName)
242 243 {
243 244 bool found = false;
244 245 // look for enum values
245 246 int enumCount = meta->enumeratorCount();
246 247 for (int i=0;i<enumCount; i++) {
247 248 QMetaEnum e = meta->enumerator(i);
248 249 for (int j=0; j < e.keyCount(); j++) {
249 250 if (qstrcmp(e.key(j), memberName)==0) {
250 251 PythonQtMemberInfo newInfo(e.value(j));
251 252 _cachedMembers.insert(memberName, newInfo);
252 253 #ifdef PYTHONQT_DEBUG
253 254 std::cout << "caching enum " << memberName << " on " << meta->className() << std::endl;
254 255 #endif
255 256 found = true;
256 257 }
257 258 }
258 259 }
259 260 return found;
260 261 }
261 262
262 263 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
263 264 {
264 265 PythonQtMemberInfo info = _cachedMembers.value(memberName);
265 266 if (info._type != PythonQtMemberInfo::Invalid) {
266 267 return info;
267 268 } else {
268 269 bool found = false;
269 270
270 271 found = lookForPropertyAndCache(memberName);
271 272 if (!found) {
272 273 found = lookForMethodAndCache(memberName);
273 274 }
274 275 if (!found) {
275 276 if (_meta) {
276 277 // check enums in our meta object directly
277 278 found = lookForEnumAndCache(_meta, memberName);
278 279 }
279 280 if (!found) {
280 281 // check enums in the class hierachy of CPP classes
281 282 // look for dynamic decorators in this class and in derived classes
282 283 PythonQtClassInfo* info = this;
283 284 while (info && !found) {
284 285 QObject* deco = info->decorator();
285 286 if (deco) {
286 287 // call on ourself for caching, but with different metaObject():
287 288 found = lookForEnumAndCache(deco->metaObject(), memberName);
288 289 }
289 290 if (!info->_parentClassInfoResolved) {
290 291 info->resolveParentClassInfo();
291 292 }
292 293 info = info->_parentClassInfo;
293 294 }
294 295 }
295 296 }
296 297 if (!found) {
297 298 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
298 299 info._type = PythonQtMemberInfo::NotFound;
299 300 _cachedMembers.insert(memberName, info);
300 301 }
301 302 }
302 303
303 304 return _cachedMembers.value(memberName);
304 305 }
305 306
306 307 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlots(const char* classname, const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool& found)
307 308 {
308 309 QListIterator<PythonQtSlotInfo*> it(PythonQt::priv()->getDecoratorSlots(classname));
309 310 while (it.hasNext()) {
310 311
311 312 PythonQtSlotInfo* infoOrig = it.next();
312 313
313 314 const char* sigStart = infoOrig->metaMethod()->signature();
314 315 if (qstrncmp("static_", sigStart, 7)==0) {
315 316 sigStart += 7;
316 317 sigStart += findCharOffset(sigStart, '_')+1;
317 318 }
318 319 int offset = findCharOffset(sigStart, '(');
319 320 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
320 321 //make a copy, otherwise we will have trouble on overloads!
321 322 PythonQtSlotInfo* info = new PythonQtSlotInfo(*infoOrig);
322 323 found = true;
323 324 if (tail) {
324 325 tail->setNextInfo(info);
325 326 } else {
326 327 PythonQtMemberInfo newInfo(info);
327 328 _cachedMembers.insert(memberName, newInfo);
328 329 }
329 330 tail = info;
330 331 }
331 332 }
332 333 return tail;
333 334 }
334 335
335 336 void PythonQtClassInfo::listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly) {
336 337 QObject* decoratorProvider = decorator();
337 338 if (decoratorProvider) {
338 339 const QMetaObject* meta = decoratorProvider->metaObject();
339 340 int numMethods = meta->methodCount();
340 341 int startFrom = QObject::staticMetaObject.methodCount();
341 342 for (int i = startFrom; i < numMethods; i++) {
342 343 QMetaMethod m = meta->method(i);
343 344 if ((m.methodType() == QMetaMethod::Method ||
344 345 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
345 346
346 347 const char* sigStart = m.signature();
347 348 bool isClassDeco = false;
348 349 if (qstrncmp(sigStart, "static_", 7)==0) {
349 350 // skip the static_classname_ part of the string
350 351 sigStart += 7 + 1 + strlen(className());
351 352 isClassDeco = true;
352 353 } else if (qstrncmp(sigStart, "new_", 4)==0) {
353 354 continue;
354 355 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
355 356 continue;
356 357 }
357 358 // find the first '('
358 359 int offset = findCharOffset(sigStart, '(');
359 360
360 361 // XXX no checking is currently done if the slots have correct first argument or not...
361 362 if (!metaOnly || isClassDeco) {
362 363 list << QString::fromLatin1(sigStart, offset);
363 364 }
364 365 }
365 366 }
366 367 }
367 368 }
368 369
369 370 QStringList PythonQtClassInfo::memberList(bool metaOnly)
370 371 {
371 372 resolveParentClassInfo();
372 373 decorator();
373 374
374 375 QStringList l;
375 376 QString h;
376 377 if (_wrappedClassName.isEmpty() && _meta && !metaOnly) {
377 378 int i;
378 379 int numProperties = _meta->propertyCount();
379 380 for (i = 0; i < numProperties; i++) {
380 381 QMetaProperty p = _meta->property(i);
381 382 l << QString(p.name());
382 383 }
383 384 }
384 385
385 386 // normal slots of QObject (or wrapper QObject)
386 387 if (!metaOnly && _meta) {
387 388 int numMethods = _meta->methodCount();
388 389 bool skipQObj = !_wrappedClassName.isEmpty();
389 390 for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) {
390 391 QMetaMethod m = _meta->method(i);
391 392 if ((m.methodType() == QMetaMethod::Method ||
392 393 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
393 394 QByteArray signa(m.signature());
394 395 if (signa.startsWith("new_")) continue;
395 396 if (signa.startsWith("delete_")) continue;
396 397 if (signa.startsWith("static_")) continue;
397 398 PythonQtSlotInfo slot(m, i);
398 399 l << slot.slotName();
399 400 }
400 401 }
401 402 }
402 403
403 404 {
404 405 // look for dynamic decorators in this class and in derived classes
405 406 PythonQtClassInfo* info = this;
406 407 while (info) {
407 408 info->listDecoratorSlotsFromDecoratorProvider(l, metaOnly);
408 409 if (!info->_parentClassInfoResolved) {
409 410 info->resolveParentClassInfo();
410 411 }
411 412 info = info->_parentClassInfo;
412 413 }
413 414 }
414 415
415 416 // look for decorators
416 417 QList<const char*> names;
417 418 if (!_wrappedClassName.isEmpty()) {
418 419 // CPP wrapper case:
419 420 names << _wrappedClassName.constData();
420 421 // for CPP classes which are wrapped, we do not want to look for decorators of the wrapping qobjects, since they
421 422 // would require a different pointer on the decorator slot call
422 423 } else {
423 424 // QObject case:
424 425 const QMetaObject* meta = _meta;
425 426 while (meta) {
426 427 if (meta==&QObject::staticMetaObject && !_wrappedClassName.isEmpty()) break;
427 428 names << meta->className();
428 429 meta = meta->superClass();
429 430 }
430 431 }
431 432
432 433 QListIterator<const char*> nameIt(names);
433 434 while (nameIt.hasNext()) {
434 435 QListIterator<PythonQtSlotInfo*> it(PythonQt::priv()->getDecoratorSlots(nameIt.next()));
435 436 while (it.hasNext()) {
436 437 PythonQtSlotInfo* slot = it.next();
437 438 if (metaOnly) {
438 439 if (slot->isClassDecorator()) {
439 440 QByteArray first = slot->slotName();
440 441 if (first.startsWith("static_")) {
441 442 int idx = first.indexOf('_');
442 443 idx = first.indexOf('_', idx+1);
443 444 first = first.mid(idx+1);
444 445 }
445 446 l << first;
446 447 }
447 448 } else {
448 449 l << slot->slotName();
449 450 }
450 451 }
451 452 }
452 453
453 454 // List enumerator keys...
454 455 QList<const QMetaObject*> enumMetaObjects;
455 456 if (_meta) {
456 457 enumMetaObjects << _meta;
457 458 }
458 459 // check enums in the class hierachy of CPP classes
459 460 PythonQtClassInfo* info = this;
460 461 while (info) {
461 462 QObject* deco = info->decorator();
462 463 if (deco) {
463 464 enumMetaObjects << deco->metaObject();
464 465 }
465 466 if (!info->_parentClassInfoResolved) {
466 467 info->resolveParentClassInfo();
467 468 }
468 469 info = info->_parentClassInfo;
469 470 }
470 471
471 472 foreach(const QMetaObject* meta, enumMetaObjects) {
472 473 for (int i = 0; i<meta->enumeratorCount(); i++) {
473 474 QMetaEnum e = meta->enumerator(i);
474 475 for (int j=0; j < e.keyCount(); j++) {
475 476 l << QString(e.key(j));
476 477 }
477 478 }
478 479 }
479 480 return l;
480 481 }
481 482
482 483 const char* PythonQtClassInfo::className()
483 484 {
484 485 if (!_wrappedClassName.isEmpty()) {
485 486 return _wrappedClassName.constData();
486 487 } else {
487 488 return _meta->className();
488 489 }
489 490 }
490 491
491 492 bool PythonQtClassInfo::inherits(const char* name)
492 493 {
493 494 resolveParentClassInfo();
494 495 if (isCPPWrapper()) {
495 496 PythonQtClassInfo* info = this;
496 497 while (info) {
497 498 if (_wrappedClassName == name) {
498 499 return true;
499 500 }
500 501 if (!info->_parentClassInfoResolved) {
501 502 info->resolveParentClassInfo();
502 503 }
503 504 info = info->_parentClassInfo;
504 505 }
505 506 } else {
506 507 const QMetaObject* m = _meta;
507 508 while (m) {
508 509 if (strcmp(name, m->className())==0) {
509 510 return true;
510 511 }
511 512 m = m->superClass();
512 513 }
513 514 }
514 515 return false;
515 516 }
516 517
517 518 QString PythonQtClassInfo::help()
518 519 {
519 520 resolveParentClassInfo();
520 521 decorator();
521 522 QString h;
522 523 h += QString("--- ") + QString(className()) + QString(" ---\n");
523 524
524 525 if (_wrappedClassName.isEmpty()) {
525 526 h += "Properties:\n";
526 527
527 528 int i;
528 529 int numProperties = _meta->propertyCount();
529 530 for (i = 0; i < numProperties; i++) {
530 531 QMetaProperty p = _meta->property(i);
531 532 h += QString(p.name()) + " (" + QString(p.typeName()) + " )\n";
532 533 }
533 534 }
534 535
535 536 if (constructors()) {
536 537 h += "Constructors:\n";
537 538 PythonQtSlotInfo* constr = constructors();
538 539 while (constr) {
539 540 h += constr->fullSignature(false) + "\n";
540 541 constr = constr->nextInfo();
541 542 }
542 543 }
543 544
544 545 h += "Slots:\n";
545 546 h += "QString help()\n";
546 547 h += "QString className()\n";
547 548
548 549 if (_meta) {
549 550 int numMethods = _meta->methodCount();
550 551 for (int i = 0; i < numMethods; i++) {
551 552 QMetaMethod m = _meta->method(i);
552 553 if ((m.methodType() == QMetaMethod::Method ||
553 554 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
554 555 QByteArray signa(m.signature());
555 556 if (signa.startsWith("new_")) continue;
556 557 if (signa.startsWith("delete_")) continue;
557 558 if (signa.startsWith("static_")) continue;
558 559 PythonQtSlotInfo slot(m, i);
559 560 h += slot.fullSignature(false)+ "\n";
560 561 }
561 562 }
562 563 }
563 564
564 565 // TODO xxx : decorators and enums from decorator() are missing...
565 566 // maybe we can reuse memberlist()?
566 567
567 568 // look for decorators
568 569 QList<const char*> names;
569 570 if (!_wrappedClassName.isEmpty()) {
570 571 names << _wrappedClassName.constData();
571 572 }
572 573 const QMetaObject* meta = _meta;
573 574 while (meta) {
574 575 names << meta->className();
575 576 meta = meta->superClass();
576 577 }
577 578
578 579 QListIterator<const char*> nameIt(names);
579 580 while (nameIt.hasNext()) {
580 581 QListIterator<PythonQtSlotInfo*> it(PythonQt::priv()->getDecoratorSlots(nameIt.next()));
581 582 while (it.hasNext()) {
582 583 PythonQtSlotInfo* slot = it.next();
583 584 h += slot->fullSignature(slot->isInstanceDecorator()) + "\n";
584 585 }
585 586 }
586 587
587 588 if (_meta && _meta->enumeratorCount()) {
588 589 h += "Enums:\n";
589 590 for (int i = 0; i<_meta->enumeratorCount(); i++) {
590 591 QMetaEnum e = _meta->enumerator(i);
591 592 h += QString(e.name()) + " {";
592 593 for (int j=0; j < e.keyCount(); j++) {
593 594 if (j) { h+= ", "; }
594 595 h += e.key(j);
595 596 }
596 597 h += " }\n";
597 598 }
598 599 }
599 600
600 601 if (_wrappedClassName.isEmpty() && _meta) {
601 602 int numMethods = _meta->methodCount();
602 603 if (numMethods>0) {
603 604 h += "Signals:\n";
604 605 for (int i = 0; i < numMethods; i++) {
605 606 QMetaMethod m = _meta->method(i);
606 607 if (m.methodType() == QMetaMethod::Signal) {
607 608 h += QString(m.signature()) + "\n";
608 609 }
609 610 }
610 611 }
611 612 }
612 613 return h;
613 614 }
614 615
615 616 PythonQtSlotInfo* PythonQtClassInfo::constructors()
616 617 {
617 618 if (!_constructors) {
618 619 // force creation of lazy decorator, which will register the decorators
619 620 decorator();
620 621 _constructors = PythonQt::priv()->getConstructorSlot(!_wrappedClassName.isEmpty()?_wrappedClassName:QByteArray(_meta->className()));
621 622 }
622 623 return _constructors;
623 624 }
624 625
625 626 void PythonQtClassInfo::setMetaObject(const QMetaObject* meta)
626 627 {
627 628 _meta = meta;
628 629 clearCachedMembers();
629 630 }
630 631
631 632 QObject* PythonQtClassInfo::decorator()
632 633 {
633 634 if (!_decoratorProvider && _decoratorProviderCB) {
634 635 _decoratorProvider = (*_decoratorProviderCB)();
635 636 if (_decoratorProvider) {
636 637 _decoratorProvider->setParent(PythonQt::priv());
637 638 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
638 639 }
639 640 }
640 641 return _decoratorProvider;
641 642 }
642 643
643 644 bool PythonQtClassInfo::hasOwnerMethodButNoOwner(void* object)
644 645 {
645 646 PythonQtMemberInfo info = member("hasOwner");
646 647 if (info._type == PythonQtMemberInfo::Slot) {
647 648 void* obj = object;
648 649 bool result = false;
649 650 void* args[2];
650 651 args[0] = &result;
651 652 args[1] = &obj;
652 653 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
653 654 return !result;
654 655 } else {
655 656 return false;
656 657 }
657 658 }
@@ -1,161 +1,169
1 1 #ifndef _PYTHONQTCLASSINFO_H
2 2 #define _PYTHONQTCLASSINFO_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 #include <QMetaObject>
37 37 #include <QMetaMethod>
38 38 #include <QHash>
39 39 #include <QByteArray>
40 40 #include <QList>
41 41 #include "PythonQt.h"
42 42
43 43 class PythonQtSlotInfo;
44 44
45 45 struct PythonQtMemberInfo {
46 46 enum Type {
47 47 Invalid, Slot, EnumValue, Property, NotFound
48 48 };
49 49
50 50 PythonQtMemberInfo():_slot(NULL),_enumValue(0),_type(Invalid) { }
51 51
52 52 PythonQtMemberInfo(PythonQtSlotInfo* info) {
53 53 _type = Slot;
54 54 _slot = info;
55 55 _enumValue = 0;
56 56 }
57 57
58 58 PythonQtMemberInfo(unsigned int enumValue) {
59 59 _type = EnumValue;
60 60 _slot = NULL;
61 61 _enumValue = enumValue;
62 62 }
63 63
64 64 PythonQtMemberInfo(const QMetaProperty& prop) {
65 65 _type = Property;
66 66 _slot = NULL;
67 67 _enumValue = 0;
68 68 _property = prop;
69 69 }
70 70
71 71 PythonQtSlotInfo* _slot;
72 72 unsigned int _enumValue;
73 73 QMetaProperty _property;
74 74 Type _type;
75 75 };
76 76
77 77 //! a class that stores all required information about a Qt object (and an optional associated C++ class name)
78 78 /*! for fast lookup of slots when calling the object from Python
79 79 */
80 80 class PythonQtClassInfo {
81 81
82 82 public:
83 83 PythonQtClassInfo(const QMetaObject* meta, const QByteArray& wrappedClassName = QByteArray());
84 84
85 85 ~PythonQtClassInfo();
86 86
87 87 //! get the Python method definition for a given slot name (without return type and signature)
88 88 PythonQtMemberInfo member(const char* member);
89 89
90 90 PythonQtSlotInfo* constructors();
91 91
92 92 //! get the classname (either of the QObject or of the wrapped CPP object)
93 93 const char* className();
94 94
95 95 //! returns if the object is a CPP wrapper
96 96 bool isCPPWrapper() { return !_wrappedClassName.isEmpty(); }
97 97
98 98 //! get the meta object
99 99 const QMetaObject* metaObject() { return _meta; }
100 100
101 101 //! set the meta object, this will reset the caching
102 102 void setMetaObject(const QMetaObject* meta);
103 103
104 104 //! returns if the meta object inherits the given classname
105 105 bool inherits(const char* name);
106 106
107 107 //! get help string for the metaobject
108 108 QString help();
109 109
110 110 //! get list of all members
111 111 QStringList memberList(bool metaOnly = false);
112 112
113 113 //! get the meta type id of this class (only valid for isCPPWrapper() == true)
114 114 int metaTypeId() { return _metaTypeId; }
115 115
116 116 //! set an additional decorator provider that offers additional decorator slots for this class
117 117 void setDecoratorProvider(PythonQtQObjectCreatorFunctionCB* cb) { _decoratorProviderCB = cb; _decoratorProvider = NULL; }
118 118
119 119 //! get the decorator qobject instance
120 120 QObject* decorator();
121 121
122 122 //! set the parent class name of a wrapped CPP pointer
123 123 void setWrappedParentClassName(const QByteArray& name) { _wrappedParentClassName = name; _parentClassInfo = NULL; _parentClassInfoResolved = false; }
124 124
125 125 //! check if the special method "hasOwner" is implemented and if it returns false, which means that the object may be destroyed
126 126 bool hasOwnerMethodButNoOwner(void* object);
127 127
128 //! set the associated PythonQtClassWrapper (which handles instance creation of this type)
129 void setPythonQtClassWrapper(PyObject* obj) { _pythonQtClassWrapper = obj; }
130
131 //! get the associated PythonQtClassWrapper (which handles instance creation of this type)
132 PyObject* pythonQtClassWrapper() { return _pythonQtClassWrapper; }
133
128 134 private:
129 135 //! resolve the parent class from either meta object or cpp parent class name
130 136 void resolveParentClassInfo();
131 137
132 138 //! clear all cached members
133 139 void clearCachedMembers();
134 140
135 141 PythonQtSlotInfo* findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache);
136 142 void listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly);
137 143
138 144 bool lookForPropertyAndCache(const char* memberName);
139 145 bool lookForMethodAndCache(const char* memberName);
140 146 bool lookForEnumAndCache(const QMetaObject* m, const char* memberName);
141 147
142 148 PythonQtSlotInfo* findDecoratorSlots(const char* classname, const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found);
143 149 int findCharOffset(const char* sigStart, char someChar);
144 150 QHash<QByteArray, PythonQtMemberInfo> _cachedMembers;
145 151 PythonQtSlotInfo* _constructors;
146 152 const QMetaObject* _meta;
147 153 QByteArray _wrappedClassName;
148 154 QByteArray _wrappedParentClassName;
149 155 QObject* _decoratorProvider;
150 156 PythonQtQObjectCreatorFunctionCB* _decoratorProviderCB;
151 157 PythonQtClassInfo* _parentClassInfo;
152 158
159 PyObject* _pythonQtClassWrapper;
160
153 161 bool _parentClassInfoResolved;
154 162 int _metaTypeId;
155 163
156 164 };
157 165
158 166 //---------------------------------------------------------------
159 167
160 168
161 169 #endif
@@ -1,256 +1,229
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 PythonQtClassWrapper.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 "PythonQtClassWrapper.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 static void PythonQtClassWrapper_dealloc(PythonQtClassWrapper* self)
50 static PyObject* PythonQtClassWrapper_alloc(PyTypeObject *self, Py_ssize_t nitems)
51 51 {
52 self->ob_type->tp_free((PyObject*)self);
53 }
52 // call the default type alloc
53 PyObject* obj = PyType_Type.tp_alloc(self, nitems);
54 54
55 static PyObject* PythonQtClassWrapper_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
56 {
57 PythonQtClassWrapper *self;
55 // take current class type, if we are called via newPythonQtClassWrapper()
56 PythonQtClassWrapper* wrap = (PythonQtClassWrapper*)obj;
57 wrap->_classInfo = PythonQt::priv()->currentClassInfoForClassWrapperCreation();
58 58
59 self = (PythonQtClassWrapper *)type->tp_alloc(type, 0);
60 if (self != NULL) {
61 self->_info = NULL;
62 }
63 return (PyObject *)self;
59 return obj;
64 60 }
65 61
66 static int PythonQtClassWrapper_init(PythonQtClassWrapper * /*self*/, PyObject * /*args*/, PyObject * /*kwds*/)
62
63 static int PythonQtClassWrapper_init(PythonQtClassWrapper* self, PyObject* args, PyObject* kwds)
67 64 {
68 return 0;
65 // call the default type init
66 if (PyType_Type.tp_init((PyObject *)self, args, kwds) < 0) {
67 return -1;
69 68 }
70 69
71 PyObject *PythonQtClassWrapper_call(PyObject *func, PyObject *args, PyObject *kw) {
72 PythonQtClassWrapper* wrapper = (PythonQtClassWrapper*)func;
73 PyObject* result = NULL;
74 QString error;
75 PyObject* err = NULL;
76 if (wrapper->_info->constructors()) {
77 result = PythonQtSlotFunction_CallImpl(NULL, wrapper->_info->constructors(), args, kw);
78 err = PyErr_Occurred();
79 }
80 if (!result) {
81 QObject* v = NULL;
82 QListIterator<PythonQtConstructorHandler*> it(PythonQt::self()->constructorHandlers());
83 while (!v && it.hasNext()) {
84 v = it.next()->create(wrapper->_info->metaObject(), args, kw, error);
85 }
86 if (v) {
87 result = PythonQt::priv()->wrapQObject(v);
88 }
89 }
90 if (result) {
91 // change ownershipflag to be owned by PythonQt
92 if (result->ob_type == &PythonQtInstanceWrapper_Type) {
93 ((PythonQtInstanceWrapper*)result)->_ownedByPythonQt = true;
94 }
95 } else {
96 if (!wrapper->_info->constructors()) {
97 if (!err) {
98 if (error.isEmpty()) {
99 error = QString("No constructors available for ") + wrapper->_info->className();
100 }
101 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
102 }
70 // if we have no CPP class information, try our base class
71 if (!self->classInfo()) {
72 PyTypeObject* superType = ((PyTypeObject *)self)->tp_base;
73
74 if (!superType || (superType->ob_type != &PythonQtClassWrapper_Type)) {
75 PyErr_Format(PyExc_TypeError, "type %s is not derived from PythonQtClassWrapper", ((PyTypeObject*)self)->tp_name);
76 return -1;
103 77 }
78
79 // take the class info from the superType
80 self->_classInfo = ((PythonQtClassWrapper*)superType)->classInfo();
104 81 }
105 return result;
82
83 return 0;
106 84 }
107 85
108 86 static PyObject *PythonQtClassWrapper_classname(PythonQtClassWrapper* type)
109 87 {
110 return PyString_FromString((QString("Meta_") + type->_info->className()).toLatin1().data());
88 return PyString_FromString((QString("Class_") + type->classInfo()->className()).toLatin1().data());
111 89 }
112 90
113 91 static PyObject *PythonQtClassWrapper_help(PythonQtClassWrapper* type)
114 92 {
115 return PythonQt::self()->helpCalled(type->_info);
93 return PythonQt::self()->helpCalled(type->classInfo());
116 94 }
117 95
118 96
119 97 static PyMethodDef PythonQtClassWrapper_methods[] = {
120 98 {"className", (PyCFunction)PythonQtClassWrapper_classname, METH_NOARGS,
121 99 "Return the classname of the object"
122 100 },
123 101 {"help", (PyCFunction)PythonQtClassWrapper_help, METH_NOARGS,
124 102 "Shows the help of available methods for this class"
125 103 },
126 104 {NULL, NULL, 0 , NULL} /* Sentinel */
127 105 };
128 106
129 107
130 108 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj,PyObject *name)
131 109 {
132 110 const char *attributeName;
133 111 PythonQtClassWrapper *wrapper = (PythonQtClassWrapper *)obj;
134 112
135 113 if ((attributeName = PyString_AsString(name)) == NULL) {
136 114 return NULL;
137 115 }
138 116
139 PythonQtMemberInfo member = wrapper->_info->member(attributeName);
117 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
140 118 if (member._type == PythonQtMemberInfo::EnumValue) {
141 119 return PyInt_FromLong(member._enumValue);
142 120 }
143 121 if (member._type == PythonQtMemberInfo::Slot && member._slot->isClassDecorator()) {
144 122 return PythonQtSlotFunction_New(member._slot, obj, NULL);
145 123 }
146 124
147 125 // look for the interal methods (className(), help())
148 126 PyObject* internalMethod = Py_FindMethod( PythonQtClassWrapper_methods, obj, (char*)attributeName);
149 127 if (internalMethod) {
150 128 return internalMethod;
151 129 }
152 130 PyErr_Clear();
153 131
154 132 if (qstrcmp(attributeName, "__dict__")==0) {
155 QStringList l = wrapper->_info->memberList(true);
133 QStringList l = wrapper->classInfo()->memberList(true);
156 134 PyObject* dict = PyDict_New();
157 135 foreach (QString name, l) {
158 136 //PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
159 137 PyDict_SetItemString(dict, name.toLatin1().data(), Py_None);
160 138 //Py_DECREF(o);
161 139 }
162 140 return dict;
163 141 }
164 142
165 QString error = QString(wrapper->_info->className()) + " has no attribute named '" + QString(attributeName) + "'";
143 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
166 144 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
167 145 return NULL;
168 146 }
169 147
148 static int PythonQtClassWrapper_setattro(PyObject *obj,PyObject *name,PyObject * /*value*/)
149 {
150 QString error;
151 char *attributeName;
152 if ((attributeName = PyString_AsString(name)) == NULL) {
153 return -1;
154 }
155 PythonQtClassWrapper *wrapper = (PythonQtClassWrapper *)obj;
156
157 // TODO
158 return -1;
159 }
160
161 /*
170 162 static PyObject * PythonQtClassWrapper_repr(PyObject * obj)
171 163 {
172 164 PythonQtClassWrapper* wrapper = (PythonQtClassWrapper*)obj;
173 if (wrapper->_info->isCPPWrapper()) {
174 const QMetaObject* meta = wrapper->_info->metaObject();
165 if (wrapper->classInfo()->isCPPWrapper()) {
166 const QMetaObject* meta = wrapper->classInfo()->metaObject();
175 167 if (!meta) {
176 QObject* decorator = wrapper->_info->decorator();
168 QObject* decorator = wrapper->classInfo()->decorator();
177 169 if (decorator) {
178 170 meta = decorator->metaObject();
179 171 }
180 172 }
181 173 if (meta) {
182 return PyString_FromFormat("%s Class (C++ wrapped by %s)", wrapper->_info->className(), meta->className());
183 } else {
184 return PyString_FromFormat("%s Class (C++ unwrapped)", wrapper->_info->className());
185 }
186 } else {
187 return PyString_FromFormat("%s Class", wrapper->_info->className());
188 }
189 }
190
191 static int PythonQtClassWrapper_compare(PyObject * obj1, PyObject * obj2)
192 {
193 if (obj1->ob_type == &PythonQtClassWrapper_Type &&
194 obj2->ob_type == &PythonQtClassWrapper_Type) {
195
196 PythonQtClassWrapper* w1 = (PythonQtClassWrapper*)obj1;
197 PythonQtClassWrapper* w2 = (PythonQtClassWrapper*)obj2;
198 if (w1->_info == w2->_info) {
199 return 0;
174 return PyString_FromFormat("%s Class (C++ wrapped by %s)", wrapper->classInfo()->className(), meta->className());
200 175 } else {
201 return -1;
176 return PyString_FromFormat("%s Class (C++ unwrapped)", wrapper->classInfo()->className());
202 177 }
203 178 } else {
204 return -1;
179 return PyString_FromFormat("%s Class", wrapper->classInfo()->className());
205 180 }
206 181 }
207 182
208 static long PythonQtClassWrapper_hash(PythonQtClassWrapper *obj)
209 {
210 return reinterpret_cast<long>(obj->_info);
211 }
183 */
212 184
213 185 PyTypeObject PythonQtClassWrapper_Type = {
214 186 PyObject_HEAD_INIT(NULL)
215 187 0, /*ob_size*/
216 188 "PythonQt.PythonQtClassWrapper", /*tp_name*/
217 189 sizeof(PythonQtClassWrapper), /*tp_basicsize*/
218 190 0, /*tp_itemsize*/
219 (destructor)PythonQtClassWrapper_dealloc, /*tp_dealloc*/
191 0, /*tp_dealloc*/
220 192 0, /*tp_print*/
221 193 0, /*tp_getattr*/
222 194 0, /*tp_setattr*/
223 PythonQtClassWrapper_compare, /*tp_compare*/
224 PythonQtClassWrapper_repr, /*tp_repr*/
195 0, /*tp_compare*/
196 0, //PythonQtClassWrapper_repr, /*tp_repr*/
225 197 0, /*tp_as_number*/
226 198 0, /*tp_as_sequence*/
227 199 0, /*tp_as_mapping*/
228 (hashfunc)PythonQtClassWrapper_hash, /*tp_hash */
229 PythonQtClassWrapper_call, /*tp_call*/
200 0, /*tp_hash */
201 0, /*tp_call*/
230 202 0, /*tp_str*/
231 203 PythonQtClassWrapper_getattro, /*tp_getattro*/
232 0, /*tp_setattro*/
204 PythonQtClassWrapper_setattro, /*tp_setattro*/
233 205 0, /*tp_as_buffer*/
234 206 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
235 "PythonQtClassWrapper object", /* tp_doc */
207 0, /* tp_doc */
236 208 0, /* tp_traverse */
237 209 0, /* tp_clear */
238 210 0, /* tp_richcompare */
239 211 0, /* tp_weaklistoffset */
240 212 0, /* tp_iter */
241 213 0, /* tp_iternext */
242 214 0, /* tp_methods */
243 215 0, /* tp_members */
244 216 0, /* tp_getset */
245 217 0, /* tp_base */
246 218 0, /* tp_dict */
247 219 0, /* tp_descr_get */
248 220 0, /* tp_descr_set */
249 221 0, /* tp_dictoffset */
250 222 (initproc)PythonQtClassWrapper_init, /* tp_init */
251 0, /* tp_alloc */
252 PythonQtClassWrapper_new, /* tp_new */
223 PythonQtClassWrapper_alloc, /* tp_alloc */
224 0, /* tp_new */
225 0, /* tp_free */
253 226 };
254 227
255 228 //-------------------------------------------------------
256 229
@@ -1,79 +1,75
1 1 #ifndef _PYTHONQTCLASSWRAPPER_H
2 2 #define _PYTHONQTCLASSWRAPPER_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 PythonQtClassWrapper.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 "structmember.h"
48 48 #include "methodobject.h"
49 49 #include "compile.h"
50 50 #include "eval.h"
51 51 #include <QString>
52 52
53 53 class PythonQtClassInfo;
54 class QObject;
55 struct QMetaObject;
56 54
55 //! the type of the PythonQt class wrapper objects
57 56 extern PyTypeObject PythonQtClassWrapper_Type;
58 57
59 58 //---------------------------------------------------------------
60 //! a Python wrapper object for Qt meta objects
59 //! a Python wrapper object for PythonQt wrapped classes
60 //! which inherits from the Python type object to allow
61 //! deriving of wrapped CPP classes from Python.
61 62 typedef struct {
62 PyObject_HEAD
63 PyHeapTypeObject _base;
63 64
64 //! the class information (which contains the meta object as well)
65 PythonQtClassInfo* _info;
65 //! the additional class information that PythonQt stores for the CPP class
66 PythonQtClassInfo* _classInfo;
67
68 //! get the class info
69 PythonQtClassInfo* classInfo() { return _classInfo; }
66 70
67 71 } PythonQtClassWrapper;
68 72
69 73 //---------------------------------------------------------------
70 // an abstact class for handling construction of objects
71 class PythonQtConstructorHandler {
72 public:
73 //! get rid of warnings
74 virtual ~PythonQtConstructorHandler() {}
75
76 virtual QObject* create(const QMetaObject* meta, PyObject *args, PyObject *kw, QString& error) = 0;
77 };
78 74
79 75 #endif
@@ -1,1076 +1,1076
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtConversion.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtConversion.h"
43 43 #include "PythonQtVariants.h"
44 44 #include <QDateTime>
45 45 #include <QTime>
46 46 #include <QDate>
47 47
48 48 PythonQtValueStorage<qint64, 128> PythonQtConv::global_valueStorage;
49 49 PythonQtValueStorage<void*, 128> PythonQtConv::global_ptrStorage;
50 50 PythonQtValueStorage<QVariant, 32> PythonQtConv::global_variantStorage;
51 51
52 52 QHash<int, PythonQtConvertMetaTypeToPythonCB*> PythonQtConv::_metaTypeToPythonConverters;
53 53 QHash<int, PythonQtConvertPythonToMetaTypeCB*> PythonQtConv::_pythonToMetaTypeConverters;
54 54
55 55 PyObject* PythonQtConv::GetPyBool(bool val)
56 56 {
57 57 PyObject* r = val?Py_True:Py_False;
58 58 Py_INCREF(r);
59 59 return r;
60 60 }
61 61
62 62 PyObject* PythonQtConv::ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data) {
63 63 if (info.typeId == QMetaType::Void) {
64 64 Py_INCREF(Py_None);
65 65 return Py_None;
66 66 } else if (info.isPointer && (info.typeId == QMetaType::Char)) {
67 67 // a char ptr will probably be a null terminated string, so we support that:
68 68 return PyString_FromString(*((char**)data));
69 69 } else if ((info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) &&
70 70 info.name.startsWith("QList<")) {
71 71 // it is a QList template:
72 72 // (TODO: check what happens if this is a pointer type?!)
73 73 QByteArray innerType = info.name.mid(6,info.name.length()-7);
74 74 if (innerType.endsWith("*")) {
75 75 innerType.truncate(innerType.length()-1);
76 76 return ConvertQListOfPointerTypeToPythonList((QList<void*>*)data, innerType);
77 77 }
78 78 }
79 79
80 80 if (info.typeId >= QMetaType::User) {
81 81 // if a converter is registered, we use is:
82 82 PythonQtConvertMetaTypeToPythonCB* converter = _metaTypeToPythonConverters.value(info.typeId);
83 83 if (converter) {
84 84 return (*converter)(data, info.typeId);
85 85 }
86 86 }
87 87
88 88 // special handling did not match, so we convert the usual way (either pointer or value version):
89 89 if (info.isPointer) {
90 90 // convert the pointer to a Python Object (we can handle ANY C++ object, in the worst case we just know the type and the pointer)
91 91 return PythonQt::priv()->wrapPtr(*((void**)data), info.name);
92 92 } else {
93 93 // handle values that are not yet handled and not pointers
94 94 return ConvertQtValueToPythonInternal(info.typeId, data);
95 95 }
96 96 }
97 97
98 98 PyObject* PythonQtConv::ConvertQtValueToPythonInternal(int type, const void* data) {
99 99 switch (type) {
100 100 case QMetaType::Void:
101 101 Py_INCREF(Py_None);
102 102 return Py_None;
103 103 case QMetaType::Char:
104 104 return PyInt_FromLong(*((char*)data));
105 105 case QMetaType::UChar:
106 106 return PyInt_FromLong(*((unsigned char*)data));
107 107 case QMetaType::Short:
108 108 return PyInt_FromLong(*((short*)data));
109 109 case QMetaType::UShort:
110 110 return PyInt_FromLong(*((unsigned short*)data));
111 111 case QMetaType::Long:
112 112 return PyInt_FromLong(*((long*)data));
113 113 case QMetaType::ULong:
114 114 // does not fit into simple int of python
115 115 return PyLong_FromUnsignedLong(*((unsigned long*)data));
116 116 case QMetaType::Bool:
117 117 return PythonQtConv::GetPyBool(*((bool*)data));
118 118 case QMetaType::Int:
119 119 return PyInt_FromLong(*((int*)data));
120 120 case QMetaType::UInt:
121 121 return PyInt_FromLong(*((unsigned int*)data));
122 122 case QMetaType::QChar:
123 123 return PyInt_FromLong(*((short*)data));
124 124 case QMetaType::Float:
125 125 return PyFloat_FromDouble(*((float*)data));
126 126 case QMetaType::Double:
127 127 return PyFloat_FromDouble(*((double*)data));
128 128 case QMetaType::LongLong:
129 129 return PyLong_FromLongLong(*((qint64*)data));
130 130 case QMetaType::ULongLong:
131 131 return PyLong_FromUnsignedLongLong(*((quint64*)data));
132 132 case QMetaType::QByteArray: {
133 133 QByteArray* v = (QByteArray*) data;
134 134 return PyString_FromStringAndSize(*v, v->size());
135 135 }
136 136 case QMetaType::QVariantMap:
137 137 return PythonQtConv::QVariantMapToPyObject(*((QVariantMap*)data));
138 138 case QMetaType::QVariantList:
139 139 return PythonQtConv::QVariantListToPyObject(*((QVariantList*)data));
140 140 case QMetaType::QString:
141 141 return PythonQtConv::QStringToPyObject(*((QString*)data));
142 142 case QMetaType::QStringList:
143 143 return PythonQtConv::QStringListToPyObject(*((QStringList*)data));
144 144
145 145 case PythonQtMethodInfo::Variant:
146 146 return PythonQtConv::QVariantToPyObject(*((QVariant*)data));
147 147 case QMetaType::QObjectStar:
148 148 case QMetaType::QWidgetStar:
149 149 return PythonQt::priv()->wrapQObject(*((QObject**)data));
150 150
151 151 default:
152 152 if (PythonQt::priv()->isPythonQtObjectPtrMetaId(type)) {
153 153 // special case, it is a PythonQtObjectPtr which contains a PyObject, take it directly:
154 154 PyObject* o = ((PythonQtObjectPtr*)data)->object();
155 155 Py_INCREF(o);
156 156 return o;
157 157 } else {
158 158 if (type > 0) {
159 159 // if the type is known, we can construct it via QMetaType::construct
160 160 void* newCPPObject = QMetaType::construct(type, data);
161 161 // XXX this could be optimized by using metatypeid directly
162 162 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)PythonQt::priv()->wrapPtr(newCPPObject, QMetaType::typeName(type));
163 163 wrap->_ownedByPythonQt = true;
164 164 wrap->_useQMetaTypeDestroy = true;
165 165 return (PyObject*)wrap;
166 166 }
167 167 std::cerr << "Unknown type that can not be converted to Python: " << type << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
168 168 }
169 169 }
170 170 Py_INCREF(Py_None);
171 171 return Py_None;
172 172 }
173 173
174 174 void* PythonQtConv::CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info) {
175 175 void* ptr = NULL;
176 176 if (info.isPointer) {
177 177 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
178 178 } else {
179 179 switch (info.typeId) {
180 180 case QMetaType::Char:
181 181 case QMetaType::UChar:
182 182 case QMetaType::Short:
183 183 case QMetaType::UShort:
184 184 case QMetaType::Long:
185 185 case QMetaType::ULong:
186 186 case QMetaType::Bool:
187 187 case QMetaType::Int:
188 188 case QMetaType::UInt:
189 189 case QMetaType::QChar:
190 190 case QMetaType::Float:
191 191 case QMetaType::Double:
192 192 PythonQtValueStorage_ADD_VALUE(global_valueStorage, long, 0, ptr);
193 193 break;
194 194 case PythonQtMethodInfo::Variant:
195 195 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, 0, ptr);
196 196 // return the ptr to the variant
197 197 break;
198 198 default:
199 199 if (info.typeId == PythonQtMethodInfo::Unknown) {
200 200 // check if we have a QList of pointers, which we can circumvent with a QList<void*>
201 201 if (info.name.startsWith("QList<")) {
202 202 QByteArray innerType = info.name.mid(6,info.name.length()-7);
203 203 if (innerType.endsWith("*")) {
204 204 static int id = QMetaType::type("QList<void*>");
205 205 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr);
206 206 // return the constData pointer that will be filled with the result value later on
207 207 ptr = (void*)((QVariant*)ptr)->constData();
208 208 }
209 209 }
210 210 }
211 211
212 212 if (!ptr) {
213 213 // everything else is stored in a QVariant...
214 214 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
215 215 // return the constData pointer that will be filled with the result value later on
216 216 ptr = (void*)((QVariant*)ptr)->constData();
217 217 }
218 218 }
219 219 }
220 220 return ptr;
221 221 }
222 222
223 223 void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, const QMetaObject* meta)
224 224 {
225 225 bool ok;
226 226 void* ptr = NULL;
227 if (obj->ob_type == &PythonQtInstanceWrapper_Type && info.typeId != PythonQtMethodInfo::Variant) {
227 if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) && info.typeId != PythonQtMethodInfo::Variant) {
228 228 // if we have a Qt wrapper object and if we do not need a QVariant, we do the following:
229 229 // (the Variant case is handled below in a switch)
230 230
231 231 // a C++ wrapper (can be passed as pointer or reference)
232 232 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)obj;
233 if (wrap->_info->inherits(info.name)) {
233 if (wrap->classInfo()->inherits(info.name)) {
234 234 void* object;
235 if (wrap->_info->isCPPWrapper()) {
235 if (wrap->classInfo()->isCPPWrapper()) {
236 236 object = wrap->_wrappedPtr;
237 237 } else {
238 238 QObject* tmp = wrap->_obj;
239 239 object = tmp;
240 240 }
241 241 if (info.isPointer) {
242 242 // store the wrapped pointer in an extra pointer and let ptr point to the extra pointer
243 243 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, object, ptr);
244 244 } else {
245 245 // store the wrapped pointer directly, since we are a reference
246 246 ptr = object;
247 247 }
248 248 } else {
249 249 // not matching
250 250 }
251 251 } else if (info.isPointer) {
252 252 // a pointer
253 253 if (info.typeId == QMetaType::Char || info.typeId == QMetaType::UChar)
254 254 {
255 255 QString str = PyObjGetString(obj, strict, ok);
256 256 if (ok) {
257 257 void* ptr2 = NULL;
258 258 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant(str.toUtf8()), ptr2);
259 259 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr);
260 260 }
261 261 } else if (info.name == "PyObject") {
262 262 // handle low level PyObject directly
263 263 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, obj, ptr);
264 264 } else if (obj == Py_None) {
265 265 // None is treated as a NULL ptr
266 266 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
267 267 } else {
268 268 // if we are not strict, we try if we are passed a 0 integer
269 269 if (!strict) {
270 270 bool ok;
271 271 int value = PyObjGetInt(obj, true, ok);
272 272 if (ok && value==0) {
273 273 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
274 274 }
275 275 }
276 276 }
277 277 } else {
278 278 // not a pointer
279 279 switch (info.typeId) {
280 280 case QMetaType::Char:
281 281 {
282 282 int val = PyObjGetInt(obj, strict, ok);
283 283 if (ok) {
284 284 PythonQtValueStorage_ADD_VALUE(global_valueStorage, char, val, ptr);
285 285 }
286 286 }
287 287 break;
288 288 case QMetaType::UChar:
289 289 {
290 290 int val = PyObjGetInt(obj, strict, ok);
291 291 if (ok) {
292 292 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned char, val, ptr);
293 293 }
294 294 }
295 295 break;
296 296 case QMetaType::Short:
297 297 {
298 298 int val = PyObjGetInt(obj, strict, ok);
299 299 if (ok) {
300 300 PythonQtValueStorage_ADD_VALUE(global_valueStorage, short, val, ptr);
301 301 }
302 302 }
303 303 break;
304 304 case QMetaType::UShort:
305 305 {
306 306 int val = PyObjGetInt(obj, strict, ok);
307 307 if (ok) {
308 308 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned short, val, ptr);
309 309 }
310 310 }
311 311 break;
312 312 case QMetaType::Long:
313 313 {
314 314 long val = (long)PyObjGetLongLong(obj, strict, ok);
315 315 if (ok) {
316 316 PythonQtValueStorage_ADD_VALUE(global_valueStorage, long, val, ptr);
317 317 }
318 318 }
319 319 break;
320 320 case QMetaType::ULong:
321 321 {
322 322 unsigned long val = (unsigned long)PyObjGetLongLong(obj, strict, ok);
323 323 if (ok) {
324 324 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned long, val, ptr);
325 325 }
326 326 }
327 327 break;
328 328 case QMetaType::Bool:
329 329 {
330 330 bool val = PyObjGetBool(obj, strict, ok);
331 331 if (ok) {
332 332 PythonQtValueStorage_ADD_VALUE(global_valueStorage, bool, val, ptr);
333 333 }
334 334 }
335 335 break;
336 336 case QMetaType::Int:
337 337 {
338 338 int val = PyObjGetInt(obj, strict, ok);
339 339 if (ok) {
340 340 PythonQtValueStorage_ADD_VALUE(global_valueStorage, int, val, ptr);
341 341 }
342 342 }
343 343 break;
344 344 case QMetaType::UInt:
345 345 {
346 346 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
347 347 if (ok) {
348 348 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned int, val, ptr);
349 349 }
350 350 }
351 351 break;
352 352 case QMetaType::QChar:
353 353 {
354 354 int val = PyObjGetInt(obj, strict, ok);
355 355 if (ok) {
356 356 PythonQtValueStorage_ADD_VALUE(global_valueStorage, short, val, ptr);
357 357 }
358 358 }
359 359 break;
360 360 case QMetaType::Float:
361 361 {
362 362 float val = (float)PyObjGetDouble(obj, strict, ok);
363 363 if (ok) {
364 364 PythonQtValueStorage_ADD_VALUE(global_valueStorage, float, val, ptr);
365 365 }
366 366 }
367 367 break;
368 368 case QMetaType::Double:
369 369 {
370 370 double val = (double)PyObjGetDouble(obj, strict, ok);
371 371 if (ok) {
372 372 PythonQtValueStorage_ADD_VALUE(global_valueStorage, double, val, ptr);
373 373 }
374 374 }
375 375 break;
376 376 case QMetaType::LongLong:
377 377 {
378 378 qint64 val = PyObjGetLongLong(obj, strict, ok);
379 379 if (ok) {
380 380 PythonQtValueStorage_ADD_VALUE(global_valueStorage, qint64, val, ptr);
381 381 }
382 382 }
383 383 break;
384 384 case QMetaType::ULongLong:
385 385 {
386 386 quint64 val = PyObjGetULongLong(obj, strict, ok);
387 387 if (ok) {
388 388 PythonQtValueStorage_ADD_VALUE(global_valueStorage, quint64, val, ptr);
389 389 }
390 390 }
391 391 break;
392 392 case QMetaType::QByteArray:
393 393 {
394 394 QByteArray bytes = PyObjGetBytes(obj, strict, ok);
395 395 if (ok) {
396 396 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant(bytes), ptr);
397 397 ptr = (void*)((QVariant*)ptr)->constData();
398 398 }
399 399 }
400 400 break;
401 401 case QMetaType::QString:
402 402 {
403 403 QString str = PyObjGetString(obj, strict, ok);
404 404 if (ok) {
405 405 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant(str), ptr);
406 406 ptr = (void*)((QVariant*)ptr)->constData();
407 407 }
408 408 }
409 409 break;
410 410 case QMetaType::QStringList:
411 411 {
412 412 QStringList l = PyObjToStringList(obj, strict, ok);
413 413 if (ok) {
414 414 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant(l), ptr);
415 415 ptr = (void*)((QVariant*)ptr)->constData();
416 416 }
417 417 }
418 418 break;
419 419
420 420 case PythonQtMethodInfo::Variant:
421 421 {
422 422 QVariant v = PyObjToQVariant(obj);
423 423 if (v.isValid()) {
424 424 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, v, ptr);
425 425 }
426 426 }
427 427 break;
428 428 default:
429 429 {
430 430 if (info.typeId == PythonQtMethodInfo::Unknown) {
431 431 // check for enum case
432 432 if (PythonQt::priv()->isEnumType(meta, info.name)) {
433 433 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
434 434 if (ok) {
435 435 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned int, val, ptr);
436 436 return ptr;
437 437 } else {
438 438 return NULL;
439 439 }
440 440 }
441 441 }
442 442 if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
443 443 // check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant
444 444 if (info.name.startsWith("QList<")) {
445 445 QByteArray innerType = info.name.mid(6,info.name.length()-7);
446 446 if (innerType.endsWith("*")) {
447 447 innerType.truncate(innerType.length()-1);
448 448 static int id = QMetaType::type("QList<void*>");
449 449 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr);
450 450 ptr = (void*)((QVariant*)ptr)->constData();
451 451 ok = ConvertPythonListToQListOfPointerType(obj, (QList<void*>*)ptr, innerType, strict);
452 452 if (ok) {
453 453 return ptr;
454 454 } else {
455 455 return NULL;
456 456 }
457 457 }
458 458 }
459 459 }
460 460
461 461 // We only do this for registered type > QMetaType::User for performance reasons.
462 462 if (info.typeId >= QMetaType::User) {
463 463 // Maybe we have a special converter that is registered for that type:
464 464 PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(info.typeId);
465 465 if (converter) {
466 466 // create a new empty variant of concrete type:
467 467 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
468 468 ptr = (void*)((QVariant*)ptr)->constData();
469 469 // now call the converter, passing the internal object of the variant
470 470 ok = (*converter)(obj, ptr, info.typeId, strict);
471 471 if (ok) {
472 472 return ptr;
473 473 } else {
474 474 return NULL;
475 475 }
476 476 }
477 477 }
478 478
479 479 // for all other types, we use the same qvariant conversion and pass out the constData of the variant:
480 480 QVariant v = PyObjToQVariant(obj, info.typeId);
481 481 if (v.isValid()) {
482 482 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, v, ptr);
483 483 ptr = (void*)((QVariant*)ptr)->constData();
484 484 }
485 485 }
486 486 }
487 487 }
488 488 return ptr;
489 489 }
490 490
491 491
492 492 QStringList PythonQtConv::PyObjToStringList(PyObject* val, bool strict, bool& ok) {
493 493 QStringList v;
494 494 ok = false;
495 495 // if we are strict, we do not want to convert a string to a stringlist
496 496 // (strings in python are detected to be sequences)
497 497 if (strict &&
498 498 (val->ob_type == &PyString_Type ||
499 499 PyUnicode_Check(val))) {
500 500 ok = false;
501 501 return v;
502 502 }
503 503 if (PySequence_Check(val)) {
504 504 int count = PySequence_Size(val);
505 505 for (int i = 0;i<count;i++) {
506 506 PyObject* value = PySequence_GetItem(val,i);
507 507 v.append(PyObjGetString(value,false,ok));
508 508 }
509 509 ok = true;
510 510 }
511 511 return v;
512 512 }
513 513
514 514 QString PythonQtConv::PyObjGetRepresentation(PyObject* val)
515 515 {
516 516 QString r;
517 517 PyObject* str = PyObject_Repr(val);
518 518 if (str) {
519 519 r = QString(PyString_AS_STRING(str));
520 520 Py_DECREF(str);
521 521 }
522 522 return r;
523 523 }
524 524
525 525 QString PythonQtConv::PyObjGetString(PyObject* val, bool strict, bool& ok) {
526 526 QString r;
527 527 ok = true;
528 528 if (val->ob_type == &PyString_Type) {
529 529 r = QString(PyString_AS_STRING(val));
530 530 } else if (PyUnicode_Check(val)) {
531 531 #ifdef WIN32
532 532 r = QString::fromUtf16(PyUnicode_AS_UNICODE(val));
533 533 #else
534 534 PyObject *ptmp = PyUnicode_AsUTF8String(val);
535 535 if(ptmp) {
536 536 r = QString::fromUtf8(PyString_AS_STRING(ptmp));
537 537 Py_DECREF(ptmp);
538 538 }
539 539 #endif
540 540 } else if (!strict) {
541 541 // EXTRA: could also use _Unicode, but why should we?
542 542 PyObject* str = PyObject_Str(val);
543 543 if (str) {
544 544 r = QString(PyString_AS_STRING(str));
545 545 Py_DECREF(str);
546 546 } else {
547 547 ok = false;
548 548 }
549 549 } else {
550 550 ok = false;
551 551 }
552 552 return r;
553 553 }
554 554
555 555 QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) {
556 556 QByteArray r;
557 557 ok = true;
558 558 if (val->ob_type == &PyString_Type) {
559 559 long size = PyString_GET_SIZE(val);
560 560 r = QByteArray(PyString_AS_STRING(val), size);
561 561 } else {
562 562 ok = false;
563 563 }
564 564 return r;
565 565 }
566 566
567 567 bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) {
568 568 bool d = false;
569 569 ok = false;
570 570 if (val == Py_False) {
571 571 d = false;
572 572 ok = true;
573 573 } else if (val == Py_True) {
574 574 d = true;
575 575 ok = true;
576 576 } else if (!strict) {
577 577 d = PyObjGetInt(val, false, ok)!=0;
578 578 ok = true;
579 579 }
580 580 return d;
581 581 }
582 582
583 583 int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) {
584 584 int d = 0;
585 585 ok = true;
586 586 if (val->ob_type == &PyInt_Type) {
587 587 d = PyInt_AS_LONG(val);
588 588 } else if (!strict) {
589 589 if (val->ob_type == &PyFloat_Type) {
590 590 d = floor(PyFloat_AS_DOUBLE(val));
591 591 } else if (val->ob_type == &PyLong_Type) {
592 592 // handle error on overflow!
593 593 d = PyLong_AsLong(val);
594 594 } else if (val == Py_False) {
595 595 d = 0;
596 596 } else if (val == Py_True) {
597 597 d = 1;
598 598 } else {
599 599 ok = false;
600 600 }
601 601 } else {
602 602 ok = false;
603 603 }
604 604 return d;
605 605 }
606 606
607 607 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
608 608 qint64 d = 0;
609 609 ok = true;
610 610 if (val->ob_type == &PyInt_Type) {
611 611 d = PyInt_AS_LONG(val);
612 612 } else if (val->ob_type == &PyLong_Type) {
613 613 d = PyLong_AsLongLong(val);
614 614 } else if (!strict) {
615 615 if (val->ob_type == &PyFloat_Type) {
616 616 d = floor(PyFloat_AS_DOUBLE(val));
617 617 } else if (val == Py_False) {
618 618 d = 0;
619 619 } else if (val == Py_True) {
620 620 d = 1;
621 621 } else {
622 622 ok = false;
623 623 }
624 624 } else {
625 625 ok = false;
626 626 }
627 627 return d;
628 628 }
629 629
630 630 quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) {
631 631 quint64 d = 0;
632 632 ok = true;
633 633 if (val->ob_type == &PyInt_Type) {
634 634 d = PyInt_AS_LONG(val);
635 635 } else if (val->ob_type == &PyLong_Type) {
636 636 d = PyLong_AsLongLong(val);
637 637 } else if (!strict) {
638 638 if (val->ob_type == &PyFloat_Type) {
639 639 d = floor(PyFloat_AS_DOUBLE(val));
640 640 } else if (val == Py_False) {
641 641 d = 0;
642 642 } else if (val == Py_True) {
643 643 d = 1;
644 644 } else {
645 645 ok = false;
646 646 }
647 647 } else {
648 648 ok = false;
649 649 }
650 650 return d;
651 651 }
652 652
653 653 double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) {
654 654 double d = 0;
655 655 ok = true;
656 656 if (val->ob_type == &PyFloat_Type) {
657 657 d = PyFloat_AS_DOUBLE(val);
658 658 } else if (!strict) {
659 659 if (val->ob_type == &PyInt_Type) {
660 660 d = PyInt_AS_LONG(val);
661 661 } else if (val->ob_type == &PyLong_Type) {
662 662 d = PyLong_AsLong(val);
663 663 } else if (val == Py_False) {
664 664 d = 0;
665 665 } else if (val == Py_True) {
666 666 d = 1;
667 667 } else {
668 668 ok = false;
669 669 }
670 670 } else {
671 671 ok = false;
672 672 }
673 673 return d;
674 674 }
675 675
676 676 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
677 677 {
678 678 QVariant v;
679 679 bool ok = true;
680 680
681 681 if (type==-1) {
682 682 // no special type requested
683 683 if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) {
684 684 type = QVariant::String;
685 685 } else if (val->ob_type==&PyInt_Type) {
686 686 type = QVariant::Int;
687 687 } else if (val->ob_type==&PyLong_Type) {
688 688 type = QVariant::LongLong;
689 689 } else if (val->ob_type==&PyFloat_Type) {
690 690 type = QVariant::Double;
691 691 } else if (val == Py_False || val == Py_True) {
692 692 type = QVariant::Bool;
693 } else if (val->ob_type == &PythonQtInstanceWrapper_Type) {
693 } else if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
694 694 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
695 695 // c++ wrapper, check if the class names of the c++ objects match
696 if (wrap->_info->isCPPWrapper()) {
697 if (wrap->_info->metaTypeId()>0) {
696 if (wrap->classInfo()->isCPPWrapper()) {
697 if (wrap->classInfo()->metaTypeId()>0) {
698 698 // construct a new variant from the C++ object if it has a meta type
699 v = QVariant(wrap->_info->metaTypeId(), wrap->_wrappedPtr);
699 v = QVariant(wrap->classInfo()->metaTypeId(), wrap->_wrappedPtr);
700 700 } else {
701 701 // is this worth anything? we loose the knowledge of the cpp object type
702 702 v = qVariantFromValue(wrap->_wrappedPtr);
703 703 }
704 704 } else {
705 705 // this gives us a QObject pointer
706 706 QObject* myObject = wrap->_obj;
707 707 v = qVariantFromValue(myObject);
708 708 }
709 709 return v;
710 710 } else if (val->ob_type==&PyDict_Type) {
711 711 type = QVariant::Map;
712 712 } else if (val->ob_type==&PyList_Type || val->ob_type==&PyTuple_Type || PySequence_Check(val)) {
713 713 type = QVariant::List;
714 714 } else if (val == Py_None) {
715 715 // none is invalid
716 716 type = QVariant::Invalid;
717 717 } else {
718 718 // this used to be:
719 719 // type = QVariant::String;
720 720 // but now we want to transport the Python Objects directly:
721 721 PythonQtObjectPtr o(val);
722 722 v = qVariantFromValue(o);
723 723 return v;
724 724 }
725 725 }
726 726 // special type request:
727 727 switch (type) {
728 728 case QVariant::Invalid:
729 729 return v;
730 730 break;
731 731 case QVariant::Int:
732 732 {
733 733 int d = PyObjGetInt(val, false, ok);
734 734 if (ok) return QVariant(d);
735 735 }
736 736 break;
737 737 case QVariant::UInt:
738 738 {
739 739 int d = PyObjGetInt(val, false,ok);
740 740 if (ok) v = QVariant((unsigned int)d);
741 741 }
742 742 break;
743 743 case QVariant::Bool:
744 744 {
745 745 int d = PyObjGetBool(val,false,ok);
746 746 if (ok) v = QVariant((bool)(d!=0));
747 747 }
748 748 break;
749 749 case QVariant::Double:
750 750 {
751 751 double d = PyObjGetDouble(val,false,ok);
752 752 if (ok) v = QVariant(d);
753 753 break;
754 754 }
755 755 case QMetaType::Float:
756 756 {
757 757 float d = (float) PyObjGetDouble(val,false,ok);
758 758 if (ok) v = qVariantFromValue(d);
759 759 break;
760 760 }
761 761 case QMetaType::Long:
762 762 {
763 763 long d = (long) PyObjGetLongLong(val,false,ok);
764 764 if (ok) v = qVariantFromValue(d);
765 765 break;
766 766 }
767 767 case QMetaType::ULong:
768 768 {
769 769 unsigned long d = (unsigned long) PyObjGetLongLong(val,false,ok);
770 770 if (ok) v = qVariantFromValue(d);
771 771 break;
772 772 }
773 773 case QMetaType::Short:
774 774 {
775 775 short d = (short) PyObjGetInt(val,false,ok);
776 776 if (ok) v = qVariantFromValue(d);
777 777 break;
778 778 }
779 779 case QMetaType::UShort:
780 780 {
781 781 unsigned short d = (unsigned short) PyObjGetInt(val,false,ok);
782 782 if (ok) v = qVariantFromValue(d);
783 783 break;
784 784 }
785 785 case QMetaType::Char:
786 786 {
787 787 char d = (char) PyObjGetInt(val,false,ok);
788 788 if (ok) v = qVariantFromValue(d);
789 789 break;
790 790 }
791 791 case QMetaType::UChar:
792 792 {
793 793 unsigned char d = (unsigned char) PyObjGetInt(val,false,ok);
794 794 if (ok) v = qVariantFromValue(d);
795 795 break;
796 796 }
797 797
798 798 case QVariant::ByteArray:
799 799 case QVariant::String:
800 800 {
801 801 bool ok;
802 802 v = QVariant(PyObjGetString(val, false, ok));
803 803 }
804 804 break;
805 805
806 806 // these are important for MeVisLab
807 807 case QVariant::Map:
808 808 {
809 809 if (PyMapping_Check(val)) {
810 810 QMap<QString,QVariant> map;
811 811 PyObject* items = PyMapping_Items(val);
812 812 if (items) {
813 813 int count = PyList_Size(items);
814 814 PyObject* value;
815 815 PyObject* key;
816 816 PyObject* tuple;
817 817 for (int i = 0;i<count;i++) {
818 818 tuple = PyList_GetItem(items,i);
819 819 key = PyTuple_GetItem(tuple, 0);
820 820 value = PyTuple_GetItem(tuple, 1);
821 821 map.insert(PyObjGetString(key), PyObjToQVariant(value,-1));
822 822 }
823 823 Py_DECREF(items);
824 824 v = map;
825 825 }
826 826 }
827 827 }
828 828 break;
829 829 case QVariant::List:
830 830 if (PySequence_Check(val)) {
831 831 QVariantList list;
832 832 int count = PySequence_Size(val);
833 833 PyObject* value;
834 834 for (int i = 0;i<count;i++) {
835 835 value = PySequence_GetItem(val,i);
836 836 list.append(PyObjToQVariant(value, -1));
837 837 }
838 838 v = list;
839 839 }
840 840 break;
841 841 case QVariant::StringList:
842 842 {
843 843 bool ok;
844 844 QStringList l = PyObjToStringList(val, false, ok);
845 845 if (ok) {
846 846 v = l;
847 847 }
848 848 }
849 849 break;
850 850
851 851 default:
852 if (val->ob_type == &PythonQtInstanceWrapper_Type) {
852 if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
853 853 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
854 if (wrap->_info->isCPPWrapper() && wrap->_info->metaTypeId() == type) {
854 if (wrap->classInfo()->isCPPWrapper() && wrap->classInfo()->metaTypeId() == type) {
855 855 // construct a new variant from the C++ object if it has the same meta type
856 856 v = QVariant(type, wrap->_wrappedPtr);
857 857 } else {
858 858 v = QVariant();
859 859 }
860 860 } else {
861 861 v = QVariant();
862 862 }
863 863 }
864 864 return v;
865 865 }
866 866
867 867 PyObject* PythonQtConv::QStringToPyObject(const QString& str)
868 868 {
869 869 if (str.isNull()) {
870 870 return PyString_FromString("");
871 871 } else {
872 872 #ifdef WIN32
873 873 // return PyString_FromString(str.toLatin1().data());
874 874 return PyUnicode_FromUnicode(str.utf16(), str.length());
875 875 #else
876 876 return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, NULL, NULL);
877 877 #endif
878 878 }
879 879 }
880 880
881 881 PyObject* PythonQtConv::QStringListToPyObject(const QStringList& list)
882 882 {
883 883 PyObject* result = PyTuple_New(list.count());
884 884 int i = 0;
885 885 QString str;
886 886 foreach (str, list) {
887 887 PyTuple_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(str));
888 888 i++;
889 889 }
890 890 // why is the error state bad after this?
891 891 PyErr_Clear();
892 892 return result;
893 893 }
894 894
895 895 PyObject* PythonQtConv::QStringListToPyList(const QStringList& list)
896 896 {
897 897 PyObject* result = PyList_New(list.count());
898 898 int i = 0;
899 899 for (QStringList::ConstIterator it = list.begin(); it!=list.end(); ++it) {
900 900 PyList_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(*it));
901 901 i++;
902 902 }
903 903 return result;
904 904 }
905 905
906 906 PyObject* PythonQtConv::QVariantToPyObject(const QVariant& v)
907 907 {
908 908 return ConvertQtValueToPythonInternal(v.userType(), (void*)v.constData());
909 909 }
910 910
911 911 PyObject* PythonQtConv::QVariantMapToPyObject(const QVariantMap& m) {
912 912 PyObject* result = PyDict_New();
913 913 QVariantMap::const_iterator t = m.constBegin();
914 914 PyObject* key;
915 915 PyObject* val;
916 916 for (;t!=m.end();t++) {
917 917 key = QStringToPyObject(t.key());
918 918 val = QVariantToPyObject(t.value());
919 919 PyDict_SetItem(result, key, val);
920 920 Py_DECREF(key);
921 921 Py_DECREF(val);
922 922 }
923 923 return result;
924 924 }
925 925
926 926 PyObject* PythonQtConv::QVariantListToPyObject(const QVariantList& l) {
927 927 PyObject* result = PyTuple_New(l.count());
928 928 int i = 0;
929 929 QVariant v;
930 930 foreach (v, l) {
931 931 PyTuple_SET_ITEM(result, i, PythonQtConv::QVariantToPyObject(v));
932 932 i++;
933 933 }
934 934 // why is the error state bad after this?
935 935 PyErr_Clear();
936 936 return result;
937 937 }
938 938
939 939 PyObject* PythonQtConv::ConvertQListOfPointerTypeToPythonList(QList<void*>* list, const QByteArray& typeName)
940 940 {
941 941 PyObject* result = PyTuple_New(list->count());
942 942 int i = 0;
943 943 foreach (void* value, *list) {
944 944 PyTuple_SET_ITEM(result, i, PythonQt::priv()->wrapPtr(value, typeName));
945 945 i++;
946 946 }
947 947 return result;
948 948 }
949 949
950 950 bool PythonQtConv::ConvertPythonListToQListOfPointerType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool /*strict*/)
951 951 {
952 952 bool result = false;
953 953 if (PySequence_Check(obj)) {
954 954 result = true;
955 955 int count = PySequence_Size(obj);
956 956 PyObject* value;
957 957 for (int i = 0;i<count;i++) {
958 958 value = PySequence_GetItem(obj,i);
959 if (value->ob_type == &PythonQtInstanceWrapper_Type) {
959 if (PyObject_TypeCheck(value, &PythonQtInstanceWrapper_Type)) {
960 960 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)value;
961 961 // both QObjects and CPP wrappers support inherits, so we use that to check of we match
962 if (wrap->_info->inherits(type)) {
963 if (wrap->_info->isCPPWrapper()) {
962 if (wrap->classInfo()->inherits(type)) {
963 if (wrap->classInfo()->isCPPWrapper()) {
964 964 list->append(wrap->_wrappedPtr);
965 965 } else {
966 966 QObject* myObject = wrap->_obj;
967 967 list->append((void*)myObject);
968 968 }
969 969 } else {
970 970 result = false;
971 971 break;
972 972 }
973 973 }
974 974 }
975 975 }
976 976 return result;
977 977 }
978 978
979 979 int PythonQtConv::getInnerTemplateMetaType(const QByteArray& typeName)
980 980 {
981 981 int idx = typeName.indexOf("<");
982 982 if (idx>0) {
983 983 int idx2 = typeName.indexOf(">");
984 984 if (idx2>0) {
985 985 QByteArray innerType = typeName.mid(idx+1,idx2-idx-1);
986 986 return QMetaType::type(innerType.constData());
987 987 }
988 988 }
989 989 return QMetaType::Void;
990 990 }
991 991
992 992
993 993
994 994 QString PythonQtConv::qVariantToString(const QVariant& v) {
995 995 return CPPObjectToString(v.userType(), v.constData());
996 996 }
997 997
998 998 QString PythonQtConv::CPPObjectToString(int type, const void* data) {
999 999 QString r;
1000 1000 switch (type) {
1001 1001 case QVariant::Size: {
1002 1002 const QSize* s = static_cast<const QSize*>(data);
1003 1003 r = QString::number(s->width()) + ", " + QString::number(s->height());
1004 1004 }
1005 1005 break;
1006 1006 case QVariant::SizeF: {
1007 1007 const QSizeF* s = static_cast<const QSizeF*>(data);
1008 1008 r = QString::number(s->width()) + ", " + QString::number(s->height());
1009 1009 }
1010 1010 break;
1011 1011 case QVariant::Point: {
1012 1012 const QPoint* s = static_cast<const QPoint*>(data);
1013 1013 r = QString::number(s->x()) + ", " + QString::number(s->y());
1014 1014 }
1015 1015 break;
1016 1016 case QVariant::PointF: {
1017 1017 const QPointF* s = static_cast<const QPointF*>(data);
1018 1018 r = QString::number(s->x()) + ", " + QString::number(s->y());
1019 1019 }
1020 1020 break;
1021 1021 case QVariant::Rect: {
1022 1022 const QRect* s = static_cast<const QRect*>(data);
1023 1023 r = QString::number(s->x()) + ", " + QString::number(s->y());
1024 1024 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1025 1025 }
1026 1026 break;
1027 1027 case QVariant::RectF: {
1028 1028 const QRectF* s = static_cast<const QRectF*>(data);
1029 1029 r = QString::number(s->x()) + ", " + QString::number(s->y());
1030 1030 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1031 1031 }
1032 1032 break;
1033 1033 case QVariant::Date: {
1034 1034 const QDate* s = static_cast<const QDate*>(data);
1035 1035 r = s->toString(Qt::ISODate);
1036 1036 }
1037 1037 break;
1038 1038 case QVariant::DateTime: {
1039 1039 const QDateTime* s = static_cast<const QDateTime*>(data);
1040 1040 r = s->toString(Qt::ISODate);
1041 1041 }
1042 1042 break;
1043 1043 case QVariant::Time: {
1044 1044 const QTime* s = static_cast<const QTime*>(data);
1045 1045 r = s->toString(Qt::ISODate);
1046 1046 }
1047 1047 break;
1048 1048 case QVariant::Pixmap:
1049 1049 {
1050 1050 const QPixmap* s = static_cast<const QPixmap*>(data);
1051 1051 r = QString("Pixmap ") + QString::number(s->width()) + ", " + QString::number(s->height());
1052 1052 }
1053 1053 break;
1054 1054 case QVariant::Image:
1055 1055 {
1056 1056 const QImage* s = static_cast<const QImage*>(data);
1057 1057 r = QString("Image ") + QString::number(s->width()) + ", " + QString::number(s->height());
1058 1058 }
1059 1059 break;
1060 1060 case QVariant::Url:
1061 1061 {
1062 1062 const QUrl* s = static_cast<const QUrl*>(data);
1063 1063 r = s->toString();
1064 1064 }
1065 1065 break;
1066 1066 //TODO: add more printing for other variant types
1067 1067 default:
1068 1068 // this creates a copy, but that should not be expensive for typical simple variants
1069 1069 // (but we do not want to do this for our won user types!
1070 1070 if (type>0 && type < (int)QVariant::UserType) {
1071 1071 QVariant v(type, data);
1072 1072 r = v.toString();
1073 1073 }
1074 1074 }
1075 1075 return r;
1076 1076 }
@@ -1,485 +1,529
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 PythonQtInstanceWrapper.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 "PythonQtInstanceWrapper.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 #include "PythonQtClassWrapper.h"
49
50 PythonQtClassInfo* PythonQtInstanceWrapper::classInfo()
51 {
52 // take the class info from our type object
53 return ((PythonQtClassWrapper*)ob_type)->_classInfo;
54 }
48 55
49 56 static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, bool force = false) {
50 57
51 58 // is this a C++ wrapper?
52 59 if (self->_wrappedPtr) {
53 //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->_info->wrappedClassName().latin1());
60 //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
54 61
55 62 PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr);
56 63 // we own our qobject, so we delete it now:
57 64 delete self->_obj;
58 65 self->_obj = NULL;
59 if (force || self->_info->hasOwnerMethodButNoOwner(self->_wrappedPtr) || self->_ownedByPythonQt) {
60 int type = self->_info->metaTypeId();
66 if (force || self->classInfo()->hasOwnerMethodButNoOwner(self->_wrappedPtr) || self->_ownedByPythonQt) {
67 int type = self->classInfo()->metaTypeId();
61 68 if (self->_useQMetaTypeDestroy && type>=0) {
62 69 // use QMetaType to destroy the object
63 70 QMetaType::destroy(type, self->_wrappedPtr);
64 71 } else {
65 PythonQtSlotInfo* slot = PythonQt::priv()->getDestructorSlot(self->_info->className());
72 PythonQtSlotInfo* slot = PythonQt::priv()->getDestructorSlot(self->classInfo()->className());
66 73 if (slot) {
67 74 void* args[2];
68 75 args[0] = NULL;
69 76 args[1] = &self->_wrappedPtr;
70 77 slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, slot->slotIndex(), args);
71 78 self->_wrappedPtr = NULL;
72 79 } else {
73 80 if (type>=0) {
74 81 // use QMetaType to destroy the object
75 82 QMetaType::destroy(type, self->_wrappedPtr);
76 83 } else {
77 84 // TODO: warn about not being able to destroy the object?
78 85 }
79 86 }
80 87 }
81 88 }
82 89 } else {
83 //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->_info->wrappedClassName().latin1());
90 //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
84 91 if (self->_objPointerCopy) {
85 92 PythonQt::priv()->removeWrapperPointer(self->_objPointerCopy);
86 93 }
87 94 if (self->_obj) {
88 95 if (force || self->_ownedByPythonQt) {
89 96 if (force || !self->_obj->parent()) {
90 97 delete self->_obj;
91 98 }
92 99 } else {
93 100 if (self->_obj->parent()==NULL) {
94 101 // tell someone who is interested that the qobject is no longer wrapped, if it has no parent
95 102 PythonQt::qObjectNoLongerWrappedCB(self->_obj);
96 103 }
97 104 }
98 105 }
99 106 }
100 107 self->_obj = NULL;
101 108 }
102 109
103 110 static void PythonQtInstanceWrapper_dealloc(PythonQtInstanceWrapper* self)
104 111 {
105 112 PythonQtInstanceWrapper_deleteObject(self);
106 113 self->_obj.~QPointer<QObject>();
107 114 self->ob_type->tp_free((PyObject*)self);
108 115 }
109 116
110 static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
117 static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * args, PyObject * /*kwds*/)
111 118 {
119 PythonQtClassWrapper *classType = (PythonQtClassWrapper*)type;
112 120 PythonQtInstanceWrapper *self;
121 static PyObject* emptyTuple = NULL;
122 if (emptyTuple==NULL) {
123 emptyTuple = PyTuple_New(0);
124 }
125
126 self = (PythonQtInstanceWrapper*)PyBaseObject_Type.tp_new(type, emptyTuple, NULL);
113 127
114 self = (PythonQtInstanceWrapper *)type->tp_alloc(type, 0);
115 128 if (self != NULL) {
116 self->_info = NULL;
117 129 new (&self->_obj) QPointer<QObject>();
118 130 self->_wrappedPtr = NULL;
119 131 self->_ownedByPythonQt = false;
120 132 self->_useQMetaTypeDestroy = false;
121 133 }
122 134 return (PyObject *)self;
123 135 }
124 136
125 static int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * /*self*/, PyObject * /*args*/, PyObject * /*kwds*/)
137 static int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds)
126 138 {
139 PyObject* result = NULL;
140
141 if (args == PythonQtPrivate::dummyTuple()) {
142 // we are called from the internal PythonQt API, so our data will be filled later on...
143 return 0;
144 }
145
146 // we are called from python, try to construct our object
147 if (self->classInfo()->constructors()) {
148 void* directCPPPointer = NULL;
149 PythonQtSlotFunction_CallImpl(NULL, self->classInfo()->constructors(), args, kwds, NULL, &directCPPPointer);
150 if (PyErr_Occurred()) {
151 return -1;
152 }
153 if (directCPPPointer) {
154 // change ownershipflag to be owned by PythonQt
155 self->_ownedByPythonQt = true;
156 self->_useQMetaTypeDestroy = false;
157 if (self->classInfo()->isCPPWrapper()) {
158 self->_wrappedPtr = directCPPPointer;
159 // TODO xxx: if there is a wrapper factory, we might want to generate a wrapper for our class?!
160 } else {
161 self->setQObject((QObject*)directCPPPointer);
162 }
163 // register with PythonQt
164 PythonQt::priv()->addWrapperPointer(directCPPPointer, self);
165 }
166 } else {
167 QString error = QString("No constructors available for ") + self->classInfo()->className();
168 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
169 return -1;
170 }
127 171 return 0;
128 172 }
129 173
130 174 static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* type)
131 175 {
132 return PyString_FromString(type->_info->className());
176 return PyString_FromString(type->classInfo()->className());
133 177 }
134 178
135 179 static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* type)
136 180 {
137 return PythonQt::self()->helpCalled(type->_info);
181 return PythonQt::self()->helpCalled(type->classInfo());
138 182 }
139 183
140 184 static PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self)
141 185 {
142 186 PythonQtInstanceWrapper_deleteObject(self, true);
143 187 Py_INCREF(Py_None);
144 188 return Py_None;
145 189 }
146 190
147 191
148 192 static PyMethodDef PythonQtInstanceWrapper_methods[] = {
149 193 {"className", (PyCFunction)PythonQtInstanceWrapper_classname, METH_NOARGS,
150 194 "Return the classname of the object"
151 195 },
152 196 {"help", (PyCFunction)PythonQtInstanceWrapper_help, METH_NOARGS,
153 197 "Shows the help of available methods for this class"
154 198 },
155 199 {"delete", (PyCFunction)PythonQtInstanceWrapper_delete, METH_NOARGS,
156 200 "Deletes the C++ object (at your own risk, my friend!)"
157 201 },
158 202 {NULL, NULL, 0, NULL} /* Sentinel */
159 203 };
160 204
161 205
162 206 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
163 207 {
164 208 const char *attributeName;
165 209 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
166 210
167 211 if ((attributeName = PyString_AsString(name)) == NULL) {
168 212 return NULL;
169 213 }
170 214
171 215 if (!wrapper->_obj && !wrapper->_wrappedPtr) {
172 QString error = QString("Trying to read attribute '") + attributeName + "' from a destroyed " + wrapper->_info->className() + " object";
216 QString error = QString("Trying to read attribute '") + attributeName + "' from a destroyed " + wrapper->classInfo()->className() + " object";
173 217 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
174 218 return NULL;
175 219 }
176 220
177 221 // mlabDebugConst("Python","get " << attributeName);
178 222
179 223 // TODO: dynamic properties are missing
180 224
181 PythonQtMemberInfo member = wrapper->_info->member(attributeName);
225 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
182 226 switch (member._type) {
183 227 case PythonQtMemberInfo::Property:
184 228 if (wrapper->_obj) {
185 229 return PythonQtConv::QVariantToPyObject(member._property.read(wrapper->_obj));
186 230 }
187 231 break;
188 232 case PythonQtMemberInfo::Slot:
189 233 return PythonQtSlotFunction_New(member._slot, obj, NULL);
190 234 break;
191 235 case PythonQtMemberInfo::EnumValue:
192 236 return PyInt_FromLong(member._enumValue);
193 237 break;
194 238 default:
195 239 // is an invalid type, go on
196 240 break;
197 241 }
198 242
199 243 // look for the interal methods (className(), help())
200 244 PyObject* internalMethod = Py_FindMethod( PythonQtInstanceWrapper_methods, obj, (char*)attributeName);
201 245 if (internalMethod) {
202 246 return internalMethod;
203 247 }
204 248 PyErr_Clear();
205 249
206 250 if (wrapper->_obj) {
207 251 // look for a child
208 252 QObjectList children = wrapper->_obj->children();
209 253 for (int i = 0; i < children.count(); i++) {
210 254 QObject *child = children.at(i);
211 255 if (child->objectName() == attributeName) {
212 256 return PythonQt::self()->priv()->wrapQObject(child);
213 257 }
214 258 }
215 259 }
216 260
217 261 if (qstrcmp(attributeName, "__dict__")==0) {
218 QStringList l = wrapper->_info->memberList(false);
262 QStringList l = wrapper->classInfo()->memberList(false);
219 263 PyObject* dict = PyDict_New();
220 264 foreach (QString name, l) {
221 265 //PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
222 266 PyDict_SetItemString(dict, name.toLatin1().data(), Py_None);
223 267 //Py_DECREF(o);
224 268 }
225 269 // Note: we do not put children into the dict, is would look confusing?!
226 270 return dict;
227 271 }
228 272
229 273
230 QString error = QString(wrapper->_info->className()) + " has no attribute named '" + QString(attributeName) + "'";
274 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
231 275 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
232 276 return NULL;
233 277 }
234 278
235 279 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
236 280 {
237 281 QString error;
238 282 char *attributeName;
239 283 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
240 284
241 285 if ((attributeName = PyString_AsString(name)) == NULL)
242 286 return -1;
243 287
244 288 if (!wrapper->_obj) {
245 error = QString("Trying to set attribute '") + attributeName + "' on a destroyed " + wrapper->_info->className() + " object";
289 error = QString("Trying to set attribute '") + attributeName + "' on a destroyed " + wrapper->classInfo()->className() + " object";
246 290 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
247 291 return -1;
248 292 }
249 293
250 PythonQtMemberInfo member = wrapper->_info->member(attributeName);
294 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
251 295 if (member._type == PythonQtMemberInfo::Property) {
252 296 QMetaProperty prop = member._property;
253 297 if (prop.isWritable()) {
254 298 QVariant v;
255 299 if (prop.isEnumType()) {
256 300 // this will give us either a string or an int, everything else will probably be an error
257 301 v = PythonQtConv::PyObjToQVariant(value);
258 302 } else {
259 303 int t = prop.userType();
260 304 v = PythonQtConv::PyObjToQVariant(value, t);
261 305 }
262 306 bool success = false;
263 307 if (v.isValid()) {
264 308 success = prop.write(wrapper->_obj, v);
265 309 }
266 310 if (success) {
267 311 return 0;
268 312 } else {
269 313 error = QString("Property '") + attributeName + "' of type '" +
270 314 prop.typeName() + "' does not accept an object of type "
271 315 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
272 316 }
273 317 } else {
274 error = QString("Property '") + attributeName + "' of " + wrapper->_info->className() + " object is not writable";
318 error = QString("Property '") + attributeName + "' of " + wrapper->classInfo()->className() + " object is not writable";
275 319 }
276 320 } else {
277 321 if (member._type == PythonQtMemberInfo::Slot) {
278 error = QString("Slot '") + attributeName + "' can not be overwritten on " + wrapper->_info->className() + " object";
322 error = QString("Slot '") + attributeName + "' can not be overwritten on " + wrapper->classInfo()->className() + " object";
279 323 } else if (member._type == PythonQtMemberInfo::EnumValue) {
280 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + wrapper->_info->className() + " object";
324 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + wrapper->classInfo()->className() + " object";
281 325 }
282 326 }
283 327
284 328 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
285 329 return -1;
286 330 }
287 331
288 332 static PyObject * PythonQtInstanceWrapper_str(PyObject * obj)
289 333 {
290 334 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
291 335 QObject *qobj = wrapper->_obj;
292 336 if (wrapper->_wrappedPtr) {
293 QString str = PythonQtConv::CPPObjectToString(wrapper->_info->metaTypeId(), wrapper->_wrappedPtr);
337 QString str = PythonQtConv::CPPObjectToString(wrapper->classInfo()->metaTypeId(), wrapper->_wrappedPtr);
294 338 if (!str.isEmpty()) {
295 339 return PyString_FromFormat("%s", str.toLatin1().constData());
296 340 } else
297 341 if (wrapper->_obj) {
298 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", wrapper->_info->className(), wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
342 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", wrapper->classInfo()->className(), wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
299 343 } else {
300 return PyString_FromFormat("%s (C++ Object %p)", wrapper->_info->className(), wrapper->_wrappedPtr);
344 return PyString_FromFormat("%s (C++ Object %p)", wrapper->classInfo()->className(), wrapper->_wrappedPtr);
301 345 }
302 346 } else {
303 return PyString_FromFormat("%s (QObject %p)", wrapper->_info->className(), qobj);
347 return PyString_FromFormat("%s (QObject %p)", wrapper->classInfo()->className(), qobj);
304 348 }
305 349 }
306 350
307 351 static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj)
308 352 {
309 353 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
310 354 QObject *qobj = wrapper->_obj;
311 355 if (wrapper->_wrappedPtr) {
312 QString str = PythonQtConv::CPPObjectToString(wrapper->_info->metaTypeId(), wrapper->_wrappedPtr);
356 QString str = PythonQtConv::CPPObjectToString(wrapper->classInfo()->metaTypeId(), wrapper->_wrappedPtr);
313 357 if (!str.isEmpty()) {
314 return PyString_FromFormat("%s(%s, %p)", QMetaType::typeName(wrapper->_info->metaTypeId()), str.toLatin1().constData(), wrapper->_wrappedPtr);
358 return PyString_FromFormat("%s(%s, %p)", QMetaType::typeName(wrapper->classInfo()->metaTypeId()), str.toLatin1().constData(), wrapper->_wrappedPtr);
315 359 } else
316 360 if (wrapper->_obj) {
317 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", wrapper->_info->className(), wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
361 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", wrapper->classInfo()->className(), wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
318 362 } else {
319 return PyString_FromFormat("%s (C++ Object %p)", wrapper->_info->className(), wrapper->_wrappedPtr);
363 return PyString_FromFormat("%s (C++ Object %p)", wrapper->classInfo()->className(), wrapper->_wrappedPtr);
320 364 }
321 365 } else {
322 return PyString_FromFormat("%s (QObject %p)", wrapper->_info->className(), qobj);
366 return PyString_FromFormat("%s (QObject %p)", wrapper->classInfo()->className(), qobj);
323 367 }
324 368 }
325 369
326 370 static int PythonQtInstanceWrapper_compare(PyObject * obj1, PyObject * obj2)
327 371 {
328 if (obj1->ob_type == &PythonQtInstanceWrapper_Type &&
329 obj2->ob_type == &PythonQtInstanceWrapper_Type) {
372 if (PyObject_TypeCheck(obj1, &PythonQtInstanceWrapper_Type) &&
373 PyObject_TypeCheck(obj2, &PythonQtInstanceWrapper_Type)) {
330 374
331 375 PythonQtInstanceWrapper* w1 = (PythonQtInstanceWrapper*)obj1;
332 376 PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)obj2;
333 377 // check pointers directly first:
334 378 if (w1->_wrappedPtr != NULL) {
335 379 if (w1->_wrappedPtr == w2->_wrappedPtr) {
336 380 return 0;
337 381 }
338 382 } else if (w1->_obj == w2->_obj) {
339 383 return 0;
340 384 }
341 const char* class1 = w1->_info->className();
342 const char* class2 = w2->_info->className();
385 const char* class1 = w1->classInfo()->className();
386 const char* class2 = w2->classInfo()->className();
343 387 if (strcmp(class1, class2) == 0) {
344 388 // same class names, so we can try the operator_equal
345 PythonQtMemberInfo info = w1->_info->member("operator_equal");
389 PythonQtMemberInfo info = w1->classInfo()->member("operator_equal");
346 390 if (info._type == PythonQtMemberInfo::Slot) {
347 391 bool result = false;
348 392 void* obj1 = w1->_wrappedPtr;
349 393 if (!obj1) {
350 394 obj1 = w1->_obj;
351 395 }
352 396 if (!obj1) { return -1; }
353 397 void* obj2 = w2->_wrappedPtr;
354 398 if (!obj2) {
355 399 obj2 = w2->_obj;
356 400 }
357 401 if (!obj2) { return -1; }
358 402 if (info._slot->isInstanceDecorator()) {
359 403 // call on decorator QObject
360 404 void* args[3];
361 405 args[0] = &result;
362 406 args[1] = &obj1; // this is a pointer, so it needs a pointer to a pointer
363 407 args[2] = obj2; // this is a reference, so it needs the direct pointer
364 408 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
365 409 return result?0:-1;
366 410 } else {
367 411 // call directly on QObject
368 412 if (w1->_obj && w2->_obj) {
369 413 void* args[2];
370 414 args[0] = &result;
371 415 args[2] = obj2; // this is a reference, so it needs the direct pointer
372 416 w1->_obj->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
373 417 }
374 418 }
375 419 }
376 420 }
377 421 }
378 422 return -1;
379 423 }
380 424
381 425 static int PythonQtInstanceWrapper_nonzero(PyObject *obj)
382 426 {
383 427 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
384 428 return (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
385 429 }
386 430
387 431
388 432 static long PythonQtInstanceWrapper_hash(PythonQtInstanceWrapper *obj)
389 433 {
390 434 if (obj->_wrappedPtr != NULL) {
391 435 return reinterpret_cast<long>(obj->_wrappedPtr);
392 436 } else {
393 437 QObject* qobj = obj->_obj; // get pointer from QPointer wrapper
394 438 return reinterpret_cast<long>(qobj);
395 439 }
396 440 }
397 441
398 442
399 443
400 444 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
401 445 static PyNumberMethods PythonQtInstanceWrapper_as_number = {
402 446 0, /* nb_add */
403 447 0, /* nb_subtract */
404 448 0, /* nb_multiply */
405 449 0, /* nb_divide */
406 450 0, /* nb_remainder */
407 451 0, /* nb_divmod */
408 452 0, /* nb_power */
409 453 0, /* nb_negative */
410 454 0, /* nb_positive */
411 455 0, /* nb_absolute */
412 456 PythonQtInstanceWrapper_nonzero, /* nb_nonzero */
413 457 0, /* nb_invert */
414 458 0, /* nb_lshift */
415 459 0, /* nb_rshift */
416 460 0, /* nb_and */
417 461 0, /* nb_xor */
418 462 0, /* nb_or */
419 463 0, /* nb_coerce */
420 464 0, /* nb_int */
421 465 0, /* nb_long */
422 466 0, /* nb_float */
423 467 0, /* nb_oct */
424 468 0, /* nb_hex */
425 469 0, /* nb_inplace_add */
426 470 0, /* nb_inplace_subtract */
427 471 0, /* nb_inplace_multiply */
428 472 0, /* nb_inplace_divide */
429 473 0, /* nb_inplace_remainder */
430 474 0, /* nb_inplace_power */
431 475 0, /* nb_inplace_lshift */
432 476 0, /* nb_inplace_rshift */
433 477 0, /* nb_inplace_and */
434 478 0, /* nb_inplace_xor */
435 479 0, /* nb_inplace_or */
436 480 0, /* nb_floor_divide */
437 481 0, /* nb_true_divide */
438 482 0, /* nb_inplace_floor_divide */
439 483 0, /* nb_inplace_true_divide */
440 484 };
441 485
442 486 PyTypeObject PythonQtInstanceWrapper_Type = {
443 PyObject_HEAD_INIT(NULL)
487 PyObject_HEAD_INIT(&PythonQtClassWrapper_Type)
444 488 0, /*ob_size*/
445 489 "PythonQt.PythonQtInstanceWrapper", /*tp_name*/
446 490 sizeof(PythonQtInstanceWrapper), /*tp_basicsize*/
447 491 0, /*tp_itemsize*/
448 492 (destructor)PythonQtInstanceWrapper_dealloc, /*tp_dealloc*/
449 493 0, /*tp_print*/
450 494 0, /*tp_getattr*/
451 495 0, /*tp_setattr*/
452 496 PythonQtInstanceWrapper_compare, /*tp_compare*/
453 497 PythonQtInstanceWrapper_repr, /*tp_repr*/
454 498 &PythonQtInstanceWrapper_as_number, /*tp_as_number*/
455 499 0, /*tp_as_sequence*/
456 500 0, /*tp_as_mapping*/
457 501 (hashfunc)PythonQtInstanceWrapper_hash, /*tp_hash */
458 502 0, /*tp_call*/
459 503 PythonQtInstanceWrapper_str, /*tp_str*/
460 504 PythonQtInstanceWrapper_getattro, /*tp_getattro*/
461 505 PythonQtInstanceWrapper_setattro, /*tp_setattro*/
462 506 0, /*tp_as_buffer*/
463 507 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
464 508 "PythonQtInstanceWrapper object", /* tp_doc */
465 509 0, /* tp_traverse */
466 510 0, /* tp_clear */
467 511 0, /* tp_richcompare */
468 512 0, /* tp_weaklistoffset */
469 513 0, /* tp_iter */
470 514 0, /* tp_iternext */
471 515 0, /* tp_methods */
472 516 0, /* tp_members */
473 517 0, /* tp_getset */
474 518 0, /* tp_base */
475 519 0, /* tp_dict */
476 520 0, /* tp_descr_get */
477 521 0, /* tp_descr_set */
478 522 0, /* tp_dictoffset */
479 523 (initproc)PythonQtInstanceWrapper_init, /* tp_init */
480 524 0, /* tp_alloc */
481 525 PythonQtInstanceWrapper_new, /* tp_new */
482 526 };
483 527
484 528 //-------------------------------------------------------
485 529
@@ -1,92 +1,92
1 1 #ifndef _PYTHONQTINSTANCEWRAPPER_H
2 2 #define _PYTHONQTINSTANCEWRAPPER_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 PythonQtInstanceWrapper.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 48 #include <QPointer>
49 49
50 50 #include "structmember.h"
51 51 #include "methodobject.h"
52 52 #include "compile.h"
53 53 #include "eval.h"
54 54
55 55 class PythonQtClassInfo;
56 56 class QObject;
57 57
58 58 extern PYTHONQT_EXPORT PyTypeObject PythonQtInstanceWrapper_Type;
59 59
60 60 //---------------------------------------------------------------
61 61 //! a Python wrapper object for Qt objects and C++ objects (that are themselves wrapped by wrapper QObjects)
62 62 typedef struct {
63 63 PyObject_HEAD
64 64
65 //! the class information, this is set even if the _obj or _wrappedPtr is NULL to support typed NULL pointers
66 PythonQtClassInfo* classInfo();
67
65 68 //! set the QObject pointer
66 69 void setQObject(QObject* object) {
67 70 _obj = object;
68 71 _objPointerCopy = object;
69 72 }
70 73
71 74 //! pointer to the wrapped Qt object or if _wrappedPtr is set, the Qt object that wraps the C++ Ptr
72 75 QPointer<QObject> _obj;
73 76 //! a copy of the _obj pointer, which is required because the wrapper needs to
74 77 //! deregister itself via the _obj pointer, even when the QPointer<QObject> object was destroyed
75 78 void* _objPointerCopy;
76 79
77 80 //! optional C++ object Ptr that is wrapped by the above _obj
78 81 void* _wrappedPtr;
79 82
80 //! the class information, this is set even if the _obj or _wrappedPtr is NULL to support typed NULL pointers
81 PythonQtClassInfo* _info;
82
83 83 //! flag that stores if the object is owned by pythonQt
84 84 bool _ownedByPythonQt;
85 85
86 86 //! stores that the owned object should be destroyed using QMetaType::destroy()
87 87 bool _useQMetaTypeDestroy;
88 88
89 89 } PythonQtInstanceWrapper;
90 90
91 91
92 92 #endif No newline at end of file
@@ -1,445 +1,458
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 PythonQtSlot.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 "PythonQtSlot.h"
44 44 #include "PythonQtInstanceWrapper.h"
45 45 #include "PythonQtClassInfo.h"
46 46 #include "PythonQtMisc.h"
47 47 #include "PythonQtConversion.h"
48 48 #include <iostream>
49 49
50 50 #define PYTHONQT_MAX_ARGS 32
51 51
52 52
53 PyObject* PythonQtCallSlot(QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument)
53 bool PythonQtCallSlot(QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer)
54 54 {
55 55 static unsigned int recursiveEntry = 0;
56 56
57 if (directReturnValuePointer) {
58 *directReturnValuePointer = NULL;
59 }
57 60 // store the current storage position, so that we can get back to this state after a slot is called
58 61 // (do this locally, so that we have all positions on the stack
59 62 PythonQtValueStoragePosition globalValueStoragePos;
60 63 PythonQtValueStoragePosition globalPtrStoragePos;
61 64 PythonQtValueStoragePosition globalVariantStoragePos;
62 65 PythonQtConv::global_valueStorage.getPos(globalValueStoragePos);
63 66 PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos);
64 67 PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos);
65 68
66 69 recursiveEntry++;
67 70
68 71 // the arguments that are passed to qt_metacall
69 72 void* argList[PYTHONQT_MAX_ARGS];
70 73 PyObject* result = NULL;
71 74 int argc = info->parameterCount();
72 75 const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters();
73 76
74 77 bool returnValueIsEnum = false;
75 78 const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);
76 79 // set return argument to NULL
77 80 argList[0] = NULL;
78 81
79 82 if (returnValueParam.typeId != QMetaType::Void) {
80 83 // extra handling of enum return value
81 84 if (!returnValueParam.isPointer && returnValueParam.typeId == PythonQtMethodInfo::Unknown) {
82 85 returnValueIsEnum = PythonQt::priv()->isEnumType(objectToCall->metaObject(), returnValueParam.name);
83 86 if (returnValueIsEnum) {
84 87 // create enum return value
85 88 PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, argList[0]);
86 89 }
87 90 }
88 91 if (argList[0]==NULL) {
89 92 // create empty default value for the return value
93 if (!directReturnValuePointer) {
94 // create empty default value for the return value
90 95 argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);
96 } else {
97 // we can use our pointer directly!
98 argList[0] = directReturnValuePointer;
99 }
91 100 }
92 101 }
93 102
94 103 const QMetaObject* meta = objectToCall?objectToCall->metaObject():NULL;
95 104 bool ok = true;
96 105 bool skipFirst = false;
97 106 if (info->isInstanceDecorator()) {
98 107 skipFirst = true;
99 108 if (!firstArgument) {
100 109 argList[1] = &objectToCall;
101 110 } else {
102 111 // for the variant call we take the ptr to the variant data, for decorators on CPP objects, we take the cpp ptr
103 112 argList[1] = &firstArgument;
104 113 }
105 114 if (ok) {
106 115 for (int i = 2; i<argc && ok; i++) {
107 116 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
108 117 //std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
109 118 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, meta);
110 119 if (argList[i]==NULL) {
111 120 ok = false;
112 121 break;
113 122 }
114 123 }
115 124 }
116 125 } else {
117 126 for (int i = 1; i<argc && ok; i++) {
118 127 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
119 128 //std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
120 129 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, meta);
121 130 if (argList[i]==NULL) {
122 131 ok = false;
123 132 break;
124 133 }
125 134 }
126 135 }
127 136
128 137 if (ok) {
129 138 (info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
130 139
131 140 if (argList[0] || returnValueParam.typeId == QMetaType::Void) {
141 if (directReturnValuePointer) {
142 result = NULL;
143 } else {
132 144 if (!returnValueIsEnum) {
133 145 result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]);
134 146 } else {
135 147 result = PyInt_FromLong(*((unsigned int*)argList[0]));
136 148 }
149 }
137 150 } else {
138 151 QString e = QString("Called ") + info->fullSignature(skipFirst) + ", return type is ignored because it is unknown to PythonQt.";
139 152 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
140 153 result = NULL;
141 154 }
142 155 }
143 156 recursiveEntry--;
144 157
145 158 // reset the parameter storage position to the stored pos to "pop" the parameter stack
146 159 PythonQtConv::global_valueStorage.setPos(globalValueStoragePos);
147 160 PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos);
148 161 PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos);
149 162
163 *pythonReturnValue = result;
150 164 // NOTE: it is important to only return here, otherwise the stack will not be popped!!!
151 return result;
165 return result || (directReturnValuePointer && *directReturnValuePointer);
152 166 }
153 167
154 168 //-----------------------------------------------------------------------------------
155 169
156 170 static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL;
157 171
158 172 PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw)
159 173 {
160 174 PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func;
161 175 PythonQtSlotInfo* info = f->m_ml;
162 if (f->m_self->ob_type == &PythonQtInstanceWrapper_Type) {
176 if (PyObject_TypeCheck(f->m_self, &PythonQtInstanceWrapper_Type)) {
163 177 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self;
164 178 return PythonQtSlotFunction_CallImpl(self->_obj, info, args, kw, self->_wrappedPtr);
165 179 } else if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
166 180 return PythonQtSlotFunction_CallImpl(NULL, info, args, kw);
167 181 } else {
168 182 return NULL;
169 183 }
170 184 }
171 185
172 PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg)
186 PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg, void** directReturnValuePointer)
173 187 {
174 188 int argc = PyTuple_Size(args);
175 189
176 190 #ifdef PYTHONQT_DEBUG
177 191 std::cout << "called " << info->metaMethod()->typeName() << " " << info->metaMethod()->signature() << std::endl;
178 192 #endif
179 193
180 194 PyObject* r = NULL;
195 bool ok = false;
196 if (directReturnValuePointer) {
197 *directReturnValuePointer = NULL;
198 }
181 199
182 200 if (info->nextInfo()) {
183 201 // overloaded slot call, try on all slots with strict conversion first
202 bool strict = true;
184 203 PythonQtSlotInfo* i = info;
185 while (i && r==NULL) {
204 while (i) {
186 205 bool skipFirst = i->isInstanceDecorator();
187 206 if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
188 207 PyErr_Clear();
189 r = PythonQtCallSlot(objectToCall, args, true, i, firstArg);
190 if (PyErr_Occurred()) break;
208 ok = PythonQtCallSlot(objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer);
209 if (PyErr_Occurred() || ok) break;
191 210 }
192 211 i = i->nextInfo();
193 }
194 if (!r) {
195 // try on all slots with non-strict conversion
212 if (!i) {
213 if (strict) {
214 // one more run without being strict
215 strict = false;
196 216 i = info;
197 while (i && r==NULL) {
198 bool skipFirst = i->isInstanceDecorator();
199 if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
200 PyErr_Clear();
201 r = PythonQtCallSlot(objectToCall, args, false, i, firstArg);
202 if (PyErr_Occurred()) break;
203 217 }
204 i = i->nextInfo();
205 218 }
206 219 }
207 if (r==NULL && !PyErr_Occurred()) {
220 if (!ok && !PyErr_Occurred()) {
208 221 QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n");
209 222 PythonQtSlotInfo* i = info;
210 223 while (i) {
211 224 bool skipFirst = i->isInstanceDecorator();
212 225 e += QString(i->fullSignature(skipFirst)) + "\n";
213 226 i = i->nextInfo();
214 227 }
215 228 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
216 229 }
217 230 } else {
218 231 // simple (non-overloaded) slot call
219 232 bool skipFirst = info->isInstanceDecorator();
220 233 if (info->parameterCount()-1-(skipFirst?1:0) == argc) {
221 234 PyErr_Clear();
222 r = PythonQtCallSlot(objectToCall, args, false, info, firstArg);
223 if (r==NULL && !PyErr_Occurred()) {
235 ok = PythonQtCallSlot(objectToCall, args, false, info, firstArg, &r, directReturnValuePointer);
236 if (!ok && !PyErr_Occurred()) {
224 237 QString e = QString("Called ") + info->fullSignature(skipFirst) + " with wrong arguments: " + PythonQtConv::PyObjGetString(args);
225 238 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
226 239 }
227 240 } else {
228 241 QString e = QString("Called ") + info->fullSignature(skipFirst) + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args);
229 242 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
230 243 }
231 244 }
232 245
233 246 return r;
234 247 }
235 248
236 249 PyObject *
237 250 PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module)
238 251 {
239 252 PythonQtSlotFunctionObject *op;
240 253 op = pythonqtslot_free_list;
241 254 if (op != NULL) {
242 255 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self);
243 256 PyObject_INIT(op, &PythonQtSlotFunction_Type);
244 257 }
245 258 else {
246 259 op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type);
247 260 if (op == NULL)
248 261 return NULL;
249 262 }
250 263 op->m_ml = ml;
251 264 Py_XINCREF(self);
252 265 op->m_self = self;
253 266 Py_XINCREF(module);
254 267 op->m_module = module;
255 268 PyObject_GC_Track(op);
256 269 return (PyObject *)op;
257 270 }
258 271
259 272 PythonQtSlotInfo*
260 273 PythonQtSlotFunction_GetSlotInfo(PyObject *op)
261 274 {
262 275 if (!PythonQtSlotFunction_Check(op)) {
263 276 PyErr_BadInternalCall();
264 277 return NULL;
265 278 }
266 279 return ((PythonQtSlotFunctionObject *)op) -> m_ml;
267 280 }
268 281
269 282 PyObject *
270 283 PythonQtSlotFunction_GetSelf(PyObject *op)
271 284 {
272 285 if (!PythonQtSlotFunction_Check(op)) {
273 286 PyErr_BadInternalCall();
274 287 return NULL;
275 288 }
276 289 return ((PythonQtSlotFunctionObject *)op) -> m_self;
277 290 }
278 291
279 292 /* Methods (the standard built-in methods, that is) */
280 293
281 294 static void
282 295 meth_dealloc(PythonQtSlotFunctionObject *m)
283 296 {
284 297 PyObject_GC_UnTrack(m);
285 298 Py_XDECREF(m->m_self);
286 299 Py_XDECREF(m->m_module);
287 300 m->m_self = (PyObject *)pythonqtslot_free_list;
288 301 pythonqtslot_free_list = m;
289 302 }
290 303
291 304 static PyObject *
292 305 meth_get__doc__(PythonQtSlotFunctionObject * /*m*/, void * /*closure*/)
293 306 {
294 307 Py_INCREF(Py_None);
295 308 return Py_None;
296 309 }
297 310
298 311 static PyObject *
299 312 meth_get__name__(PythonQtSlotFunctionObject *m, void * /*closure*/)
300 313 {
301 314 return PyString_FromString(m->m_ml->metaMethod()->signature());
302 315 }
303 316
304 317 static int
305 318 meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg)
306 319 {
307 320 int err;
308 321 if (m->m_self != NULL) {
309 322 err = visit(m->m_self, arg);
310 323 if (err)
311 324 return err;
312 325 }
313 326 if (m->m_module != NULL) {
314 327 err = visit(m->m_module, arg);
315 328 if (err)
316 329 return err;
317 330 }
318 331 return 0;
319 332 }
320 333
321 334 static PyObject *
322 335 meth_get__self__(PythonQtSlotFunctionObject *m, void * /*closure*/)
323 336 {
324 337 PyObject *self;
325 338 if (PyEval_GetRestricted()) {
326 339 PyErr_SetString(PyExc_RuntimeError,
327 340 "method.__self__ not accessible in restricted mode");
328 341 return NULL;
329 342 }
330 343 self = m->m_self;
331 344 if (self == NULL)
332 345 self = Py_None;
333 346 Py_INCREF(self);
334 347 return self;
335 348 }
336 349
337 350 static PyGetSetDef meth_getsets [] = {
338 351 {"__doc__", (getter)meth_get__doc__, NULL, NULL},
339 352 {"__name__", (getter)meth_get__name__, NULL, NULL},
340 353 {"__self__", (getter)meth_get__self__, NULL, NULL},
341 354 {NULL, NULL, NULL,NULL},
342 355 };
343 356
344 357 #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6
345 358 #define PY_WRITE_RESTRICTED WRITE_RESTRICTED
346 359 #endif
347 360
348 361 #define OFF(x) offsetof(PythonQtSlotFunctionObject, x)
349 362
350 363 static PyMemberDef meth_members[] = {
351 364 {"__module__", T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED},
352 365 {NULL}
353 366 };
354 367
355 368 static PyObject *
356 369 meth_repr(PythonQtSlotFunctionObject *m)
357 370 {
358 371 return PyString_FromFormat("<built-in qt slot %s of %s object at %p>",
359 372 m->m_ml->metaMethod()->signature(),
360 373 m->m_self->ob_type->tp_name,
361 374 m->m_self);
362 375 }
363 376
364 377 static int
365 378 meth_compare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b)
366 379 {
367 380 if (a->m_self != b->m_self)
368 381 return (a->m_self < b->m_self) ? -1 : 1;
369 382 if (a->m_ml == b->m_ml)
370 383 return 0;
371 384 if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0)
372 385 return -1;
373 386 else
374 387 return 1;
375 388 }
376 389
377 390 static long
378 391 meth_hash(PythonQtSlotFunctionObject *a)
379 392 {
380 393 long x,y;
381 394 if (a->m_self == NULL)
382 395 x = 0;
383 396 else {
384 397 x = PyObject_Hash(a->m_self);
385 398 if (x == -1)
386 399 return -1;
387 400 }
388 401 y = _Py_HashPointer((void*)(a->m_ml));
389 402 if (y == -1)
390 403 return -1;
391 404 x ^= y;
392 405 if (x == -1)
393 406 x = -2;
394 407 return x;
395 408 }
396 409
397 410
398 411 PyTypeObject PythonQtSlotFunction_Type = {
399 412 PyObject_HEAD_INIT(&PyType_Type)
400 413 0,
401 414 "builtin_qt_slot",
402 415 sizeof(PythonQtSlotFunctionObject),
403 416 0,
404 417 (destructor)meth_dealloc, /* tp_dealloc */
405 418 0, /* tp_print */
406 419 0, /* tp_getattr */
407 420 0, /* tp_setattr */
408 421 (cmpfunc)meth_compare, /* tp_compare */
409 422 (reprfunc)meth_repr, /* tp_repr */
410 423 0, /* tp_as_number */
411 424 0, /* tp_as_sequence */
412 425 0, /* tp_as_mapping */
413 426 (hashfunc)meth_hash, /* tp_hash */
414 427 PythonQtSlotFunction_Call, /* tp_call */
415 428 0, /* tp_str */
416 429 PyObject_GenericGetAttr, /* tp_getattro */
417 430 0, /* tp_setattro */
418 431 0, /* tp_as_buffer */
419 432 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
420 433 0, /* tp_doc */
421 434 (traverseproc)meth_traverse, /* tp_traverse */
422 435 0, /* tp_clear */
423 436 0, /* tp_richcompare */
424 437 0, /* tp_weaklistoffset */
425 438 0, /* tp_iter */
426 439 0, /* tp_iternext */
427 440 0, /* tp_methods */
428 441 meth_members, /* tp_members */
429 442 meth_getsets, /* tp_getset */
430 443 0, /* tp_base */
431 444 0, /* tp_dict */
432 445 };
433 446
434 447 /* Clear out the free list */
435 448
436 449 void
437 450 PythonQtSlotFunction_Fini(void)
438 451 {
439 452 while (pythonqtslot_free_list) {
440 453 PythonQtSlotFunctionObject *v = pythonqtslot_free_list;
441 454 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(v->m_self);
442 455 PyObject_GC_Del(v);
443 456 }
444 457 }
445 458
@@ -1,79 +1,79
1 1 #ifndef _PYTHONQTSLOT_H
2 2 #define _PYTHONQTSLOT_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 PythonQtSlot.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "Python.h"
46 46 #include "structmember.h"
47 47
48 48 class PythonQtSlotInfo;
49 49
50 50 extern PyTypeObject PythonQtSlotFunction_Type;
51 51
52 52 #define PythonQtSlotFunction_Check(op) ((op)->ob_type == &PythonQtSlotFunction_Type)
53 53
54 54 PythonQtSlotInfo* PythonQtSlotFunction_GetSlotInfo(PyObject *);
55 55 PyObject* PythonQtSlotFunction_GetSelf(PyObject *);
56 56
57 57 /* Macros for direct access to these values. Type checks are *not*
58 58 done, so use with care. */
59 59 #define PythonQtSlotFunction_GET_SELF(func) \
60 60 (((PythonQtSlotFunctionObject *)func) -> m_self)
61 61
62 62 PyObject* PythonQtSlotFunction_Call(PyObject *, PyObject *, PyObject *);
63 63
64 PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject *kw, void* firstArg=NULL);
64 PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject *kw, void* firstArg=NULL, void** directReturnValuePointer=NULL);
65 65
66 66
67 67 PyObject* PythonQtSlotFunction_New(PythonQtSlotInfo *, PyObject *,
68 68 PyObject *);
69 69
70 70 //! defines a python object that stores a Qt slot info
71 71 typedef struct {
72 72 PyObject_HEAD
73 73 PythonQtSlotInfo *m_ml; /* Description of the C function to call */
74 74 PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */
75 75 PyObject *m_module; /* The __module__ attribute, can be anything */
76 76 } PythonQtSlotFunctionObject;
77 77
78 78
79 79 #endif
General Comments 0
You need to be logged in to leave comments. Login now