diff options
author | Renato Filho <renato.filho@openbossa.org> | 2010-05-13 15:50:42 -0300 |
---|---|---|
committer | Renato Filho <renato.filho@openbossa.org> | 2010-05-17 19:53:54 -0300 |
commit | c5fd4d4830cb49c9f8087d7e54335f4c248f76bf (patch) | |
tree | 6a4fd6a9e30f1d5a1b3ead182d768d2f4fc38a79 /libpyside/qsignal.cpp | |
parent | d2a6f35ef914b000ddd7685925075985c76817ac (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
Diffstat (limited to 'libpyside/qsignal.cpp')
-rw-r--r-- | libpyside/qsignal.cpp | 413 |
1 files changed, 413 insertions, 0 deletions
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 |