##// END OF EJS Templates
moved return value creation AFTER the successful check of the call parameters, otherwise the return value allocation is done for nothing...
florianlink -
r45:73b37bcd54f9
parent child
Show More
@@ -1,1099 +1,1099
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 if (!ptr) {
213 // everything else is stored in a QVariant...
212 if (!ptr && info.typeId!=PythonQtMethodInfo::Unknown) {
213 // everything else is stored in a QVariant, if we know the meta type...
214 214 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
215 215 // return the constData pointer that will be filled with the result value later on
216 216 ptr = (void*)((QVariant*)ptr)->constData();
217 217 }
218 218 }
219 219 }
220 220 return ptr;
221 221 }
222 222
223 223 void* PythonQtConv::castWrapperTo(PythonQtInstanceWrapper* wrapper, const QByteArray& className, bool& ok)
224 224 {
225 225 void* object;
226 226 if (wrapper->classInfo()->isCPPWrapper()) {
227 227 object = wrapper->_wrappedPtr;
228 228 } else {
229 229 QObject* tmp = wrapper->_obj;
230 230 object = tmp;
231 231 }
232 232 if (object) {
233 233 // if we can be upcasted to the given name, we pass the casted pointer in:
234 234 object = wrapper->classInfo()->castTo(object, className);
235 235 ok = object!=NULL;
236 236 } else {
237 237 // if it is a NULL ptr, we need to check if it inherits, so that we might pass the NULL ptr
238 238 ok = wrapper->classInfo()->inherits(className);
239 239 }
240 240 return object;
241 241 }
242 242
243 243 void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* meta, void* alreadyAllocatedCPPObject)
244 244 {
245 245 bool ok;
246 246 void* ptr = NULL;
247 247 if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) && info.typeId != PythonQtMethodInfo::Variant) {
248 248 // if we have a Qt wrapper object and if we do not need a QVariant, we do the following:
249 249 // (the Variant case is handled below in a switch)
250 250
251 251 // a C++ wrapper (can be passed as pointer or reference)
252 252 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)obj;
253 253 bool ok;
254 254 void* object = castWrapperTo(wrap, info.name, ok);
255 255 if (ok) {
256 256 if (info.isPointer) {
257 257 // store the wrapped pointer in an extra pointer and let ptr point to the extra pointer
258 258 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, object, ptr);
259 259 } else {
260 260 // store the wrapped pointer directly, since we are a reference
261 261 ptr = object;
262 262 }
263 263 } else {
264 264 // not matching
265 265 }
266 266 } else if (info.isPointer) {
267 267 // a pointer
268 268 if (info.typeId == QMetaType::Char || info.typeId == QMetaType::UChar)
269 269 {
270 270 QString str = PyObjGetString(obj, strict, ok);
271 271 if (ok) {
272 272 void* ptr2 = NULL;
273 273 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str.toUtf8()), ptr2);
274 274 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr);
275 275 }
276 276 } else if (info.name == "PyObject") {
277 277 // handle low level PyObject directly
278 278 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, obj, ptr);
279 279 } else if (obj == Py_None) {
280 280 // None is treated as a NULL ptr
281 281 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
282 282 } else {
283 283 // if we are not strict, we try if we are passed a 0 integer
284 284 if (!strict) {
285 285 bool ok;
286 286 int value = PyObjGetInt(obj, true, ok);
287 287 if (ok && value==0) {
288 288 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
289 289 }
290 290 }
291 291 }
292 292 } else {
293 293 // not a pointer
294 294 switch (info.typeId) {
295 295 case QMetaType::Char:
296 296 {
297 297 int val = PyObjGetInt(obj, strict, ok);
298 298 if (ok) {
299 299 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, char, val, ptr);
300 300 }
301 301 }
302 302 break;
303 303 case QMetaType::UChar:
304 304 {
305 305 int val = PyObjGetInt(obj, strict, ok);
306 306 if (ok) {
307 307 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned char, val, ptr);
308 308 }
309 309 }
310 310 break;
311 311 case QMetaType::Short:
312 312 {
313 313 int val = PyObjGetInt(obj, strict, ok);
314 314 if (ok) {
315 315 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
316 316 }
317 317 }
318 318 break;
319 319 case QMetaType::UShort:
320 320 {
321 321 int val = PyObjGetInt(obj, strict, ok);
322 322 if (ok) {
323 323 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned short, val, ptr);
324 324 }
325 325 }
326 326 break;
327 327 case QMetaType::Long:
328 328 {
329 329 long val = (long)PyObjGetLongLong(obj, strict, ok);
330 330 if (ok) {
331 331 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, long, val, ptr);
332 332 }
333 333 }
334 334 break;
335 335 case QMetaType::ULong:
336 336 {
337 337 unsigned long val = (unsigned long)PyObjGetLongLong(obj, strict, ok);
338 338 if (ok) {
339 339 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned long, val, ptr);
340 340 }
341 341 }
342 342 break;
343 343 case QMetaType::Bool:
344 344 {
345 345 bool val = PyObjGetBool(obj, strict, ok);
346 346 if (ok) {
347 347 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, bool, val, ptr);
348 348 }
349 349 }
350 350 break;
351 351 case QMetaType::Int:
352 352 {
353 353 int val = PyObjGetInt(obj, strict, ok);
354 354 if (ok) {
355 355 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, int, val, ptr);
356 356 }
357 357 }
358 358 break;
359 359 case QMetaType::UInt:
360 360 {
361 361 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
362 362 if (ok) {
363 363 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
364 364 }
365 365 }
366 366 break;
367 367 case QMetaType::QChar:
368 368 {
369 369 int val = PyObjGetInt(obj, strict, ok);
370 370 if (ok) {
371 371 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
372 372 }
373 373 }
374 374 break;
375 375 case QMetaType::Float:
376 376 {
377 377 float val = (float)PyObjGetDouble(obj, strict, ok);
378 378 if (ok) {
379 379 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, float, val, ptr);
380 380 }
381 381 }
382 382 break;
383 383 case QMetaType::Double:
384 384 {
385 385 double val = (double)PyObjGetDouble(obj, strict, ok);
386 386 if (ok) {
387 387 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, double, val, ptr);
388 388 }
389 389 }
390 390 break;
391 391 case QMetaType::LongLong:
392 392 {
393 393 qint64 val = PyObjGetLongLong(obj, strict, ok);
394 394 if (ok) {
395 395 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, qint64, val, ptr);
396 396 }
397 397 }
398 398 break;
399 399 case QMetaType::ULongLong:
400 400 {
401 401 quint64 val = PyObjGetULongLong(obj, strict, ok);
402 402 if (ok) {
403 403 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, quint64, val, ptr);
404 404 }
405 405 }
406 406 break;
407 407 case QMetaType::QByteArray:
408 408 {
409 409 QByteArray bytes = PyObjGetBytes(obj, strict, ok);
410 410 if (ok) {
411 411 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(bytes), ptr);
412 412 ptr = (void*)((QVariant*)ptr)->constData();
413 413 }
414 414 }
415 415 break;
416 416 case QMetaType::QString:
417 417 {
418 418 QString str = PyObjGetString(obj, strict, ok);
419 419 if (ok) {
420 420 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str), ptr);
421 421 ptr = (void*)((QVariant*)ptr)->constData();
422 422 }
423 423 }
424 424 break;
425 425 case QMetaType::QStringList:
426 426 {
427 427 QStringList l = PyObjToStringList(obj, strict, ok);
428 428 if (ok) {
429 429 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(l), ptr);
430 430 ptr = (void*)((QVariant*)ptr)->constData();
431 431 }
432 432 }
433 433 break;
434 434
435 435 case PythonQtMethodInfo::Variant:
436 436 {
437 437 QVariant v = PyObjToQVariant(obj);
438 438 if (v.isValid()) {
439 439 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
440 440 }
441 441 }
442 442 break;
443 443 default:
444 444 {
445 445 if (info.typeId == PythonQtMethodInfo::Unknown) {
446 446 // check for enum case
447 447 if (PythonQtClassInfo::hasEnum(info.name, meta)) {
448 448 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
449 449 if (ok) {
450 450 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
451 451 return ptr;
452 452 } else {
453 453 return NULL;
454 454 }
455 455 }
456 456 }
457 457 if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
458 458 // check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant
459 459 if (info.name.startsWith("QList<")) {
460 460 QByteArray innerType = info.name.mid(6,info.name.length()-7);
461 461 if (innerType.endsWith("*")) {
462 462 innerType.truncate(innerType.length()-1);
463 463 static int id = QMetaType::type("QList<void*>");
464 464 if (!alreadyAllocatedCPPObject) {
465 465 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(id), ptr);
466 466 ptr = (void*)((QVariant*)ptr)->constData();
467 467 } else {
468 468 ptr = alreadyAllocatedCPPObject;
469 469 }
470 470 ok = ConvertPythonListToQListOfPointerType(obj, (QList<void*>*)ptr, innerType, strict);
471 471 if (ok) {
472 472 return ptr;
473 473 } else {
474 474 return NULL;
475 475 }
476 476 }
477 477 }
478 478 }
479 479
480 480 // We only do this for registered type > QMetaType::User for performance reasons.
481 481 if (info.typeId >= QMetaType::User) {
482 482 // Maybe we have a special converter that is registered for that type:
483 483 PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(info.typeId);
484 484 if (converter) {
485 485 if (!alreadyAllocatedCPPObject) {
486 486 // create a new empty variant of concrete type:
487 487 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
488 488 ptr = (void*)((QVariant*)ptr)->constData();
489 489 } else {
490 490 ptr = alreadyAllocatedCPPObject;
491 491 }
492 492 // now call the converter, passing the internal object of the variant
493 493 ok = (*converter)(obj, ptr, info.typeId, strict);
494 494 if (ok) {
495 495 return ptr;
496 496 } else {
497 497 return NULL;
498 498 }
499 499 }
500 500 }
501 501 // if no type id is available, conversion to a QVariant makes no sense/is not possible
502 502 if (info.typeId != PythonQtMethodInfo::Unknown) {
503 503 // for all other types, we use the same qvariant conversion and pass out the constData of the variant:
504 504 QVariant v = PyObjToQVariant(obj, info.typeId);
505 505 if (v.isValid()) {
506 506 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
507 507 ptr = (void*)((QVariant*)ptr)->constData();
508 508 }
509 509 }
510 510 }
511 511 }
512 512 }
513 513 return ptr;
514 514 }
515 515
516 516
517 517 QStringList PythonQtConv::PyObjToStringList(PyObject* val, bool strict, bool& ok) {
518 518 QStringList v;
519 519 ok = false;
520 520 // if we are strict, we do not want to convert a string to a stringlist
521 521 // (strings in python are detected to be sequences)
522 522 if (strict &&
523 523 (val->ob_type == &PyString_Type ||
524 524 PyUnicode_Check(val))) {
525 525 ok = false;
526 526 return v;
527 527 }
528 528 if (PySequence_Check(val)) {
529 529 int count = PySequence_Size(val);
530 530 for (int i = 0;i<count;i++) {
531 531 PyObject* value = PySequence_GetItem(val,i);
532 532 v.append(PyObjGetString(value,false,ok));
533 533 }
534 534 ok = true;
535 535 }
536 536 return v;
537 537 }
538 538
539 539 QString PythonQtConv::PyObjGetRepresentation(PyObject* val)
540 540 {
541 541 QString r;
542 542 PyObject* str = PyObject_Repr(val);
543 543 if (str) {
544 544 r = QString(PyString_AS_STRING(str));
545 545 Py_DECREF(str);
546 546 }
547 547 return r;
548 548 }
549 549
550 550 QString PythonQtConv::PyObjGetString(PyObject* val, bool strict, bool& ok) {
551 551 QString r;
552 552 ok = true;
553 553 if (val->ob_type == &PyString_Type) {
554 554 r = QString(PyString_AS_STRING(val));
555 555 } else if (PyUnicode_Check(val)) {
556 556 #ifdef WIN32
557 557 r = QString::fromUtf16(PyUnicode_AS_UNICODE(val));
558 558 #else
559 559 PyObject *ptmp = PyUnicode_AsUTF8String(val);
560 560 if(ptmp) {
561 561 r = QString::fromUtf8(PyString_AS_STRING(ptmp));
562 562 Py_DECREF(ptmp);
563 563 }
564 564 #endif
565 565 } else if (!strict) {
566 566 // EXTRA: could also use _Unicode, but why should we?
567 567 PyObject* str = PyObject_Str(val);
568 568 if (str) {
569 569 r = QString(PyString_AS_STRING(str));
570 570 Py_DECREF(str);
571 571 } else {
572 572 ok = false;
573 573 }
574 574 } else {
575 575 ok = false;
576 576 }
577 577 return r;
578 578 }
579 579
580 580 QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) {
581 581 QByteArray r;
582 582 ok = true;
583 583 if (val->ob_type == &PyString_Type) {
584 584 long size = PyString_GET_SIZE(val);
585 585 r = QByteArray(PyString_AS_STRING(val), size);
586 586 } else {
587 587 ok = false;
588 588 }
589 589 return r;
590 590 }
591 591
592 592 bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) {
593 593 bool d = false;
594 594 ok = false;
595 595 if (val == Py_False) {
596 596 d = false;
597 597 ok = true;
598 598 } else if (val == Py_True) {
599 599 d = true;
600 600 ok = true;
601 601 } else if (!strict) {
602 602 d = PyObjGetInt(val, false, ok)!=0;
603 603 ok = true;
604 604 }
605 605 return d;
606 606 }
607 607
608 608 int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) {
609 609 int d = 0;
610 610 ok = true;
611 611 if (val->ob_type == &PyInt_Type) {
612 612 d = PyInt_AS_LONG(val);
613 613 } else if (!strict) {
614 614 if (val->ob_type == &PyFloat_Type) {
615 615 d = floor(PyFloat_AS_DOUBLE(val));
616 616 } else if (val->ob_type == &PyLong_Type) {
617 617 // handle error on overflow!
618 618 d = PyLong_AsLong(val);
619 619 } else if (val == Py_False) {
620 620 d = 0;
621 621 } else if (val == Py_True) {
622 622 d = 1;
623 623 } else {
624 624 ok = false;
625 625 }
626 626 } else {
627 627 ok = false;
628 628 }
629 629 return d;
630 630 }
631 631
632 632 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
633 633 qint64 d = 0;
634 634 ok = true;
635 635 if (val->ob_type == &PyInt_Type) {
636 636 d = PyInt_AS_LONG(val);
637 637 } else if (val->ob_type == &PyLong_Type) {
638 638 d = PyLong_AsLongLong(val);
639 639 } else if (!strict) {
640 640 if (val->ob_type == &PyFloat_Type) {
641 641 d = floor(PyFloat_AS_DOUBLE(val));
642 642 } else if (val == Py_False) {
643 643 d = 0;
644 644 } else if (val == Py_True) {
645 645 d = 1;
646 646 } else {
647 647 ok = false;
648 648 }
649 649 } else {
650 650 ok = false;
651 651 }
652 652 return d;
653 653 }
654 654
655 655 quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) {
656 656 quint64 d = 0;
657 657 ok = true;
658 658 if (val->ob_type == &PyInt_Type) {
659 659 d = PyInt_AS_LONG(val);
660 660 } else if (val->ob_type == &PyLong_Type) {
661 661 d = PyLong_AsLongLong(val);
662 662 } else if (!strict) {
663 663 if (val->ob_type == &PyFloat_Type) {
664 664 d = floor(PyFloat_AS_DOUBLE(val));
665 665 } else if (val == Py_False) {
666 666 d = 0;
667 667 } else if (val == Py_True) {
668 668 d = 1;
669 669 } else {
670 670 ok = false;
671 671 }
672 672 } else {
673 673 ok = false;
674 674 }
675 675 return d;
676 676 }
677 677
678 678 double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) {
679 679 double d = 0;
680 680 ok = true;
681 681 if (val->ob_type == &PyFloat_Type) {
682 682 d = PyFloat_AS_DOUBLE(val);
683 683 } else if (!strict) {
684 684 if (val->ob_type == &PyInt_Type) {
685 685 d = PyInt_AS_LONG(val);
686 686 } else if (val->ob_type == &PyLong_Type) {
687 687 d = PyLong_AsLong(val);
688 688 } else if (val == Py_False) {
689 689 d = 0;
690 690 } else if (val == Py_True) {
691 691 d = 1;
692 692 } else {
693 693 ok = false;
694 694 }
695 695 } else {
696 696 ok = false;
697 697 }
698 698 return d;
699 699 }
700 700
701 701 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
702 702 {
703 703 QVariant v;
704 704 bool ok = true;
705 705
706 706 if (type==-1) {
707 707 // no special type requested
708 708 if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) {
709 709 type = QVariant::String;
710 710 } else if (val->ob_type==&PyInt_Type) {
711 711 type = QVariant::Int;
712 712 } else if (val->ob_type==&PyLong_Type) {
713 713 type = QVariant::LongLong;
714 714 } else if (val->ob_type==&PyFloat_Type) {
715 715 type = QVariant::Double;
716 716 } else if (val == Py_False || val == Py_True) {
717 717 type = QVariant::Bool;
718 718 } else if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
719 719 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
720 720 // c++ wrapper, check if the class names of the c++ objects match
721 721 if (wrap->classInfo()->isCPPWrapper()) {
722 722 if (wrap->classInfo()->metaTypeId()>0) {
723 723 // construct a new variant from the C++ object if it has a meta type (this will COPY the object!)
724 724 v = QVariant(wrap->classInfo()->metaTypeId(), wrap->_wrappedPtr);
725 725 } else {
726 726 // TODOXXX we could as well check if there is a registered meta type for "classname*", so that we may pass
727 727 // the pointer here...
728 728 // is this worth anything? we loose the knowledge of the cpp object type
729 729 v = qVariantFromValue(wrap->_wrappedPtr);
730 730 }
731 731 } else {
732 732 // this gives us a QObject pointer
733 733 QObject* myObject = wrap->_obj;
734 734 v = qVariantFromValue(myObject);
735 735 }
736 736 return v;
737 737 } else if (val->ob_type==&PyDict_Type) {
738 738 type = QVariant::Map;
739 739 } else if (val->ob_type==&PyList_Type || val->ob_type==&PyTuple_Type || PySequence_Check(val)) {
740 740 type = QVariant::List;
741 741 } else if (val == Py_None) {
742 742 // none is invalid
743 743 type = QVariant::Invalid;
744 744 } else {
745 745 // this used to be:
746 746 // type = QVariant::String;
747 747 // but now we want to transport the Python Objects directly:
748 748 PythonQtObjectPtr o(val);
749 749 v = qVariantFromValue(o);
750 750 return v;
751 751 }
752 752 }
753 753 // special type request:
754 754 switch (type) {
755 755 case QVariant::Invalid:
756 756 return v;
757 757 break;
758 758 case QVariant::Int:
759 759 {
760 760 int d = PyObjGetInt(val, false, ok);
761 761 if (ok) return QVariant(d);
762 762 }
763 763 break;
764 764 case QVariant::UInt:
765 765 {
766 766 int d = PyObjGetInt(val, false,ok);
767 767 if (ok) v = QVariant((unsigned int)d);
768 768 }
769 769 break;
770 770 case QVariant::Bool:
771 771 {
772 772 int d = PyObjGetBool(val,false,ok);
773 773 if (ok) v = QVariant((bool)(d!=0));
774 774 }
775 775 break;
776 776 case QVariant::Double:
777 777 {
778 778 double d = PyObjGetDouble(val,false,ok);
779 779 if (ok) v = QVariant(d);
780 780 break;
781 781 }
782 782 case QMetaType::Float:
783 783 {
784 784 float d = (float) PyObjGetDouble(val,false,ok);
785 785 if (ok) v = qVariantFromValue(d);
786 786 break;
787 787 }
788 788 case QMetaType::Long:
789 789 {
790 790 long d = (long) PyObjGetLongLong(val,false,ok);
791 791 if (ok) v = qVariantFromValue(d);
792 792 break;
793 793 }
794 794 case QMetaType::ULong:
795 795 {
796 796 unsigned long d = (unsigned long) PyObjGetLongLong(val,false,ok);
797 797 if (ok) v = qVariantFromValue(d);
798 798 break;
799 799 }
800 800 case QMetaType::Short:
801 801 {
802 802 short d = (short) PyObjGetInt(val,false,ok);
803 803 if (ok) v = qVariantFromValue(d);
804 804 break;
805 805 }
806 806 case QMetaType::UShort:
807 807 {
808 808 unsigned short d = (unsigned short) PyObjGetInt(val,false,ok);
809 809 if (ok) v = qVariantFromValue(d);
810 810 break;
811 811 }
812 812 case QMetaType::Char:
813 813 {
814 814 char d = (char) PyObjGetInt(val,false,ok);
815 815 if (ok) v = qVariantFromValue(d);
816 816 break;
817 817 }
818 818 case QMetaType::UChar:
819 819 {
820 820 unsigned char d = (unsigned char) PyObjGetInt(val,false,ok);
821 821 if (ok) v = qVariantFromValue(d);
822 822 break;
823 823 }
824 824
825 825 case QVariant::ByteArray:
826 826 case QVariant::String:
827 827 {
828 828 bool ok;
829 829 v = QVariant(PyObjGetString(val, false, ok));
830 830 }
831 831 break;
832 832
833 833 // these are important for MeVisLab
834 834 case QVariant::Map:
835 835 {
836 836 if (PyMapping_Check(val)) {
837 837 QMap<QString,QVariant> map;
838 838 PyObject* items = PyMapping_Items(val);
839 839 if (items) {
840 840 int count = PyList_Size(items);
841 841 PyObject* value;
842 842 PyObject* key;
843 843 PyObject* tuple;
844 844 for (int i = 0;i<count;i++) {
845 845 tuple = PyList_GetItem(items,i);
846 846 key = PyTuple_GetItem(tuple, 0);
847 847 value = PyTuple_GetItem(tuple, 1);
848 848 map.insert(PyObjGetString(key), PyObjToQVariant(value,-1));
849 849 }
850 850 Py_DECREF(items);
851 851 v = map;
852 852 }
853 853 }
854 854 }
855 855 break;
856 856 case QVariant::List:
857 857 if (PySequence_Check(val)) {
858 858 QVariantList list;
859 859 int count = PySequence_Size(val);
860 860 PyObject* value;
861 861 for (int i = 0;i<count;i++) {
862 862 value = PySequence_GetItem(val,i);
863 863 list.append(PyObjToQVariant(value, -1));
864 864 }
865 865 v = list;
866 866 }
867 867 break;
868 868 case QVariant::StringList:
869 869 {
870 870 bool ok;
871 871 QStringList l = PyObjToStringList(val, false, ok);
872 872 if (ok) {
873 873 v = l;
874 874 }
875 875 }
876 876 break;
877 877
878 878 default:
879 879 if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
880 880 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
881 881 if (wrap->classInfo()->isCPPWrapper() && wrap->classInfo()->metaTypeId() == type) {
882 882 // construct a new variant from the C++ object if it has the same meta type
883 883 v = QVariant(type, wrap->_wrappedPtr);
884 884 } else {
885 885 v = QVariant();
886 886 }
887 887 } else {
888 888 v = QVariant();
889 889 }
890 890 }
891 891 return v;
892 892 }
893 893
894 894 PyObject* PythonQtConv::QStringToPyObject(const QString& str)
895 895 {
896 896 if (str.isNull()) {
897 897 return PyString_FromString("");
898 898 } else {
899 899 #ifdef WIN32
900 900 // return PyString_FromString(str.toLatin1().data());
901 901 return PyUnicode_FromUnicode(str.utf16(), str.length());
902 902 #else
903 903 return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, NULL, NULL);
904 904 #endif
905 905 }
906 906 }
907 907
908 908 PyObject* PythonQtConv::QStringListToPyObject(const QStringList& list)
909 909 {
910 910 PyObject* result = PyTuple_New(list.count());
911 911 int i = 0;
912 912 QString str;
913 913 foreach (str, list) {
914 914 PyTuple_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(str));
915 915 i++;
916 916 }
917 917 // why is the error state bad after this?
918 918 PyErr_Clear();
919 919 return result;
920 920 }
921 921
922 922 PyObject* PythonQtConv::QStringListToPyList(const QStringList& list)
923 923 {
924 924 PyObject* result = PyList_New(list.count());
925 925 int i = 0;
926 926 for (QStringList::ConstIterator it = list.begin(); it!=list.end(); ++it) {
927 927 PyList_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(*it));
928 928 i++;
929 929 }
930 930 return result;
931 931 }
932 932
933 933 PyObject* PythonQtConv::QVariantToPyObject(const QVariant& v)
934 934 {
935 935 return ConvertQtValueToPythonInternal(v.userType(), (void*)v.constData());
936 936 }
937 937
938 938 PyObject* PythonQtConv::QVariantMapToPyObject(const QVariantMap& m) {
939 939 PyObject* result = PyDict_New();
940 940 QVariantMap::const_iterator t = m.constBegin();
941 941 PyObject* key;
942 942 PyObject* val;
943 943 for (;t!=m.end();t++) {
944 944 key = QStringToPyObject(t.key());
945 945 val = QVariantToPyObject(t.value());
946 946 PyDict_SetItem(result, key, val);
947 947 Py_DECREF(key);
948 948 Py_DECREF(val);
949 949 }
950 950 return result;
951 951 }
952 952
953 953 PyObject* PythonQtConv::QVariantListToPyObject(const QVariantList& l) {
954 954 PyObject* result = PyTuple_New(l.count());
955 955 int i = 0;
956 956 QVariant v;
957 957 foreach (v, l) {
958 958 PyTuple_SET_ITEM(result, i, PythonQtConv::QVariantToPyObject(v));
959 959 i++;
960 960 }
961 961 // why is the error state bad after this?
962 962 PyErr_Clear();
963 963 return result;
964 964 }
965 965
966 966 PyObject* PythonQtConv::ConvertQListOfPointerTypeToPythonList(QList<void*>* list, const QByteArray& typeName)
967 967 {
968 968 PyObject* result = PyTuple_New(list->count());
969 969 int i = 0;
970 970 foreach (void* value, *list) {
971 971 PyTuple_SET_ITEM(result, i, PythonQt::priv()->wrapPtr(value, typeName));
972 972 i++;
973 973 }
974 974 return result;
975 975 }
976 976
977 977 bool PythonQtConv::ConvertPythonListToQListOfPointerType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool /*strict*/)
978 978 {
979 979 bool result = false;
980 980 if (PySequence_Check(obj)) {
981 981 result = true;
982 982 int count = PySequence_Size(obj);
983 983 PyObject* value;
984 984 for (int i = 0;i<count;i++) {
985 985 value = PySequence_GetItem(obj,i);
986 986 if (PyObject_TypeCheck(value, &PythonQtInstanceWrapper_Type)) {
987 987 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)value;
988 988 bool ok;
989 989 void* object = castWrapperTo(wrap, type, ok);
990 990 if (ok) {
991 991 list->append(object);
992 992 } else {
993 993 result = false;
994 994 break;
995 995 }
996 996 }
997 997 }
998 998 }
999 999 return result;
1000 1000 }
1001 1001
1002 1002 int PythonQtConv::getInnerTemplateMetaType(const QByteArray& typeName)
1003 1003 {
1004 1004 int idx = typeName.indexOf("<");
1005 1005 if (idx>0) {
1006 1006 int idx2 = typeName.indexOf(">");
1007 1007 if (idx2>0) {
1008 1008 QByteArray innerType = typeName.mid(idx+1,idx2-idx-1);
1009 1009 return QMetaType::type(innerType.constData());
1010 1010 }
1011 1011 }
1012 1012 return QMetaType::Void;
1013 1013 }
1014 1014
1015 1015
1016 1016
1017 1017 QString PythonQtConv::qVariantToString(const QVariant& v) {
1018 1018 return CPPObjectToString(v.userType(), v.constData());
1019 1019 }
1020 1020
1021 1021 QString PythonQtConv::CPPObjectToString(int type, const void* data) {
1022 1022 QString r;
1023 1023 switch (type) {
1024 1024 case QVariant::Size: {
1025 1025 const QSize* s = static_cast<const QSize*>(data);
1026 1026 r = QString::number(s->width()) + ", " + QString::number(s->height());
1027 1027 }
1028 1028 break;
1029 1029 case QVariant::SizeF: {
1030 1030 const QSizeF* s = static_cast<const QSizeF*>(data);
1031 1031 r = QString::number(s->width()) + ", " + QString::number(s->height());
1032 1032 }
1033 1033 break;
1034 1034 case QVariant::Point: {
1035 1035 const QPoint* s = static_cast<const QPoint*>(data);
1036 1036 r = QString::number(s->x()) + ", " + QString::number(s->y());
1037 1037 }
1038 1038 break;
1039 1039 case QVariant::PointF: {
1040 1040 const QPointF* s = static_cast<const QPointF*>(data);
1041 1041 r = QString::number(s->x()) + ", " + QString::number(s->y());
1042 1042 }
1043 1043 break;
1044 1044 case QVariant::Rect: {
1045 1045 const QRect* s = static_cast<const QRect*>(data);
1046 1046 r = QString::number(s->x()) + ", " + QString::number(s->y());
1047 1047 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1048 1048 }
1049 1049 break;
1050 1050 case QVariant::RectF: {
1051 1051 const QRectF* s = static_cast<const QRectF*>(data);
1052 1052 r = QString::number(s->x()) + ", " + QString::number(s->y());
1053 1053 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1054 1054 }
1055 1055 break;
1056 1056 case QVariant::Date: {
1057 1057 const QDate* s = static_cast<const QDate*>(data);
1058 1058 r = s->toString(Qt::ISODate);
1059 1059 }
1060 1060 break;
1061 1061 case QVariant::DateTime: {
1062 1062 const QDateTime* s = static_cast<const QDateTime*>(data);
1063 1063 r = s->toString(Qt::ISODate);
1064 1064 }
1065 1065 break;
1066 1066 case QVariant::Time: {
1067 1067 const QTime* s = static_cast<const QTime*>(data);
1068 1068 r = s->toString(Qt::ISODate);
1069 1069 }
1070 1070 break;
1071 1071 case QVariant::Pixmap:
1072 1072 {
1073 1073 const QPixmap* s = static_cast<const QPixmap*>(data);
1074 1074 r = QString("Pixmap ") + QString::number(s->width()) + ", " + QString::number(s->height());
1075 1075 }
1076 1076 break;
1077 1077 case QVariant::Image:
1078 1078 {
1079 1079 const QImage* s = static_cast<const QImage*>(data);
1080 1080 r = QString("Image ") + QString::number(s->width()) + ", " + QString::number(s->height());
1081 1081 }
1082 1082 break;
1083 1083 case QVariant::Url:
1084 1084 {
1085 1085 const QUrl* s = static_cast<const QUrl*>(data);
1086 1086 r = s->toString();
1087 1087 }
1088 1088 break;
1089 1089 //TODO: add more printing for other variant types
1090 1090 default:
1091 1091 // this creates a copy, but that should not be expensive for typical simple variants
1092 1092 // (but we do not want to do this for our won user types!
1093 1093 if (type>0 && type < (int)QVariant::UserType) {
1094 1094 QVariant v(type, data);
1095 1095 r = v.toString();
1096 1096 }
1097 1097 }
1098 1098 return r;
1099 1099 }
@@ -1,495 +1,498
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 53 bool PythonQtCallSlot(PythonQtClassInfo* classInfo, 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 57 if (directReturnValuePointer) {
58 58 *directReturnValuePointer = NULL;
59 59 }
60 60 // store the current storage position, so that we can get back to this state after a slot is called
61 61 // (do this locally, so that we have all positions on the stack
62 62 PythonQtValueStoragePosition globalValueStoragePos;
63 63 PythonQtValueStoragePosition globalPtrStoragePos;
64 64 PythonQtValueStoragePosition globalVariantStoragePos;
65 65 PythonQtConv::global_valueStorage.getPos(globalValueStoragePos);
66 66 PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos);
67 67 PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos);
68 68
69 69 recursiveEntry++;
70 70
71 71 // the arguments that are passed to qt_metacall
72 72 void* argList[PYTHONQT_MAX_ARGS];
73 73 PyObject* result = NULL;
74 74 int argc = info->parameterCount();
75 75 const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters();
76 76
77 77 bool returnValueIsEnum = false;
78 78 const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);
79 79 // set return argument to NULL
80 80 argList[0] = NULL;
81
82 if (returnValueParam.typeId != QMetaType::Void) {
83 // extra handling of enum return value
84 if (!returnValueParam.isPointer && returnValueParam.typeId == PythonQtMethodInfo::Unknown) {
85 returnValueIsEnum = PythonQtClassInfo::hasEnum(returnValueParam.name, classInfo);
86 if (returnValueIsEnum) {
87 // create enum return value
88 PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, argList[0]);
89 }
90 }
91 if (argList[0]==NULL) {
92 // create empty default value for the return value
93 if (!directReturnValuePointer) {
94 // create empty default value for the return value
95 argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);
96 } else {
97 // we can use our pointer directly!
98 argList[0] = directReturnValuePointer;
99 }
100 }
101 }
102 81
103 82 bool ok = true;
104 83 bool skipFirst = false;
105 84 if (info->isInstanceDecorator()) {
106 85 skipFirst = true;
107 86
108 87 // for decorators on CPP objects, we take the cpp ptr, for QObjects we take the QObject pointer
109 88 void* arg1 = firstArgument;
110 89 if (!arg1) {
111 90 arg1 = objectToCall;
112 91 }
113 92 if (arg1) {
114 93 // upcast to correct parent class
115 94 arg1 = ((char*)arg1)+info->upcastingOffset();
116 95 }
117 96
118 97 argList[1] = &arg1;
119 98 if (ok) {
120 99 for (int i = 2; i<argc && ok; i++) {
121 100 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
122 101 //std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
123 102 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, classInfo);
124 103 if (argList[i]==NULL) {
125 104 ok = false;
126 105 break;
127 106 }
128 107 }
129 108 }
130 109 } else {
131 110 for (int i = 1; i<argc && ok; i++) {
132 111 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
133 112 //std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
134 113 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, classInfo);
135 114 if (argList[i]==NULL) {
136 115 ok = false;
137 116 break;
138 117 }
139 118 }
140 119 }
141 120
142 121 if (ok) {
122 // parameters are ok, now create the qt return value which is assigned to by metacall
123 if (returnValueParam.typeId != QMetaType::Void) {
124 // extra handling of enum return value
125 if (!returnValueParam.isPointer && returnValueParam.typeId == PythonQtMethodInfo::Unknown) {
126 returnValueIsEnum = PythonQtClassInfo::hasEnum(returnValueParam.name, classInfo);
127 if (returnValueIsEnum) {
128 // create enum return value
129 PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, argList[0]);
130 }
131 }
132 if (argList[0]==NULL) {
133 // create empty default value for the return value
134 if (!directReturnValuePointer) {
135 // create empty default value for the return value
136 argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);
137 } else {
138 // we can use our pointer directly!
139 argList[0] = directReturnValuePointer;
140 }
141 }
142 }
143
144 // invoke the slot via metacall
143 145 (info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
144
146
147 // handle the return value (which in most cases still needs to be converted to a Python object)
145 148 if (argList[0] || returnValueParam.typeId == QMetaType::Void) {
146 149 if (directReturnValuePointer) {
147 150 result = NULL;
148 151 } else {
149 152 if (!returnValueIsEnum) {
150 153 result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]);
151 154 } else {
152 155 result = PyInt_FromLong(*((unsigned int*)argList[0]));
153 156 }
154 157 }
155 158 } else {
156 QString e = QString("Called ") + info->fullSignature() + ", return type is ignored because it is unknown to PythonQt.";
159 QString e = QString("Called ") + info->fullSignature() + ", return type '" + returnValueParam.name + "' is ignored because it is unknown to PythonQt. Probaby you should register it using qRegisterMetaType().";
157 160 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
158 161 result = NULL;
159 162 }
160 163 }
161 164 recursiveEntry--;
162 165
163 166 // reset the parameter storage position to the stored pos to "pop" the parameter stack
164 167 PythonQtConv::global_valueStorage.setPos(globalValueStoragePos);
165 168 PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos);
166 169 PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos);
167 170
168 171 *pythonReturnValue = result;
169 172 // NOTE: it is important to only return here, otherwise the stack will not be popped!!!
170 173 return result || (directReturnValuePointer && *directReturnValuePointer);
171 174 }
172 175
173 176 //-----------------------------------------------------------------------------------
174 177
175 178 static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL;
176 179
177 180 PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw)
178 181 {
179 182 PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func;
180 183 PythonQtSlotInfo* info = f->m_ml;
181 184 if (PyObject_TypeCheck(f->m_self, &PythonQtInstanceWrapper_Type)) {
182 185 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self;
183 186 return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr);
184 187 } else if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
185 188 PythonQtClassWrapper* type = (PythonQtClassWrapper*) f->m_self;
186 189 if (info->isClassDecorator()) {
187 190 return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw);
188 191 } else {
189 192 // otherwise, it is an unbound call and we have an instanceDecorator or normal slot...
190 193 Py_ssize_t argc = PyTuple_Size(args);
191 194 if (argc>0) {
192 195 PyObject* firstArg = PyTuple_GET_ITEM(args, 0);
193 196 if (PyObject_TypeCheck(firstArg, (PyTypeObject*)&PythonQtInstanceWrapper_Type)
194 197 && ((PythonQtInstanceWrapper*)firstArg)->classInfo()->inherits(type->classInfo())) {
195 198 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg;
196 199 // strip the first argument...
197 200 PyObject* newargs = PyTuple_GetSlice(args, 1, argc);
198 201 PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, newargs, kw, self->_wrappedPtr);
199 202 Py_DECREF(newargs);
200 203 return result;
201 204 } else {
202 205 // first arg is not of correct type!
203 206 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument, got " + firstArg->ob_type->tp_name;
204 207 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
205 208 return NULL;
206 209 }
207 210 } else {
208 211 // wrong number of args
209 212 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument.";
210 213 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
211 214 return NULL;
212 215 }
213 216 }
214 217 }
215 218 return NULL;
216 219 }
217 220
218 221 PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg, void** directReturnValuePointer)
219 222 {
220 223 int argc = PyTuple_Size(args);
221 224
222 225 #ifdef PYTHONQT_DEBUG
223 226 std::cout << "called " << info->metaMethod()->typeName() << " " << info->metaMethod()->signature() << std::endl;
224 227 #endif
225 228
226 229 PyObject* r = NULL;
227 230 bool ok = false;
228 231 if (directReturnValuePointer) {
229 232 *directReturnValuePointer = NULL;
230 233 }
231 234 if (info->nextInfo()) {
232 235 // overloaded slot call, try on all slots with strict conversion first
233 236 bool strict = true;
234 237 PythonQtSlotInfo* i = info;
235 238 while (i) {
236 239 bool skipFirst = i->isInstanceDecorator();
237 240 if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
238 241 PyErr_Clear();
239 242 ok = PythonQtCallSlot(classInfo, objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer);
240 243 if (PyErr_Occurred() || ok) break;
241 244 }
242 245 i = i->nextInfo();
243 246 if (!i) {
244 247 if (strict) {
245 248 // one more run without being strict
246 249 strict = false;
247 250 i = info;
248 251 }
249 252 }
250 253 }
251 254 if (!ok && !PyErr_Occurred()) {
252 255 QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n");
253 256 PythonQtSlotInfo* i = info;
254 257 while (i) {
255 258 e += QString(i->fullSignature()) + "\n";
256 259 i = i->nextInfo();
257 260 }
258 261 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
259 262 }
260 263 } else {
261 264 // simple (non-overloaded) slot call
262 265 bool skipFirst = info->isInstanceDecorator();
263 266 if (info->parameterCount()-1-(skipFirst?1:0) == argc) {
264 267 PyErr_Clear();
265 268 ok = PythonQtCallSlot(classInfo, objectToCall, args, false, info, firstArg, &r, directReturnValuePointer);
266 269 if (!ok && !PyErr_Occurred()) {
267 270 QString e = QString("Called ") + info->fullSignature() + " with wrong arguments: " + PythonQtConv::PyObjGetString(args);
268 271 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
269 272 }
270 273 } else {
271 274 QString e = QString("Called ") + info->fullSignature() + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args);
272 275 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
273 276 }
274 277 }
275 278
276 279 return r;
277 280 }
278 281
279 282 PyObject *
280 283 PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module)
281 284 {
282 285 PythonQtSlotFunctionObject *op;
283 286 op = pythonqtslot_free_list;
284 287 if (op != NULL) {
285 288 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self);
286 289 PyObject_INIT(op, &PythonQtSlotFunction_Type);
287 290 }
288 291 else {
289 292 op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type);
290 293 if (op == NULL)
291 294 return NULL;
292 295 }
293 296 op->m_ml = ml;
294 297 Py_XINCREF(self);
295 298 op->m_self = self;
296 299 Py_XINCREF(module);
297 300 op->m_module = module;
298 301 PyObject_GC_Track(op);
299 302 return (PyObject *)op;
300 303 }
301 304
302 305 PythonQtSlotInfo*
303 306 PythonQtSlotFunction_GetSlotInfo(PyObject *op)
304 307 {
305 308 if (!PythonQtSlotFunction_Check(op)) {
306 309 PyErr_BadInternalCall();
307 310 return NULL;
308 311 }
309 312 return ((PythonQtSlotFunctionObject *)op) -> m_ml;
310 313 }
311 314
312 315 PyObject *
313 316 PythonQtSlotFunction_GetSelf(PyObject *op)
314 317 {
315 318 if (!PythonQtSlotFunction_Check(op)) {
316 319 PyErr_BadInternalCall();
317 320 return NULL;
318 321 }
319 322 return ((PythonQtSlotFunctionObject *)op) -> m_self;
320 323 }
321 324
322 325 /* Methods (the standard built-in methods, that is) */
323 326
324 327 static void
325 328 meth_dealloc(PythonQtSlotFunctionObject *m)
326 329 {
327 330 PyObject_GC_UnTrack(m);
328 331 Py_XDECREF(m->m_self);
329 332 Py_XDECREF(m->m_module);
330 333 m->m_self = (PyObject *)pythonqtslot_free_list;
331 334 pythonqtslot_free_list = m;
332 335 }
333 336
334 337 static PyObject *
335 338 meth_get__doc__(PythonQtSlotFunctionObject * /*m*/, void * /*closure*/)
336 339 {
337 340 Py_INCREF(Py_None);
338 341 return Py_None;
339 342 }
340 343
341 344 static PyObject *
342 345 meth_get__name__(PythonQtSlotFunctionObject *m, void * /*closure*/)
343 346 {
344 347 return PyString_FromString(m->m_ml->metaMethod()->signature());
345 348 }
346 349
347 350 static int
348 351 meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg)
349 352 {
350 353 int err;
351 354 if (m->m_self != NULL) {
352 355 err = visit(m->m_self, arg);
353 356 if (err)
354 357 return err;
355 358 }
356 359 if (m->m_module != NULL) {
357 360 err = visit(m->m_module, arg);
358 361 if (err)
359 362 return err;
360 363 }
361 364 return 0;
362 365 }
363 366
364 367 static PyObject *
365 368 meth_get__self__(PythonQtSlotFunctionObject *m, void * /*closure*/)
366 369 {
367 370 PyObject *self;
368 371 if (PyEval_GetRestricted()) {
369 372 PyErr_SetString(PyExc_RuntimeError,
370 373 "method.__self__ not accessible in restricted mode");
371 374 return NULL;
372 375 }
373 376 self = m->m_self;
374 377 if (self == NULL)
375 378 self = Py_None;
376 379 Py_INCREF(self);
377 380 return self;
378 381 }
379 382
380 383 static PyGetSetDef meth_getsets [] = {
381 384 {"__doc__", (getter)meth_get__doc__, NULL, NULL},
382 385 {"__name__", (getter)meth_get__name__, NULL, NULL},
383 386 {"__self__", (getter)meth_get__self__, NULL, NULL},
384 387 {NULL, NULL, NULL,NULL},
385 388 };
386 389
387 390 #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6
388 391 #define PY_WRITE_RESTRICTED WRITE_RESTRICTED
389 392 #endif
390 393
391 394 #define OFF(x) offsetof(PythonQtSlotFunctionObject, x)
392 395
393 396 static PyMemberDef meth_members[] = {
394 397 {"__module__", T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED},
395 398 {NULL}
396 399 };
397 400
398 401 static PyObject *
399 402 meth_repr(PythonQtSlotFunctionObject *f)
400 403 {
401 404 if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
402 405 PythonQtClassWrapper* self = (PythonQtClassWrapper*) f->m_self;
403 406 return PyString_FromFormat("<unbound qt slot %s of %s type>",
404 407 f->m_ml->slotName().data(),
405 408 self->classInfo()->className());
406 409 } else {
407 410 return PyString_FromFormat("<qt slot %s of %s instance at %p>",
408 411 f->m_ml->slotName().data(),
409 412 f->m_self->ob_type->tp_name,
410 413 f->m_self);
411 414 }
412 415 }
413 416
414 417 static int
415 418 meth_compare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b)
416 419 {
417 420 if (a->m_self != b->m_self)
418 421 return (a->m_self < b->m_self) ? -1 : 1;
419 422 if (a->m_ml == b->m_ml)
420 423 return 0;
421 424 if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0)
422 425 return -1;
423 426 else
424 427 return 1;
425 428 }
426 429
427 430 static long
428 431 meth_hash(PythonQtSlotFunctionObject *a)
429 432 {
430 433 long x,y;
431 434 if (a->m_self == NULL)
432 435 x = 0;
433 436 else {
434 437 x = PyObject_Hash(a->m_self);
435 438 if (x == -1)
436 439 return -1;
437 440 }
438 441 y = _Py_HashPointer((void*)(a->m_ml));
439 442 if (y == -1)
440 443 return -1;
441 444 x ^= y;
442 445 if (x == -1)
443 446 x = -2;
444 447 return x;
445 448 }
446 449
447 450
448 451 PyTypeObject PythonQtSlotFunction_Type = {
449 452 PyObject_HEAD_INIT(&PyType_Type)
450 453 0,
451 454 "builtin_qt_slot",
452 455 sizeof(PythonQtSlotFunctionObject),
453 456 0,
454 457 (destructor)meth_dealloc, /* tp_dealloc */
455 458 0, /* tp_print */
456 459 0, /* tp_getattr */
457 460 0, /* tp_setattr */
458 461 (cmpfunc)meth_compare, /* tp_compare */
459 462 (reprfunc)meth_repr, /* tp_repr */
460 463 0, /* tp_as_number */
461 464 0, /* tp_as_sequence */
462 465 0, /* tp_as_mapping */
463 466 (hashfunc)meth_hash, /* tp_hash */
464 467 PythonQtSlotFunction_Call, /* tp_call */
465 468 0, /* tp_str */
466 469 PyObject_GenericGetAttr, /* tp_getattro */
467 470 0, /* tp_setattro */
468 471 0, /* tp_as_buffer */
469 472 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
470 473 0, /* tp_doc */
471 474 (traverseproc)meth_traverse, /* tp_traverse */
472 475 0, /* tp_clear */
473 476 0, /* tp_richcompare */
474 477 0, /* tp_weaklistoffset */
475 478 0, /* tp_iter */
476 479 0, /* tp_iternext */
477 480 0, /* tp_methods */
478 481 meth_members, /* tp_members */
479 482 meth_getsets, /* tp_getset */
480 483 0, /* tp_base */
481 484 0, /* tp_dict */
482 485 };
483 486
484 487 /* Clear out the free list */
485 488
486 489 void
487 490 PythonQtSlotFunction_Fini(void)
488 491 {
489 492 while (pythonqtslot_free_list) {
490 493 PythonQtSlotFunctionObject *v = pythonqtslot_free_list;
491 494 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(v->m_self);
492 495 PyObject_GC_Del(v);
493 496 }
494 497 }
495 498
General Comments 0
You need to be logged in to leave comments. Login now