Skip to content

Commit 4563bba

Browse files
committed
cache enumWrappers in method infos and make use of the extra information for better enum overloading
1 parent a3e2db8 commit 4563bba

9 files changed

Lines changed: 61 additions & 60 deletions

src/PythonQt.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -915,9 +915,9 @@ void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
915915
QMetaMethod m = o->metaObject()->method(i);
916916
if ((m.methodType() == QMetaMethod::Method ||
917917
m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
918-
const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
919918
if (qstrncmp(m.signature(), "new_", 4)==0) {
920919
if ((decoTypes & ConstructorDecorator) == 0) continue;
920+
const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
921921
if (info->parameters().at(0).isPointer) {
922922
QByteArray signature = m.signature();
923923
QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
@@ -942,6 +942,7 @@ void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
942942
classInfo->addDecoratorSlot(newSlot);
943943
} else {
944944
if ((decoTypes & InstanceDecorator) == 0) continue;
945+
const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
945946
if (info->parameters().count()>1) {
946947
PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
947948
if (p.isPointer) {

src/PythonQtClassInfo.cpp

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,9 @@ bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char*
251251
int enumCount = meta->enumeratorCount();
252252
for (int i=0;i<enumCount; i++) {
253253
QMetaEnum e = meta->enumerator(i);
254+
// we do not want flags, they will cause our values to appear two times
255+
if (e.isFlag()) continue;
256+
254257
for (int j=0; j < e.keyCount(); j++) {
255258
if (qstrcmp(e.key(j), memberName)==0) {
256259
PyObject* enumType = findEnumWrapper(e.name());
@@ -490,6 +493,9 @@ QStringList PythonQtClassInfo::memberList(bool metaOnly)
490493
for (int i = 0; i<meta->enumeratorCount(); i++) {
491494
QMetaEnum e = meta->enumerator(i);
492495
l << e.name();
496+
// we do not want flags, they will cause our values to appear two times
497+
if (e.isFlag()) continue;
498+
493499
for (int j=0; j < e.keyCount(); j++) {
494500
l << QString(e.key(j));
495501
}
@@ -750,46 +756,27 @@ void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resul
750756
return resultPtr;
751757
}
752758

753-
bool PythonQtClassInfo::hasEnum(const QByteArray& name, PythonQtClassInfo* localScope)
759+
PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool& isLocalEnum)
754760
{
761+
isLocalEnum = true;
755762
int scopePos = name.lastIndexOf("::");
756763
if (scopePos != -1) {
764+
isLocalEnum = false;
757765
// slit into scope and enum name
758766
QByteArray enumScope = name.mid(0,scopePos);
759767
QByteArray enumName = name.mid(scopePos+2);
760768
PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(enumScope);
761769
if (info) {
762-
return info->hasEnum(enumName);
770+
return info->findEnumWrapper(enumName);
763771
} else{
764-
return false;
772+
return NULL;
765773
}
766774
}
767775
if (localScope) {
768-
return localScope->hasEnum(name);
776+
return localScope->findEnumWrapper(name);
769777
} else {
770-
return false;
771-
}
772-
}
773-
774-
bool PythonQtClassInfo::hasEnum(const QByteArray& name)
775-
{
776-
bool found = false;
777-
if (_meta) {
778-
found = _meta->indexOfEnumerator(name)!=-1;
779-
}
780-
if (!found) {
781-
// check enums in the class hierachy of CPP classes
782-
// look for dynamic decorators in this class and in derived classes
783-
QList<QObject*> decoObjects;
784-
recursiveCollectDecoratorObjects(decoObjects);
785-
foreach(QObject* deco, decoObjects) {
786-
found = deco->metaObject()->indexOfEnumerator(name)!=-1;
787-
if (found) {
788-
break;
789-
}
790-
}
778+
return NULL;
791779
}
792-
return found;
793780
}
794781

795782
void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta)

src/PythonQtClassInfo.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,16 +195,13 @@ class PythonQtClassInfo {
195195
void* castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo);
196196

197197
//! returns if the localScope has an enum of that type name or if the enum contains a :: scope, if that class contails the enum
198-
static bool hasEnum(const QByteArray& name, PythonQtClassInfo* localScope);
198+
static PyObject* findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool& isLocalEnum);
199199

200200
private:
201201
void createEnumWrappers();
202202
void createEnumWrappers(const QMetaObject* meta);
203203
PyObject* findEnumWrapper(const char* name);
204204

205-
//! checks if the enum is part of this class (without any leading scope!)
206-
bool hasEnum(const QByteArray& name);
207-
208205
//! clear all cached members
209206
void clearCachedMembers();
210207

src/PythonQtConversion.cpp

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ return Py_None;
240240
return object;
241241
}
242242

243-
void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* meta, void* alreadyAllocatedCPPObject)
243+
void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* /*classInfo*/, void* alreadyAllocatedCPPObject)
244244
{
245245
bool ok;
246246
void* ptr = NULL;
@@ -442,18 +442,25 @@ return Py_None;
442442
break;
443443
default:
444444
{
445-
if (info.typeId == PythonQtMethodInfo::Unknown) {
446-
// check for enum case
447-
if (PythonQtClassInfo::hasEnum(info.name, meta)) {
448-
unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
449-
if (ok) {
450-
PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
451-
return ptr;
452-
} else {
453-
return NULL;
454-
}
445+
// check for enum case
446+
if (info.enumWrapper) {
447+
unsigned int val;
448+
if ((PyObject*)obj->ob_type == info.enumWrapper) {
449+
// we have a direct enum type match:
450+
val = PyInt_AS_LONG(obj);
451+
ok = true;
452+
} else {
453+
// we try to get an integer, and in strict mode, it may not be a derived int class, so that no other enum can be taken as an int
454+
val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
455+
}
456+
if (ok) {
457+
PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
458+
return ptr;
459+
} else {
460+
return NULL;
455461
}
456462
}
463+
457464
if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
458465
// check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant
459466
if (info.name.startsWith("QList<")) {

src/PythonQtConversion.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ class PYTHONQT_EXPORT PythonQtConv {
7777
//! converts the Qt parameter given in \c data, interpreting it as a \c info parameter, into a Python object,
7878
static PyObject* ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data);
7979

80-
//! convert python object to Qt (according to the given parameter) and if the conversion should be strict, the meta object is passed in for enum resolving
81-
static void* ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* meta, void* alreadyAllocatedCPPObject = NULL);
80+
//! convert python object to Qt (according to the given parameter) and if the conversion should be strict (classInfo is currently not used anymore)
81+
static void* ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* classInfo, void* alreadyAllocatedCPPObject = NULL);
8282

8383
//! creates a data storage for the passed parameter type and returns a void pointer to be set as arg[0] of qt_metacall
8484
static void* CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info);

src/PythonQtInstanceWrapper.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ static void PythonQtInstanceWrapper_dealloc(PythonQtInstanceWrapper* self)
114114
self->ob_type->tp_free((PyObject*)self);
115115
}
116116

117-
static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * args, PyObject * /*kwds*/)
117+
static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
118118
{
119119
//PythonQtClassWrapper *classType = (PythonQtClassWrapper*)type;
120120
PythonQtInstanceWrapper *self;
@@ -415,7 +415,7 @@ static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj)
415415
return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
416416
}
417417
} else {
418-
return PyString_FromFormat("%s (QObject %p)", typeName, wrapper->classInfo()->className(), qobj);
418+
return PyString_FromFormat("%s (%s %p)", typeName, wrapper->classInfo()->className(), qobj);
419419
}
420420
}
421421

src/PythonQtMethodInfo.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInf
5656
#endif
5757

5858
ParameterInfo type;
59-
fillParameterInfo(type, QByteArray(meta.typeName()));
59+
fillParameterInfo(type, QByteArray(meta.typeName()), classInfo);
6060
_parameters.append(type);
6161
QByteArray name;
6262
QList<QByteArray> names = meta.parameterTypes();
6363
foreach (name, names) {
64-
fillParameterInfo(type, name);
64+
fillParameterInfo(type, name, classInfo);
6565
_parameters.append(type);
6666
}
6767
}
@@ -87,10 +87,12 @@ const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromMetaObjectA
8787
return PythonQtMethodInfo::getCachedMethodInfo(meta, NULL);
8888
}
8989

90-
void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName)
90+
void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo)
9191
{
9292
QByteArray name = orgName;
9393

94+
type.enumWrapper = NULL;
95+
9496
int len = name.length();
9597
if (len>0) {
9698
if (strncmp(name.constData(), "const ", 6)==0) {
@@ -129,6 +131,12 @@ void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray
129131
}
130132
}
131133
type.name = name;
134+
135+
if (type.typeId == PythonQtMethodInfo::Unknown || type.typeId >= QMetaType::User) {
136+
bool isLocalEnum;
137+
// TODOXXX: make use of this flag!
138+
type.enumWrapper = PythonQtClassInfo::findEnumWrapper(type.name, classInfo, isLocalEnum);
139+
}
132140
} else {
133141
type.typeId = QMetaType::Void;
134142
type.isPointer = false;

src/PythonQtMethodInfo.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
#include <QMetaMethod>
5151

5252
class PythonQtClassInfo;
53+
struct _object;
54+
typedef struct _object PyObject;
5355

5456
//! stores information about a specific signal/slot/method
5557
class PYTHONQT_EXPORT PythonQtMethodInfo
@@ -62,8 +64,9 @@ class PYTHONQT_EXPORT PythonQtMethodInfo
6264

6365
//! stores the QVariant id (if available) and the name of the type
6466
struct ParameterInfo {
65-
int typeId; // a mixture from QMetaType and ParameterType
6667
QByteArray name;
68+
PyObject* enumWrapper; // if it is an enum, a pointer to the enum wrapper
69+
int typeId; // a mixture from QMetaType and ParameterType
6770
bool isPointer;
6871
bool isConst;
6972
};
@@ -98,7 +101,7 @@ class PYTHONQT_EXPORT PythonQtMethodInfo
98101
static void addParameterTypeAlias(const QByteArray& alias, const QByteArray& name);
99102

100103
protected:
101-
static void fillParameterInfo(ParameterInfo& type, const QByteArray& name);
104+
static void fillParameterInfo(ParameterInfo& type, const QByteArray& name, PythonQtClassInfo* classInfo);
102105

103106
static QHash<QByteArray, int> _parameterTypeDict;
104107
static QHash<QByteArray, QByteArray> _parameterNameAliases;

src/PythonQtSlot.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj
7474
int argc = info->parameterCount();
7575
const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters();
7676

77-
bool returnValueIsEnum = false;
7877
const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);
7978
// set return argument to NULL
8079
argList[0] = NULL;
@@ -119,17 +118,16 @@ bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj
119118
}
120119

121120
if (ok) {
121+
bool returnValueIsEnum = false;
122+
122123
// parameters are ok, now create the qt return value which is assigned to by metacall
123124
if (returnValueParam.typeId != QMetaType::Void) {
124125
// extra handling of enum return value
125-
if (!returnValueParam.isPointer && returnValueParam.typeId == PythonQtMethodInfo::Unknown) {
126-
returnValueIsEnum = PythonQtClassInfo::hasEnum(returnValueParam.name, classInfo);
127-
if (returnValueIsEnum) {
128-
// create enum return value
129-
PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, argList[0]);
130-
}
131-
}
132-
if (argList[0]==NULL) {
126+
if (!returnValueParam.isPointer && returnValueParam.enumWrapper) {
127+
// create enum return value
128+
PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, argList[0]);
129+
returnValueIsEnum = true;
130+
} else {
133131
// create empty default value for the return value
134132
if (!directReturnValuePointer) {
135133
// create empty default value for the return value

0 commit comments

Comments
 (0)