// Handle the getting of a lazy attribute, ie. a native Qt signal. int qpycore_get_lazy_attr(const sipTypeDef *td, PyObject *dict) { const pyqt5QtSignal *sigs = reinterpret_cast<const pyqt5ClassPluginDef *>( sipTypePluginData(td))->qt_signals; // Handle the trvial case. if (!sigs) return 0; QByteArray default_name; qpycore_pyqtSignal *default_signal = 0; do { // See if we have come to the end of the current signal. if (default_signal && !is_signal_name(sigs->signature, default_name)) { if (PyDict_SetItemString(dict, default_name.constData(), (PyObject *)default_signal) < 0) return -1; default_signal = 0; } bool fatal; qpycore_pyqtSignal *sig = qpycore_pyqtSignal_New(sigs->signature, &fatal); if (!sig) { if (fatal) return -1; PyErr_Clear(); continue; } sig->docstring = sigs->docstring; sig->emitter = sigs->emitter; // See if this is a new default. if (default_signal) { sig->default_signal = default_signal; append_overload(sig); } else { sig->non_signals = sigs->non_signals; default_signal = sig->default_signal = sig; default_name = sigs->signature; default_name.truncate(default_name.indexOf('(')); } } while ((++sigs)->signature); // Save the last one, if any (in case of a non-fatal error). if (!default_signal) return 0; return PyDict_SetItemString(dict, default_name.constData(), (PyObject *)default_signal); }
// See if we can find an attribute in the Qt meta-type system. This is // primarily to support access to JavaScript (e.g. QDeclarativeItem) so we // don't support overloads. PyObject *qpycore_qobject_getattr(QObject *qobj, PyObject *py_qobj, const char *name) { const QMetaObject *mo = qobj->metaObject(); // Try and find a method with the name. QMetaMethod method; int method_index = -1; // Count down to allow overrides (assuming they are possible). for (int m = mo->methodCount() - 1; m >= 0; --m) { method = mo->method(m); #if QT_VERSION >= 0x040500 if (method.methodType() == QMetaMethod::Constructor) continue; #endif // Get the method name. #if QT_VERSION >= 0x050000 QByteArray mname(method.methodSignature()); #else QByteArray mname(method.signature()); #endif int idx = mname.indexOf('('); if (idx >= 0) mname.truncate(idx); if (mname == name) { method_index = m; break; } } if (method_index < 0) { // Replicate the standard Python exception. PyErr_Format(PyExc_AttributeError, "'%s' object has no attribute '%s'", Py_TYPE(py_qobj)->tp_name, name); return 0; } // Get the value to return. Note that this is recreated each time. We // could put a descriptor in the type dictionary to satisfy the request in // future but the typical use case is getting a value from a C++ proxy // (e.g. QDeclarativeItem) and we can't assume that what is being proxied // is the same each time. PyObject *value; if (method.methodType() == QMetaMethod::Signal) { // We need to keep explicit references to the unbound signals (because // we don't use the type dictionary to do so) because they own the // parsed signature which may be needed by a PyQtProxy at some point. typedef QHash<QByteArray, PyObject *> SignalHash; static SignalHash *sig_hash = 0; // For crappy compilers. if (!sig_hash) sig_hash = new SignalHash; PyObject *sig_obj; #if QT_VERSION >= 0x050000 QByteArray sig_str(method.methodSignature()); #else QByteArray sig_str(method.signature()); #endif SignalHash::const_iterator it = sig_hash->find(sig_str); if (it == sig_hash->end()) { sig_obj = (PyObject *)qpycore_pyqtSignal_New(sig_str.constData()); if (!sig_obj) return 0; sig_hash->insert(sig_str, sig_obj); } else { sig_obj = it.value(); } value = qpycore_pyqtBoundSignal_New((qpycore_pyqtSignal *)sig_obj, py_qobj, qobj); } else { QByteArray py_name(Py_TYPE(py_qobj)->tp_name); py_name.append('.'); py_name.append(name); value = qpycore_pyqtMethodProxy_New(qobj, method_index, py_name); } return value; }
// Handle the getting of a lazy attribute, ie. a native Qt signal. int qpycore_get_lazy_attr(const sipTypeDef *td, PyObject *dict) { pyqt4ClassTypeDef *ctd = (pyqt4ClassTypeDef *)td; const pyqt4QtSignal *sigs = ctd->qt4_signals; // Handle the trvial case. if (!sigs) return 0; QByteArray default_name; qpycore_pyqtSignal *default_signal = 0; do { // See if we have come to the end of the current signal. if (default_signal && !is_signal_name(sigs->signature, default_name.constData(), default_name.size())) { if (PyDict_SetItemString(dict, default_name.constData(), (PyObject *)default_signal) < 0) return -1; default_signal = 0; } bool fatal; qpycore_pyqtSignal *sig = qpycore_pyqtSignal_New(sigs->signature, &fatal); if (!sig) { if (fatal) return -1; PyErr_Clear(); continue; } sig->docstring = sigs->docstring; // See if this is a new default. if (default_signal) { sig->default_signal = default_signal; append_overload(sig); } else { sig->non_signals = sigs->non_signals; default_signal = sig->default_signal = sig; // Get the name. default_name = sig->signature->name().mid(1); } } while ((++sigs)->signature); // Save the last one, if any (in case of a non-fatal error). if (!default_signal) return 0; return PyDict_SetItemString(dict, default_name.constData(), (PyObject *)default_signal); }