@@ -0,0 +1,350 | |||
|
1 | /* | |
|
2 | * | |
|
3 | * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved. | |
|
4 | * | |
|
5 | * This library is free software; you can redistribute it and/or | |
|
6 | * modify it under the terms of the GNU Lesser General Public | |
|
7 | * License as published by the Free Software Foundation; either | |
|
8 | * version 2.1 of the License, or (at your option) any later version. | |
|
9 | * | |
|
10 | * This library is distributed in the hope that it will be useful, | |
|
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
|
13 | * Lesser General Public License for more details. | |
|
14 | * | |
|
15 | * Further, this software is distributed without any warranty that it is | |
|
16 | * free of the rightful claim of any third person regarding infringement | |
|
17 | * or the like. Any license provided herein, whether implied or | |
|
18 | * otherwise, applies only to this software file. Patent licenses, if | |
|
19 | * any, provided herein do not apply to combinations of this program with | |
|
20 | * other software, or any other product whatsoever. | |
|
21 | * | |
|
22 | * You should have received a copy of the GNU Lesser General Public | |
|
23 | * License along with this library; if not, write to the Free Software | |
|
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
|
25 | * | |
|
26 | * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29, | |
|
27 | * 28359 Bremen, Germany or: | |
|
28 | * | |
|
29 | * http://www.mevis.de | |
|
30 | * | |
|
31 | */ | |
|
32 | ||
|
33 | //---------------------------------------------------------------------------------- | |
|
34 | /*! | |
|
35 | // \file PythonQtSignal.cpp | |
|
36 | // \author Florian Link | |
|
37 | // \author Last changed by $Author: florian $ | |
|
38 | // \date 2012-02 | |
|
39 | */ | |
|
40 | //---------------------------------------------------------------------------------- | |
|
41 | ||
|
42 | #include "PythonQt.h" | |
|
43 | #include "PythonQtSignal.h" | |
|
44 | #include "PythonQtInstanceWrapper.h" | |
|
45 | #include "PythonQtClassInfo.h" | |
|
46 | #include "PythonQtMisc.h" | |
|
47 | #include "PythonQtConversion.h" | |
|
48 | #include "PythonQtSlot.h" | |
|
49 | ||
|
50 | #include <iostream> | |
|
51 | ||
|
52 | #include <exception> | |
|
53 | #include <stdexcept> | |
|
54 | ||
|
55 | #include <QByteArray> | |
|
56 | ||
|
57 | //----------------------------------------------------------------------------------- | |
|
58 | ||
|
59 | static PythonQtSignalFunctionObject *PythonQtSignal_free_list = NULL; | |
|
60 | ||
|
61 | PyObject *PythonQtSignalFunction_Call(PyObject *func, PyObject *args, PyObject *kw) | |
|
62 | { | |
|
63 | PythonQtSignalFunctionObject* f = (PythonQtSignalFunctionObject*)func; | |
|
64 | return PythonQtMemberFunction_Call(f->m_ml, f->m_self, args, kw); | |
|
65 | } | |
|
66 | ||
|
67 | PyObject * | |
|
68 | PythonQtSignalFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module) | |
|
69 | { | |
|
70 | PythonQtSignalFunctionObject *op; | |
|
71 | op = PythonQtSignal_free_list; | |
|
72 | if (op != NULL) { | |
|
73 | PythonQtSignal_free_list = (PythonQtSignalFunctionObject *)(op->m_self); | |
|
74 | PyObject_INIT(op, &PythonQtSignalFunction_Type); | |
|
75 | } | |
|
76 | else { | |
|
77 | op = PyObject_GC_New(PythonQtSignalFunctionObject, &PythonQtSignalFunction_Type); | |
|
78 | if (op == NULL) | |
|
79 | return NULL; | |
|
80 | } | |
|
81 | op->m_ml = ml; | |
|
82 | Py_XINCREF(self); | |
|
83 | op->m_self = self; | |
|
84 | Py_XINCREF(module); | |
|
85 | op->m_module = module; | |
|
86 | PyObject_GC_Track(op); | |
|
87 | return (PyObject *)op; | |
|
88 | } | |
|
89 | ||
|
90 | /* Methods (the standard built-in methods, that is) */ | |
|
91 | ||
|
92 | static void | |
|
93 | meth_dealloc(PythonQtSignalFunctionObject *m) | |
|
94 | { | |
|
95 | PyObject_GC_UnTrack(m); | |
|
96 | Py_XDECREF(m->m_self); | |
|
97 | Py_XDECREF(m->m_module); | |
|
98 | m->m_self = (PyObject *)PythonQtSignal_free_list; | |
|
99 | PythonQtSignal_free_list = m; | |
|
100 | } | |
|
101 | ||
|
102 | static PyObject * | |
|
103 | meth_get__doc__(PythonQtSignalFunctionObject * /*m*/, void * /*closure*/) | |
|
104 | { | |
|
105 | Py_INCREF(Py_None); | |
|
106 | return Py_None; | |
|
107 | } | |
|
108 | ||
|
109 | static PyObject * | |
|
110 | meth_get__name__(PythonQtSignalFunctionObject *m, void * /*closure*/) | |
|
111 | { | |
|
112 | return PyString_FromString(m->m_ml->metaMethod()->signature()); | |
|
113 | } | |
|
114 | ||
|
115 | static int | |
|
116 | meth_traverse(PythonQtSignalFunctionObject *m, visitproc visit, void *arg) | |
|
117 | { | |
|
118 | int err; | |
|
119 | if (m->m_self != NULL) { | |
|
120 | err = visit(m->m_self, arg); | |
|
121 | if (err) | |
|
122 | return err; | |
|
123 | } | |
|
124 | if (m->m_module != NULL) { | |
|
125 | err = visit(m->m_module, arg); | |
|
126 | if (err) | |
|
127 | return err; | |
|
128 | } | |
|
129 | return 0; | |
|
130 | } | |
|
131 | ||
|
132 | static PyObject * | |
|
133 | meth_get__self__(PythonQtSignalFunctionObject *m, void * /*closure*/) | |
|
134 | { | |
|
135 | PyObject *self; | |
|
136 | if (PyEval_GetRestricted()) { | |
|
137 | PyErr_SetString(PyExc_RuntimeError, | |
|
138 | "method.__self__ not accessible in restricted mode"); | |
|
139 | return NULL; | |
|
140 | } | |
|
141 | self = m->m_self; | |
|
142 | if (self == NULL) | |
|
143 | self = Py_None; | |
|
144 | Py_INCREF(self); | |
|
145 | return self; | |
|
146 | } | |
|
147 | ||
|
148 | static PyGetSetDef meth_getsets [] = { | |
|
149 | {const_cast<char*>("__doc__"), (getter)meth_get__doc__, NULL, NULL}, | |
|
150 | {const_cast<char*>("__name__"), (getter)meth_get__name__, NULL, NULL}, | |
|
151 | {const_cast<char*>("__self__"), (getter)meth_get__self__, NULL, NULL}, | |
|
152 | {NULL, NULL, NULL,NULL}, | |
|
153 | }; | |
|
154 | ||
|
155 | #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6 | |
|
156 | #define PY_WRITE_RESTRICTED WRITE_RESTRICTED | |
|
157 | #endif | |
|
158 | ||
|
159 | #define OFF(x) offsetof(PythonQtSignalFunctionObject, x) | |
|
160 | ||
|
161 | static PyMemberDef meth_members[] = { | |
|
162 | {const_cast<char*>("__module__"), T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED}, | |
|
163 | {NULL} | |
|
164 | }; | |
|
165 | ||
|
166 | static PyObject *PythonQtSignalFunction_parameterTypes(PythonQtSignalFunctionObject* type) | |
|
167 | { | |
|
168 | return PythonQtMemberFunction_parameterTypes(type->m_ml); | |
|
169 | } | |
|
170 | ||
|
171 | static PyObject *PythonQtSignalFunction_parameterNames(PythonQtSignalFunctionObject* type) | |
|
172 | { | |
|
173 | return PythonQtMemberFunction_parameterNames(type->m_ml); | |
|
174 | } | |
|
175 | ||
|
176 | static PyObject *PythonQtSignalFunction_typeName(PythonQtSignalFunctionObject* type) | |
|
177 | { | |
|
178 | return PythonQtMemberFunction_typeName(type->m_ml); | |
|
179 | } | |
|
180 | ||
|
181 | static PyObject *PythonQtSignalFunction_connect(PythonQtSignalFunctionObject* type, PyObject *args) | |
|
182 | { | |
|
183 | if (PyObject_TypeCheck(type->m_self, &PythonQtInstanceWrapper_Type)) { | |
|
184 | PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) type->m_self; | |
|
185 | if (self->_obj) { | |
|
186 | Py_ssize_t argc = PyTuple_Size(args); | |
|
187 | if (argc==1) { | |
|
188 | // connect with Python callable | |
|
189 | PyObject* callable = PyTuple_GET_ITEM(args, 0); | |
|
190 | bool result = PythonQt::self()->addSignalHandler(self->_obj, QByteArray("2") + type->m_ml->metaMethod()->signature(), callable); | |
|
191 | return PythonQtConv::GetPyBool(result); | |
|
192 | } else { | |
|
193 | PyErr_SetString(PyExc_ValueError, "Called connect with wrong number of arguments"); | |
|
194 | } | |
|
195 | } | |
|
196 | } | |
|
197 | return NULL; | |
|
198 | } | |
|
199 | ||
|
200 | static PyObject *PythonQtSignalFunction_disconnect(PythonQtSignalFunctionObject* type, PyObject *args) | |
|
201 | { | |
|
202 | if (PyObject_TypeCheck(type->m_self, &PythonQtInstanceWrapper_Type)) { | |
|
203 | PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) type->m_self; | |
|
204 | if (self->_obj) { | |
|
205 | Py_ssize_t argc = PyTuple_Size(args); | |
|
206 | QByteArray signal = QByteArray("2") + type->m_ml->metaMethod()->signature(); | |
|
207 | if (argc==1) { | |
|
208 | // disconnect with Python callable | |
|
209 | PyObject* callable = PyTuple_GET_ITEM(args, 0); | |
|
210 | bool result = PythonQt::self()->removeSignalHandler(self->_obj, signal, callable); | |
|
211 | return PythonQtConv::GetPyBool(result); | |
|
212 | } else if (argc==0) { | |
|
213 | bool result = PythonQt::self()->removeSignalHandler(self->_obj, signal, NULL); | |
|
214 | result |= QObject::disconnect(self->_obj, signal, NULL, NULL); | |
|
215 | return PythonQtConv::GetPyBool(result); | |
|
216 | } else { | |
|
217 | PyErr_SetString(PyExc_ValueError, "Called disconnect with wrong number of arguments"); | |
|
218 | } | |
|
219 | } | |
|
220 | } | |
|
221 | return NULL; | |
|
222 | } | |
|
223 | ||
|
224 | static PyObject *PythonQtSignalFunction_emit(PythonQtSignalFunctionObject* func, PyObject *args) | |
|
225 | { | |
|
226 | PythonQtSignalFunctionObject* f = (PythonQtSignalFunctionObject*)func; | |
|
227 | return PythonQtMemberFunction_Call(f->m_ml, f->m_self, args, NULL); | |
|
228 | } | |
|
229 | ||
|
230 | static PyMethodDef meth_methods[] = { | |
|
231 | {"parameterTypes", (PyCFunction)PythonQtSignalFunction_parameterTypes, METH_NOARGS, | |
|
232 | "Returns a tuple of tuples of the C++ parameter types for all overloads of the signal" | |
|
233 | }, | |
|
234 | {"parameterNames", (PyCFunction)PythonQtSignalFunction_parameterNames, METH_NOARGS, | |
|
235 | "Returns a tuple of tuples of the C++ parameter type names (if available), for all overloads of the signal" | |
|
236 | }, | |
|
237 | {"typeName", (PyCFunction)PythonQtSignalFunction_typeName, METH_NOARGS, | |
|
238 | "Returns a tuple of the C++ return value types of each signal overload" | |
|
239 | }, | |
|
240 | {"connect", (PyCFunction)PythonQtSignalFunction_connect, METH_VARARGS, | |
|
241 | "Connects the signal to the Python callable" | |
|
242 | }, | |
|
243 | {"disconnect", (PyCFunction)PythonQtSignalFunction_disconnect, METH_VARARGS, | |
|
244 | "Disconnects the signal from the given Python callable or disconnects all if no argument is passed." | |
|
245 | }, | |
|
246 | {"emit", (PyCFunction)PythonQtSignalFunction_emit, METH_VARARGS, | |
|
247 | "Emits the signal with given arguments" | |
|
248 | }, | |
|
249 | {NULL, NULL, 0 , NULL} /* Sentinel */ | |
|
250 | }; | |
|
251 | ||
|
252 | static PyObject * | |
|
253 | meth_repr(PythonQtSignalFunctionObject *f) | |
|
254 | { | |
|
255 | if (f->m_self->ob_type == &PythonQtClassWrapper_Type) { | |
|
256 | PythonQtClassWrapper* self = (PythonQtClassWrapper*) f->m_self; | |
|
257 | return PyString_FromFormat("<unbound qt signal %s of %s type>", | |
|
258 | f->m_ml->slotName().data(), | |
|
259 | self->classInfo()->className()); | |
|
260 | } else { | |
|
261 | return PyString_FromFormat("<qt signal %s of %s instance at %p>", | |
|
262 | f->m_ml->slotName().data(), | |
|
263 | f->m_self->ob_type->tp_name, | |
|
264 | f->m_self); | |
|
265 | } | |
|
266 | } | |
|
267 | ||
|
268 | static int | |
|
269 | meth_compare(PythonQtSignalFunctionObject *a, PythonQtSignalFunctionObject *b) | |
|
270 | { | |
|
271 | if (a->m_self != b->m_self) | |
|
272 | return (a->m_self < b->m_self) ? -1 : 1; | |
|
273 | if (a->m_ml == b->m_ml) | |
|
274 | return 0; | |
|
275 | if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0) | |
|
276 | return -1; | |
|
277 | else | |
|
278 | return 1; | |
|
279 | } | |
|
280 | ||
|
281 | static long | |
|
282 | meth_hash(PythonQtSignalFunctionObject *a) | |
|
283 | { | |
|
284 | long x,y; | |
|
285 | if (a->m_self == NULL) | |
|
286 | x = 0; | |
|
287 | else { | |
|
288 | x = PyObject_Hash(a->m_self); | |
|
289 | if (x == -1) | |
|
290 | return -1; | |
|
291 | } | |
|
292 | y = _Py_HashPointer((void*)(a->m_ml)); | |
|
293 | if (y == -1) | |
|
294 | return -1; | |
|
295 | x ^= y; | |
|
296 | if (x == -1) | |
|
297 | x = -2; | |
|
298 | return x; | |
|
299 | } | |
|
300 | ||
|
301 | ||
|
302 | PyTypeObject PythonQtSignalFunction_Type = { | |
|
303 | PyObject_HEAD_INIT(&PyType_Type) | |
|
304 | 0, | |
|
305 | "builtin_qt_signal", | |
|
306 | sizeof(PythonQtSignalFunctionObject), | |
|
307 | 0, | |
|
308 | (destructor)meth_dealloc, /* tp_dealloc */ | |
|
309 | 0, /* tp_print */ | |
|
310 | 0, /* tp_getattr */ | |
|
311 | 0, /* tp_setattr */ | |
|
312 | (cmpfunc)meth_compare, /* tp_compare */ | |
|
313 | (reprfunc)meth_repr, /* tp_repr */ | |
|
314 | 0, /* tp_as_number */ | |
|
315 | 0, /* tp_as_sequence */ | |
|
316 | // TODO: implement tp_as_mapping to support overload resolution on the signal | |
|
317 | 0, /* tp_as_mapping */ | |
|
318 | (hashfunc)meth_hash, /* tp_hash */ | |
|
319 | PythonQtSignalFunction_Call, /* tp_call */ | |
|
320 | 0, /* tp_str */ | |
|
321 | PyObject_GenericGetAttr, /* tp_getattro */ | |
|
322 | 0, /* tp_setattro */ | |
|
323 | 0, /* tp_as_buffer */ | |
|
324 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ | |
|
325 | 0, /* tp_doc */ | |
|
326 | (traverseproc)meth_traverse, /* tp_traverse */ | |
|
327 | 0, /* tp_clear */ | |
|
328 | 0, /* tp_richcompare */ | |
|
329 | 0, /* tp_weaklistoffset */ | |
|
330 | 0, /* tp_iter */ | |
|
331 | 0, /* tp_iternext */ | |
|
332 | meth_methods, /* tp_methods */ | |
|
333 | meth_members, /* tp_members */ | |
|
334 | meth_getsets, /* tp_getset */ | |
|
335 | 0, /* tp_base */ | |
|
336 | 0, /* tp_dict */ | |
|
337 | }; | |
|
338 | ||
|
339 | /* Clear out the free list */ | |
|
340 | ||
|
341 | void | |
|
342 | PythonQtSignalFunction_Fini(void) | |
|
343 | { | |
|
344 | while (PythonQtSignal_free_list) { | |
|
345 | PythonQtSignalFunctionObject *v = PythonQtSignal_free_list; | |
|
346 | PythonQtSignal_free_list = (PythonQtSignalFunctionObject *)(v->m_self); | |
|
347 | PyObject_GC_Del(v); | |
|
348 | } | |
|
349 | } | |
|
350 |
@@ -0,0 +1,68 | |||
|
1 | #ifndef _PythonQtSignal_H | |
|
2 | #define _PythonQtSignal_H | |
|
3 | ||
|
4 | /* | |
|
5 | * | |
|
6 | * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved. | |
|
7 | * | |
|
8 | * This library is free software; you can redistribute it and/or | |
|
9 | * modify it under the terms of the GNU Lesser General Public | |
|
10 | * License as published by the Free Software Foundation; either | |
|
11 | * version 2.1 of the License, or (at your option) any later version. | |
|
12 | * | |
|
13 | * This library is distributed in the hope that it will be useful, | |
|
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
|
16 | * Lesser General Public License for more details. | |
|
17 | * | |
|
18 | * Further, this software is distributed without any warranty that it is | |
|
19 | * free of the rightful claim of any third person regarding infringement | |
|
20 | * or the like. Any license provided herein, whether implied or | |
|
21 | * otherwise, applies only to this software file. Patent licenses, if | |
|
22 | * any, provided herein do not apply to combinations of this program with | |
|
23 | * other software, or any other product whatsoever. | |
|
24 | * | |
|
25 | * You should have received a copy of the GNU Lesser General Public | |
|
26 | * License along with this library; if not, write to the Free Software | |
|
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
|
28 | * | |
|
29 | * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29, | |
|
30 | * 28359 Bremen, Germany or: | |
|
31 | * | |
|
32 | * http://www.mevis.de | |
|
33 | * | |
|
34 | */ | |
|
35 | ||
|
36 | //---------------------------------------------------------------------------------- | |
|
37 | /*! | |
|
38 | // \file PythonQtSignal.h | |
|
39 | // \author Florian Link | |
|
40 | // \author Last changed by $Author: florian $ | |
|
41 | // \date 2006-05 | |
|
42 | */ | |
|
43 | //---------------------------------------------------------------------------------- | |
|
44 | ||
|
45 | #include "PythonQtPythonInclude.h" | |
|
46 | ||
|
47 | #include "PythonQtSystem.h" | |
|
48 | #include "structmember.h" | |
|
49 | ||
|
50 | class PythonQtSlotInfo; | |
|
51 | ||
|
52 | extern PYTHONQT_EXPORT PyTypeObject PythonQtSignalFunction_Type; | |
|
53 | ||
|
54 | #define PythonQtSignalFunction_Check(op) ((op)->ob_type == &PythonQtSignalFunction_Type) | |
|
55 | ||
|
56 | PyObject* PythonQtSignalFunction_New(PythonQtSlotInfo *, PyObject *, | |
|
57 | PyObject *); | |
|
58 | ||
|
59 | //! defines a python object that stores a Qt signal info | |
|
60 | typedef struct { | |
|
61 | PyObject_HEAD | |
|
62 | PythonQtSlotInfo *m_ml; /* Description of the C function to call */ | |
|
63 | PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */ | |
|
64 | PyObject *m_module; /* The __module__ attribute, can be anything */ | |
|
65 | } PythonQtSignalFunctionObject; | |
|
66 | ||
|
67 | ||
|
68 | #endif |
@@ -43,6 +43,7 | |||
|
43 | 43 | #include "PythonQtImporter.h" |
|
44 | 44 | #include "PythonQtClassInfo.h" |
|
45 | 45 | #include "PythonQtMethodInfo.h" |
|
46 | #include "PythonQtSignal.h" | |
|
46 | 47 | #include "PythonQtSignalReceiver.h" |
|
47 | 48 | #include "PythonQtConversion.h" |
|
48 | 49 | #include "PythonQtStdIn.h" |
@@ -167,6 +168,11 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName) | |||
|
167 | 168 | } |
|
168 | 169 | Py_INCREF(&PythonQtSlotFunction_Type); |
|
169 | 170 | |
|
171 | if (PyType_Ready(&PythonQtSignalFunction_Type) < 0) { | |
|
172 | std::cerr << "could not initialize PythonQtSignalFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl; | |
|
173 | } | |
|
174 | Py_INCREF(&PythonQtSignalFunction_Type); | |
|
175 | ||
|
170 | 176 | // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it |
|
171 | 177 | PythonQtClassWrapper_Type.tp_base = &PyType_Type; |
|
172 | 178 | // add our own python object types for classes |
@@ -412,6 +418,20 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name) | |||
|
412 | 418 | if (info) { |
|
413 | 419 | // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull |
|
414 | 420 | ptr = info->castDownIfPossible(ptr, &info); |
|
421 | ||
|
422 | // if downcasting found out that the object is a QObject, | |
|
423 | // handle it like one: | |
|
424 | if (info && info->isQObject()) { | |
|
425 | QObject* qptr = (QObject*)ptr; | |
|
426 | // if the object is a derived object, we want to switch the class info to the one of the derived class: | |
|
427 | if (name!=(qptr->metaObject()->className())) { | |
|
428 | registerClass(qptr->metaObject()); | |
|
429 | info = _knownClassInfos.value(qptr->metaObject()->className()); | |
|
430 | } | |
|
431 | wrap = createNewPythonQtInstanceWrapper(qptr, info); | |
|
432 | // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1()); | |
|
433 | return (PyObject*)wrap; | |
|
434 | } | |
|
415 | 435 | } |
|
416 | 436 | |
|
417 | 437 | if (!info || info->pythonQtClassWrapper()==NULL) { |
@@ -602,7 +622,6 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name) | |||
|
602 | 622 | QStringList l = name.split('.'); |
|
603 | 623 | PythonQtObjectPtr p = module; |
|
604 | 624 | PythonQtObjectPtr prev; |
|
605 | QString s; | |
|
606 | 625 | QByteArray b; |
|
607 | 626 | for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) { |
|
608 | 627 | prev = p; |
@@ -784,97 +803,171 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, | |||
|
784 | 803 | } |
|
785 | 804 | |
|
786 | 805 | if (object) { |
|
787 | if (type == CallOverloads) { | |
|
788 | if (PythonQtSlotFunction_Check(object)) { | |
|
789 | PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object(); | |
|
790 | PythonQtSlotInfo* info = o->m_ml; | |
|
791 | ||
|
792 | while (info) { | |
|
793 | results << info->fullSignature(); | |
|
794 | info = info->nextInfo(); | |
|
795 | } | |
|
796 | } else if (object->ob_type == &PythonQtClassWrapper_Type) { | |
|
797 | PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object(); | |
|
798 | PythonQtSlotInfo* info = o->classInfo()->constructors(); | |
|
806 | results = introspectObject(object, type); | |
|
807 | } | |
|
808 | ||
|
809 | return results; | |
|
810 | } | |
|
799 | 811 | |
|
800 | while (info) { | |
|
801 | results << info->fullSignature(); | |
|
802 | info = info->nextInfo(); | |
|
803 | } | |
|
812 | QStringList PythonQt::introspectObject(PyObject* object, ObjectType type) | |
|
813 | { | |
|
814 | QStringList results; | |
|
815 | ||
|
816 | if (type == CallOverloads) { | |
|
817 | if (PythonQtSlotFunction_Check(object)) { | |
|
818 | PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object; | |
|
819 | PythonQtSlotInfo* info = o->m_ml; | |
|
820 | ||
|
821 | while (info) { | |
|
822 | results << info->fullSignature(); | |
|
823 | info = info->nextInfo(); | |
|
824 | } | |
|
825 | } else if (PythonQtSignalFunction_Check(object)) { | |
|
826 | PythonQtSignalFunctionObject* o = (PythonQtSignalFunctionObject*)object; | |
|
827 | PythonQtSlotInfo* info = o->m_ml; | |
|
828 | ||
|
829 | while (info) { | |
|
830 | results << info->fullSignature(); | |
|
831 | info = info->nextInfo(); | |
|
832 | } | |
|
833 | } else if (object->ob_type == &PythonQtClassWrapper_Type) { | |
|
834 | PythonQtClassWrapper* o = (PythonQtClassWrapper*)object; | |
|
835 | PythonQtSlotInfo* info = o->classInfo()->constructors(); | |
|
836 | ||
|
837 | while (info) { | |
|
838 | results << info->fullSignature(); | |
|
839 | info = info->nextInfo(); | |
|
840 | } | |
|
841 | } else { | |
|
842 | QString signature = _p->getSignature(object); | |
|
843 | if (!signature.isEmpty()) { | |
|
844 | results << signature; | |
|
804 | 845 | } else { |
|
805 | //TODO: use pydoc! | |
|
806 | 846 | PyObject* doc = PyObject_GetAttrString(object, "__doc__"); |
|
807 | 847 | if (doc) { |
|
808 | 848 | results << PyString_AsString(doc); |
|
809 | 849 | Py_DECREF(doc); |
|
810 | 850 | } |
|
811 | 851 | } |
|
852 | } | |
|
853 | } else { | |
|
854 | PyObject* keys = NULL; | |
|
855 | bool isDict = false; | |
|
856 | if (PyDict_Check(object)) { | |
|
857 | keys = PyDict_Keys(object); | |
|
858 | isDict = true; | |
|
812 | 859 | } else { |
|
813 | PyObject* keys = NULL; | |
|
814 | bool isDict = false; | |
|
815 | if (PyDict_Check(object)) { | |
|
816 | keys = PyDict_Keys(object); | |
|
817 | isDict = true; | |
|
818 | } else { | |
|
819 | keys = PyObject_Dir(object); | |
|
820 | } | |
|
821 | if (keys) { | |
|
822 | int count = PyList_Size(keys); | |
|
823 | PyObject* key; | |
|
824 |
|
|
|
825 | QString keystr; | |
|
826 | for (int i = 0;i<count;i++) { | |
|
827 | key = PyList_GetItem(keys,i); | |
|
828 | if (isDict) { | |
|
829 | value = PyDict_GetItem(object, key); | |
|
830 | Py_INCREF(value); | |
|
831 | } else { | |
|
832 | value = PyObject_GetAttr(object, key); | |
|
833 | } | |
|
834 | if (!value) continue; | |
|
835 | keystr = PyString_AsString(key); | |
|
836 | static const QString underscoreStr("__tmp"); | |
|
837 | if (!keystr.startsWith(underscoreStr)) { | |
|
838 | switch (type) { | |
|
839 |
|
|
|
860 | keys = PyObject_Dir(object); | |
|
861 | } | |
|
862 | if (keys) { | |
|
863 | int count = PyList_Size(keys); | |
|
864 | PyObject* key; | |
|
865 | PyObject* value; | |
|
866 | QString keystr; | |
|
867 | for (int i = 0;i<count;i++) { | |
|
868 | key = PyList_GetItem(keys,i); | |
|
869 | if (isDict) { | |
|
870 | value = PyDict_GetItem(object, key); | |
|
871 | Py_INCREF(value); | |
|
872 | } else { | |
|
873 | value = PyObject_GetAttr(object, key); | |
|
874 | } | |
|
875 | if (!value) continue; | |
|
876 | keystr = PyString_AsString(key); | |
|
877 | static const QString underscoreStr("__tmp"); | |
|
878 | if (!keystr.startsWith(underscoreStr)) { | |
|
879 | switch (type) { | |
|
880 | case Anything: | |
|
881 | results << keystr; | |
|
882 | break; | |
|
883 | case Class: | |
|
884 | if (value->ob_type == &PyClass_Type || value->ob_type == &PyType_Type) { | |
|
885 | results << keystr; | |
|
886 | } | |
|
887 | break; | |
|
888 | case Variable: | |
|
889 | if (value->ob_type != &PyClass_Type | |
|
890 | && value->ob_type != &PyCFunction_Type | |
|
891 | && value->ob_type != &PyFunction_Type | |
|
892 | && value->ob_type != &PyMethod_Type | |
|
893 | && value->ob_type != &PyModule_Type | |
|
894 | && value->ob_type != &PyType_Type | |
|
895 | && value->ob_type != &PythonQtSlotFunction_Type | |
|
896 | ) { | |
|
897 | results << keystr; | |
|
898 | } | |
|
899 | break; | |
|
900 | case Function: | |
|
901 | if (value->ob_type == &PyCFunction_Type || | |
|
902 | value->ob_type == &PyFunction_Type || | |
|
903 | value->ob_type == &PyMethod_Type || | |
|
904 | value->ob_type == &PythonQtSlotFunction_Type | |
|
905 | ) { | |
|
840 | 906 | results << keystr; |
|
841 | break; | |
|
842 | case Class: | |
|
843 | if (value->ob_type == &PyClass_Type) { | |
|
844 | results << keystr; | |
|
845 | } | |
|
846 | break; | |
|
847 | case Variable: | |
|
848 | if (value->ob_type != &PyClass_Type | |
|
849 | && value->ob_type != &PyCFunction_Type | |
|
850 | && value->ob_type != &PyFunction_Type | |
|
851 | && value->ob_type != &PyModule_Type | |
|
852 | ) { | |
|
853 | results << keystr; | |
|
854 | } | |
|
855 | break; | |
|
856 | case Function: | |
|
857 | if (value->ob_type == &PyFunction_Type || | |
|
858 | value->ob_type == &PyMethod_Type | |
|
859 | ) { | |
|
860 | results << keystr; | |
|
861 | } | |
|
862 | break; | |
|
863 | case Module: | |
|
864 | if (value->ob_type == &PyModule_Type) { | |
|
865 | results << keystr; | |
|
866 | } | |
|
867 | break; | |
|
868 | default: | |
|
869 | std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl; | |
|
870 | 907 | } |
|
908 | break; | |
|
909 | case Module: | |
|
910 | if (value->ob_type == &PyModule_Type) { | |
|
911 | results << keystr; | |
|
912 | } | |
|
913 | break; | |
|
914 | default: | |
|
915 | std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl; | |
|
871 | 916 | } |
|
872 | Py_DECREF(value); | |
|
873 | 917 | } |
|
874 |
Py_DECREF( |
|
|
918 | Py_DECREF(value); | |
|
875 | 919 | } |
|
920 | Py_DECREF(keys); | |
|
921 | } | |
|
922 | } | |
|
923 | return results; | |
|
924 | } | |
|
925 | ||
|
926 | PyObject* PythonQt::getObjectByType(const QString& typeName) | |
|
927 | { | |
|
928 | PythonQtObjectPtr sys; | |
|
929 | sys.setNewRef(PyImport_ImportModule("sys")); | |
|
930 | PythonQtObjectPtr modules = lookupObject(sys, "modules"); | |
|
931 | Q_ASSERT(PyDict_Check(modules)); | |
|
932 | ||
|
933 | QStringList tmp = typeName.split("."); | |
|
934 | QString simpleTypeName = tmp.takeLast(); | |
|
935 | QString moduleName = tmp.join("."); | |
|
936 | ||
|
937 | PyObject* object = NULL; | |
|
938 | PyObject* moduleObject = PyDict_GetItemString(modules, moduleName.toLatin1().constData()); | |
|
939 | if (moduleObject) { | |
|
940 | object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData()); | |
|
941 | } | |
|
942 | ||
|
943 | if (!object) { | |
|
944 | moduleObject = PyDict_GetItemString(modules, "__builtin__"); | |
|
945 | if (moduleObject) { | |
|
946 | object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData()); | |
|
947 | } | |
|
948 | } | |
|
949 | ||
|
950 | return object; | |
|
951 | } | |
|
952 | ||
|
953 | QStringList PythonQt::introspectType(const QString& typeName, ObjectType type) | |
|
954 | { | |
|
955 | QStringList results; | |
|
956 | PyObject* object = getObjectByType(typeName); | |
|
957 | if (!object) { | |
|
958 | // the last item may be a member, split it away and try again | |
|
959 | QStringList tmp = typeName.split("."); | |
|
960 | QString memberName = tmp.takeLast(); | |
|
961 | QString typeName = tmp.takeLast(); | |
|
962 | PyObject* typeObject = getObjectByType(typeName); | |
|
963 | if (typeObject) { | |
|
964 | object = PyObject_GetAttrString(typeObject, memberName.toLatin1().constData()); | |
|
876 | 965 | } |
|
877 | 966 | } |
|
967 | if (object) { | |
|
968 | results = introspectObject(object, type); | |
|
969 | Py_DECREF(object); | |
|
970 | } | |
|
878 | 971 | return results; |
|
879 | 972 | } |
|
880 | 973 | |
@@ -1190,6 +1283,107 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQ | |||
|
1190 | 1283 | } |
|
1191 | 1284 | } |
|
1192 | 1285 | |
|
1286 | QString PythonQt::getReturnTypeOfWrappedMethod(PyObject* module, const QString& name) | |
|
1287 | { | |
|
1288 | QStringList tmp = name.split("."); | |
|
1289 | QString methodName = tmp.takeLast(); | |
|
1290 | QString variableName = tmp.join("."); | |
|
1291 | // TODO: the variableName may be a type name, this needs to be handled differently, | |
|
1292 | // because it is not necessarily known in the module context | |
|
1293 | PythonQtObjectPtr variableObject = lookupObject(module, variableName); | |
|
1294 | if (variableObject.isNull()) { | |
|
1295 | return ""; | |
|
1296 | } | |
|
1297 | ||
|
1298 | return getReturnTypeOfWrappedMethodHelper(variableObject, methodName, name); | |
|
1299 | } | |
|
1300 | ||
|
1301 | QString PythonQt::getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName) | |
|
1302 | { | |
|
1303 | PythonQtObjectPtr typeObject = getObjectByType(typeName); | |
|
1304 | if (typeObject.isNull()) { | |
|
1305 | return ""; | |
|
1306 | } | |
|
1307 | return getReturnTypeOfWrappedMethodHelper(typeObject, methodName, typeName + "." + methodName); | |
|
1308 | } | |
|
1309 | ||
|
1310 | QString PythonQt::getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context) | |
|
1311 | { | |
|
1312 | PythonQtObjectPtr methodObject; | |
|
1313 | if (PyDict_Check(variableObject)) { | |
|
1314 | methodObject = PyDict_GetItemString(variableObject, methodName.toLatin1().constData()); | |
|
1315 | } else { | |
|
1316 | methodObject.setNewRef(PyObject_GetAttrString(variableObject, methodName.toLatin1().constData())); | |
|
1317 | } | |
|
1318 | if (methodObject.isNull()) { | |
|
1319 | return ""; | |
|
1320 | } | |
|
1321 | ||
|
1322 | QString type; | |
|
1323 | ||
|
1324 | if (methodObject->ob_type == &PyClass_Type || methodObject->ob_type == &PyType_Type) { | |
|
1325 | // the methodObject is not a method, but the name of a type/class. This means | |
|
1326 | // a constructor is called. Return the context. | |
|
1327 | type = context; | |
|
1328 | } else if (methodObject->ob_type == &PythonQtSlotFunction_Type) { | |
|
1329 | QString className; | |
|
1330 | ||
|
1331 | if (PyObject_TypeCheck(variableObject, &PythonQtInstanceWrapper_Type)) { | |
|
1332 | // the type name of wrapped instance is the class name | |
|
1333 | className = variableObject->ob_type->tp_name; | |
|
1334 | } else { | |
|
1335 | PyObject* classNameObject = PyObject_GetAttrString(variableObject, "__name__"); | |
|
1336 | if (classNameObject) { | |
|
1337 | Q_ASSERT(PyString_Check(classNameObject)); | |
|
1338 | className = PyString_AsString(classNameObject); | |
|
1339 | Py_DECREF(classNameObject); | |
|
1340 | } | |
|
1341 | } | |
|
1342 | ||
|
1343 | if (!className.isEmpty()) { | |
|
1344 | PythonQtClassInfo* info = _p->_knownClassInfos.value(className.toLatin1().constData()); | |
|
1345 | if (info) { | |
|
1346 | PythonQtSlotInfo* slotInfo = info->member(methodName.toLatin1().constData())._slot; | |
|
1347 | if (slotInfo) { | |
|
1348 | if (slotInfo->metaMethod()) { | |
|
1349 | type = slotInfo->metaMethod()->typeName(); | |
|
1350 | if (!type.isEmpty()) { | |
|
1351 | QChar c = type.at(type.length()-1); | |
|
1352 | while (c == '*' || c == '&') { | |
|
1353 | type.truncate(type.length()-1); | |
|
1354 | if (!type.isEmpty()) { | |
|
1355 | c = type.at(type.length()-1); | |
|
1356 | } else { | |
|
1357 | break; | |
|
1358 | } | |
|
1359 | } | |
|
1360 | // split away template arguments | |
|
1361 | type = type.split("<").first(); | |
|
1362 | // split away const | |
|
1363 | type = type.split(" ").last().trimmed(); | |
|
1364 | ||
|
1365 | // if the type is a known class info, then create the full type name, i.e. include the | |
|
1366 | // module name. For example, the slot may return a QDate, then this looks up the | |
|
1367 | // name _PythonQt.QtCore.QDate. | |
|
1368 | PythonQtClassInfo* typeInfo = _p->_knownClassInfos.value(type.toLatin1().constData()); | |
|
1369 | if (typeInfo && typeInfo->pythonQtClassWrapper()) { | |
|
1370 | PyObject* s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__module__"); | |
|
1371 | Q_ASSERT(PyString_Check(s)); | |
|
1372 | type = QString(PyString_AsString(s)) + "." + type; | |
|
1373 | Py_DECREF(s); | |
|
1374 | s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__name__"); | |
|
1375 | Q_ASSERT(PyString_Check(s)); | |
|
1376 | Py_DECREF(s); | |
|
1377 | } | |
|
1378 | } | |
|
1379 | } | |
|
1380 | } | |
|
1381 | } | |
|
1382 | } | |
|
1383 | } | |
|
1384 | return type; | |
|
1385 | } | |
|
1386 | ||
|
1193 | 1387 | void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell) |
|
1194 | 1388 | { |
|
1195 | 1389 | _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell); |
@@ -1349,4 +1543,150 void* PythonQtPrivate::unwrapForeignWrapper( const QByteArray& classname, PyObje | |||
|
1349 | 1543 | } |
|
1350 | 1544 | } |
|
1351 | 1545 | return NULL; |
|
1352 | } No newline at end of file | |
|
1546 | } | |
|
1547 | ||
|
1548 | bool PythonQtPrivate::isMethodDescriptor(PyObject* object) const | |
|
1549 | { | |
|
1550 | // This implementation is the same as in inspect.ismethoddescriptor(), inspect.py. | |
|
1551 | if (PyObject_HasAttrString(object, "__get__") && | |
|
1552 | !PyObject_HasAttrString(object, "__set__") && | |
|
1553 | !PyMethod_Check(object) && | |
|
1554 | !PyFunction_Check(object) && | |
|
1555 | !PyClass_Check(object)) { | |
|
1556 | return true; | |
|
1557 | } | |
|
1558 | return false; | |
|
1559 | } | |
|
1560 | ||
|
1561 | QString PythonQtPrivate::getSignature(PyObject* object) | |
|
1562 | { | |
|
1563 | QString signature; | |
|
1564 | ||
|
1565 | if (object) { | |
|
1566 | PyMethodObject* method = NULL; | |
|
1567 | PyFunctionObject* func = NULL; | |
|
1568 | ||
|
1569 | bool decrefMethod = false; | |
|
1570 | ||
|
1571 | if (object->ob_type == &PyClass_Type || object->ob_type == &PyType_Type) { | |
|
1572 | method = (PyMethodObject*)PyObject_GetAttrString(object, "__init__"); | |
|
1573 | decrefMethod = true; | |
|
1574 | } else if (object->ob_type == &PyFunction_Type) { | |
|
1575 | func = (PyFunctionObject*)object; | |
|
1576 | } else if (object->ob_type == &PyMethod_Type) { | |
|
1577 | method = (PyMethodObject*)object; | |
|
1578 | } | |
|
1579 | if (method) { | |
|
1580 | if (PyFunction_Check(method->im_func)) { | |
|
1581 | func = (PyFunctionObject*)method->im_func; | |
|
1582 | } else if (isMethodDescriptor((PyObject*)method)) { | |
|
1583 | QString docstr; | |
|
1584 | PyObject* doc = PyObject_GetAttrString(object, "__doc__"); | |
|
1585 | if (doc) { | |
|
1586 | docstr = PyString_AsString(doc); | |
|
1587 | Py_DECREF(doc); | |
|
1588 | } | |
|
1589 | ||
|
1590 | PyObject* s = PyObject_GetAttrString(object, "__name__"); | |
|
1591 | if (s) { | |
|
1592 | Q_ASSERT(PyString_Check(s)); | |
|
1593 | signature = PyString_AsString(s); | |
|
1594 | if (docstr.startsWith(signature + "(")) { | |
|
1595 | signature = docstr; | |
|
1596 | } else { | |
|
1597 | signature += "(...)"; | |
|
1598 | if (!docstr.isEmpty()) { | |
|
1599 | signature += "\n\n" + docstr; | |
|
1600 | } | |
|
1601 | } | |
|
1602 | Py_DECREF(s); | |
|
1603 | } | |
|
1604 | } | |
|
1605 | } | |
|
1606 | ||
|
1607 | if (func) { | |
|
1608 | QString funcName; | |
|
1609 | PyObject* s = PyObject_GetAttrString((PyObject*)func, "__name__"); | |
|
1610 | if (s) { | |
|
1611 | Q_ASSERT(PyString_Check(s)); | |
|
1612 | funcName = PyString_AsString(s); | |
|
1613 | Py_DECREF(s); | |
|
1614 | } | |
|
1615 | if (method && funcName == "__init__") { | |
|
1616 | PyObject* s = PyObject_GetAttrString(object, "__name__"); | |
|
1617 | if (s) { | |
|
1618 | Q_ASSERT(PyString_Check(s)); | |
|
1619 | funcName = PyString_AsString(s); | |
|
1620 | Py_DECREF(s); | |
|
1621 | } | |
|
1622 | } | |
|
1623 | ||
|
1624 | QStringList arguments; | |
|
1625 | QStringList defaults; | |
|
1626 | QString varargs; | |
|
1627 | QString varkeywords; | |
|
1628 | // NOTE: This implementation is based on function getargs() in inspect.py. | |
|
1629 | // inspect.getargs() can handle anonymous (tuple) arguments, while this code does not. | |
|
1630 | // It can be implemented, but it may be rarely needed and not necessary. | |
|
1631 | PyCodeObject* code = (PyCodeObject*)func->func_code; | |
|
1632 | if (code->co_varnames) { | |
|
1633 | int nargs = code->co_argcount; | |
|
1634 | Q_ASSERT(PyTuple_Check(code->co_varnames)); | |
|
1635 | for (int i=0; i<nargs; i++) { | |
|
1636 | PyObject* name = PyTuple_GetItem(code->co_varnames, i); | |
|
1637 | Q_ASSERT(PyString_Check(name)); | |
|
1638 | arguments << PyString_AsString(name); | |
|
1639 | } | |
|
1640 | if (code->co_flags & CO_VARARGS) { | |
|
1641 | PyObject* s = PyTuple_GetItem(code->co_varnames, nargs); | |
|
1642 | Q_ASSERT(PyString_Check(s)); | |
|
1643 | varargs = PyString_AsString(s); | |
|
1644 | nargs += 1; | |
|
1645 | } | |
|
1646 | if (code->co_flags & CO_VARKEYWORDS) { | |
|
1647 | PyObject* s = PyTuple_GetItem(code->co_varnames, nargs); | |
|
1648 | Q_ASSERT(PyString_Check(s)); | |
|
1649 | varkeywords = PyString_AsString(s); | |
|
1650 | } | |
|
1651 | } | |
|
1652 | ||
|
1653 | PyObject* defaultsTuple = func->func_defaults; | |
|
1654 | if (defaultsTuple) { | |
|
1655 | Q_ASSERT(PyTuple_Check(defaultsTuple)); | |
|
1656 | for (Py_ssize_t i=0; i<PyTuple_Size(defaultsTuple); i++) { | |
|
1657 | PyObject* d = PyTuple_GetItem(defaultsTuple, i); | |
|
1658 | PyObject* s = PyObject_Repr(d); | |
|
1659 | Q_ASSERT(PyString_Check(s)); | |
|
1660 | defaults << PyString_AsString(s); | |
|
1661 | Py_DECREF(s); | |
|
1662 | } | |
|
1663 | } | |
|
1664 | ||
|
1665 | int firstdefault = arguments.size() - defaults.size(); | |
|
1666 | for (int i=0; i<arguments.size(); i++) { | |
|
1667 | if (!signature.isEmpty()) { signature += ", "; } | |
|
1668 | if (!method || i>0 || arguments[i] != "self") { | |
|
1669 | signature += arguments[i]; | |
|
1670 | if (i >= firstdefault) { | |
|
1671 | signature += "=" + defaults[i-firstdefault]; | |
|
1672 | } | |
|
1673 | } | |
|
1674 | } | |
|
1675 | if (!varargs.isEmpty()) { | |
|
1676 | if (!signature.isEmpty()) { signature += ", "; } | |
|
1677 | signature += "*" + varargs; | |
|
1678 | } | |
|
1679 | if (!varkeywords.isEmpty()) { | |
|
1680 | if (!signature.isEmpty()) { signature += ", "; } | |
|
1681 | signature += "**" + varkeywords; | |
|
1682 | } | |
|
1683 | signature = funcName + "(" + signature + ")"; | |
|
1684 | } | |
|
1685 | ||
|
1686 | if (method && decrefMethod) { | |
|
1687 | Py_DECREF(method); | |
|
1688 | } | |
|
1689 | } | |
|
1690 | ||
|
1691 | return signature; | |
|
1692 | } |
@@ -333,11 +333,22 public: | |||
|
333 | 333 | |
|
334 | 334 | //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname |
|
335 | 335 | QStringList introspection(PyObject* object, const QString& objectname, ObjectType type); |
|
336 | //! read vars etc. in scope of the given \c object | |
|
337 | QStringList introspectObject(PyObject* object, ObjectType type); | |
|
338 | //! read vars etc. in scope of the type object called \c typename. First the typename | |
|
339 | //! of the form module.type is split into module and type. Then the module is looked up | |
|
340 | //! in sys.modules. If the module or type is not found there, then the type is looked up in | |
|
341 | //! the __builtin__ module. | |
|
342 | QStringList introspectType(const QString& typeName, ObjectType type); | |
|
336 | 343 | |
|
337 | 344 | //! returns the found callable object or NULL |
|
338 | 345 | //! @return new reference |
|
339 | 346 | PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name); |
|
340 | ||
|
347 | ||
|
348 | //! returns the return type of the method of a wrapped c++ object referenced by \c objectname | |
|
349 | QString getReturnTypeOfWrappedMethod(PyObject* module, const QString& objectname); | |
|
350 | //! returns the return type of the method \c methodName of a wrapped c++ type referenced by \c typeName | |
|
351 | QString getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName); | |
|
341 | 352 | //@} |
|
342 | 353 | |
|
343 | 354 | //--------------------------------------------------------------------------- |
@@ -501,6 +512,10 signals: | |||
|
501 | 512 | |
|
502 | 513 | private: |
|
503 | 514 | void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName); |
|
515 | ||
|
516 | QString getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context); | |
|
517 | ||
|
518 | PyObject* getObjectByType(const QString& typeName); | |
|
504 | 519 | |
|
505 | 520 | //! callback for stdout redirection, emits pythonStdOut signal |
|
506 | 521 | static void stdOutRedirectCB(const QString& str); |
@@ -626,6 +641,12 public: | |||
|
626 | 641 | |
|
627 | 642 | //! returns the profiling callback, which may be NULL |
|
628 | 643 | PythonQt::ProfilingCB* profilingCB() const { return _profilingCB; } |
|
644 | ||
|
645 | //! determines the signature of the given callable object (similar as pydoc) | |
|
646 | QString getSignature(PyObject* object); | |
|
647 | ||
|
648 | //! returns true if the object is a method descriptor (same as inspect.ismethoddescriptor() in inspect.py) | |
|
649 | bool isMethodDescriptor(PyObject* object) const; | |
|
629 | 650 | |
|
630 | 651 | private: |
|
631 | 652 | //! Setup the shared library suffixes by getting them from the "imp" module. |
@@ -96,7 +96,7 void PythonQtClassInfo::clearCachedMembers() | |||
|
96 | 96 | QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers); |
|
97 | 97 | while (i.hasNext()) { |
|
98 | 98 | PythonQtMemberInfo member = i.next().value(); |
|
99 | if (member._type== PythonQtMemberInfo::Slot) { | |
|
99 | if (member._type== PythonQtMemberInfo::Slot || member._type== PythonQtMemberInfo::Signal) { | |
|
100 | 100 | PythonQtSlotInfo* info = member._slot; |
|
101 | 101 | while (info) { |
|
102 | 102 | PythonQtSlotInfo* next = info->nextInfo(); |
@@ -462,18 +462,14 QStringList PythonQtClassInfo::propertyList() | |||
|
462 | 462 | return l; |
|
463 | 463 | } |
|
464 | 464 | |
|
465 |
QStringList PythonQtClassInfo::memberList( |
|
|
465 | QStringList PythonQtClassInfo::memberList() | |
|
466 | 466 | { |
|
467 | 467 | decorator(); |
|
468 | 468 | |
|
469 | 469 | QStringList l; |
|
470 | 470 | QString h; |
|
471 | if (_isQObject && _meta && !metaOnly) { | |
|
472 | l = propertyList(); | |
|
473 | } | |
|
474 | ||
|
475 | 471 | // normal slots of QObject (or wrapper QObject) |
|
476 |
if ( |
|
|
472 | if (_meta) { | |
|
477 | 473 | int numMethods = _meta->methodCount(); |
|
478 | 474 | bool skipQObj = !_isQObject; |
|
479 | 475 | for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) { |
@@ -493,7 +489,7 QStringList PythonQtClassInfo::memberList(bool metaOnly) | |||
|
493 | 489 | QList<PythonQtClassInfo*> infos; |
|
494 | 490 | recursiveCollectClassInfos(infos); |
|
495 | 491 | foreach(PythonQtClassInfo* info, infos) { |
|
496 |
info->listDecoratorSlotsFromDecoratorProvider(l, |
|
|
492 | info->listDecoratorSlotsFromDecoratorProvider(l, false); | |
|
497 | 493 | } |
|
498 | 494 | } |
|
499 | 495 | |
@@ -866,3 +862,33 void PythonQtClassInfo::clearNotFoundCachedMembers() | |||
|
866 | 862 | } |
|
867 | 863 | } |
|
868 | 864 | } |
|
865 | ||
|
866 | //------------------------------------------------------------------------- | |
|
867 | ||
|
868 | PythonQtMemberInfo::PythonQtMemberInfo( PythonQtSlotInfo* info ) | |
|
869 | { | |
|
870 | if (info->metaMethod()->methodType() == QMetaMethod::Signal) { | |
|
871 | _type = Signal; | |
|
872 | } else { | |
|
873 | _type = Slot; | |
|
874 | } | |
|
875 | _slot = info; | |
|
876 | _enumValue = NULL; | |
|
877 | } | |
|
878 | ||
|
879 | PythonQtMemberInfo::PythonQtMemberInfo( const PythonQtObjectPtr& enumValue ) | |
|
880 | { | |
|
881 | _type = EnumValue; | |
|
882 | _slot = NULL; | |
|
883 | _enumValue = enumValue; | |
|
884 | _enumWrapper = NULL; | |
|
885 | } | |
|
886 | ||
|
887 | PythonQtMemberInfo::PythonQtMemberInfo( const QMetaProperty& prop ) | |
|
888 | { | |
|
889 | _type = Property; | |
|
890 | _slot = NULL; | |
|
891 | _enumValue = NULL; | |
|
892 | _property = prop; | |
|
893 | _enumWrapper = NULL; | |
|
894 | } No newline at end of file |
@@ -44,31 +44,16 class PythonQtSlotInfo; | |||
|
44 | 44 | |
|
45 | 45 | struct PythonQtMemberInfo { |
|
46 | 46 | enum Type { |
|
47 | Invalid, Slot, EnumValue, EnumWrapper, Property, NotFound | |
|
47 | Invalid, Slot, Signal, EnumValue, EnumWrapper, Property, NotFound | |
|
48 | 48 | }; |
|
49 | 49 | |
|
50 | 50 | PythonQtMemberInfo():_type(Invalid),_slot(NULL),_enumWrapper(NULL),_enumValue(0) { } |
|
51 | 51 | |
|
52 |
PythonQtMemberInfo(PythonQtSlotInfo* info) |
|
|
53 | _type = Slot; | |
|
54 | _slot = info; | |
|
55 | _enumValue = NULL; | |
|
56 | } | |
|
52 | PythonQtMemberInfo(PythonQtSlotInfo* info); | |
|
57 | 53 | |
|
58 |
PythonQtMemberInfo(const PythonQtObjectPtr& enumValue) |
|
|
59 | _type = EnumValue; | |
|
60 | _slot = NULL; | |
|
61 | _enumValue = enumValue; | |
|
62 | _enumWrapper = NULL; | |
|
63 | } | |
|
54 | PythonQtMemberInfo(const PythonQtObjectPtr& enumValue); | |
|
64 | 55 | |
|
65 |
PythonQtMemberInfo(const QMetaProperty& prop) |
|
|
66 | _type = Property; | |
|
67 | _slot = NULL; | |
|
68 | _enumValue = NULL; | |
|
69 | _property = prop; | |
|
70 | _enumWrapper = NULL; | |
|
71 | } | |
|
56 | PythonQtMemberInfo(const QMetaProperty& prop); | |
|
72 | 57 | |
|
73 | 58 | Type _type; |
|
74 | 59 | |
@@ -159,8 +144,8 public: | |||
|
159 | 144 | //! get list of all properties (on QObjects only, otherwise the list is empty) |
|
160 | 145 | QStringList propertyList(); |
|
161 | 146 | |
|
162 | //! get list of all members | |
|
163 |
QStringList memberList( |
|
|
147 | //! get list of all members (excluding properties, which can be listed with propertyList()) | |
|
148 | QStringList memberList(); | |
|
164 | 149 | |
|
165 | 150 | //! get the meta type id of this class (only valid for isCPPWrapper() == true) |
|
166 | 151 | int metaTypeId() { return _metaTypeId; } |
@@ -44,6 +44,7 | |||
|
44 | 44 | |
|
45 | 45 | #include "PythonQt.h" |
|
46 | 46 | #include "PythonQtSlot.h" |
|
47 | #include "PythonQtSignal.h" | |
|
47 | 48 | #include "PythonQtClassInfo.h" |
|
48 | 49 | #include "PythonQtConversion.h" |
|
49 | 50 | #include "PythonQtInstanceWrapper.h" |
@@ -291,40 +292,8 PyObject *PythonQtClassWrapper_inherits(PythonQtClassWrapper *type, PyObject *ar | |||
|
291 | 292 | return PythonQtConv::GetPyBool(wrapper->classInfo()->inherits(name)); |
|
292 | 293 | } |
|
293 | 294 | |
|
294 | PyObject *PythonQtClassWrapper__init__(PythonQtClassWrapper *type, PyObject *args) | |
|
295 | { | |
|
296 | Py_ssize_t argc = PyTuple_Size(args); | |
|
297 | if (argc>0) { | |
|
298 | // we need to call __init__ of the instance | |
|
299 | PyObject* self = PyTuple_GET_ITEM(args, 0); | |
|
300 | if (PyObject_TypeCheck(self, (PyTypeObject*)type->classInfo()->pythonQtClassWrapper())) { | |
|
301 | PyObject* newargs = PyTuple_New(argc-1); | |
|
302 | for (int i = 0;i<argc-1; i++) { | |
|
303 | PyTuple_SET_ITEM(newargs, i,PyTuple_GET_ITEM(args, i+1)); | |
|
304 | } | |
|
305 | PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)self; | |
|
306 | int result = PythonQtInstanceWrapper_init(wrapper, newargs, NULL); | |
|
307 | Py_DECREF(newargs); | |
|
308 | if (result==0) { | |
|
309 | Py_INCREF(Py_None); | |
|
310 | return Py_None; | |
|
311 | } else { | |
|
312 | // init failed! | |
|
313 | } | |
|
314 | } else { | |
|
315 | // self not of correct type! | |
|
316 | } | |
|
317 | } else { | |
|
318 | // wrong number of args | |
|
319 | } | |
|
320 | return NULL; | |
|
321 | } | |
|
322 | ||
|
323 | 295 | |
|
324 | 296 | static PyMethodDef PythonQtClassWrapper_methods[] = { |
|
325 | {"__init__", (PyCFunction)PythonQtClassWrapper__init__, METH_VARARGS, | |
|
326 | "Init function" | |
|
327 | }, | |
|
328 | 297 | {"className", (PyCFunction)PythonQtClassWrapper_classname, METH_NOARGS, |
|
329 | 298 | "Return the classname of the object" |
|
330 | 299 | }, |
@@ -354,14 +323,14 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) | |||
|
354 | 323 | } |
|
355 | 324 | |
|
356 | 325 | if (qstrcmp(attributeName, "__dict__")==0) { |
|
357 |
PyObject* |
|
|
326 | PyObject* objectDict = ((PyTypeObject *)wrapper)->tp_dict; | |
|
358 | 327 | if (!wrapper->classInfo()) { |
|
359 |
Py_INCREF( |
|
|
360 |
return |
|
|
328 | Py_INCREF(objectDict); | |
|
329 | return objectDict; | |
|
361 | 330 | } |
|
362 |
dict = PyDict_ |
|
|
363 | ||
|
364 |
|
|
|
331 | PyObject* dict = PyDict_New(); | |
|
332 | ||
|
333 | QStringList l = wrapper->classInfo()->memberList(); | |
|
365 | 334 | foreach (QString name, l) { |
|
366 | 335 | PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data()); |
|
367 | 336 | if (o) { |
@@ -369,21 +338,33 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) | |||
|
369 | 338 | Py_DECREF(o); |
|
370 | 339 | } else { |
|
371 | 340 | // it must have been a property or child, which we do not know as a class object... |
|
341 | PyErr_Clear(); | |
|
372 | 342 | } |
|
373 | 343 | } |
|
374 | 344 | if (wrapper->classInfo()->constructors()) { |
|
375 | PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[0], obj); | |
|
345 | PyObject* initName = PyString_FromString("__init__"); | |
|
346 | PyObject* func = PyType_Type.tp_getattro(obj, initName); | |
|
347 | Py_DECREF(initName); | |
|
376 | 348 | PyDict_SetItemString(dict, "__init__", func); |
|
377 | 349 | Py_DECREF(func); |
|
378 | 350 | } |
|
379 |
for (int i = |
|
|
351 | for (int i = 0; PythonQtClassWrapper_methods[i].ml_name != NULL; i++) { | |
|
380 | 352 | PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[i], obj); |
|
381 | 353 | PyDict_SetItemString(dict, PythonQtClassWrapper_methods[i].ml_name, func); |
|
382 | 354 | Py_DECREF(func); |
|
383 | 355 | } |
|
356 | ||
|
357 | PyDict_Update(dict, objectDict); | |
|
384 | 358 | return dict; |
|
385 | 359 | } |
|
386 | 360 | |
|
361 | // look in Python to support derived Python classes | |
|
362 | PyObject* superAttr = PyType_Type.tp_getattro(obj, name); | |
|
363 | if (superAttr) { | |
|
364 | return superAttr; | |
|
365 | } | |
|
366 | PyErr_Clear(); | |
|
367 | ||
|
387 | 368 | if (wrapper->classInfo()) { |
|
388 | 369 | PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName); |
|
389 | 370 | if (member._type == PythonQtMemberInfo::EnumValue) { |
@@ -397,21 +378,17 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) | |||
|
397 | 378 | } else if (member._type == PythonQtMemberInfo::Slot) { |
|
398 | 379 | // we return all slots, even the instance slots, since they are callable as unbound slots with self argument |
|
399 | 380 | return PythonQtSlotFunction_New(member._slot, obj, NULL); |
|
381 | } else if (member._type == PythonQtMemberInfo::Signal) { | |
|
382 | // we return all signals, even the instance signals, since they are callable as unbound signals with self argument | |
|
383 | return PythonQtSignalFunction_New(member._slot, obj, NULL); | |
|
400 | 384 | } |
|
401 | 385 | } |
|
402 | 386 | |
|
403 | // look for the interal methods (className(), help()) | |
|
387 | // look for the internal methods (className(), help()) | |
|
404 | 388 | PyObject* internalMethod = Py_FindMethod( PythonQtClassWrapper_methods, obj, (char*)attributeName); |
|
405 | 389 | if (internalMethod) { |
|
406 | 390 | return internalMethod; |
|
407 | 391 | } |
|
408 | PyErr_Clear(); | |
|
409 | ||
|
410 | // look in super | |
|
411 | PyObject* superAttr = PyType_Type.tp_getattro(obj, name); | |
|
412 | if (superAttr) { | |
|
413 | return superAttr; | |
|
414 | } | |
|
415 | 392 | |
|
416 | 393 | QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'"; |
|
417 | 394 | PyErr_SetString(PyExc_AttributeError, error.toLatin1().data()); |
@@ -70,6 +70,11 public: | |||
|
70 | 70 | //! indicates that *.py files which are newer than their corresponding *.pyc files |
|
71 | 71 | //! are ignored |
|
72 | 72 | virtual bool ignoreUpdatedPythonSourceFiles() { return false; } |
|
73 | ||
|
74 | //! called by PythonQt after successful import to allow | |
|
75 | //! recording of imports | |
|
76 | virtual void importedModule(const QString& /*module*/) {}; | |
|
77 | ||
|
73 | 78 | }; |
|
74 | 79 | |
|
75 | 80 | #endif |
@@ -255,7 +255,13 PythonQtImporter_load_module(PyObject *obj, PyObject *args) | |||
|
255 | 255 | return NULL; |
|
256 | 256 | } |
|
257 | 257 | } |
|
258 | ||
|
258 | 259 | mod = PyImport_ExecCodeModuleEx(fullname, code, fullPath.toLatin1().data()); |
|
260 | ||
|
261 | if (PythonQt::importInterface()) { | |
|
262 | PythonQt::importInterface()->importedModule(fullname); | |
|
263 | } | |
|
264 | ||
|
259 | 265 | Py_DECREF(code); |
|
260 | 266 | if (Py_VerboseFlag) { |
|
261 | 267 | PySys_WriteStderr("import %s # loaded from %s\n", |
@@ -43,6 +43,7 | |||
|
43 | 43 | #include <QObject> |
|
44 | 44 | #include "PythonQt.h" |
|
45 | 45 | #include "PythonQtSlot.h" |
|
46 | #include "PythonQtSignal.h" | |
|
46 | 47 | #include "PythonQtClassInfo.h" |
|
47 | 48 | #include "PythonQtConversion.h" |
|
48 | 49 | #include "PythonQtClassWrapper.h" |
@@ -413,6 +414,9 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) | |||
|
413 | 414 | case PythonQtMemberInfo::Slot: |
|
414 | 415 | return PythonQtSlotFunction_New(member._slot, obj, NULL); |
|
415 | 416 | break; |
|
417 | case PythonQtMemberInfo::Signal: | |
|
418 | return PythonQtSignalFunction_New(member._slot, obj, NULL); | |
|
419 | break; | |
|
416 | 420 | case PythonQtMemberInfo::EnumValue: |
|
417 | 421 | { |
|
418 | 422 | PyObject* enumValue = member._enumValue; |
@@ -529,6 +533,8 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObjec | |||
|
529 | 533 | } |
|
530 | 534 | } else if (member._type == PythonQtMemberInfo::Slot) { |
|
531 | 535 | error = QString("Slot '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object"; |
|
536 | } else if (member._type == PythonQtMemberInfo::Signal) { | |
|
537 | error = QString("Signal '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object"; | |
|
532 | 538 | } else if (member._type == PythonQtMemberInfo::EnumValue) { |
|
533 | 539 | error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object"; |
|
534 | 540 | } else if (member._type == PythonQtMemberInfo::EnumWrapper) { |
@@ -590,14 +596,16 static QString getStringFromObject(PythonQtInstanceWrapper* wrapper) { | |||
|
590 | 596 | return result; |
|
591 | 597 | } |
|
592 | 598 | } |
|
593 | // next, try to call py_toString | |
|
594 | PythonQtMemberInfo info = wrapper->classInfo()->member("py_toString"); | |
|
595 | if (info._type == PythonQtMemberInfo::Slot) { | |
|
596 | PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, NULL, NULL, wrapper->_wrappedPtr); | |
|
597 | if (resultObj) { | |
|
598 | // TODO this is one conversion too much, would be nicer to call the slot directly... | |
|
599 | result = PythonQtConv::PyObjGetString(resultObj); | |
|
600 | Py_DECREF(resultObj); | |
|
599 | if (wrapper->_wrappedPtr || wrapper->_obj) { | |
|
600 | // next, try to call py_toString | |
|
601 | PythonQtMemberInfo info = wrapper->classInfo()->member("py_toString"); | |
|
602 | if (info._type == PythonQtMemberInfo::Slot) { | |
|
603 | PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, NULL, NULL, wrapper->_wrappedPtr); | |
|
604 | if (resultObj) { | |
|
605 | // TODO this is one conversion too much, would be nicer to call the slot directly... | |
|
606 | result = PythonQtConv::PyObjGetString(resultObj); | |
|
607 | Py_DECREF(resultObj); | |
|
608 | } | |
|
601 | 609 | } |
|
602 | 610 | } |
|
603 | 611 | return result; |
@@ -99,7 +99,9 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromArgumentLis | |||
|
99 | 99 | if (i>1) { |
|
100 | 100 | fullSig += ","; |
|
101 | 101 | } |
|
102 |
|
|
|
102 | QByteArray arg(args[i]); | |
|
103 | fullSig += arg; | |
|
104 | arguments << arg; | |
|
103 | 105 | } |
|
104 | 106 | fullSig += ")"; |
|
105 | 107 | PythonQtMethodInfo* result = _cachedSignatures.value(fullSig); |
@@ -66,7 +66,7 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInf | |||
|
66 | 66 | PyObject* o = callable; |
|
67 | 67 | PyFunctionObject* func = (PyFunctionObject*)o; |
|
68 | 68 | PyCodeObject* code = (PyCodeObject*)func->func_code; |
|
69 |
if (!(code->co_flags & |
|
|
69 | if (!(code->co_flags & CO_VARARGS)) { | |
|
70 | 70 | numPythonArgs = code->co_argcount; |
|
71 | 71 | } else { |
|
72 | 72 | // variable numbers of arguments allowed |
@@ -77,7 +77,7 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInf | |||
|
77 | 77 | if (PyFunction_Check(method->im_func)) { |
|
78 | 78 | PyFunctionObject* func = (PyFunctionObject*)method->im_func; |
|
79 | 79 | PyCodeObject* code = (PyCodeObject*)func->func_code; |
|
80 |
if (!(code->co_flags & |
|
|
80 | if (!(code->co_flags & CO_VARARGS)) { | |
|
81 | 81 | numPythonArgs = code->co_argcount - 1; // we subtract one because the first is "self" |
|
82 | 82 | } else { |
|
83 | 83 | // variable numbers of arguments allowed |
@@ -187,11 +187,20 bool PythonQtSignalReceiver::removeSignalHandler(const char* signal, PyObject* c | |||
|
187 | 187 | int sigId = getSignalIndex(signal); |
|
188 | 188 | if (sigId>=0) { |
|
189 | 189 | QMutableListIterator<PythonQtSignalTarget> i(_targets); |
|
190 | while (i.hasNext()) { | |
|
191 | if (i.next().isSame(sigId, callable)) { | |
|
192 | i.remove(); | |
|
193 | found = true; | |
|
194 | break; | |
|
190 | if (callable) { | |
|
191 | while (i.hasNext()) { | |
|
192 | if (i.next().isSame(sigId, callable)) { | |
|
193 | i.remove(); | |
|
194 | found = true; | |
|
195 | break; | |
|
196 | } | |
|
197 | } | |
|
198 | } else { | |
|
199 | while (i.hasNext()) { | |
|
200 | if (i.next().signalId() == sigId) { | |
|
201 | i.remove(); | |
|
202 | found = true; | |
|
203 | } | |
|
195 | 204 | } |
|
196 | 205 | } |
|
197 | 206 | } |
@@ -118,8 +118,8 public: | |||
|
118 | 118 | //! add a signal handler |
|
119 | 119 | bool addSignalHandler(const char* signal, PyObject* callable); |
|
120 | 120 | |
|
121 | //! remove a signal handler | |
|
122 | bool removeSignalHandler(const char* signal, PyObject* callable); | |
|
121 | //! remove a signal handler for given callable (or all callables on that signal if callable is NULL) | |
|
122 | bool removeSignalHandler(const char* signal, PyObject* callable = NULL); | |
|
123 | 123 | |
|
124 | 124 | //! remove all signal handlers |
|
125 | 125 | void removeSignalHandlers(); |
@@ -140,3 +140,4 private: | |||
|
140 | 140 | |
|
141 | 141 | |
|
142 | 142 | #endif |
|
143 |
@@ -50,6 +50,8 | |||
|
50 | 50 | #include <exception> |
|
51 | 51 | #include <stdexcept> |
|
52 | 52 | |
|
53 | #include <QByteArray> | |
|
54 | ||
|
53 | 55 | #define PYTHONQT_MAX_ARGS 32 |
|
54 | 56 | |
|
55 | 57 | |
@@ -160,28 +162,34 bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj | |||
|
160 | 162 | |
|
161 | 163 | // invoke the slot via metacall |
|
162 | 164 | bool hadException = false; |
|
163 | try { | |
|
164 | (info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList); | |
|
165 | } catch (std::bad_alloc & e) { | |
|
166 | hadException = true; | |
|
167 | QByteArray what("std::bad_alloc: "); | |
|
168 | what += e.what(); | |
|
169 | PyErr_SetString(PyExc_MemoryError, what.constData()); | |
|
170 | } catch (std::runtime_error & e) { | |
|
171 | hadException = true; | |
|
172 | QByteArray what("std::runtime_error: "); | |
|
173 | what += e.what(); | |
|
174 | PyErr_SetString(PyExc_RuntimeError, what.constData()); | |
|
175 | } catch (std::logic_error & e) { | |
|
165 | QObject* obj = info->decorator()?info->decorator():objectToCall; | |
|
166 | if (!obj) { | |
|
176 | 167 | hadException = true; |
|
177 | QByteArray what("std::logic_error: "); | |
|
178 | what += e.what(); | |
|
179 | PyErr_SetString(PyExc_RuntimeError, what.constData()); | |
|
180 | } catch (std::exception& e) { | |
|
181 | hadException = true; | |
|
182 | QByteArray what("std::exception: "); | |
|
183 | what += e.what(); | |
|
184 | PyErr_SetString(PyExc_StandardError, what.constData()); | |
|
168 | PyErr_SetString(PyExc_RuntimeError, "Trying to call a slot on a deleted QObject!"); | |
|
169 | } else { | |
|
170 | try { | |
|
171 | obj->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList); | |
|
172 | } catch (std::bad_alloc & e) { | |
|
173 | hadException = true; | |
|
174 | QByteArray what("std::bad_alloc: "); | |
|
175 | what += e.what(); | |
|
176 | PyErr_SetString(PyExc_MemoryError, what.constData()); | |
|
177 | } catch (std::runtime_error & e) { | |
|
178 | hadException = true; | |
|
179 | QByteArray what("std::runtime_error: "); | |
|
180 | what += e.what(); | |
|
181 | PyErr_SetString(PyExc_RuntimeError, what.constData()); | |
|
182 | } catch (std::logic_error & e) { | |
|
183 | hadException = true; | |
|
184 | QByteArray what("std::logic_error: "); | |
|
185 | what += e.what(); | |
|
186 | PyErr_SetString(PyExc_RuntimeError, what.constData()); | |
|
187 | } catch (std::exception& e) { | |
|
188 | hadException = true; | |
|
189 | QByteArray what("std::exception: "); | |
|
190 | what += e.what(); | |
|
191 | PyErr_SetString(PyExc_StandardError, what.constData()); | |
|
192 | } | |
|
185 | 193 | } |
|
186 | 194 | |
|
187 | 195 | if (profilingCB) { |
@@ -227,18 +235,22 static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL; | |||
|
227 | 235 | PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw) |
|
228 | 236 | { |
|
229 | 237 | PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func; |
|
230 | PythonQtSlotInfo* info = f->m_ml; | |
|
231 | if (PyObject_TypeCheck(f->m_self, &PythonQtInstanceWrapper_Type)) { | |
|
232 | PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self; | |
|
238 | return PythonQtMemberFunction_Call(f->m_ml, f->m_self, args, kw); | |
|
239 | } | |
|
240 | ||
|
241 | PyObject *PythonQtMemberFunction_Call(PythonQtSlotInfo* info, PyObject* m_self, PyObject *args, PyObject *kw) | |
|
242 | { | |
|
243 | if (PyObject_TypeCheck(m_self, &PythonQtInstanceWrapper_Type)) { | |
|
244 | PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) m_self; | |
|
233 | 245 | if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) { |
|
234 |
QString error = QString("Trying to call '") + |
|
|
246 | QString error = QString("Trying to call '") + info->slotName() + "' on a destroyed " + self->classInfo()->className() + " object"; | |
|
235 | 247 | PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); |
|
236 | 248 | return NULL; |
|
237 | 249 | } else { |
|
238 | 250 | return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr); |
|
239 | 251 | } |
|
240 |
} else if ( |
|
|
241 |
PythonQtClassWrapper* type = (PythonQtClassWrapper*) |
|
|
252 | } else if (m_self->ob_type == &PythonQtClassWrapper_Type) { | |
|
253 | PythonQtClassWrapper* type = (PythonQtClassWrapper*) m_self; | |
|
242 | 254 | if (info->isClassDecorator()) { |
|
243 | 255 | return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw); |
|
244 | 256 | } else { |
@@ -250,7 +262,7 PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw | |||
|
250 | 262 | && ((PythonQtInstanceWrapper*)firstArg)->classInfo()->inherits(type->classInfo())) { |
|
251 | 263 | PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg; |
|
252 | 264 | if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) { |
|
253 |
QString error = QString("Trying to call '") + |
|
|
265 | QString error = QString("Trying to call '") + info->slotName() + "' on a destroyed " + self->classInfo()->className() + " object"; | |
|
254 | 266 | PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); |
|
255 | 267 | return NULL; |
|
256 | 268 | } |
@@ -456,6 +468,96 static PyMemberDef meth_members[] = { | |||
|
456 | 468 | {NULL} |
|
457 | 469 | }; |
|
458 | 470 | |
|
471 | static PyObject *PythonQtSlotFunction_parameterTypes(PythonQtSlotFunctionObject* type) | |
|
472 | { | |
|
473 | return PythonQtMemberFunction_parameterTypes(type->m_ml); | |
|
474 | } | |
|
475 | ||
|
476 | static PyObject *PythonQtSlotFunction_parameterNames(PythonQtSlotFunctionObject* type) | |
|
477 | { | |
|
478 | return PythonQtMemberFunction_parameterNames(type->m_ml); | |
|
479 | } | |
|
480 | ||
|
481 | static PyObject *PythonQtSlotFunction_typeName(PythonQtSlotFunctionObject* type) | |
|
482 | { | |
|
483 | return PythonQtMemberFunction_typeName(type->m_ml); | |
|
484 | } | |
|
485 | ||
|
486 | PyObject *PythonQtMemberFunction_parameterTypes(PythonQtSlotInfo* theInfo) | |
|
487 | { | |
|
488 | PythonQtSlotInfo* info = theInfo; | |
|
489 | int count = 0; | |
|
490 | while (info) { | |
|
491 | info = info->nextInfo(); | |
|
492 | count++; | |
|
493 | } | |
|
494 | info = theInfo; | |
|
495 | PyObject* result = PyTuple_New(count); | |
|
496 | for (int j = 0;j<count;j++) { | |
|
497 | QList<QByteArray> types = info->metaMethod()->parameterTypes(); | |
|
498 | PyObject* tuple = PyTuple_New(types.count()); | |
|
499 | for (int i = 0; i<types.count();i++) { | |
|
500 | PyTuple_SET_ITEM(tuple, i, PyString_FromString(types.at(i).constData())); | |
|
501 | } | |
|
502 | info = info->nextInfo(); | |
|
503 | PyTuple_SET_ITEM(result, j, tuple); | |
|
504 | } | |
|
505 | return result; | |
|
506 | } | |
|
507 | ||
|
508 | PyObject *PythonQtMemberFunction_parameterNames(PythonQtSlotInfo* theInfo) | |
|
509 | { | |
|
510 | PythonQtSlotInfo* info = theInfo; | |
|
511 | int count = 0; | |
|
512 | while (info) { | |
|
513 | info = info->nextInfo(); | |
|
514 | count++; | |
|
515 | } | |
|
516 | info = theInfo; | |
|
517 | PyObject* result = PyTuple_New(count); | |
|
518 | for (int j = 0;j<count;j++) { | |
|
519 | QList<QByteArray> names = info->metaMethod()->parameterNames(); | |
|
520 | PyObject* tuple = PyTuple_New(names.count()); | |
|
521 | for (int i = 0; i<names.count();i++) { | |
|
522 | PyTuple_SET_ITEM(tuple, i, PyString_FromString(names.at(i).constData())); | |
|
523 | } | |
|
524 | info = info->nextInfo(); | |
|
525 | PyTuple_SET_ITEM(result, j, tuple); | |
|
526 | } | |
|
527 | return result; | |
|
528 | } | |
|
529 | ||
|
530 | PyObject *PythonQtMemberFunction_typeName(PythonQtSlotInfo* theInfo) | |
|
531 | { | |
|
532 | PythonQtSlotInfo* info = theInfo; | |
|
533 | int count = 0; | |
|
534 | while (info) { | |
|
535 | info = info->nextInfo(); | |
|
536 | count++; | |
|
537 | } | |
|
538 | info = theInfo; | |
|
539 | PyObject* result = PyTuple_New(count); | |
|
540 | for (int j = 0;j<count;j++) { | |
|
541 | QByteArray name = info->metaMethod()->typeName(); | |
|
542 | PyTuple_SET_ITEM(result, j, PyString_FromString(name.constData())); | |
|
543 | info = info->nextInfo(); | |
|
544 | } | |
|
545 | return result; | |
|
546 | } | |
|
547 | ||
|
548 | static PyMethodDef meth_methods[] = { | |
|
549 | {"parameterTypes", (PyCFunction)PythonQtSlotFunction_parameterTypes, METH_NOARGS, | |
|
550 | "Returns a tuple of tuples of the C++ parameter types for all overloads of the slot" | |
|
551 | }, | |
|
552 | {"parameterNames", (PyCFunction)PythonQtSlotFunction_parameterNames, METH_NOARGS, | |
|
553 | "Returns a tuple of tuples of the C++ parameter type names (if available), for all overloads of the slot" | |
|
554 | }, | |
|
555 | {"typeName", (PyCFunction)PythonQtSlotFunction_typeName, METH_NOARGS, | |
|
556 | "Returns a tuple of the C++ return value types of each slot overload" | |
|
557 | }, | |
|
558 | {NULL, NULL, 0 , NULL} /* Sentinel */ | |
|
559 | }; | |
|
560 | ||
|
459 | 561 | static PyObject * |
|
460 | 562 | meth_repr(PythonQtSlotFunctionObject *f) |
|
461 | 563 | { |
@@ -535,7 +637,7 PyTypeObject PythonQtSlotFunction_Type = { | |||
|
535 | 637 | 0, /* tp_weaklistoffset */ |
|
536 | 638 | 0, /* tp_iter */ |
|
537 | 639 | 0, /* tp_iternext */ |
|
538 |
|
|
|
640 | meth_methods, /* tp_methods */ | |
|
539 | 641 | meth_members, /* tp_members */ |
|
540 | 642 | meth_getsets, /* tp_getset */ |
|
541 | 643 | 0, /* tp_base */ |
@@ -65,10 +65,14 PyObject* PythonQtSlotFunction_Call(PyObject *, PyObject *, PyObject *); | |||
|
65 | 65 | |
|
66 | 66 | PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject *kw, void* firstArg=NULL, void** directReturnValuePointer=NULL); |
|
67 | 67 | |
|
68 | ||
|
69 | 68 | PyObject* PythonQtSlotFunction_New(PythonQtSlotInfo *, PyObject *, |
|
70 | 69 | PyObject *); |
|
71 | 70 | |
|
71 | PyObject *PythonQtMemberFunction_Call(PythonQtSlotInfo* info, PyObject* m_self, PyObject *args, PyObject *kw); | |
|
72 | PyObject *PythonQtMemberFunction_parameterTypes(PythonQtSlotInfo* theInfo); | |
|
73 | PyObject *PythonQtMemberFunction_parameterNames(PythonQtSlotInfo* theInfo); | |
|
74 | PyObject *PythonQtMemberFunction_typeName(PythonQtSlotInfo* theInfo); | |
|
75 | ||
|
72 | 76 | //! defines a python object that stores a Qt slot info |
|
73 | 77 | typedef struct { |
|
74 | 78 | PyObject_HEAD |
@@ -102,6 +102,9 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal | |||
|
102 | 102 | } |
|
103 | 103 | if (sender) { |
|
104 | 104 | result = PythonQt::self()->removeSignalHandler(sender, signalTmp, callable); |
|
105 | if (callable == NULL) { | |
|
106 | result |= QObject::disconnect(sender, signalTmp, NULL, NULL); | |
|
107 | } | |
|
105 | 108 | if (!result) { |
|
106 | 109 | if (sender->metaObject()->indexOfSignal(QMetaObject::normalizedSignature(signalTmp.constData()+1)) == -1) { |
|
107 | 110 | qWarning("PythonQt: QObject::disconnect() signal '%s' does not exist on %s", signal.constData(), sender->metaObject()->className()); |
@@ -61,7 +61,7 class PYTHONQT_EXPORT PythonQtStdDecorators : public QObject | |||
|
61 | 61 | public slots: |
|
62 | 62 | bool connect(QObject* sender, const QByteArray& signal, PyObject* callable); |
|
63 | 63 | bool connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot); |
|
64 | bool disconnect(QObject* sender, const QByteArray& signal, PyObject* callable); | |
|
64 | bool disconnect(QObject* sender, const QByteArray& signal, PyObject* callable = NULL); | |
|
65 | 65 | bool disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot); |
|
66 | 66 | |
|
67 | 67 | QObject* parent(QObject* o); |
@@ -6,6 +6,7 HEADERS += \ | |||
|
6 | 6 | $$PWD/PythonQtClassInfo.h \ |
|
7 | 7 | $$PWD/PythonQtImporter.h \ |
|
8 | 8 | $$PWD/PythonQtObjectPtr.h \ |
|
9 | $$PWD/PythonQtSignal.h \ | |
|
9 | 10 | $$PWD/PythonQtSlot.h \ |
|
10 | 11 | $$PWD/PythonQtStdIn.h \ |
|
11 | 12 | $$PWD/PythonQtStdOut.h \ |
@@ -31,6 +32,7 SOURCES += \ | |||
|
31 | 32 | $$PWD/PythonQtObjectPtr.cpp \ |
|
32 | 33 | $$PWD/PythonQtStdIn.cpp \ |
|
33 | 34 | $$PWD/PythonQtStdOut.cpp \ |
|
35 | $$PWD/PythonQtSignal.cpp \ | |
|
34 | 36 | $$PWD/PythonQtSlot.cpp \ |
|
35 | 37 | $$PWD/PythonQtMisc.cpp \ |
|
36 | 38 | $$PWD/PythonQtMethodInfo.cpp \ |
General Comments 0
You need to be logged in to leave comments.
Login now