##// END OF EJS Templates
added enum wrapper classes derived from python int, so that enums are distinguishable from normal python integers. This will allow better overload handling e.g. of QColor constructors in the future...
florianlink -
r51:581e3ee75957
parent child
Show More
@@ -431,6 +431,30 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtCla
431 return result;
431 return result;
432 }
432 }
433
433
434 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
435 PyObject* result;
436
437 PyObject* className = PyString_FromString(enumName);
438
439 PyObject* baseClasses = PyTuple_New(1);
440 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
441
442 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
443 PyObject* typeDict = PyDict_New();
444 PyDict_SetItemString(typeDict, "__module__", module);
445
446 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
447
448 // create the new int derived type object by calling the core type
449 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
450
451 Py_DECREF(baseClasses);
452 Py_DECREF(typeDict);
453 Py_DECREF(args);
454 Py_DECREF(className);
455
456 return result;
457 }
434
458
435 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
459 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
436 {
460 {
@@ -446,6 +446,9 public:
446 //! helper method that creates a PythonQtClassWrapper object
446 //! helper method that creates a PythonQtClassWrapper object
447 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package = NULL);
447 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package = NULL);
448
448
449 //! helper that creates a new int derived class that represents the enum of the given name
450 PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
451
449 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
452 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
450 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
453 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
451
454
@@ -43,6 +43,8
43 #include "PythonQtMethodInfo.h"
43 #include "PythonQtMethodInfo.h"
44 #include "PythonQt.h"
44 #include "PythonQt.h"
45 #include <QMetaMethod>
45 #include <QMetaMethod>
46 #include <QMetaObject>
47 #include <QMetaEnum>
46
48
47 QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;
49 QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;
48
50
@@ -56,6 +58,7 PythonQtClassInfo::PythonQtClassInfo() {
56 _shellSetInstanceWrapperCB = NULL;
58 _shellSetInstanceWrapperCB = NULL;
57 _metaTypeId = -1;
59 _metaTypeId = -1;
58 _isQObject = false;
60 _isQObject = false;
61 _enumsCreated = false;
59 }
62 }
60
63
61 PythonQtClassInfo::~PythonQtClassInfo()
64 PythonQtClassInfo::~PythonQtClassInfo()
@@ -250,13 +253,23 bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char*
250 QMetaEnum e = meta->enumerator(i);
253 QMetaEnum e = meta->enumerator(i);
251 for (int j=0; j < e.keyCount(); j++) {
254 for (int j=0; j < e.keyCount(); j++) {
252 if (qstrcmp(e.key(j), memberName)==0) {
255 if (qstrcmp(e.key(j), memberName)==0) {
253 PythonQtMemberInfo newInfo(e.value(j));
256 PyObject* enumType = findEnumWrapper(e.name());
254 _cachedMembers.insert(memberName, newInfo);
257 if (enumType) {
258 PyObject* args = Py_BuildValue("(i)", e.value(j));
259 PyObject* enumValue = PyObject_Call(enumType, args, NULL);
260 Py_DECREF(args);
261 PythonQtObjectPtr enumValuePtr;
262 enumValuePtr.setNewRef(enumValue);
263 PythonQtMemberInfo newInfo(enumValuePtr);
264 _cachedMembers.insert(memberName, newInfo);
255 #ifdef PYTHONQT_DEBUG
265 #ifdef PYTHONQT_DEBUG
256 std::cout << "caching enum " << memberName << " on " << meta->className() << std::endl;
266 std::cout << "caching enum " << memberName << " on " << meta->className() << std::endl;
257 #endif
267 #endif
258 found = true;
268 found = true;
259 break;
269 break;
270 } else {
271 std::cout << "enum " << e.name() << " not found on " << className() << std::endl;
272 }
260 }
273 }
261 }
274 }
262 }
275 }
@@ -295,6 +308,15 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
295 }
308 }
296 }
309 }
297 if (!found) {
310 if (!found) {
311 PyObject* p = findEnumWrapper(memberName);
312 if (p) {
313 info._type = PythonQtMemberInfo::EnumWrapper;
314 info._enumWrapper = p;
315 _cachedMembers.insert(memberName, info);
316 found = true;
317 }
318 }
319 if (!found) {
298 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
320 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
299 info._type = PythonQtMemberInfo::NotFound;
321 info._type = PythonQtMemberInfo::NotFound;
300 _cachedMembers.insert(memberName, info);
322 _cachedMembers.insert(memberName, info);
@@ -470,6 +492,7 QStringList PythonQtClassInfo::memberList(bool metaOnly)
470 foreach(const QMetaObject* meta, enumMetaObjects) {
492 foreach(const QMetaObject* meta, enumMetaObjects) {
471 for (int i = 0; i<meta->enumeratorCount(); i++) {
493 for (int i = 0; i<meta->enumeratorCount(); i++) {
472 QMetaEnum e = meta->enumerator(i);
494 QMetaEnum e = meta->enumerator(i);
495 l << e.name();
473 for (int j=0; j < e.keyCount(); j++) {
496 for (int j=0; j < e.keyCount(); j++) {
474 l << QString(e.key(j));
497 l << QString(e.key(j));
475 }
498 }
@@ -661,6 +684,9 QObject* PythonQtClassInfo::decorator()
661 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
684 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
662 }
685 }
663 }
686 }
687 if (!_enumsCreated) {
688 createEnumWrappers();
689 }
664 return _decoratorProvider;
690 return _decoratorProvider;
665 }
691 }
666
692
@@ -768,3 +794,43 bool PythonQtClassInfo::hasEnum(const QByteArray& name)
768 return found;
794 return found;
769 }
795 }
770
796
797 void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta)
798 {
799 for (int i = meta->enumeratorOffset();i<meta->enumeratorCount();i++) {
800 QMetaEnum e = meta->enumerator(i);
801 PythonQtObjectPtr p;
802 p.setNewRef(PythonQt::priv()->createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper));
803 _enumWrappers.append(p);
804 }
805 }
806
807 void PythonQtClassInfo::createEnumWrappers()
808 {
809 if (!_enumsCreated) {
810 _enumsCreated = true;
811 if (_meta) {
812 createEnumWrappers(_meta);
813 }
814 if (decorator()) {
815 createEnumWrappers(decorator()->metaObject());
816 }
817 foreach(const ParentClassInfo& info, _parentClasses) {
818 info._parent->createEnumWrappers();
819 }
820 }
821 }
822
823 PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) {
824 foreach(const PythonQtObjectPtr& p, _enumWrappers) {
825 const char* className = ((PyTypeObject*)p.object())->tp_name;
826 if (qstrcmp(className, name)==0) {
827 return p.object();
828 }
829 }
830 foreach(const ParentClassInfo& info, _parentClasses) {
831 PyObject* p = info._parent->findEnumWrapper(name);
832 if (p) return p;
833 }
834 return NULL;
835 }
836
@@ -44,35 +44,38 class PythonQtSlotInfo;
44
44
45 struct PythonQtMemberInfo {
45 struct PythonQtMemberInfo {
46 enum Type {
46 enum Type {
47 Invalid, Slot, EnumValue, Property, NotFound
47 Invalid, Slot, EnumValue, EnumWrapper, Property, NotFound
48 };
48 };
49
49
50 PythonQtMemberInfo():_type(Invalid),_slot(NULL),_enumValue(0) { }
50 PythonQtMemberInfo():_type(Invalid),_slot(NULL),_enumWrapper(NULL),_enumValue(0) { }
51
51
52 PythonQtMemberInfo(PythonQtSlotInfo* info) {
52 PythonQtMemberInfo(PythonQtSlotInfo* info) {
53 _type = Slot;
53 _type = Slot;
54 _slot = info;
54 _slot = info;
55 _enumValue = 0;
55 _enumValue = NULL;
56 }
56 }
57
57
58 PythonQtMemberInfo(unsigned int enumValue) {
58 PythonQtMemberInfo(const PythonQtObjectPtr& enumValue) {
59 _type = EnumValue;
59 _type = EnumValue;
60 _slot = NULL;
60 _slot = NULL;
61 _enumValue = enumValue;
61 _enumValue = enumValue;
62 _enumWrapper = NULL;
62 }
63 }
63
64
64 PythonQtMemberInfo(const QMetaProperty& prop) {
65 PythonQtMemberInfo(const QMetaProperty& prop) {
65 _type = Property;
66 _type = Property;
66 _slot = NULL;
67 _slot = NULL;
67 _enumValue = 0;
68 _enumValue = NULL;
68 _property = prop;
69 _property = prop;
70 _enumWrapper = NULL;
69 }
71 }
70
72
71 Type _type;
73 Type _type;
72
74
73 // TODO: this could be a union...
75 // TODO: this could be a union...
74 PythonQtSlotInfo* _slot;
76 PythonQtSlotInfo* _slot;
75 unsigned int _enumValue;
77 PyObject* _enumWrapper;
78 PythonQtObjectPtr _enumValue;
76 QMetaProperty _property;
79 QMetaProperty _property;
77 };
80 };
78
81
@@ -194,7 +197,11 public:
194 //! returns if the localScope has an enum of that type name or if the enum contains a :: scope, if that class contails the enum
197 //! returns if the localScope has an enum of that type name or if the enum contains a :: scope, if that class contails the enum
195 static bool hasEnum(const QByteArray& name, PythonQtClassInfo* localScope);
198 static bool hasEnum(const QByteArray& name, PythonQtClassInfo* localScope);
196
199
197 private:
200 private:
201 void createEnumWrappers();
202 void createEnumWrappers(const QMetaObject* meta);
203 PyObject* findEnumWrapper(const char* name);
204
198 //! checks if the enum is part of this class (without any leading scope!)
205 //! checks if the enum is part of this class (without any leading scope!)
199 bool hasEnum(const QByteArray& name);
206 bool hasEnum(const QByteArray& name);
200
207
@@ -223,6 +230,8 private:
223 PythonQtSlotInfo* _destructor;
230 PythonQtSlotInfo* _destructor;
224 QList<PythonQtSlotInfo*> _decoratorSlots;
231 QList<PythonQtSlotInfo*> _decoratorSlots;
225
232
233 QList<PythonQtObjectPtr> _enumWrappers;
234
226 const QMetaObject* _meta;
235 const QMetaObject* _meta;
227
236
228 QByteArray _wrappedClassName;
237 QByteArray _wrappedClassName;
@@ -240,6 +249,7 private:
240 int _metaTypeId;
249 int _metaTypeId;
241
250
242 bool _isQObject;
251 bool _isQObject;
252 bool _enumsCreated;
243
253
244 };
254 };
245
255
@@ -183,9 +183,14 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name)
183 if (wrapper->classInfo()) {
183 if (wrapper->classInfo()) {
184 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
184 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
185 if (member._type == PythonQtMemberInfo::EnumValue) {
185 if (member._type == PythonQtMemberInfo::EnumValue) {
186 return PyInt_FromLong(member._enumValue);
186 PyObject* enumValue = member._enumValue;
187 } else
187 Py_INCREF(enumValue);
188 if (member._type == PythonQtMemberInfo::Slot) {
188 return enumValue;
189 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
190 PyObject* enumWrapper = member._enumWrapper;
191 Py_INCREF(enumWrapper);
192 return enumWrapper;
193 } else if (member._type == PythonQtMemberInfo::Slot) {
189 // we return all slots, even the instance slots, since they are callable as unbound slots with self argument
194 // we return all slots, even the instance slots, since they are callable as unbound slots with self argument
190 return PythonQtSlotFunction_New(member._slot, obj, NULL);
195 return PythonQtSlotFunction_New(member._slot, obj, NULL);
191 }
196 }
@@ -611,7 +611,10 int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) {
611 if (val->ob_type == &PyInt_Type) {
611 if (val->ob_type == &PyInt_Type) {
612 d = PyInt_AS_LONG(val);
612 d = PyInt_AS_LONG(val);
613 } else if (!strict) {
613 } else if (!strict) {
614 if (val->ob_type == &PyFloat_Type) {
614 if (PyObject_TypeCheck(val, &PyInt_Type)) {
615 // support for derived int classes, e.g. for our enums
616 d = PyInt_AS_LONG(val);
617 } else if (val->ob_type == &PyFloat_Type) {
615 d = floor(PyFloat_AS_DOUBLE(val));
618 d = floor(PyFloat_AS_DOUBLE(val));
616 } else if (val->ob_type == &PyLong_Type) {
619 } else if (val->ob_type == &PyLong_Type) {
617 // handle error on overflow!
620 // handle error on overflow!
@@ -632,7 +635,7 int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) {
632 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
635 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
633 qint64 d = 0;
636 qint64 d = 0;
634 ok = true;
637 ok = true;
635 if (val->ob_type == &PyInt_Type) {
638 if (PyObject_TypeCheck(val, &PyInt_Type)) {
636 d = PyInt_AS_LONG(val);
639 d = PyInt_AS_LONG(val);
637 } else if (val->ob_type == &PyLong_Type) {
640 } else if (val->ob_type == &PyLong_Type) {
638 d = PyLong_AsLongLong(val);
641 d = PyLong_AsLongLong(val);
@@ -655,7 +658,7 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
655 quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) {
658 quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) {
656 quint64 d = 0;
659 quint64 d = 0;
657 ok = true;
660 ok = true;
658 if (val->ob_type == &PyInt_Type) {
661 if (PyObject_TypeCheck(val, &PyInt_Type)) {
659 d = PyInt_AS_LONG(val);
662 d = PyInt_AS_LONG(val);
660 } else if (val->ob_type == &PyLong_Type) {
663 } else if (val->ob_type == &PyLong_Type) {
661 d = PyLong_AsLongLong(val);
664 d = PyLong_AsLongLong(val);
@@ -681,7 +684,7 double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) {
681 if (val->ob_type == &PyFloat_Type) {
684 if (val->ob_type == &PyFloat_Type) {
682 d = PyFloat_AS_DOUBLE(val);
685 d = PyFloat_AS_DOUBLE(val);
683 } else if (!strict) {
686 } else if (!strict) {
684 if (val->ob_type == &PyInt_Type) {
687 if (PyObject_TypeCheck(val, &PyInt_Type)) {
685 d = PyInt_AS_LONG(val);
688 d = PyInt_AS_LONG(val);
686 } else if (val->ob_type == &PyLong_Type) {
689 } else if (val->ob_type == &PyLong_Type) {
687 d = PyLong_AsLong(val);
690 d = PyLong_AsLong(val);
@@ -707,7 +710,7 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
707 // no special type requested
710 // no special type requested
708 if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) {
711 if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) {
709 type = QVariant::String;
712 type = QVariant::String;
710 } else if (val->ob_type==&PyInt_Type) {
713 } else if (PyObject_TypeCheck(val, &PyInt_Type)) {
711 type = QVariant::Int;
714 type = QVariant::Int;
712 } else if (val->ob_type==&PyLong_Type) {
715 } else if (val->ob_type==&PyLong_Type) {
713 type = QVariant::LongLong;
716 type = QVariant::LongLong;
@@ -277,7 +277,14 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
277 return PythonQtSlotFunction_New(member._slot, obj, NULL);
277 return PythonQtSlotFunction_New(member._slot, obj, NULL);
278 break;
278 break;
279 case PythonQtMemberInfo::EnumValue:
279 case PythonQtMemberInfo::EnumValue:
280 return PyInt_FromLong(member._enumValue);
280 PyObject* enumValue = member._enumValue;
281 Py_INCREF(enumValue);
282 return enumValue;
283 break;
284 case PythonQtMemberInfo::EnumWrapper:
285 PyObject* enumWrapper = member._enumWrapper;
286 Py_INCREF(enumWrapper);
287 return enumWrapper;
281 break;
288 break;
282 default:
289 default:
283 // is an invalid type, go on
290 // is an invalid type, go on
@@ -353,6 +360,8 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObjec
353 error = QString("Slot '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
360 error = QString("Slot '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
354 } else if (member._type == PythonQtMemberInfo::EnumValue) {
361 } else if (member._type == PythonQtMemberInfo::EnumValue) {
355 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
362 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
363 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
364 error = QString("Enum '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
356 } else if (member._type == PythonQtMemberInfo::NotFound) {
365 } else if (member._type == PythonQtMemberInfo::NotFound) {
357 // if we are a derived python class, we allow setting attributes.
366 // if we are a derived python class, we allow setting attributes.
358 // if we are a direct CPP wrapper, we do NOT allow it, since
367 // if we are a direct CPP wrapper, we do NOT allow it, since
General Comments 0
You need to be logged in to leave comments. Login now