aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRenato Filho <renato.filho@openbossa.org>2010-05-13 15:50:42 -0300
committerRenato Filho <renato.filho@openbossa.org>2010-05-17 19:53:54 -0300
commitc5fd4d4830cb49c9f8087d7e54335f4c248f76bf (patch)
tree6a4fd6a9e30f1d5a1b3ead182d768d2f4fc38a79
parentd2a6f35ef914b000ddd7685925075985c76817ac (diff)
Implemented support to modify slot return type.
Included method type in DynamicQMetaObject metadata. Moved Signal/Slot objet to libpyside. Create unittest to signal class. Implemented disconnection function. Fixed emit method on signal object
-rw-r--r--PySide/QtCore/typesystem_core.xml6
-rw-r--r--libpyside/CMakeLists.txt4
-rw-r--r--libpyside/dynamicqmetaobject.cpp108
-rw-r--r--libpyside/dynamicqmetaobject.h25
-rw-r--r--libpyside/pyside.cpp51
-rw-r--r--libpyside/pyside.h50
-rw-r--r--libpyside/qsignal.cpp413
-rw-r--r--libpyside/qsignal.h29
-rw-r--r--libpyside/qslot.cpp (renamed from PySide/QtCore/glue/qslot.cpp)16
-rw-r--r--tests/signals/decorators_test.py17
-rw-r--r--tests/signals/signal_object_test.py39
11 files changed, 710 insertions, 48 deletions
diff --git a/PySide/QtCore/typesystem_core.xml b/PySide/QtCore/typesystem_core.xml
index 1033f4763..887f001b6 100644
--- a/PySide/QtCore/typesystem_core.xml
+++ b/PySide/QtCore/typesystem_core.xml
@@ -718,9 +718,11 @@
<enum-type name="QMetaMethod::MethodType"/>
<!--signal/slot-->
- <inject-code class="native" position="beginning" file="glue/qslot.cpp" />
<inject-code class="target" position="end">
- init_slot(module);
+ PySide::init(module);
+ </inject-code>
+ <inject-code class="native" position="beginning">
+ #include &lt;pyside.h&gt;
</inject-code>
<object-type name="QAbstractTableModel">
diff --git a/libpyside/CMakeLists.txt b/libpyside/CMakeLists.txt
index 23345efbf..0597f1608 100644
--- a/libpyside/CMakeLists.txt
+++ b/libpyside/CMakeLists.txt
@@ -4,6 +4,9 @@ set(libpyside_SRC
dynamicqmetaobject.cpp
signalmanager.cpp
globalreceiver.cpp
+qsignal.cpp
+qslot.cpp
+pyside.cpp
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}
@@ -31,6 +34,7 @@ set(libpyside_HEADERS
pysideconversions.h
pysidemacros.h
signalmanager.h
+ pyside.h
)
# create pkg-config file
diff --git a/libpyside/dynamicqmetaobject.cpp b/libpyside/dynamicqmetaobject.cpp
index a2e6bef0f..5cf1b9dbe 100644
--- a/libpyside/dynamicqmetaobject.cpp
+++ b/libpyside/dynamicqmetaobject.cpp
@@ -35,12 +35,15 @@
#include "dynamicqmetaobject.h"
#include <QByteArray>
#include <QString>
+#include <QStringList>
#include <QList>
#include <QObject>
#include <cstring>
#include <QDebug>
#include <QMetaMethod>
+#include "qsignal.h"
+
#define MAX_SIGNALS_COUNT 50
using namespace PySide;
@@ -58,11 +61,32 @@ static int registerString(const QByteArray& s, QList<QByteArray>* strings)
return idx;
}
-static void clearItem(QLinkedList<QByteArray> &l, const QByteArray &value)
+MethodData::MethodData(const char *signature, const char *type)
+ : m_signature(signature), m_type(type)
+{
+}
+
+void MethodData::clear()
+{
+ m_signature.clear();
+ m_type.clear();
+}
+
+bool MethodData::operator==(const MethodData &other) const
+{
+ return m_signature == other.signature();
+}
+
+QByteArray MethodData::signature() const
+{
+ return m_signature;
+}
+
+QByteArray MethodData::type() const
{
- QLinkedList<QByteArray>::iterator i = qFind(l.begin(), l.end(), value);
- if (i != l.end())
- *i = QByteArray();
+ if (m_type == "void")
+ return QByteArray("");
+ return m_type;
}
DynamicQMetaObject::DynamicQMetaObject(const char *className, const QMetaObject* metaObject)
@@ -81,13 +105,13 @@ DynamicQMetaObject::~DynamicQMetaObject()
delete[] d.data;
}
-void DynamicQMetaObject::addSignal(const char* signal)
+void DynamicQMetaObject::addSignal(const char *signal, const char *type)
{
//search for a empty space
- QByteArray blank;
- QLinkedList<QByteArray>::iterator i = qFind(m_signals.begin(), m_signals.end(), blank);
+ MethodData blank;
+ QLinkedList<MethodData>::iterator i = qFind(m_signals.begin(), m_signals.end(), blank);
if (i != m_signals.end()) {
- *i = QByteArray(signal);
+ *i = MethodData(signal, type);
updateMetaObject();
return;
}
@@ -97,19 +121,19 @@ void DynamicQMetaObject::addSignal(const char* signal)
return;
}
- m_signals << QByteArray(signal);
+ m_signals << MethodData(signal, type);
updateMetaObject();
}
-void DynamicQMetaObject::addSlot(const char* slot)
+void DynamicQMetaObject::addSlot(const char *slot, const char *type)
{
//search for a empty space
- QByteArray blank;
- QLinkedList<QByteArray>::iterator i = qFind(m_slots.begin(), m_slots.end(), blank);
+ MethodData blank;
+ QLinkedList<MethodData>::iterator i = qFind(m_slots.begin(), m_slots.end(), blank);
if (i != m_slots.end()) {
- *i = QByteArray(slot);
+ *i = MethodData(slot, type);
} else {
- m_slots << QByteArray(slot);
+ m_slots << MethodData(slot, type);
}
updateMetaObject();
}
@@ -117,13 +141,16 @@ void DynamicQMetaObject::addSlot(const char* slot)
void DynamicQMetaObject::removeSlot(uint index)
{
QMetaMethod m = method(index);
- if (m_slots.contains(m.signature())) {
- clearItem(m_slots, m.signature());
- updateMetaObject();
+ foreach(MethodData md, m_slots) {
+ if (md.signature() == m.signature()) {
+ md.clear();
+ updateMetaObject();
+ break;
+ }
}
}
-DynamicQMetaObject* DynamicQMetaObject::createBasedOn(PyTypeObject *type, const QMetaObject *base)
+DynamicQMetaObject* DynamicQMetaObject::createBasedOn(PyObject *pyObj, PyTypeObject *type, const QMetaObject *base)
{
PyObject *key, *value;
Py_ssize_t pos = 0;
@@ -133,14 +160,30 @@ DynamicQMetaObject* DynamicQMetaObject::createBasedOn(PyTypeObject *type, const
DynamicQMetaObject *mo = new PySide::DynamicQMetaObject(className.toAscii(), base);
while (PyDict_Next(type->tp_dict, &pos, &key, &value)) {
+
+ //Register signals
+ if (value->ob_type == &PySideSignal_Type) {
+ SignalData *data = reinterpret_cast<SignalData*>(value);
+
+ for(int i=0, i_max=data->signatures_size; i < i_max; i++) {
+ mo->addSignal(data->signatures[i]);
+ printf("QObject with signal:[%s][%s]\n",
+ PyString_AS_STRING(PyObject_Str(key)), data->signatures[i]);
+ }
+ }
+
if (!PyFunction_Check(value))
continue;
+ //Register Slots
if (PyObject_HasAttrString(value, PYSIDE_SLOT_LIST_ATTR)) {
PyObject *signature_list = PyObject_GetAttrString(value, PYSIDE_SLOT_LIST_ATTR);
for(Py_ssize_t i=0, i_max=PyList_Size(signature_list); i < i_max; i++) {
PyObject *signature = PyList_GET_ITEM(signature_list, i);
- mo->addSlot(PyString_AsString(signature));
+ QString sig(PyString_AsString(signature));
+ //slot the slot type and signature
+ QStringList slotInfo = sig.split(" ", QString::SkipEmptyParts);
+ mo->addSlot(slotInfo[1].toAscii(), slotInfo[0].toAscii());
}
}
}
@@ -151,9 +194,12 @@ void DynamicQMetaObject::removeSignal(uint index)
{
//Current Qt implementation does not support runtime remove signal
QMetaMethod m = method(index);
- if (m_signals.contains(m.signature())) {
- clearItem(m_signals, m.signature());
- updateMetaObject();
+ foreach(MethodData md, m_signals) {
+ if (md.signature() == m.signature()) {
+ md.clear();
+ updateMetaObject();
+ break;
+ }
}
}
@@ -198,26 +244,28 @@ void DynamicQMetaObject::updateMetaObject()
int index = HEADER_LENGHT;
//write signals
- QLinkedList<QByteArray>::iterator iSignal = m_signals.begin();
+ QLinkedList<MethodData>::iterator iSignal = m_signals.begin();
for(int i=0; i < MAX_SIGNALS_COUNT; i++) {
+ QByteArray sigType;
if (iSignal != m_signals.end()) {
- data[index++] = registerString(*iSignal, &strings); // func name
+ data[index++] = registerString((*iSignal).signature(), &strings); // func name
+ sigType = (*iSignal).type();
iSignal++;
} else {
data[index++] = NULL_INDEX; // func name
}
data[index++] = NULL_INDEX; // arguments
- data[index++] = NULL_INDEX; // normalized type
+ data[index++] = (sigType.size() > 0 ? registerString(sigType, &strings) : NULL_INDEX); // normalized type
data[index++] = NULL_INDEX; // tags
data[index++] = AccessPublic | MethodSignal; // flags
}
//write slots
- foreach(QByteArray slot, m_slots) {
- data[index++] = registerString(slot, &strings); // func name
+ foreach(MethodData slot, m_slots) {
+ data[index++] = registerString(slot.signature(), &strings); // func name
data[index++] = NULL_INDEX; // arguments
- data[index++] = NULL_INDEX; // normalized type
+ data[index++] = (slot.type().size() > 0 ? registerString(slot.type(), &strings) : NULL_INDEX); // normalized type
data[index++] = NULL_INDEX; // tags
data[index++] = AccessPublic | MethodSlot; // flags
}
@@ -225,8 +273,8 @@ void DynamicQMetaObject::updateMetaObject()
// create the m_metadata string
QByteArray str;
- foreach(QByteArray signature, strings) {
- str.append(signature);
+ foreach(QByteArray field, strings) {
+ str.append(field);
str.append(char(0));
}
diff --git a/libpyside/dynamicqmetaobject.h b/libpyside/dynamicqmetaobject.h
index 9336b63ac..bec8dd3df 100644
--- a/libpyside/dynamicqmetaobject.h
+++ b/libpyside/dynamicqmetaobject.h
@@ -48,24 +48,39 @@ class QObject;
namespace PySide
{
+class MethodData
+{
+ public:
+ MethodData(){}
+ MethodData(const char *signature, const char *type);
+ void clear();
+ QByteArray signature() const;
+ QByteArray type() const;
+ bool operator==(const MethodData &other) const;
+
+ private:
+ QByteArray m_signature;
+ QByteArray m_type;
+};
+
class PYSIDE_API DynamicQMetaObject : public QMetaObject
{
public:
DynamicQMetaObject(const char* className, const QMetaObject* metaObject);
~DynamicQMetaObject();
- void addSignal(const char* signal);
- void addSlot(const char* slot);
+ void addSignal(const char* signal, const char* type=0);
+ void addSlot(const char* slot, const char* type=0);
void removeSignal(uint idex);
void removeSlot(uint index);
//Retrieve Python metadata to create QMetaObject (class name, signals, slot)
- static DynamicQMetaObject *createBasedOn(PyTypeObject *obj, const QMetaObject* base);
+ static DynamicQMetaObject *createBasedOn(PyObject *obj, PyTypeObject *type, const QMetaObject* base);
private:
- QLinkedList<QByteArray> m_signals;
- QLinkedList<QByteArray> m_slots;
+ QLinkedList<MethodData> m_signals;
+ QLinkedList<MethodData> m_slots;
QByteArray m_className;
void updateMetaObject();
diff --git a/libpyside/pyside.cpp b/libpyside/pyside.cpp
new file mode 100644
index 000000000..02eea7867
--- /dev/null
+++ b/libpyside/pyside.cpp
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation. Please
+ * review the following information to ensure the GNU Lesser General
+ * Public License version 2.1 requirements will be met:
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * As a special exception to the GNU Lesser General Public License
+ * version 2.1, the object code form of a "work that uses the Library"
+ * may incorporate material from a header file that is part of the
+ * Library. You may distribute such object code under terms of your
+ * choice, provided that the incorporated material (i) does not exceed
+ * more than 5% of the total size of the Library; and (ii) is limited to
+ * numerical parameters, data structure layouts, accessors, macros,
+ * inline functions and templates.
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+
+#include "pyside.h"
+
+extern "C" PyAPI_FUNC(void) init_signal(PyObject* module);
+extern "C" PyAPI_FUNC(void) init_slot(PyObject* module);
+
+namespace PySide
+{
+
+void init(PyObject *module)
+{
+ init_signal(module);
+ init_slot(module);
+}
+
+} //namespace PySide
+
diff --git a/libpyside/pyside.h b/libpyside/pyside.h
new file mode 100644
index 000000000..aaeeb43d2
--- /dev/null
+++ b/libpyside/pyside.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation. Please
+ * review the following information to ensure the GNU Lesser General
+ * Public License version 2.1 requirements will be met:
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * As a special exception to the GNU Lesser General Public License
+ * version 2.1, the object code form of a "work that uses the Library"
+ * may incorporate material from a header file that is part of the
+ * Library. You may distribute such object code under terms of your
+ * choice, provided that the incorporated material (i) does not exceed
+ * more than 5% of the total size of the Library; and (ii) is limited to
+ * numerical parameters, data structure layouts, accessors, macros,
+ * inline functions and templates.
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef PYSIDE_H
+#define PYSIDE_H
+
+#include <Python.h>
+#include <pysidemacros.h>
+
+namespace PySide
+{
+
+PYSIDE_API void init(PyObject *module);
+
+} //namespace PySide
+
+
+#endif // PYSIDE_H
+
diff --git a/libpyside/qsignal.cpp b/libpyside/qsignal.cpp
new file mode 100644
index 000000000..8fe79ee1e
--- /dev/null
+++ b/libpyside/qsignal.cpp
@@ -0,0 +1,413 @@
+#define protected public
+
+#include <shiboken.h>
+#include <Python.h>
+#include <QDebug>
+
+#include "qsignal.h"
+#include "signalmanager.h"
+
+#define SIGNAL_CLASS_NAME "Signal"
+
+namespace PySide
+{
+
+extern "C"
+{
+
+static int qsignal_init(PyObject*, PyObject*, PyObject*);
+static void qsignal_free(void*);
+static void qsignal_instance_free(void*);
+
+//methods
+static PyObject* qsignal_instance_connect(PyObject *self, PyObject *args, PyObject *kw);
+static PyObject* qsignal_instance_disconnect(PyObject *self, PyObject *args);
+static PyObject* qsignal_instance_emit(PyObject *self, PyObject *args);
+
+//aux
+static char* qsignal_build_signature(const char *name, const char *signature);
+static const char* qsignal_get_type_name(PyObject *type);
+static void qsignal_append_signature(SignalData *self, PyObject *args);
+static void qsignal_instance_initialize(PyObject *instance, SignalData *data, PyObject *source);
+
+PyTypeObject PySideSignal_Type = {
+ PyObject_HEAD_INIT(0)
+ 0, /*ob_size*/
+ SIGNAL_CLASS_NAME, /*tp_name*/
+ sizeof(SignalData), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ SIGNAL_CLASS_NAME, /*tp_doc */
+ 0, /*tp_traverse */
+ 0, /*tp_clear */
+ 0, /*tp_richcompare */
+ 0, /*tp_weaklistoffset */
+ 0, /*tp_iter */
+ 0, /*tp_iternext */
+ 0, /*tp_methods */
+ 0, /*tp_members */
+ 0, /*tp_getset */
+ 0, /*tp_base */
+ 0, /*tp_dict */
+ 0, /*tp_descr_get */
+ 0, /*tp_descr_set */
+ 0, /*tp_dictoffset */
+ (initproc)qsignal_init, /*tp_init */
+ 0, /*tp_alloc */
+ PyType_GenericNew, /*tp_new */
+ qsignal_free, /*tp_free */
+ 0, /*tp_is_gc */
+ 0, /*tp_bases */
+ 0, /*tp_mro */
+ 0, /*tp_cache */
+ 0, /*tp_subclasses */
+ 0, /*tp_weaklist */
+ 0, /*tp_del */
+};
+
+static PyMethodDef PySideQtSignalInstance_methods[] = {
+ {"connect", (PyCFunction)qsignal_instance_connect, METH_VARARGS|METH_KEYWORDS},
+ {"disconnect", (PyCFunction)qsignal_instance_disconnect, METH_VARARGS},
+ {"emit", (PyCFunction)qsignal_instance_emit, METH_VARARGS},
+ {NULL} /* Sentinel */
+};
+
+PyTypeObject PySideSignalInstance_Type = {
+ PyObject_HEAD_INIT(0)
+ 0, /*ob_size*/
+ SIGNAL_CLASS_NAME, /*tp_name*/
+ sizeof(SignalData), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ SIGNAL_CLASS_NAME"I", /*tp_doc */
+ 0, /*tp_traverse */
+ 0, /*tp_clear */
+ 0, /*tp_richcompare */
+ 0, /*tp_weaklistoffset */
+ 0, /*tp_iter */
+ 0, /*tp_iternext */
+ PySideQtSignalInstance_methods, /*tp_methods */
+ 0, /*tp_members */
+ 0, /*tp_getset */
+ &PySideSignal_Type, /*tp_base */
+ 0, /*tp_dict */
+ 0, /*tp_descr_get */
+ 0, /*tp_descr_set */
+ 0, /*tp_dictoffset */
+ 0, /*tp_init */
+ 0, /*tp_alloc */
+ PyType_GenericNew, /*tp_new */
+ qsignal_instance_free, /*tp_free */
+ 0, /*tp_is_gc */
+ 0, /*tp_bases */
+ 0, /*tp_mro */
+ 0, /*tp_cache */
+ 0, /*tp_subclasses */
+ 0, /*tp_weaklist */
+ 0, /*tp_del */
+};
+
+
+PyAPI_FUNC(void) init_signal(PyObject* module)
+{
+ if (PyType_Ready(&PySideSignal_Type) < 0)
+ return;
+
+ Py_INCREF(&PySideSignal_Type);
+ PyModule_AddObject(module, SIGNAL_CLASS_NAME, ((PyObject*)&PySideSignal_Type));
+
+ if (PyType_Ready(&PySideSignalInstance_Type) < 0)
+ return;
+
+ Py_INCREF(&PySideSignalInstance_Type);
+}
+
+
+} // extern "C"
+
+void signal_update_source(PyObject *source)
+{
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ PyTypeObject *obType = source->ob_type;
+
+ while (PyDict_Next(obType->tp_dict, &pos, &key, &value)) {
+
+ if (value->ob_type == &PySideSignal_Type) {
+ PyObject *signal_instance = (PyObject*)PyObject_New(SignalData, &PySideSignalInstance_Type);
+
+ qsignal_instance_initialize(signal_instance, reinterpret_cast<SignalData*>(value), source);
+
+ PyObject_SetAttr(source, key, signal_instance);
+ Py_DECREF(signal_instance);
+
+ }
+
+ }
+}
+
+const char* qsignal_get_type_name(PyObject *type)
+{
+ if (PyType_Check(type)) {
+ //tp_name return the full name
+ Shiboken::AutoDecRef type_name(PyObject_GetAttrString(type, "__name__"));
+ return PyString_AS_STRING((PyObject*)type_name);
+ } else if (PyString_Check(type)) {
+ return PyString_AS_STRING(type);
+ }
+ return "";
+}
+
+char* qsignal_build_signature(const char *name, const char *signature)
+{
+ QString signal;
+ signal.sprintf("2%s(%s)", name, (signature ? signature : "()"));
+ return strdup(QMetaObject::normalizedSignature(signal.toAscii()));
+}
+
+void qsignal_append_signature(SignalData *self, PyObject *args)
+{
+ char *signature = 0;
+ for(Py_ssize_t i=0, i_max=PySequence_Size(args); i < i_max; i++) {
+ Shiboken::AutoDecRef arg(PySequence_ITEM(args, i));
+ const char *type_name = qsignal_get_type_name(arg);
+ if (strlen(type_name) > 0) {
+ if (signature) {
+ signature = strcat(signature, ",");
+ signature = strcat(signature, type_name);
+ } else {
+ signature = strdup(type_name);
+ }
+ }
+ }
+
+ self->signatures_size++;
+ if (self->signatures_size > 1) {
+ self->signatures = (char**) realloc(self->signatures, sizeof(char**) * self->signatures_size);
+ } else {
+ self->signatures = (char**) malloc(sizeof(char**));
+ }
+ self->signatures[self->signatures_size -1] = qsignal_build_signature(self->signal_name, signature);
+ printf("registred signature:[%d][%s]\n", self->signatures_size -1, self->signatures[self->signatures_size -1]);
+ free(signature);
+}
+
+int qsignal_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static PyObject *emptyTuple = 0;
+ static const char *kwlist[] = {"name", 0};
+ char* arg_name = 0;
+
+ if (emptyTuple == 0)
+ emptyTuple = PyTuple_New(0);
+
+ if (!PyArg_ParseTupleAndKeywords(emptyTuple, kwds,
+ "|s:QtCore."SIGNAL_CLASS_NAME, (char**) kwlist, &arg_name))
+ return 0;
+
+ bool tupled_args = false;
+ SignalData *data = reinterpret_cast<SignalData*>(self);
+ if (arg_name)
+ data->signal_name = strdup(arg_name);
+
+ for(Py_ssize_t i=0, i_max=PyTuple_Size(args); i < i_max; i++) {
+ PyObject *arg = PyTuple_GET_ITEM(args, i);
+ if (PySequence_Check(arg)) {
+ tupled_args = true;
+ qsignal_append_signature(data, arg);
+ }
+ }
+
+ if (!tupled_args)
+ qsignal_append_signature(data, args);
+
+
+ return 1;
+}
+
+void qsignal_free(void *self)
+{
+ PyObject *pySelf = reinterpret_cast<PyObject*>(self);
+ SignalData *data = reinterpret_cast<SignalData*>(self);
+
+ //keep the data to instance
+ if (!data->initialized)
+ qsignal_instance_free(self);
+
+ pySelf->ob_type->tp_free (self);
+}
+
+void qsignal_instance_free(void *self)
+{
+ PyObject *pySelf = reinterpret_cast<PyObject*>(self);
+ SignalData *data = reinterpret_cast<SignalData*>(self);
+ free(data->signatures[0]);
+ for(int i=1, i_max=data->signatures_size; i < i_max; i++) {
+ free(data->signatures[i]);
+ }
+ free(data->signatures);
+ free(data->signal_name);
+ data->initialized = false;
+
+ pySelf->ob_type->tp_free (self);
+}
+
+void qsignal_instance_initialize(PyObject *instance, SignalData *data, PyObject *source)
+{
+ SignalData *self = reinterpret_cast<SignalData*>(instance);
+ self->signal_name = data->signal_name;
+ self->signatures_size = data->signatures_size;
+ self->signatures = data->signatures;
+ self->initialized = true;
+ self->source = source;
+ data->initialized = true;
+}
+
+PyObject* qsignal_instance_connect(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *slot;
+ PyObject *type;
+ static const char *kwlist[] = {"type", 0};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
+ "O|O:"SIGNAL_CLASS_NAME, (char**) kwlist, &slot, &type))
+ return 0;
+
+ SignalData *source = reinterpret_cast<SignalData*>(self);
+ Shiboken::AutoDecRef pyArgs(PyList_New(0));
+
+ bool match = false;
+ if (slot->ob_type == &PySideSignal_Type) {
+ SignalData *target = reinterpret_cast<SignalData*>(slot);
+ for(int s, s_max=source->signatures_size; s < s_max; s++) {
+ for(int t, t_max=target->signatures_size; t < t_max; t++) {
+ if (QMetaObject::checkConnectArgs(source->signatures[s], target->signatures[t])) {
+ PyList_Append(pyArgs, source->source);
+ Shiboken::AutoDecRef source_signature(PyString_FromString(source->signatures[s]));
+ PyList_Append(pyArgs, source_signature);
+
+ PyList_Append(pyArgs, target->source);
+ Shiboken::AutoDecRef target_signature(PyString_FromString(source->signatures[s]));
+ PyList_Append(pyArgs, target_signature);
+ match = true;
+ break;
+ }
+ }
+ if (match) break;
+ }
+ } else {
+ //try the first signature
+ PyList_Append(pyArgs, source->source);
+ Shiboken::AutoDecRef signature(PyString_FromString(source->signatures[0]));
+ PyList_Append(pyArgs, signature);
+
+ PyList_Append(pyArgs, slot);
+ match = true;
+ }
+
+ if (match) {
+ Shiboken::AutoDecRef tupleArgs(PyList_AsTuple(pyArgs));
+ Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(source->source, "connect"));
+ return PyObject_CallObject(pyMethod, tupleArgs);
+ }
+
+ return 0;
+}
+
+PyObject* qsignal_instance_disconnect(PyObject *self, PyObject *args)
+{
+ SignalData *source = reinterpret_cast<SignalData*>(self);
+ Shiboken::AutoDecRef pyArgs(PyList_New(0));
+
+ PyObject *slot;
+ if PyTuple_Check(args)
+ slot = PyTuple_GET_ITEM(args, 0);
+ else
+ slot = args;
+
+ bool match = false;
+ if (slot->ob_type == &PySideSignal_Type) {
+ SignalData *target = reinterpret_cast<SignalData*>(slot);
+ for(int s, s_max=source->signatures_size; s < s_max; s++) {
+ for(int t, t_max=target->signatures_size; t < t_max; t++) {
+ if (QMetaObject::checkConnectArgs(source->signatures[s], target->signatures[t])) {
+ PyList_Append(pyArgs, source->source);
+ Shiboken::AutoDecRef source_signature(PyString_FromString(source->signatures[s]));
+ PyList_Append(pyArgs, source_signature);
+
+ PyList_Append(pyArgs, target->source);
+ Shiboken::AutoDecRef target_signature(PyString_FromString(source->signatures[s]));
+ PyList_Append(pyArgs, target_signature);
+ match = true;
+ break;
+ }
+ }
+ if (match) break;
+ }
+ } else {
+ //try the first signature
+ PyList_Append(pyArgs, source->source);
+ Shiboken::AutoDecRef signature(PyString_FromString(source->signatures[0]));
+ PyList_Append(pyArgs, signature);
+
+ PyList_Append(pyArgs, slot);
+ match = true;
+ }
+
+ if (match) {
+ Shiboken::AutoDecRef tupleArgs(PyList_AsTuple(pyArgs));
+ Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(source->source, "disconnect"));
+ return PyObject_CallObject(pyMethod, tupleArgs);
+ }
+
+ return 0;
+}
+
+PyObject* qsignal_instance_emit(PyObject *self, PyObject *args)
+{
+ SignalData *source = reinterpret_cast<SignalData*>(self);
+
+ Shiboken::AutoDecRef pyArgs(PyList_New(0));
+ Shiboken::AutoDecRef source_signature(PyString_FromString(source->signatures[0]));
+
+ PyList_Append(pyArgs, source_signature);
+ for(Py_ssize_t i=0, i_max=PyTuple_Size(args); i < i_max; i++)
+ PyList_Append(pyArgs, PyTuple_GetItem(args, i));
+
+ Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(source->source, "emit"));
+
+ Shiboken::AutoDecRef tupleArgs(PyList_AsTuple(pyArgs));
+ return PyObject_CallObject(pyMethod, tupleArgs);
+}
+
+} //namespace PySide
diff --git a/libpyside/qsignal.h b/libpyside/qsignal.h
new file mode 100644
index 000000000..1c91756c9
--- /dev/null
+++ b/libpyside/qsignal.h
@@ -0,0 +1,29 @@
+#ifndef QSIGNAL_H
+#define QSIGNAL_H
+
+#include <pysidemacros.h>
+#include <Python.h>
+#include <QObject>
+
+namespace PySide
+{
+
+typedef struct {
+ PyObject_HEAD
+ bool initialized;
+ char *signal_name;
+ char **signatures;
+ int signatures_size;
+ PyObject *source;
+} SignalData;
+
+extern "C"
+{
+ PyAPI_DATA(PyTypeObject) PySideSignal_Type;
+ PyAPI_DATA(PyTypeObject) PySideSignalInstance_Type;
+}; //extern "C"
+
+PYSIDE_API void signal_update_source(PyObject *source);
+
+} //namespace PySide
+#endif
diff --git a/PySide/QtCore/glue/qslot.cpp b/libpyside/qslot.cpp
index 8b8bac8b0..a2db44e97 100644
--- a/PySide/QtCore/glue/qslot.cpp
+++ b/libpyside/qslot.cpp
@@ -1,7 +1,10 @@
-#include <signalmanager.h>
+#include <shiboken.h>
#include <dynamicqmetaobject.h>
+#include <QString>
+
#define SLOT_DEC_NAME "Slot"
+
typedef struct
{
PyObject_HEAD
@@ -67,10 +70,6 @@ static PyTypeObject PySideSlot_Type = {
0, /*tp_del */
};
-static PyMethodDef PySideQtSlot_methods[] = {
- {NULL} /* Sentinel */
-};
-
PyAPI_FUNC(void) init_slot(PyObject* module)
{
if (PyType_Ready(&PySideSlot_Type) < 0)
@@ -86,7 +85,6 @@ PyAPI_FUNC(void) init_slot(PyObject* module)
static const char* qslot_get_type_name(PyObject *type)
{
if (PyType_Check(type)) {
- PyTypeObject *obj_type = (PyTypeObject*)(type);
//tp_name return the full name
Shiboken::AutoDecRef type_name(PyObject_GetAttrString(type, "__name__"));
return PyString_AS_STRING((PyObject*)type_name);
@@ -106,7 +104,7 @@ static int qslot_init(PyObject *self, PyObject *args, PyObject *kw)
if (emptyTuple == 0)
emptyTuple = PyTuple_New(0);
- if (!PyArg_ParseTupleAndKeywords(emptyTuple, kw, "|sN:QtCore."SLOT_DEC_NAME, (char**) kwlist, &arg_name, &arg_result))
+ if (!PyArg_ParseTupleAndKeywords(emptyTuple, kw, "|sO:QtCore."SLOT_DEC_NAME, (char**) kwlist, &arg_name, &arg_result))
return 0;
SlotData *data = reinterpret_cast<SlotData*>(self);
@@ -128,6 +126,8 @@ static int qslot_init(PyObject *self, PyObject *args, PyObject *kw)
if (arg_result)
data->result_type = strdup(qslot_get_type_name(arg_result));
+ else
+ data->result_type = strdup("void");
return 1;
}
@@ -147,7 +147,7 @@ static PyObject* qslot_call(PyObject *self, PyObject *args, PyObject *kw)
}
QString signature;
- signature.sprintf("%s(%s)",data->slot_name, data->args);
+ signature.sprintf("%s %s(%s)", data->result_type, data->slot_name, data->args);
PyObject *pySignature = PyString_FromString(QMetaObject::normalizedSignature(signature.toAscii()));
PyObject *signature_list = 0;
diff --git a/tests/signals/decorators_test.py b/tests/signals/decorators_test.py
index 43ae799b2..db068d009 100644
--- a/tests/signals/decorators_test.py
+++ b/tests/signals/decorators_test.py
@@ -24,8 +24,12 @@ class MyObject(QObject):
def foo(self):
self._slotCalledCount = self._slotCalledCount + 1
- @Slot(QString)
- def mySlot4(self, a):
+ @Slot(QString, int)
+ def mySlot4(self, a, b):
+ self._slotCalledCount = self._slotCalledCount + 1
+
+ @Slot(result=int)
+ def mySlot5(self):
self._slotCalledCount = self._slotCalledCount + 1
class StaticMetaObjectTest(unittest.TestCase):
@@ -37,7 +41,7 @@ class StaticMetaObjectTest(unittest.TestCase):
self.assert_(m.indexOfSlot('mySlot2(int)') > 0)
self.assert_(m.indexOfSlot('mySlot2(QString)') > 0)
self.assert_(m.indexOfSlot('mySlot3()') > 0)
- self.assert_(m.indexOfSlot('mySlot4(QString)') > 0)
+ self.assert_(m.indexOfSlot('mySlot4(QString,int)') > 0)
def testEmission(self):
o = MyObject()
@@ -45,5 +49,12 @@ class StaticMetaObjectTest(unittest.TestCase):
o.emit(SIGNAL("mySignal()"))
self.assert_(o._slotCalledCount == 1)
+ def testResult(self):
+ o = MyObject()
+ mo = o.metaObject()
+ i = mo.indexOfSlot('mySlot5()')
+ m = mo.method(i)
+ self.assertEqual(m.typeName(), "int")
+
if __name__ == '__main__':
unittest.main()
diff --git a/tests/signals/signal_object_test.py b/tests/signals/signal_object_test.py
new file mode 100644
index 000000000..89e114d67
--- /dev/null
+++ b/tests/signals/signal_object_test.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+import sys
+import unittest
+import functools
+
+from PySide.QtCore import *
+
+class MyObject(QObject):
+ sig1 = Signal()
+ sig2 = Signal(int, name='rangeChanged')
+
+
+ @Slot(int)
+ def myRange(self, r):
+ print "Range changed:", r
+
+
+ def slot1(self):
+ self._called = True
+
+
+
+class SignalObjectTest(unittest.TestCase):
+
+ def testsingleConnect(self):
+ o = MyObject()
+ o.sig1.connect(o.slot1)
+ o.sig1.emit()
+ self.assert_(o._called)
+
+ def testSignatureParse(self):
+ o = MyObject()
+ o.sig2.connect(o.myRange)
+ o.sig2.emit(10)
+
+
+if __name__ == '__main__':
+ unittest.main()