##// END OF EJS Templates
- fixed support for QList<AnyObject*>* (which occured with QObjectList* return values)...
florianlink -
r77:0b14472ff76a
parent child
Show More
@@ -1,1213 +1,1218
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 // is it an enum value?
64 64 if (info.enumWrapper) {
65 65 if (!info.isPointer) {
66 66 return PythonQtPrivate::createEnumValueInstance(info.enumWrapper, *((unsigned int*)data));
67 67 } else {
68 68 // we do not support pointers to enums (who needs them?)
69 69 Py_INCREF(Py_None);
70 70 return Py_None;
71 71 }
72 72 }
73 73
74 74 if (info.typeId == QMetaType::Void) {
75 75 Py_INCREF(Py_None);
76 76 return Py_None;
77 77 } else if (info.isPointer && (info.typeId == QMetaType::Char)) {
78 78 // a char ptr will probably be a null terminated string, so we support that:
79 79 return PyString_FromString(*((char**)data));
80 80 } else if ((info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) &&
81 81 info.name.startsWith("QList<")) {
82 82 // it is a QList template:
83 // (TODO: check what happens if this is a pointer type?!)
84 83 QByteArray innerType = info.name.mid(6,info.name.length()-7);
85 84 if (innerType.endsWith("*")) {
86 85 innerType.truncate(innerType.length()-1);
87 return ConvertQListOfPointerTypeToPythonList((QList<void*>*)data, innerType);
86 QList<void*>* listPtr;
87 if (info.isPointer) {
88 listPtr = *((QList<void*>**)data);
89 } else {
90 listPtr = (QList<void*>*)data;
91 }
92 return ConvertQListOfPointerTypeToPythonList(listPtr, innerType);
88 93 }
89 94 }
90 95
91 96 if (info.typeId >= QMetaType::User) {
92 97 // if a converter is registered, we use is:
93 98 PythonQtConvertMetaTypeToPythonCB* converter = _metaTypeToPythonConverters.value(info.typeId);
94 99 if (converter) {
95 100 return (*converter)(data, info.typeId);
96 101 }
97 102 }
98 103
99 104 // special handling did not match, so we convert the usual way (either pointer or value version):
100 105 if (info.isPointer) {
101 106 // 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)
102 107 return PythonQt::priv()->wrapPtr(*((void**)data), info.name);
103 108 } else {
104 109 // handle values that are not yet handled and not pointers
105 110 return ConvertQtValueToPythonInternal(info.typeId, data);
106 111 }
107 112 }
108 113
109 114 PyObject* PythonQtConv::ConvertQtValueToPythonInternal(int type, const void* data) {
110 115 switch (type) {
111 116 case QMetaType::Void:
112 117 Py_INCREF(Py_None);
113 118 return Py_None;
114 119 case QMetaType::Char:
115 120 return PyInt_FromLong(*((char*)data));
116 121 case QMetaType::UChar:
117 122 return PyInt_FromLong(*((unsigned char*)data));
118 123 case QMetaType::Short:
119 124 return PyInt_FromLong(*((short*)data));
120 125 case QMetaType::UShort:
121 126 return PyInt_FromLong(*((unsigned short*)data));
122 127 case QMetaType::Long:
123 128 return PyInt_FromLong(*((long*)data));
124 129 case QMetaType::ULong:
125 130 // does not fit into simple int of python
126 131 return PyLong_FromUnsignedLong(*((unsigned long*)data));
127 132 case QMetaType::Bool:
128 133 return PythonQtConv::GetPyBool(*((bool*)data));
129 134 case QMetaType::Int:
130 135 return PyInt_FromLong(*((int*)data));
131 136 case QMetaType::UInt:
132 137 return PyInt_FromLong(*((unsigned int*)data));
133 138 case QMetaType::QChar:
134 139 return PyInt_FromLong(*((short*)data));
135 140 case QMetaType::Float:
136 141 return PyFloat_FromDouble(*((float*)data));
137 142 case QMetaType::Double:
138 143 return PyFloat_FromDouble(*((double*)data));
139 144 case QMetaType::LongLong:
140 145 return PyLong_FromLongLong(*((qint64*)data));
141 146 case QMetaType::ULongLong:
142 147 return PyLong_FromUnsignedLongLong(*((quint64*)data));
143 148 case QMetaType::QByteArray: {
144 149 QByteArray* v = (QByteArray*) data;
145 150 return PyString_FromStringAndSize(*v, v->size());
146 151 }
147 152 case QMetaType::QVariantMap:
148 153 return PythonQtConv::QVariantMapToPyObject(*((QVariantMap*)data));
149 154 case QMetaType::QVariantList:
150 155 return PythonQtConv::QVariantListToPyObject(*((QVariantList*)data));
151 156 case QMetaType::QString:
152 157 return PythonQtConv::QStringToPyObject(*((QString*)data));
153 158 case QMetaType::QStringList:
154 159 return PythonQtConv::QStringListToPyObject(*((QStringList*)data));
155 160
156 161 case PythonQtMethodInfo::Variant:
157 162 return PythonQtConv::QVariantToPyObject(*((QVariant*)data));
158 163 case QMetaType::QObjectStar:
159 164 case QMetaType::QWidgetStar:
160 165 return PythonQt::priv()->wrapQObject(*((QObject**)data));
161 166
162 167 default:
163 168 if (PythonQt::priv()->isPythonQtObjectPtrMetaId(type)) {
164 169 // special case, it is a PythonQtObjectPtr which contains a PyObject, take it directly:
165 170 PyObject* o = ((PythonQtObjectPtr*)data)->object();
166 171 Py_INCREF(o);
167 172 return o;
168 173 } else {
169 174 if (type > 0) {
170 175 // if the type is known, we can construct it via QMetaType::construct
171 176 void* newCPPObject = QMetaType::construct(type, data);
172 177 // XXX this could be optimized by using metatypeid directly
173 178 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)PythonQt::priv()->wrapPtr(newCPPObject, QMetaType::typeName(type));
174 179 wrap->_ownedByPythonQt = true;
175 180 wrap->_useQMetaTypeDestroy = true;
176 181 return (PyObject*)wrap;
177 182 }
178 183 std::cerr << "Unknown type that can not be converted to Python: " << type << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
179 184 }
180 185 }
181 186 Py_INCREF(Py_None);
182 187 return Py_None;
183 188 }
184 189
185 190 void* PythonQtConv::CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info) {
186 191 void* ptr = NULL;
187 192 if (info.isPointer) {
188 193 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
189 194 } else if (info.enumWrapper) {
190 195 // create enum return value
191 196 PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, ptr);
192 197 } else {
193 198 switch (info.typeId) {
194 199 case QMetaType::Char:
195 200 case QMetaType::UChar:
196 201 case QMetaType::Short:
197 202 case QMetaType::UShort:
198 203 case QMetaType::Long:
199 204 case QMetaType::ULong:
200 205 case QMetaType::Bool:
201 206 case QMetaType::Int:
202 207 case QMetaType::UInt:
203 208 case QMetaType::QChar:
204 209 case QMetaType::Float:
205 210 case QMetaType::Double:
206 211 PythonQtValueStorage_ADD_VALUE(global_valueStorage, long, 0, ptr);
207 212 break;
208 213 case PythonQtMethodInfo::Variant:
209 214 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, 0, ptr);
210 215 // return the ptr to the variant
211 216 break;
212 217 default:
213 218 if (info.typeId == PythonQtMethodInfo::Unknown) {
214 219 // check if we have a QList of pointers, which we can circumvent with a QList<void*>
215 220 if (info.name.startsWith("QList<")) {
216 221 QByteArray innerType = info.name.mid(6,info.name.length()-7);
217 222 if (innerType.endsWith("*")) {
218 223 static int id = QMetaType::type("QList<void*>");
219 224 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr);
220 225 // return the constData pointer that will be filled with the result value later on
221 226 ptr = (void*)((QVariant*)ptr)->constData();
222 227 }
223 228 }
224 229 }
225 230
226 231 if (!ptr && info.typeId!=PythonQtMethodInfo::Unknown) {
227 232 // everything else is stored in a QVariant, if we know the meta type...
228 233 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
229 234 // return the constData pointer that will be filled with the result value later on
230 235 ptr = (void*)((QVariant*)ptr)->constData();
231 236 }
232 237 }
233 238 }
234 239 return ptr;
235 240 }
236 241
237 242 void* PythonQtConv::castWrapperTo(PythonQtInstanceWrapper* wrapper, const QByteArray& className, bool& ok)
238 243 {
239 244 void* object;
240 245 if (wrapper->classInfo()->isCPPWrapper()) {
241 246 object = wrapper->_wrappedPtr;
242 247 } else {
243 248 QObject* tmp = wrapper->_obj;
244 249 object = tmp;
245 250 }
246 251 if (object) {
247 252 // if we can be upcasted to the given name, we pass the casted pointer in:
248 253 object = wrapper->classInfo()->castTo(object, className);
249 254 ok = object!=NULL;
250 255 } else {
251 256 // if it is a NULL ptr, we need to check if it inherits, so that we might pass the NULL ptr
252 257 ok = wrapper->classInfo()->inherits(className);
253 258 }
254 259 return object;
255 260 }
256 261
257 262 void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject)
258 263 {
259 264 void* ptr = alreadyAllocatedCPPObject;
260 265
261 266 static int penId = QMetaType::type("QPen");
262 267 static int brushId = QMetaType::type("QBrush");
263 268 static int cursorId = QMetaType::type("QCursor");
264 269 static int colorId = QMetaType::type("QColor");
265 270 static PyObject* qtGlobalColorEnum = PythonQtClassInfo::findEnumWrapper("Qt::GlobalColor", NULL);
266 271 if (typeId == cursorId) {
267 272 static PyObject* qtCursorShapeEnum = PythonQtClassInfo::findEnumWrapper("Qt::CursorShape", NULL);
268 273 if ((PyObject*)obj->ob_type == qtCursorShapeEnum) {
269 274 Qt::CursorShape val = (Qt::CursorShape)PyInt_AS_LONG(obj);
270 275 if (!ptr) {
271 276 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QCursor(), ptr);
272 277 ptr = (void*)((QVariant*)ptr)->constData();
273 278 }
274 279 *((QCursor*)ptr) = QCursor(val);
275 280 return ptr;
276 281 }
277 282 } else if (typeId == penId) {
278 283 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
279 284 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
280 285 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
281 286 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
282 287 if (!ptr) {
283 288 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
284 289 ptr = (void*)((QVariant*)ptr)->constData();
285 290 }
286 291 *((QPen*)ptr) = QPen(QColor(val));
287 292 return ptr;
288 293 } else if ((PyObject*)obj->ob_type == qtColorClass) {
289 294 if (!ptr) {
290 295 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
291 296 ptr = (void*)((QVariant*)ptr)->constData();
292 297 }
293 298 *((QPen*)ptr) = QPen(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
294 299 return ptr;
295 300 }
296 301 } else if (typeId == brushId) {
297 302 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
298 303 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
299 304 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
300 305 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
301 306 if (!ptr) {
302 307 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
303 308 ptr = (void*)((QVariant*)ptr)->constData();
304 309 }
305 310 *((QBrush*)ptr) = QBrush(QColor(val));
306 311 return ptr;
307 312 } else if ((PyObject*)obj->ob_type == qtColorClass) {
308 313 if (!ptr) {
309 314 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
310 315 ptr = (void*)((QVariant*)ptr)->constData();
311 316 }
312 317 *((QBrush*)ptr) = QBrush(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
313 318 return ptr;
314 319 }
315 320 } else if (typeId == colorId) {
316 321 // colors can be created from Qt::GlobalColor (and from colors, but that's the default)
317 322 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
318 323 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
319 324 if (!ptr) {
320 325 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QColor(), ptr);
321 326 ptr = (void*)((QVariant*)ptr)->constData();
322 327 }
323 328 *((QColor*)ptr) = QColor(val);
324 329 return ptr;
325 330 }
326 331 }
327 332 return NULL;
328 333 }
329 334
330 335 void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* /*classInfo*/, void* alreadyAllocatedCPPObject)
331 336 {
332 337 bool ok = false;
333 338 void* ptr = NULL;
334 339
335 340 // autoconversion of QPen/QBrush/QCursor/QColor from different type
336 341 if (!info.isPointer && !strict) {
337 342 ptr = handlePythonToQtAutoConversion(info.typeId, obj, alreadyAllocatedCPPObject);
338 343 if (ptr) {
339 344 return ptr;
340 345 }
341 346 }
342 347
343 348 if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) && info.typeId != PythonQtMethodInfo::Variant) {
344 349 // if we have a Qt wrapper object and if we do not need a QVariant, we do the following:
345 350 // (the Variant case is handled below in a switch)
346 351
347 352 // a C++ wrapper (can be passed as pointer or reference)
348 353 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)obj;
349 354 void* object = castWrapperTo(wrap, info.name, ok);
350 355 if (ok) {
351 356 if (info.isPointer) {
352 357 // store the wrapped pointer in an extra pointer and let ptr point to the extra pointer
353 358 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, object, ptr);
354 359 } else {
355 360 // store the wrapped pointer directly, since we are a reference
356 361 ptr = object;
357 362 }
358 363 } else {
359 364 // not matching
360 365 }
361 366 } else if (info.isPointer) {
362 367 // a pointer
363 368 if (info.typeId == QMetaType::Char || info.typeId == QMetaType::UChar)
364 369 {
365 370 QString str = PyObjGetString(obj, strict, ok);
366 371 if (ok) {
367 372 void* ptr2 = NULL;
368 373 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str.toUtf8()), ptr2);
369 374 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr);
370 375 }
371 376 } else if (info.name == "PyObject") {
372 377 // handle low level PyObject directly
373 378 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, obj, ptr);
374 379 } else if (obj == Py_None) {
375 380 // None is treated as a NULL ptr
376 381 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
377 382 } else {
378 383 // if we are not strict, we try if we are passed a 0 integer
379 384 if (!strict) {
380 385 bool ok;
381 386 int value = PyObjGetInt(obj, true, ok);
382 387 if (ok && value==0) {
383 388 // TODOXXX is this wise? or should it be expected from the programmer to use None?
384 389 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
385 390 }
386 391 }
387 392 }
388 393 } else {
389 394 // not a pointer
390 395 switch (info.typeId) {
391 396 case QMetaType::Char:
392 397 {
393 398 int val = PyObjGetInt(obj, strict, ok);
394 399 if (ok) {
395 400 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, char, val, ptr);
396 401 }
397 402 }
398 403 break;
399 404 case QMetaType::UChar:
400 405 {
401 406 int val = PyObjGetInt(obj, strict, ok);
402 407 if (ok) {
403 408 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned char, val, ptr);
404 409 }
405 410 }
406 411 break;
407 412 case QMetaType::Short:
408 413 {
409 414 int val = PyObjGetInt(obj, strict, ok);
410 415 if (ok) {
411 416 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
412 417 }
413 418 }
414 419 break;
415 420 case QMetaType::UShort:
416 421 {
417 422 int val = PyObjGetInt(obj, strict, ok);
418 423 if (ok) {
419 424 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned short, val, ptr);
420 425 }
421 426 }
422 427 break;
423 428 case QMetaType::Long:
424 429 {
425 430 long val = (long)PyObjGetLongLong(obj, strict, ok);
426 431 if (ok) {
427 432 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, long, val, ptr);
428 433 }
429 434 }
430 435 break;
431 436 case QMetaType::ULong:
432 437 {
433 438 unsigned long val = (unsigned long)PyObjGetLongLong(obj, strict, ok);
434 439 if (ok) {
435 440 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned long, val, ptr);
436 441 }
437 442 }
438 443 break;
439 444 case QMetaType::Bool:
440 445 {
441 446 bool val = PyObjGetBool(obj, strict, ok);
442 447 if (ok) {
443 448 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, bool, val, ptr);
444 449 }
445 450 }
446 451 break;
447 452 case QMetaType::Int:
448 453 {
449 454 int val = PyObjGetInt(obj, strict, ok);
450 455 if (ok) {
451 456 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, int, val, ptr);
452 457 }
453 458 }
454 459 break;
455 460 case QMetaType::UInt:
456 461 {
457 462 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
458 463 if (ok) {
459 464 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
460 465 }
461 466 }
462 467 break;
463 468 case QMetaType::QChar:
464 469 {
465 470 int val = PyObjGetInt(obj, strict, ok);
466 471 if (ok) {
467 472 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
468 473 }
469 474 }
470 475 break;
471 476 case QMetaType::Float:
472 477 {
473 478 float val = (float)PyObjGetDouble(obj, strict, ok);
474 479 if (ok) {
475 480 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, float, val, ptr);
476 481 }
477 482 }
478 483 break;
479 484 case QMetaType::Double:
480 485 {
481 486 double val = (double)PyObjGetDouble(obj, strict, ok);
482 487 if (ok) {
483 488 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, double, val, ptr);
484 489 }
485 490 }
486 491 break;
487 492 case QMetaType::LongLong:
488 493 {
489 494 qint64 val = PyObjGetLongLong(obj, strict, ok);
490 495 if (ok) {
491 496 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, qint64, val, ptr);
492 497 }
493 498 }
494 499 break;
495 500 case QMetaType::ULongLong:
496 501 {
497 502 quint64 val = PyObjGetULongLong(obj, strict, ok);
498 503 if (ok) {
499 504 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, quint64, val, ptr);
500 505 }
501 506 }
502 507 break;
503 508 case QMetaType::QByteArray:
504 509 {
505 510 QByteArray bytes = PyObjGetBytes(obj, strict, ok);
506 511 if (ok) {
507 512 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(bytes), ptr);
508 513 ptr = (void*)((QVariant*)ptr)->constData();
509 514 }
510 515 }
511 516 break;
512 517 case QMetaType::QString:
513 518 {
514 519 QString str = PyObjGetString(obj, strict, ok);
515 520 if (ok) {
516 521 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str), ptr);
517 522 ptr = (void*)((QVariant*)ptr)->constData();
518 523 }
519 524 }
520 525 break;
521 526 case QMetaType::QStringList:
522 527 {
523 528 QStringList l = PyObjToStringList(obj, strict, ok);
524 529 if (ok) {
525 530 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(l), ptr);
526 531 ptr = (void*)((QVariant*)ptr)->constData();
527 532 }
528 533 }
529 534 break;
530 535
531 536 case PythonQtMethodInfo::Variant:
532 537 {
533 538 QVariant v = PyObjToQVariant(obj);
534 539 if (v.isValid()) {
535 540 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
536 541 }
537 542 }
538 543 break;
539 544 default:
540 545 {
541 546 // check for enum case
542 547 if (info.enumWrapper) {
543 548 unsigned int val;
544 549 ok = false;
545 550 if ((PyObject*)obj->ob_type == info.enumWrapper) {
546 551 // we have a exact enum type match:
547 552 val = PyInt_AS_LONG(obj);
548 553 ok = true;
549 554 } else if (!strict) {
550 555 // we try to get any integer, when not being strict. If we are strict, integers are not wanted because
551 556 // we want an integer overload to be taken first!
552 557 val = (unsigned int)PyObjGetLongLong(obj, false, ok);
553 558 }
554 559 if (ok) {
555 560 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
556 561 return ptr;
557 562 } else {
558 563 return NULL;
559 564 }
560 565 }
561 566
562 567 if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
563 568 // check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant
564 569 if (info.name.startsWith("QList<")) {
565 570 QByteArray innerType = info.name.mid(6,info.name.length()-7);
566 571 if (innerType.endsWith("*")) {
567 572 innerType.truncate(innerType.length()-1);
568 573 static int id = QMetaType::type("QList<void*>");
569 574 if (!alreadyAllocatedCPPObject) {
570 575 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(id), ptr);
571 576 ptr = (void*)((QVariant*)ptr)->constData();
572 577 } else {
573 578 ptr = alreadyAllocatedCPPObject;
574 579 }
575 580 ok = ConvertPythonListToQListOfPointerType(obj, (QList<void*>*)ptr, innerType, strict);
576 581 if (ok) {
577 582 return ptr;
578 583 } else {
579 584 return NULL;
580 585 }
581 586 }
582 587 }
583 588 }
584 589
585 590 // We only do this for registered type > QMetaType::User for performance reasons.
586 591 if (info.typeId >= QMetaType::User) {
587 592 // Maybe we have a special converter that is registered for that type:
588 593 PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(info.typeId);
589 594 if (converter) {
590 595 if (!alreadyAllocatedCPPObject) {
591 596 // create a new empty variant of concrete type:
592 597 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
593 598 ptr = (void*)((QVariant*)ptr)->constData();
594 599 } else {
595 600 ptr = alreadyAllocatedCPPObject;
596 601 }
597 602 // now call the converter, passing the internal object of the variant
598 603 ok = (*converter)(obj, ptr, info.typeId, strict);
599 604 if (ok) {
600 605 return ptr;
601 606 } else {
602 607 return NULL;
603 608 }
604 609 }
605 610 }
606 611 // if no type id is available, conversion to a QVariant makes no sense/is not possible
607 612 if (info.typeId != PythonQtMethodInfo::Unknown) {
608 613 // for all other types, we use the same qvariant conversion and pass out the constData of the variant:
609 614 QVariant v = PyObjToQVariant(obj, info.typeId);
610 615 if (v.isValid()) {
611 616 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
612 617 ptr = (void*)((QVariant*)ptr)->constData();
613 618 }
614 619 }
615 620 }
616 621 }
617 622 }
618 623 return ptr;
619 624 }
620 625
621 626
622 627 QStringList PythonQtConv::PyObjToStringList(PyObject* val, bool strict, bool& ok) {
623 628 QStringList v;
624 629 ok = false;
625 630 // if we are strict, we do not want to convert a string to a stringlist
626 631 // (strings in python are detected to be sequences)
627 632 if (strict &&
628 633 (val->ob_type == &PyString_Type ||
629 634 PyUnicode_Check(val))) {
630 635 ok = false;
631 636 return v;
632 637 }
633 638 if (PySequence_Check(val)) {
634 639 int count = PySequence_Size(val);
635 640 for (int i = 0;i<count;i++) {
636 641 PyObject* value = PySequence_GetItem(val,i);
637 642 v.append(PyObjGetString(value,false,ok));
638 643 }
639 644 ok = true;
640 645 }
641 646 return v;
642 647 }
643 648
644 649 QString PythonQtConv::PyObjGetRepresentation(PyObject* val)
645 650 {
646 651 QString r;
647 652 PyObject* str = PyObject_Repr(val);
648 653 if (str) {
649 654 r = QString(PyString_AS_STRING(str));
650 655 Py_DECREF(str);
651 656 }
652 657 return r;
653 658 }
654 659
655 660 QString PythonQtConv::PyObjGetString(PyObject* val, bool strict, bool& ok) {
656 661 QString r;
657 662 ok = true;
658 663 if (val->ob_type == &PyString_Type) {
659 664 r = QString(PyString_AS_STRING(val));
660 665 } else if (PyUnicode_Check(val)) {
661 666 #ifdef WIN32
662 667 r = QString::fromUtf16(PyUnicode_AS_UNICODE(val));
663 668 #else
664 669 PyObject *ptmp = PyUnicode_AsUTF8String(val);
665 670 if(ptmp) {
666 671 r = QString::fromUtf8(PyString_AS_STRING(ptmp));
667 672 Py_DECREF(ptmp);
668 673 }
669 674 #endif
670 675 } else if (!strict) {
671 676 // EXTRA: could also use _Unicode, but why should we?
672 677 PyObject* str = PyObject_Str(val);
673 678 if (str) {
674 679 r = QString(PyString_AS_STRING(str));
675 680 Py_DECREF(str);
676 681 } else {
677 682 ok = false;
678 683 }
679 684 } else {
680 685 ok = false;
681 686 }
682 687 return r;
683 688 }
684 689
685 690 QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) {
686 691 QByteArray r;
687 692 ok = true;
688 693 if (val->ob_type == &PyString_Type) {
689 694 long size = PyString_GET_SIZE(val);
690 695 r = QByteArray(PyString_AS_STRING(val), size);
691 696 } else {
692 697 ok = false;
693 698 }
694 699 return r;
695 700 }
696 701
697 702 bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) {
698 703 bool d = false;
699 704 ok = false;
700 705 if (val == Py_False) {
701 706 d = false;
702 707 ok = true;
703 708 } else if (val == Py_True) {
704 709 d = true;
705 710 ok = true;
706 711 } else if (!strict) {
707 712 d = PyObjGetInt(val, false, ok)!=0;
708 713 ok = true;
709 714 }
710 715 return d;
711 716 }
712 717
713 718 int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) {
714 719 int d = 0;
715 720 ok = true;
716 721 if (val->ob_type == &PyInt_Type) {
717 722 d = PyInt_AS_LONG(val);
718 723 } else if (!strict) {
719 724 if (PyObject_TypeCheck(val, &PyInt_Type)) {
720 725 // support for derived int classes, e.g. for our enums
721 726 d = PyInt_AS_LONG(val);
722 727 } else if (val->ob_type == &PyFloat_Type) {
723 728 d = floor(PyFloat_AS_DOUBLE(val));
724 729 } else if (val->ob_type == &PyLong_Type) {
725 730 // handle error on overflow!
726 731 d = PyLong_AsLong(val);
727 732 } else if (val == Py_False) {
728 733 d = 0;
729 734 } else if (val == Py_True) {
730 735 d = 1;
731 736 } else {
732 737 ok = false;
733 738 }
734 739 } else {
735 740 ok = false;
736 741 }
737 742 return d;
738 743 }
739 744
740 745 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
741 746 qint64 d = 0;
742 747 ok = true;
743 748 if (val->ob_type == &PyInt_Type) {
744 749 d = PyInt_AS_LONG(val);
745 750 } else if (val->ob_type == &PyLong_Type) {
746 751 d = PyLong_AsLongLong(val);
747 752 } else if (!strict) {
748 753 if (PyObject_TypeCheck(val, &PyInt_Type)) {
749 754 // support for derived int classes, e.g. for our enums
750 755 d = PyInt_AS_LONG(val);
751 756 } else if (val->ob_type == &PyFloat_Type) {
752 757 d = floor(PyFloat_AS_DOUBLE(val));
753 758 } else if (val == Py_False) {
754 759 d = 0;
755 760 } else if (val == Py_True) {
756 761 d = 1;
757 762 } else {
758 763 ok = false;
759 764 }
760 765 } else {
761 766 ok = false;
762 767 }
763 768 return d;
764 769 }
765 770
766 771 quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) {
767 772 quint64 d = 0;
768 773 ok = true;
769 774 if (PyObject_TypeCheck(val, &PyInt_Type)) {
770 775 d = PyInt_AS_LONG(val);
771 776 } else if (val->ob_type == &PyLong_Type) {
772 777 d = PyLong_AsLongLong(val);
773 778 } else if (!strict) {
774 779 if (PyObject_TypeCheck(val, &PyInt_Type)) {
775 780 // support for derived int classes, e.g. for our enums
776 781 d = PyInt_AS_LONG(val);
777 782 } else if (val->ob_type == &PyFloat_Type) {
778 783 d = floor(PyFloat_AS_DOUBLE(val));
779 784 } else if (val == Py_False) {
780 785 d = 0;
781 786 } else if (val == Py_True) {
782 787 d = 1;
783 788 } else {
784 789 ok = false;
785 790 }
786 791 } else {
787 792 ok = false;
788 793 }
789 794 return d;
790 795 }
791 796
792 797 double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) {
793 798 double d = 0;
794 799 ok = true;
795 800 if (val->ob_type == &PyFloat_Type) {
796 801 d = PyFloat_AS_DOUBLE(val);
797 802 } else if (!strict) {
798 803 if (PyObject_TypeCheck(val, &PyInt_Type)) {
799 804 d = PyInt_AS_LONG(val);
800 805 } else if (val->ob_type == &PyLong_Type) {
801 806 d = PyLong_AsLong(val);
802 807 } else if (val == Py_False) {
803 808 d = 0;
804 809 } else if (val == Py_True) {
805 810 d = 1;
806 811 } else {
807 812 ok = false;
808 813 }
809 814 } else {
810 815 ok = false;
811 816 }
812 817 return d;
813 818 }
814 819
815 820 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
816 821 {
817 822 QVariant v;
818 823 bool ok = true;
819 824
820 825 if (type==-1) {
821 826 // no special type requested
822 827 if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) {
823 828 type = QVariant::String;
824 829 } else if (PyObject_TypeCheck(val, &PyInt_Type)) {
825 830 type = QVariant::Int;
826 831 } else if (val->ob_type==&PyLong_Type) {
827 832 type = QVariant::LongLong;
828 833 } else if (val->ob_type==&PyFloat_Type) {
829 834 type = QVariant::Double;
830 835 } else if (val == Py_False || val == Py_True) {
831 836 type = QVariant::Bool;
832 837 } else if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
833 838 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
834 839 // c++ wrapper, check if the class names of the c++ objects match
835 840 if (wrap->classInfo()->isCPPWrapper()) {
836 841 if (wrap->classInfo()->metaTypeId()>0) {
837 842 // construct a new variant from the C++ object if it has a meta type (this will COPY the object!)
838 843 v = QVariant(wrap->classInfo()->metaTypeId(), wrap->_wrappedPtr);
839 844 } else {
840 845 // TODOXXX we could as well check if there is a registered meta type for "classname*", so that we may pass
841 846 // the pointer here...
842 847 // is this worth anything? we loose the knowledge of the cpp object type
843 848 v = qVariantFromValue(wrap->_wrappedPtr);
844 849 }
845 850 } else {
846 851 // this gives us a QObject pointer
847 852 QObject* myObject = wrap->_obj;
848 853 v = qVariantFromValue(myObject);
849 854 }
850 855 return v;
851 856 } else if (val->ob_type==&PyDict_Type) {
852 857 type = QVariant::Map;
853 858 } else if (val->ob_type==&PyList_Type || val->ob_type==&PyTuple_Type || PySequence_Check(val)) {
854 859 type = QVariant::List;
855 860 } else if (val == Py_None) {
856 861 // none is invalid
857 862 type = QVariant::Invalid;
858 863 } else {
859 864 // this used to be:
860 865 // type = QVariant::String;
861 866 // but now we want to transport the Python Objects directly:
862 867 PythonQtObjectPtr o(val);
863 868 v = qVariantFromValue(o);
864 869 return v;
865 870 }
866 871 }
867 872 // special type request:
868 873 switch (type) {
869 874 case QVariant::Invalid:
870 875 return v;
871 876 break;
872 877 case QVariant::Int:
873 878 {
874 879 int d = PyObjGetInt(val, false, ok);
875 880 if (ok) return QVariant(d);
876 881 }
877 882 break;
878 883 case QVariant::UInt:
879 884 {
880 885 int d = PyObjGetInt(val, false,ok);
881 886 if (ok) v = QVariant((unsigned int)d);
882 887 }
883 888 break;
884 889 case QVariant::Bool:
885 890 {
886 891 int d = PyObjGetBool(val,false,ok);
887 892 if (ok) v = QVariant((bool)(d!=0));
888 893 }
889 894 break;
890 895 case QVariant::Double:
891 896 {
892 897 double d = PyObjGetDouble(val,false,ok);
893 898 if (ok) v = QVariant(d);
894 899 break;
895 900 }
896 901 case QMetaType::Float:
897 902 {
898 903 float d = (float) PyObjGetDouble(val,false,ok);
899 904 if (ok) v = qVariantFromValue(d);
900 905 break;
901 906 }
902 907 case QMetaType::Long:
903 908 {
904 909 long d = (long) PyObjGetLongLong(val,false,ok);
905 910 if (ok) v = qVariantFromValue(d);
906 911 break;
907 912 }
908 913 case QMetaType::ULong:
909 914 {
910 915 unsigned long d = (unsigned long) PyObjGetLongLong(val,false,ok);
911 916 if (ok) v = qVariantFromValue(d);
912 917 break;
913 918 }
914 919 case QMetaType::Short:
915 920 {
916 921 short d = (short) PyObjGetInt(val,false,ok);
917 922 if (ok) v = qVariantFromValue(d);
918 923 break;
919 924 }
920 925 case QMetaType::UShort:
921 926 {
922 927 unsigned short d = (unsigned short) PyObjGetInt(val,false,ok);
923 928 if (ok) v = qVariantFromValue(d);
924 929 break;
925 930 }
926 931 case QMetaType::Char:
927 932 {
928 933 char d = (char) PyObjGetInt(val,false,ok);
929 934 if (ok) v = qVariantFromValue(d);
930 935 break;
931 936 }
932 937 case QMetaType::UChar:
933 938 {
934 939 unsigned char d = (unsigned char) PyObjGetInt(val,false,ok);
935 940 if (ok) v = qVariantFromValue(d);
936 941 break;
937 942 }
938 943
939 944 case QVariant::ByteArray:
940 945 case QVariant::String:
941 946 {
942 947 bool ok;
943 948 v = QVariant(PyObjGetString(val, false, ok));
944 949 }
945 950 break;
946 951
947 952 // these are important for MeVisLab
948 953 case QVariant::Map:
949 954 {
950 955 if (PyMapping_Check(val)) {
951 956 QMap<QString,QVariant> map;
952 957 PyObject* items = PyMapping_Items(val);
953 958 if (items) {
954 959 int count = PyList_Size(items);
955 960 PyObject* value;
956 961 PyObject* key;
957 962 PyObject* tuple;
958 963 for (int i = 0;i<count;i++) {
959 964 tuple = PyList_GetItem(items,i);
960 965 key = PyTuple_GetItem(tuple, 0);
961 966 value = PyTuple_GetItem(tuple, 1);
962 967 map.insert(PyObjGetString(key), PyObjToQVariant(value,-1));
963 968 }
964 969 Py_DECREF(items);
965 970 v = map;
966 971 }
967 972 }
968 973 }
969 974 break;
970 975 case QVariant::List:
971 976 if (PySequence_Check(val)) {
972 977 QVariantList list;
973 978 int count = PySequence_Size(val);
974 979 PyObject* value;
975 980 for (int i = 0;i<count;i++) {
976 981 value = PySequence_GetItem(val,i);
977 982 list.append(PyObjToQVariant(value, -1));
978 983 }
979 984 v = list;
980 985 }
981 986 break;
982 987 case QVariant::StringList:
983 988 {
984 989 bool ok;
985 990 QStringList l = PyObjToStringList(val, false, ok);
986 991 if (ok) {
987 992 v = l;
988 993 }
989 994 }
990 995 break;
991 996
992 997 default:
993 998 if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
994 999 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
995 1000 if (wrap->classInfo()->isCPPWrapper() && wrap->classInfo()->metaTypeId() == type) {
996 1001 // construct a new variant from the C++ object if it has the same meta type
997 1002 v = QVariant(type, wrap->_wrappedPtr);
998 1003 } else {
999 1004 v = QVariant();
1000 1005 }
1001 1006 } else {
1002 1007 v = QVariant();
1003 1008 }
1004 1009 }
1005 1010 return v;
1006 1011 }
1007 1012
1008 1013 PyObject* PythonQtConv::QStringToPyObject(const QString& str)
1009 1014 {
1010 1015 if (str.isNull()) {
1011 1016 return PyString_FromString("");
1012 1017 } else {
1013 1018 #ifdef WIN32
1014 1019 // return PyString_FromString(str.toLatin1().data());
1015 1020 return PyUnicode_FromUnicode(str.utf16(), str.length());
1016 1021 #else
1017 1022 return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, NULL, NULL);
1018 1023 #endif
1019 1024 }
1020 1025 }
1021 1026
1022 1027 PyObject* PythonQtConv::QStringListToPyObject(const QStringList& list)
1023 1028 {
1024 1029 PyObject* result = PyTuple_New(list.count());
1025 1030 int i = 0;
1026 1031 QString str;
1027 1032 foreach (str, list) {
1028 1033 PyTuple_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(str));
1029 1034 i++;
1030 1035 }
1031 1036 // why is the error state bad after this?
1032 1037 PyErr_Clear();
1033 1038 return result;
1034 1039 }
1035 1040
1036 1041 PyObject* PythonQtConv::QStringListToPyList(const QStringList& list)
1037 1042 {
1038 1043 PyObject* result = PyList_New(list.count());
1039 1044 int i = 0;
1040 1045 for (QStringList::ConstIterator it = list.begin(); it!=list.end(); ++it) {
1041 1046 PyList_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(*it));
1042 1047 i++;
1043 1048 }
1044 1049 return result;
1045 1050 }
1046 1051
1047 1052 PyObject* PythonQtConv::QVariantToPyObject(const QVariant& v)
1048 1053 {
1049 1054 return ConvertQtValueToPythonInternal(v.userType(), (void*)v.constData());
1050 1055 }
1051 1056
1052 1057 PyObject* PythonQtConv::QVariantMapToPyObject(const QVariantMap& m) {
1053 1058 PyObject* result = PyDict_New();
1054 1059 QVariantMap::const_iterator t = m.constBegin();
1055 1060 PyObject* key;
1056 1061 PyObject* val;
1057 1062 for (;t!=m.end();t++) {
1058 1063 key = QStringToPyObject(t.key());
1059 1064 val = QVariantToPyObject(t.value());
1060 1065 PyDict_SetItem(result, key, val);
1061 1066 Py_DECREF(key);
1062 1067 Py_DECREF(val);
1063 1068 }
1064 1069 return result;
1065 1070 }
1066 1071
1067 1072 PyObject* PythonQtConv::QVariantListToPyObject(const QVariantList& l) {
1068 1073 PyObject* result = PyTuple_New(l.count());
1069 1074 int i = 0;
1070 1075 QVariant v;
1071 1076 foreach (v, l) {
1072 1077 PyTuple_SET_ITEM(result, i, PythonQtConv::QVariantToPyObject(v));
1073 1078 i++;
1074 1079 }
1075 1080 // why is the error state bad after this?
1076 1081 PyErr_Clear();
1077 1082 return result;
1078 1083 }
1079 1084
1080 1085 PyObject* PythonQtConv::ConvertQListOfPointerTypeToPythonList(QList<void*>* list, const QByteArray& typeName)
1081 1086 {
1082 1087 PyObject* result = PyTuple_New(list->count());
1083 1088 int i = 0;
1084 1089 foreach (void* value, *list) {
1085 1090 PyTuple_SET_ITEM(result, i, PythonQt::priv()->wrapPtr(value, typeName));
1086 1091 i++;
1087 1092 }
1088 1093 return result;
1089 1094 }
1090 1095
1091 1096 bool PythonQtConv::ConvertPythonListToQListOfPointerType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool /*strict*/)
1092 1097 {
1093 1098 bool result = false;
1094 1099 if (PySequence_Check(obj)) {
1095 1100 result = true;
1096 1101 int count = PySequence_Size(obj);
1097 1102 PyObject* value;
1098 1103 for (int i = 0;i<count;i++) {
1099 1104 value = PySequence_GetItem(obj,i);
1100 1105 if (PyObject_TypeCheck(value, &PythonQtInstanceWrapper_Type)) {
1101 1106 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)value;
1102 1107 bool ok;
1103 1108 void* object = castWrapperTo(wrap, type, ok);
1104 1109 if (ok) {
1105 1110 list->append(object);
1106 1111 } else {
1107 1112 result = false;
1108 1113 break;
1109 1114 }
1110 1115 }
1111 1116 }
1112 1117 }
1113 1118 return result;
1114 1119 }
1115 1120
1116 1121 int PythonQtConv::getInnerTemplateMetaType(const QByteArray& typeName)
1117 1122 {
1118 1123 int idx = typeName.indexOf("<");
1119 1124 if (idx>0) {
1120 1125 int idx2 = typeName.indexOf(">");
1121 1126 if (idx2>0) {
1122 1127 QByteArray innerType = typeName.mid(idx+1,idx2-idx-1);
1123 1128 return QMetaType::type(innerType.constData());
1124 1129 }
1125 1130 }
1126 1131 return QMetaType::Void;
1127 1132 }
1128 1133
1129 1134
1130 1135
1131 1136 QString PythonQtConv::qVariantToString(const QVariant& v) {
1132 1137 return CPPObjectToString(v.userType(), v.constData());
1133 1138 }
1134 1139
1135 1140 QString PythonQtConv::CPPObjectToString(int type, const void* data) {
1136 1141 QString r;
1137 1142 switch (type) {
1138 1143 case QVariant::Size: {
1139 1144 const QSize* s = static_cast<const QSize*>(data);
1140 1145 r = QString::number(s->width()) + ", " + QString::number(s->height());
1141 1146 }
1142 1147 break;
1143 1148 case QVariant::SizeF: {
1144 1149 const QSizeF* s = static_cast<const QSizeF*>(data);
1145 1150 r = QString::number(s->width()) + ", " + QString::number(s->height());
1146 1151 }
1147 1152 break;
1148 1153 case QVariant::Point: {
1149 1154 const QPoint* s = static_cast<const QPoint*>(data);
1150 1155 r = QString::number(s->x()) + ", " + QString::number(s->y());
1151 1156 }
1152 1157 break;
1153 1158 case QVariant::PointF: {
1154 1159 const QPointF* s = static_cast<const QPointF*>(data);
1155 1160 r = QString::number(s->x()) + ", " + QString::number(s->y());
1156 1161 }
1157 1162 break;
1158 1163 case QVariant::Rect: {
1159 1164 const QRect* s = static_cast<const QRect*>(data);
1160 1165 r = QString::number(s->x()) + ", " + QString::number(s->y());
1161 1166 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1162 1167 }
1163 1168 break;
1164 1169 case QVariant::RectF: {
1165 1170 const QRectF* s = static_cast<const QRectF*>(data);
1166 1171 r = QString::number(s->x()) + ", " + QString::number(s->y());
1167 1172 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1168 1173 }
1169 1174 break;
1170 1175 case QVariant::Date: {
1171 1176 const QDate* s = static_cast<const QDate*>(data);
1172 1177 r = s->toString(Qt::ISODate);
1173 1178 }
1174 1179 break;
1175 1180 case QVariant::DateTime: {
1176 1181 const QDateTime* s = static_cast<const QDateTime*>(data);
1177 1182 r = s->toString(Qt::ISODate);
1178 1183 }
1179 1184 break;
1180 1185 case QVariant::Time: {
1181 1186 const QTime* s = static_cast<const QTime*>(data);
1182 1187 r = s->toString(Qt::ISODate);
1183 1188 }
1184 1189 break;
1185 1190 case QVariant::Pixmap:
1186 1191 {
1187 1192 const QPixmap* s = static_cast<const QPixmap*>(data);
1188 1193 r = QString("Pixmap ") + QString::number(s->width()) + ", " + QString::number(s->height());
1189 1194 }
1190 1195 break;
1191 1196 case QVariant::Image:
1192 1197 {
1193 1198 const QImage* s = static_cast<const QImage*>(data);
1194 1199 r = QString("Image ") + QString::number(s->width()) + ", " + QString::number(s->height());
1195 1200 }
1196 1201 break;
1197 1202 case QVariant::Url:
1198 1203 {
1199 1204 const QUrl* s = static_cast<const QUrl*>(data);
1200 1205 r = s->toString();
1201 1206 }
1202 1207 break;
1203 1208 //TODO: add more printing for other variant types
1204 1209 default:
1205 1210 // this creates a copy, but that should not be expensive for typical simple variants
1206 1211 // (but we do not want to do this for our won user types!
1207 1212 if (type>0 && type < (int)QVariant::UserType) {
1208 1213 QVariant v(type, data);
1209 1214 r = v.toString();
1210 1215 }
1211 1216 }
1212 1217 return r;
1213 1218 }
@@ -1,500 +1,511
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 const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);
78 78 // set return argument to NULL
79 79 argList[0] = NULL;
80 80
81 81 bool ok = true;
82 82 bool skipFirst = false;
83 83 if (info->isInstanceDecorator()) {
84 84 skipFirst = true;
85 85
86 86 // for decorators on CPP objects, we take the cpp ptr, for QObjects we take the QObject pointer
87 87 void* arg1 = firstArgument;
88 88 if (!arg1) {
89 89 arg1 = objectToCall;
90 90 }
91 91 if (arg1) {
92 92 // upcast to correct parent class
93 93 arg1 = ((char*)arg1)+info->upcastingOffset();
94 94 }
95 95
96 96 argList[1] = &arg1;
97 97 if (ok) {
98 98 for (int i = 2; i<argc && ok; i++) {
99 99 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
100 100 //std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
101 101 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, classInfo);
102 102 if (argList[i]==NULL) {
103 103 ok = false;
104 104 break;
105 105 }
106 106 }
107 107 }
108 108 } else {
109 109 for (int i = 1; i<argc && ok; i++) {
110 110 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
111 111 //std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
112 112 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, classInfo);
113 113 if (argList[i]==NULL) {
114 114 ok = false;
115 115 break;
116 116 }
117 117 }
118 118 }
119 119
120 120 if (ok) {
121 121 // parameters are ok, now create the qt return value which is assigned to by metacall
122 122 if (returnValueParam.typeId != QMetaType::Void) {
123 123 // create empty default value for the return value
124 124 if (!directReturnValuePointer) {
125 125 // create empty default value for the return value
126 126 argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);
127 127 if (argList[0]==NULL) {
128 128 // return value could not be created, maybe we have a registered class with a default constructor, so that we can construct the pythonqt wrapper object and
129 129 // pass its internal pointer
130 130 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(returnValueParam.name);
131 131 if (info && info->pythonQtClassWrapper()) {
132 132 PyObject* emptyTuple = PyTuple_New(0);
133 133 // 1) default construct an empty object as python object (owned by PythonQt), by calling the meta class with empty arguments
134 134 result = PyObject_Call((PyObject*)info->pythonQtClassWrapper(), emptyTuple, NULL);
135 135 if (result) {
136 136 argList[0] = ((PythonQtInstanceWrapper*)result)->_wrappedPtr;
137 137 }
138 138 Py_DECREF(emptyTuple);
139 139 }
140 140 }
141 141 } else {
142 142 // we can use our pointer directly!
143 143 argList[0] = directReturnValuePointer;
144 144 }
145 145 }
146 146
147 147 // invoke the slot via metacall
148 148 (info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
149 149
150 150 // handle the return value (which in most cases still needs to be converted to a Python object)
151 151 if (argList[0] || returnValueParam.typeId == QMetaType::Void) {
152 152 if (directReturnValuePointer) {
153 153 result = NULL;
154 154 } else {
155 155 // the resulting object maybe present already, because we created it above at 1)...
156 156 if (!result) {
157 157 result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]);
158 158 }
159 159 }
160 160 } else {
161 161 QString e = QString("Called ") + info->fullSignature() + ", return type '" + returnValueParam.name + "' is ignored because it is unknown to PythonQt. Probably you should register it using qRegisterMetaType() or add a default constructor decorator to the class.";
162 162 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
163 163 result = NULL;
164 164 }
165 165 }
166 166 recursiveEntry--;
167 167
168 168 // reset the parameter storage position to the stored pos to "pop" the parameter stack
169 169 PythonQtConv::global_valueStorage.setPos(globalValueStoragePos);
170 170 PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos);
171 171 PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos);
172 172
173 173 *pythonReturnValue = result;
174 174 // NOTE: it is important to only return here, otherwise the stack will not be popped!!!
175 175 return result || (directReturnValuePointer && *directReturnValuePointer);
176 176 }
177 177
178 178 //-----------------------------------------------------------------------------------
179 179
180 180 static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL;
181 181
182 182 PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw)
183 183 {
184 184 PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func;
185 185 PythonQtSlotInfo* info = f->m_ml;
186 186 if (PyObject_TypeCheck(f->m_self, &PythonQtInstanceWrapper_Type)) {
187 187 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self;
188 return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr);
188 if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
189 QString error = QString("Trying to call '") + f->m_ml->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
190 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
191 return NULL;
192 } else {
193 return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr);
194 }
189 195 } else if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
190 196 PythonQtClassWrapper* type = (PythonQtClassWrapper*) f->m_self;
191 197 if (info->isClassDecorator()) {
192 198 return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw);
193 199 } else {
194 200 // otherwise, it is an unbound call and we have an instanceDecorator or normal slot...
195 201 Py_ssize_t argc = PyTuple_Size(args);
196 202 if (argc>0) {
197 203 PyObject* firstArg = PyTuple_GET_ITEM(args, 0);
198 204 if (PyObject_TypeCheck(firstArg, (PyTypeObject*)&PythonQtInstanceWrapper_Type)
199 205 && ((PythonQtInstanceWrapper*)firstArg)->classInfo()->inherits(type->classInfo())) {
200 206 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg;
207 if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
208 QString error = QString("Trying to call '") + f->m_ml->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
209 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
210 return NULL;
211 }
201 212 // strip the first argument...
202 213 PyObject* newargs = PyTuple_GetSlice(args, 1, argc);
203 214 PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, newargs, kw, self->_wrappedPtr);
204 215 Py_DECREF(newargs);
205 216 return result;
206 217 } else {
207 218 // first arg is not of correct type!
208 219 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument, got " + firstArg->ob_type->tp_name;
209 220 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
210 221 return NULL;
211 222 }
212 223 } else {
213 224 // wrong number of args
214 225 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument.";
215 226 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
216 227 return NULL;
217 228 }
218 229 }
219 230 }
220 231 return NULL;
221 232 }
222 233
223 234 PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg, void** directReturnValuePointer)
224 235 {
225 236 int argc = PyTuple_Size(args);
226 237
227 238 #ifdef PYTHONQT_DEBUG
228 239 std::cout << "called " << info->metaMethod()->typeName() << " " << info->metaMethod()->signature() << std::endl;
229 240 #endif
230 241
231 242 PyObject* r = NULL;
232 243 bool ok = false;
233 244 if (directReturnValuePointer) {
234 245 *directReturnValuePointer = NULL;
235 246 }
236 247 if (info->nextInfo()) {
237 248 // overloaded slot call, try on all slots with strict conversion first
238 249 bool strict = true;
239 250 PythonQtSlotInfo* i = info;
240 251 while (i) {
241 252 bool skipFirst = i->isInstanceDecorator();
242 253 if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
243 254 PyErr_Clear();
244 255 ok = PythonQtCallSlot(classInfo, objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer);
245 256 if (PyErr_Occurred() || ok) break;
246 257 }
247 258 i = i->nextInfo();
248 259 if (!i) {
249 260 if (strict) {
250 261 // one more run without being strict
251 262 strict = false;
252 263 i = info;
253 264 }
254 265 }
255 266 }
256 267 if (!ok && !PyErr_Occurred()) {
257 268 QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n");
258 269 PythonQtSlotInfo* i = info;
259 270 while (i) {
260 271 e += QString(i->fullSignature()) + "\n";
261 272 i = i->nextInfo();
262 273 }
263 274 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
264 275 }
265 276 } else {
266 277 // simple (non-overloaded) slot call
267 278 bool skipFirst = info->isInstanceDecorator();
268 279 if (info->parameterCount()-1-(skipFirst?1:0) == argc) {
269 280 PyErr_Clear();
270 281 ok = PythonQtCallSlot(classInfo, objectToCall, args, false, info, firstArg, &r, directReturnValuePointer);
271 282 if (!ok && !PyErr_Occurred()) {
272 283 QString e = QString("Called ") + info->fullSignature() + " with wrong arguments: " + PythonQtConv::PyObjGetString(args);
273 284 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
274 285 }
275 286 } else {
276 287 QString e = QString("Called ") + info->fullSignature() + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args);
277 288 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
278 289 }
279 290 }
280 291
281 292 return r;
282 293 }
283 294
284 295 PyObject *
285 296 PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module)
286 297 {
287 298 PythonQtSlotFunctionObject *op;
288 299 op = pythonqtslot_free_list;
289 300 if (op != NULL) {
290 301 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self);
291 302 PyObject_INIT(op, &PythonQtSlotFunction_Type);
292 303 }
293 304 else {
294 305 op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type);
295 306 if (op == NULL)
296 307 return NULL;
297 308 }
298 309 op->m_ml = ml;
299 310 Py_XINCREF(self);
300 311 op->m_self = self;
301 312 Py_XINCREF(module);
302 313 op->m_module = module;
303 314 PyObject_GC_Track(op);
304 315 return (PyObject *)op;
305 316 }
306 317
307 318 PythonQtSlotInfo*
308 319 PythonQtSlotFunction_GetSlotInfo(PyObject *op)
309 320 {
310 321 if (!PythonQtSlotFunction_Check(op)) {
311 322 PyErr_BadInternalCall();
312 323 return NULL;
313 324 }
314 325 return ((PythonQtSlotFunctionObject *)op) -> m_ml;
315 326 }
316 327
317 328 PyObject *
318 329 PythonQtSlotFunction_GetSelf(PyObject *op)
319 330 {
320 331 if (!PythonQtSlotFunction_Check(op)) {
321 332 PyErr_BadInternalCall();
322 333 return NULL;
323 334 }
324 335 return ((PythonQtSlotFunctionObject *)op) -> m_self;
325 336 }
326 337
327 338 /* Methods (the standard built-in methods, that is) */
328 339
329 340 static void
330 341 meth_dealloc(PythonQtSlotFunctionObject *m)
331 342 {
332 343 PyObject_GC_UnTrack(m);
333 344 Py_XDECREF(m->m_self);
334 345 Py_XDECREF(m->m_module);
335 346 m->m_self = (PyObject *)pythonqtslot_free_list;
336 347 pythonqtslot_free_list = m;
337 348 }
338 349
339 350 static PyObject *
340 351 meth_get__doc__(PythonQtSlotFunctionObject * /*m*/, void * /*closure*/)
341 352 {
342 353 Py_INCREF(Py_None);
343 354 return Py_None;
344 355 }
345 356
346 357 static PyObject *
347 358 meth_get__name__(PythonQtSlotFunctionObject *m, void * /*closure*/)
348 359 {
349 360 return PyString_FromString(m->m_ml->metaMethod()->signature());
350 361 }
351 362
352 363 static int
353 364 meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg)
354 365 {
355 366 int err;
356 367 if (m->m_self != NULL) {
357 368 err = visit(m->m_self, arg);
358 369 if (err)
359 370 return err;
360 371 }
361 372 if (m->m_module != NULL) {
362 373 err = visit(m->m_module, arg);
363 374 if (err)
364 375 return err;
365 376 }
366 377 return 0;
367 378 }
368 379
369 380 static PyObject *
370 381 meth_get__self__(PythonQtSlotFunctionObject *m, void * /*closure*/)
371 382 {
372 383 PyObject *self;
373 384 if (PyEval_GetRestricted()) {
374 385 PyErr_SetString(PyExc_RuntimeError,
375 386 "method.__self__ not accessible in restricted mode");
376 387 return NULL;
377 388 }
378 389 self = m->m_self;
379 390 if (self == NULL)
380 391 self = Py_None;
381 392 Py_INCREF(self);
382 393 return self;
383 394 }
384 395
385 396 static PyGetSetDef meth_getsets [] = {
386 397 {"__doc__", (getter)meth_get__doc__, NULL, NULL},
387 398 {"__name__", (getter)meth_get__name__, NULL, NULL},
388 399 {"__self__", (getter)meth_get__self__, NULL, NULL},
389 400 {NULL, NULL, NULL,NULL},
390 401 };
391 402
392 403 #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6
393 404 #define PY_WRITE_RESTRICTED WRITE_RESTRICTED
394 405 #endif
395 406
396 407 #define OFF(x) offsetof(PythonQtSlotFunctionObject, x)
397 408
398 409 static PyMemberDef meth_members[] = {
399 410 {"__module__", T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED},
400 411 {NULL}
401 412 };
402 413
403 414 static PyObject *
404 415 meth_repr(PythonQtSlotFunctionObject *f)
405 416 {
406 417 if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
407 418 PythonQtClassWrapper* self = (PythonQtClassWrapper*) f->m_self;
408 419 return PyString_FromFormat("<unbound qt slot %s of %s type>",
409 420 f->m_ml->slotName().data(),
410 421 self->classInfo()->className());
411 422 } else {
412 423 return PyString_FromFormat("<qt slot %s of %s instance at %p>",
413 424 f->m_ml->slotName().data(),
414 425 f->m_self->ob_type->tp_name,
415 426 f->m_self);
416 427 }
417 428 }
418 429
419 430 static int
420 431 meth_compare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b)
421 432 {
422 433 if (a->m_self != b->m_self)
423 434 return (a->m_self < b->m_self) ? -1 : 1;
424 435 if (a->m_ml == b->m_ml)
425 436 return 0;
426 437 if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0)
427 438 return -1;
428 439 else
429 440 return 1;
430 441 }
431 442
432 443 static long
433 444 meth_hash(PythonQtSlotFunctionObject *a)
434 445 {
435 446 long x,y;
436 447 if (a->m_self == NULL)
437 448 x = 0;
438 449 else {
439 450 x = PyObject_Hash(a->m_self);
440 451 if (x == -1)
441 452 return -1;
442 453 }
443 454 y = _Py_HashPointer((void*)(a->m_ml));
444 455 if (y == -1)
445 456 return -1;
446 457 x ^= y;
447 458 if (x == -1)
448 459 x = -2;
449 460 return x;
450 461 }
451 462
452 463
453 464 PyTypeObject PythonQtSlotFunction_Type = {
454 465 PyObject_HEAD_INIT(&PyType_Type)
455 466 0,
456 467 "builtin_qt_slot",
457 468 sizeof(PythonQtSlotFunctionObject),
458 469 0,
459 470 (destructor)meth_dealloc, /* tp_dealloc */
460 471 0, /* tp_print */
461 472 0, /* tp_getattr */
462 473 0, /* tp_setattr */
463 474 (cmpfunc)meth_compare, /* tp_compare */
464 475 (reprfunc)meth_repr, /* tp_repr */
465 476 0, /* tp_as_number */
466 477 0, /* tp_as_sequence */
467 478 0, /* tp_as_mapping */
468 479 (hashfunc)meth_hash, /* tp_hash */
469 480 PythonQtSlotFunction_Call, /* tp_call */
470 481 0, /* tp_str */
471 482 PyObject_GenericGetAttr, /* tp_getattro */
472 483 0, /* tp_setattro */
473 484 0, /* tp_as_buffer */
474 485 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
475 486 0, /* tp_doc */
476 487 (traverseproc)meth_traverse, /* tp_traverse */
477 488 0, /* tp_clear */
478 489 0, /* tp_richcompare */
479 490 0, /* tp_weaklistoffset */
480 491 0, /* tp_iter */
481 492 0, /* tp_iternext */
482 493 0, /* tp_methods */
483 494 meth_members, /* tp_members */
484 495 meth_getsets, /* tp_getset */
485 496 0, /* tp_base */
486 497 0, /* tp_dict */
487 498 };
488 499
489 500 /* Clear out the free list */
490 501
491 502 void
492 503 PythonQtSlotFunction_Fini(void)
493 504 {
494 505 while (pythonqtslot_free_list) {
495 506 PythonQtSlotFunctionObject *v = pythonqtslot_free_list;
496 507 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(v->m_self);
497 508 PyObject_GC_Del(v);
498 509 }
499 510 }
500 511
@@ -1,161 +1,156
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtStdDecorators.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2007-04
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtStdDecorators.h"
43 43 #include "PythonQt.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include <QCoreApplication>
46 46
47 47 bool PythonQtStdDecorators::connect(QObject* sender, const QByteArray& signal, PyObject* callable)
48 48 {
49 49 QByteArray signalTmp;
50 50 char first = signal.at(0);
51 51 if (first>='0' && first<='9') {
52 52 signalTmp = signal;
53 53 } else {
54 54 signalTmp = "2" + signal;
55 55 }
56 56
57 57 if (sender) {
58 58 return PythonQt::self()->addSignalHandler(sender, signalTmp, callable);
59 59 } else {
60 60 return false;
61 61 }
62 62 }
63 63
64 64 bool PythonQtStdDecorators::connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot)
65 65 {
66 66 bool r = false;
67 67 if (sender && receiver) {
68 68 QByteArray signalTmp;
69 69 char first = signal.at(0);
70 70 if (first>='0' && first<='9') {
71 71 signalTmp = signal;
72 72 } else {
73 73 signalTmp = "2" + signal;
74 74 }
75 75
76 76 QByteArray slotTmp;
77 77 first = slot.at(0);
78 78 if (first>='0' && first<='9') {
79 79 slotTmp = slot;
80 80 } else {
81 81 slotTmp = "1" + slot;
82 82 }
83 83 r = QObject::connect(sender, signalTmp, receiver, slotTmp);
84 84 }
85 85 return r;
86 86 }
87 87
88 88 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal, PyObject* callable)
89 89 {
90 90 QByteArray signalTmp;
91 91 char first = signal.at(0);
92 92 if (first>='0' && first<='9') {
93 93 signalTmp = signal;
94 94 } else {
95 95 signalTmp = "2" + signal;
96 96 }
97 97 if (sender) {
98 98 return PythonQt::self()->removeSignalHandler(sender, signalTmp, callable);
99 99 } else {
100 100 return false;
101 101 }
102 102 }
103 103
104 104 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot)
105 105 {
106 106 bool r = false;
107 107 if (sender && receiver) {
108 108 QByteArray signalTmp;
109 109 char first = signal.at(0);
110 110 if (first>='0' && first<='9') {
111 111 signalTmp = signal;
112 112 } else {
113 113 signalTmp = "2" + signal;
114 114 }
115 115
116 116 QByteArray slotTmp;
117 117 first = slot.at(0);
118 118 if (first>='0' && first<='9') {
119 119 slotTmp = slot;
120 120 } else {
121 121 slotTmp = "1" + slot;
122 122 }
123 123
124 124 r = QObject::disconnect(sender, signalTmp, receiver, slotTmp);
125 125 }
126 126 return r;
127 127 }
128 128
129 129 #undef emit
130 130 void PythonQtStdDecorators::emit(QObject* sender, const QByteArray& signal, PyObject* arg1 ,PyObject* arg2 ,
131 131 PyObject* arg3 ,PyObject* arg4 ,PyObject* arg5 ,PyObject* arg6 ,PyObject* arg7 )
132 132 {
133 133 // TODO xxx
134 134 // use normal PythonQtSlot calling code, add "allowSignal" to member lookup?!
135 135 }
136 136 #define emit
137 137
138 138 QObject* PythonQtStdDecorators::parent(QObject* o) {
139 139 return o->parent();
140 140 }
141 141
142 142 void PythonQtStdDecorators::setParent(QObject* o, QObject* parent)
143 143 {
144 144 o->setParent(parent);
145 145 }
146 146
147 QVariantList PythonQtStdDecorators::children(QObject* o)
147 const QObjectList* PythonQtStdDecorators::children(QObject* o)
148 148 {
149 QVariantList v;
150 QListIterator<QObject*> it(o->children());
151 while (it.hasNext()) {
152 v << qVariantFromValue(it.next());
153 }
154 return v;
149 return &o->children();
155 150 }
156 151
157 152 QString PythonQtStdDecorators::tr(QObject* obj, const QByteArray& text, const QByteArray& ambig, int n)
158 153 {
159 154 return QCoreApplication::translate(obj->metaObject()->className(), text.constData(), ambig.constData(), QCoreApplication::CodecForTr, n);
160 155 }
161 156
@@ -1,103 +1,103
1 1 #ifndef _PYTHONQTSTDDECORATORS_H
2 2 #define _PYTHONQTSTDDECORATORS_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtStdDecorators.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2007-04
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46 #include <Python.h>
47 47 #include <QObject>
48 48 #include <QVariantList>
49 49 #include <QTextDocument>
50 50 #include <QColor>
51 51 #include <QDateTime>
52 52 #include <QDate>
53 53 #include <QTime>
54 54
55 55 class PYTHONQT_EXPORT PythonQtStdDecorators : public QObject
56 56 {
57 57 Q_OBJECT
58 58
59 59 public slots:
60 60 bool connect(QObject* sender, const QByteArray& signal, PyObject* callable);
61 61 bool connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot);
62 62 bool disconnect(QObject* sender, const QByteArray& signal, PyObject* callable);
63 63 bool disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot);
64 64
65 65 #undef emit
66 66 void emit(QObject* sender, const QByteArray& signal, PyObject* arg1 = NULL,PyObject* arg2 = NULL,
67 67 PyObject* arg3 = NULL,PyObject* arg4 = NULL,PyObject* arg5 = NULL,PyObject* arg6 = NULL,PyObject* arg7 = NULL);
68 68 #define emit
69 69
70 70 QObject* parent(QObject* o);
71 71 void setParent(QObject* o, QObject* parent);
72 72
73 QVariantList children(QObject* o);
73 const QObjectList* children(QObject* o);
74 74
75 75 double static_Qt_qAbs(double a) { return qAbs(a); }
76 76 double static_Qt_qBound(double a,double b,double c) { return qBound(a,b,c); }
77 77 void static_Qt_qDebug(const QByteArray& msg) { qDebug(msg.constData()); }
78 78 // TODO: multi arg qDebug...
79 79 void static_Qt_qWarning(const QByteArray& msg) { qWarning(msg.constData()); }
80 80 // TODO: multi arg qWarning...
81 81 void static_Qt_qCritical(const QByteArray& msg) { qCritical(msg.constData()); }
82 82 // TODO: multi arg qCritical...
83 83 void static_Qt_qFatal(const QByteArray& msg) { qFatal(msg.constData()); }
84 84 // TODO: multi arg qFatal...
85 85 bool static_Qt_qFuzzyCompare(double a, double b) { return qFuzzyCompare(a, b); }
86 86 double static_Qt_qMax(double a, double b) { return qMax(a, b); }
87 87 double static_Qt_qMin(double a, double b) { return qMin(a, b); }
88 88 int static_Qt_qRound(double a) { return qRound(a); }
89 89 qint64 static_Qt_qRound64(double a) { return qRound64(a); }
90 90 const char* static_Qt_qVersion() { return qVersion(); }
91 91 int static_Qt_qrand() { return qrand(); }
92 92 void static_Qt_qsrand(uint a) { qsrand(a); }
93 93
94 94 QString tr(QObject* obj, const QByteArray& text, const QByteArray& ambig = QByteArray(), int n = -1);
95 95
96 96 QByteArray static_Qt_SIGNAL(const QByteArray& s) { return QByteArray("2") + s; }
97 97 QByteArray static_Qt_SLOT(const QByteArray& s) { return QByteArray("1") + s; }
98 98
99 99 //TODO: add findChild/findChildren/children/...
100 100 };
101 101
102 102
103 103 #endif
General Comments 0
You need to be logged in to leave comments. Login now