diff options
-rw-r--r-- | libpyside/qsignal.cpp | 166 | ||||
-rw-r--r-- | libpyside/qsignal.h | 10 | ||||
-rw-r--r-- | tests/signals/signal_object_test.py | 10 |
3 files changed, 120 insertions, 66 deletions
diff --git a/libpyside/qsignal.cpp b/libpyside/qsignal.cpp index 57876bad4..833c12af2 100644 --- a/libpyside/qsignal.cpp +++ b/libpyside/qsignal.cpp @@ -23,12 +23,14 @@ static void qsignal_instance_free(void*); 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); +static PyObject* qsignal_instance_get_item(PyObject *self, PyObject *key); //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, PyObject *name, SignalData *data, PyObject *source); +static void qsignal_instance_initialize(PyObject *instance, PyObject *name, SignalData *data, PyObject *source, int index); +static char* qsignal_parse_signature(PyObject *args); PyTypeObject PySideSignal_Type = { PyObject_HEAD_INIT(0) @@ -87,11 +89,17 @@ static PyMethodDef PySideQtSignalInstance_methods[] = { {NULL} /* Sentinel */ }; +static PyMappingMethods PySideQSignalInstance_as_mapping = { + 0, + qsignal_instance_get_item, + 0 +}; + PyTypeObject PySideSignalInstance_Type = { PyObject_HEAD_INIT(0) 0, /*ob_size*/ SIGNAL_CLASS_NAME, /*tp_name*/ - sizeof(SignalData), /*tp_basicsize*/ + sizeof(SignalInstanceData),/*tp_basicsize*/ 0, /*tp_itemsize*/ 0, /*tp_dealloc*/ 0, /*tp_print*/ @@ -101,7 +109,7 @@ PyTypeObject PySideSignalInstance_Type = { 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ + &PySideQSignalInstance_as_mapping, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ 0, /*tp_str*/ @@ -109,7 +117,7 @@ PyTypeObject PySideSignalInstance_Type = { 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - SIGNAL_CLASS_NAME"I", /*tp_doc */ + SIGNAL_CLASS_NAME, /*tp_doc */ 0, /*tp_traverse */ 0, /*tp_clear */ 0, /*tp_richcompare */ @@ -119,7 +127,7 @@ PyTypeObject PySideSignalInstance_Type = { PySideQtSignalInstance_methods, /*tp_methods */ 0, /*tp_members */ 0, /*tp_getset */ - &PySideSignal_Type, /*tp_base */ + 0, /*tp_base */ 0, /*tp_dict */ 0, /*tp_descr_get */ 0, /*tp_descr_set */ @@ -155,6 +163,27 @@ PyAPI_FUNC(void) init_signal(PyObject* module) } // extern "C" + +PyObject* qsignal_instance_get_item(PyObject *self, PyObject *key) +{ + SignalInstanceData *data = reinterpret_cast<SignalInstanceData*>(self); + char *sig_key = qsignal_parse_signature(key); + char *sig = qsignal_build_signature(data->signal_name, sig_key); + free(sig_key); + + while(data) { + if (strcmp(data->signature, sig) == 0) { + free(sig); + PyObject *result = reinterpret_cast<PyObject*>(data); + Py_INCREF(result); + return result; + } + data = reinterpret_cast<SignalInstanceData*>(data->next); + } + free(sig); + return 0; +} + void signal_update_source(PyObject *source) { PyObject *key, *value; @@ -162,17 +191,12 @@ void signal_update_source(PyObject *source) 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, key, reinterpret_cast<SignalData*>(value), source); - + qsignal_instance_initialize(signal_instance, key, reinterpret_cast<SignalData*>(value), source, 0); PyObject_SetAttr(source, key, signal_instance); Py_DECREF(signal_instance); - } - } } @@ -191,14 +215,16 @@ const char* qsignal_get_type_name(PyObject *type) 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* qsignal_parse_signature(PyObject *args) { char *signature = 0; + if (args && !PySequence_Check(args) && (args != Py_None && args)) + return strdup(qsignal_get_type_name(args)); + 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); @@ -212,6 +238,13 @@ void qsignal_append_signature(SignalData *self, PyObject *args) } } + return signature; +} + +void qsignal_append_signature(SignalData *self, PyObject *args) +{ + char *signature = qsignal_parse_signature(args); + self->signatures_size++; if (self->signatures_size > 1) { @@ -271,33 +304,46 @@ void qsignal_free(void *self) data->initialized = false; data->signatures_size = 0; - pySelf->ob_type->tp_free (self); + pySelf->ob_type->tp_base->tp_free(self); } void qsignal_instance_free(void *self) { PyObject *pySelf = reinterpret_cast<PyObject*>(self); - qsignal_free(self); - pySelf->ob_type->tp_free(self); + SignalInstanceData *data = reinterpret_cast<SignalInstanceData*>(self); + + free(data->signal_name); + free(data->signature); + + while(data) { + Py_XDECREF(data->next); + data = reinterpret_cast<SignalInstanceData*>(data->next); + } + pySelf->ob_type->tp_base->tp_free(self); } -void qsignal_instance_initialize(PyObject *instance, PyObject *name, SignalData *data, PyObject *source) +void qsignal_instance_initialize(PyObject *instance, PyObject *name, SignalData *data, PyObject *source, int index) { - SignalData *self = reinterpret_cast<SignalData*>(instance); + if (data->initialized) + return; + + SignalInstanceData *self = reinterpret_cast<SignalInstanceData*>(instance); if (data->signal_name) self->signal_name = strdup(data->signal_name); else self->signal_name = strdup(PyString_AsString(name)); - self->signatures_size = data->signatures_size; - self->initialized = true; self->source = source; - data->initialized = true; + self->signature = qsignal_build_signature(self->signal_name, data->signatures[index]); + index++; - self->signatures = (char**) malloc(sizeof(char**) * self->signatures_size); - ///build signature - for(int i=0, i_max=self->signatures_size; i < i_max; i++) - self->signatures[i] = qsignal_build_signature(self->signal_name, data->signatures[i]); + if (index < data->signatures_size) { + self->next = (PyObject*)PyObject_New(SignalData, &PySideSignalInstance_Type); + qsignal_instance_initialize(self->next, name, data, source, index); + } + + if (index == 0) + data->initialized = true; } PyObject* qsignal_instance_connect(PyObject *self, PyObject *args, PyObject *kwds) @@ -310,32 +356,28 @@ PyObject* qsignal_instance_connect(PyObject *self, PyObject *args, PyObject *kwd "O|O:"SIGNAL_CLASS_NAME, (char**) kwlist, &slot, &type)) return 0; - SignalData *source = reinterpret_cast<SignalData*>(self); + SignalInstanceData *source = reinterpret_cast<SignalInstanceData*>(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; + if (slot->ob_type == &PySideSignalInstance_Type) { + //TODO: find best match + SignalInstanceData *target = reinterpret_cast<SignalInstanceData*>(slot); + + if (QMetaObject::checkConnectArgs(source->signature, target->signature)) { + PyList_Append(pyArgs, source->source); + Shiboken::AutoDecRef source_signature(PyString_FromString(source->signature)); + PyList_Append(pyArgs, source_signature); + + PyList_Append(pyArgs, target->source); + Shiboken::AutoDecRef target_signature(PyString_FromString(target->signature)); + PyList_Append(pyArgs, target_signature); + match = true; } } else { //try the first signature PyList_Append(pyArgs, source->source); - Shiboken::AutoDecRef signature(PyString_FromString(source->signatures[0])); + Shiboken::AutoDecRef signature(PyString_FromString(source->signature)); PyList_Append(pyArgs, signature); PyList_Append(pyArgs, slot); @@ -353,7 +395,7 @@ PyObject* qsignal_instance_connect(PyObject *self, PyObject *args, PyObject *kwd PyObject* qsignal_instance_disconnect(PyObject *self, PyObject *args) { - SignalData *source = reinterpret_cast<SignalData*>(self); + SignalInstanceData *source = reinterpret_cast<SignalInstanceData*>(self); Shiboken::AutoDecRef pyArgs(PyList_New(0)); PyObject *slot; @@ -363,28 +405,22 @@ PyObject* qsignal_instance_disconnect(PyObject *self, PyObject *args) 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; + if (slot->ob_type == &PySideSignalInstance_Type) { + SignalInstanceData *target = reinterpret_cast<SignalInstanceData*>(slot); + if (QMetaObject::checkConnectArgs(source->signature, target->signature)) { + PyList_Append(pyArgs, source->source); + Shiboken::AutoDecRef source_signature(PyString_FromString(source->signature)); + PyList_Append(pyArgs, source_signature); + + PyList_Append(pyArgs, target->source); + Shiboken::AutoDecRef target_signature(PyString_FromString(target->signature)); + PyList_Append(pyArgs, target_signature); + match = true; } } else { //try the first signature PyList_Append(pyArgs, source->source); - Shiboken::AutoDecRef signature(PyString_FromString(source->signatures[0])); + Shiboken::AutoDecRef signature(PyString_FromString(source->signature)); PyList_Append(pyArgs, signature); PyList_Append(pyArgs, slot); @@ -402,10 +438,10 @@ PyObject* qsignal_instance_disconnect(PyObject *self, PyObject *args) PyObject* qsignal_instance_emit(PyObject *self, PyObject *args) { - SignalData *source = reinterpret_cast<SignalData*>(self); + SignalInstanceData *source = reinterpret_cast<SignalInstanceData*>(self); Shiboken::AutoDecRef pyArgs(PyList_New(0)); - Shiboken::AutoDecRef source_signature(PyString_FromString(source->signatures[0])); + Shiboken::AutoDecRef source_signature(PyString_FromString(source->signature)); PyList_Append(pyArgs, source_signature); for(Py_ssize_t i=0, i_max=PyTuple_Size(args); i < i_max; i++) diff --git a/libpyside/qsignal.h b/libpyside/qsignal.h index 1c91756c9..ea034cd7c 100644 --- a/libpyside/qsignal.h +++ b/libpyside/qsignal.h @@ -14,9 +14,17 @@ typedef struct { char *signal_name; char **signatures; int signatures_size; - PyObject *source; } SignalData; +typedef struct { + PyObject_HEAD + char *signal_name; + char *signature; + PyObject *source; + PyObject *next; +} SignalInstanceData; + + extern "C" { PyAPI_DATA(PyTypeObject) PySideSignal_Type; diff --git a/tests/signals/signal_object_test.py b/tests/signals/signal_object_test.py index a3dee57d1..49ab5a4fd 100644 --- a/tests/signals/signal_object_test.py +++ b/tests/signals/signal_object_test.py @@ -10,6 +10,7 @@ class MyObject(QObject): sig1 = Signal() sig2 = Signal(int, name='rangeChanged') sig3 = Signal(int) + sig4 = Signal((int,), (QString,)) @Slot(int) @@ -21,6 +22,9 @@ class MyObject(QObject): def slot1(self): self._called = True + def slotString(self, s): + self._s = s + class SignalObjectTest(unittest.TestCase): def testsingleConnect(self): @@ -40,5 +44,11 @@ class SignalObjectTest(unittest.TestCase): o.sig2.connect(o.myRange) o.sig2.emit(10) + def testDictOperator(self): + o = MyObject() + o.sig4[QString].connect(o.slotString) + o.sig4[QString].emit("PySide") + self.assertEqual(o._s, "PySide") + if __name__ == '__main__': unittest.main() |