diff --git a/generator/abstractmetabuilder.cpp b/generator/abstractmetabuilder.cpp index 162f4a4..847e5ec 100644 --- a/generator/abstractmetabuilder.cpp +++ b/generator/abstractmetabuilder.cpp @@ -79,7 +79,7 @@ QString rename_operator(const QString &oper) operator_names->insert("&", "__and__"); operator_names->insert("|", "__or__"); operator_names->insert("^", "__xor__"); - operator_names->insert("~", "__negate__"); + operator_names->insert("~", "__invert__"); operator_names->insert("<<", "__lshift__"); operator_names->insert(">>", "__rshift__"); @@ -106,12 +106,12 @@ QString rename_operator(const QString &oper) operator_names->insert("--", "decrement"); // compare - operator_names->insert("<", "less"); - operator_names->insert(">", "greater"); - operator_names->insert("<=", "less_or_equal"); - operator_names->insert(">=", "greater_or_equal"); - operator_names->insert("!=", "not_equal"); - operator_names->insert("==", "equal"); + operator_names->insert("<", "__lt__"); + operator_names->insert(">", "__gt__"); + operator_names->insert("<=", "__le__"); + operator_names->insert(">=", "__ge__"); + operator_names->insert("!=", "__ne__"); + operator_names->insert("==", "__eq__"); // other operator_names->insert("[]", "subscript"); diff --git a/generator/abstractmetalang.cpp b/generator/abstractmetalang.cpp index 0801ac4..f7487d3 100644 --- a/generator/abstractmetalang.cpp +++ b/generator/abstractmetalang.cpp @@ -849,6 +849,16 @@ AbstractMetaFunctionList AbstractMetaClass::queryFunctionsByName(const QString & return returned; } +bool AbstractMetaClass::hasDefaultIsNull() const +{ + foreach(const AbstractMetaFunction* fun, queryFunctionsByName("isNull")) { + if (fun->actualMinimumArgumentCount()==0) { + return true; + } + } + return false; +} + /******************************************************************************* * Returns all reference count modifications for any function in the class */ diff --git a/generator/abstractmetalang.h b/generator/abstractmetalang.h index 820540c..c35ac4b 100644 --- a/generator/abstractmetalang.h +++ b/generator/abstractmetalang.h @@ -796,6 +796,8 @@ public: void setHasCloneOperator(bool on) { m_has_clone_operator = on; } bool hasCloneOperator() const { return m_has_clone_operator; } + bool hasDefaultIsNull() const; + void addPropertySpec(QPropertySpec *spec) { m_property_specs << spec; } QList propertySpecs() const { return m_property_specs; } diff --git a/generator/setupgenerator.cpp b/generator/setupgenerator.cpp index e021dc4..f9fa48d 100644 --- a/generator/setupgenerator.cpp +++ b/generator/setupgenerator.cpp @@ -55,6 +55,64 @@ void maybeDeclareMetaType(QTextStream &stream, const QString &typeName, QSet ®isteredTypeNames); bool hasDefaultConstructor(const AbstractMetaClass *meta_class); +static QStringList getOperatorCodes(const AbstractMetaClass* cls) { + QSet operatorCodes; + AbstractMetaFunctionList returned; + AbstractMetaFunctionList functions = cls->functions(); + foreach (AbstractMetaFunction *function, functions) { + if (function->originalName().startsWith("operator")) { + QString op = function->originalName().mid(8); + operatorCodes.insert(op); + } + } + QSet r; + foreach(QString op, operatorCodes.toList()) { + if (op == ">" || op == "<" || op == ">=" || op == "<=" || op == "==" || op == "!=") { + r.insert("PythonQt::Type_RichCompare"); + } else if (op == "+") { + r.insert("PythonQt::Type_Add"); + } else if (op == "-") { + r.insert("PythonQt::Type_Subtract"); + } else if (op == "/") { + r.insert("PythonQt::Type_Divide"); + } else if (op == "*") { + r.insert("PythonQt::Type_Multiply"); + } else if (op == "%") { + r.insert("PythonQt::Type_Mod"); + } else if (op == "&") { + r.insert("PythonQt::Type_And"); + } else if (op == "|") { + r.insert("PythonQt::Type_Or"); + } else if (op == "^") { + r.insert("PythonQt::Type_Xor"); + } else if (op == "~") { + r.insert("PythonQt::Type_Invert"); + + } else if (op == "+=") { + r.insert("PythonQt::Type_InplaceAdd"); + } else if (op == "-=") { + r.insert("PythonQt::Type_InplaceSubtract"); + } else if (op == "/=") { + r.insert("PythonQt::Type_InplaceDivide"); + } else if (op == "*=") { + r.insert("PythonQt::Type_InplaceMultiply"); + } else if (op == "%=") { + r.insert("PythonQt::Type_InplaceMod"); + } else if (op == "&=") { + r.insert("PythonQt::Type_InplaceAnd"); + } else if (op == "|=") { + r.insert("PythonQt::Type_InplaceOr"); + } else if (op == "^=") { + r.insert("PythonQt::Type_InplaceXor"); + } + } + if (cls->hasDefaultIsNull()) { + r.insert("PythonQt::Type_NonZero"); + } + QStringList result = r.toList(); + return result; +} + void SetupGenerator::generate() { AbstractMetaClassList classes_with_polymorphic_id; @@ -138,11 +196,15 @@ void SetupGenerator::generate() } else { shellCreator = ", NULL"; } + QString operatorCodes = getOperatorCodes(cls).join("|"); + if (operatorCodes.isEmpty()) { + operatorCodes = "0"; + } if (cls->isQObject()) { - s << "PythonQt::priv()->registerClass(&" << cls->qualifiedCppName() << "::staticMetaObject, \"" << shortPackName <<"\", PythonQtCreateObjectname() << ">" << shellCreator << ", module);" << endl; + s << "PythonQt::priv()->registerClass(&" << cls->qualifiedCppName() << "::staticMetaObject, \"" << shortPackName <<"\", PythonQtCreateObjectname() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl; } else { QString baseName = cls->baseClass()?cls->baseClass()->qualifiedCppName():""; - s << "PythonQt::priv()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << shortPackName <<"\", PythonQtCreateObjectname() << ">" << shellCreator << ", module);" << endl; + s << "PythonQt::priv()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << shortPackName <<"\", PythonQtCreateObjectname() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl; } foreach(AbstractMetaClass* interface, cls->interfaces()) { // the interface might be our own class... (e.g. QPaintDevice) diff --git a/generator/shellheadergenerator.cpp b/generator/shellheadergenerator.cpp index 7df2b28..5305816 100644 --- a/generator/shellheadergenerator.cpp +++ b/generator/shellheadergenerator.cpp @@ -282,6 +282,9 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c if (meta_class->hasDefaultToStringFunction() || meta_class->hasToStringCapability()) { s << " QString py_toString(" << meta_class->qualifiedCppName() << "*);" << endl; } + if (meta_class->hasDefaultIsNull()) { + s << " bool __nonzero__(" << meta_class->qualifiedCppName() << "* obj) { return !obj->isNull(); }" << endl; + } // Field accessors foreach (const AbstractMetaField *field, meta_class->fields()) { diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index eeecd4a..95d34cc 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -227,7 +227,7 @@ void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, _p->registerClass(metaobject, package, wrapperCreator, shell); } -void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module) +void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots) { // we register all classes in the hierarchy const QMetaObject* m = metaobject; @@ -235,6 +235,7 @@ void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* p while (m) { PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className()); if (!info->pythonQtClassWrapper()) { + info->setTypeSlots(typeSlots); info->setupQObject(m); createPythonQtClassWrapper(info, package, module); if (m->superClass()) { @@ -1130,10 +1131,11 @@ bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTyp } } -void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module) +void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots) { PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName); if (!info->pythonQtClassWrapper()) { + info->setTypeSlots(typeSlots); info->setupCPPObject(typeName); createPythonQtClassWrapper(info, package, module); } diff --git a/src/PythonQt.h b/src/PythonQt.h index 2aa3c0b..bfde1a0 100644 --- a/src/PythonQt.h +++ b/src/PythonQt.h @@ -96,6 +96,42 @@ public: ExternalHelp = 4 //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal }; + //! flags that tell PythonQt which operators to expect on the registered type + enum TypeSlots { + Type_Add = 1, + Type_Subtract = 1 << 1, + Type_Multiply = 1 << 2, + Type_Divide = 1 << 3, + Type_Mod = 1 << 4, + Type_And = 1 << 5, + Type_Or = 1 << 6, + Type_Xor = 1 << 7, + Type_LShift = 1 << 8, + Type_RShift = 1 << 9, + + Type_InplaceAdd = 1 << 10, + Type_InplaceSubtract = 1 << 11, + Type_InplaceMultiply = 1 << 12, + Type_InplaceDivide = 1 << 13, + Type_InplaceMod = 1 << 14, + Type_InplaceAnd = 1 << 15, + Type_InplaceOr = 1 << 16, + Type_InplaceXor = 1 << 17, + Type_InplaceLShift = 1 << 18, + Type_InplaceRShift = 1 << 19, + + // Not yet needed/nicely mappable/generated... + //Type_Positive = 1 << 29, + //Type_Negative = 1 << 29, + //Type_Abs = 1 << 29, + //Type_Hash = 1 << 29, + + Type_Invert = 1 << 29, + Type_RichCompare = 1 << 30, + Type_NonZero = 1 << 31, + + }; + //! initialize the python qt binding (flags are a or combination of InitFlags), if \c pythonQtModuleName is given //! it defines the name of the python module that PythonQt will add, otherwise "PythonQt" is used. //! This can be used to e.g. pass in PySide or PyQt4 to make it more compatible. @@ -432,7 +468,7 @@ public: //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well) /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject, you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */ - void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL); + void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0); //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants //! (ownership of wrapper is passed to PythonQt) @@ -442,7 +478,7 @@ public: All slots that take a pointer to typeName as the first argument will be callable from Python on a variant object that contains such a type. */ - void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL); + void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0); //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes //! and it will register the classes when it first sees a pointer to such a derived class diff --git a/src/PythonQtClassInfo.cpp b/src/PythonQtClassInfo.cpp index 85998df..38e154d 100644 --- a/src/PythonQtClassInfo.cpp +++ b/src/PythonQtClassInfo.cpp @@ -57,6 +57,7 @@ PythonQtClassInfo::PythonQtClassInfo() { _pythonQtClassWrapper = NULL; _shellSetInstanceWrapperCB = NULL; _metaTypeId = -1; + _typeSlots = 0; _isQObject = false; _enumsCreated = false; } diff --git a/src/PythonQtClassInfo.h b/src/PythonQtClassInfo.h index 9bc78ae..5dd1fda 100644 --- a/src/PythonQtClassInfo.h +++ b/src/PythonQtClassInfo.h @@ -104,6 +104,11 @@ public: //! setup as a CPP (non-QObject), taking the classname void setupCPPObject(const QByteArray& classname); + //! set the type capabilities + void setTypeSlots(int typeSlots) { _typeSlots = typeSlots; } + //! get the type capabilities + int typeSlots() const { return _typeSlots; } + //! get the Python method definition for a given slot name (without return type and signature) PythonQtMemberInfo member(const char* member); @@ -244,6 +249,7 @@ private: PythonQtShellSetInstanceWrapperCB* _shellSetInstanceWrapperCB; int _metaTypeId; + int _typeSlots; bool _isQObject; bool _enumsCreated; diff --git a/src/PythonQtClassWrapper.cpp b/src/PythonQtClassWrapper.cpp index 976744f..118ac12 100644 --- a/src/PythonQtClassWrapper.cpp +++ b/src/PythonQtClassWrapper.cpp @@ -48,6 +48,167 @@ #include "PythonQtConversion.h" #include "PythonQtInstanceWrapper.h" +static PyObject* PythonQtInstanceWrapper_invert(PythonQtInstanceWrapper* wrapper) +{ + PyObject* result = NULL; + static QByteArray memberName = "__invert__"; + PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName); + if (opSlot._type == PythonQtMemberInfo::Slot) { + result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr); + } + return result; +} + +static int PythonQtInstanceWrapper_nonzero(PythonQtInstanceWrapper* wrapper) +{ + int result = (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1; + if (result) { + static QByteArray memberName = "__nonzero__"; + PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName); + if (opSlot._type == PythonQtMemberInfo::Slot) { + PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr); + if (resultObj == Py_False) { + result = 0; + } + Py_XDECREF(resultObj); + } + } + return result; +} + + +static PyObject* PythonQtInstanceWrapper_binaryfunc(PythonQtInstanceWrapper* wrapper, PyObject* other, const QByteArray& opName, const QByteArray& fallbackOpName = QByteArray()) +{ + PyObject* result = NULL; + PythonQtMemberInfo opSlot = wrapper->classInfo()->member(opName); + if (opSlot._type == PythonQtMemberInfo::Slot) { + // TODO get rid of tuple + PyObject* args = PyTuple_New(1); + Py_INCREF(other); + PyTuple_SET_ITEM(args, 0, other); + result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr); + Py_DECREF(args); + if (!result && !fallbackOpName.isEmpty()) { + // try fallback if we did not get a result + result = PythonQtInstanceWrapper_binaryfunc(wrapper, other, fallbackOpName); + } + } + return result; +} + +#define BINARY_OP(NAME) \ +static PyObject* PythonQtInstanceWrapper_ ## NAME(PythonQtInstanceWrapper* wrapper, PyObject* other) \ +{ \ + static const QByteArray opName("__" #NAME "__"); \ + return PythonQtInstanceWrapper_binaryfunc(wrapper, other, opName); \ +} + +#define BINARY_OP_INPLACE(NAME) \ + static PyObject* PythonQtInstanceWrapper_i ## NAME(PythonQtInstanceWrapper* wrapper, PyObject* other) \ +{ \ + static const QByteArray opName("__i" #NAME "__"); \ + static const QByteArray fallbackName("__" #NAME "__"); \ + return PythonQtInstanceWrapper_binaryfunc(wrapper, other, opName, fallbackName); \ +} + +BINARY_OP(add) +BINARY_OP(sub) +BINARY_OP(mul) +BINARY_OP(div) +BINARY_OP(and) +BINARY_OP(or) +BINARY_OP(xor) +BINARY_OP(mod) +BINARY_OP(lshift) +BINARY_OP(rshift) + +BINARY_OP_INPLACE(add) +BINARY_OP_INPLACE(sub) +BINARY_OP_INPLACE(mul) +BINARY_OP_INPLACE(div) +BINARY_OP_INPLACE(and) +BINARY_OP_INPLACE(or) +BINARY_OP_INPLACE(xor) +BINARY_OP_INPLACE(mod) +BINARY_OP_INPLACE(lshift) +BINARY_OP_INPLACE(rshift) + +static void initializeSlots(PythonQtClassWrapper* wrap) +{ + int typeSlots = wrap->classInfo()->typeSlots(); + if (typeSlots) { + if (typeSlots & PythonQt::Type_Add) { + wrap->_base.as_number.nb_add = (binaryfunc)PythonQtInstanceWrapper_add; + } + if (typeSlots & PythonQt::Type_Subtract) { + wrap->_base.as_number.nb_subtract = (binaryfunc)PythonQtInstanceWrapper_sub; + } + if (typeSlots & PythonQt::Type_Multiply) { + wrap->_base.as_number.nb_multiply = (binaryfunc)PythonQtInstanceWrapper_mul; + } + if (typeSlots & PythonQt::Type_Divide) { + wrap->_base.as_number.nb_divide = (binaryfunc)PythonQtInstanceWrapper_div; + wrap->_base.as_number.nb_true_divide = (binaryfunc)PythonQtInstanceWrapper_div; + } + if (typeSlots & PythonQt::Type_And) { + wrap->_base.as_number.nb_and = (binaryfunc)PythonQtInstanceWrapper_and; + } + if (typeSlots & PythonQt::Type_Or) { + wrap->_base.as_number.nb_or = (binaryfunc)PythonQtInstanceWrapper_or; + } + if (typeSlots & PythonQt::Type_Xor) { + wrap->_base.as_number.nb_xor = (binaryfunc)PythonQtInstanceWrapper_xor; + } + if (typeSlots & PythonQt::Type_Mod) { + wrap->_base.as_number.nb_remainder = (binaryfunc)PythonQtInstanceWrapper_mod; + } + if (typeSlots & PythonQt::Type_LShift) { + wrap->_base.as_number.nb_lshift = (binaryfunc)PythonQtInstanceWrapper_lshift; + } + if (typeSlots & PythonQt::Type_RShift) { + wrap->_base.as_number.nb_rshift = (binaryfunc)PythonQtInstanceWrapper_rshift; + } + + if (typeSlots & PythonQt::Type_InplaceAdd) { + wrap->_base.as_number.nb_add = (binaryfunc)PythonQtInstanceWrapper_iadd; + } + if (typeSlots & PythonQt::Type_InplaceSubtract) { + wrap->_base.as_number.nb_subtract = (binaryfunc)PythonQtInstanceWrapper_isub; + } + if (typeSlots & PythonQt::Type_InplaceMultiply) { + wrap->_base.as_number.nb_multiply = (binaryfunc)PythonQtInstanceWrapper_imul; + } + if (typeSlots & PythonQt::Type_InplaceDivide) { + wrap->_base.as_number.nb_inplace_divide = (binaryfunc)PythonQtInstanceWrapper_idiv; + wrap->_base.as_number.nb_inplace_true_divide = (binaryfunc)PythonQtInstanceWrapper_idiv; + } + if (typeSlots & PythonQt::Type_InplaceAnd) { + wrap->_base.as_number.nb_inplace_and = (binaryfunc)PythonQtInstanceWrapper_iand; + } + if (typeSlots & PythonQt::Type_InplaceOr) { + wrap->_base.as_number.nb_inplace_or = (binaryfunc)PythonQtInstanceWrapper_ior; + } + if (typeSlots & PythonQt::Type_InplaceXor) { + wrap->_base.as_number.nb_inplace_xor = (binaryfunc)PythonQtInstanceWrapper_ixor; + } + if (typeSlots & PythonQt::Type_InplaceMod) { + wrap->_base.as_number.nb_inplace_remainder = (binaryfunc)PythonQtInstanceWrapper_imod; + } + if (typeSlots & PythonQt::Type_InplaceLShift) { + wrap->_base.as_number.nb_inplace_lshift = (binaryfunc)PythonQtInstanceWrapper_ilshift; + } + if (typeSlots & PythonQt::Type_InplaceRShift) { + wrap->_base.as_number.nb_inplace_rshift = (binaryfunc)PythonQtInstanceWrapper_irshift; + } + if (typeSlots & PythonQt::Type_Invert) { + wrap->_base.as_number.nb_invert = (unaryfunc)PythonQtInstanceWrapper_invert; + } + if (typeSlots & PythonQt::Type_NonZero) { + wrap->_base.as_number.nb_nonzero = (inquiry)PythonQtInstanceWrapper_nonzero; + } + } +} + static PyObject* PythonQtClassWrapper_alloc(PyTypeObject *self, Py_ssize_t nitems) { // call the default type alloc @@ -56,6 +217,7 @@ static PyObject* PythonQtClassWrapper_alloc(PyTypeObject *self, Py_ssize_t nitem // take current class type, if we are called via newPythonQtClassWrapper() PythonQtClassWrapper* wrap = (PythonQtClassWrapper*)obj; wrap->_classInfo = PythonQt::priv()->currentClassInfoForClassWrapperCreation(); + initializeSlots(wrap); return obj; } diff --git a/src/PythonQtInstanceWrapper.cpp b/src/PythonQtInstanceWrapper.cpp index 41b03c3..576f2de 100644 --- a/src/PythonQtInstanceWrapper.cpp +++ b/src/PythonQtInstanceWrapper.cpp @@ -54,11 +54,11 @@ PythonQtClassInfo* PythonQtInstanceWrapperStruct::classInfo() } static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, bool force = false) { - + // is this a C++ wrapper? if (self->_wrappedPtr) { //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1()); - + PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr); // we own our qobject, so we delete it now: delete self->_obj; @@ -183,6 +183,106 @@ int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args return 0; } +static PyObject *PythonQtInstanceWrapper_richcompare(PythonQtInstanceWrapper* wrapper, PyObject* other, int code) +{ + bool validPtrs = false; + bool areSamePtrs = false; + if (PyObject_TypeCheck((PyObject*)wrapper, &PythonQtInstanceWrapper_Type)) { + if (PyObject_TypeCheck(other, &PythonQtInstanceWrapper_Type)) { + validPtrs = true; + PythonQtInstanceWrapper* w1 = wrapper; + PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)other; + // check pointers directly + if (w1->_wrappedPtr != NULL) { + if (w1->_wrappedPtr == w2->_wrappedPtr) { + areSamePtrs = true; + } + } else if (w1->_obj == w2->_obj) { + areSamePtrs = true; + } + } else if (other == Py_None) { + validPtrs = true; + if (wrapper->_obj || wrapper->_wrappedPtr) { + areSamePtrs = false; + } else { + areSamePtrs = true; + } + } + } + + if ((wrapper->classInfo()->typeSlots() & PythonQt::Type_RichCompare) == 0) { + // shortcut if richcompare is not supported: + if (validPtrs && code == Py_EQ) { + return PythonQtConv::GetPyBool(areSamePtrs); + } else if (validPtrs && code == Py_NE) { + return PythonQtConv::GetPyBool(!areSamePtrs); + } + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + QByteArray memberName; + switch (code) { + case Py_LT: + { + static QByteArray name = "__lt__"; + memberName = name; + } + break; + + case Py_LE: + { + static QByteArray name = "__le__"; + memberName = name; + } + break; + + case Py_EQ: + { + static QByteArray name = "__eq__"; + memberName = name; + } + break; + + case Py_NE: + { + static QByteArray name = "__ne__"; + memberName = name; + } + break; + + case Py_GT: + { + static QByteArray name = "__gt__"; + memberName = name; + } + break; + + case Py_GE: + { + static QByteArray name = "__ge__"; + memberName = name; + } + break; + } + + PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName); + if (opSlot._type == PythonQtMemberInfo::Slot) { + // TODO get rid of tuple + PyObject* args = PyTuple_New(1); + Py_INCREF(other); + PyTuple_SET_ITEM(args, 0, other); + PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr); + Py_DECREF(args); + return result; + } else { + // not implemented, let python try something else! + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } +} + + static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* obj) { return PyString_FromString(obj->ob_type->tp_name); @@ -242,7 +342,7 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) } } - QList dynamicProps = wrapper->_obj->dynamicPropertyNames(); + QList dynamicProps = wrapper->_obj->dynamicPropertyNames(); foreach (QByteArray name, dynamicProps) { PyObject* o = PyObject_GetAttrString(obj, name.data()); if (o) { @@ -362,7 +462,7 @@ static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObjec PyErr_SetString(PyExc_AttributeError, error.toLatin1().data()); return -1; } - + QMetaProperty prop = member._property; if (prop.isWritable()) { QVariant v; @@ -395,7 +495,7 @@ static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObjec error = QString("Enum '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object"; } else if (member._type == PythonQtMemberInfo::NotFound) { // check for a setter slot - static const QByteArray setterString("py_set_"); + static const QByteArray setterString("py_set_"); PythonQtMemberInfo setter = wrapper->classInfo()->member(setterString + attributeName); if (setter._type == PythonQtMemberInfo::Slot) { // call the setter and ignore the result value @@ -424,7 +524,7 @@ static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObjec } } } - + // if we are a derived python class, we allow setting attributes. // if we are a direct CPP wrapper, we do NOT allow it, since // it would be confusing to allow it because a wrapper will go away when it is not seen by python anymore @@ -487,7 +587,7 @@ static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj) { PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj; const char* typeName = obj->ob_type->tp_name; - + QObject *qobj = wrapper->_obj; QString str = getStringFromObject(wrapper); if (!str.isEmpty()) { @@ -508,63 +608,7 @@ static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj) } } -static int PythonQtInstanceWrapper_compare(PyObject * obj1, PyObject * obj2) -{ - if (PyObject_TypeCheck(obj1, &PythonQtInstanceWrapper_Type) && - PyObject_TypeCheck(obj2, &PythonQtInstanceWrapper_Type)) { - - PythonQtInstanceWrapper* w1 = (PythonQtInstanceWrapper*)obj1; - PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)obj2; - // check pointers directly first: - if (w1->_wrappedPtr != NULL) { - if (w1->_wrappedPtr == w2->_wrappedPtr) { - return 0; - } - } else if (w1->_obj == w2->_obj) { - return 0; - } - const char* class1 = w1->classInfo()->className(); - const char* class2 = w2->classInfo()->className(); - if (strcmp(class1, class2) == 0) { - // same class names, so we can try the operator_equal - PythonQtMemberInfo info = w1->classInfo()->member("operator_equal"); - if (info._type == PythonQtMemberInfo::Slot) { - bool result = false; - void* obj1 = w1->_wrappedPtr; - if (!obj1) { - obj1 = w1->_obj; - } - if (!obj1) { return -1; } - void* obj2 = w2->_wrappedPtr; - if (!obj2) { - obj2 = w2->_obj; - } - if (!obj2) { return -1; } - if (info._slot->isInstanceDecorator()) { - // call on decorator QObject - void* args[3]; - args[0] = &result; - args[1] = &obj1; // this is a pointer, so it needs a pointer to a pointer - args[2] = obj2; // this is a reference, so it needs the direct pointer - info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args); - return result?0:-1; - } else { - // call directly on QObject - if (w1->_obj && w2->_obj) { - void* args[2]; - args[0] = &result; - args[1] = obj2; // this is a reference, so it needs the direct pointer - w1->_obj->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args); - return result?0:-1; - } - } - } - } - } - return -1; -} - -static int PythonQtInstanceWrapper_nonzero(PyObject *obj) +static int PythonQtInstanceWrapper_builtin_nonzero(PyObject *obj) { PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj; return (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1; @@ -595,7 +639,7 @@ static PyNumberMethods PythonQtInstanceWrapper_as_number = { 0, /* nb_negative */ 0, /* nb_positive */ 0, /* nb_absolute */ - PythonQtInstanceWrapper_nonzero, /* nb_nonzero */ + PythonQtInstanceWrapper_builtin_nonzero, /* nb_nonzero */ 0, /* nb_invert */ 0, /* nb_lshift */ 0, /* nb_rshift */ @@ -635,7 +679,7 @@ PyTypeObject PythonQtInstanceWrapper_Type = { 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ - PythonQtInstanceWrapper_compare, /*tp_compare*/ + 0, /*tp_compare*/ PythonQtInstanceWrapper_repr, /*tp_repr*/ &PythonQtInstanceWrapper_as_number, /*tp_as_number*/ 0, /*tp_as_sequence*/ @@ -646,11 +690,11 @@ PyTypeObject PythonQtInstanceWrapper_Type = { PythonQtInstanceWrapper_getattro, /*tp_getattro*/ PythonQtInstanceWrapper_setattro, /*tp_setattro*/ 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ "PythonQtInstanceWrapper object", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + (richcmpfunc)PythonQtInstanceWrapper_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */