From 15ceed791f8dda4aa1256e67c11f8a748ce4b7b0 Mon Sep 17 00:00:00 2001 From: Hugo Parente Lima Date: Wed, 26 Oct 2011 18:28:51 -0200 Subject: Fix bug 1016 - "Calling of Q_INVOKABLE method returning not QVariant is impossible..." --- libpyside/pysidemetafunction.cpp | 72 +++++++++++++++++++++++------- tests/pysidetest/CMakeLists.txt | 3 ++ tests/pysidetest/bug_1016.py | 12 +++++ tests/pysidetest/hiddenobject.cpp | 38 ++++++++++++++++ tests/pysidetest/hiddenobject.h | 49 ++++++++++++++++++++ tests/pysidetest/pysidetest_global.h | 5 ++- tests/pysidetest/typesystem_pysidetest.xml | 2 + 7 files changed, 163 insertions(+), 18 deletions(-) create mode 100644 tests/pysidetest/bug_1016.py create mode 100644 tests/pysidetest/hiddenobject.cpp create mode 100644 tests/pysidetest/hiddenobject.h diff --git a/libpyside/pysidemetafunction.cpp b/libpyside/pysidemetafunction.cpp index 9338f8eda..de4d3244a 100644 --- a/libpyside/pysidemetafunction.cpp +++ b/libpyside/pysidemetafunction.cpp @@ -97,31 +97,69 @@ void functionFree(void *self) PyObject* functionCall(PyObject* self, PyObject* args, PyObject* kw) { - static Shiboken::TypeResolver* typeResolver = Shiboken::TypeResolver::get("QVariant"); - Q_ASSERT(typeResolver); - - QGenericArgument gArgs[10]; - QVariant vArgs[10]; PySideMetaFunction* function = reinterpret_cast(self); QMetaMethod method = function->d->method; - int argsGiven = method.parameterTypes().size(); + QList argTypes = method.parameterTypes(); + + // args given plus return type + int numArgs = PyTuple_GET_SIZE(args) + 1; + + if (numArgs - 1 != argTypes.count()) { + PyErr_Format(PyExc_TypeError, "%s only accepts %d arguments, %d given!", method.signature(), argTypes.count(), numArgs); + return 0; + } - for (int i = 0; i < argsGiven; ++i) { - Shiboken::AutoDecRef pyArg(PySequence_GetItem(args, i)); - gArgs[i] = Q_ARG(QVariant, vArgs[i]); - void* v[1] = { &vArgs[i] }; - typeResolver->toCpp(pyArg, v); + QVariant* methValues = new QVariant[numArgs]; + void** methArgs = new void*[numArgs]; + + // Prepare room for return type + const char* returnType = method.typeName(); + if (returnType) + argTypes.prepend(returnType); + else + argTypes.prepend(QByteArray()); + + int i; + for (i = 0; i < numArgs; ++i) { + const QByteArray& typeName = argTypes[i]; + // This must happen only when the method hasn't return type. + if (typeName.isEmpty()) { + methArgs[i] = 0; + continue; + } + + Shiboken::TypeResolver* typeResolver = Shiboken::TypeResolver::get(typeName); + if (typeResolver) { + if (Shiboken::TypeResolver::getType(typeName) == Shiboken::TypeResolver::ValueType) { + int typeId = QMetaType::type(typeName); + if (!typeId) { + PyErr_Format(PyExc_TypeError, "Value type used on signal needs to be registered on meta type: %s", typeName.data()); + break; + } + methValues[i] = QVariant(typeId, (void*) 0); + } + methArgs[i] = methValues[i].data(); + if (i != 0) // Don't do this for return type + typeResolver->toCpp(PyTuple_GET_ITEM(args, i - 1), &methArgs[i]); + } else { + PyErr_Format(PyExc_TypeError, "Unknown type used to emit a signal: %s", argTypes[i].constData()); + break; + } } - QVariant retVariant; - QGenericReturnArgument returnValue = Q_RETURN_ARG(QVariant, retVariant); - method.invoke(function->d->qobject, returnValue, gArgs[0], gArgs[1], gArgs[2], gArgs[3], gArgs[4], gArgs[5], gArgs[6], gArgs[7], gArgs[8], gArgs[9]); + bool ok = i == numArgs; + if (ok) + QMetaObject::metacall(function->d->qobject, QMetaObject::InvokeMetaMethod, method.methodIndex(), methArgs); + + static Shiboken::TypeResolver* qVariantTypeResolver = Shiboken::TypeResolver::get("QVariant"); + Q_ASSERT(qVariantTypeResolver); + PyObject* retVal = qVariantTypeResolver->toPython(&methValues[0]); - if (retVariant.isValid()) - return typeResolver->toPython(&retVariant); + delete[] methArgs; + delete[] methValues; - Py_RETURN_NONE; + return retVal; } } // extern "C" diff --git a/tests/pysidetest/CMakeLists.txt b/tests/pysidetest/CMakeLists.txt index 807463dc9..7661da875 100644 --- a/tests/pysidetest/CMakeLists.txt +++ b/tests/pysidetest/CMakeLists.txt @@ -12,11 +12,13 @@ add_definitions(-DRXX_ALLOCATOR_INIT_0) set(pysidetest_SRC testobject.cpp testview.cpp +hiddenobject.cpp ) set(pysidetest_MOC_HEADERS testobject.h testview.h +hiddenobject.h ) qt4_wrap_cpp(pysidetest_MOC_SRC ${pysidetest_MOC_HEADERS}) @@ -86,3 +88,4 @@ PYSIDE_TEST(signalwithdefaultvalue_test.py) PYSIDE_TEST(signalemissionfrompython_test.py) PYSIDE_TEST(version_test.py) PYSIDE_TEST(typedef_signal_test.py) +PYSIDE_TEST(bug_1016.py) diff --git a/tests/pysidetest/bug_1016.py b/tests/pysidetest/bug_1016.py new file mode 100644 index 000000000..38432c62f --- /dev/null +++ b/tests/pysidetest/bug_1016.py @@ -0,0 +1,12 @@ +from testbinding import * +import unittest + +class TestBug1016 (unittest.TestCase): + + def testIt(self): + obj = getHiddenObject() + self.assertEqual(obj.callMe(), None) + self.assertTrue(obj.wasCalled()) + +if __name__ == "__main__": + unittest.main() diff --git a/tests/pysidetest/hiddenobject.cpp b/tests/pysidetest/hiddenobject.cpp new file mode 100644 index 000000000..00c7bed6e --- /dev/null +++ b/tests/pysidetest/hiddenobject.cpp @@ -0,0 +1,38 @@ +/* + * This file is part of the PySide project. + * + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "hiddenobject.h" + +void HiddenObject::callMe() +{ + m_called = true; +} + +bool HiddenObject::wasCalled() +{ + return m_called; +} + +QObject* getHiddenObject() +{ + return new HiddenObject(); +} diff --git a/tests/pysidetest/hiddenobject.h b/tests/pysidetest/hiddenobject.h new file mode 100644 index 000000000..eb02d142d --- /dev/null +++ b/tests/pysidetest/hiddenobject.h @@ -0,0 +1,49 @@ +/* + * This file is part of the PySide project. + * + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef HIDDENOBJECT_H +#define HIDDENOBJECT_H + +#ifdef pysidetest_EXPORTS +#define PYSIDE_EXPORTS 1 +#endif +#include "pysidemacros.h" +#include + +// This class shouldn't be exported! +class HiddenObject : public QObject +{ + Q_OBJECT +public: + HiddenObject() : m_called(false) {} + Q_INVOKABLE void callMe(); +public slots: + bool wasCalled(); +private: + bool m_called; +}; + +// Return a instance of HiddenObject +PYSIDE_API QObject* getHiddenObject(); + + +#endif diff --git a/tests/pysidetest/pysidetest_global.h b/tests/pysidetest/pysidetest_global.h index a7efcf91c..bad6e8e2a 100644 --- a/tests/pysidetest/pysidetest_global.h +++ b/tests/pysidetest/pysidetest_global.h @@ -1,3 +1,6 @@ -#include +// PySide global.h file +#include "pyside_global.h" #include "testobject.h" #include "testview.h" +#define PYSIDE_API +#include "hiddenobject.h" diff --git a/tests/pysidetest/typesystem_pysidetest.xml b/tests/pysidetest/typesystem_pysidetest.xml index 5077f6b26..fb9b82b6f 100644 --- a/tests/pysidetest/typesystem_pysidetest.xml +++ b/tests/pysidetest/typesystem_pysidetest.xml @@ -6,6 +6,8 @@ + + Shiboken::TypeResolver::createObjectTypeResolver< ::PySideCPP2::TestObjectWithoutNamespace>("TestObjectWithoutNamespace*"); Shiboken::TypeResolver::createValueTypeResolver< ::PySideCPP2::PySideLong>("PySideLong"); -- cgit v1.2.3