PythonQtConversion.cpp
1076 lines
| 33.3 KiB
| text/x-c
|
CppLexer
/ src / PythonQtConversion.cpp
ezust
|
r0 | /* | ||
* | ||||
* Copyright (C) 2006 MeVis Research GmbH All Rights Reserved. | ||||
* | ||||
* This library is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU Lesser General Public | ||||
* License as published by the Free Software Foundation; either | ||||
* version 2.1 of the License, or (at your option) any later version. | ||||
* | ||||
* This library is distributed in the hope that it will be useful, | ||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
* Lesser General Public License for more details. | ||||
* | ||||
* Further, this software is distributed without any warranty that it is | ||||
* free of the rightful claim of any third person regarding infringement | ||||
* or the like. Any license provided herein, whether implied or | ||||
* otherwise, applies only to this software file. Patent licenses, if | ||||
* any, provided herein do not apply to combinations of this program with | ||||
* other software, or any other product whatsoever. | ||||
* | ||||
* You should have received a copy of the GNU Lesser General Public | ||||
* License along with this library; if not, write to the Free Software | ||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
* | ||||
* Contact information: MeVis Research GmbH, Universitaetsallee 29, | ||||
* 28359 Bremen, Germany or: | ||||
* | ||||
* http://www.mevis.de | ||||
* | ||||
*/ | ||||
//---------------------------------------------------------------------------------- | ||||
/*! | ||||
// \file PythonQtConversion.cpp | ||||
// \author Florian Link | ||||
// \author Last changed by $Author: florian $ | ||||
// \date 2006-05 | ||||
*/ | ||||
//---------------------------------------------------------------------------------- | ||||
#include "PythonQtConversion.h" | ||||
#include "PythonQtVariants.h" | ||||
#include <QDateTime> | ||||
#include <QTime> | ||||
#include <QDate> | ||||
PythonQtValueStorage<qint64, 128> PythonQtConv::global_valueStorage; | ||||
PythonQtValueStorage<void*, 128> PythonQtConv::global_ptrStorage; | ||||
PythonQtValueStorage<QVariant, 32> PythonQtConv::global_variantStorage; | ||||
florianlink
|
r10 | QHash<int, PythonQtConvertMetaTypeToPythonCB*> PythonQtConv::_metaTypeToPythonConverters; | ||
QHash<int, PythonQtConvertPythonToMetaTypeCB*> PythonQtConv::_pythonToMetaTypeConverters; | ||||
ezust
|
r0 | |||
PyObject* PythonQtConv::GetPyBool(bool val) | ||||
{ | ||||
PyObject* r = val?Py_True:Py_False; | ||||
Py_INCREF(r); | ||||
return r; | ||||
} | ||||
florianlink
|
r10 | PyObject* PythonQtConv::ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data) { | ||
ezust
|
r0 | if (info.typeId == QMetaType::Void) { | ||
Py_INCREF(Py_None); | ||||
return Py_None; | ||||
florianlink
|
r10 | } else if (info.isPointer && (info.typeId == QMetaType::Char)) { | ||
// a char ptr will probably be a null terminated string, so we support that: | ||||
return PyString_FromString(*((char**)data)); | ||||
} else if ((info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) && | ||||
info.name.startsWith("QList<")) { | ||||
// it is a QList template: | ||||
// (TODO: check what happens if this is a pointer type?!) | ||||
QByteArray innerType = info.name.mid(6,info.name.length()-7); | ||||
if (innerType.endsWith("*")) { | ||||
innerType.truncate(innerType.length()-1); | ||||
return ConvertQListOfPointerTypeToPythonList((QList<void*>*)data, innerType); | ||||
ezust
|
r0 | } | ||
} | ||||
florianlink
|
r10 | |||
if (info.typeId >= QMetaType::User) { | ||||
// if a converter is registered, we use is: | ||||
PythonQtConvertMetaTypeToPythonCB* converter = _metaTypeToPythonConverters.value(info.typeId); | ||||
if (converter) { | ||||
return (*converter)(data, info.typeId); | ||||
} | ||||
} | ||||
// special handling did not match, so we convert the usual way (either pointer or value version): | ||||
if (info.isPointer) { | ||||
// 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) | ||||
return PythonQt::priv()->wrapPtr(*((void**)data), info.name); | ||||
} else { | ||||
// handle values that are not yet handled and not pointers | ||||
return ConvertQtValueToPythonInternal(info.typeId, data); | ||||
} | ||||
ezust
|
r0 | } | ||
florianlink
|
r10 | PyObject* PythonQtConv::ConvertQtValueToPythonInternal(int type, const void* data) { | ||
ezust
|
r0 | switch (type) { | ||
case QMetaType::Void: | ||||
Py_INCREF(Py_None); | ||||
return Py_None; | ||||
case QMetaType::Char: | ||||
return PyInt_FromLong(*((char*)data)); | ||||
case QMetaType::UChar: | ||||
return PyInt_FromLong(*((unsigned char*)data)); | ||||
case QMetaType::Short: | ||||
return PyInt_FromLong(*((short*)data)); | ||||
case QMetaType::UShort: | ||||
return PyInt_FromLong(*((unsigned short*)data)); | ||||
case QMetaType::Long: | ||||
return PyInt_FromLong(*((long*)data)); | ||||
case QMetaType::ULong: | ||||
// does not fit into simple int of python | ||||
return PyLong_FromUnsignedLong(*((unsigned long*)data)); | ||||
case QMetaType::Bool: | ||||
return PythonQtConv::GetPyBool(*((bool*)data)); | ||||
case QMetaType::Int: | ||||
return PyInt_FromLong(*((int*)data)); | ||||
case QMetaType::UInt: | ||||
return PyInt_FromLong(*((unsigned int*)data)); | ||||
case QMetaType::QChar: | ||||
return PyInt_FromLong(*((short*)data)); | ||||
case QMetaType::Float: | ||||
return PyFloat_FromDouble(*((float*)data)); | ||||
case QMetaType::Double: | ||||
return PyFloat_FromDouble(*((double*)data)); | ||||
case QMetaType::LongLong: | ||||
return PyLong_FromLongLong(*((qint64*)data)); | ||||
case QMetaType::ULongLong: | ||||
return PyLong_FromUnsignedLongLong(*((quint64*)data)); | ||||
case QMetaType::QByteArray: { | ||||
QByteArray* v = (QByteArray*) data; | ||||
return PyString_FromStringAndSize(*v, v->size()); | ||||
} | ||||
case QMetaType::QVariantMap: | ||||
return PythonQtConv::QVariantMapToPyObject(*((QVariantMap*)data)); | ||||
case QMetaType::QVariantList: | ||||
return PythonQtConv::QVariantListToPyObject(*((QVariantList*)data)); | ||||
case QMetaType::QString: | ||||
return PythonQtConv::QStringToPyObject(*((QString*)data)); | ||||
case QMetaType::QStringList: | ||||
return PythonQtConv::QStringListToPyObject(*((QStringList*)data)); | ||||
case PythonQtMethodInfo::Variant: | ||||
return PythonQtConv::QVariantToPyObject(*((QVariant*)data)); | ||||
case QMetaType::QObjectStar: | ||||
case QMetaType::QWidgetStar: | ||||
return PythonQt::priv()->wrapQObject(*((QObject**)data)); | ||||
default: | ||||
if (PythonQt::priv()->isPythonQtObjectPtrMetaId(type)) { | ||||
florianlink
|
r10 | // special case, it is a PythonQtObjectPtr which contains a PyObject, take it directly: | ||
ezust
|
r0 | PyObject* o = ((PythonQtObjectPtr*)data)->object(); | ||
Py_INCREF(o); | ||||
return o; | ||||
} else { | ||||
florianlink
|
r10 | if (type > 0) { | ||
// if the type is known, we can construct it via QMetaType::construct | ||||
void* newCPPObject = QMetaType::construct(type, data); | ||||
// XXX this could be optimized by using metatypeid directly | ||||
florianlink
|
r16 | PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)PythonQt::priv()->wrapPtr(newCPPObject, QMetaType::typeName(type)); | ||
florianlink
|
r10 | wrap->_ownedByPythonQt = true; | ||
wrap->_useQMetaTypeDestroy = true; | ||||
return (PyObject*)wrap; | ||||
ezust
|
r0 | } | ||
std::cerr << "Unknown type that can not be converted to Python: " << type << ", in " << __FILE__ << ":" << __LINE__ << std::endl; | ||||
} | ||||
} | ||||
Py_INCREF(Py_None); | ||||
return Py_None; | ||||
} | ||||
void* PythonQtConv::CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info) { | ||||
void* ptr = NULL; | ||||
if (info.isPointer) { | ||||
PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr); | ||||
} else { | ||||
switch (info.typeId) { | ||||
case QMetaType::Char: | ||||
case QMetaType::UChar: | ||||
case QMetaType::Short: | ||||
case QMetaType::UShort: | ||||
case QMetaType::Long: | ||||
case QMetaType::ULong: | ||||
case QMetaType::Bool: | ||||
case QMetaType::Int: | ||||
case QMetaType::UInt: | ||||
case QMetaType::QChar: | ||||
case QMetaType::Float: | ||||
case QMetaType::Double: | ||||
PythonQtValueStorage_ADD_VALUE(global_valueStorage, long, 0, ptr); | ||||
break; | ||||
case PythonQtMethodInfo::Variant: | ||||
PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, 0, ptr); | ||||
// return the ptr to the variant | ||||
break; | ||||
default: | ||||
if (info.typeId == PythonQtMethodInfo::Unknown) { | ||||
// check if we have a QList of pointers, which we can circumvent with a QList<void*> | ||||
if (info.name.startsWith("QList<")) { | ||||
QByteArray innerType = info.name.mid(6,info.name.length()-7); | ||||
if (innerType.endsWith("*")) { | ||||
static int id = QMetaType::type("QList<void*>"); | ||||
PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr); | ||||
// return the constData pointer that will be filled with the result value later on | ||||
ptr = (void*)((QVariant*)ptr)->constData(); | ||||
} | ||||
} | ||||
} | ||||
if (!ptr) { | ||||
// everything else is stored in a QVariant... | ||||
PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr); | ||||
// return the constData pointer that will be filled with the result value later on | ||||
ptr = (void*)((QVariant*)ptr)->constData(); | ||||
} | ||||
} | ||||
} | ||||
return ptr; | ||||
} | ||||
void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, const QMetaObject* meta) | ||||
{ | ||||
bool ok; | ||||
void* ptr = NULL; | ||||
florianlink
|
r18 | if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) && info.typeId != PythonQtMethodInfo::Variant) { | ||
florianlink
|
r10 | // if we have a Qt wrapper object and if we do not need a QVariant, we do the following: | ||
// (the Variant case is handled below in a switch) | ||||
// a C++ wrapper (can be passed as pointer or reference) | ||||
florianlink
|
r16 | PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)obj; | ||
florianlink
|
r18 | if (wrap->classInfo()->inherits(info.name)) { | ||
florianlink
|
r10 | void* object; | ||
florianlink
|
r18 | if (wrap->classInfo()->isCPPWrapper()) { | ||
florianlink
|
r10 | object = wrap->_wrappedPtr; | ||
ezust
|
r0 | } else { | ||
florianlink
|
r10 | QObject* tmp = wrap->_obj; | ||
object = tmp; | ||||
ezust
|
r0 | } | ||
florianlink
|
r10 | if (info.isPointer) { | ||
// store the wrapped pointer in an extra pointer and let ptr point to the extra pointer | ||||
PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, object, ptr); | ||||
ezust
|
r0 | } else { | ||
florianlink
|
r10 | // store the wrapped pointer directly, since we are a reference | ||
ptr = object; | ||||
} | ||||
} else { | ||||
// not matching | ||||
} | ||||
} else if (info.isPointer) { | ||||
// a pointer | ||||
if (info.typeId == QMetaType::Char || info.typeId == QMetaType::UChar) | ||||
{ | ||||
QString str = PyObjGetString(obj, strict, ok); | ||||
if (ok) { | ||||
void* ptr2 = NULL; | ||||
PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant(str.toUtf8()), ptr2); | ||||
PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr); | ||||
} | ||||
} else if (info.name == "PyObject") { | ||||
// handle low level PyObject directly | ||||
PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, obj, ptr); | ||||
} else if (obj == Py_None) { | ||||
// None is treated as a NULL ptr | ||||
PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr); | ||||
} else { | ||||
// if we are not strict, we try if we are passed a 0 integer | ||||
if (!strict) { | ||||
bool ok; | ||||
int value = PyObjGetInt(obj, true, ok); | ||||
if (ok && value==0) { | ||||
PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr); | ||||
ezust
|
r0 | } | ||
} | ||||
florianlink
|
r10 | } | ||
ezust
|
r0 | } else { | ||
// not a pointer | ||||
switch (info.typeId) { | ||||
case QMetaType::Char: | ||||
{ | ||||
int val = PyObjGetInt(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_valueStorage, char, val, ptr); | ||||
} | ||||
} | ||||
break; | ||||
case QMetaType::UChar: | ||||
{ | ||||
int val = PyObjGetInt(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned char, val, ptr); | ||||
} | ||||
} | ||||
break; | ||||
case QMetaType::Short: | ||||
{ | ||||
int val = PyObjGetInt(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_valueStorage, short, val, ptr); | ||||
} | ||||
} | ||||
break; | ||||
case QMetaType::UShort: | ||||
{ | ||||
int val = PyObjGetInt(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned short, val, ptr); | ||||
} | ||||
} | ||||
break; | ||||
case QMetaType::Long: | ||||
{ | ||||
long val = (long)PyObjGetLongLong(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_valueStorage, long, val, ptr); | ||||
} | ||||
} | ||||
break; | ||||
case QMetaType::ULong: | ||||
{ | ||||
unsigned long val = (unsigned long)PyObjGetLongLong(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned long, val, ptr); | ||||
} | ||||
} | ||||
break; | ||||
case QMetaType::Bool: | ||||
{ | ||||
bool val = PyObjGetBool(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_valueStorage, bool, val, ptr); | ||||
} | ||||
} | ||||
break; | ||||
case QMetaType::Int: | ||||
{ | ||||
int val = PyObjGetInt(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_valueStorage, int, val, ptr); | ||||
} | ||||
} | ||||
break; | ||||
case QMetaType::UInt: | ||||
{ | ||||
unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned int, val, ptr); | ||||
} | ||||
} | ||||
break; | ||||
case QMetaType::QChar: | ||||
{ | ||||
int val = PyObjGetInt(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_valueStorage, short, val, ptr); | ||||
} | ||||
} | ||||
break; | ||||
case QMetaType::Float: | ||||
{ | ||||
float val = (float)PyObjGetDouble(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_valueStorage, float, val, ptr); | ||||
} | ||||
} | ||||
break; | ||||
case QMetaType::Double: | ||||
{ | ||||
double val = (double)PyObjGetDouble(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_valueStorage, double, val, ptr); | ||||
} | ||||
} | ||||
break; | ||||
case QMetaType::LongLong: | ||||
{ | ||||
qint64 val = PyObjGetLongLong(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_valueStorage, qint64, val, ptr); | ||||
} | ||||
} | ||||
break; | ||||
case QMetaType::ULongLong: | ||||
{ | ||||
quint64 val = PyObjGetULongLong(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_valueStorage, quint64, val, ptr); | ||||
} | ||||
} | ||||
break; | ||||
case QMetaType::QByteArray: | ||||
{ | ||||
QByteArray bytes = PyObjGetBytes(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant(bytes), ptr); | ||||
ptr = (void*)((QVariant*)ptr)->constData(); | ||||
} | ||||
} | ||||
break; | ||||
case QMetaType::QString: | ||||
{ | ||||
QString str = PyObjGetString(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant(str), ptr); | ||||
ptr = (void*)((QVariant*)ptr)->constData(); | ||||
} | ||||
} | ||||
break; | ||||
case QMetaType::QStringList: | ||||
{ | ||||
QStringList l = PyObjToStringList(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant(l), ptr); | ||||
ptr = (void*)((QVariant*)ptr)->constData(); | ||||
} | ||||
} | ||||
break; | ||||
case PythonQtMethodInfo::Variant: | ||||
{ | ||||
QVariant v = PyObjToQVariant(obj); | ||||
if (v.isValid()) { | ||||
PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, v, ptr); | ||||
} | ||||
} | ||||
break; | ||||
default: | ||||
{ | ||||
if (info.typeId == PythonQtMethodInfo::Unknown) { | ||||
// check for enum case | ||||
if (PythonQt::priv()->isEnumType(meta, info.name)) { | ||||
unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok); | ||||
if (ok) { | ||||
PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned int, val, ptr); | ||||
return ptr; | ||||
florianlink
|
r4 | } else { | ||
return NULL; | ||||
ezust
|
r0 | } | ||
} | ||||
} | ||||
if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) { | ||||
// check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant | ||||
if (info.name.startsWith("QList<")) { | ||||
QByteArray innerType = info.name.mid(6,info.name.length()-7); | ||||
if (innerType.endsWith("*")) { | ||||
innerType.truncate(innerType.length()-1); | ||||
static int id = QMetaType::type("QList<void*>"); | ||||
PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr); | ||||
ptr = (void*)((QVariant*)ptr)->constData(); | ||||
florianlink
|
r10 | ok = ConvertPythonListToQListOfPointerType(obj, (QList<void*>*)ptr, innerType, strict); | ||
ezust
|
r0 | if (ok) { | ||
return ptr; | ||||
} else { | ||||
return NULL; | ||||
} | ||||
} | ||||
} | ||||
} | ||||
florianlink
|
r10 | // We only do this for registered type > QMetaType::User for performance reasons. | ||
if (info.typeId >= QMetaType::User) { | ||||
// Maybe we have a special converter that is registered for that type: | ||||
PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(info.typeId); | ||||
if (converter) { | ||||
// create a new empty variant of concrete type: | ||||
PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr); | ||||
ptr = (void*)((QVariant*)ptr)->constData(); | ||||
// now call the converter, passing the internal object of the variant | ||||
ok = (*converter)(obj, ptr, info.typeId, strict); | ||||
if (ok) { | ||||
return ptr; | ||||
} else { | ||||
return NULL; | ||||
} | ||||
} | ||||
} | ||||
ezust
|
r0 | // for all other types, we use the same qvariant conversion and pass out the constData of the variant: | ||
QVariant v = PyObjToQVariant(obj, info.typeId); | ||||
if (v.isValid()) { | ||||
PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, v, ptr); | ||||
ptr = (void*)((QVariant*)ptr)->constData(); | ||||
} | ||||
} | ||||
} | ||||
} | ||||
return ptr; | ||||
} | ||||
QStringList PythonQtConv::PyObjToStringList(PyObject* val, bool strict, bool& ok) { | ||||
QStringList v; | ||||
ok = false; | ||||
// if we are strict, we do not want to convert a string to a stringlist | ||||
// (strings in python are detected to be sequences) | ||||
if (strict && | ||||
(val->ob_type == &PyString_Type || | ||||
PyUnicode_Check(val))) { | ||||
ok = false; | ||||
return v; | ||||
} | ||||
if (PySequence_Check(val)) { | ||||
int count = PySequence_Size(val); | ||||
for (int i = 0;i<count;i++) { | ||||
PyObject* value = PySequence_GetItem(val,i); | ||||
v.append(PyObjGetString(value,false,ok)); | ||||
} | ||||
ok = true; | ||||
} | ||||
return v; | ||||
} | ||||
QString PythonQtConv::PyObjGetRepresentation(PyObject* val) | ||||
{ | ||||
QString r; | ||||
PyObject* str = PyObject_Repr(val); | ||||
if (str) { | ||||
r = QString(PyString_AS_STRING(str)); | ||||
Py_DECREF(str); | ||||
} | ||||
return r; | ||||
} | ||||
QString PythonQtConv::PyObjGetString(PyObject* val, bool strict, bool& ok) { | ||||
QString r; | ||||
ok = true; | ||||
if (val->ob_type == &PyString_Type) { | ||||
r = QString(PyString_AS_STRING(val)); | ||||
} else if (PyUnicode_Check(val)) { | ||||
#ifdef WIN32 | ||||
r = QString::fromUtf16(PyUnicode_AS_UNICODE(val)); | ||||
#else | ||||
PyObject *ptmp = PyUnicode_AsUTF8String(val); | ||||
if(ptmp) { | ||||
r = QString::fromUtf8(PyString_AS_STRING(ptmp)); | ||||
Py_DECREF(ptmp); | ||||
} | ||||
#endif | ||||
} else if (!strict) { | ||||
// EXTRA: could also use _Unicode, but why should we? | ||||
PyObject* str = PyObject_Str(val); | ||||
if (str) { | ||||
r = QString(PyString_AS_STRING(str)); | ||||
Py_DECREF(str); | ||||
} else { | ||||
ok = false; | ||||
} | ||||
} else { | ||||
ok = false; | ||||
} | ||||
return r; | ||||
} | ||||
florianlink
|
r8 | QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) { | ||
ezust
|
r0 | QByteArray r; | ||
ok = true; | ||||
if (val->ob_type == &PyString_Type) { | ||||
long size = PyString_GET_SIZE(val); | ||||
r = QByteArray(PyString_AS_STRING(val), size); | ||||
} else { | ||||
ok = false; | ||||
} | ||||
return r; | ||||
} | ||||
bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) { | ||||
bool d = false; | ||||
ok = false; | ||||
if (val == Py_False) { | ||||
d = false; | ||||
ok = true; | ||||
} else if (val == Py_True) { | ||||
d = true; | ||||
ok = true; | ||||
} else if (!strict) { | ||||
d = PyObjGetInt(val, false, ok)!=0; | ||||
ok = true; | ||||
} | ||||
return d; | ||||
} | ||||
int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) { | ||||
int d = 0; | ||||
ok = true; | ||||
if (val->ob_type == &PyInt_Type) { | ||||
d = PyInt_AS_LONG(val); | ||||
} else if (!strict) { | ||||
if (val->ob_type == &PyFloat_Type) { | ||||
d = floor(PyFloat_AS_DOUBLE(val)); | ||||
} else if (val->ob_type == &PyLong_Type) { | ||||
// handle error on overflow! | ||||
d = PyLong_AsLong(val); | ||||
} else if (val == Py_False) { | ||||
d = 0; | ||||
} else if (val == Py_True) { | ||||
d = 1; | ||||
} else { | ||||
ok = false; | ||||
} | ||||
} else { | ||||
ok = false; | ||||
} | ||||
return d; | ||||
} | ||||
qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) { | ||||
qint64 d = 0; | ||||
ok = true; | ||||
if (val->ob_type == &PyInt_Type) { | ||||
d = PyInt_AS_LONG(val); | ||||
} else if (val->ob_type == &PyLong_Type) { | ||||
d = PyLong_AsLongLong(val); | ||||
} else if (!strict) { | ||||
if (val->ob_type == &PyFloat_Type) { | ||||
d = floor(PyFloat_AS_DOUBLE(val)); | ||||
} else if (val == Py_False) { | ||||
d = 0; | ||||
} else if (val == Py_True) { | ||||
d = 1; | ||||
} else { | ||||
ok = false; | ||||
} | ||||
} else { | ||||
ok = false; | ||||
} | ||||
return d; | ||||
} | ||||
quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) { | ||||
quint64 d = 0; | ||||
ok = true; | ||||
if (val->ob_type == &PyInt_Type) { | ||||
d = PyInt_AS_LONG(val); | ||||
} else if (val->ob_type == &PyLong_Type) { | ||||
d = PyLong_AsLongLong(val); | ||||
} else if (!strict) { | ||||
if (val->ob_type == &PyFloat_Type) { | ||||
d = floor(PyFloat_AS_DOUBLE(val)); | ||||
} else if (val == Py_False) { | ||||
d = 0; | ||||
} else if (val == Py_True) { | ||||
d = 1; | ||||
} else { | ||||
ok = false; | ||||
} | ||||
} else { | ||||
ok = false; | ||||
} | ||||
return d; | ||||
} | ||||
double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) { | ||||
double d = 0; | ||||
ok = true; | ||||
if (val->ob_type == &PyFloat_Type) { | ||||
d = PyFloat_AS_DOUBLE(val); | ||||
} else if (!strict) { | ||||
if (val->ob_type == &PyInt_Type) { | ||||
d = PyInt_AS_LONG(val); | ||||
} else if (val->ob_type == &PyLong_Type) { | ||||
d = PyLong_AsLong(val); | ||||
} else if (val == Py_False) { | ||||
d = 0; | ||||
} else if (val == Py_True) { | ||||
d = 1; | ||||
} else { | ||||
ok = false; | ||||
} | ||||
} else { | ||||
ok = false; | ||||
} | ||||
return d; | ||||
} | ||||
QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) | ||||
{ | ||||
QVariant v; | ||||
bool ok = true; | ||||
if (type==-1) { | ||||
// no special type requested | ||||
if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) { | ||||
type = QVariant::String; | ||||
} else if (val->ob_type==&PyInt_Type) { | ||||
type = QVariant::Int; | ||||
} else if (val->ob_type==&PyLong_Type) { | ||||
type = QVariant::LongLong; | ||||
} else if (val->ob_type==&PyFloat_Type) { | ||||
type = QVariant::Double; | ||||
} else if (val == Py_False || val == Py_True) { | ||||
type = QVariant::Bool; | ||||
florianlink
|
r18 | } else if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) { | ||
florianlink
|
r16 | PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val; | ||
ezust
|
r0 | // c++ wrapper, check if the class names of the c++ objects match | ||
florianlink
|
r18 | if (wrap->classInfo()->isCPPWrapper()) { | ||
if (wrap->classInfo()->metaTypeId()>0) { | ||||
florianlink
|
r10 | // construct a new variant from the C++ object if it has a meta type | ||
florianlink
|
r18 | v = QVariant(wrap->classInfo()->metaTypeId(), wrap->_wrappedPtr); | ||
florianlink
|
r10 | } else { | ||
// is this worth anything? we loose the knowledge of the cpp object type | ||||
v = qVariantFromValue(wrap->_wrappedPtr); | ||||
} | ||||
ezust
|
r0 | } else { | ||
florianlink
|
r10 | // this gives us a QObject pointer | ||
florianlink
|
r4 | QObject* myObject = wrap->_obj; | ||
v = qVariantFromValue(myObject); | ||||
ezust
|
r0 | } | ||
return v; | ||||
} else if (val->ob_type==&PyDict_Type) { | ||||
type = QVariant::Map; | ||||
} else if (val->ob_type==&PyList_Type || val->ob_type==&PyTuple_Type || PySequence_Check(val)) { | ||||
type = QVariant::List; | ||||
} else if (val == Py_None) { | ||||
// none is invalid | ||||
type = QVariant::Invalid; | ||||
} else { | ||||
// this used to be: | ||||
// type = QVariant::String; | ||||
// but now we want to transport the Python Objects directly: | ||||
PythonQtObjectPtr o(val); | ||||
v = qVariantFromValue(o); | ||||
return v; | ||||
} | ||||
} | ||||
// special type request: | ||||
switch (type) { | ||||
case QVariant::Invalid: | ||||
return v; | ||||
break; | ||||
case QVariant::Int: | ||||
{ | ||||
int d = PyObjGetInt(val, false, ok); | ||||
if (ok) return QVariant(d); | ||||
} | ||||
break; | ||||
case QVariant::UInt: | ||||
{ | ||||
int d = PyObjGetInt(val, false,ok); | ||||
if (ok) v = QVariant((unsigned int)d); | ||||
} | ||||
break; | ||||
case QVariant::Bool: | ||||
{ | ||||
int d = PyObjGetBool(val,false,ok); | ||||
if (ok) v = QVariant((bool)(d!=0)); | ||||
} | ||||
break; | ||||
case QVariant::Double: | ||||
{ | ||||
double d = PyObjGetDouble(val,false,ok); | ||||
if (ok) v = QVariant(d); | ||||
break; | ||||
} | ||||
case QMetaType::Float: | ||||
{ | ||||
float d = (float) PyObjGetDouble(val,false,ok); | ||||
if (ok) v = qVariantFromValue(d); | ||||
break; | ||||
} | ||||
case QMetaType::Long: | ||||
{ | ||||
long d = (long) PyObjGetLongLong(val,false,ok); | ||||
if (ok) v = qVariantFromValue(d); | ||||
break; | ||||
} | ||||
case QMetaType::ULong: | ||||
{ | ||||
unsigned long d = (unsigned long) PyObjGetLongLong(val,false,ok); | ||||
if (ok) v = qVariantFromValue(d); | ||||
break; | ||||
} | ||||
case QMetaType::Short: | ||||
{ | ||||
short d = (short) PyObjGetInt(val,false,ok); | ||||
if (ok) v = qVariantFromValue(d); | ||||
break; | ||||
} | ||||
case QMetaType::UShort: | ||||
{ | ||||
unsigned short d = (unsigned short) PyObjGetInt(val,false,ok); | ||||
if (ok) v = qVariantFromValue(d); | ||||
break; | ||||
} | ||||
case QMetaType::Char: | ||||
{ | ||||
char d = (char) PyObjGetInt(val,false,ok); | ||||
if (ok) v = qVariantFromValue(d); | ||||
break; | ||||
} | ||||
case QMetaType::UChar: | ||||
{ | ||||
unsigned char d = (unsigned char) PyObjGetInt(val,false,ok); | ||||
if (ok) v = qVariantFromValue(d); | ||||
break; | ||||
} | ||||
case QVariant::ByteArray: | ||||
case QVariant::String: | ||||
{ | ||||
bool ok; | ||||
v = QVariant(PyObjGetString(val, false, ok)); | ||||
} | ||||
break; | ||||
// these are important for MeVisLab | ||||
case QVariant::Map: | ||||
{ | ||||
if (PyMapping_Check(val)) { | ||||
QMap<QString,QVariant> map; | ||||
PyObject* items = PyMapping_Items(val); | ||||
if (items) { | ||||
int count = PyList_Size(items); | ||||
PyObject* value; | ||||
PyObject* key; | ||||
PyObject* tuple; | ||||
for (int i = 0;i<count;i++) { | ||||
tuple = PyList_GetItem(items,i); | ||||
key = PyTuple_GetItem(tuple, 0); | ||||
value = PyTuple_GetItem(tuple, 1); | ||||
map.insert(PyObjGetString(key), PyObjToQVariant(value,-1)); | ||||
} | ||||
Py_DECREF(items); | ||||
v = map; | ||||
} | ||||
} | ||||
} | ||||
break; | ||||
case QVariant::List: | ||||
if (PySequence_Check(val)) { | ||||
QVariantList list; | ||||
int count = PySequence_Size(val); | ||||
PyObject* value; | ||||
for (int i = 0;i<count;i++) { | ||||
value = PySequence_GetItem(val,i); | ||||
list.append(PyObjToQVariant(value, -1)); | ||||
} | ||||
v = list; | ||||
} | ||||
break; | ||||
case QVariant::StringList: | ||||
{ | ||||
bool ok; | ||||
QStringList l = PyObjToStringList(val, false, ok); | ||||
if (ok) { | ||||
v = l; | ||||
} | ||||
} | ||||
break; | ||||
default: | ||||
florianlink
|
r18 | if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) { | ||
florianlink
|
r16 | PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val; | ||
florianlink
|
r18 | if (wrap->classInfo()->isCPPWrapper() && wrap->classInfo()->metaTypeId() == type) { | ||
florianlink
|
r10 | // construct a new variant from the C++ object if it has the same meta type | ||
v = QVariant(type, wrap->_wrappedPtr); | ||||
} else { | ||||
v = QVariant(); | ||||
ezust
|
r0 | } | ||
} else { | ||||
v = QVariant(); | ||||
} | ||||
} | ||||
return v; | ||||
} | ||||
PyObject* PythonQtConv::QStringToPyObject(const QString& str) | ||||
{ | ||||
if (str.isNull()) { | ||||
return PyString_FromString(""); | ||||
} else { | ||||
#ifdef WIN32 | ||||
// return PyString_FromString(str.toLatin1().data()); | ||||
return PyUnicode_FromUnicode(str.utf16(), str.length()); | ||||
#else | ||||
return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, NULL, NULL); | ||||
#endif | ||||
} | ||||
} | ||||
PyObject* PythonQtConv::QStringListToPyObject(const QStringList& list) | ||||
{ | ||||
PyObject* result = PyTuple_New(list.count()); | ||||
int i = 0; | ||||
QString str; | ||||
foreach (str, list) { | ||||
PyTuple_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(str)); | ||||
i++; | ||||
} | ||||
// why is the error state bad after this? | ||||
PyErr_Clear(); | ||||
return result; | ||||
} | ||||
PyObject* PythonQtConv::QStringListToPyList(const QStringList& list) | ||||
{ | ||||
PyObject* result = PyList_New(list.count()); | ||||
int i = 0; | ||||
for (QStringList::ConstIterator it = list.begin(); it!=list.end(); ++it) { | ||||
PyList_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(*it)); | ||||
i++; | ||||
} | ||||
return result; | ||||
} | ||||
PyObject* PythonQtConv::QVariantToPyObject(const QVariant& v) | ||||
{ | ||||
return ConvertQtValueToPythonInternal(v.userType(), (void*)v.constData()); | ||||
} | ||||
PyObject* PythonQtConv::QVariantMapToPyObject(const QVariantMap& m) { | ||||
PyObject* result = PyDict_New(); | ||||
QVariantMap::const_iterator t = m.constBegin(); | ||||
PyObject* key; | ||||
PyObject* val; | ||||
for (;t!=m.end();t++) { | ||||
key = QStringToPyObject(t.key()); | ||||
val = QVariantToPyObject(t.value()); | ||||
PyDict_SetItem(result, key, val); | ||||
Py_DECREF(key); | ||||
Py_DECREF(val); | ||||
} | ||||
return result; | ||||
} | ||||
PyObject* PythonQtConv::QVariantListToPyObject(const QVariantList& l) { | ||||
PyObject* result = PyTuple_New(l.count()); | ||||
int i = 0; | ||||
QVariant v; | ||||
foreach (v, l) { | ||||
PyTuple_SET_ITEM(result, i, PythonQtConv::QVariantToPyObject(v)); | ||||
i++; | ||||
} | ||||
// why is the error state bad after this? | ||||
PyErr_Clear(); | ||||
return result; | ||||
} | ||||
florianlink
|
r10 | PyObject* PythonQtConv::ConvertQListOfPointerTypeToPythonList(QList<void*>* list, const QByteArray& typeName) | ||
ezust
|
r0 | { | ||
PyObject* result = PyTuple_New(list->count()); | ||||
int i = 0; | ||||
foreach (void* value, *list) { | ||||
florianlink
|
r10 | PyTuple_SET_ITEM(result, i, PythonQt::priv()->wrapPtr(value, typeName)); | ||
ezust
|
r0 | i++; | ||
} | ||||
return result; | ||||
} | ||||
florianlink
|
r10 | bool PythonQtConv::ConvertPythonListToQListOfPointerType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool /*strict*/) | ||
ezust
|
r0 | { | ||
bool result = false; | ||||
if (PySequence_Check(obj)) { | ||||
result = true; | ||||
int count = PySequence_Size(obj); | ||||
PyObject* value; | ||||
for (int i = 0;i<count;i++) { | ||||
value = PySequence_GetItem(obj,i); | ||||
florianlink
|
r18 | if (PyObject_TypeCheck(value, &PythonQtInstanceWrapper_Type)) { | ||
florianlink
|
r16 | PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)value; | ||
florianlink
|
r10 | // both QObjects and CPP wrappers support inherits, so we use that to check of we match | ||
florianlink
|
r18 | if (wrap->classInfo()->inherits(type)) { | ||
if (wrap->classInfo()->isCPPWrapper()) { | ||||
ezust
|
r0 | list->append(wrap->_wrappedPtr); | ||
} else { | ||||
florianlink
|
r4 | QObject* myObject = wrap->_obj; | ||
list->append((void*)myObject); | ||||
ezust
|
r0 | } | ||
florianlink
|
r10 | } else { | ||
result = false; | ||||
break; | ||||
ezust
|
r0 | } | ||
} | ||||
} | ||||
} | ||||
return result; | ||||
} | ||||
florianlink
|
r10 | int PythonQtConv::getInnerTemplateMetaType(const QByteArray& typeName) | ||
{ | ||||
int idx = typeName.indexOf("<"); | ||||
if (idx>0) { | ||||
int idx2 = typeName.indexOf(">"); | ||||
if (idx2>0) { | ||||
QByteArray innerType = typeName.mid(idx+1,idx2-idx-1); | ||||
return QMetaType::type(innerType.constData()); | ||||
} | ||||
} | ||||
return QMetaType::Void; | ||||
} | ||||
QString PythonQtConv::qVariantToString(const QVariant& v) { | ||||
return CPPObjectToString(v.userType(), v.constData()); | ||||
} | ||||
QString PythonQtConv::CPPObjectToString(int type, const void* data) { | ||||
QString r; | ||||
switch (type) { | ||||
case QVariant::Size: { | ||||
const QSize* s = static_cast<const QSize*>(data); | ||||
r = QString::number(s->width()) + ", " + QString::number(s->height()); | ||||
} | ||||
break; | ||||
case QVariant::SizeF: { | ||||
const QSizeF* s = static_cast<const QSizeF*>(data); | ||||
r = QString::number(s->width()) + ", " + QString::number(s->height()); | ||||
} | ||||
break; | ||||
case QVariant::Point: { | ||||
const QPoint* s = static_cast<const QPoint*>(data); | ||||
r = QString::number(s->x()) + ", " + QString::number(s->y()); | ||||
} | ||||
break; | ||||
case QVariant::PointF: { | ||||
const QPointF* s = static_cast<const QPointF*>(data); | ||||
r = QString::number(s->x()) + ", " + QString::number(s->y()); | ||||
} | ||||
break; | ||||
case QVariant::Rect: { | ||||
const QRect* s = static_cast<const QRect*>(data); | ||||
r = QString::number(s->x()) + ", " + QString::number(s->y()); | ||||
r += ", " + QString::number(s->width()) + ", " + QString::number(s->height()); | ||||
} | ||||
break; | ||||
case QVariant::RectF: { | ||||
const QRectF* s = static_cast<const QRectF*>(data); | ||||
r = QString::number(s->x()) + ", " + QString::number(s->y()); | ||||
r += ", " + QString::number(s->width()) + ", " + QString::number(s->height()); | ||||
} | ||||
break; | ||||
case QVariant::Date: { | ||||
const QDate* s = static_cast<const QDate*>(data); | ||||
r = s->toString(Qt::ISODate); | ||||
} | ||||
break; | ||||
case QVariant::DateTime: { | ||||
const QDateTime* s = static_cast<const QDateTime*>(data); | ||||
r = s->toString(Qt::ISODate); | ||||
} | ||||
break; | ||||
case QVariant::Time: { | ||||
const QTime* s = static_cast<const QTime*>(data); | ||||
r = s->toString(Qt::ISODate); | ||||
} | ||||
break; | ||||
case QVariant::Pixmap: | ||||
{ | ||||
const QPixmap* s = static_cast<const QPixmap*>(data); | ||||
r = QString("Pixmap ") + QString::number(s->width()) + ", " + QString::number(s->height()); | ||||
} | ||||
break; | ||||
case QVariant::Image: | ||||
{ | ||||
const QImage* s = static_cast<const QImage*>(data); | ||||
r = QString("Image ") + QString::number(s->width()) + ", " + QString::number(s->height()); | ||||
} | ||||
break; | ||||
case QVariant::Url: | ||||
{ | ||||
const QUrl* s = static_cast<const QUrl*>(data); | ||||
r = s->toString(); | ||||
} | ||||
break; | ||||
//TODO: add more printing for other variant types | ||||
default: | ||||
// this creates a copy, but that should not be expensive for typical simple variants | ||||
// (but we do not want to do this for our won user types! | ||||
if (type>0 && type < (int)QVariant::UserType) { | ||||
QVariant v(type, data); | ||||
r = v.toString(); | ||||
} | ||||
} | ||||
return r; | ||||
} | ||||