@@ -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 | #include "PythonQtImporter.h" |
|
43 | #include "PythonQtImporter.h" | |
44 | #include "PythonQtClassInfo.h" |
|
44 | #include "PythonQtClassInfo.h" | |
45 | #include "PythonQtMethodInfo.h" |
|
45 | #include "PythonQtMethodInfo.h" | |
|
46 | #include "PythonQtSignal.h" | |||
46 | #include "PythonQtSignalReceiver.h" |
|
47 | #include "PythonQtSignalReceiver.h" | |
47 | #include "PythonQtConversion.h" |
|
48 | #include "PythonQtConversion.h" | |
48 | #include "PythonQtStdIn.h" |
|
49 | #include "PythonQtStdIn.h" | |
@@ -167,6 +168,11 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName) | |||||
167 | } |
|
168 | } | |
168 | Py_INCREF(&PythonQtSlotFunction_Type); |
|
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 | // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it |
|
176 | // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it | |
171 | PythonQtClassWrapper_Type.tp_base = &PyType_Type; |
|
177 | PythonQtClassWrapper_Type.tp_base = &PyType_Type; | |
172 | // add our own python object types for classes |
|
178 | // add our own python object types for classes | |
@@ -412,6 +418,20 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name) | |||||
412 | if (info) { |
|
418 | if (info) { | |
413 | // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull |
|
419 | // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull | |
414 | ptr = info->castDownIfPossible(ptr, &info); |
|
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 | if (!info || info->pythonQtClassWrapper()==NULL) { |
|
437 | if (!info || info->pythonQtClassWrapper()==NULL) { | |
@@ -602,7 +622,6 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name) | |||||
602 | QStringList l = name.split('.'); |
|
622 | QStringList l = name.split('.'); | |
603 | PythonQtObjectPtr p = module; |
|
623 | PythonQtObjectPtr p = module; | |
604 | PythonQtObjectPtr prev; |
|
624 | PythonQtObjectPtr prev; | |
605 | QString s; |
|
|||
606 | QByteArray b; |
|
625 | QByteArray b; | |
607 | for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) { |
|
626 | for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) { | |
608 | prev = p; |
|
627 | prev = p; | |
@@ -784,97 +803,171 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, | |||||
784 | } |
|
803 | } | |
785 |
|
804 | |||
786 | if (object) { |
|
805 | if (object) { | |
787 | if (type == CallOverloads) { |
|
806 | results = introspectObject(object, type); | |
788 | if (PythonQtSlotFunction_Check(object)) { |
|
807 | } | |
789 | PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object(); |
|
808 | ||
790 | PythonQtSlotInfo* info = o->m_ml; |
|
809 | return results; | |
791 |
|
810 | } | ||
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(); |
|
|||
799 |
|
811 | |||
800 | while (info) { |
|
812 | QStringList PythonQt::introspectObject(PyObject* object, ObjectType type) | |
801 | results << info->fullSignature(); |
|
813 | { | |
802 | info = info->nextInfo(); |
|
814 | QStringList results; | |
803 | } |
|
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 | } else { |
|
845 | } else { | |
805 | //TODO: use pydoc! |
|
|||
806 | PyObject* doc = PyObject_GetAttrString(object, "__doc__"); |
|
846 | PyObject* doc = PyObject_GetAttrString(object, "__doc__"); | |
807 | if (doc) { |
|
847 | if (doc) { | |
808 | results << PyString_AsString(doc); |
|
848 | results << PyString_AsString(doc); | |
809 | Py_DECREF(doc); |
|
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 | } else { |
|
859 | } else { | |
813 | PyObject* keys = NULL; |
|
860 | keys = PyObject_Dir(object); | |
814 | bool isDict = false; |
|
861 | } | |
815 | if (PyDict_Check(object)) { |
|
862 | if (keys) { | |
816 | keys = PyDict_Keys(object); |
|
863 | int count = PyList_Size(keys); | |
817 | isDict = true; |
|
864 | PyObject* key; | |
818 | } else { |
|
865 | PyObject* value; | |
819 | keys = PyObject_Dir(object); |
|
866 | QString keystr; | |
820 | } |
|
867 | for (int i = 0;i<count;i++) { | |
821 | if (keys) { |
|
868 | key = PyList_GetItem(keys,i); | |
822 | int count = PyList_Size(keys); |
|
869 | if (isDict) { | |
823 | PyObject* key; |
|
870 | value = PyDict_GetItem(object, key); | |
824 |
|
|
871 | Py_INCREF(value); | |
825 | QString keystr; |
|
872 | } else { | |
826 | for (int i = 0;i<count;i++) { |
|
873 | value = PyObject_GetAttr(object, key); | |
827 | key = PyList_GetItem(keys,i); |
|
874 | } | |
828 | if (isDict) { |
|
875 | if (!value) continue; | |
829 | value = PyDict_GetItem(object, key); |
|
876 | keystr = PyString_AsString(key); | |
830 | Py_INCREF(value); |
|
877 | static const QString underscoreStr("__tmp"); | |
831 | } else { |
|
878 | if (!keystr.startsWith(underscoreStr)) { | |
832 | value = PyObject_GetAttr(object, key); |
|
879 | switch (type) { | |
833 | } |
|
880 | case Anything: | |
834 | if (!value) continue; |
|
881 | results << keystr; | |
835 | keystr = PyString_AsString(key); |
|
882 | break; | |
836 | static const QString underscoreStr("__tmp"); |
|
883 | case Class: | |
837 | if (!keystr.startsWith(underscoreStr)) { |
|
884 | if (value->ob_type == &PyClass_Type || value->ob_type == &PyType_Type) { | |
838 | switch (type) { |
|
885 | results << keystr; | |
839 |
|
|
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 | results << keystr; |
|
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 | return results; |
|
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 | void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell) |
|
1387 | void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell) | |
1194 | { |
|
1388 | { | |
1195 | _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell); |
|
1389 | _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell); | |
@@ -1349,4 +1543,150 void* PythonQtPrivate::unwrapForeignWrapper( const QByteArray& classname, PyObje | |||||
1349 | } |
|
1543 | } | |
1350 | } |
|
1544 | } | |
1351 | return NULL; |
|
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 | //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname |
|
334 | //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname | |
335 | QStringList introspection(PyObject* object, const QString& objectname, ObjectType type); |
|
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 | //! returns the found callable object or NULL |
|
344 | //! returns the found callable object or NULL | |
338 | //! @return new reference |
|
345 | //! @return new reference | |
339 | PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name); |
|
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 | private: |
|
513 | private: | |
503 | void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName); |
|
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 | //! callback for stdout redirection, emits pythonStdOut signal |
|
520 | //! callback for stdout redirection, emits pythonStdOut signal | |
506 | static void stdOutRedirectCB(const QString& str); |
|
521 | static void stdOutRedirectCB(const QString& str); | |
@@ -626,6 +641,12 public: | |||||
626 |
|
641 | |||
627 | //! returns the profiling callback, which may be NULL |
|
642 | //! returns the profiling callback, which may be NULL | |
628 | PythonQt::ProfilingCB* profilingCB() const { return _profilingCB; } |
|
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 | private: |
|
651 | private: | |
631 | //! Setup the shared library suffixes by getting them from the "imp" module. |
|
652 | //! Setup the shared library suffixes by getting them from the "imp" module. |
@@ -96,7 +96,7 void PythonQtClassInfo::clearCachedMembers() | |||||
96 | QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers); |
|
96 | QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers); | |
97 | while (i.hasNext()) { |
|
97 | while (i.hasNext()) { | |
98 | PythonQtMemberInfo member = i.next().value(); |
|
98 | PythonQtMemberInfo member = i.next().value(); | |
99 | if (member._type== PythonQtMemberInfo::Slot) { |
|
99 | if (member._type== PythonQtMemberInfo::Slot || member._type== PythonQtMemberInfo::Signal) { | |
100 | PythonQtSlotInfo* info = member._slot; |
|
100 | PythonQtSlotInfo* info = member._slot; | |
101 | while (info) { |
|
101 | while (info) { | |
102 | PythonQtSlotInfo* next = info->nextInfo(); |
|
102 | PythonQtSlotInfo* next = info->nextInfo(); | |
@@ -462,18 +462,14 QStringList PythonQtClassInfo::propertyList() | |||||
462 | return l; |
|
462 | return l; | |
463 | } |
|
463 | } | |
464 |
|
464 | |||
465 |
QStringList PythonQtClassInfo::memberList( |
|
465 | QStringList PythonQtClassInfo::memberList() | |
466 | { |
|
466 | { | |
467 | decorator(); |
|
467 | decorator(); | |
468 |
|
468 | |||
469 | QStringList l; |
|
469 | QStringList l; | |
470 | QString h; |
|
470 | QString h; | |
471 | if (_isQObject && _meta && !metaOnly) { |
|
|||
472 | l = propertyList(); |
|
|||
473 | } |
|
|||
474 |
|
||||
475 | // normal slots of QObject (or wrapper QObject) |
|
471 | // normal slots of QObject (or wrapper QObject) | |
476 |
if ( |
|
472 | if (_meta) { | |
477 | int numMethods = _meta->methodCount(); |
|
473 | int numMethods = _meta->methodCount(); | |
478 | bool skipQObj = !_isQObject; |
|
474 | bool skipQObj = !_isQObject; | |
479 | for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) { |
|
475 | for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) { | |
@@ -493,7 +489,7 QStringList PythonQtClassInfo::memberList(bool metaOnly) | |||||
493 | QList<PythonQtClassInfo*> infos; |
|
489 | QList<PythonQtClassInfo*> infos; | |
494 | recursiveCollectClassInfos(infos); |
|
490 | recursiveCollectClassInfos(infos); | |
495 | foreach(PythonQtClassInfo* info, infos) { |
|
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 | struct PythonQtMemberInfo { |
|
45 | struct PythonQtMemberInfo { | |
46 | enum Type { |
|
46 | enum Type { | |
47 | Invalid, Slot, EnumValue, EnumWrapper, Property, NotFound |
|
47 | Invalid, Slot, Signal, EnumValue, EnumWrapper, Property, NotFound | |
48 | }; |
|
48 | }; | |
49 |
|
49 | |||
50 | PythonQtMemberInfo():_type(Invalid),_slot(NULL),_enumWrapper(NULL),_enumValue(0) { } |
|
50 | PythonQtMemberInfo():_type(Invalid),_slot(NULL),_enumWrapper(NULL),_enumValue(0) { } | |
51 |
|
51 | |||
52 |
PythonQtMemberInfo(PythonQtSlotInfo* info) |
|
52 | PythonQtMemberInfo(PythonQtSlotInfo* info); | |
53 | _type = Slot; |
|
|||
54 | _slot = info; |
|
|||
55 | _enumValue = NULL; |
|
|||
56 | } |
|
|||
57 |
|
53 | |||
58 |
PythonQtMemberInfo(const PythonQtObjectPtr& enumValue) |
|
54 | PythonQtMemberInfo(const PythonQtObjectPtr& enumValue); | |
59 | _type = EnumValue; |
|
|||
60 | _slot = NULL; |
|
|||
61 | _enumValue = enumValue; |
|
|||
62 | _enumWrapper = NULL; |
|
|||
63 | } |
|
|||
64 |
|
55 | |||
65 |
PythonQtMemberInfo(const QMetaProperty& prop) |
|
56 | PythonQtMemberInfo(const QMetaProperty& prop); | |
66 | _type = Property; |
|
|||
67 | _slot = NULL; |
|
|||
68 | _enumValue = NULL; |
|
|||
69 | _property = prop; |
|
|||
70 | _enumWrapper = NULL; |
|
|||
71 | } |
|
|||
72 |
|
57 | |||
73 | Type _type; |
|
58 | Type _type; | |
74 |
|
59 | |||
@@ -159,8 +144,8 public: | |||||
159 | //! get list of all properties (on QObjects only, otherwise the list is empty) |
|
144 | //! get list of all properties (on QObjects only, otherwise the list is empty) | |
160 | QStringList propertyList(); |
|
145 | QStringList propertyList(); | |
161 |
|
146 | |||
162 | //! get list of all members |
|
147 | //! get list of all members (excluding properties, which can be listed with propertyList()) | |
163 |
QStringList memberList( |
|
148 | QStringList memberList(); | |
164 |
|
149 | |||
165 | //! get the meta type id of this class (only valid for isCPPWrapper() == true) |
|
150 | //! get the meta type id of this class (only valid for isCPPWrapper() == true) | |
166 | int metaTypeId() { return _metaTypeId; } |
|
151 | int metaTypeId() { return _metaTypeId; } |
@@ -44,6 +44,7 | |||||
44 |
|
44 | |||
45 | #include "PythonQt.h" |
|
45 | #include "PythonQt.h" | |
46 | #include "PythonQtSlot.h" |
|
46 | #include "PythonQtSlot.h" | |
|
47 | #include "PythonQtSignal.h" | |||
47 | #include "PythonQtClassInfo.h" |
|
48 | #include "PythonQtClassInfo.h" | |
48 | #include "PythonQtConversion.h" |
|
49 | #include "PythonQtConversion.h" | |
49 | #include "PythonQtInstanceWrapper.h" |
|
50 | #include "PythonQtInstanceWrapper.h" | |
@@ -291,40 +292,8 PyObject *PythonQtClassWrapper_inherits(PythonQtClassWrapper *type, PyObject *ar | |||||
291 | return PythonQtConv::GetPyBool(wrapper->classInfo()->inherits(name)); |
|
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 | static PyMethodDef PythonQtClassWrapper_methods[] = { |
|
296 | static PyMethodDef PythonQtClassWrapper_methods[] = { | |
325 | {"__init__", (PyCFunction)PythonQtClassWrapper__init__, METH_VARARGS, |
|
|||
326 | "Init function" |
|
|||
327 | }, |
|
|||
328 | {"className", (PyCFunction)PythonQtClassWrapper_classname, METH_NOARGS, |
|
297 | {"className", (PyCFunction)PythonQtClassWrapper_classname, METH_NOARGS, | |
329 | "Return the classname of the object" |
|
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 | if (qstrcmp(attributeName, "__dict__")==0) { |
|
325 | if (qstrcmp(attributeName, "__dict__")==0) { | |
357 |
PyObject* |
|
326 | PyObject* objectDict = ((PyTypeObject *)wrapper)->tp_dict; | |
358 | if (!wrapper->classInfo()) { |
|
327 | if (!wrapper->classInfo()) { | |
359 |
Py_INCREF( |
|
328 | Py_INCREF(objectDict); | |
360 |
return |
|
329 | return objectDict; | |
361 | } |
|
330 | } | |
362 |
dict = PyDict_ |
|
331 | PyObject* dict = PyDict_New(); | |
363 |
|
332 | |||
364 |
|
|
333 | QStringList l = wrapper->classInfo()->memberList(); | |
365 | foreach (QString name, l) { |
|
334 | foreach (QString name, l) { | |
366 | PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data()); |
|
335 | PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data()); | |
367 | if (o) { |
|
336 | if (o) { | |
@@ -369,21 +338,33 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) | |||||
369 | Py_DECREF(o); |
|
338 | Py_DECREF(o); | |
370 | } else { |
|
339 | } else { | |
371 | // it must have been a property or child, which we do not know as a class object... |
|
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 | if (wrapper->classInfo()->constructors()) { |
|
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 | PyDict_SetItemString(dict, "__init__", func); |
|
348 | PyDict_SetItemString(dict, "__init__", func); | |
377 | Py_DECREF(func); |
|
349 | Py_DECREF(func); | |
378 | } |
|
350 | } | |
379 |
for (int i = |
|
351 | for (int i = 0; PythonQtClassWrapper_methods[i].ml_name != NULL; i++) { | |
380 | PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[i], obj); |
|
352 | PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[i], obj); | |
381 | PyDict_SetItemString(dict, PythonQtClassWrapper_methods[i].ml_name, func); |
|
353 | PyDict_SetItemString(dict, PythonQtClassWrapper_methods[i].ml_name, func); | |
382 | Py_DECREF(func); |
|
354 | Py_DECREF(func); | |
383 | } |
|
355 | } | |
|
356 | ||||
|
357 | PyDict_Update(dict, objectDict); | |||
384 | return dict; |
|
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 | if (wrapper->classInfo()) { |
|
368 | if (wrapper->classInfo()) { | |
388 | PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName); |
|
369 | PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName); | |
389 | if (member._type == PythonQtMemberInfo::EnumValue) { |
|
370 | if (member._type == PythonQtMemberInfo::EnumValue) { | |
@@ -397,21 +378,17 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) | |||||
397 | } else if (member._type == PythonQtMemberInfo::Slot) { |
|
378 | } else if (member._type == PythonQtMemberInfo::Slot) { | |
398 | // we return all slots, even the instance slots, since they are callable as unbound slots with self argument |
|
379 | // we return all slots, even the instance slots, since they are callable as unbound slots with self argument | |
399 | return PythonQtSlotFunction_New(member._slot, obj, NULL); |
|
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 | PyObject* internalMethod = Py_FindMethod( PythonQtClassWrapper_methods, obj, (char*)attributeName); |
|
388 | PyObject* internalMethod = Py_FindMethod( PythonQtClassWrapper_methods, obj, (char*)attributeName); | |
405 | if (internalMethod) { |
|
389 | if (internalMethod) { | |
406 | return internalMethod; |
|
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 | QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'"; |
|
393 | QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'"; | |
417 | PyErr_SetString(PyExc_AttributeError, error.toLatin1().data()); |
|
394 | PyErr_SetString(PyExc_AttributeError, error.toLatin1().data()); |
@@ -70,6 +70,11 public: | |||||
70 | //! indicates that *.py files which are newer than their corresponding *.pyc files |
|
70 | //! indicates that *.py files which are newer than their corresponding *.pyc files | |
71 | //! are ignored |
|
71 | //! are ignored | |
72 | virtual bool ignoreUpdatedPythonSourceFiles() { return false; } |
|
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 | #endif |
|
80 | #endif |
@@ -255,7 +255,13 PythonQtImporter_load_module(PyObject *obj, PyObject *args) | |||||
255 | return NULL; |
|
255 | return NULL; | |
256 | } |
|
256 | } | |
257 | } |
|
257 | } | |
|
258 | ||||
258 | mod = PyImport_ExecCodeModuleEx(fullname, code, fullPath.toLatin1().data()); |
|
259 | mod = PyImport_ExecCodeModuleEx(fullname, code, fullPath.toLatin1().data()); | |
|
260 | ||||
|
261 | if (PythonQt::importInterface()) { | |||
|
262 | PythonQt::importInterface()->importedModule(fullname); | |||
|
263 | } | |||
|
264 | ||||
259 | Py_DECREF(code); |
|
265 | Py_DECREF(code); | |
260 | if (Py_VerboseFlag) { |
|
266 | if (Py_VerboseFlag) { | |
261 | PySys_WriteStderr("import %s # loaded from %s\n", |
|
267 | PySys_WriteStderr("import %s # loaded from %s\n", |
@@ -43,6 +43,7 | |||||
43 | #include <QObject> |
|
43 | #include <QObject> | |
44 | #include "PythonQt.h" |
|
44 | #include "PythonQt.h" | |
45 | #include "PythonQtSlot.h" |
|
45 | #include "PythonQtSlot.h" | |
|
46 | #include "PythonQtSignal.h" | |||
46 | #include "PythonQtClassInfo.h" |
|
47 | #include "PythonQtClassInfo.h" | |
47 | #include "PythonQtConversion.h" |
|
48 | #include "PythonQtConversion.h" | |
48 | #include "PythonQtClassWrapper.h" |
|
49 | #include "PythonQtClassWrapper.h" | |
@@ -413,6 +414,9 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) | |||||
413 | case PythonQtMemberInfo::Slot: |
|
414 | case PythonQtMemberInfo::Slot: | |
414 | return PythonQtSlotFunction_New(member._slot, obj, NULL); |
|
415 | return PythonQtSlotFunction_New(member._slot, obj, NULL); | |
415 | break; |
|
416 | break; | |
|
417 | case PythonQtMemberInfo::Signal: | |||
|
418 | return PythonQtSignalFunction_New(member._slot, obj, NULL); | |||
|
419 | break; | |||
416 | case PythonQtMemberInfo::EnumValue: |
|
420 | case PythonQtMemberInfo::EnumValue: | |
417 | { |
|
421 | { | |
418 | PyObject* enumValue = member._enumValue; |
|
422 | PyObject* enumValue = member._enumValue; | |
@@ -529,6 +533,8 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObjec | |||||
529 | } |
|
533 | } | |
530 | } else if (member._type == PythonQtMemberInfo::Slot) { |
|
534 | } else if (member._type == PythonQtMemberInfo::Slot) { | |
531 | error = QString("Slot '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object"; |
|
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 | } else if (member._type == PythonQtMemberInfo::EnumValue) { |
|
538 | } else if (member._type == PythonQtMemberInfo::EnumValue) { | |
533 | error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object"; |
|
539 | error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object"; | |
534 | } else if (member._type == PythonQtMemberInfo::EnumWrapper) { |
|
540 | } else if (member._type == PythonQtMemberInfo::EnumWrapper) { | |
@@ -590,14 +596,16 static QString getStringFromObject(PythonQtInstanceWrapper* wrapper) { | |||||
590 | return result; |
|
596 | return result; | |
591 | } |
|
597 | } | |
592 | } |
|
598 | } | |
593 | // next, try to call py_toString |
|
599 | if (wrapper->_wrappedPtr || wrapper->_obj) { | |
594 | PythonQtMemberInfo info = wrapper->classInfo()->member("py_toString"); |
|
600 | // next, try to call py_toString | |
595 | if (info._type == PythonQtMemberInfo::Slot) { |
|
601 | PythonQtMemberInfo info = wrapper->classInfo()->member("py_toString"); | |
596 | PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, NULL, NULL, wrapper->_wrappedPtr); |
|
602 | if (info._type == PythonQtMemberInfo::Slot) { | |
597 | if (resultObj) { |
|
603 | PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, NULL, NULL, wrapper->_wrappedPtr); | |
598 | // TODO this is one conversion too much, would be nicer to call the slot directly... |
|
604 | if (resultObj) { | |
599 | result = PythonQtConv::PyObjGetString(resultObj); |
|
605 | // TODO this is one conversion too much, would be nicer to call the slot directly... | |
600 | Py_DECREF(resultObj); |
|
606 | result = PythonQtConv::PyObjGetString(resultObj); | |
|
607 | Py_DECREF(resultObj); | |||
|
608 | } | |||
601 | } |
|
609 | } | |
602 | } |
|
610 | } | |
603 | return result; |
|
611 | return result; |
@@ -99,7 +99,9 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromArgumentLis | |||||
99 | if (i>1) { |
|
99 | if (i>1) { | |
100 | fullSig += ","; |
|
100 | fullSig += ","; | |
101 | } |
|
101 | } | |
102 |
|
|
102 | QByteArray arg(args[i]); | |
|
103 | fullSig += arg; | |||
|
104 | arguments << arg; | |||
103 | } |
|
105 | } | |
104 | fullSig += ")"; |
|
106 | fullSig += ")"; | |
105 | PythonQtMethodInfo* result = _cachedSignatures.value(fullSig); |
|
107 | PythonQtMethodInfo* result = _cachedSignatures.value(fullSig); |
@@ -66,7 +66,7 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInf | |||||
66 | PyObject* o = callable; |
|
66 | PyObject* o = callable; | |
67 | PyFunctionObject* func = (PyFunctionObject*)o; |
|
67 | PyFunctionObject* func = (PyFunctionObject*)o; | |
68 | PyCodeObject* code = (PyCodeObject*)func->func_code; |
|
68 | PyCodeObject* code = (PyCodeObject*)func->func_code; | |
69 |
if (!(code->co_flags & |
|
69 | if (!(code->co_flags & CO_VARARGS)) { | |
70 | numPythonArgs = code->co_argcount; |
|
70 | numPythonArgs = code->co_argcount; | |
71 | } else { |
|
71 | } else { | |
72 | // variable numbers of arguments allowed |
|
72 | // variable numbers of arguments allowed | |
@@ -77,7 +77,7 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInf | |||||
77 | if (PyFunction_Check(method->im_func)) { |
|
77 | if (PyFunction_Check(method->im_func)) { | |
78 | PyFunctionObject* func = (PyFunctionObject*)method->im_func; |
|
78 | PyFunctionObject* func = (PyFunctionObject*)method->im_func; | |
79 | PyCodeObject* code = (PyCodeObject*)func->func_code; |
|
79 | PyCodeObject* code = (PyCodeObject*)func->func_code; | |
80 |
if (!(code->co_flags & |
|
80 | if (!(code->co_flags & CO_VARARGS)) { | |
81 | numPythonArgs = code->co_argcount - 1; // we subtract one because the first is "self" |
|
81 | numPythonArgs = code->co_argcount - 1; // we subtract one because the first is "self" | |
82 | } else { |
|
82 | } else { | |
83 | // variable numbers of arguments allowed |
|
83 | // variable numbers of arguments allowed | |
@@ -187,11 +187,20 bool PythonQtSignalReceiver::removeSignalHandler(const char* signal, PyObject* c | |||||
187 | int sigId = getSignalIndex(signal); |
|
187 | int sigId = getSignalIndex(signal); | |
188 | if (sigId>=0) { |
|
188 | if (sigId>=0) { | |
189 | QMutableListIterator<PythonQtSignalTarget> i(_targets); |
|
189 | QMutableListIterator<PythonQtSignalTarget> i(_targets); | |
190 | while (i.hasNext()) { |
|
190 | if (callable) { | |
191 | if (i.next().isSame(sigId, callable)) { |
|
191 | while (i.hasNext()) { | |
192 | i.remove(); |
|
192 | if (i.next().isSame(sigId, callable)) { | |
193 | found = true; |
|
193 | i.remove(); | |
194 | break; |
|
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 | //! add a signal handler |
|
118 | //! add a signal handler | |
119 | bool addSignalHandler(const char* signal, PyObject* callable); |
|
119 | bool addSignalHandler(const char* signal, PyObject* callable); | |
120 |
|
120 | |||
121 | //! remove a signal handler |
|
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); |
|
122 | bool removeSignalHandler(const char* signal, PyObject* callable = NULL); | |
123 |
|
123 | |||
124 | //! remove all signal handlers |
|
124 | //! remove all signal handlers | |
125 | void removeSignalHandlers(); |
|
125 | void removeSignalHandlers(); | |
@@ -140,3 +140,4 private: | |||||
140 |
|
140 | |||
141 |
|
141 | |||
142 | #endif |
|
142 | #endif | |
|
143 |
@@ -50,6 +50,8 | |||||
50 | #include <exception> |
|
50 | #include <exception> | |
51 | #include <stdexcept> |
|
51 | #include <stdexcept> | |
52 |
|
52 | |||
|
53 | #include <QByteArray> | |||
|
54 | ||||
53 | #define PYTHONQT_MAX_ARGS 32 |
|
55 | #define PYTHONQT_MAX_ARGS 32 | |
54 |
|
56 | |||
55 |
|
57 | |||
@@ -160,28 +162,34 bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj | |||||
160 |
|
162 | |||
161 | // invoke the slot via metacall |
|
163 | // invoke the slot via metacall | |
162 | bool hadException = false; |
|
164 | bool hadException = false; | |
163 | try { |
|
165 | QObject* obj = info->decorator()?info->decorator():objectToCall; | |
164 | (info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList); |
|
166 | if (!obj) { | |
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) { |
|
|||
176 | hadException = true; |
|
167 | hadException = true; | |
177 | QByteArray what("std::logic_error: "); |
|
168 | PyErr_SetString(PyExc_RuntimeError, "Trying to call a slot on a deleted QObject!"); | |
178 | what += e.what(); |
|
169 | } else { | |
179 | PyErr_SetString(PyExc_RuntimeError, what.constData()); |
|
170 | try { | |
180 | } catch (std::exception& e) { |
|
171 | obj->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList); | |
181 | hadException = true; |
|
172 | } catch (std::bad_alloc & e) { | |
182 | QByteArray what("std::exception: "); |
|
173 | hadException = true; | |
183 | what += e.what(); |
|
174 | QByteArray what("std::bad_alloc: "); | |
184 | PyErr_SetString(PyExc_StandardError, what.constData()); |
|
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 | if (profilingCB) { |
|
195 | if (profilingCB) { | |
@@ -227,18 +235,22 static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL; | |||||
227 | PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw) |
|
235 | PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw) | |
228 | { |
|
236 | { | |
229 | PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func; |
|
237 | PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func; | |
230 | PythonQtSlotInfo* info = f->m_ml; |
|
238 | return PythonQtMemberFunction_Call(f->m_ml, f->m_self, args, kw); | |
231 | if (PyObject_TypeCheck(f->m_self, &PythonQtInstanceWrapper_Type)) { |
|
239 | } | |
232 | PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self; |
|
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 | if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) { |
|
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 | PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); |
|
247 | PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); | |
236 | return NULL; |
|
248 | return NULL; | |
237 | } else { |
|
249 | } else { | |
238 | return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr); |
|
250 | return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr); | |
239 | } |
|
251 | } | |
240 |
} else if ( |
|
252 | } else if (m_self->ob_type == &PythonQtClassWrapper_Type) { | |
241 |
PythonQtClassWrapper* type = (PythonQtClassWrapper*) |
|
253 | PythonQtClassWrapper* type = (PythonQtClassWrapper*) m_self; | |
242 | if (info->isClassDecorator()) { |
|
254 | if (info->isClassDecorator()) { | |
243 | return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw); |
|
255 | return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw); | |
244 | } else { |
|
256 | } else { | |
@@ -250,7 +262,7 PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw | |||||
250 | && ((PythonQtInstanceWrapper*)firstArg)->classInfo()->inherits(type->classInfo())) { |
|
262 | && ((PythonQtInstanceWrapper*)firstArg)->classInfo()->inherits(type->classInfo())) { | |
251 | PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg; |
|
263 | PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg; | |
252 | if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) { |
|
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 | PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); |
|
266 | PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); | |
255 | return NULL; |
|
267 | return NULL; | |
256 | } |
|
268 | } | |
@@ -456,6 +468,96 static PyMemberDef meth_members[] = { | |||||
456 | {NULL} |
|
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 | static PyObject * |
|
561 | static PyObject * | |
460 | meth_repr(PythonQtSlotFunctionObject *f) |
|
562 | meth_repr(PythonQtSlotFunctionObject *f) | |
461 | { |
|
563 | { | |
@@ -535,7 +637,7 PyTypeObject PythonQtSlotFunction_Type = { | |||||
535 | 0, /* tp_weaklistoffset */ |
|
637 | 0, /* tp_weaklistoffset */ | |
536 | 0, /* tp_iter */ |
|
638 | 0, /* tp_iter */ | |
537 | 0, /* tp_iternext */ |
|
639 | 0, /* tp_iternext */ | |
538 |
|
|
640 | meth_methods, /* tp_methods */ | |
539 | meth_members, /* tp_members */ |
|
641 | meth_members, /* tp_members */ | |
540 | meth_getsets, /* tp_getset */ |
|
642 | meth_getsets, /* tp_getset */ | |
541 | 0, /* tp_base */ |
|
643 | 0, /* tp_base */ |
@@ -65,10 +65,14 PyObject* PythonQtSlotFunction_Call(PyObject *, PyObject *, PyObject *); | |||||
65 |
|
65 | |||
66 | PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject *kw, void* firstArg=NULL, void** directReturnValuePointer=NULL); |
|
66 | PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject *kw, void* firstArg=NULL, void** directReturnValuePointer=NULL); | |
67 |
|
67 | |||
68 |
|
||||
69 | PyObject* PythonQtSlotFunction_New(PythonQtSlotInfo *, PyObject *, |
|
68 | PyObject* PythonQtSlotFunction_New(PythonQtSlotInfo *, PyObject *, | |
70 | PyObject *); |
|
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 | //! defines a python object that stores a Qt slot info |
|
76 | //! defines a python object that stores a Qt slot info | |
73 | typedef struct { |
|
77 | typedef struct { | |
74 | PyObject_HEAD |
|
78 | PyObject_HEAD |
@@ -102,6 +102,9 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal | |||||
102 | } |
|
102 | } | |
103 | if (sender) { |
|
103 | if (sender) { | |
104 | result = PythonQt::self()->removeSignalHandler(sender, signalTmp, callable); |
|
104 | result = PythonQt::self()->removeSignalHandler(sender, signalTmp, callable); | |
|
105 | if (callable == NULL) { | |||
|
106 | result |= QObject::disconnect(sender, signalTmp, NULL, NULL); | |||
|
107 | } | |||
105 | if (!result) { |
|
108 | if (!result) { | |
106 | if (sender->metaObject()->indexOfSignal(QMetaObject::normalizedSignature(signalTmp.constData()+1)) == -1) { |
|
109 | if (sender->metaObject()->indexOfSignal(QMetaObject::normalizedSignature(signalTmp.constData()+1)) == -1) { | |
107 | qWarning("PythonQt: QObject::disconnect() signal '%s' does not exist on %s", signal.constData(), sender->metaObject()->className()); |
|
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 | public slots: |
|
61 | public slots: | |
62 | bool connect(QObject* sender, const QByteArray& signal, PyObject* callable); |
|
62 | bool connect(QObject* sender, const QByteArray& signal, PyObject* callable); | |
63 | bool connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot); |
|
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 | bool disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot); |
|
65 | bool disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot); | |
66 |
|
66 | |||
67 | QObject* parent(QObject* o); |
|
67 | QObject* parent(QObject* o); |
@@ -6,6 +6,7 HEADERS += \ | |||||
6 | $$PWD/PythonQtClassInfo.h \ |
|
6 | $$PWD/PythonQtClassInfo.h \ | |
7 | $$PWD/PythonQtImporter.h \ |
|
7 | $$PWD/PythonQtImporter.h \ | |
8 | $$PWD/PythonQtObjectPtr.h \ |
|
8 | $$PWD/PythonQtObjectPtr.h \ | |
|
9 | $$PWD/PythonQtSignal.h \ | |||
9 | $$PWD/PythonQtSlot.h \ |
|
10 | $$PWD/PythonQtSlot.h \ | |
10 | $$PWD/PythonQtStdIn.h \ |
|
11 | $$PWD/PythonQtStdIn.h \ | |
11 | $$PWD/PythonQtStdOut.h \ |
|
12 | $$PWD/PythonQtStdOut.h \ | |
@@ -31,6 +32,7 SOURCES += \ | |||||
31 | $$PWD/PythonQtObjectPtr.cpp \ |
|
32 | $$PWD/PythonQtObjectPtr.cpp \ | |
32 | $$PWD/PythonQtStdIn.cpp \ |
|
33 | $$PWD/PythonQtStdIn.cpp \ | |
33 | $$PWD/PythonQtStdOut.cpp \ |
|
34 | $$PWD/PythonQtStdOut.cpp \ | |
|
35 | $$PWD/PythonQtSignal.cpp \ | |||
34 | $$PWD/PythonQtSlot.cpp \ |
|
36 | $$PWD/PythonQtSlot.cpp \ | |
35 | $$PWD/PythonQtMisc.cpp \ |
|
37 | $$PWD/PythonQtMisc.cpp \ | |
36 | $$PWD/PythonQtMethodInfo.cpp \ |
|
38 | $$PWD/PythonQtMethodInfo.cpp \ |
General Comments 0
You need to be logged in to leave comments.
Login now