##// END OF EJS Templates
Updated from current MeVisLab development...
florianlink -
r173:7f1e2590af31
parent child
Show More
@@ -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
@@ -1,1352 +1,1692
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
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"
49 50 #include "PythonQtStdOut.h"
50 51 #include "PythonQtCppWrapperFactory.h"
51 52 #include "PythonQtVariants.h"
52 53 #include "PythonQtStdDecorators.h"
53 54 #include "PythonQtQFileImporter.h"
54 55 #include <pydebug.h>
55 56 #include <vector>
56 57
57 58 PythonQt* PythonQt::_self = NULL;
58 59 int PythonQt::_uniqueModuleCount = 0;
59 60
60 61 void PythonQt_init_QtGuiBuiltin(PyObject*);
61 62 void PythonQt_init_QtCoreBuiltin(PyObject*);
62 63
63 64 void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
64 65 {
65 66 if (!_self) {
66 67 _self = new PythonQt(flags, pythonQtModuleName);
67 68
68 69 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
69 70 qRegisterMetaType<QList<QObject*> >("QList<void*>");
70 71
71 72 PythonQtRegisterToolClassesTemplateConverter(int);
72 73 PythonQtRegisterToolClassesTemplateConverter(float);
73 74 PythonQtRegisterToolClassesTemplateConverter(double);
74 75 PythonQtRegisterToolClassesTemplateConverter(qint32);
75 76 PythonQtRegisterToolClassesTemplateConverter(quint32);
76 77 PythonQtRegisterToolClassesTemplateConverter(qint64);
77 78 PythonQtRegisterToolClassesTemplateConverter(quint64);
78 79 // TODO: which other POD types should be available for QList etc.
79 80
80 81 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
81 82
82 83 PythonQt_init_QtCoreBuiltin(NULL);
83 84 PythonQt_init_QtGuiBuiltin(NULL);
84 85
85 86 PythonQtRegisterToolClassesTemplateConverter(QByteArray);
86 87 PythonQtRegisterToolClassesTemplateConverter(QDate);
87 88 PythonQtRegisterToolClassesTemplateConverter(QTime);
88 89 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
89 90 PythonQtRegisterToolClassesTemplateConverter(QUrl);
90 91 PythonQtRegisterToolClassesTemplateConverter(QLocale);
91 92 PythonQtRegisterToolClassesTemplateConverter(QRect);
92 93 PythonQtRegisterToolClassesTemplateConverter(QRectF);
93 94 PythonQtRegisterToolClassesTemplateConverter(QSize);
94 95 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
95 96 PythonQtRegisterToolClassesTemplateConverter(QLine);
96 97 PythonQtRegisterToolClassesTemplateConverter(QLineF);
97 98 PythonQtRegisterToolClassesTemplateConverter(QPoint);
98 99 PythonQtRegisterToolClassesTemplateConverter(QPointF);
99 100 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
100 101
101 102 PythonQtRegisterToolClassesTemplateConverter(QFont);
102 103 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
103 104 PythonQtRegisterToolClassesTemplateConverter(QBrush);
104 105 PythonQtRegisterToolClassesTemplateConverter(QColor);
105 106 PythonQtRegisterToolClassesTemplateConverter(QPalette);
106 107 PythonQtRegisterToolClassesTemplateConverter(QIcon);
107 108 PythonQtRegisterToolClassesTemplateConverter(QImage);
108 109 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
109 110 PythonQtRegisterToolClassesTemplateConverter(QRegion);
110 111 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
111 112 PythonQtRegisterToolClassesTemplateConverter(QCursor);
112 113 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
113 114 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
114 115 PythonQtRegisterToolClassesTemplateConverter(QPen);
115 116 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
116 117 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
117 118 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
118 119
119 120
120 121 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
121 122 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
122 123 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
123 124 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
124 125 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
125 126 for (unsigned int i = 0;i<16; i++) {
126 127 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
127 128 if (obj) {
128 129 PyModule_AddObject(pack, names[i], obj);
129 130 Py_INCREF(obj);
130 131 PyModule_AddObject(pack2, names[i], obj);
131 132 } else {
132 133 std::cerr << "method not found " << names[i];
133 134 }
134 135 }
135 136 }
136 137 }
137 138
138 139 void PythonQt::cleanup()
139 140 {
140 141 if (_self) {
141 142 delete _self;
142 143 _self = NULL;
143 144 }
144 145 }
145 146
146 147 PythonQt* PythonQt::self() { return _self; }
147 148
148 149 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
149 150 {
150 151 _p = new PythonQtPrivate;
151 152 _p->_initFlags = flags;
152 153
153 154 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
154 155
155 156 if ((flags & PythonAlreadyInitialized) == 0) {
156 157 Py_SetProgramName(const_cast<char*>("PythonQt"));
157 158 if (flags & IgnoreSiteModule) {
158 159 // this prevents the automatic importing of Python site files
159 160 Py_NoSiteFlag = 1;
160 161 }
161 162 Py_Initialize();
162 163 }
163 164
164 165 // add our own python object types for qt object slots
165 166 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
166 167 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
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
173 179 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
174 180 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
175 181 }
176 182 Py_INCREF(&PythonQtClassWrapper_Type);
177 183
178 184 // add our own python object types for CPP instances
179 185 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
180 186 PythonQt::handleError();
181 187 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
182 188 }
183 189 Py_INCREF(&PythonQtInstanceWrapper_Type);
184 190
185 191 // add our own python object types for redirection of stdout
186 192 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
187 193 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
188 194 }
189 195 Py_INCREF(&PythonQtStdOutRedirectType);
190 196
191 197 // add our own python object types for redirection of stdin
192 198 if (PyType_Ready(&PythonQtStdInRedirectType) < 0) {
193 199 std::cerr << "could not initialize PythonQtStdInRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
194 200 }
195 201 Py_INCREF(&PythonQtStdInRedirectType);
196 202
197 203 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
198 204
199 205 _p->setupSharedLibrarySuffixes();
200 206
201 207 }
202 208
203 209 PythonQt::~PythonQt() {
204 210 delete _p;
205 211 _p = NULL;
206 212 }
207 213
208 214 PythonQtPrivate::~PythonQtPrivate() {
209 215 delete _defaultImporter;
210 216 _defaultImporter = NULL;
211 217
212 218 {
213 219 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
214 220 while (i.hasNext()) {
215 221 delete i.next().value();
216 222 }
217 223 }
218 224 PythonQtConv::global_valueStorage.clear();
219 225 PythonQtConv::global_ptrStorage.clear();
220 226 PythonQtConv::global_variantStorage.clear();
221 227
222 228 PythonQtMethodInfo::cleanupCachedMethodInfos();
223 229 }
224 230
225 231 void PythonQt::setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData)
226 232 {
227 233 if (!callback)
228 234 {
229 235 std::cerr << "PythonQt::setRedirectStdInCallback - callback parameter is NULL !" << std::endl;
230 236 return;
231 237 }
232 238
233 239 PythonQtObjectPtr sys;
234 240 PythonQtObjectPtr in;
235 241 sys.setNewRef(PyImport_ImportModule("sys"));
236 242
237 243 // Backup original 'sys.stdin' if not yet done
238 244 PyRun_SimpleString("if not hasattr(sys, 'pythonqt_original_stdin'):"
239 245 "sys.pythonqt_original_stdin = sys.stdin");
240 246
241 247 in = PythonQtStdInRedirectType.tp_new(&PythonQtStdInRedirectType, NULL, NULL);
242 248 ((PythonQtStdInRedirect*)in.object())->_cb = callback;
243 249 ((PythonQtStdInRedirect*)in.object())->_callData = callbackData;
244 250 // replace the built in file objects with our own objects
245 251 PyModule_AddObject(sys, "stdin", in);
246 252
247 253 // Backup custom 'stdin' into 'pythonqt_stdin'
248 254 PyRun_SimpleString("sys.pythonqt_stdin = sys.stdin");
249 255 }
250 256
251 257 void PythonQt::setRedirectStdInCallbackEnabled(bool enabled)
252 258 {
253 259 if (enabled)
254 260 {
255 261 PyRun_SimpleString("if hasattr(sys, 'pythonqt_stdin'):"
256 262 "sys.stdin = sys.pythonqt_stdin");
257 263 }
258 264 else
259 265 {
260 266 PyRun_SimpleString("if hasattr(sys,'pythonqt_original_stdin'):"
261 267 "sys.stdin = sys.pythonqt_original_stdin");
262 268 }
263 269 }
264 270
265 271 PythonQtImportFileInterface* PythonQt::importInterface()
266 272 {
267 273 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
268 274 }
269 275
270 276 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
271 277 {
272 278 if (_self->_p->_noLongerWrappedCB) {
273 279 (*_self->_p->_noLongerWrappedCB)(o);
274 280 };
275 281 }
276 282
277 283 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
278 284 {
279 285 _p->registerClass(metaobject, package, wrapperCreator, shell);
280 286 }
281 287
282 288 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
283 289 {
284 290 // we register all classes in the hierarchy
285 291 const QMetaObject* m = metaobject;
286 292 bool first = true;
287 293 while (m) {
288 294 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
289 295 if (!info->pythonQtClassWrapper()) {
290 296 info->setTypeSlots(typeSlots);
291 297 info->setupQObject(m);
292 298 createPythonQtClassWrapper(info, package, module);
293 299 if (m->superClass()) {
294 300 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
295 301 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
296 302 }
297 303 } else if (first && module) {
298 304 // There is a wrapper already, but if we got a module, we want to place the wrapper into that module as well,
299 305 // since it might have been placed into "private" earlier on.
300 306 // If the wrapper was already added to module before, it is just readded, which does no harm.
301 307 PyObject* classWrapper = info->pythonQtClassWrapper();
302 308 // AddObject steals a reference, so we need to INCREF
303 309 Py_INCREF(classWrapper);
304 310 PyModule_AddObject(module, info->className(), classWrapper);
305 311 }
306 312 if (first) {
307 313 first = false;
308 314 if (wrapperCreator) {
309 315 info->setDecoratorProvider(wrapperCreator);
310 316 }
311 317 if (shell) {
312 318 info->setShellSetInstanceWrapperCB(shell);
313 319 }
314 320 }
315 321 m = m->superClass();
316 322 }
317 323 }
318 324
319 325 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
320 326 {
321 327 PyObject* pack = module?module:packageByName(package);
322 328 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
323 329 PyModule_AddObject(pack, info->className(), pyobj);
324 330 if (!module && package && strncmp(package,"Qt",2)==0) {
325 331 // since PyModule_AddObject steals the reference, we need a incref once more...
326 332 Py_INCREF(pyobj);
327 333 // put all qt objects into Qt as well
328 334 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
329 335 }
330 336 info->setPythonQtClassWrapper(pyobj);
331 337 }
332 338
333 339 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
334 340 {
335 341 if (!obj) {
336 342 Py_INCREF(Py_None);
337 343 return Py_None;
338 344 }
339 345 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
340 346 if (!wrap) {
341 347 // smuggling it in...
342 348 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
343 349 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
344 350 registerClass(obj->metaObject());
345 351 classInfo = _knownClassInfos.value(obj->metaObject()->className());
346 352 }
347 353 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
348 354 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
349 355 } else {
350 356 Py_INCREF(wrap);
351 357 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
352 358 }
353 359 return (PyObject*)wrap;
354 360 }
355 361
356 362 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
357 363 {
358 364 if (!ptr) {
359 365 Py_INCREF(Py_None);
360 366 return Py_None;
361 367 }
362 368
363 369 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
364 370 if (!wrap) {
365 371 PythonQtClassInfo* info = _knownClassInfos.value(name);
366 372 if (!info) {
367 373 // maybe it is a PyObject, which we can return directly
368 374 if (name == "PyObject") {
369 375 PyObject* p = (PyObject*)ptr;
370 376 Py_INCREF(p);
371 377 return p;
372 378 }
373 379
374 380 // we do not know the metaobject yet, but we might know it by it's name:
375 381 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
376 382 // yes, we know it, so we can convert to QObject
377 383 QObject* qptr = (QObject*)ptr;
378 384 registerClass(qptr->metaObject());
379 385 info = _knownClassInfos.value(qptr->metaObject()->className());
380 386 }
381 387 }
382 388 if (info && info->isQObject()) {
383 389 QObject* qptr = (QObject*)ptr;
384 390 // if the object is a derived object, we want to switch the class info to the one of the derived class:
385 391 if (name!=(qptr->metaObject()->className())) {
386 392 registerClass(qptr->metaObject());
387 393 info = _knownClassInfos.value(qptr->metaObject()->className());
388 394 }
389 395 wrap = createNewPythonQtInstanceWrapper(qptr, info);
390 396 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
391 397 return (PyObject*)wrap;
392 398 }
393 399
394 400 // not a known QObject, try to wrap via foreign wrapper factories
395 401 PyObject* foreignWrapper = NULL;
396 402 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
397 403 foreignWrapper = _foreignWrapperFactories.at(i)->wrap(name, ptr);
398 404 if (foreignWrapper) {
399 405 return foreignWrapper;
400 406 }
401 407 }
402 408
403 409 // not a known QObject, so try our wrapper factory:
404 410 QObject* wrapper = NULL;
405 411 for (int i=0; i<_cppWrapperFactories.size(); i++) {
406 412 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
407 413 if (wrapper) {
408 414 break;
409 415 }
410 416 }
411 417
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) {
418 438 // still unknown, register as CPP class
419 439 registerCPPClass(name.constData());
420 440 info = _knownClassInfos.value(name);
421 441 }
422 442 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
423 443 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
424 444 info->setMetaObject(wrapper->metaObject());
425 445 }
426 446
427 447 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
428 448 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
429 449 } else {
430 450 Py_INCREF(wrap);
431 451 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
432 452 }
433 453 return (PyObject*)wrap;
434 454 }
435 455
436 456 PyObject* PythonQtPrivate::dummyTuple() {
437 457 static PyObject* dummyTuple = NULL;
438 458 if (dummyTuple==NULL) {
439 459 dummyTuple = PyTuple_New(1);
440 460 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
441 461 }
442 462 return dummyTuple;
443 463 }
444 464
445 465
446 466 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
447 467 // call the associated class type to create a new instance...
448 468 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
449 469
450 470 result->setQObject(obj);
451 471 result->_wrappedPtr = wrappedPtr;
452 472 result->_ownedByPythonQt = false;
453 473 result->_useQMetaTypeDestroy = false;
454 474
455 475 if (wrappedPtr) {
456 476 _wrappedObjects.insert(wrappedPtr, result);
457 477 } else {
458 478 _wrappedObjects.insert(obj, result);
459 479 if (obj->parent()== NULL && _wrappedCB) {
460 480 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
461 481 (*_wrappedCB)(obj);
462 482 }
463 483 }
464 484 return result;
465 485 }
466 486
467 487 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
468 488 PythonQtClassWrapper* result;
469 489
470 490 PyObject* className = PyString_FromString(info->className());
471 491
472 492 PyObject* baseClasses = PyTuple_New(1);
473 493 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
474 494
475 495 PyObject* typeDict = PyDict_New();
476 496 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
477 497 PyDict_SetItemString(typeDict, "__module__", moduleName);
478 498
479 499 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
480 500
481 501 // set the class info so that PythonQtClassWrapper_new can read it
482 502 _currentClassInfoForClassWrapperCreation = info;
483 503 // create the new type object by calling the type
484 504 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
485 505
486 506 Py_DECREF(baseClasses);
487 507 Py_DECREF(typeDict);
488 508 Py_DECREF(args);
489 509 Py_DECREF(className);
490 510
491 511 return result;
492 512 }
493 513
494 514 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
495 515 {
496 516 PyObject* args = Py_BuildValue("(i)", enumValue);
497 517 PyObject* result = PyObject_Call(enumType, args, NULL);
498 518 Py_DECREF(args);
499 519 return result;
500 520 }
501 521
502 522 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
503 523 PyObject* result;
504 524
505 525 PyObject* className = PyString_FromString(enumName);
506 526
507 527 PyObject* baseClasses = PyTuple_New(1);
508 528 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
509 529
510 530 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
511 531 PyObject* typeDict = PyDict_New();
512 532 PyDict_SetItemString(typeDict, "__module__", module);
513 533
514 534 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
515 535
516 536 // create the new int derived type object by calling the core type
517 537 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
518 538
519 539 Py_DECREF(baseClasses);
520 540 Py_DECREF(typeDict);
521 541 Py_DECREF(args);
522 542 Py_DECREF(className);
523 543
524 544 return result;
525 545 }
526 546
527 547 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
528 548 {
529 549 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
530 550 if (!r) {
531 551 r = new PythonQtSignalReceiver(obj);
532 552 _p->_signalReceivers.insert(obj, r);
533 553 }
534 554 return r;
535 555 }
536 556
537 557 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
538 558 {
539 559 bool flag = false;
540 560 PythonQtObjectPtr callable = lookupCallable(module, objectname);
541 561 if (callable) {
542 562 PythonQtSignalReceiver* r = getSignalReceiver(obj);
543 563 flag = r->addSignalHandler(signal, callable);
544 564 if (!flag) {
545 565 // signal not found
546 566 }
547 567 } else {
548 568 // callable not found
549 569 }
550 570 return flag;
551 571 }
552 572
553 573 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
554 574 {
555 575 bool flag = false;
556 576 PythonQtSignalReceiver* r = getSignalReceiver(obj);
557 577 if (r) {
558 578 flag = r->addSignalHandler(signal, receiver);
559 579 }
560 580 return flag;
561 581 }
562 582
563 583 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
564 584 {
565 585 bool flag = false;
566 586 PythonQtObjectPtr callable = lookupCallable(module, objectname);
567 587 if (callable) {
568 588 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
569 589 if (r) {
570 590 flag = r->removeSignalHandler(signal, callable);
571 591 }
572 592 } else {
573 593 // callable not found
574 594 }
575 595 return flag;
576 596 }
577 597
578 598 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
579 599 {
580 600 bool flag = false;
581 601 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
582 602 if (r) {
583 603 flag = r->removeSignalHandler(signal, receiver);
584 604 }
585 605 return flag;
586 606 }
587 607
588 608 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
589 609 {
590 610 PythonQtObjectPtr p = lookupObject(module, name);
591 611 if (p) {
592 612 if (PyCallable_Check(p)) {
593 613 return p;
594 614 }
595 615 }
596 616 PyErr_Clear();
597 617 return NULL;
598 618 }
599 619
600 620 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
601 621 {
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;
609 628 b = (*i).toLatin1();
610 629 if (PyDict_Check(p)) {
611 630 p = PyDict_GetItemString(p, b.data());
612 631 } else {
613 632 p.setNewRef(PyObject_GetAttrString(p, b.data()));
614 633 }
615 634 }
616 635 PyErr_Clear();
617 636 return p;
618 637 }
619 638
620 639 PythonQtObjectPtr PythonQt::getMainModule() {
621 640 //both borrowed
622 641 PythonQtObjectPtr dict = PyImport_GetModuleDict();
623 642 return PyDict_GetItemString(dict, "__main__");
624 643 }
625 644
626 645 PythonQtObjectPtr PythonQt::importModule(const QString& name)
627 646 {
628 647 PythonQtObjectPtr mod;
629 648 mod.setNewRef(PyImport_ImportModule(name.toLatin1().constData()));
630 649 return mod;
631 650 }
632 651
633 652
634 653 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
635 654 QVariant result;
636 655 if (pycode) {
637 656 PyObject* dict = NULL;
638 657 if (PyModule_Check(object)) {
639 658 dict = PyModule_GetDict(object);
640 659 } else if (PyDict_Check(object)) {
641 660 dict = object;
642 661 }
643 662 PyObject* r = NULL;
644 663 if (dict) {
645 664 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
646 665 }
647 666 if (r) {
648 667 result = PythonQtConv::PyObjToQVariant(r);
649 668 Py_DECREF(r);
650 669 } else {
651 670 handleError();
652 671 }
653 672 } else {
654 673 handleError();
655 674 }
656 675 return result;
657 676 }
658 677
659 678 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
660 679 {
661 680 QVariant result;
662 681 PythonQtObjectPtr p;
663 682 PyObject* dict = NULL;
664 683 if (PyModule_Check(object)) {
665 684 dict = PyModule_GetDict(object);
666 685 } else if (PyDict_Check(object)) {
667 686 dict = object;
668 687 }
669 688 if (dict) {
670 689 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
671 690 }
672 691 if (p) {
673 692 result = PythonQtConv::PyObjToQVariant(p);
674 693 } else {
675 694 handleError();
676 695 }
677 696 return result;
678 697 }
679 698
680 699 void PythonQt::evalFile(PyObject* module, const QString& filename)
681 700 {
682 701 PythonQtObjectPtr code = parseFile(filename);
683 702 if (code) {
684 703 evalCode(module, code);
685 704 } else {
686 705 handleError();
687 706 }
688 707 }
689 708
690 709 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
691 710 {
692 711 PythonQtObjectPtr p;
693 712 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
694 713 if (!p) {
695 714 handleError();
696 715 }
697 716 return p;
698 717 }
699 718
700 719 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
701 720 {
702 721 PythonQtObjectPtr code = parseFile(filename);
703 722 PythonQtObjectPtr module = _p->createModule(name, code);
704 723 return module;
705 724 }
706 725
707 726 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
708 727 {
709 728 PyErr_Clear();
710 729 QString scriptCode = script;
711 730 if (scriptCode.isEmpty()) {
712 731 // we always need at least a linefeed
713 732 scriptCode = "\n";
714 733 }
715 734 PythonQtObjectPtr pycode;
716 735 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
717 736 PythonQtObjectPtr module = _p->createModule(name, pycode);
718 737 return module;
719 738 }
720 739
721 740 PythonQtObjectPtr PythonQt::createUniqueModule()
722 741 {
723 742 static QString pyQtStr("PythonQt_module");
724 743 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
725 744 return createModuleFromScript(moduleName);
726 745 }
727 746
728 747 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
729 748 {
730 749 if (PyModule_Check(object)) {
731 750 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
732 751 } else if (PyDict_Check(object)) {
733 752 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
734 753 } else {
735 754 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
736 755 }
737 756 }
738 757
739 758 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
740 759 {
741 760 if (PyModule_Check(object)) {
742 761 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
743 762 } else if (PyDict_Check(object)) {
744 763 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
745 764 } else {
746 765 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
747 766 }
748 767 }
749 768
750 769 void PythonQt::removeVariable(PyObject* object, const QString& name)
751 770 {
752 771 if (PyDict_Check(object)) {
753 772 PyDict_DelItemString(object, name.toLatin1().data());
754 773 } else {
755 774 PyObject_DelAttrString(object, name.toLatin1().data());
756 775 }
757 776 }
758 777
759 778 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
760 779 {
761 780 QVariant result;
762 781 PythonQtObjectPtr obj = lookupObject(object, objectname);
763 782 if (obj) {
764 783 result = PythonQtConv::PyObjToQVariant(obj);
765 784 }
766 785 return result;
767 786 }
768 787
769 788 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
770 789 {
771 790 QStringList results;
772 791
773 792 PythonQtObjectPtr object;
774 793 if (objectname.isEmpty()) {
775 794 object = module;
776 795 } else {
777 796 object = lookupObject(module, objectname);
778 797 if (!object && type == CallOverloads) {
779 798 PyObject* dict = lookupObject(module, "__builtins__");
780 799 if (dict) {
781 800 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
782 801 }
783 802 }
784 803 }
785 804
786 805 if (object) {
806 results = introspectObject(object, type);
807 }
808
809 return results;
810 }
811
812 QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
813 {
814 QStringList results;
815
787 816 if (type == CallOverloads) {
788 817 if (PythonQtSlotFunction_Check(object)) {
789 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.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;
790 827 PythonQtSlotInfo* info = o->m_ml;
791 828
792 829 while (info) {
793 830 results << info->fullSignature();
794 831 info = info->nextInfo();
795 832 }
796 833 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
797 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
834 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
798 835 PythonQtSlotInfo* info = o->classInfo()->constructors();
799 836
800 837 while (info) {
801 838 results << info->fullSignature();
802 839 info = info->nextInfo();
803 840 }
804 841 } else {
805 //TODO: use pydoc!
842 QString signature = _p->getSignature(object);
843 if (!signature.isEmpty()) {
844 results << signature;
845 } else {
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 }
812 853 } else {
813 854 PyObject* keys = NULL;
814 855 bool isDict = false;
815 856 if (PyDict_Check(object)) {
816 857 keys = PyDict_Keys(object);
817 858 isDict = true;
818 859 } else {
819 860 keys = PyObject_Dir(object);
820 861 }
821 862 if (keys) {
822 863 int count = PyList_Size(keys);
823 864 PyObject* key;
824 865 PyObject* value;
825 866 QString keystr;
826 867 for (int i = 0;i<count;i++) {
827 868 key = PyList_GetItem(keys,i);
828 869 if (isDict) {
829 870 value = PyDict_GetItem(object, key);
830 871 Py_INCREF(value);
831 872 } else {
832 873 value = PyObject_GetAttr(object, key);
833 874 }
834 875 if (!value) continue;
835 876 keystr = PyString_AsString(key);
836 877 static const QString underscoreStr("__tmp");
837 878 if (!keystr.startsWith(underscoreStr)) {
838 879 switch (type) {
839 880 case Anything:
840 881 results << keystr;
841 882 break;
842 883 case Class:
843 if (value->ob_type == &PyClass_Type) {
884 if (value->ob_type == &PyClass_Type || value->ob_type == &PyType_Type) {
844 885 results << keystr;
845 886 }
846 887 break;
847 888 case Variable:
848 889 if (value->ob_type != &PyClass_Type
849 890 && value->ob_type != &PyCFunction_Type
850 891 && value->ob_type != &PyFunction_Type
892 && value->ob_type != &PyMethod_Type
851 893 && value->ob_type != &PyModule_Type
894 && value->ob_type != &PyType_Type
895 && value->ob_type != &PythonQtSlotFunction_Type
852 896 ) {
853 897 results << keystr;
854 898 }
855 899 break;
856 900 case Function:
857 if (value->ob_type == &PyFunction_Type ||
858 value->ob_type == &PyMethod_Type
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
859 905 ) {
860 906 results << keystr;
861 907 }
862 908 break;
863 909 case Module:
864 910 if (value->ob_type == &PyModule_Type) {
865 911 results << keystr;
866 912 }
867 913 break;
868 914 default:
869 915 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
870 916 }
871 917 }
872 918 Py_DECREF(value);
873 919 }
874 920 Py_DECREF(keys);
875 921 }
876 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());
965 }
966 }
967 if (object) {
968 results = introspectObject(object, type);
969 Py_DECREF(object);
877 970 }
878 971 return results;
879 972 }
880 973
881 974 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
882 975 {
883 976 PythonQtObjectPtr callable = lookupCallable(object, name);
884 977 if (callable) {
885 978 return call(callable, args);
886 979 } else {
887 980 return QVariant();
888 981 }
889 982 }
890 983
891 984 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
892 985 {
893 986 QVariant r;
894 987 PythonQtObjectPtr result;
895 988 result.setNewRef(callAndReturnPyObject(callable, args));
896 989 if (result) {
897 990 r = PythonQtConv::PyObjToQVariant(result);
898 991 } else {
899 992 PythonQt::self()->handleError();
900 993 }
901 994 return r;
902 995 }
903 996
904 997 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args)
905 998 {
906 999 PyObject* result = NULL;
907 1000 if (callable) {
908 1001 PythonQtObjectPtr pargs;
909 1002 int count = args.size();
910 1003 if (count>0) {
911 1004 pargs.setNewRef(PyTuple_New(count));
912 1005 }
913 1006 bool err = false;
914 1007 // transform QVariants to Python
915 1008 for (int i = 0; i < count; i++) {
916 1009 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
917 1010 if (arg) {
918 1011 // steals reference, no unref
919 1012 PyTuple_SetItem(pargs, i,arg);
920 1013 } else {
921 1014 err = true;
922 1015 break;
923 1016 }
924 1017 }
925 1018
926 1019 if (!err) {
927 1020 PyErr_Clear();
928 1021 result = PyObject_CallObject(callable, pargs);
929 1022 }
930 1023 }
931 1024 return result;
932 1025 }
933 1026
934 1027 void PythonQt::addInstanceDecorators(QObject* o)
935 1028 {
936 1029 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
937 1030 }
938 1031
939 1032 void PythonQt::addClassDecorators(QObject* o)
940 1033 {
941 1034 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
942 1035 }
943 1036
944 1037 void PythonQt::addDecorators(QObject* o)
945 1038 {
946 1039 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
947 1040 }
948 1041
949 1042 void PythonQt::registerQObjectClassNames(const QStringList& names)
950 1043 {
951 1044 _p->registerQObjectClassNames(names);
952 1045 }
953 1046
954 1047 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
955 1048 {
956 1049 _p->_importInterface = importInterface;
957 1050 PythonQtImport::init();
958 1051 }
959 1052
960 1053 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
961 1054 {
962 1055 _p->_importIgnorePaths = paths;
963 1056 }
964 1057
965 1058 const QStringList& PythonQt::getImporterIgnorePaths()
966 1059 {
967 1060 return _p->_importIgnorePaths;
968 1061 }
969 1062
970 1063 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
971 1064 {
972 1065 _p->_cppWrapperFactories.append(factory);
973 1066 }
974 1067
975 1068 void PythonQt::addWrapperFactory( PythonQtForeignWrapperFactory* factory )
976 1069 {
977 1070 _p->_foreignWrapperFactories.append(factory);
978 1071 }
979 1072
980 1073 //---------------------------------------------------------------------------------------------------
981 1074 PythonQtPrivate::PythonQtPrivate()
982 1075 {
983 1076 _importInterface = NULL;
984 1077 _defaultImporter = new PythonQtQFileImporter;
985 1078 _noLongerWrappedCB = NULL;
986 1079 _wrappedCB = NULL;
987 1080 _currentClassInfoForClassWrapperCreation = NULL;
988 1081 _profilingCB = NULL;
989 1082 }
990 1083
991 1084 void PythonQtPrivate::setupSharedLibrarySuffixes()
992 1085 {
993 1086 _sharedLibrarySuffixes.clear();
994 1087 PythonQtObjectPtr imp;
995 1088 imp.setNewRef(PyImport_ImportModule("imp"));
996 1089 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
997 1090 QVariant result = imp.call("get_suffixes");
998 1091 #ifdef __linux
999 1092 #ifdef _DEBUG
1000 1093 // First look for shared libraries with the '_d' suffix in debug mode on Linux.
1001 1094 // This is a workaround, because python does not append the '_d' suffix on Linux
1002 1095 // and would always load the release library otherwise.
1003 1096 _sharedLibrarySuffixes << "_d.so";
1004 1097 #endif
1005 1098 #endif
1006 1099 foreach (QVariant entry, result.toList()) {
1007 1100 QVariantList suffixEntry = entry.toList();
1008 1101 if (suffixEntry.count()==3) {
1009 1102 int code = suffixEntry.at(2).toInt();
1010 1103 if (code == cExtensionCode) {
1011 1104 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
1012 1105 }
1013 1106 }
1014 1107 }
1015 1108 }
1016 1109
1017 1110 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
1018 1111 {
1019 1112 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
1020 1113 _currentClassInfoForClassWrapperCreation = NULL;
1021 1114 return info;
1022 1115 }
1023 1116
1024 1117 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
1025 1118 {
1026 1119 o->setParent(this);
1027 1120 int numMethods = o->metaObject()->methodCount();
1028 1121 for (int i = 0; i < numMethods; i++) {
1029 1122 QMetaMethod m = o->metaObject()->method(i);
1030 1123 if ((m.methodType() == QMetaMethod::Method ||
1031 1124 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
1032 1125 if (qstrncmp(m.signature(), "new_", 4)==0) {
1033 1126 if ((decoTypes & ConstructorDecorator) == 0) continue;
1034 1127 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1035 1128 if (info->parameters().at(0).pointerCount == 1) {
1036 1129 QByteArray signature = m.signature();
1037 1130 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
1038 1131 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1039 1132 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1040 1133 classInfo->addConstructor(newSlot);
1041 1134 }
1042 1135 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
1043 1136 if ((decoTypes & DestructorDecorator) == 0) continue;
1044 1137 QByteArray signature = m.signature();
1045 1138 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
1046 1139 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1047 1140 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1048 1141 classInfo->setDestructor(newSlot);
1049 1142 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
1050 1143 if ((decoTypes & StaticDecorator) == 0) continue;
1051 1144 QByteArray signature = m.signature();
1052 1145 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
1053 1146 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
1054 1147 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1055 1148 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1056 1149 classInfo->addDecoratorSlot(newSlot);
1057 1150 } else {
1058 1151 if ((decoTypes & InstanceDecorator) == 0) continue;
1059 1152 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1060 1153 if (info->parameters().count()>1) {
1061 1154 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
1062 1155 if (p.pointerCount==1) {
1063 1156 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
1064 1157 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
1065 1158 classInfo->addDecoratorSlot(newSlot);
1066 1159 }
1067 1160 }
1068 1161 }
1069 1162 }
1070 1163 }
1071 1164 }
1072 1165
1073 1166 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
1074 1167 {
1075 1168 foreach(QString name, names) {
1076 1169 _knownQObjectClassNames.insert(name.toLatin1(), true);
1077 1170 }
1078 1171 }
1079 1172
1080 1173 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
1081 1174 {
1082 1175 _signalReceivers.remove(obj);
1083 1176 }
1084 1177
1085 1178 bool PythonQt::handleError()
1086 1179 {
1087 1180 bool flag = false;
1088 1181 if (PyErr_Occurred()) {
1089 1182
1090 1183 // currently we just print the error and the stderr handler parses the errors
1091 1184 PyErr_Print();
1092 1185
1093 1186 /*
1094 1187 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1095 1188 PyObject *ptype;
1096 1189 PyObject *pvalue;
1097 1190 PyObject *ptraceback;
1098 1191 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1099 1192
1100 1193 Py_XDECREF(ptype);
1101 1194 Py_XDECREF(pvalue);
1102 1195 Py_XDECREF(ptraceback);
1103 1196 */
1104 1197 PyErr_Clear();
1105 1198 flag = true;
1106 1199 }
1107 1200 return flag;
1108 1201 }
1109 1202
1110 1203 void PythonQt::addSysPath(const QString& path)
1111 1204 {
1112 1205 PythonQtObjectPtr sys;
1113 1206 sys.setNewRef(PyImport_ImportModule("sys"));
1114 1207 PythonQtObjectPtr obj = lookupObject(sys, "path");
1115 1208 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1116 1209 }
1117 1210
1118 1211 void PythonQt::overwriteSysPath(const QStringList& paths)
1119 1212 {
1120 1213 PythonQtObjectPtr sys;
1121 1214 sys.setNewRef(PyImport_ImportModule("sys"));
1122 1215 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1123 1216 }
1124 1217
1125 1218 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1126 1219 {
1127 1220 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1128 1221 }
1129 1222
1130 1223 void PythonQt::stdOutRedirectCB(const QString& str)
1131 1224 {
1132 1225 if (!PythonQt::self()) {
1133 1226 std::cout << str.toLatin1().data() << std::endl;
1134 1227 return;
1135 1228 }
1136 1229 emit PythonQt::self()->pythonStdOut(str);
1137 1230 }
1138 1231
1139 1232 void PythonQt::stdErrRedirectCB(const QString& str)
1140 1233 {
1141 1234 if (!PythonQt::self()) {
1142 1235 std::cerr << str.toLatin1().data() << std::endl;
1143 1236 return;
1144 1237 }
1145 1238 emit PythonQt::self()->pythonStdErr(str);
1146 1239 }
1147 1240
1148 1241 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1149 1242 {
1150 1243 _p->_wrappedCB = cb;
1151 1244 }
1152 1245
1153 1246 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1154 1247 {
1155 1248 _p->_noLongerWrappedCB = cb;
1156 1249 }
1157 1250
1158 1251 void PythonQt::setProfilingCallback(ProfilingCB* cb)
1159 1252 {
1160 1253 _p->_profilingCB = cb;
1161 1254 }
1162 1255
1163 1256
1164 1257 static PyMethodDef PythonQtMethods[] = {
1165 1258 {NULL, NULL, 0, NULL}
1166 1259 };
1167 1260
1168 1261 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1169 1262 {
1170 1263 QByteArray name = "PythonQt";
1171 1264 if (!pythonQtModuleName.isEmpty()) {
1172 1265 name = pythonQtModuleName;
1173 1266 }
1174 1267 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1175 1268 _p->_pythonQtModuleName = name;
1176 1269
1177 1270 if (redirectStdOut) {
1178 1271 PythonQtObjectPtr sys;
1179 1272 PythonQtObjectPtr out;
1180 1273 PythonQtObjectPtr err;
1181 1274 sys.setNewRef(PyImport_ImportModule("sys"));
1182 1275 // create a redirection object for stdout and stderr
1183 1276 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1184 1277 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1185 1278 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1186 1279 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1187 1280 // replace the built in file objects with our own objects
1188 1281 PyModule_AddObject(sys, "stdout", out);
1189 1282 PyModule_AddObject(sys, "stderr", err);
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);
1196 1390 }
1197 1391
1198 1392
1199 1393 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1200 1394 {
1201 1395 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1202 1396 if (!info) {
1203 1397 info = new PythonQtClassInfo();
1204 1398 info->setupCPPObject(typeName);
1205 1399 _knownClassInfos.insert(typeName, info);
1206 1400 }
1207 1401 return info;
1208 1402 }
1209 1403
1210 1404 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1211 1405 {
1212 1406 _p->addPolymorphicHandler(typeName, cb);
1213 1407 }
1214 1408
1215 1409 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1216 1410 {
1217 1411 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1218 1412 info->addPolymorphicHandler(cb);
1219 1413 }
1220 1414
1221 1415 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1222 1416 {
1223 1417 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1224 1418 }
1225 1419
1226 1420 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1227 1421 {
1228 1422 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1229 1423 if (info) {
1230 1424 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1231 1425 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1232 1426 return true;
1233 1427 } else {
1234 1428 return false;
1235 1429 }
1236 1430 }
1237 1431
1238 1432 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1239 1433 {
1240 1434 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1241 1435 if (!info->pythonQtClassWrapper()) {
1242 1436 info->setTypeSlots(typeSlots);
1243 1437 info->setupCPPObject(typeName);
1244 1438 createPythonQtClassWrapper(info, package, module);
1245 1439 }
1246 1440 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1247 1441 addParentClass(typeName, parentTypeName, 0);
1248 1442 }
1249 1443 if (wrapperCreator) {
1250 1444 info->setDecoratorProvider(wrapperCreator);
1251 1445 }
1252 1446 if (shell) {
1253 1447 info->setShellSetInstanceWrapperCB(shell);
1254 1448 }
1255 1449 }
1256 1450
1257 1451 PyObject* PythonQtPrivate::packageByName(const char* name)
1258 1452 {
1259 1453 if (name==NULL || name[0]==0) {
1260 1454 name = "private";
1261 1455 }
1262 1456 PyObject* v = _packages.value(name);
1263 1457 if (!v) {
1264 1458 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1265 1459 _packages.insert(name, v);
1266 1460 // AddObject steals the reference, so increment it!
1267 1461 Py_INCREF(v);
1268 1462 PyModule_AddObject(_pythonQtModule, name, v);
1269 1463 }
1270 1464 return v;
1271 1465 }
1272 1466
1273 1467 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1274 1468 {
1275 1469 QString error = "Return value '" + PythonQtConv::PyObjGetString(result) + "' can not be converted to expected C++ type '" + methodInfo->parameters().at(0).name + "' as return value of virtual method " + signature;
1276 1470 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1277 1471 PythonQt::self()->handleError();
1278 1472 }
1279 1473
1280 1474 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1281 1475 {
1282 1476 if (_p->_initFlags & ExternalHelp) {
1283 1477 emit pythonHelpRequest(QByteArray(info->className()));
1284 1478 return Py_BuildValue("");
1285 1479 } else {
1286 1480 return PyString_FromString(info->help().toLatin1().data());
1287 1481 }
1288 1482 }
1289 1483
1290 1484 void PythonQt::clearNotFoundCachedMembers()
1291 1485 {
1292 1486 foreach(PythonQtClassInfo* info, _p->_knownClassInfos) {
1293 1487 info->clearNotFoundCachedMembers();
1294 1488 }
1295 1489 }
1296 1490
1297 1491 void PythonQt::removeWrapperFactory( PythonQtCppWrapperFactory* factory )
1298 1492 {
1299 1493 _p->_cppWrapperFactories.removeAll(factory);
1300 1494 }
1301 1495
1302 1496 void PythonQt::removeWrapperFactory( PythonQtForeignWrapperFactory* factory )
1303 1497 {
1304 1498 _p->_foreignWrapperFactories.removeAll(factory);
1305 1499 }
1306 1500
1307 1501 void PythonQtPrivate::removeWrapperPointer(void* obj)
1308 1502 {
1309 1503 _wrappedObjects.remove(obj);
1310 1504 }
1311 1505
1312 1506 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1313 1507 {
1314 1508 _wrappedObjects.insert(obj, wrapper);
1315 1509 }
1316 1510
1317 1511 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1318 1512 {
1319 1513 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1320 1514 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1321 1515 // this is a wrapper whose QObject was already removed due to destruction
1322 1516 // so the obj pointer has to be a new QObject with the same address...
1323 1517 // we remove the old one and set the copy to NULL
1324 1518 wrap->_objPointerCopy = NULL;
1325 1519 removeWrapperPointer(obj);
1326 1520 wrap = NULL;
1327 1521 }
1328 1522 return wrap;
1329 1523 }
1330 1524
1331 1525 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1332 1526 {
1333 1527 PythonQtObjectPtr result;
1334 1528 if (pycode) {
1335 1529 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1336 1530 } else {
1337 1531 PythonQt::self()->handleError();
1338 1532 }
1339 1533 return result;
1340 1534 }
1341 1535
1342 1536 void* PythonQtPrivate::unwrapForeignWrapper( const QByteArray& classname, PyObject* obj )
1343 1537 {
1344 1538 void* foreignObject = NULL;
1345 1539 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
1346 1540 foreignObject = _foreignWrapperFactories.at(i)->unwrap(classname, obj);
1347 1541 if (foreignObject) {
1348 1542 return foreignObject;
1349 1543 }
1350 1544 }
1351 1545 return NULL;
1352 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 }
@@ -1,690 +1,711
1 1 #ifndef _PYTHONQT_H
2 2 #define _PYTHONQT_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQt.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46 #include "PythonQtInstanceWrapper.h"
47 47 #include "PythonQtClassWrapper.h"
48 48 #include "PythonQtSlot.h"
49 49 #include "PythonQtObjectPtr.h"
50 50 #include "PythonQtStdIn.h"
51 51 #include <QObject>
52 52 #include <QVariant>
53 53 #include <QList>
54 54 #include <QHash>
55 55 #include <QByteArray>
56 56 #include <QStringList>
57 57 #include <QtDebug>
58 58 #include <iostream>
59 59
60 60
61 61 class PythonQtClassInfo;
62 62 class PythonQtPrivate;
63 63 class PythonQtMethodInfo;
64 64 class PythonQtSignalReceiver;
65 65 class PythonQtImportFileInterface;
66 66 class PythonQtCppWrapperFactory;
67 67 class PythonQtForeignWrapperFactory;
68 68 class PythonQtQFileImporter;
69 69
70 70 typedef void PythonQtQObjectWrappedCB(QObject* object);
71 71 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
72 72 typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, const char **class_name);
73 73
74 74 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
75 75
76 76 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) {
77 77 (reinterpret_cast<T*>(object))->_wrapper = wrapper;
78 78 }
79 79
80 80 //! returns the offset that needs to be added to upcast an object of type T1 to T2
81 81 template<class T1, class T2> int PythonQtUpcastingOffset() {
82 82 return ((reinterpret_cast<char*>(static_cast<T2*>(reinterpret_cast<T1*>(0x100))))
83 83 - (reinterpret_cast<char*>(reinterpret_cast<T1*>(0x100))));
84 84 }
85 85
86 86 //! callback to create a QObject lazily
87 87 typedef QObject* PythonQtQObjectCreatorFunctionCB();
88 88
89 89 //! helper template to create a derived QObject class
90 90 template<class T> QObject* PythonQtCreateObject() { return new T(); };
91 91
92 92 //! The main interface to the Python Qt binding, realized as a singleton
93 93 /*!
94 94 Use PythonQt::init() to initialize the singleton and PythonQt::self() to access it.
95 95 While there can be only one PythonQt instance, you can have any number of Python context to do scripting in.
96 96 One possibility is to use createModuleFromFile(), createModuleFromScript() or createUniqueModule() to get a context
97 97 that is separated from the other contexts. Alternatively you can use Python dicts as contexts for script evaluation,
98 98 but you will need to populate the dict with the __builtins__ instance to have all Pythons available when running
99 99 code in the scope of a dict.
100 100 */
101 101 class PYTHONQT_EXPORT PythonQt : public QObject {
102 102
103 103 Q_OBJECT
104 104
105 105 public:
106 106
107 107 //! flags that can be passed to PythonQt::init()
108 108 enum InitFlags {
109 109 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
110 110 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
111 111 ExternalHelp = 4, //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
112 112 PythonAlreadyInitialized = 8 //!<< sets that PythonQt should not can PyInitialize, since it is already done
113 113 };
114 114
115 115 //! flags that tell PythonQt which operators to expect on the registered type
116 116 enum TypeSlots {
117 117 Type_Add = 1,
118 118 Type_Subtract = 1 << 1,
119 119 Type_Multiply = 1 << 2,
120 120 Type_Divide = 1 << 3,
121 121 Type_Mod = 1 << 4,
122 122 Type_And = 1 << 5,
123 123 Type_Or = 1 << 6,
124 124 Type_Xor = 1 << 7,
125 125 Type_LShift = 1 << 8,
126 126 Type_RShift = 1 << 9,
127 127
128 128 Type_InplaceAdd = 1 << 10,
129 129 Type_InplaceSubtract = 1 << 11,
130 130 Type_InplaceMultiply = 1 << 12,
131 131 Type_InplaceDivide = 1 << 13,
132 132 Type_InplaceMod = 1 << 14,
133 133 Type_InplaceAnd = 1 << 15,
134 134 Type_InplaceOr = 1 << 16,
135 135 Type_InplaceXor = 1 << 17,
136 136 Type_InplaceLShift = 1 << 18,
137 137 Type_InplaceRShift = 1 << 19,
138 138
139 139 // Not yet needed/nicely mappable/generated...
140 140 //Type_Positive = 1 << 29,
141 141 //Type_Negative = 1 << 29,
142 142 //Type_Abs = 1 << 29,
143 143 //Type_Hash = 1 << 29,
144 144
145 145 Type_Invert = 1 << 29,
146 146 Type_RichCompare = 1 << 30,
147 147 Type_NonZero = 1 << 31,
148 148
149 149 };
150 150
151 151 //! enum for profiling callback
152 152 enum ProfilingCallbackState {
153 153 Enter = 1,
154 154 Leave = 2
155 155 };
156 156
157 157 //! callback for profiling. className and methodName are only passed when state == Enter, otherwise
158 158 //! they are NULL.
159 159 typedef void ProfilingCB(ProfilingCallbackState state, const char* className, const char* methodName);
160 160
161 161 //---------------------------------------------------------------------------
162 162 //! \name Singleton Initialization
163 163 //@{
164 164
165 165 //! initialize the python qt binding (flags are a or combination of PythonQt::InitFlags), if \c pythonQtModuleName is given
166 166 //! it defines the name of the python module that PythonQt will add, otherwise "PythonQt" is used.
167 167 //! This can be used to e.g. pass in PySide or PyQt4 to make it more compatible.
168 168 static void init(int flags = IgnoreSiteModule | RedirectStdOut, const QByteArray& pythonQtModuleName = QByteArray());
169 169
170 170 //! cleanup of the singleton
171 171 static void cleanup();
172 172
173 173 //! get the singleton instance
174 174 static PythonQt* self();
175 175
176 176 //@}
177 177
178 178 //! defines the object types for introspection
179 179 enum ObjectType {
180 180 Class,
181 181 Function,
182 182 Variable,
183 183 Module,
184 184 Anything,
185 185 CallOverloads
186 186 };
187 187
188 188
189 189 //---------------------------------------------------------------------------
190 190 //! \name Standard input handling
191 191 //@{
192 192
193 193 //! Overwrite default handling of stdin using a custom callback. It internally backup
194 194 //! the original 'sys.stdin' into 'sys.pythonqt_original_stdin'
195 195 void setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData = 0);
196 196
197 197 //! Enable or disable stdin custom callback. It resets 'sys.stdin' using either 'sys.pythonqt_stdin'
198 198 //! or 'sys.pythonqt_original_stdin'
199 199 void setRedirectStdInCallbackEnabled(bool enabled);
200 200
201 201 //@}
202 202
203 203 //---------------------------------------------------------------------------
204 204 //! \name Modules
205 205 //@{
206 206
207 207 //! get the __main__ module of python
208 208 PythonQtObjectPtr getMainModule();
209 209
210 210 //! import the given module and return a reference to it (useful to import e.g. "sys" and call something on it)
211 211 //! If a module is already imported, this returns the already imported module.
212 212 PythonQtObjectPtr importModule(const QString& name);
213 213
214 214 //! creates the new module \c name and evaluates the given file in the context of that module
215 215 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
216 216 //! to a module later on.
217 217 //! The user needs to make sure that the \c name is unique in the python module dictionary.
218 218 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
219 219
220 220 //! creates the new module \c name and evaluates the given script in the context of that module.
221 221 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
222 222 //! to a module later on.
223 223 //! The user needs to make sure that the \c name is unique in the python module dictionary.
224 224 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
225 225
226 226 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
227 227 //! script code
228 228 PythonQtObjectPtr createUniqueModule();
229 229
230 230 //@}
231 231
232 232 //---------------------------------------------------------------------------
233 233 //! \name Importing/Paths
234 234 //@{
235 235
236 236 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
237 237 void overwriteSysPath(const QStringList& paths);
238 238
239 239 //! prepend a path to sys.path to allow importing from it
240 240 void addSysPath(const QString& path);
241 241
242 242 //! sets the __path__ list of a module to the given list (important for local imports)
243 243 void setModuleImportPath(PyObject* module, const QStringList& paths);
244 244
245 245 //@}
246 246
247 247 //---------------------------------------------------------------------------
248 248 //! \name Registering Classes
249 249 //@{
250 250
251 251 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
252 252 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
253 253 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
254 254 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
255 255
256 256 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
257 257 //! (ownership of wrapper is passed to PythonQt)
258 258 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
259 259
260 260 This will add a wrapper object that is used to make calls to the given classname \c typeName.
261 261 All slots that take a pointer to typeName as the first argument will be callable from Python on
262 262 a variant object that contains such a type.
263 263 */
264 264 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
265 265
266 266 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
267 267 //! and it will register the classes when it first sees a pointer to such a derived class
268 268 void registerQObjectClassNames(const QStringList& names);
269 269
270 270 //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance
271 271 //! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that
272 272 //! type is really derived from parentType.
273 273 //! Returns false if the typeName was not yet registered.
274 274 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
275 275
276 276 //! add a handler for polymorphic downcasting
277 277 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
278 278
279 279 //@}
280 280
281 281 //---------------------------------------------------------------------------
282 282 //! \name Script Parsing and Evaluation
283 283 //@{
284 284
285 285 //! parses the given file and returns the python code object, this can then be used to call evalCode()
286 286 PythonQtObjectPtr parseFile(const QString& filename);
287 287
288 288 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
289 289 //! If pycode is NULL, a python error is printed.
290 290 QVariant evalCode(PyObject* object, PyObject* pycode);
291 291
292 292 //! evaluates the given script code and returns the result value
293 293 QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input);
294 294
295 295 //! evaluates the given script code from file
296 296 void evalFile(PyObject* object, const QString& filename);
297 297
298 298 //@}
299 299
300 300 //---------------------------------------------------------------------------
301 301 //! \name Signal Handlers
302 302 //@{
303 303
304 304 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
305 305 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
306 306
307 307 //! remove a signal handler from the given \c signal of \c obj
308 308 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
309 309
310 310 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
311 311 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
312 312
313 313 //! remove a signal handler from the given \c signal of \c obj
314 314 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
315 315
316 316 //@}
317 317
318 318 //---------------------------------------------------------------------------
319 319 //! \name Variable access
320 320 //@{
321 321
322 322 //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable)
323 323 void addObject(PyObject* object, const QString& name, QObject* qObject);
324 324
325 325 //! add the given variable to the object
326 326 void addVariable(PyObject* object, const QString& name, const QVariant& v);
327 327
328 328 //! remove the given variable
329 329 void removeVariable(PyObject* module, const QString& name);
330 330
331 331 //! get the variable with the \c name of the \c object, returns an invalid QVariant on error
332 332 QVariant getVariable(PyObject* object, const QString& name);
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 //---------------------------------------------------------------------------
344 355 //! \name Calling Python Objects
345 356 //@{
346 357
347 358 //! call the given python \c callable in the scope of object, returns the result converted to a QVariant
348 359 QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList());
349 360
350 361 //! call the given python object, returns the result converted to a QVariant
351 362 QVariant call(PyObject* callable, const QVariantList& args = QVariantList());
352 363
353 364 //! call the given python object, returns the result as new PyObject
354 365 PyObject* callAndReturnPyObject(PyObject* callable, const QVariantList& args = QVariantList());
355 366
356 367 //@}
357 368
358 369 //---------------------------------------------------------------------------
359 370 //! \name Decorations, Constructors, Wrappers...
360 371 //@{
361 372
362 373 //! add an object whose slots will be used as decorator slots for
363 374 //! other QObjects or CPP classes. The slots need to follow the
364 375 //! convention that the first argument is a pointer to the wrapped object.
365 376 //! (ownership is passed to PythonQt)
366 377 /*!
367 378 Example:
368 379
369 380 A slot with the signature
370 381
371 382 \code
372 383 bool doSomething(QWidget* w, int a)
373 384 \endcode
374 385
375 386 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
376 387 that will be called with the concrete instance as first argument.
377 388 So in Python you can now e.g. call
378 389
379 390 \code
380 391 someWidget.doSomething(12)
381 392 \endcode
382 393
383 394 without QWidget really having this method. This allows to easily make normal methods
384 395 of Qt classes callable by forwarding them with such decorator slots
385 396 or to make CPP classes (which are not derived from QObject) callable from Python.
386 397 */
387 398 void addInstanceDecorators(QObject* o);
388 399
389 400 //! add an object whose slots will be used as decorator slots for
390 401 //! class objects (ownership is passed to PythonQt)
391 402 /*!
392 403 The slots need to follow the following convention:
393 404 - SomeClass* new_SomeClass(...)
394 405 - QVariant new_SomeClass(...)
395 406 - void delete_SomeClass(SomeClass*)
396 407 - ... static_SomeClass_someName(...)
397 408
398 409 This will add:
399 410 - a constructor
400 411 - a constructor which generates a QVariant
401 412 - a destructor (only useful for CPP objects)
402 413 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
403 414
404 415 */
405 416 void addClassDecorators(QObject* o);
406 417
407 418 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
408 419 void addDecorators(QObject* o);
409 420
410 421 //! add the given factory to PythonQt (ownership stays with caller)
411 422 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
412 423
413 424 //! add the given factory to PythonQt (ownership stays with caller)
414 425 void addWrapperFactory(PythonQtForeignWrapperFactory* factory);
415 426
416 427 //! remove the wrapper factory
417 428 void removeWrapperFactory(PythonQtCppWrapperFactory* factory);
418 429
419 430 //! remove the wrapper factory
420 431 void removeWrapperFactory(PythonQtForeignWrapperFactory* factory);
421 432
422 433 //@}
423 434
424 435 //---------------------------------------------------------------------------
425 436 //! \name Custom Importer
426 437 //@{
427 438
428 439 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
429 440 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
430 441 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
431 442 //! This is not reversible, so even setting setImporter(NULL) afterwards will
432 443 //! keep the custom PythonQt importer with a QFile default import interface.
433 444 //! Subsequent python import calls will make use of the passed importInterface
434 445 //! which forwards all import calls to the given \c importInterface.
435 446 //! Passing NULL will install a default QFile importer.
436 447 //! (\c importInterface ownership stays with caller)
437 448 void setImporter(PythonQtImportFileInterface* importInterface);
438 449
439 450 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
440 451 //! (without calling setImporter or installDefaultImporter at least once, the default python import
441 452 //! mechanism is in place)
442 453 //! the default importer allows to import files from anywhere QFile can read from,
443 454 //! including the Qt resource system using ":". Keep in mind that you need to extend
444 455 //! "sys.path" with ":" to be able to import from the Qt resources.
445 456 void installDefaultImporter() { setImporter(NULL); }
446 457
447 458 //! set paths that the importer should ignore
448 459 void setImporterIgnorePaths(const QStringList& paths);
449 460
450 461 //! get paths that the importer should ignore
451 462 const QStringList& getImporterIgnorePaths();
452 463
453 464 //! get access to the file importer (if set)
454 465 static PythonQtImportFileInterface* importInterface();
455 466
456 467 //@}
457 468
458 469 //---------------------------------------------------------------------------
459 470 //! \name Other Stuff
460 471 //@{
461 472
462 473 //! get access to internal data (should not be used on the public API, but is used by some C functions)
463 474 static PythonQtPrivate* priv() { return _self->_p; }
464 475
465 476 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
466 477 //! The error is currently just output to the python stderr, future version might implement better trace printing
467 478 bool handleError();
468 479
469 480 //! clear all NotFound entries on all class infos, to ensure that
470 481 //! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded
471 482 void clearNotFoundCachedMembers();
472 483
473 484 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
474 485 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
475 486 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
476 487 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
477 488
478 489 //! call the callback if it is set
479 490 static void qObjectNoLongerWrappedCB(QObject* o);
480 491
481 492 //! called by internal help methods
482 493 PyObject* helpCalled(PythonQtClassInfo* info);
483 494
484 495 //! returns the found object or NULL
485 496 //! @return new reference
486 497 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
487 498
488 499 //! sets a callback that is called before and after function calls for profiling
489 500 void setProfilingCallback(ProfilingCB* cb);
490 501
491 502 //@}
492 503
493 504 signals:
494 505 //! emitted when python outputs something to stdout (and redirection is turned on)
495 506 void pythonStdOut(const QString& str);
496 507 //! emitted when python outputs something to stderr (and redirection is turned on)
497 508 void pythonStdErr(const QString& str);
498 509
499 510 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
500 511 void pythonHelpRequest(const QByteArray& cppClassName);
501 512
502 513 private:
503 514 void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName);
504 515
516 QString getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context);
517
518 PyObject* getObjectByType(const QString& typeName);
519
505 520 //! callback for stdout redirection, emits pythonStdOut signal
506 521 static void stdOutRedirectCB(const QString& str);
507 522 //! callback for stderr redirection, emits pythonStdErr signal
508 523 static void stdErrRedirectCB(const QString& str);
509 524
510 525 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
511 526 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
512 527
513 528 PythonQt(int flags, const QByteArray& pythonQtModuleName);
514 529 ~PythonQt();
515 530
516 531 static PythonQt* _self;
517 532 static int _uniqueModuleCount;
518 533
519 534 PythonQtPrivate* _p;
520 535
521 536 };
522 537
523 538 //! internal PythonQt details
524 539 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
525 540
526 541 Q_OBJECT
527 542
528 543 public:
529 544 PythonQtPrivate();
530 545 ~PythonQtPrivate();
531 546
532 547 enum DecoratorTypes {
533 548 StaticDecorator = 1,
534 549 ConstructorDecorator = 2,
535 550 DestructorDecorator = 4,
536 551 InstanceDecorator = 8,
537 552 AllDecorators = 0xffff
538 553 };
539 554
540 555 //! get the suffixes that are used for shared libraries
541 556 const QStringList& sharedLibrarySuffixes() { return _sharedLibrarySuffixes; }
542 557
543 558 //! returns if the id is the id for PythonQtObjectPtr
544 559 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
545 560
546 561 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
547 562 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
548 563 //! remove the wrapper ptr again
549 564 void removeWrapperPointer(void* obj);
550 565
551 566 //! try to unwrap the given object to a C++ pointer using the foreign wrapper factories
552 567 void* unwrapForeignWrapper(const QByteArray& classname, PyObject* obj);
553 568
554 569 //! add parent class relation
555 570 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
556 571
557 572 //! add a handler for polymorphic downcasting
558 573 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
559 574
560 575 //! lookup existing classinfo and return new if not yet present
561 576 PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
562 577
563 578 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
564 579 void removeSignalEmitter(QObject* obj);
565 580
566 581 //! wrap the given QObject into a Python object (or return existing wrapper!)
567 582 PyObject* wrapQObject(QObject* obj);
568 583
569 584 //! wrap the given ptr into a Python object (or return existing wrapper!) if there is a known QObject of that name or a known wrapper in the factory
570 585 PyObject* wrapPtr(void* ptr, const QByteArray& name);
571 586
572 587 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
573 588 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
574 589 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
575 590 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
576 591
577 592 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
578 593 //! (ownership of wrapper is passed to PythonQt)
579 594 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
580 595
581 596 This will add a wrapper object that is used to make calls to the given classname \c typeName.
582 597 All slots that take a pointer to typeName as the first argument will be callable from Python on
583 598 a variant object that contains such a type.
584 599 */
585 600 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
586 601
587 602 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
588 603 //! and it will register the classes when it first sees a pointer to such a derived class
589 604 void registerQObjectClassNames(const QStringList& names);
590 605
591 606 //! add a decorator object
592 607 void addDecorators(QObject* o, int decoTypes);
593 608
594 609 //! helper method that creates a PythonQtClassWrapper object (returns a new reference)
595 610 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* module);
596 611
597 612 //! create a new instance of the given enum type with given value (returns a new reference)
598 613 static PyObject* createEnumValueInstance(PyObject* enumType, unsigned int enumValue);
599 614
600 615 //! helper that creates a new int derived class that represents the enum of the given name (returns a new reference)
601 616 static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
602 617
603 618 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
604 619 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
605 620
606 621 //! get the class info for a meta object (if available)
607 622 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
608 623
609 624 //! get the class info for a meta object (if available)
610 625 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
611 626
612 627 //! creates the new module from the given pycode
613 628 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
614 629
615 630 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
616 631 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
617 632
618 633 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
619 634 static PyObject* dummyTuple();
620 635
621 636 //! called by virtual overloads when a python return value can not be converted to the required Qt type
622 637 void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result);
623 638
624 639 //! get access to the PythonQt module
625 640 PythonQtObjectPtr pythonQtModule() const { return _pythonQtModule; }
626 641
627 642 //! returns the profiling callback, which may be NULL
628 643 PythonQt::ProfilingCB* profilingCB() const { return _profilingCB; }
629 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;
650
630 651 private:
631 652 //! Setup the shared library suffixes by getting them from the "imp" module.
632 653 void setupSharedLibrarySuffixes();
633 654
634 655 //! create a new pythonqt class wrapper and place it in the pythonqt module
635 656 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module = NULL);
636 657
637 658 //! get/create new package module (the returned object is a borrowed reference)
638 659 PyObject* packageByName(const char* name);
639 660
640 661 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
641 662 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
642 663
643 664 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
644 665 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
645 666
646 667 //! stores the meta info of known Qt classes
647 668 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
648 669
649 670 //! names of qobject derived classes that can be casted to qobject savely
650 671 QHash<QByteArray, bool> _knownQObjectClassNames;
651 672
652 673 //! stores signal receivers for QObjects
653 674 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
654 675
655 676 //! the PythonQt python module
656 677 PythonQtObjectPtr _pythonQtModule;
657 678
658 679 //! the name of the PythonQt python module
659 680 QByteArray _pythonQtModuleName;
660 681
661 682 //! the importer interface (if set)
662 683 PythonQtImportFileInterface* _importInterface;
663 684
664 685 //! the default importer
665 686 PythonQtQFileImporter* _defaultImporter;
666 687
667 688 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
668 689 PythonQtQObjectWrappedCB* _wrappedCB;
669 690
670 691 QStringList _importIgnorePaths;
671 692 QStringList _sharedLibrarySuffixes;
672 693
673 694 //! the cpp object wrapper factories
674 695 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
675 696
676 697 QList<PythonQtForeignWrapperFactory*> _foreignWrapperFactories;
677 698
678 699 QHash<QByteArray, PyObject*> _packages;
679 700
680 701 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
681 702
682 703 PythonQt::ProfilingCB* _profilingCB;
683 704
684 705 int _initFlags;
685 706 int _PythonQtObjectPtr_metaId;
686 707
687 708 friend class PythonQt;
688 709 };
689 710
690 711 #endif
@@ -1,868 +1,894
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtClassInfo.h"
43 43 #include "PythonQtMethodInfo.h"
44 44 #include "PythonQt.h"
45 45 #include <QMetaMethod>
46 46 #include <QMetaObject>
47 47 #include <QMetaEnum>
48 48
49 49 QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;
50 50
51 51 PythonQtClassInfo::PythonQtClassInfo() {
52 52 _meta = NULL;
53 53 _constructors = NULL;
54 54 _destructor = NULL;
55 55 _decoratorProvider = NULL;
56 56 _decoratorProviderCB = NULL;
57 57 _pythonQtClassWrapper = NULL;
58 58 _shellSetInstanceWrapperCB = NULL;
59 59 _metaTypeId = -1;
60 60 _typeSlots = 0;
61 61 _isQObject = false;
62 62 _enumsCreated = false;
63 63 }
64 64
65 65 PythonQtClassInfo::~PythonQtClassInfo()
66 66 {
67 67 clearCachedMembers();
68 68
69 69 if (_constructors) {
70 70 _constructors->deleteOverloadsAndThis();
71 71 }
72 72 if (_destructor) {
73 73 _destructor->deleteOverloadsAndThis();
74 74 }
75 75 foreach(PythonQtSlotInfo* info, _decoratorSlots) {
76 76 info->deleteOverloadsAndThis();
77 77 }
78 78 }
79 79
80 80 void PythonQtClassInfo::setupQObject(const QMetaObject* meta)
81 81 {
82 82 // _wrappedClassName is already set earlier in the class setup
83 83 _isQObject = true;
84 84 _meta = meta;
85 85 }
86 86
87 87 void PythonQtClassInfo::setupCPPObject(const QByteArray& classname)
88 88 {
89 89 _isQObject = false;
90 90 _wrappedClassName = classname;
91 91 _metaTypeId = QMetaType::type(classname);
92 92 }
93 93
94 94 void PythonQtClassInfo::clearCachedMembers()
95 95 {
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();
103 103 delete info;
104 104 info = next;
105 105 }
106 106 }
107 107 }
108 108 }
109 109
110 110 int PythonQtClassInfo::findCharOffset(const char* sigStart, char someChar)
111 111 {
112 112 const char* sigEnd = sigStart;
113 113 char c;
114 114 do {
115 115 c = *sigEnd++;
116 116 } while (c!=someChar && c!=0);
117 117 return sigEnd-sigStart-1;
118 118 }
119 119
120 120 bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName)
121 121 {
122 122 if (!_meta) return false;
123 123
124 124 bool found = false;
125 125 bool nameMapped = false;
126 126 const char* attributeName = memberName;
127 127 // look for properties
128 128 int i = _meta->indexOfProperty(attributeName);
129 129 if (i==-1) {
130 130 // try to map name to objectName
131 131 if (qstrcmp(attributeName, "name")==0) {
132 132 attributeName = "objectName";
133 133 nameMapped = true;
134 134 i = _meta->indexOfProperty(attributeName);
135 135 }
136 136 }
137 137 if (i!=-1) {
138 138 PythonQtMemberInfo newInfo(_meta->property(i));
139 139 _cachedMembers.insert(attributeName, newInfo);
140 140 if (nameMapped) {
141 141 _cachedMembers.insert(memberName, newInfo);
142 142 }
143 143 #ifdef PYTHONQT_DEBUG
144 144 std::cout << "caching property " << memberName << " on " << _meta->className() << std::endl;
145 145 #endif
146 146 found = true;
147 147 }
148 148 return found;
149 149 }
150 150
151 151 PythonQtSlotInfo* PythonQtClassInfo::recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
152 152 {
153 153 inputInfo = findDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset);
154 154 foreach(const ParentClassInfo& info, _parentClasses) {
155 155 inputInfo = info._parent->recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset+info._upcastingOffset);
156 156 }
157 157 return inputInfo;
158 158 }
159 159
160 160 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset) {
161 161 QObject* decoratorProvider = decorator();
162 162 int memberNameLen = static_cast<int>(strlen(memberName));
163 163 if (decoratorProvider) {
164 164 //qDebug()<< "looking " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
165 165 const QMetaObject* meta = decoratorProvider->metaObject();
166 166 int numMethods = meta->methodCount();
167 167 int startFrom = QObject::staticMetaObject.methodCount();
168 168 for (int i = startFrom; i < numMethods; i++) {
169 169 QMetaMethod m = meta->method(i);
170 170 if ((m.methodType() == QMetaMethod::Method ||
171 171 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
172 172
173 173 const char* sigStart = m.signature();
174 174 bool isClassDeco = false;
175 175 if (qstrncmp(sigStart, "static_", 7)==0) {
176 176 // skip the static_classname_ part of the string
177 177 sigStart += 7 + 1 + strlen(className());
178 178 isClassDeco = true;
179 179 } else if (qstrncmp(sigStart, "new_", 4)==0) {
180 180 isClassDeco = true;
181 181 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
182 182 isClassDeco = true;
183 183 }
184 184 // find the first '('
185 185 int offset = findCharOffset(sigStart, '(');
186 186
187 187 // XXX no checking is currently done if the slots have correct first argument or not...
188 188
189 189 // check if same length and same name
190 190 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
191 191 found = true;
192 192 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i, decoratorProvider, isClassDeco?PythonQtSlotInfo::ClassDecorator:PythonQtSlotInfo::InstanceDecorator);
193 193 info->setUpcastingOffset(upcastingOffset);
194 194 //qDebug()<< "adding " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
195 195 if (tail) {
196 196 tail->setNextInfo(info);
197 197 } else {
198 198 PythonQtMemberInfo newInfo(info);
199 199 memberCache.insert(memberName, newInfo);
200 200 }
201 201 tail = info;
202 202 }
203 203 }
204 204 }
205 205 }
206 206
207 207 tail = findDecoratorSlots(memberName, memberNameLen, tail, found, memberCache, upcastingOffset);
208 208
209 209 return tail;
210 210 }
211 211
212 212 bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName)
213 213 {
214 214 bool found = false;
215 215 int memberNameLen = static_cast<int>(strlen(memberName));
216 216 PythonQtSlotInfo* tail = NULL;
217 217 if (_meta) {
218 218 int numMethods = _meta->methodCount();
219 219 for (int i = 0; i < numMethods; i++) {
220 220 QMetaMethod m = _meta->method(i);
221 221 if (((m.methodType() == QMetaMethod::Method ||
222 222 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public)
223 223 || m.methodType()==QMetaMethod::Signal) {
224 224
225 225 const char* sigStart = m.signature();
226 226 // find the first '('
227 227 int offset = findCharOffset(sigStart, '(');
228 228
229 229 // check if same length and same name
230 230 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
231 231 found = true;
232 232 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i);
233 233 if (tail) {
234 234 tail->setNextInfo(info);
235 235 } else {
236 236 PythonQtMemberInfo newInfo(info);
237 237 _cachedMembers.insert(memberName, newInfo);
238 238 }
239 239 tail = info;
240 240 }
241 241 }
242 242 }
243 243 }
244 244
245 245 // look for dynamic decorators in this class and in derived classes
246 246 tail = recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, tail, found, _cachedMembers, 0);
247 247
248 248 return found;
249 249 }
250 250
251 251 bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* memberName)
252 252 {
253 253 bool found = false;
254 254 // look for enum values
255 255 int enumCount = meta->enumeratorCount();
256 256 for (int i=0;i<enumCount; i++) {
257 257 QMetaEnum e = meta->enumerator(i);
258 258 // we do not want flags, they will cause our values to appear two times
259 259 if (e.isFlag()) continue;
260 260
261 261 for (int j=0; j < e.keyCount(); j++) {
262 262 if (qstrcmp(e.key(j), memberName)==0) {
263 263 PyObject* enumType = findEnumWrapper(e.name());
264 264 if (enumType) {
265 265 PythonQtObjectPtr enumValuePtr;
266 266 enumValuePtr.setNewRef(PythonQtPrivate::createEnumValueInstance(enumType, e.value(j)));
267 267 PythonQtMemberInfo newInfo(enumValuePtr);
268 268 _cachedMembers.insert(memberName, newInfo);
269 269 #ifdef PYTHONQT_DEBUG
270 270 std::cout << "caching enum " << memberName << " on " << meta->className() << std::endl;
271 271 #endif
272 272 found = true;
273 273 break;
274 274 } else {
275 275 std::cout << "enum " << e.name() << " not found on " << className() << std::endl;
276 276 }
277 277 }
278 278 }
279 279 }
280 280 return found;
281 281 }
282 282
283 283 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
284 284 {
285 285 PythonQtMemberInfo info = _cachedMembers.value(memberName);
286 286 if (info._type != PythonQtMemberInfo::Invalid) {
287 287 return info;
288 288 } else {
289 289 bool found = false;
290 290
291 291 found = lookForPropertyAndCache(memberName);
292 292 if (!found) {
293 293 found = lookForMethodAndCache(memberName);
294 294 }
295 295 if (!found) {
296 296 if (_meta) {
297 297 // check enums in our meta object directly
298 298 found = lookForEnumAndCache(_meta, memberName);
299 299 }
300 300 if (!found) {
301 301 // check enums in the class hierachy of CPP classes
302 302 // look for dynamic decorators in this class and in derived classes
303 303 QList<QObject*> decoObjects;
304 304 recursiveCollectDecoratorObjects(decoObjects);
305 305 foreach(QObject* deco, decoObjects) {
306 306 // call on ourself for caching, but with different metaObject():
307 307 found = lookForEnumAndCache(deco->metaObject(), memberName);
308 308 if (found) {
309 309 break;
310 310 }
311 311 }
312 312 }
313 313 }
314 314 if (!found) {
315 315 // maybe it is an enum wrapper?
316 316 PyObject* p = findEnumWrapper(memberName);
317 317 if (p) {
318 318 info._type = PythonQtMemberInfo::EnumWrapper;
319 319 info._enumWrapper = p;
320 320 _cachedMembers.insert(memberName, info);
321 321 found = true;
322 322 }
323 323 }
324 324 if (!found) {
325 325 // since python keywords can not be looked up, we check if the name contains a single trailing _
326 326 // and remove that and look again, so that we e.g. find exec on an exec_ lookup
327 327 QByteArray mbrName(memberName);
328 328 if ((mbrName.length()>2) &&
329 329 (mbrName.at(mbrName.length()-1) == '_') &&
330 330 (mbrName.at(mbrName.length()-2) != '_')) {
331 331 mbrName = mbrName.mid(0,mbrName.length()-1);
332 332 found = lookForMethodAndCache(mbrName.constData());
333 333 if (found) {
334 334 return _cachedMembers.value(mbrName);
335 335 }
336 336 }
337 337 }
338 338 if (!found) {
339 339 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
340 340 info._type = PythonQtMemberInfo::NotFound;
341 341 _cachedMembers.insert(memberName, info);
342 342 }
343 343 }
344 344
345 345 return _cachedMembers.value(memberName);
346 346 }
347 347
348 348 void PythonQtClassInfo::recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects) {
349 349 QObject* deco = decorator();
350 350 if (deco) {
351 351 decoratorObjects.append(deco);
352 352 }
353 353 foreach(const ParentClassInfo& info, _parentClasses) {
354 354 info._parent->recursiveCollectDecoratorObjects(decoratorObjects);
355 355 }
356 356 }
357 357
358 358 void PythonQtClassInfo::recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects) {
359 359 classInfoObjects.append(this);
360 360 foreach(const ParentClassInfo& info, _parentClasses) {
361 361 info._parent->recursiveCollectClassInfos(classInfoObjects);
362 362 }
363 363 }
364 364
365 365 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
366 366 {
367 367 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
368 368 while (it.hasNext()) {
369 369
370 370 PythonQtSlotInfo* infoOrig = it.next();
371 371
372 372 const char* sigStart = infoOrig->metaMethod()->signature();
373 373 if (qstrncmp("static_", sigStart, 7)==0) {
374 374 sigStart += 7;
375 375 sigStart += findCharOffset(sigStart, '_')+1;
376 376 }
377 377 int offset = findCharOffset(sigStart, '(');
378 378 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
379 379 //make a copy, otherwise we will have trouble on overloads!
380 380 PythonQtSlotInfo* info = new PythonQtSlotInfo(*infoOrig);
381 381 info->setUpcastingOffset(upcastingOffset);
382 382 found = true;
383 383 if (tail) {
384 384 tail->setNextInfo(info);
385 385 } else {
386 386 PythonQtMemberInfo newInfo(info);
387 387 memberCache.insert(memberName, newInfo);
388 388 }
389 389 tail = info;
390 390 }
391 391 }
392 392 return tail;
393 393 }
394 394
395 395 void PythonQtClassInfo::listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly) {
396 396 QObject* decoratorProvider = decorator();
397 397 if (decoratorProvider) {
398 398 const QMetaObject* meta = decoratorProvider->metaObject();
399 399 int numMethods = meta->methodCount();
400 400 int startFrom = QObject::staticMetaObject.methodCount();
401 401 for (int i = startFrom; i < numMethods; i++) {
402 402 QMetaMethod m = meta->method(i);
403 403 if ((m.methodType() == QMetaMethod::Method ||
404 404 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
405 405
406 406 const char* sigStart = m.signature();
407 407 bool isClassDeco = false;
408 408 if (qstrncmp(sigStart, "static_", 7)==0) {
409 409 // skip the static_classname_ part of the string
410 410 sigStart += 7 + 1 + strlen(className());
411 411 isClassDeco = true;
412 412 } else if (qstrncmp(sigStart, "new_", 4)==0) {
413 413 continue;
414 414 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
415 415 continue;
416 416 } else if (qstrncmp(sigStart, "py_", 3)==0) {
417 417 // hide everything that starts with py_
418 418 continue;
419 419 }
420 420 // find the first '('
421 421 int offset = findCharOffset(sigStart, '(');
422 422
423 423 // XXX no checking is currently done if the slots have correct first argument or not...
424 424 if (!metaOnly || isClassDeco) {
425 425 list << QString::fromLatin1(sigStart, offset);
426 426 }
427 427 }
428 428 }
429 429 }
430 430
431 431 // look for global decorator slots
432 432 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
433 433 while (it.hasNext()) {
434 434 PythonQtSlotInfo* slot = it.next();
435 435 if (metaOnly) {
436 436 if (slot->isClassDecorator()) {
437 437 QByteArray first = slot->slotName();
438 438 if (first.startsWith("static_")) {
439 439 int idx = first.indexOf('_');
440 440 idx = first.indexOf('_', idx+1);
441 441 first = first.mid(idx+1);
442 442 }
443 443 list << first;
444 444 }
445 445 } else {
446 446 list << slot->slotName();
447 447 }
448 448 }
449 449 }
450 450
451 451 QStringList PythonQtClassInfo::propertyList()
452 452 {
453 453 QStringList l;
454 454 if (_isQObject && _meta) {
455 455 int i;
456 456 int numProperties = _meta->propertyCount();
457 457 for (i = 0; i < numProperties; i++) {
458 458 QMetaProperty p = _meta->property(i);
459 459 l << QString(p.name());
460 460 }
461 461 }
462 462 return l;
463 463 }
464 464
465 QStringList PythonQtClassInfo::memberList(bool metaOnly)
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 (!metaOnly && _meta) {
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++) {
480 476 QMetaMethod m = _meta->method(i);
481 477 if (((m.methodType() == QMetaMethod::Method ||
482 478 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public)
483 479 || m.methodType()==QMetaMethod::Signal) {
484 480 QByteArray signa(m.signature());
485 481 signa = signa.left(signa.indexOf('('));
486 482 l << signa;
487 483 }
488 484 }
489 485 }
490 486
491 487 {
492 488 // look for dynamic decorators in this class and in derived classes
493 489 QList<PythonQtClassInfo*> infos;
494 490 recursiveCollectClassInfos(infos);
495 491 foreach(PythonQtClassInfo* info, infos) {
496 info->listDecoratorSlotsFromDecoratorProvider(l, metaOnly);
492 info->listDecoratorSlotsFromDecoratorProvider(l, false);
497 493 }
498 494 }
499 495
500 496 // List enumerator keys...
501 497 QList<const QMetaObject*> enumMetaObjects;
502 498 if (_meta) {
503 499 enumMetaObjects << _meta;
504 500 }
505 501 // check enums in the class hierachy of CPP classes
506 502 QList<QObject*> decoObjects;
507 503 recursiveCollectDecoratorObjects(decoObjects);
508 504 foreach(QObject* deco, decoObjects) {
509 505 enumMetaObjects << deco->metaObject();
510 506 }
511 507
512 508 foreach(const QMetaObject* meta, enumMetaObjects) {
513 509 for (int i = 0; i<meta->enumeratorCount(); i++) {
514 510 QMetaEnum e = meta->enumerator(i);
515 511 l << e.name();
516 512 // we do not want flags, they will cause our values to appear two times
517 513 if (e.isFlag()) continue;
518 514
519 515 for (int j=0; j < e.keyCount(); j++) {
520 516 l << QString(e.key(j));
521 517 }
522 518 }
523 519 }
524 520
525 521 return QSet<QString>::fromList(l).toList();
526 522 }
527 523
528 524 const char* PythonQtClassInfo::className()
529 525 {
530 526 return _wrappedClassName.constData();
531 527 }
532 528
533 529 void* PythonQtClassInfo::castTo(void* ptr, const char* classname)
534 530 {
535 531 if (ptr==NULL) {
536 532 return NULL;
537 533 }
538 534 if (_wrappedClassName == classname) {
539 535 return ptr;
540 536 }
541 537 foreach(const ParentClassInfo& info, _parentClasses) {
542 538 void* result = info._parent->castTo((char*)ptr + info._upcastingOffset, classname);
543 539 if (result) {
544 540 return result;
545 541 }
546 542 }
547 543 return NULL;
548 544 }
549 545
550 546 bool PythonQtClassInfo::inherits(const char* name)
551 547 {
552 548 if (_wrappedClassName == name) {
553 549 return true;
554 550 }
555 551 foreach(const ParentClassInfo& info, _parentClasses) {
556 552 if (info._parent->inherits(name)) {
557 553 return true;
558 554 }
559 555 }
560 556 return false;
561 557 }
562 558
563 559 bool PythonQtClassInfo::inherits(PythonQtClassInfo* classInfo)
564 560 {
565 561 if (classInfo == this) {
566 562 return true;
567 563 }
568 564 foreach(const ParentClassInfo& info, _parentClasses) {
569 565 if (info._parent->inherits(classInfo)) {
570 566 return true;
571 567 }
572 568 }
573 569 return false;
574 570 }
575 571
576 572 QString PythonQtClassInfo::help()
577 573 {
578 574 decorator();
579 575 QString h;
580 576 h += QString("--- ") + QString(className()) + QString(" ---\n");
581 577
582 578 if (_isQObject) {
583 579 h += "Properties:\n";
584 580
585 581 int i;
586 582 int numProperties = _meta->propertyCount();
587 583 for (i = 0; i < numProperties; i++) {
588 584 QMetaProperty p = _meta->property(i);
589 585 h += QString(p.name()) + " (" + QString(p.typeName()) + " )\n";
590 586 }
591 587 }
592 588
593 589 if (constructors()) {
594 590 h += "Constructors:\n";
595 591 PythonQtSlotInfo* constr = constructors();
596 592 while (constr) {
597 593 h += constr->fullSignature() + "\n";
598 594 constr = constr->nextInfo();
599 595 }
600 596 }
601 597
602 598 h += "Slots:\n";
603 599 h += "QString help()\n";
604 600 h += "QString className()\n";
605 601
606 602 if (_meta) {
607 603 int numMethods = _meta->methodCount();
608 604 for (int i = 0; i < numMethods; i++) {
609 605 QMetaMethod m = _meta->method(i);
610 606 if ((m.methodType() == QMetaMethod::Method ||
611 607 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
612 608 PythonQtSlotInfo slot(this, m, i);
613 609 h += slot.fullSignature()+ "\n";
614 610 }
615 611 }
616 612 }
617 613
618 614 // TODO xxx : decorators and enums from decorator() are missing...
619 615 // maybe we can reuse memberlist()?
620 616
621 617 if (_meta && _meta->enumeratorCount()) {
622 618 h += "Enums:\n";
623 619 for (int i = 0; i<_meta->enumeratorCount(); i++) {
624 620 QMetaEnum e = _meta->enumerator(i);
625 621 h += QString(e.name()) + " {";
626 622 for (int j=0; j < e.keyCount(); j++) {
627 623 if (j) { h+= ", "; }
628 624 h += e.key(j);
629 625 }
630 626 h += " }\n";
631 627 }
632 628 }
633 629
634 630 if (_isQObject && _meta) {
635 631 int numMethods = _meta->methodCount();
636 632 if (numMethods>0) {
637 633 h += "Signals:\n";
638 634 for (int i = 0; i < numMethods; i++) {
639 635 QMetaMethod m = _meta->method(i);
640 636 if (m.methodType() == QMetaMethod::Signal) {
641 637 h += QString(m.signature()) + "\n";
642 638 }
643 639 }
644 640 }
645 641 }
646 642 return h;
647 643 }
648 644
649 645 PythonQtSlotInfo* PythonQtClassInfo::constructors()
650 646 {
651 647 if (!_constructors) {
652 648 // force creation of lazy decorator, which will register the decorators
653 649 decorator();
654 650 }
655 651 return _constructors;
656 652 }
657 653
658 654 PythonQtSlotInfo* PythonQtClassInfo::destructor()
659 655 {
660 656 if (!_destructor) {
661 657 // force creation of lazy decorator, which will register the decorators
662 658 decorator();
663 659 }
664 660 return _destructor;
665 661 }
666 662
667 663 void PythonQtClassInfo::addConstructor(PythonQtSlotInfo* info)
668 664 {
669 665 PythonQtSlotInfo* prev = constructors();
670 666 if (prev) {
671 667 info->setNextInfo(prev->nextInfo());
672 668 prev->setNextInfo(info);
673 669 } else {
674 670 _constructors = info;
675 671 }
676 672 }
677 673
678 674 void PythonQtClassInfo::addDecoratorSlot(PythonQtSlotInfo* info)
679 675 {
680 676 _decoratorSlots.append(info);
681 677 }
682 678
683 679 void PythonQtClassInfo::setDestructor(PythonQtSlotInfo* info)
684 680 {
685 681 if (_destructor) {
686 682 _destructor->deleteOverloadsAndThis();
687 683 }
688 684 _destructor = info;
689 685 }
690 686
691 687 void PythonQtClassInfo::setMetaObject(const QMetaObject* meta)
692 688 {
693 689 _meta = meta;
694 690 clearCachedMembers();
695 691 }
696 692
697 693 QObject* PythonQtClassInfo::decorator()
698 694 {
699 695 if (!_decoratorProvider && _decoratorProviderCB) {
700 696 _decoratorProvider = (*_decoratorProviderCB)();
701 697 if (_decoratorProvider) {
702 698 _decoratorProvider->setParent(PythonQt::priv());
703 699 // setup enums early, since they might be needed by the constructor decorators:
704 700 if (!_enumsCreated) {
705 701 createEnumWrappers();
706 702 }
707 703 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
708 704 }
709 705 }
710 706 // check if enums need to be created and create them if they are not yet created
711 707 if (!_enumsCreated) {
712 708 createEnumWrappers();
713 709 }
714 710 return _decoratorProvider;
715 711 }
716 712
717 713 bool PythonQtClassInfo::hasOwnerMethodButNoOwner(void* object)
718 714 {
719 715 PythonQtMemberInfo info = member("py_hasOwner");
720 716 if (info._type == PythonQtMemberInfo::Slot) {
721 717 void* obj = object;
722 718 bool result = false;
723 719 void* args[2];
724 720 args[0] = &result;
725 721 args[1] = &obj;
726 722 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
727 723 return !result;
728 724 } else {
729 725 return false;
730 726 }
731 727 }
732 728
733 729 void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, const char** resultClassName)
734 730 {
735 731 if (!_polymorphicHandlers.isEmpty()) {
736 732 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
737 733 void* resultPtr = (*cb)(ptr, resultClassName);
738 734 if (resultPtr) {
739 735 return resultPtr;
740 736 }
741 737 }
742 738 }
743 739 foreach(const ParentClassInfo& info, _parentClasses) {
744 740 if (!info._parent->isQObject()) {
745 741 void* resultPtr = info._parent->recursiveCastDownIfPossible((char*)ptr + info._upcastingOffset, resultClassName);
746 742 if (resultPtr) {
747 743 return resultPtr;
748 744 }
749 745 }
750 746 }
751 747 return NULL;
752 748 }
753 749
754 750 void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo)
755 751 {
756 752 const char* className;
757 753 // this would do downcasting recursively...
758 754 // void* resultPtr = recursiveCastDownIfPossible(ptr, &className);
759 755
760 756 // we only do downcasting on the base object, not on the whole inheritance tree...
761 757 void* resultPtr = NULL;
762 758 if (!_polymorphicHandlers.isEmpty()) {
763 759 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
764 760 resultPtr = (*cb)(ptr, &className);
765 761 if (resultPtr) {
766 762 break;
767 763 }
768 764 }
769 765 }
770 766 if (resultPtr) {
771 767 *resultClassInfo = PythonQt::priv()->getClassInfo(className);
772 768 } else {
773 769 *resultClassInfo = this;
774 770 resultPtr = ptr;
775 771 }
776 772 return resultPtr;
777 773 }
778 774
779 775 PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum)
780 776 {
781 777 if (isLocalEnum) {
782 778 *isLocalEnum = true;
783 779 }
784 780 int scopePos = name.lastIndexOf("::");
785 781 if (scopePos != -1) {
786 782 if (isLocalEnum) {
787 783 *isLocalEnum = false;
788 784 }
789 785 // split into scope and enum name
790 786 QByteArray enumScope = name.mid(0,scopePos);
791 787 QByteArray enumName = name.mid(scopePos+2);
792 788 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(enumScope);
793 789 if (info) {
794 790 return info->findEnumWrapper(enumName);
795 791 } else{
796 792 return NULL;
797 793 }
798 794 }
799 795 if (localScope) {
800 796 return localScope->findEnumWrapper(name);
801 797 } else {
802 798 return NULL;
803 799 }
804 800 }
805 801
806 802 void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta)
807 803 {
808 804 for (int i = meta->enumeratorOffset();i<meta->enumeratorCount();i++) {
809 805 QMetaEnum e = meta->enumerator(i);
810 806 PythonQtObjectPtr p;
811 807 p.setNewRef(PythonQtPrivate::createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper));
812 808 _enumWrappers.append(p);
813 809 }
814 810 }
815 811
816 812 void PythonQtClassInfo::createEnumWrappers()
817 813 {
818 814 if (!_enumsCreated) {
819 815 _enumsCreated = true;
820 816 if (_meta) {
821 817 createEnumWrappers(_meta);
822 818 }
823 819 if (decorator()) {
824 820 createEnumWrappers(decorator()->metaObject());
825 821 }
826 822 foreach(const ParentClassInfo& info, _parentClasses) {
827 823 info._parent->createEnumWrappers();
828 824 }
829 825 }
830 826 }
831 827
832 828 PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) {
833 829 // force enum creation
834 830 if (!_enumsCreated) {
835 831 createEnumWrappers();
836 832 }
837 833 foreach(const PythonQtObjectPtr& p, _enumWrappers) {
838 834 const char* className = ((PyTypeObject*)p.object())->tp_name;
839 835 if (qstrcmp(className, name)==0) {
840 836 return p.object();
841 837 }
842 838 }
843 839 foreach(const ParentClassInfo& info, _parentClasses) {
844 840 PyObject* p = info._parent->findEnumWrapper(name);
845 841 if (p) return p;
846 842 }
847 843 return NULL;
848 844 }
849 845
850 846 void PythonQtClassInfo::setDecoratorProvider( PythonQtQObjectCreatorFunctionCB* cb )
851 847 {
852 848 _decoratorProviderCB = cb;
853 849 _decoratorProvider = NULL;
854 850 _enumsCreated = false;
855 851 }
856 852
857 853 void PythonQtClassInfo::clearNotFoundCachedMembers()
858 854 {
859 855 // remove all not found entries, since a new decorator means new slots,
860 856 // which might have been cached as "NotFound" already.
861 857 QMutableHashIterator<QByteArray, PythonQtMemberInfo> it(_cachedMembers);
862 858 while (it.hasNext()) {
863 859 it.next();
864 860 if (it.value()._type == PythonQtMemberInfo::NotFound) {
865 861 it.remove();
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
@@ -1,265 +1,250
1 1 #ifndef _PYTHONQTCLASSINFO_H
2 2 #define _PYTHONQTCLASSINFO_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 #include <QMetaObject>
37 37 #include <QMetaMethod>
38 38 #include <QHash>
39 39 #include <QByteArray>
40 40 #include <QList>
41 41 #include "PythonQt.h"
42 42
43 43 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
75 60 // TODO: this could be a union...
76 61 PythonQtSlotInfo* _slot;
77 62 PyObject* _enumWrapper;
78 63 PythonQtObjectPtr _enumValue;
79 64 QMetaProperty _property;
80 65 };
81 66
82 67 //! a class that stores all required information about a Qt object (and an optional associated C++ class name)
83 68 /*! for fast lookup of slots when calling the object from Python
84 69 */
85 70 class PYTHONQT_EXPORT PythonQtClassInfo {
86 71
87 72 public:
88 73 PythonQtClassInfo();
89 74 ~PythonQtClassInfo();
90 75
91 76 //! store information about parent classes
92 77 struct ParentClassInfo {
93 78 ParentClassInfo(PythonQtClassInfo* parent, int upcastingOffset=0):_parent(parent),_upcastingOffset(upcastingOffset)
94 79 {};
95 80
96 81 PythonQtClassInfo* _parent;
97 82 int _upcastingOffset;
98 83 };
99 84
100 85
101 86 //! setup as a QObject, taking the meta object as meta information about the QObject
102 87 void setupQObject(const QMetaObject* meta);
103 88
104 89 //! setup as a CPP (non-QObject), taking the classname
105 90 void setupCPPObject(const QByteArray& classname);
106 91
107 92 //! set the type capabilities
108 93 void setTypeSlots(int typeSlots) { _typeSlots = typeSlots; }
109 94 //! get the type capabilities
110 95 int typeSlots() const { return _typeSlots; }
111 96
112 97 //! get the Python method definition for a given slot name (without return type and signature)
113 98 PythonQtMemberInfo member(const char* member);
114 99
115 100 //! get access to the constructor slot (which may be overloaded if there are multiple constructors)
116 101 PythonQtSlotInfo* constructors();
117 102
118 103 //! get access to the destructor slot
119 104 PythonQtSlotInfo* destructor();
120 105
121 106 //! add a constructor, ownership is passed to classinfo
122 107 void addConstructor(PythonQtSlotInfo* info);
123 108
124 109 //! set a destructor, ownership is passed to classinfo
125 110 void setDestructor(PythonQtSlotInfo* info);
126 111
127 112 //! add a decorator slot, ownership is passed to classinfo
128 113 void addDecoratorSlot(PythonQtSlotInfo* info);
129 114
130 115 //! get the classname (either of the QObject or of the wrapped CPP object)
131 116 const char* className();
132 117
133 118 //! returns if the QObject
134 119 bool isQObject() { return _isQObject; }
135 120
136 121 //! returns if the class is a CPP wrapper
137 122 bool isCPPWrapper() { return !_isQObject; }
138 123
139 124 //! get the meta object
140 125 const QMetaObject* metaObject() { return _meta; }
141 126
142 127 //! set the meta object, this will reset the caching
143 128 void setMetaObject(const QMetaObject* meta);
144 129
145 130 //! returns if this class inherits from the given classname
146 131 bool inherits(const char* classname);
147 132
148 133 //! returns if this class inherits from the given classinfo
149 134 bool inherits(PythonQtClassInfo* info);
150 135
151 136 //! casts the given \c ptr to an object of type \c classname, returns the new pointer
152 137 //! which might be different to \c ptr due to C++ multiple inheritance
153 138 //! (if the cast is not possible or if ptr is NULL, NULL is returned)
154 139 void* castTo(void* ptr, const char* classname);
155 140
156 141 //! get help string for the metaobject
157 142 QString help();
158 143
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(bool metaOnly = false);
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; }
167 152
168 153 //! set an additional decorator provider that offers additional decorator slots for this class
169 154 void setDecoratorProvider(PythonQtQObjectCreatorFunctionCB* cb);
170 155
171 156 //! get the decorator qobject instance
172 157 QObject* decorator();
173 158
174 159 //! add the parent class info of a CPP object
175 160 void addParentClass(const ParentClassInfo& info) { _parentClasses.append(info); }
176 161
177 162 //! check if the special method "py_hasOwner" is implemented and if it returns false, which means that the object may be destroyed
178 163 bool hasOwnerMethodButNoOwner(void* object);
179 164
180 165 //! set the associated PythonQtClassWrapper (which handles instance creation of this type)
181 166 void setPythonQtClassWrapper(PyObject* obj) { _pythonQtClassWrapper = obj; }
182 167
183 168 //! get the associated PythonQtClassWrapper (which handles instance creation of this type)
184 169 PyObject* pythonQtClassWrapper() { return _pythonQtClassWrapper; }
185 170
186 171 //! set the shell set instance wrapper cb
187 172 void setShellSetInstanceWrapperCB(PythonQtShellSetInstanceWrapperCB* cb) {
188 173 _shellSetInstanceWrapperCB = cb;
189 174 }
190 175
191 176 //! get the shell set instance wrapper cb
192 177 PythonQtShellSetInstanceWrapperCB* shellSetInstanceWrapperCB() {
193 178 return _shellSetInstanceWrapperCB;
194 179 }
195 180
196 181 //! add a handler for polymorphic downcasting
197 182 void addPolymorphicHandler(PythonQtPolymorphicHandlerCB* cb) { _polymorphicHandlers.append(cb); }
198 183
199 184 //! cast the pointer down in the class hierarchy if a polymorphic handler allows to do that
200 185 void* castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo);
201 186
202 187 //! returns if the localScope has an enum of that type name or if the enum contains a :: scope, if that class contails the enum
203 188 static PyObject* findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum = NULL);
204 189
205 190 //! clear all members that where cached as "NotFound"
206 191 void clearNotFoundCachedMembers();
207 192
208 193 private:
209 194 void createEnumWrappers();
210 195 void createEnumWrappers(const QMetaObject* meta);
211 196 PyObject* findEnumWrapper(const char* name);
212 197
213 198 //! clear all cached members
214 199 void clearCachedMembers();
215 200
216 201 void* recursiveCastDownIfPossible(void* ptr, const char** resultClassName);
217 202
218 203 PythonQtSlotInfo* findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
219 204 void listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly);
220 205 PythonQtSlotInfo* recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
221 206
222 207 void recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects);
223 208 void recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects);
224 209
225 210 bool lookForPropertyAndCache(const char* memberName);
226 211 bool lookForMethodAndCache(const char* memberName);
227 212 bool lookForEnumAndCache(const QMetaObject* m, const char* memberName);
228 213
229 214 PythonQtSlotInfo* findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
230 215 int findCharOffset(const char* sigStart, char someChar);
231 216
232 217 QHash<QByteArray, PythonQtMemberInfo> _cachedMembers;
233 218
234 219 PythonQtSlotInfo* _constructors;
235 220 PythonQtSlotInfo* _destructor;
236 221 QList<PythonQtSlotInfo*> _decoratorSlots;
237 222
238 223 QList<PythonQtObjectPtr> _enumWrappers;
239 224
240 225 const QMetaObject* _meta;
241 226
242 227 QByteArray _wrappedClassName;
243 228 QList<ParentClassInfo> _parentClasses;
244 229
245 230 QList<PythonQtPolymorphicHandlerCB*> _polymorphicHandlers;
246 231
247 232 QObject* _decoratorProvider;
248 233 PythonQtQObjectCreatorFunctionCB* _decoratorProviderCB;
249 234
250 235 PyObject* _pythonQtClassWrapper;
251 236
252 237 PythonQtShellSetInstanceWrapperCB* _shellSetInstanceWrapperCB;
253 238
254 239 int _metaTypeId;
255 240 int _typeSlots;
256 241
257 242 bool _isQObject;
258 243 bool _enumsCreated;
259 244
260 245 };
261 246
262 247 //---------------------------------------------------------------
263 248
264 249
265 250 #endif
@@ -1,494 +1,471
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtClassWrapper.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtClassWrapper.h"
43 43 #include <QObject>
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"
50 51
51 52 static PyObject* PythonQtInstanceWrapper_invert(PythonQtInstanceWrapper* wrapper)
52 53 {
53 54 PyObject* result = NULL;
54 55 static QByteArray memberName = "__invert__";
55 56 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
56 57 if (opSlot._type == PythonQtMemberInfo::Slot) {
57 58 result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr);
58 59 }
59 60 return result;
60 61 }
61 62
62 63 static int PythonQtInstanceWrapper_nonzero(PythonQtInstanceWrapper* wrapper)
63 64 {
64 65 int result = (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
65 66 if (result) {
66 67 static QByteArray memberName = "__nonzero__";
67 68 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
68 69 if (opSlot._type == PythonQtMemberInfo::Slot) {
69 70 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr);
70 71 if (resultObj == Py_False) {
71 72 result = 0;
72 73 }
73 74 Py_XDECREF(resultObj);
74 75 }
75 76 }
76 77 return result;
77 78 }
78 79
79 80
80 81 static PyObject* PythonQtInstanceWrapper_binaryfunc(PyObject* self, PyObject* other, const QByteArray& opName, const QByteArray& fallbackOpName = QByteArray())
81 82 {
82 83 // since we disabled type checking, we can receive any object as self, but we currently only support
83 84 // different objects on the right. Otherwise we would need to generate __radd__ etc. methods.
84 85 if (!PyObject_TypeCheck(self, &PythonQtInstanceWrapper_Type)) {
85 86 QString error = "Unsupported operation " + opName + "(" + self->ob_type->tp_name + ", " + other->ob_type->tp_name + ")";
86 87 PyErr_SetString(PyExc_ArithmeticError, error.toLatin1().data());
87 88 return NULL;
88 89 }
89 90 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)self;
90 91 PyObject* result = NULL;
91 92 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(opName);
92 93 if (opSlot._type == PythonQtMemberInfo::Slot) {
93 94 // TODO get rid of tuple
94 95 PyObject* args = PyTuple_New(1);
95 96 Py_INCREF(other);
96 97 PyTuple_SET_ITEM(args, 0, other);
97 98 result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr);
98 99 Py_DECREF(args);
99 100 if (!result && !fallbackOpName.isEmpty()) {
100 101 // try fallback if we did not get a result
101 102 result = PythonQtInstanceWrapper_binaryfunc(self, other, fallbackOpName);
102 103 }
103 104 }
104 105 return result;
105 106 }
106 107
107 108 #define BINARY_OP(NAME) \
108 109 static PyObject* PythonQtInstanceWrapper_ ## NAME(PyObject* self, PyObject* other) \
109 110 { \
110 111 static const QByteArray opName("__" #NAME "__"); \
111 112 return PythonQtInstanceWrapper_binaryfunc(self, other, opName); \
112 113 }
113 114
114 115 #define BINARY_OP_INPLACE(NAME) \
115 116 static PyObject* PythonQtInstanceWrapper_i ## NAME(PyObject* self, PyObject* other) \
116 117 { \
117 118 static const QByteArray opName("__i" #NAME "__"); \
118 119 static const QByteArray fallbackName("__" #NAME "__"); \
119 120 return PythonQtInstanceWrapper_binaryfunc(self, other, opName, fallbackName); \
120 121 }
121 122
122 123 BINARY_OP(add)
123 124 BINARY_OP(sub)
124 125 BINARY_OP(mul)
125 126 BINARY_OP(div)
126 127 BINARY_OP(and)
127 128 BINARY_OP(or)
128 129 BINARY_OP(xor)
129 130 BINARY_OP(mod)
130 131 BINARY_OP(lshift)
131 132 BINARY_OP(rshift)
132 133
133 134 BINARY_OP_INPLACE(add)
134 135 BINARY_OP_INPLACE(sub)
135 136 BINARY_OP_INPLACE(mul)
136 137 BINARY_OP_INPLACE(div)
137 138 BINARY_OP_INPLACE(and)
138 139 BINARY_OP_INPLACE(or)
139 140 BINARY_OP_INPLACE(xor)
140 141 BINARY_OP_INPLACE(mod)
141 142 BINARY_OP_INPLACE(lshift)
142 143 BINARY_OP_INPLACE(rshift)
143 144
144 145 static void initializeSlots(PythonQtClassWrapper* wrap)
145 146 {
146 147 int typeSlots = wrap->classInfo()->typeSlots();
147 148 if (typeSlots) {
148 149 if (typeSlots & PythonQt::Type_Add) {
149 150 wrap->_base.as_number.nb_add = (binaryfunc)PythonQtInstanceWrapper_add;
150 151 }
151 152 if (typeSlots & PythonQt::Type_Subtract) {
152 153 wrap->_base.as_number.nb_subtract = (binaryfunc)PythonQtInstanceWrapper_sub;
153 154 }
154 155 if (typeSlots & PythonQt::Type_Multiply) {
155 156 wrap->_base.as_number.nb_multiply = (binaryfunc)PythonQtInstanceWrapper_mul;
156 157 }
157 158 if (typeSlots & PythonQt::Type_Divide) {
158 159 wrap->_base.as_number.nb_divide = (binaryfunc)PythonQtInstanceWrapper_div;
159 160 wrap->_base.as_number.nb_true_divide = (binaryfunc)PythonQtInstanceWrapper_div;
160 161 }
161 162 if (typeSlots & PythonQt::Type_And) {
162 163 wrap->_base.as_number.nb_and = (binaryfunc)PythonQtInstanceWrapper_and;
163 164 }
164 165 if (typeSlots & PythonQt::Type_Or) {
165 166 wrap->_base.as_number.nb_or = (binaryfunc)PythonQtInstanceWrapper_or;
166 167 }
167 168 if (typeSlots & PythonQt::Type_Xor) {
168 169 wrap->_base.as_number.nb_xor = (binaryfunc)PythonQtInstanceWrapper_xor;
169 170 }
170 171 if (typeSlots & PythonQt::Type_Mod) {
171 172 wrap->_base.as_number.nb_remainder = (binaryfunc)PythonQtInstanceWrapper_mod;
172 173 }
173 174 if (typeSlots & PythonQt::Type_LShift) {
174 175 wrap->_base.as_number.nb_lshift = (binaryfunc)PythonQtInstanceWrapper_lshift;
175 176 }
176 177 if (typeSlots & PythonQt::Type_RShift) {
177 178 wrap->_base.as_number.nb_rshift = (binaryfunc)PythonQtInstanceWrapper_rshift;
178 179 }
179 180
180 181 if (typeSlots & PythonQt::Type_InplaceAdd) {
181 182 wrap->_base.as_number.nb_add = (binaryfunc)PythonQtInstanceWrapper_iadd;
182 183 }
183 184 if (typeSlots & PythonQt::Type_InplaceSubtract) {
184 185 wrap->_base.as_number.nb_subtract = (binaryfunc)PythonQtInstanceWrapper_isub;
185 186 }
186 187 if (typeSlots & PythonQt::Type_InplaceMultiply) {
187 188 wrap->_base.as_number.nb_multiply = (binaryfunc)PythonQtInstanceWrapper_imul;
188 189 }
189 190 if (typeSlots & PythonQt::Type_InplaceDivide) {
190 191 wrap->_base.as_number.nb_inplace_divide = (binaryfunc)PythonQtInstanceWrapper_idiv;
191 192 wrap->_base.as_number.nb_inplace_true_divide = (binaryfunc)PythonQtInstanceWrapper_idiv;
192 193 }
193 194 if (typeSlots & PythonQt::Type_InplaceAnd) {
194 195 wrap->_base.as_number.nb_inplace_and = (binaryfunc)PythonQtInstanceWrapper_iand;
195 196 }
196 197 if (typeSlots & PythonQt::Type_InplaceOr) {
197 198 wrap->_base.as_number.nb_inplace_or = (binaryfunc)PythonQtInstanceWrapper_ior;
198 199 }
199 200 if (typeSlots & PythonQt::Type_InplaceXor) {
200 201 wrap->_base.as_number.nb_inplace_xor = (binaryfunc)PythonQtInstanceWrapper_ixor;
201 202 }
202 203 if (typeSlots & PythonQt::Type_InplaceMod) {
203 204 wrap->_base.as_number.nb_inplace_remainder = (binaryfunc)PythonQtInstanceWrapper_imod;
204 205 }
205 206 if (typeSlots & PythonQt::Type_InplaceLShift) {
206 207 wrap->_base.as_number.nb_inplace_lshift = (binaryfunc)PythonQtInstanceWrapper_ilshift;
207 208 }
208 209 if (typeSlots & PythonQt::Type_InplaceRShift) {
209 210 wrap->_base.as_number.nb_inplace_rshift = (binaryfunc)PythonQtInstanceWrapper_irshift;
210 211 }
211 212 if (typeSlots & PythonQt::Type_Invert) {
212 213 wrap->_base.as_number.nb_invert = (unaryfunc)PythonQtInstanceWrapper_invert;
213 214 }
214 215 if (typeSlots & PythonQt::Type_NonZero) {
215 216 wrap->_base.as_number.nb_nonzero = (inquiry)PythonQtInstanceWrapper_nonzero;
216 217 }
217 218 }
218 219 }
219 220
220 221 static PyObject* PythonQtClassWrapper_alloc(PyTypeObject *self, Py_ssize_t nitems)
221 222 {
222 223 // call the default type alloc
223 224 PyObject* obj = PyType_Type.tp_alloc(self, nitems);
224 225
225 226 // take current class type, if we are called via newPythonQtClassWrapper()
226 227 PythonQtClassWrapper* wrap = (PythonQtClassWrapper*)obj;
227 228 wrap->_classInfo = PythonQt::priv()->currentClassInfoForClassWrapperCreation();
228 229 if (wrap->_classInfo) {
229 230 initializeSlots(wrap);
230 231 }
231 232
232 233 return obj;
233 234 }
234 235
235 236
236 237 static int PythonQtClassWrapper_init(PythonQtClassWrapper* self, PyObject* args, PyObject* kwds)
237 238 {
238 239 // call the default type init
239 240 if (PyType_Type.tp_init((PyObject *)self, args, kwds) < 0) {
240 241 return -1;
241 242 }
242 243
243 244 // if we have no CPP class information, try our base class
244 245 if (!self->classInfo()) {
245 246 PyTypeObject* superType = ((PyTypeObject *)self)->tp_base;
246 247
247 248 if (!superType || (superType->ob_type != &PythonQtClassWrapper_Type)) {
248 249 PyErr_Format(PyExc_TypeError, "type %s is not derived from PythonQtClassWrapper", ((PyTypeObject*)self)->tp_name);
249 250 return -1;
250 251 }
251 252
252 253 // take the class info from the superType
253 254 self->_classInfo = ((PythonQtClassWrapper*)superType)->classInfo();
254 255 }
255 256
256 257 return 0;
257 258 }
258 259
259 260 static PyObject *PythonQtClassWrapper_classname(PythonQtClassWrapper* type)
260 261 {
261 262 return PyString_FromString((QString("Class_") + type->classInfo()->className()).toLatin1().data());
262 263 }
263 264
264 265 static PyObject *PythonQtClassWrapper_help(PythonQtClassWrapper* type)
265 266 {
266 267 return PythonQt::self()->helpCalled(type->classInfo());
267 268 }
268 269
269 270 PyObject *PythonQtClassWrapper_delete(PythonQtClassWrapper *type, PyObject *args)
270 271 {
271 272 Q_UNUSED(type);
272 273
273 274 Py_ssize_t argc = PyTuple_Size(args);
274 275 if (argc>0) {
275 276 PyObject* self = PyTuple_GET_ITEM(args, 0);
276 277 if (PyObject_TypeCheck(self, &PythonQtInstanceWrapper_Type)) {
277 278 return PythonQtInstanceWrapper_delete((PythonQtInstanceWrapper*)self);
278 279 }
279 280 }
280 281 return NULL;
281 282 }
282 283
283 284 PyObject *PythonQtClassWrapper_inherits(PythonQtClassWrapper *type, PyObject *args)
284 285 {
285 286 Q_UNUSED(type);
286 287 PythonQtInstanceWrapper* wrapper = NULL;
287 288 char *name = NULL;
288 289 if (!PyArg_ParseTuple(args, "O!s:PythonQtClassWrapper.inherits",&PythonQtInstanceWrapper_Type, &wrapper, &name)) {
289 290 return NULL;
290 291 }
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 },
331 300 {"inherits", (PyCFunction)PythonQtClassWrapper_inherits, METH_VARARGS,
332 301 "Returns if the class inherits or is of given type name"
333 302 },
334 303 {"help", (PyCFunction)PythonQtClassWrapper_help, METH_NOARGS,
335 304 "Shows the help of available methods for this class"
336 305 },
337 306 {"delete", (PyCFunction)PythonQtClassWrapper_delete, METH_VARARGS,
338 307 "Deletes the given C++ object"
339 308 },
340 309 {NULL, NULL, 0 , NULL} /* Sentinel */
341 310 };
342 311
343 312
344 313 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name)
345 314 {
346 315 const char *attributeName;
347 316 PythonQtClassWrapper *wrapper = (PythonQtClassWrapper *)obj;
348 317
349 318 if ((attributeName = PyString_AsString(name)) == NULL) {
350 319 return NULL;
351 320 }
352 321 if (obj == (PyObject*)&PythonQtInstanceWrapper_Type) {
353 322 return NULL;
354 323 }
355 324
356 325 if (qstrcmp(attributeName, "__dict__")==0) {
357 PyObject* dict = ((PyTypeObject *)wrapper)->tp_dict;
326 PyObject* objectDict = ((PyTypeObject *)wrapper)->tp_dict;
358 327 if (!wrapper->classInfo()) {
359 Py_INCREF(dict);
360 return dict;
328 Py_INCREF(objectDict);
329 return objectDict;
361 330 }
362 dict = PyDict_Copy(dict);
331 PyObject* dict = PyDict_New();
363 332
364 QStringList l = wrapper->classInfo()->memberList(false);
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) {
368 337 PyDict_SetItemString(dict, name.toLatin1().data(), o);
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 = 1; PythonQtClassWrapper_methods[i].ml_name != NULL; 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) {
390 371 PyObject* enumValue = member._enumValue;
391 372 Py_INCREF(enumValue);
392 373 return enumValue;
393 374 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
394 375 PyObject* enumWrapper = member._enumWrapper;
395 376 Py_INCREF(enumWrapper);
396 377 return enumWrapper;
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());
418 395 return NULL;
419 396 }
420 397
421 398 static int PythonQtClassWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
422 399 {
423 400 return PyType_Type.tp_setattro(obj,name,value);
424 401 }
425 402
426 403 /*
427 404 static PyObject * PythonQtClassWrapper_repr(PyObject * obj)
428 405 {
429 406 PythonQtClassWrapper* wrapper = (PythonQtClassWrapper*)obj;
430 407 if (wrapper->classInfo()->isCPPWrapper()) {
431 408 const QMetaObject* meta = wrapper->classInfo()->metaObject();
432 409 if (!meta) {
433 410 QObject* decorator = wrapper->classInfo()->decorator();
434 411 if (decorator) {
435 412 meta = decorator->metaObject();
436 413 }
437 414 }
438 415 if (meta) {
439 416 return PyString_FromFormat("%s Class (C++ wrapped by %s)", wrapper->classInfo()->className(), meta->className());
440 417 } else {
441 418 return PyString_FromFormat("%s Class (C++ unwrapped)", wrapper->classInfo()->className());
442 419 }
443 420 } else {
444 421 return PyString_FromFormat("%s Class", wrapper->classInfo()->className());
445 422 }
446 423 }
447 424
448 425 */
449 426
450 427 PyTypeObject PythonQtClassWrapper_Type = {
451 428 PyObject_HEAD_INIT(NULL)
452 429 0, /*ob_size*/
453 430 "PythonQt.PythonQtClassWrapper", /*tp_name*/
454 431 sizeof(PythonQtClassWrapper), /*tp_basicsize*/
455 432 0, /*tp_itemsize*/
456 433 0, /*tp_dealloc*/
457 434 0, /*tp_print*/
458 435 0, /*tp_getattr*/
459 436 0, /*tp_setattr*/
460 437 0, /*tp_compare*/
461 438 0, //PythonQtClassWrapper_repr, /*tp_repr*/
462 439 0, /*tp_as_number*/
463 440 0, /*tp_as_sequence*/
464 441 0, /*tp_as_mapping*/
465 442 0, /*tp_hash */
466 443 0, /*tp_call*/
467 444 0, /*tp_str*/
468 445 PythonQtClassWrapper_getattro, /*tp_getattro*/
469 446 PythonQtClassWrapper_setattro, /*tp_setattro*/
470 447 0, /*tp_as_buffer*/
471 448 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
472 449 0, /* tp_doc */
473 450 0, /* tp_traverse */
474 451 0, /* tp_clear */
475 452 0, /* tp_richcompare */
476 453 0, /* tp_weaklistoffset */
477 454 0, /* tp_iter */
478 455 0, /* tp_iternext */
479 456 0, /* tp_methods */
480 457 0, /* tp_members */
481 458 0, /* tp_getset */
482 459 0, /* tp_base */
483 460 0, /* tp_dict */
484 461 0, /* tp_descr_get */
485 462 0, /* tp_descr_set */
486 463 0, /* tp_dictoffset */
487 464 (initproc)PythonQtClassWrapper_init, /* tp_init */
488 465 PythonQtClassWrapper_alloc, /* tp_alloc */
489 466 0, /* tp_new */
490 467 0, /* tp_free */
491 468 };
492 469
493 470 //-------------------------------------------------------
494 471
@@ -1,76 +1,81
1 1 #ifndef _PYTHONQTIMPORTFILEINTERFACE_H
2 2 #define _PYTHONQTIMPORTFILEINTERFACE_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtImportFileInterface.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include <QDateTime>
46 46 #include <QString>
47 47 #include <QByteArray>
48 48
49 49 //! Defines an abstract interface to file access for the Python import statement.
50 50 //! see PythonQt::setImporter()
51 51 class PythonQtImportFileInterface {
52 52
53 53 public:
54 54 // get rid of warnings
55 55 virtual ~PythonQtImportFileInterface() {}
56 56
57 57 //! read the given file as byte array, without doing any linefeed translations
58 58 virtual QByteArray readFileAsBytes(const QString& filename) = 0;
59 59
60 60 //! read a source file, expects a readable Python text file with translated line feeds.
61 61 //! If the file can not be load OR it can not be verified, ok is set to false
62 62 virtual QByteArray readSourceFile(const QString& filename, bool& ok) = 0;
63 63
64 64 //! returns if the file exists
65 65 virtual bool exists(const QString& filename) = 0;
66 66
67 67 //! get the last modified data of a file
68 68 virtual QDateTime lastModifiedDate(const QString& filename) = 0;
69 69
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
76 81
@@ -1,822 +1,828
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtImporter.h
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 // This module was inspired by the zipimport.c module of the original
41 41 // Python distribution. Most of the functions are identical or slightly
42 42 // modified to do all the loading of Python files via an external file interface.
43 43 // In contrast to zipimport.c, this module also writes *.pyc files
44 44 // automatically if it has write access/is not inside of a zip file.
45 45 //----------------------------------------------------------------------------------
46 46
47 47 #include "PythonQtImporter.h"
48 48 #include "PythonQtImportFileInterface.h"
49 49 #include "PythonQt.h"
50 50 #include "PythonQtConversion.h"
51 51 #include <QFile>
52 52 #include <QFileInfo>
53 53
54 54 #define IS_SOURCE 0x0
55 55 #define IS_BYTECODE 0x1
56 56 #define IS_PACKAGE 0x2
57 57
58 58 struct st_mlab_searchorder {
59 59 char suffix[14];
60 60 int type;
61 61 };
62 62
63 63 /* mlab_searchorder defines how we search for a module in the Zip
64 64 archive: we first search for a package __init__, then for
65 65 non-package .pyc, .pyo and .py entries. The .pyc and .pyo entries
66 66 are swapped by initmlabimport() if we run in optimized mode. Also,
67 67 '/' is replaced by SEP there. */
68 68 struct st_mlab_searchorder mlab_searchorder[] = {
69 69 {"/__init__.pyc", IS_PACKAGE | IS_BYTECODE},
70 70 {"/__init__.pyo", IS_PACKAGE | IS_BYTECODE},
71 71 {"/__init__.py", IS_PACKAGE | IS_SOURCE},
72 72 {".pyc", IS_BYTECODE},
73 73 {".pyo", IS_BYTECODE},
74 74 {".py", IS_SOURCE},
75 75 {"", 0}
76 76 };
77 77
78 78 extern PyTypeObject PythonQtImporter_Type;
79 79 PyObject *PythonQtImportError;
80 80
81 81 QString PythonQtImport::getSubName(const QString& str)
82 82 {
83 83 int idx = str.lastIndexOf('.');
84 84 if (idx!=-1) {
85 85 return str.mid(idx+1);
86 86 } else {
87 87 return str;
88 88 }
89 89 }
90 90
91 91 PythonQtImport::ModuleInfo PythonQtImport::getModuleInfo(PythonQtImporter* self, const QString& fullname)
92 92 {
93 93 ModuleInfo info;
94 94 QString subname;
95 95 struct st_mlab_searchorder *zso;
96 96
97 97 subname = getSubName(fullname);
98 98 QString path = *self->_path + "/" + subname;
99 99
100 100 QString test;
101 101 for (zso = mlab_searchorder; *zso->suffix; zso++) {
102 102 test = path + zso->suffix;
103 103 if (PythonQt::importInterface()->exists(test)) {
104 104 info.fullPath = test;
105 105 info.moduleName = subname;
106 106 info.type = (zso->type & IS_PACKAGE)?MI_PACKAGE:MI_MODULE;
107 107 return info;
108 108 }
109 109 }
110 110 // test if it is a shared library
111 111 foreach(const QString& suffix, PythonQt::priv()->sharedLibrarySuffixes()) {
112 112 test = path+suffix;
113 113 if (PythonQt::importInterface()->exists(test)) {
114 114 info.fullPath = test;
115 115 info.moduleName = subname;
116 116 info.type = MI_SHAREDLIBRARY;
117 117 return info;
118 118 }
119 119 }
120 120 return info;
121 121 }
122 122
123 123
124 124 /* PythonQtImporter.__init__
125 125 Just store the path argument (or reject if it is in the ignorePaths list
126 126 */
127 127 int PythonQtImporter_init(PythonQtImporter *self, PyObject *args, PyObject * /*kwds*/)
128 128 {
129 129 self->_path = NULL;
130 130
131 131 const char* cpath;
132 132 if (!PyArg_ParseTuple(args, "s",
133 133 &cpath))
134 134 return -1;
135 135
136 136 QString path(cpath);
137 137 if (PythonQt::importInterface()->exists(path)) {
138 138 const QStringList& ignorePaths = PythonQt::self()->getImporterIgnorePaths();
139 139 foreach(QString ignorePath, ignorePaths) {
140 140 if (path.startsWith(ignorePath)) {
141 141 PyErr_SetString(PythonQtImportError,
142 142 "path ignored");
143 143 return -1;
144 144 }
145 145 }
146 146
147 147 self->_path = new QString(path);
148 148 return 0;
149 149 } else {
150 150 PyErr_SetString(PythonQtImportError,
151 151 "path does not exist error");
152 152 return -1;
153 153 }
154 154 }
155 155
156 156 void
157 157 PythonQtImporter_dealloc(PythonQtImporter *self)
158 158 {
159 159 // free the stored path
160 160 if (self->_path) delete self->_path;
161 161 // free ourself
162 162 self->ob_type->tp_free((PyObject *)self);
163 163 }
164 164
165 165
166 166 /* Check whether we can satisfy the import of the module named by
167 167 'fullname'. Return self if we can, None if we can't. */
168 168 PyObject *
169 169 PythonQtImporter_find_module(PyObject *obj, PyObject *args)
170 170 {
171 171 PythonQtImporter *self = (PythonQtImporter *)obj;
172 172 PyObject *path = NULL;
173 173 char *fullname;
174 174
175 175 if (!PyArg_ParseTuple(args, "s|O:PythonQtImporter.find_module",
176 176 &fullname, &path))
177 177 return NULL;
178 178
179 179 //qDebug() << "looking for " << fullname << " at " << *self->_path;
180 180
181 181 PythonQtImport::ModuleInfo info = PythonQtImport::getModuleInfo(self, fullname);
182 182 if (info.type != PythonQtImport::MI_NOT_FOUND) {
183 183 Py_INCREF(self);
184 184 return (PyObject *)self;
185 185 } else {
186 186 Py_INCREF(Py_None);
187 187 return Py_None;
188 188 }
189 189 }
190 190
191 191 /* Load and return the module named by 'fullname'. */
192 192 PyObject *
193 193 PythonQtImporter_load_module(PyObject *obj, PyObject *args)
194 194 {
195 195 PythonQtImporter *self = (PythonQtImporter *)obj;
196 196 PyObject *code = NULL, *mod = NULL, *dict = NULL;
197 197 char *fullname;
198 198
199 199 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.load_module",
200 200 &fullname))
201 201 return NULL;
202 202
203 203 PythonQtImport::ModuleInfo info = PythonQtImport::getModuleInfo(self, fullname);
204 204 if (info.type == PythonQtImport::MI_NOT_FOUND) {
205 205 return NULL;
206 206 }
207 207
208 208 if (info.type == PythonQtImport::MI_PACKAGE || info.type == PythonQtImport::MI_MODULE) {
209 209 QString fullPath;
210 210 code = PythonQtImport::getModuleCode(self, fullname, fullPath);
211 211 if (code == NULL) {
212 212 return NULL;
213 213 }
214 214
215 215 mod = PyImport_AddModule(fullname);
216 216 if (mod == NULL) {
217 217 Py_DECREF(code);
218 218 return NULL;
219 219 }
220 220 dict = PyModule_GetDict(mod);
221 221
222 222 if (PyDict_SetItemString(dict, "__loader__", (PyObject *)self) != 0) {
223 223 Py_DECREF(code);
224 224 Py_DECREF(mod);
225 225 return NULL;
226 226 }
227 227
228 228 if (info.type == PythonQtImport::MI_PACKAGE) {
229 229 PyObject *pkgpath, *fullpath;
230 230 QString subname = info.moduleName;
231 231 int err;
232 232
233 233 fullpath = PyString_FromFormat("%s%c%s",
234 234 self->_path->toLatin1().constData(),
235 235 SEP,
236 236 subname.toLatin1().constData());
237 237 if (fullpath == NULL) {
238 238 Py_DECREF(code);
239 239 Py_DECREF(mod);
240 240 return NULL;
241 241 }
242 242
243 243 pkgpath = Py_BuildValue("[O]", fullpath);
244 244 Py_DECREF(fullpath);
245 245 if (pkgpath == NULL) {
246 246 Py_DECREF(code);
247 247 Py_DECREF(mod);
248 248 return NULL;
249 249 }
250 250 err = PyDict_SetItemString(dict, "__path__", pkgpath);
251 251 Py_DECREF(pkgpath);
252 252 if (err != 0) {
253 253 Py_DECREF(code);
254 254 Py_DECREF(mod);
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",
262 268 fullname, fullPath.toLatin1().constData());
263 269 }
264 270 } else {
265 271 PythonQtObjectPtr imp;
266 272 imp.setNewRef(PyImport_ImportModule("imp"));
267 273
268 274 // Create a PyList with the current path as its single element,
269 275 // which is required for find_module (it won't accept a tuple...)
270 276 PythonQtObjectPtr pathList;
271 277 pathList.setNewRef(PythonQtConv::QStringListToPyList(QStringList() << *self->_path));
272 278
273 279 QVariantList args;
274 280 // Pass the module name without the package prefix
275 281 args.append(info.moduleName);
276 282 // And the path where we know that the shared library is
277 283 args.append(QVariant::fromValue(pathList));
278 284 QVariant result = imp.call("find_module", args);
279 285 if (result.isValid()) {
280 286 // This will return a tuple with (file, pathname, description=(suffix,mode,type))
281 287 QVariantList list = result.toList();
282 288 if (list.count()==3) {
283 289 // We prepend the full module name (including package prefix)
284 290 list.prepend(fullname);
285 291 #ifdef __linux
286 292 #ifdef _DEBUG
287 293 // imp_find_module() does not respect the debug suffix '_d' on Linux,
288 294 // so it does not return the correct file path and we correct it now
289 295 // find_module opened a file to the release library, but that file handle is
290 296 // ignored on Linux and Windows, maybe on MacOS also.
291 297 list[2] = info.fullPath;
292 298 #endif
293 299 #endif
294 300 // And call "load_module" with (fullname, file, pathname, description=(suffix,mode,type))
295 301 PythonQtObjectPtr module = imp.call("load_module", list);
296 302 mod = module.object();
297 303 if (mod) {
298 304 Py_INCREF(mod);
299 305 }
300 306
301 307 // Finally, we need to close the file again, which find_module opened for us
302 308 PythonQtObjectPtr file = list.at(1);
303 309 file.call("close");
304 310 }
305 311 }
306 312 }
307 313 return mod;
308 314 }
309 315
310 316
311 317 PyObject *
312 318 PythonQtImporter_get_data(PyObject* /*obj*/, PyObject* /*args*/)
313 319 {
314 320 // EXTRA, NOT YET IMPLEMENTED
315 321 return NULL;
316 322 }
317 323
318 324 PyObject *
319 325 PythonQtImporter_get_code(PyObject *obj, PyObject *args)
320 326 {
321 327 PythonQtImporter *self = (PythonQtImporter *)obj;
322 328 char *fullname;
323 329
324 330 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.get_code", &fullname))
325 331 return NULL;
326 332
327 333 QString notused;
328 334 return PythonQtImport::getModuleCode(self, fullname, notused);
329 335 }
330 336
331 337 PyObject *
332 338 PythonQtImporter_get_source(PyObject * /*obj*/, PyObject * /*args*/)
333 339 {
334 340 // EXTRA, NOT YET IMPLEMENTED
335 341 return NULL;
336 342 }
337 343
338 344 PyDoc_STRVAR(doc_find_module,
339 345 "find_module(fullname, path=None) -> self or None.\n\
340 346 \n\
341 347 Search for a module specified by 'fullname'. 'fullname' must be the\n\
342 348 fully qualified (dotted) module name. It returns the PythonQtImporter\n\
343 349 instance itself if the module was found, or None if it wasn't.\n\
344 350 The optional 'path' argument is ignored -- it's there for compatibility\n\
345 351 with the importer protocol.");
346 352
347 353 PyDoc_STRVAR(doc_load_module,
348 354 "load_module(fullname) -> module.\n\
349 355 \n\
350 356 Load the module specified by 'fullname'. 'fullname' must be the\n\
351 357 fully qualified (dotted) module name. It returns the imported\n\
352 358 module, or raises PythonQtImportError if it wasn't found.");
353 359
354 360 PyDoc_STRVAR(doc_get_data,
355 361 "get_data(pathname) -> string with file data.\n\
356 362 \n\
357 363 Return the data associated with 'pathname'. Raise IOError if\n\
358 364 the file wasn't found.");
359 365
360 366 PyDoc_STRVAR(doc_get_code,
361 367 "get_code(fullname) -> code object.\n\
362 368 \n\
363 369 Return the code object for the specified module. Raise PythonQtImportError\n\
364 370 is the module couldn't be found.");
365 371
366 372 PyDoc_STRVAR(doc_get_source,
367 373 "get_source(fullname) -> source string.\n\
368 374 \n\
369 375 Return the source code for the specified module. Raise PythonQtImportError\n\
370 376 is the module couldn't be found, return None if the archive does\n\
371 377 contain the module, but has no source for it.");
372 378
373 379 PyMethodDef PythonQtImporter_methods[] = {
374 380 {"find_module", PythonQtImporter_find_module, METH_VARARGS,
375 381 doc_find_module},
376 382 {"load_module", PythonQtImporter_load_module, METH_VARARGS,
377 383 doc_load_module},
378 384 {"get_data", PythonQtImporter_get_data, METH_VARARGS,
379 385 doc_get_data},
380 386 {"get_code", PythonQtImporter_get_code, METH_VARARGS,
381 387 doc_get_code},
382 388 {"get_source", PythonQtImporter_get_source, METH_VARARGS,
383 389 doc_get_source},
384 390 {NULL, NULL, 0 , NULL} /* sentinel */
385 391 };
386 392
387 393
388 394 PyDoc_STRVAR(PythonQtImporter_doc,
389 395 "PythonQtImporter(path) -> PythonQtImporter object\n\
390 396 \n\
391 397 Create a new PythonQtImporter instance. 'path' must be a valid path on disk/or inside of a zip file known to MeVisLab\n\
392 398 . Every path is accepted.");
393 399
394 400 #define DEFERRED_ADDRESS(ADDR) 0
395 401
396 402 PyTypeObject PythonQtImporter_Type = {
397 403 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
398 404 0,
399 405 "PythonQtImport.PythonQtImporter",
400 406 sizeof(PythonQtImporter),
401 407 0, /* tp_itemsize */
402 408 (destructor)PythonQtImporter_dealloc, /* tp_dealloc */
403 409 0, /* tp_print */
404 410 0, /* tp_getattr */
405 411 0, /* tp_setattr */
406 412 0, /* tp_compare */
407 413 0, /* tp_repr */
408 414 0, /* tp_as_number */
409 415 0, /* tp_as_sequence */
410 416 0, /* tp_as_mapping */
411 417 0, /* tp_hash */
412 418 0, /* tp_call */
413 419 0, /* tp_str */
414 420 PyObject_GenericGetAttr, /* tp_getattro */
415 421 0, /* tp_setattro */
416 422 0, /* tp_as_buffer */
417 423 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE , /* tp_flags */
418 424 PythonQtImporter_doc, /* tp_doc */
419 425 0, /* tp_traverse */
420 426 0, /* tp_clear */
421 427 0, /* tp_richcompare */
422 428 0, /* tp_weaklistoffset */
423 429 0, /* tp_iter */
424 430 0, /* tp_iternext */
425 431 PythonQtImporter_methods, /* tp_methods */
426 432 0, /* tp_members */
427 433 0, /* tp_getset */
428 434 0, /* tp_base */
429 435 0, /* tp_dict */
430 436 0, /* tp_descr_get */
431 437 0, /* tp_descr_set */
432 438 0, /* tp_dictoffset */
433 439 (initproc)PythonQtImporter_init, /* tp_init */
434 440 PyType_GenericAlloc, /* tp_alloc */
435 441 PyType_GenericNew, /* tp_new */
436 442 PyObject_Del, /* tp_free */
437 443 };
438 444
439 445
440 446 /* Given a buffer, return the long that is represented by the first
441 447 4 bytes, encoded as little endian. This partially reimplements
442 448 marshal.c:r_long() */
443 449 long
444 450 PythonQtImport::getLong(unsigned char *buf)
445 451 {
446 452 long x;
447 453 x = buf[0];
448 454 x |= (long)buf[1] << 8;
449 455 x |= (long)buf[2] << 16;
450 456 x |= (long)buf[3] << 24;
451 457 #if SIZEOF_LONG > 4
452 458 /* Sign extension for 64-bit machines */
453 459 x |= -(x & 0x80000000L);
454 460 #endif
455 461 return x;
456 462 }
457 463
458 464 FILE *
459 465 open_exclusive(const QString& filename)
460 466 {
461 467 #if defined(O_EXCL)&&defined(O_CREAT)&&defined(O_WRONLY)&&defined(O_TRUNC)
462 468 /* Use O_EXCL to avoid a race condition when another process tries to
463 469 write the same file. When that happens, our open() call fails,
464 470 which is just fine (since it's only a cache).
465 471 XXX If the file exists and is writable but the directory is not
466 472 writable, the file will never be written. Oh well.
467 473 */
468 474 QFile::remove(filename);
469 475
470 476 int fd;
471 477 int flags = O_EXCL|O_CREAT|O_WRONLY|O_TRUNC;
472 478 #ifdef O_BINARY
473 479 flags |= O_BINARY; /* necessary for Windows */
474 480 #endif
475 481 #ifdef WIN32
476 482 fd = _wopen(filename.ucs2(), flags, 0666);
477 483 #else
478 484 fd = open(filename.local8Bit(), flags, 0666);
479 485 #endif
480 486 if (fd < 0)
481 487 return NULL;
482 488 return fdopen(fd, "wb");
483 489 #else
484 490 /* Best we can do -- on Windows this can't happen anyway */
485 491 return fopen(filename.toLocal8Bit().constData(), "wb");
486 492 #endif
487 493 }
488 494
489 495
490 496 void PythonQtImport::writeCompiledModule(PyCodeObject *co, const QString& filename, long mtime)
491 497 {
492 498 FILE *fp;
493 499 // we do not want to write Qt resources to disk, do we?
494 500 if (filename.startsWith(":")) {
495 501 return;
496 502 }
497 503 fp = open_exclusive(filename);
498 504 if (fp == NULL) {
499 505 if (Py_VerboseFlag)
500 506 PySys_WriteStderr(
501 507 "# can't create %s\n", filename.toLatin1().constData());
502 508 return;
503 509 }
504 510 #if PY_VERSION_HEX < 0x02040000
505 511 PyMarshal_WriteLongToFile(PyImport_GetMagicNumber(), fp);
506 512 #else
507 513 PyMarshal_WriteLongToFile(PyImport_GetMagicNumber(), fp, Py_MARSHAL_VERSION);
508 514 #endif
509 515 /* First write a 0 for mtime */
510 516 #if PY_VERSION_HEX < 0x02040000
511 517 PyMarshal_WriteLongToFile(0L, fp);
512 518 #else
513 519 PyMarshal_WriteLongToFile(0L, fp, Py_MARSHAL_VERSION);
514 520 #endif
515 521 #if PY_VERSION_HEX < 0x02040000
516 522 PyMarshal_WriteObjectToFile((PyObject *)co, fp);
517 523 #else
518 524 PyMarshal_WriteObjectToFile((PyObject *)co, fp, Py_MARSHAL_VERSION);
519 525 #endif
520 526 if (ferror(fp)) {
521 527 if (Py_VerboseFlag)
522 528 PySys_WriteStderr("# can't write %s\n", filename.toLatin1().constData());
523 529 /* Don't keep partial file */
524 530 fclose(fp);
525 531 QFile::remove(filename);
526 532 return;
527 533 }
528 534 /* Now write the true mtime */
529 535 fseek(fp, 4L, 0);
530 536 #if PY_VERSION_HEX < 0x02040000
531 537 PyMarshal_WriteLongToFile(mtime, fp);
532 538 #else
533 539 PyMarshal_WriteLongToFile(mtime, fp, Py_MARSHAL_VERSION);
534 540 #endif
535 541 fflush(fp);
536 542 fclose(fp);
537 543 if (Py_VerboseFlag)
538 544 PySys_WriteStderr("# wrote %s\n", filename.toLatin1().constData());
539 545 //#ifdef macintosh
540 546 // PyMac_setfiletype(cpathname, 'Pyth', 'PYC ');
541 547 //#endif
542 548 }
543 549
544 550 /* Given the contents of a .py[co] file in a buffer, unmarshal the data
545 551 and return the code object. Return None if it the magic word doesn't
546 552 match (we do this instead of raising an exception as we fall back
547 553 to .py if available and we don't want to mask other errors).
548 554 Returns a new reference. */
549 555 PyObject *
550 556 PythonQtImport::unmarshalCode(const QString& path, const QByteArray& data, time_t mtime)
551 557 {
552 558 PyObject *code;
553 559 // ugly cast, but Python API is not const safe
554 560 char *buf = (char*) data.constData();
555 561 int size = data.size();
556 562
557 563 if (size <= 9) {
558 564 PySys_WriteStderr("# %s has bad pyc data\n",
559 565 path.toLatin1().constData());
560 566 Py_INCREF(Py_None);
561 567 return Py_None;
562 568 }
563 569
564 570 if (getLong((unsigned char *)buf) != PyImport_GetMagicNumber()) {
565 571 if (Py_VerboseFlag)
566 572 PySys_WriteStderr("# %s has bad magic\n",
567 573 path.toLatin1().constData());
568 574 Py_INCREF(Py_None);
569 575 return Py_None;
570 576 }
571 577
572 578 if (mtime != 0) {
573 579 time_t timeDiff = getLong((unsigned char *)buf + 4) - mtime;
574 580 if (timeDiff<0) { timeDiff = -timeDiff; }
575 581 if (timeDiff > 1) {
576 582 if (Py_VerboseFlag)
577 583 PySys_WriteStderr("# %s has bad mtime\n",
578 584 path.toLatin1().constData());
579 585 Py_INCREF(Py_None);
580 586 return Py_None;
581 587 }
582 588 }
583 589
584 590 code = PyMarshal_ReadObjectFromString(buf + 8, size - 8);
585 591 if (code == NULL)
586 592 return NULL;
587 593 if (!PyCode_Check(code)) {
588 594 Py_DECREF(code);
589 595 PyErr_Format(PyExc_TypeError,
590 596 "compiled module %.200s is not a code object",
591 597 path.toLatin1().constData());
592 598 return NULL;
593 599 }
594 600 return code;
595 601 }
596 602
597 603
598 604 /* Given a string buffer containing Python source code, compile it
599 605 return and return a code object as a new reference. */
600 606 PyObject *
601 607 PythonQtImport::compileSource(const QString& path, const QByteArray& data)
602 608 {
603 609 PyObject *code;
604 610 QByteArray data1 = data;
605 611 // in qt4, data is null terminated
606 612 // data1.resize(data.size()+1);
607 613 // data1.data()[data.size()-1] = 0;
608 614 code = Py_CompileString(data.data(), path.toLatin1().constData(),
609 615 Py_file_input);
610 616 return code;
611 617 }
612 618
613 619
614 620 /* Return the code object for the module named by 'fullname' from the
615 621 Zip archive as a new reference. */
616 622 PyObject *
617 623 PythonQtImport::getCodeFromData(const QString& path, int isbytecode,int /*ispackage*/, time_t mtime)
618 624 {
619 625 PyObject *code;
620 626
621 627 QByteArray qdata;
622 628 if (!isbytecode) {
623 629 // mlabDebugConst("MLABPython", "reading source " << path);
624 630 bool ok;
625 631 qdata = PythonQt::importInterface()->readSourceFile(path, ok);
626 632 if (!ok) {
627 633 // mlabErrorConst("PythonQtImporter","File could not be verified" << path);
628 634 return NULL;
629 635 }
630 636 if (qdata == " ") {
631 637 qdata.clear();
632 638 }
633 639 } else {
634 640 qdata = PythonQt::importInterface()->readFileAsBytes(path);
635 641 }
636 642
637 643 if (isbytecode) {
638 644 // mlabDebugConst("MLABPython", "reading bytecode " << path);
639 645 code = unmarshalCode(path, qdata, mtime);
640 646 }
641 647 else {
642 648 // mlabDebugConst("MLABPython", "compiling source " << path);
643 649 code = compileSource(path, qdata);
644 650 if (code) {
645 651 // save a pyc file if possible
646 652 QDateTime time;
647 653 time = PythonQt::importInterface()->lastModifiedDate(path);
648 654 writeCompiledModule((PyCodeObject*)code, path+"c", time.toTime_t());
649 655 }
650 656 }
651 657 return code;
652 658 }
653 659
654 660 time_t
655 661 PythonQtImport::getMTimeOfSource(const QString& path)
656 662 {
657 663 time_t mtime = 0;
658 664 QString path2 = path;
659 665 path2.truncate(path.length()-1);
660 666
661 667 if (PythonQt::importInterface()->exists(path2)) {
662 668 QDateTime t = PythonQt::importInterface()->lastModifiedDate(path2);
663 669 if (t.isValid()) {
664 670 mtime = t.toTime_t();
665 671 }
666 672 }
667 673
668 674 return mtime;
669 675 }
670 676
671 677 /* Get the code object associated with the module specified by
672 678 'fullname'. */
673 679 PyObject *
674 680 PythonQtImport::getModuleCode(PythonQtImporter *self, const char* fullname, QString& modpath)
675 681 {
676 682 QString subname;
677 683 struct st_mlab_searchorder *zso;
678 684
679 685 subname = getSubName(fullname);
680 686 QString path = *self->_path + "/" + subname;
681 687
682 688 QString test;
683 689 for (zso = mlab_searchorder; *zso->suffix; zso++) {
684 690 PyObject *code = NULL;
685 691 test = path + zso->suffix;
686 692
687 693 if (Py_VerboseFlag > 1)
688 694 PySys_WriteStderr("# trying %s\n",
689 695 test.toLatin1().constData());
690 696 if (PythonQt::importInterface()->exists(test)) {
691 697 time_t mtime = 0;
692 698 int ispackage = zso->type & IS_PACKAGE;
693 699 int isbytecode = zso->type & IS_BYTECODE;
694 700
695 701 // if ignoreUpdatedPythonSourceFiles() returns true, then mtime stays 0
696 702 // and unmarshalCode() in getCodeFromData() will always read an existing *.pyc file,
697 703 // even if a newer *.py file exists. This is a release optimization where
698 704 // typically only *.pyc files are delivered without *.py files and reading file
699 705 // modification time is slow.
700 706 if (isbytecode && !PythonQt::importInterface()->ignoreUpdatedPythonSourceFiles()) {
701 707 mtime = getMTimeOfSource(test);
702 708 }
703 709 code = getCodeFromData(test, isbytecode, ispackage, mtime);
704 710 if (code == Py_None) {
705 711 Py_DECREF(code);
706 712 continue;
707 713 }
708 714 if (code != NULL) {
709 715 modpath = test;
710 716 }
711 717 return code;
712 718 }
713 719 }
714 720 PyErr_Format(PythonQtImportError, "can't find module '%.200s'", fullname);
715 721
716 722 return NULL;
717 723 }
718 724
719 725 QString PythonQtImport::replaceExtension(const QString& str, const QString& ext)
720 726 {
721 727 QString r;
722 728 int i = str.lastIndexOf('.');
723 729 if (i!=-1) {
724 730 r = str.mid(0,i) + "." + ext;
725 731 } else {
726 732 r = str + "." + ext;
727 733 }
728 734 return r;
729 735 }
730 736
731 737 PyObject* PythonQtImport::getCodeFromPyc(const QString& file)
732 738 {
733 739 PyObject* code;
734 740 const static QString pycStr("pyc");
735 741 QString pyc = replaceExtension(file, pycStr);
736 742 if (PythonQt::importInterface()->exists(pyc)) {
737 743 time_t mtime = 0;
738 744 // if ignoreUpdatedPythonSourceFiles() returns true, then mtime stays 0
739 745 // and unmarshalCode() in getCodeFromData() will always read an existing *.pyc file,
740 746 // even if a newer *.py file exists. This is a release optimization where
741 747 // typically only *.pyc files are delivered without *.py files and reading file
742 748 // modification time is slow.
743 749 if (!PythonQt::importInterface()->ignoreUpdatedPythonSourceFiles()) {
744 750 mtime = getMTimeOfSource(pyc);
745 751 }
746 752 code = getCodeFromData(pyc, true, false, mtime);
747 753 if (code != Py_None && code != NULL) {
748 754 return code;
749 755 }
750 756 if (code) {
751 757 Py_DECREF(code);
752 758 }
753 759 }
754 760 code = getCodeFromData(file,false,false,0);
755 761 return code;
756 762 }
757 763
758 764 /* Module init */
759 765
760 766 PyDoc_STRVAR(mlabimport_doc,
761 767 "Imports python files into PythonQt, completely replaces internal python import");
762 768
763 769 void PythonQtImport::init()
764 770 {
765 771 static bool first = true;
766 772 if (!first) {
767 773 return;
768 774 }
769 775 first = false;
770 776
771 777 PyObject *mod;
772 778
773 779 if (PyType_Ready(&PythonQtImporter_Type) < 0)
774 780 return;
775 781
776 782 /* Correct directory separator */
777 783 mlab_searchorder[0].suffix[0] = SEP;
778 784 mlab_searchorder[1].suffix[0] = SEP;
779 785 mlab_searchorder[2].suffix[0] = SEP;
780 786 if (Py_OptimizeFlag) {
781 787 /* Reverse *.pyc and *.pyo */
782 788 struct st_mlab_searchorder tmp;
783 789 tmp = mlab_searchorder[0];
784 790 mlab_searchorder[0] = mlab_searchorder[1];
785 791 mlab_searchorder[1] = tmp;
786 792 tmp = mlab_searchorder[3];
787 793 mlab_searchorder[3] = mlab_searchorder[4];
788 794 mlab_searchorder[4] = tmp;
789 795 }
790 796
791 797 mod = Py_InitModule4("PythonQtImport", NULL, mlabimport_doc,
792 798 NULL, PYTHON_API_VERSION);
793 799
794 800 PythonQtImportError = PyErr_NewException(const_cast<char*>("PythonQtImport.PythonQtImportError"),
795 801 PyExc_ImportError, NULL);
796 802 if (PythonQtImportError == NULL)
797 803 return;
798 804
799 805 Py_INCREF(PythonQtImportError);
800 806 if (PyModule_AddObject(mod, "PythonQtImportError",
801 807 PythonQtImportError) < 0)
802 808 return;
803 809
804 810 Py_INCREF(&PythonQtImporter_Type);
805 811 if (PyModule_AddObject(mod, "PythonQtImporter",
806 812 (PyObject *)&PythonQtImporter_Type) < 0)
807 813 return;
808 814
809 815 // set our importer into the path_hooks to handle all path on sys.path
810 816 PyObject* classobj = PyDict_GetItemString(PyModule_GetDict(mod), "PythonQtImporter");
811 817 PyObject* path_hooks = PySys_GetObject(const_cast<char*>("path_hooks"));
812 818 PyList_Append(path_hooks, classobj);
813 819
814 820 #ifndef WIN32
815 821 // reload the encodings module, because it might fail to custom import requirements (e.g. encryption).
816 822 PyObject* modules = PyImport_GetModuleDict();
817 823 PyObject* encodingsModule = PyDict_GetItemString(modules, "encodings");
818 824 if (encodingsModule != NULL) {
819 825 PyImport_ReloadModule(encodingsModule);
820 826 }
821 827 #endif
822 828 }
@@ -1,766 +1,774
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtInstanceWrapper.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtInstanceWrapper.h"
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"
49 50
50 51 PythonQtClassInfo* PythonQtInstanceWrapperStruct::classInfo()
51 52 {
52 53 // take the class info from our type object
53 54 return ((PythonQtClassWrapper*)ob_type)->_classInfo;
54 55 }
55 56
56 57 static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, bool force = false) {
57 58
58 59 // is this a C++ wrapper?
59 60 if (self->_wrappedPtr) {
60 61 //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
61 62
62 63 PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr);
63 64 // we own our qobject, so we delete it now:
64 65 delete self->_obj;
65 66 self->_obj = NULL;
66 67 if (force || self->classInfo()->hasOwnerMethodButNoOwner(self->_wrappedPtr) || self->_ownedByPythonQt) {
67 68 int type = self->classInfo()->metaTypeId();
68 69 if (self->_useQMetaTypeDestroy && type>=0) {
69 70 // use QMetaType to destroy the object
70 71 QMetaType::destroy(type, self->_wrappedPtr);
71 72 } else {
72 73 PythonQtSlotInfo* slot = self->classInfo()->destructor();
73 74 if (slot) {
74 75 void* args[2];
75 76 args[0] = NULL;
76 77 args[1] = &self->_wrappedPtr;
77 78 slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, slot->slotIndex(), args);
78 79 self->_wrappedPtr = NULL;
79 80 } else {
80 81 if (type>=0) {
81 82 // use QMetaType to destroy the object
82 83 QMetaType::destroy(type, self->_wrappedPtr);
83 84 } else {
84 85 // TODO: warn about not being able to destroy the object?
85 86 }
86 87 }
87 88 }
88 89 }
89 90 } else {
90 91 //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
91 92 if (self->_objPointerCopy) {
92 93 PythonQt::priv()->removeWrapperPointer(self->_objPointerCopy);
93 94 }
94 95 if (self->_obj) {
95 96 if (force || self->_ownedByPythonQt) {
96 97 if (force || !self->_obj->parent()) {
97 98 delete self->_obj;
98 99 }
99 100 } else {
100 101 if (self->_obj->parent()==NULL) {
101 102 // tell someone who is interested that the qobject is no longer wrapped, if it has no parent
102 103 PythonQt::qObjectNoLongerWrappedCB(self->_obj);
103 104 }
104 105 }
105 106 }
106 107 }
107 108 self->_obj = NULL;
108 109 }
109 110
110 111 static void PythonQtInstanceWrapper_dealloc(PythonQtInstanceWrapper* self)
111 112 {
112 113 PythonQtInstanceWrapper_deleteObject(self);
113 114 self->_obj.~QPointer<QObject>();
114 115 self->ob_type->tp_free((PyObject*)self);
115 116 }
116 117
117 118 static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
118 119 {
119 120 //PythonQtClassWrapper *classType = (PythonQtClassWrapper*)type;
120 121 PythonQtInstanceWrapper *self;
121 122 static PyObject* emptyTuple = NULL;
122 123 if (emptyTuple==NULL) {
123 124 emptyTuple = PyTuple_New(0);
124 125 }
125 126
126 127 self = (PythonQtInstanceWrapper*)PyBaseObject_Type.tp_new(type, emptyTuple, NULL);
127 128
128 129 if (self != NULL) {
129 130 new (&self->_obj) QPointer<QObject>();
130 131 self->_wrappedPtr = NULL;
131 132 self->_ownedByPythonQt = false;
132 133 self->_useQMetaTypeDestroy = false;
133 134 self->_isShellInstance = false;
134 135 }
135 136 return (PyObject *)self;
136 137 }
137 138
138 139 int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds)
139 140 {
140 141 if (args == PythonQtPrivate::dummyTuple()) {
141 142 // we are called from the internal PythonQt API, so our data will be filled later on...
142 143 return 0;
143 144 }
144 145
145 146 // we are called from python, try to construct our object
146 147 if (self->classInfo()->constructors()) {
147 148 void* directCPPPointer = NULL;
148 149 PythonQtSlotFunction_CallImpl(self->classInfo(), NULL, self->classInfo()->constructors(), args, kwds, NULL, &directCPPPointer);
149 150 if (PyErr_Occurred()) {
150 151 return -1;
151 152 }
152 153 if (directCPPPointer) {
153 154 // change ownershipflag to be owned by PythonQt
154 155 self->_ownedByPythonQt = true;
155 156 self->_useQMetaTypeDestroy = false;
156 157 if (self->classInfo()->isCPPWrapper()) {
157 158 self->_wrappedPtr = directCPPPointer;
158 159 // TODO xxx: if there is a wrapper factory, we might want to generate a wrapper for our class?!
159 160 } else {
160 161 self->setQObject((QObject*)directCPPPointer);
161 162 }
162 163 // register with PythonQt
163 164 PythonQt::priv()->addWrapperPointer(directCPPPointer, self);
164 165
165 166 PythonQtShellSetInstanceWrapperCB* cb = self->classInfo()->shellSetInstanceWrapperCB();
166 167 if (cb) {
167 168 // if we are a derived python class, we set the wrapper
168 169 // to activate the shell class, otherwise we just ignore that it is a shell...
169 170 // we detect it be checking if the type does not have PythonQtInstanceWrapper_Type as direct base class,
170 171 // which is the case for all non-python derived types
171 172 if (((PyObject*)self)->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
172 173 // set the wrapper and remember that we have a shell instance!
173 174 (*cb)(directCPPPointer, self);
174 175 self->_isShellInstance = true;
175 176 }
176 177 }
177 178 }
178 179 } else {
179 180 QString error = QString("No constructors available for ") + self->classInfo()->className();
180 181 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
181 182 return -1;
182 183 }
183 184 return 0;
184 185 }
185 186
186 187 static PyObject *PythonQtInstanceWrapper_richcompare(PythonQtInstanceWrapper* wrapper, PyObject* other, int code)
187 188 {
188 189 bool validPtrs = false;
189 190 bool areSamePtrs = false;
190 191 if (PyObject_TypeCheck((PyObject*)wrapper, &PythonQtInstanceWrapper_Type)) {
191 192 if (PyObject_TypeCheck(other, &PythonQtInstanceWrapper_Type)) {
192 193 validPtrs = true;
193 194 PythonQtInstanceWrapper* w1 = wrapper;
194 195 PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)other;
195 196 // check pointers directly
196 197 if (w1->_wrappedPtr != NULL) {
197 198 if (w1->_wrappedPtr == w2->_wrappedPtr) {
198 199 areSamePtrs = true;
199 200 }
200 201 } else if (w1->_obj == w2->_obj) {
201 202 areSamePtrs = true;
202 203 }
203 204 } else if (other == Py_None) {
204 205 validPtrs = true;
205 206 if (wrapper->_obj || wrapper->_wrappedPtr) {
206 207 areSamePtrs = false;
207 208 } else {
208 209 areSamePtrs = true;
209 210 }
210 211 }
211 212 }
212 213
213 214 if ((wrapper->classInfo()->typeSlots() & PythonQt::Type_RichCompare) == 0) {
214 215 // shortcut if richcompare is not supported:
215 216 if (validPtrs && code == Py_EQ) {
216 217 return PythonQtConv::GetPyBool(areSamePtrs);
217 218 } else if (validPtrs && code == Py_NE) {
218 219 return PythonQtConv::GetPyBool(!areSamePtrs);
219 220 }
220 221 Py_INCREF(Py_NotImplemented);
221 222 return Py_NotImplemented;
222 223 }
223 224
224 225 QByteArray memberName;
225 226 switch (code) {
226 227 case Py_LT:
227 228 {
228 229 static QByteArray name = "__lt__";
229 230 memberName = name;
230 231 }
231 232 break;
232 233
233 234 case Py_LE:
234 235 {
235 236 static QByteArray name = "__le__";
236 237 memberName = name;
237 238 }
238 239 break;
239 240
240 241 case Py_EQ:
241 242 {
242 243 static QByteArray name = "__eq__";
243 244 memberName = name;
244 245 }
245 246 break;
246 247
247 248 case Py_NE:
248 249 {
249 250 static QByteArray name = "__ne__";
250 251 memberName = name;
251 252 }
252 253 break;
253 254
254 255 case Py_GT:
255 256 {
256 257 static QByteArray name = "__gt__";
257 258 memberName = name;
258 259 }
259 260 break;
260 261
261 262 case Py_GE:
262 263 {
263 264 static QByteArray name = "__ge__";
264 265 memberName = name;
265 266 }
266 267 break;
267 268 }
268 269
269 270 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
270 271 if (opSlot._type == PythonQtMemberInfo::Slot) {
271 272 // TODO get rid of tuple
272 273 PyObject* args = PyTuple_New(1);
273 274 Py_INCREF(other);
274 275 PyTuple_SET_ITEM(args, 0, other);
275 276 PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr);
276 277 Py_DECREF(args);
277 278 return result;
278 279 } else {
279 280 // not implemented, let python try something else!
280 281 Py_INCREF(Py_NotImplemented);
281 282 return Py_NotImplemented;
282 283 }
283 284 }
284 285
285 286
286 287 static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* obj)
287 288 {
288 289 return PyString_FromString(obj->ob_type->tp_name);
289 290 }
290 291
291 292 PyObject *PythonQtInstanceWrapper_inherits(PythonQtInstanceWrapper* obj, PyObject *args)
292 293 {
293 294 char *name = NULL;
294 295 if (!PyArg_ParseTuple(args, "s:PythonQtInstanceWrapper.inherits",&name)) {
295 296 return NULL;
296 297 }
297 298 return PythonQtConv::GetPyBool(obj->classInfo()->inherits(name));
298 299 }
299 300
300 301 static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* obj)
301 302 {
302 303 return PythonQt::self()->helpCalled(obj->classInfo());
303 304 }
304 305
305 306 PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self)
306 307 {
307 308 PythonQtInstanceWrapper_deleteObject(self, true);
308 309 Py_INCREF(Py_None);
309 310 return Py_None;
310 311 }
311 312
312 313
313 314 static PyMethodDef PythonQtInstanceWrapper_methods[] = {
314 315 {"className", (PyCFunction)PythonQtInstanceWrapper_classname, METH_NOARGS,
315 316 "Return the classname of the object"
316 317 },
317 318 {"inherits", (PyCFunction)PythonQtInstanceWrapper_inherits, METH_VARARGS,
318 319 "Returns if the class inherits or is of given type name"
319 320 },
320 321 {"help", (PyCFunction)PythonQtInstanceWrapper_help, METH_NOARGS,
321 322 "Shows the help of available methods for this class"
322 323 },
323 324 {"delete", (PyCFunction)PythonQtInstanceWrapper_delete, METH_NOARGS,
324 325 "Deletes the C++ object (at your own risk, my friend!)"
325 326 },
326 327 {NULL, NULL, 0, NULL} /* Sentinel */
327 328 };
328 329
329 330
330 331 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
331 332 {
332 333 const char *attributeName;
333 334 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
334 335
335 336 if ((attributeName = PyString_AsString(name)) == NULL) {
336 337 return NULL;
337 338 }
338 339
339 340 if (qstrcmp(attributeName, "__dict__")==0) {
340 341 PyObject* dict = PyBaseObject_Type.tp_getattro(obj, name);
341 342 dict = PyDict_Copy(dict);
342 343
343 344 if (wrapper->_obj) {
344 345 // only the properties are missing, the rest is already available from
345 346 // PythonQtClassWrapper...
346 347 QStringList l = wrapper->classInfo()->propertyList();
347 348 foreach (QString name, l) {
348 349 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
349 350 if (o) {
350 351 PyDict_SetItemString(dict, name.toLatin1().data(), o);
351 352 Py_DECREF(o);
352 353 } else {
353 354 std::cerr << "PythonQtInstanceWrapper: something is wrong, could not get attribute " << name.toLatin1().data();
354 355 }
355 356 }
356 357
357 358 QList<QByteArray> dynamicProps = wrapper->_obj->dynamicPropertyNames();
358 359 foreach (QByteArray name, dynamicProps) {
359 360 PyObject* o = PyObject_GetAttrString(obj, name.data());
360 361 if (o) {
361 362 PyDict_SetItemString(dict, name.data(), o);
362 363 Py_DECREF(o);
363 364 } else {
364 365 std::cerr << "PythonQtInstanceWrapper: dynamic property could not be read " << name.data();
365 366 }
366 367 }
367 368 }
368 369 // Note: we do not put children into the dict, is would look confusing?!
369 370 return dict;
370 371 }
371 372
372 373 // first look in super, to return derived methods from base object first
373 374 PyObject* superAttr = PyBaseObject_Type.tp_getattro(obj, name);
374 375 if (superAttr) {
375 376 return superAttr;
376 377 }
377 378 PyErr_Clear();
378 379
379 380 // mlabDebugConst("Python","get " << attributeName);
380 381
381 382 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
382 383 switch (member._type) {
383 384 case PythonQtMemberInfo::Property:
384 385 if (wrapper->_obj) {
385 386 if (member._property.userType() != QVariant::Invalid) {
386 387
387 388 PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB();
388 389 if (profilingCB) {
389 390 QString methodName = "getProperty(";
390 391 methodName += attributeName;
391 392 methodName += ")";
392 393 profilingCB(PythonQt::Enter, wrapper->_obj->metaObject()->className(), methodName.toLatin1());
393 394 }
394 395
395 396 PyObject* value = PythonQtConv::QVariantToPyObject(member._property.read(wrapper->_obj));
396 397
397 398 if (profilingCB) {
398 399 profilingCB(PythonQt::Leave, NULL, NULL);
399 400 }
400 401
401 402 return value;
402 403
403 404 } else {
404 405 Py_INCREF(Py_None);
405 406 return Py_None;
406 407 }
407 408 } else {
408 409 QString error = QString("Trying to read property '") + attributeName + "' from a destroyed " + wrapper->classInfo()->className() + " object";
409 410 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
410 411 return NULL;
411 412 }
412 413 break;
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;
419 423 Py_INCREF(enumValue);
420 424 return enumValue;
421 425 }
422 426 break;
423 427 case PythonQtMemberInfo::EnumWrapper:
424 428 {
425 429 PyObject* enumWrapper = member._enumWrapper;
426 430 Py_INCREF(enumWrapper);
427 431 return enumWrapper;
428 432 }
429 433 break;
430 434 case PythonQtMemberInfo::NotFound:
431 435 {
432 436 static const QByteArray getterString("py_get_");
433 437 // check for a getter slot
434 438 PythonQtMemberInfo member = wrapper->classInfo()->member(getterString + attributeName);
435 439 if (member._type == PythonQtMemberInfo::Slot) {
436 440 return PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, member._slot, NULL, NULL, wrapper->_wrappedPtr);
437 441 }
438 442
439 443 // handle dynamic properties
440 444 if (wrapper->_obj) {
441 445 QVariant v = wrapper->_obj->property(attributeName);
442 446 if (v.isValid()) {
443 447 return PythonQtConv::QVariantToPyObject(v);
444 448 }
445 449 }
446 450 }
447 451 break;
448 452 default:
449 453 // is an invalid type, go on
450 454 break;
451 455 }
452 456
453 457 // look for the internal methods (className(), help())
454 458 PyObject* internalMethod = Py_FindMethod( PythonQtInstanceWrapper_methods, obj, (char*)attributeName);
455 459 if (internalMethod) {
456 460 return internalMethod;
457 461 }
458 462 PyErr_Clear();
459 463
460 464 if (wrapper->_obj) {
461 465 // look for a child
462 466 QObjectList children = wrapper->_obj->children();
463 467 for (int i = 0; i < children.count(); i++) {
464 468 QObject *child = children.at(i);
465 469 if (child->objectName() == attributeName) {
466 470 return PythonQt::priv()->wrapQObject(child);
467 471 }
468 472 }
469 473 }
470 474
471 475 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
472 476 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
473 477 return NULL;
474 478 }
475 479
476 480 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
477 481 {
478 482 QString error;
479 483 const char *attributeName;
480 484 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
481 485
482 486 if ((attributeName = PyString_AsString(name)) == NULL)
483 487 return -1;
484 488
485 489 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
486 490 if (member._type == PythonQtMemberInfo::Property) {
487 491
488 492 if (!wrapper->_obj) {
489 493 error = QString("Trying to set property '") + attributeName + "' on a destroyed " + wrapper->classInfo()->className() + " object";
490 494 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
491 495 return -1;
492 496 }
493 497
494 498 QMetaProperty prop = member._property;
495 499 if (prop.isWritable()) {
496 500 QVariant v;
497 501 if (prop.isEnumType()) {
498 502 // this will give us either a string or an int, everything else will probably be an error
499 503 v = PythonQtConv::PyObjToQVariant(value);
500 504 } else {
501 505 int t = prop.userType();
502 506 v = PythonQtConv::PyObjToQVariant(value, t);
503 507 }
504 508 bool success = false;
505 509 if (v.isValid()) {
506 510 PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB();
507 511 if (profilingCB) {
508 512 QString methodName = "setProperty(";
509 513 methodName += attributeName;
510 514 methodName += ")";
511 515 profilingCB(PythonQt::Enter, wrapper->_obj->metaObject()->className(), methodName.toLatin1());
512 516 }
513 517
514 518 success = prop.write(wrapper->_obj, v);
515 519
516 520 if (profilingCB) {
517 521 profilingCB(PythonQt::Leave, NULL, NULL);
518 522 }
519 523 }
520 524 if (success) {
521 525 return 0;
522 526 } else {
523 527 error = QString("Property '") + attributeName + "' of type '" +
524 528 prop.typeName() + "' does not accept an object of type "
525 529 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
526 530 }
527 531 } else {
528 532 error = QString("Property '") + attributeName + "' of " + obj->ob_type->tp_name + " object is not writable";
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) {
535 541 error = QString("Enum '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
536 542 } else if (member._type == PythonQtMemberInfo::NotFound) {
537 543 // check for a setter slot
538 544 static const QByteArray setterString("py_set_");
539 545 PythonQtMemberInfo setter = wrapper->classInfo()->member(setterString + attributeName);
540 546 if (setter._type == PythonQtMemberInfo::Slot) {
541 547 // call the setter and ignore the result value
542 548 void* result;
543 549 PyObject* args = PyTuple_New(1);
544 550 Py_INCREF(value);
545 551 PyTuple_SET_ITEM(args, 0, value);
546 552 PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, setter._slot, args, NULL, wrapper->_wrappedPtr, &result);
547 553 Py_DECREF(args);
548 554 return 0;
549 555 }
550 556
551 557 // handle dynamic properties
552 558 if (wrapper->_obj) {
553 559 QVariant prop = wrapper->_obj->property(attributeName);
554 560 if (prop.isValid()) {
555 561 QVariant v = PythonQtConv::PyObjToQVariant(value);
556 562 if (v.isValid()) {
557 563 wrapper->_obj->setProperty(attributeName, v);
558 564 return 0;
559 565 } else {
560 566 error = QString("Dynamic property '") + attributeName + "' does not accept an object of type "
561 567 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
562 568 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
563 569 return -1;
564 570 }
565 571 }
566 572 }
567 573
568 574 // if we are a derived python class, we allow setting attributes.
569 575 // if we are a direct CPP wrapper, we do NOT allow it, since
570 576 // it would be confusing to allow it because a wrapper will go away when it is not seen by python anymore
571 577 // and when it is recreated from a CPP pointer the attributes are gone...
572 578 if (obj->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
573 579 return PyBaseObject_Type.tp_setattro(obj,name,value);
574 580 } else {
575 581 error = QString("'") + attributeName + "' does not exist on " + obj->ob_type->tp_name + " and creating new attributes on C++ objects is not allowed";
576 582 }
577 583 }
578 584
579 585 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
580 586 return -1;
581 587 }
582 588
583 589 static QString getStringFromObject(PythonQtInstanceWrapper* wrapper) {
584 590 QString result;
585 591 if (wrapper->_wrappedPtr) {
586 592 // first try some manually string conversions for some variants
587 593 int metaid = wrapper->classInfo()->metaTypeId();
588 594 result = PythonQtConv::CPPObjectToString(metaid, wrapper->_wrappedPtr);
589 595 if (!result.isEmpty()) {
590 596 return result;
591 597 }
592 598 }
599 if (wrapper->_wrappedPtr || wrapper->_obj) {
593 600 // next, try to call py_toString
594 601 PythonQtMemberInfo info = wrapper->classInfo()->member("py_toString");
595 602 if (info._type == PythonQtMemberInfo::Slot) {
596 603 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, NULL, NULL, wrapper->_wrappedPtr);
597 604 if (resultObj) {
598 605 // TODO this is one conversion too much, would be nicer to call the slot directly...
599 606 result = PythonQtConv::PyObjGetString(resultObj);
600 607 Py_DECREF(resultObj);
601 608 }
602 609 }
610 }
603 611 return result;
604 612 }
605 613
606 614 static PyObject * PythonQtInstanceWrapper_str(PyObject * obj)
607 615 {
608 616 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
609 617
610 618 // QByteArray should be directly returned as a str
611 619 if (wrapper->classInfo()->metaTypeId()==QVariant::ByteArray) {
612 620 QByteArray* b = (QByteArray*) wrapper->_wrappedPtr;
613 621 if (b->data()) {
614 622 return PyString_FromStringAndSize(b->data(), b->size());
615 623 } else {
616 624 return PyString_FromString("");
617 625 }
618 626 }
619 627
620 628 const char* typeName = obj->ob_type->tp_name;
621 629 QObject *qobj = wrapper->_obj;
622 630 QString str = getStringFromObject(wrapper);
623 631 if (!str.isEmpty()) {
624 632 return PyString_FromFormat("%s", str.toLatin1().constData());
625 633 }
626 634 if (wrapper->_wrappedPtr) {
627 635 if (wrapper->_obj) {
628 636 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
629 637 } else {
630 638 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
631 639 }
632 640 } else {
633 641 return PyString_FromFormat("%s (QObject %p)", typeName, qobj);
634 642 }
635 643 }
636 644
637 645 static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj)
638 646 {
639 647 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
640 648 const char* typeName = obj->ob_type->tp_name;
641 649
642 650 QObject *qobj = wrapper->_obj;
643 651 QString str = getStringFromObject(wrapper);
644 652 if (!str.isEmpty()) {
645 653 if (str.startsWith(typeName)) {
646 654 return PyString_FromFormat("%s", str.toLatin1().constData());
647 655 } else {
648 656 return PyString_FromFormat("%s (%s, at: %p)", typeName, str.toLatin1().constData(), wrapper->_wrappedPtr ? wrapper->_wrappedPtr : qobj);
649 657 }
650 658 }
651 659 if (wrapper->_wrappedPtr) {
652 660 if (wrapper->_obj) {
653 661 return PyString_FromFormat("%s (C++ object at: %p wrapped by %s at: %p)", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
654 662 } else {
655 663 return PyString_FromFormat("%s (C++ object at: %p)", typeName, wrapper->_wrappedPtr);
656 664 }
657 665 } else {
658 666 return PyString_FromFormat("%s (%s at: %p)", typeName, wrapper->classInfo()->className(), qobj);
659 667 }
660 668 }
661 669
662 670 static int PythonQtInstanceWrapper_builtin_nonzero(PyObject *obj)
663 671 {
664 672 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
665 673 return (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
666 674 }
667 675
668 676
669 677 static long PythonQtInstanceWrapper_hash(PythonQtInstanceWrapper *obj)
670 678 {
671 679 if (obj->_wrappedPtr != NULL) {
672 680 return reinterpret_cast<long>(obj->_wrappedPtr);
673 681 } else {
674 682 QObject* qobj = obj->_obj; // get pointer from QPointer wrapper
675 683 return reinterpret_cast<long>(qobj);
676 684 }
677 685 }
678 686
679 687
680 688
681 689 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
682 690 static PyNumberMethods PythonQtInstanceWrapper_as_number = {
683 691 0, /* nb_add */
684 692 0, /* nb_subtract */
685 693 0, /* nb_multiply */
686 694 0, /* nb_divide */
687 695 0, /* nb_remainder */
688 696 0, /* nb_divmod */
689 697 0, /* nb_power */
690 698 0, /* nb_negative */
691 699 0, /* nb_positive */
692 700 0, /* nb_absolute */
693 701 PythonQtInstanceWrapper_builtin_nonzero, /* nb_nonzero */
694 702 0, /* nb_invert */
695 703 0, /* nb_lshift */
696 704 0, /* nb_rshift */
697 705 0, /* nb_and */
698 706 0, /* nb_xor */
699 707 0, /* nb_or */
700 708 0, /* nb_coerce */
701 709 0, /* nb_int */
702 710 0, /* nb_long */
703 711 0, /* nb_float */
704 712 0, /* nb_oct */
705 713 0, /* nb_hex */
706 714 0, /* nb_inplace_add */
707 715 0, /* nb_inplace_subtract */
708 716 0, /* nb_inplace_multiply */
709 717 0, /* nb_inplace_divide */
710 718 0, /* nb_inplace_remainder */
711 719 0, /* nb_inplace_power */
712 720 0, /* nb_inplace_lshift */
713 721 0, /* nb_inplace_rshift */
714 722 0, /* nb_inplace_and */
715 723 0, /* nb_inplace_xor */
716 724 0, /* nb_inplace_or */
717 725 0, /* nb_floor_divide */
718 726 0, /* nb_true_divide */
719 727 0, /* nb_inplace_floor_divide */
720 728 0, /* nb_inplace_true_divide */
721 729 };
722 730
723 731 PyTypeObject PythonQtInstanceWrapper_Type = {
724 732 PyObject_HEAD_INIT(&PythonQtClassWrapper_Type)
725 733 0, /*ob_size*/
726 734 "PythonQt.PythonQtInstanceWrapper", /*tp_name*/
727 735 sizeof(PythonQtInstanceWrapper), /*tp_basicsize*/
728 736 0, /*tp_itemsize*/
729 737 (destructor)PythonQtInstanceWrapper_dealloc, /*tp_dealloc*/
730 738 0, /*tp_print*/
731 739 0, /*tp_getattr*/
732 740 0, /*tp_setattr*/
733 741 0, /*tp_compare*/
734 742 PythonQtInstanceWrapper_repr, /*tp_repr*/
735 743 &PythonQtInstanceWrapper_as_number, /*tp_as_number*/
736 744 0, /*tp_as_sequence*/
737 745 0, /*tp_as_mapping*/
738 746 (hashfunc)PythonQtInstanceWrapper_hash, /*tp_hash */
739 747 0, /*tp_call*/
740 748 PythonQtInstanceWrapper_str, /*tp_str*/
741 749 PythonQtInstanceWrapper_getattro, /*tp_getattro*/
742 750 PythonQtInstanceWrapper_setattro, /*tp_setattro*/
743 751 0, /*tp_as_buffer*/
744 752 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
745 753 "PythonQtInstanceWrapper object", /* tp_doc */
746 754 0, /* tp_traverse */
747 755 0, /* tp_clear */
748 756 (richcmpfunc)PythonQtInstanceWrapper_richcompare, /* tp_richcompare */
749 757 0, /* tp_weaklistoffset */
750 758 0, /* tp_iter */
751 759 0, /* tp_iternext */
752 760 0, /* tp_methods */
753 761 0, /* tp_members */
754 762 0, /* tp_getset */
755 763 0, /* tp_base */
756 764 0, /* tp_dict */
757 765 0, /* tp_descr_get */
758 766 0, /* tp_descr_set */
759 767 0, /* tp_dictoffset */
760 768 (initproc)PythonQtInstanceWrapper_init, /* tp_init */
761 769 0, /* tp_alloc */
762 770 PythonQtInstanceWrapper_new, /* tp_new */
763 771 };
764 772
765 773 //-------------------------------------------------------
766 774
@@ -1,350 +1,352
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtMethodInfo.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtMethodInfo.h"
43 43 #include "PythonQtClassInfo.h"
44 44 #include <iostream>
45 45
46 46 QHash<QByteArray, PythonQtMethodInfo*> PythonQtMethodInfo::_cachedSignatures;
47 47 QHash<QByteArray, QByteArray> PythonQtMethodInfo::_parameterNameAliases;
48 48
49 49 PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo)
50 50 {
51 51 #ifdef PYTHONQT_DEBUG
52 52 QByteArray sig(meta.signature());
53 53 sig = sig.mid(sig.indexOf('('));
54 54 QByteArray fullSig = QByteArray(meta.typeName()) + " " + sig;
55 55 std::cout << "caching " << fullSig.data() << std::endl;
56 56 #endif
57 57
58 58 ParameterInfo type;
59 59 fillParameterInfo(type, QByteArray(meta.typeName()), classInfo);
60 60 _parameters.append(type);
61 61 QList<QByteArray> names = meta.parameterTypes();
62 62 foreach (const QByteArray& name, names) {
63 63 fillParameterInfo(type, name, classInfo);
64 64 _parameters.append(type);
65 65 }
66 66 }
67 67
68 68 PythonQtMethodInfo::PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args)
69 69 {
70 70 ParameterInfo type;
71 71 fillParameterInfo(type, typeName, NULL);
72 72 _parameters.append(type);
73 73 foreach (const QByteArray& name, args) {
74 74 fillParameterInfo(type, name, NULL);
75 75 _parameters.append(type);
76 76 }
77 77 }
78 78
79 79 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo)
80 80 {
81 81 QByteArray sig(signal.signature());
82 82 sig = sig.mid(sig.indexOf('('));
83 83 QByteArray fullSig = QByteArray(signal.typeName()) + " " + sig;
84 84 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
85 85 if (!result) {
86 86 result = new PythonQtMethodInfo(signal, classInfo);
87 87 _cachedSignatures.insert(fullSig, result);
88 88 }
89 89 return result;
90 90 }
91 91
92 92 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(int numArgs, const char** args)
93 93 {
94 94 QByteArray typeName = args[0];
95 95 QList<QByteArray> arguments;
96 96 QByteArray fullSig = typeName;
97 97 fullSig += "(";
98 98 for (int i =1;i<numArgs; i++) {
99 99 if (i>1) {
100 100 fullSig += ",";
101 101 }
102 arguments << QByteArray(args[i]);
102 QByteArray arg(args[i]);
103 fullSig += arg;
104 arguments << arg;
103 105 }
104 106 fullSig += ")";
105 107 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
106 108 if (!result) {
107 109 result = new PythonQtMethodInfo(typeName, arguments);
108 110 _cachedSignatures.insert(fullSig, result);
109 111 }
110 112 return result;
111 113 }
112 114
113 115 void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo)
114 116 {
115 117 QByteArray name = orgName;
116 118
117 119 type.enumWrapper = NULL;
118 120
119 121 int len = name.length();
120 122 if (len>0) {
121 123 if (strncmp(name.constData(), "const ", 6)==0) {
122 124 name = name.mid(6);
123 125 len -= 6;
124 126 type.isConst = true;
125 127 } else {
126 128 type.isConst = false;
127 129 }
128 130 char pointerCount = 0;
129 131 bool hadReference = false;
130 132 // remove * and & from the end of the string, handle & and * the same way
131 133 while (name.at(len-1) == '*') {
132 134 len--;
133 135 pointerCount++;
134 136 }
135 137 while (name.at(len-1) == '&') {
136 138 len--;
137 139 hadReference = true;
138 140 }
139 141 if (len!=name.length()) {
140 142 name = name.left(len);
141 143 }
142 144 type.pointerCount = pointerCount;
143 145
144 146 QByteArray alias = _parameterNameAliases.value(name);
145 147 if (!alias.isEmpty()) {
146 148 name = alias;
147 149 }
148 150
149 151 type.typeId = nameToType(name);
150 152 if ((type.pointerCount == 0) && type.typeId == Unknown) {
151 153 type.typeId = QMetaType::type(name.constData());
152 154 if (type.typeId == QMetaType::Void) {
153 155 type.typeId = Unknown;
154 156 }
155 157 }
156 158 type.name = name;
157 159
158 160 if (type.typeId == PythonQtMethodInfo::Unknown || type.typeId >= QMetaType::User) {
159 161 bool isLocalEnum;
160 162 // TODOXXX: make use of this flag!
161 163 type.enumWrapper = PythonQtClassInfo::findEnumWrapper(type.name, classInfo, &isLocalEnum);
162 164 }
163 165 } else {
164 166 type.typeId = QMetaType::Void;
165 167 type.pointerCount = 0;
166 168 type.isConst = false;
167 169 }
168 170 }
169 171
170 172 int PythonQtMethodInfo::nameToType(const char* name)
171 173 {
172 174 if (_parameterTypeDict.isEmpty()) {
173 175 // we could also use QMetaType::nameToType, but that does a string compare search
174 176 // and does not support QVariant
175 177
176 178 // QMetaType names
177 179 _parameterTypeDict.insert("long", QMetaType::Long);
178 180 _parameterTypeDict.insert("int", QMetaType::Int);
179 181 _parameterTypeDict.insert("short", QMetaType::Short);
180 182 _parameterTypeDict.insert("char", QMetaType::Char);
181 183 _parameterTypeDict.insert("ulong", QMetaType::ULong);
182 184 _parameterTypeDict.insert("unsigned long", QMetaType::ULong);
183 185 _parameterTypeDict.insert("uint", QMetaType::UInt);
184 186 _parameterTypeDict.insert("unsigned int", QMetaType::UInt);
185 187 _parameterTypeDict.insert("ushort", QMetaType::UShort);
186 188 _parameterTypeDict.insert("unsigned short", QMetaType::UShort);
187 189 _parameterTypeDict.insert("uchar", QMetaType::UChar);
188 190 _parameterTypeDict.insert("unsigned char", QMetaType::UChar);
189 191 _parameterTypeDict.insert("bool", QMetaType::Bool);
190 192 _parameterTypeDict.insert("float", QMetaType::Float);
191 193 _parameterTypeDict.insert("double", QMetaType::Double);
192 194 _parameterTypeDict.insert("qreal", QMetaType::Double);
193 195 _parameterTypeDict.insert("QChar", QMetaType::QChar);
194 196 _parameterTypeDict.insert("QByteArray", QMetaType::QByteArray);
195 197 _parameterTypeDict.insert("QString", QMetaType::QString);
196 198 _parameterTypeDict.insert("", QMetaType::Void);
197 199 _parameterTypeDict.insert("void", QMetaType::Void);
198 200 // QVariant names
199 201 _parameterTypeDict.insert("Q_LLONG", QMetaType::LongLong);
200 202 _parameterTypeDict.insert("Q_ULLONG", QMetaType::ULongLong);
201 203 _parameterTypeDict.insert("qlonglong", QMetaType::LongLong);
202 204 _parameterTypeDict.insert("qulonglong", QMetaType::ULongLong);
203 205 _parameterTypeDict.insert("qint64", QMetaType::LongLong);
204 206 _parameterTypeDict.insert("quint64", QMetaType::ULongLong);
205 207 _parameterTypeDict.insert("QVariantMap", QMetaType::QVariantMap);
206 208 _parameterTypeDict.insert("QVariantList", QMetaType::QVariantList);
207 209 _parameterTypeDict.insert("QMap<QString,QVariant>", QMetaType::QVariantMap);
208 210 _parameterTypeDict.insert("QList<QVariant>", QMetaType::QVariantList);
209 211 _parameterTypeDict.insert("QStringList", QMetaType::QStringList);
210 212 _parameterTypeDict.insert("QBitArray", QMetaType::QBitArray);
211 213 _parameterTypeDict.insert("QDate", QMetaType::QDate);
212 214 _parameterTypeDict.insert("QTime", QMetaType::QTime);
213 215 _parameterTypeDict.insert("QDateTime", QMetaType::QDateTime);
214 216 _parameterTypeDict.insert("QUrl", QMetaType::QUrl);
215 217 _parameterTypeDict.insert("QLocale", QMetaType::QLocale);
216 218 _parameterTypeDict.insert("QRect", QMetaType::QRect);
217 219 _parameterTypeDict.insert("QRectF", QMetaType::QRectF);
218 220 _parameterTypeDict.insert("QSize", QMetaType::QSize);
219 221 _parameterTypeDict.insert("QSizeF", QMetaType::QSizeF);
220 222 _parameterTypeDict.insert("QLine", QMetaType::QLine);
221 223 _parameterTypeDict.insert("QLineF", QMetaType::QLineF);
222 224 _parameterTypeDict.insert("QPoint", QMetaType::QPoint);
223 225 _parameterTypeDict.insert("QPointF", QMetaType::QPointF);
224 226 _parameterTypeDict.insert("QRegExp", QMetaType::QRegExp);
225 227 _parameterTypeDict.insert("QFont", QMetaType::QFont);
226 228 _parameterTypeDict.insert("QPixmap", QMetaType::QPixmap);
227 229 _parameterTypeDict.insert("QBrush", QMetaType::QBrush);
228 230 _parameterTypeDict.insert("QColor", QMetaType::QColor);
229 231 _parameterTypeDict.insert("QCursor", QMetaType::QCursor);
230 232 _parameterTypeDict.insert("QPalette", QMetaType::QPalette);
231 233 _parameterTypeDict.insert("QIcon", QMetaType::QIcon);
232 234 _parameterTypeDict.insert("QImage", QMetaType::QImage);
233 235 _parameterTypeDict.insert("QRegion", QMetaType::QRegion);
234 236 _parameterTypeDict.insert("QBitmap", QMetaType::QBitmap);
235 237 _parameterTypeDict.insert("QSizePolicy", QMetaType::QSizePolicy);
236 238 _parameterTypeDict.insert("QKeySequence", QMetaType::QKeySequence);
237 239 _parameterTypeDict.insert("QPen", QMetaType::QPen);
238 240 _parameterTypeDict.insert("QTextLength", QMetaType::QTextLength);
239 241 _parameterTypeDict.insert("QTextFormat", QMetaType::QTextFormat);
240 242 _parameterTypeDict.insert("QMatrix", QMetaType::QMatrix);
241 243 _parameterTypeDict.insert("QVariant", PythonQtMethodInfo::Variant);
242 244 // own special types... (none so far, could be e.g. ObjectList
243 245 }
244 246 QHash<QByteArray, int>::const_iterator it = _parameterTypeDict.find(name);
245 247 if (it!=_parameterTypeDict.end()) {
246 248 return it.value();
247 249 } else {
248 250 return PythonQtMethodInfo::Unknown;
249 251 }
250 252 }
251 253
252 254 void PythonQtMethodInfo::cleanupCachedMethodInfos()
253 255 {
254 256 QHashIterator<QByteArray, PythonQtMethodInfo *> i(_cachedSignatures);
255 257 while (i.hasNext()) {
256 258 delete i.next().value();
257 259 }
258 260 }
259 261
260 262 void PythonQtMethodInfo::addParameterTypeAlias(const QByteArray& alias, const QByteArray& name)
261 263 {
262 264 _parameterNameAliases.insert(alias, name);
263 265 }
264 266
265 267 //-------------------------------------------------------------------------------------------------
266 268
267 269 void PythonQtSlotInfo::deleteOverloadsAndThis()
268 270 {
269 271 PythonQtSlotInfo* cur = this;
270 272 while(cur->nextInfo()) {
271 273 PythonQtSlotInfo* next = cur->nextInfo();
272 274 delete cur;
273 275 cur = next;
274 276 }
275 277 }
276 278
277 279
278 280 QString PythonQtSlotInfo::fullSignature()
279 281 {
280 282 bool skipFirstArg = isInstanceDecorator();
281 283 QString result = _meta.typeName();
282 284 QByteArray sig = slotName();
283 285 QList<QByteArray> names = _meta.parameterNames();
284 286
285 287 bool isStatic = false;
286 288 bool isConstructor = false;
287 289 bool isDestructor = false;
288 290
289 291 if (_type == ClassDecorator) {
290 292 if (sig.startsWith("new_")) {
291 293 sig = sig.mid(4);
292 294 isConstructor = true;
293 295 } else if (sig.startsWith("delete_")) {
294 296 sig = sig.mid(7);
295 297 isDestructor = true;
296 298 } else if(sig.startsWith("static_")) {
297 299 isStatic = true;
298 300 sig = sig.mid(7);
299 301 int idx = sig.indexOf("_");
300 302 if (idx>=0) {
301 303 sig = sig.mid(idx+1);
302 304 }
303 305 }
304 306 }
305 307
306 308 result += QByteArray(" ") + sig;
307 309 result += "(";
308 310
309 311 int lastEntry = _parameters.count()-1;
310 312 for (int i = skipFirstArg?2:1; i<_parameters.count(); i++) {
311 313 if (_parameters.at(i).isConst) {
312 314 result += "const ";
313 315 }
314 316 result += _parameters.at(i).name;
315 317 if (_parameters.at(i).pointerCount) {
316 318 QByteArray stars;
317 319 stars.fill('*', _parameters.at(i).pointerCount);
318 320 result += stars;
319 321 }
320 322 if (!names.at(i-1).isEmpty()) {
321 323 result += " ";
322 324 result += names.at(i-1);
323 325 }
324 326 if (i!=lastEntry) {
325 327 result += ", ";
326 328 }
327 329 }
328 330 result += ")";
329 331
330 332 if (isStatic) {
331 333 result = QString("static ") + result;
332 334 }
333 335 if (isConstructor) {
334 336 // result = QString("constructor ") + result;
335 337 }
336 338 if (isDestructor) {
337 339 result = QString("~") + result;
338 340 }
339 341 return result;
340 342 }
341 343
342 344
343 345 QByteArray PythonQtSlotInfo::slotName()
344 346 {
345 347 QByteArray sig(_meta.signature());
346 348 int idx = sig.indexOf('(');
347 349 sig = sig.left(idx);
348 350 return sig;
349 351 }
350 352
@@ -1,233 +1,242
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtSignalReceiver.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtSignalReceiver.h"
43 43 #include "PythonQtClassInfo.h"
44 44 #include "PythonQtMethodInfo.h"
45 45 #include "PythonQtConversion.h"
46 46 #include <QMetaObject>
47 47 #include <QMetaMethod>
48 48 #include "funcobject.h"
49 49
50 50 void PythonQtSignalTarget::call(void **arguments) const {
51 51 PyObject* result = call(_callable, methodInfo(), arguments);
52 52 if (result) {
53 53 Py_DECREF(result);
54 54 }
55 55 }
56 56
57 57 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInfo* methodInfos, void **arguments, bool skipFirstArgumentOfMethodInfo)
58 58 {
59 59 Q_UNUSED(skipFirstArgumentOfMethodInfo)
60 60
61 61 // Note: we check if the callable is a PyFunctionObject and has a fixed number of arguments
62 62 // if that is the case, we only pass these arguments to python and skip the additional arguments from the signal
63 63
64 64 int numPythonArgs = -1;
65 65 if (PyFunction_Check(callable)) {
66 66 PyObject* o = callable;
67 67 PyFunctionObject* func = (PyFunctionObject*)o;
68 68 PyCodeObject* code = (PyCodeObject*)func->func_code;
69 if (!(code->co_flags & 0x04)) {
69 if (!(code->co_flags & CO_VARARGS)) {
70 70 numPythonArgs = code->co_argcount;
71 71 } else {
72 72 // variable numbers of arguments allowed
73 73 }
74 74 } else if (PyMethod_Check(callable)) {
75 75 PyObject* o = callable;
76 76 PyMethodObject* method = (PyMethodObject*)o;
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 & 0x04)) {
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
84 84 }
85 85 }
86 86 }
87 87
88 88 const PythonQtMethodInfo* m = methodInfos;
89 89 // parameterCount includes return value:
90 90 int count = m->parameterCount();
91 91 if (numPythonArgs!=-1) {
92 92 if (count>numPythonArgs+1) {
93 93 // take less arguments
94 94 count = numPythonArgs+1;
95 95 }
96 96 }
97 97
98 98 PyObject* pargs = NULL;
99 99 if (count>1) {
100 100 pargs = PyTuple_New(count-1);
101 101 }
102 102 bool err = false;
103 103 // transform Qt values to Python
104 104 const QList<PythonQtMethodInfo::ParameterInfo>& params = m->parameters();
105 105 for (int i = 1; i < count; i++) {
106 106 const PythonQtMethodInfo::ParameterInfo& param = params.at(i);
107 107 PyObject* arg = PythonQtConv::ConvertQtValueToPython(param, arguments[i]);
108 108 if (arg) {
109 109 // steals reference, no unref
110 110 PyTuple_SetItem(pargs, i-1,arg);
111 111 } else {
112 112 err = true;
113 113 break;
114 114 }
115 115 }
116 116
117 117 PyObject* result = NULL;
118 118 if (!err) {
119 119 PyErr_Clear();
120 120 result = PyObject_CallObject(callable, pargs);
121 121 if (result) {
122 122 // ok
123 123 } else {
124 124 PythonQt::self()->handleError();
125 125 }
126 126 }
127 127 if (pargs) {
128 128 // free the arguments again
129 129 Py_DECREF(pargs);
130 130 }
131 131
132 132 return result;
133 133 }
134 134
135 135 bool PythonQtSignalTarget::isSame( int signalId, PyObject* callable ) const
136 136 {
137 137 return PyObject_Compare(callable, _callable) == 0 && signalId==_signalId;
138 138 }
139 139
140 140 //------------------------------------------------------------------------------
141 141
142 142 PythonQtSignalReceiver::PythonQtSignalReceiver(QObject* obj):PythonQtSignalReceiverBase(obj)
143 143 {
144 144 _obj = obj;
145 145
146 146 // fetch the class info for object, since we will need to for correct enum resolution in
147 147 // signals
148 148 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
149 149 if (!_objClassInfo || !_objClassInfo->isQObject()) {
150 150 PythonQt::self()->registerClass(obj->metaObject());
151 151 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
152 152 }
153 153 // force decorator/enum creation
154 154 _objClassInfo->decorator();
155 155
156 156 _slotCount = staticMetaObject.methodOffset();
157 157 }
158 158
159 159 PythonQtSignalReceiver::~PythonQtSignalReceiver()
160 160 {
161 161 PythonQt::priv()->removeSignalEmitter(_obj);
162 162 }
163 163
164 164
165 165 bool PythonQtSignalReceiver::addSignalHandler(const char* signal, PyObject* callable)
166 166 {
167 167 bool flag = false;
168 168 int sigId = getSignalIndex(signal);
169 169 if (sigId>=0) {
170 170 // create PythonQtMethodInfo from signal
171 171 QMetaMethod meta = _obj->metaObject()->method(sigId);
172 172 const PythonQtMethodInfo* signalInfo = PythonQtMethodInfo::getCachedMethodInfo(meta, _objClassInfo);
173 173 PythonQtSignalTarget t(sigId, signalInfo, _slotCount, callable);
174 174 _targets.append(t);
175 175 // now connect to ourselves with the new slot id
176 176 QMetaObject::connect(_obj, sigId, this, _slotCount, Qt::AutoConnection, 0);
177 177
178 178 _slotCount++;
179 179 flag = true;
180 180 }
181 181 return flag;
182 182 }
183 183
184 184 bool PythonQtSignalReceiver::removeSignalHandler(const char* signal, PyObject* callable)
185 185 {
186 186 bool found = false;
187 187 int sigId = getSignalIndex(signal);
188 188 if (sigId>=0) {
189 189 QMutableListIterator<PythonQtSignalTarget> i(_targets);
190 if (callable) {
190 191 while (i.hasNext()) {
191 192 if (i.next().isSame(sigId, callable)) {
192 193 i.remove();
193 194 found = true;
194 195 break;
195 196 }
196 197 }
198 } else {
199 while (i.hasNext()) {
200 if (i.next().signalId() == sigId) {
201 i.remove();
202 found = true;
203 }
204 }
205 }
197 206 }
198 207 return found;
199 208 }
200 209
201 210 void PythonQtSignalReceiver::removeSignalHandlers()
202 211 {
203 212 _targets.clear();
204 213 }
205 214
206 215 int PythonQtSignalReceiver::getSignalIndex(const char* signal)
207 216 {
208 217 int sigId = _obj->metaObject()->indexOfSignal(signal+1);
209 218 if (sigId<0) {
210 219 QByteArray tmpSig = QMetaObject::normalizedSignature(signal+1);
211 220 sigId = _obj->metaObject()->indexOfSignal(tmpSig);
212 221 }
213 222 return sigId;
214 223 }
215 224
216 225 int PythonQtSignalReceiver::qt_metacall(QMetaObject::Call c, int id, void **arguments)
217 226 {
218 227 // mlabDebugConst("PythonQt", "PythonQtSignalReceiver invoke " << _obj->className() << " " << _obj->name() << " " << id);
219 228 if (c != QMetaObject::InvokeMetaMethod) {
220 229 QObject::qt_metacall(c, id, arguments);
221 230 }
222 231
223 232 bool found = false;
224 233 foreach(const PythonQtSignalTarget& t, _targets) {
225 234 if (t.slotId() == id) {
226 235 found = true;
227 236 t.call(arguments);
228 237 break;
229 238 }
230 239 }
231 240 return 0;
232 241 }
233 242
@@ -1,142 +1,143
1 1 #ifndef _PYTHONQTSIGNALRECEIVER_H
2 2 #define _PYTHONQTSIGNALRECEIVER_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtSignalReceiver.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtPythonInclude.h"
46 46
47 47 #include "PythonQtSystem.h"
48 48 #include "PythonQtObjectPtr.h"
49 49
50 50 class PythonQtMethodInfo;
51 51 class PythonQtClassInfo;
52 52
53 53 //! stores information about a signal target
54 54 /*! copy construction and assignment works fine with the C++ standard behavior and are thus not implemented
55 55 */
56 56 class PYTHONQT_EXPORT PythonQtSignalTarget {
57 57 public:
58 58 PythonQtSignalTarget() {
59 59 _signalId = -1;
60 60 _methodInfo = NULL;
61 61 _slotId = -1;
62 62 }
63 63
64 64 PythonQtSignalTarget(int signalId,const PythonQtMethodInfo* methodInfo, int slotId, PyObject* callable)
65 65 {
66 66 _signalId = signalId;
67 67 _slotId = slotId;
68 68 _methodInfo = methodInfo;
69 69 _callable = callable;
70 70 };
71 71
72 72 ~PythonQtSignalTarget() {
73 73 };
74 74
75 75 //! get the id of the original signal
76 76 int signalId() const { return _signalId; }
77 77
78 78 //! get the id that was assigned to this simulated slot
79 79 int slotId() const { return _slotId; }
80 80
81 81 //! get the signals parameter info
82 82 const PythonQtMethodInfo* methodInfo() const { return _methodInfo; }
83 83
84 84 //! call the python callable with the given arguments (as defined in methodInfo)
85 85 void call(void **arguments) const;
86 86
87 87 //! check if it is the same signal target
88 88 bool isSame(int signalId, PyObject* callable) const;
89 89
90 90 //! call the given callable with arguments described by PythonQtMethodInfo, returns a new reference as result value (or NULL)
91 91 static PyObject* call(PyObject* callable, const PythonQtMethodInfo* methodInfo, void **arguments, bool skipFirstArgumentOfMethodInfo = false);
92 92
93 93 private:
94 94 int _signalId;
95 95 int _slotId;
96 96 const PythonQtMethodInfo* _methodInfo;
97 97 PythonQtObjectPtr _callable;
98 98 };
99 99
100 100 //! base class for signal receivers
101 101 /*!
102 102 */
103 103 class PythonQtSignalReceiverBase : public QObject {
104 104 Q_OBJECT
105 105 public:
106 106 PythonQtSignalReceiverBase(QObject* obj):QObject(obj) {};
107 107 };
108 108
109 109 //! receives all signals for one QObject
110 110 /*! we derive from our base but do not declare the QObject macro because we want to reimplement qt_metacall only.
111 111 */
112 112 class PythonQtSignalReceiver : public PythonQtSignalReceiverBase {
113 113
114 114 public:
115 115 PythonQtSignalReceiver(QObject* obj);
116 116 ~PythonQtSignalReceiver();
117 117
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();
126 126
127 127 //! we implement this method to simulate a number of slots that match the ids in _targets
128 128 virtual int qt_metacall(QMetaObject::Call c, int id, void **arguments);
129 129
130 130 private:
131 131 //! get the index of the signal
132 132 int getSignalIndex(const char* signal);
133 133
134 134 QObject* _obj;
135 135 PythonQtClassInfo* _objClassInfo;
136 136 int _slotCount;
137 137 // linear list may get slow on multiple targets, but I think typically we have many objects and just a few signals
138 138 QList<PythonQtSignalTarget> _targets;
139 139 };
140 140
141 141
142 142 #endif
143
@@ -1,556 +1,658
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtSlot.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtSlot.h"
44 44 #include "PythonQtInstanceWrapper.h"
45 45 #include "PythonQtClassInfo.h"
46 46 #include "PythonQtMisc.h"
47 47 #include "PythonQtConversion.h"
48 48 #include <iostream>
49 49
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
56 58 bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer)
57 59 {
58 60 static unsigned int recursiveEntry = 0;
59 61
60 62 if (directReturnValuePointer) {
61 63 *directReturnValuePointer = NULL;
62 64 }
63 65 // store the current storage position, so that we can get back to this state after a slot is called
64 66 // (do this locally, so that we have all positions on the stack
65 67 PythonQtValueStoragePosition globalValueStoragePos;
66 68 PythonQtValueStoragePosition globalPtrStoragePos;
67 69 PythonQtValueStoragePosition globalVariantStoragePos;
68 70 PythonQtConv::global_valueStorage.getPos(globalValueStoragePos);
69 71 PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos);
70 72 PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos);
71 73
72 74 recursiveEntry++;
73 75
74 76 // the arguments that are passed to qt_metacall
75 77 void* argList[PYTHONQT_MAX_ARGS];
76 78 PyObject* result = NULL;
77 79 int argc = info->parameterCount();
78 80 const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters();
79 81
80 82 const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);
81 83 // set return argument to NULL
82 84 argList[0] = NULL;
83 85
84 86 bool ok = true;
85 87 bool skipFirst = false;
86 88 if (info->isInstanceDecorator()) {
87 89 skipFirst = true;
88 90
89 91 // for decorators on CPP objects, we take the cpp ptr, for QObjects we take the QObject pointer
90 92 void* arg1 = firstArgument;
91 93 if (!arg1) {
92 94 arg1 = objectToCall;
93 95 }
94 96 if (arg1) {
95 97 // upcast to correct parent class
96 98 arg1 = ((char*)arg1)+info->upcastingOffset();
97 99 }
98 100
99 101 argList[1] = &arg1;
100 102 if (ok) {
101 103 for (int i = 2; i<argc && ok; i++) {
102 104 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
103 105 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, classInfo);
104 106 if (argList[i]==NULL) {
105 107 ok = false;
106 108 break;
107 109 }
108 110 }
109 111 }
110 112 } else {
111 113 for (int i = 1; i<argc && ok; i++) {
112 114 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
113 115 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, classInfo);
114 116 if (argList[i]==NULL) {
115 117 ok = false;
116 118 break;
117 119 }
118 120 }
119 121 }
120 122
121 123 if (ok) {
122 124 // parameters are ok, now create the qt return value which is assigned to by metacall
123 125 if (returnValueParam.typeId != QMetaType::Void) {
124 126 // create empty default value for the return value
125 127 if (!directReturnValuePointer) {
126 128 // create empty default value for the return value
127 129 argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);
128 130 if (argList[0]==NULL) {
129 131 // return value could not be created, maybe we have a registered class with a default constructor, so that we can construct the pythonqt wrapper object and
130 132 // pass its internal pointer
131 133 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(returnValueParam.name);
132 134 if (info && info->pythonQtClassWrapper()) {
133 135 PyObject* emptyTuple = PyTuple_New(0);
134 136 // 1) default construct an empty object as python object (owned by PythonQt), by calling the meta class with empty arguments
135 137 result = PyObject_Call((PyObject*)info->pythonQtClassWrapper(), emptyTuple, NULL);
136 138 if (result) {
137 139 argList[0] = ((PythonQtInstanceWrapper*)result)->_wrappedPtr;
138 140 }
139 141 Py_DECREF(emptyTuple);
140 142 }
141 143 }
142 144 } else {
143 145 // we can use our pointer directly!
144 146 argList[0] = directReturnValuePointer;
145 147 }
146 148 }
147 149
148 150
149 151 PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB();
150 152 if (profilingCB) {
151 153 const char* className = NULL;
152 154 if (info->decorator()) {
153 155 className = info->decorator()->metaObject()->className();
154 156 } else {
155 157 className = objectToCall->metaObject()->className();
156 158 }
157 159
158 160 profilingCB(PythonQt::Enter, className, info->metaMethod()->signature());
159 161 }
160 162
161 163 // invoke the slot via metacall
162 164 bool hadException = false;
165 QObject* obj = info->decorator()?info->decorator():objectToCall;
166 if (!obj) {
167 hadException = true;
168 PyErr_SetString(PyExc_RuntimeError, "Trying to call a slot on a deleted QObject!");
169 } else {
163 170 try {
164 (info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
171 obj->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
165 172 } catch (std::bad_alloc & e) {
166 173 hadException = true;
167 174 QByteArray what("std::bad_alloc: ");
168 175 what += e.what();
169 176 PyErr_SetString(PyExc_MemoryError, what.constData());
170 177 } catch (std::runtime_error & e) {
171 178 hadException = true;
172 179 QByteArray what("std::runtime_error: ");
173 180 what += e.what();
174 181 PyErr_SetString(PyExc_RuntimeError, what.constData());
175 182 } catch (std::logic_error & e) {
176 183 hadException = true;
177 184 QByteArray what("std::logic_error: ");
178 185 what += e.what();
179 186 PyErr_SetString(PyExc_RuntimeError, what.constData());
180 187 } catch (std::exception& e) {
181 188 hadException = true;
182 189 QByteArray what("std::exception: ");
183 190 what += e.what();
184 191 PyErr_SetString(PyExc_StandardError, what.constData());
185 192 }
193 }
186 194
187 195 if (profilingCB) {
188 196 profilingCB(PythonQt::Leave, NULL, NULL);
189 197 }
190 198
191 199 // handle the return value (which in most cases still needs to be converted to a Python object)
192 200 if (!hadException) {
193 201 if (argList[0] || returnValueParam.typeId == QMetaType::Void) {
194 202 if (directReturnValuePointer) {
195 203 result = NULL;
196 204 } else {
197 205 // the resulting object maybe present already, because we created it above at 1)...
198 206 if (!result) {
199 207 result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]);
200 208 }
201 209 }
202 210 } else {
203 211 QString e = QString("Called ") + info->fullSignature() + ", return type '" + returnValueParam.name + "' is ignored because it is unknown to PythonQt. Probably you should register it using qRegisterMetaType() or add a default constructor decorator to the class.";
204 212 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
205 213 result = NULL;
206 214 }
207 215 } else {
208 216 result = NULL;
209 217 }
210 218 }
211 219 recursiveEntry--;
212 220
213 221 // reset the parameter storage position to the stored pos to "pop" the parameter stack
214 222 PythonQtConv::global_valueStorage.setPos(globalValueStoragePos);
215 223 PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos);
216 224 PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos);
217 225
218 226 *pythonReturnValue = result;
219 227 // NOTE: it is important to only return here, otherwise the stack will not be popped!!!
220 228 return result || (directReturnValuePointer && *directReturnValuePointer);
221 229 }
222 230
223 231 //-----------------------------------------------------------------------------------
224 232
225 233 static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL;
226 234
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 '") + f->m_ml->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
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 (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
241 PythonQtClassWrapper* type = (PythonQtClassWrapper*) f->m_self;
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 {
245 257 // otherwise, it is an unbound call and we have an instanceDecorator or normal slot...
246 258 Py_ssize_t argc = PyTuple_Size(args);
247 259 if (argc>0) {
248 260 PyObject* firstArg = PyTuple_GET_ITEM(args, 0);
249 261 if (PyObject_TypeCheck(firstArg, (PyTypeObject*)&PythonQtInstanceWrapper_Type)
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 '") + f->m_ml->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
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 }
257 269 // strip the first argument...
258 270 PyObject* newargs = PyTuple_GetSlice(args, 1, argc);
259 271 PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, newargs, kw, self->_wrappedPtr);
260 272 Py_DECREF(newargs);
261 273 return result;
262 274 } else {
263 275 // first arg is not of correct type!
264 276 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument, got " + firstArg->ob_type->tp_name;
265 277 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
266 278 return NULL;
267 279 }
268 280 } else {
269 281 // wrong number of args
270 282 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument.";
271 283 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
272 284 return NULL;
273 285 }
274 286 }
275 287 }
276 288 return NULL;
277 289 }
278 290
279 291 PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg, void** directReturnValuePointer)
280 292 {
281 293 int argc = args?PyTuple_Size(args):0;
282 294
283 295 #ifdef PYTHONQT_DEBUG
284 296 std::cout << "called " << info->metaMethod()->typeName() << " " << info->metaMethod()->signature() << std::endl;
285 297 #endif
286 298
287 299 PyObject* r = NULL;
288 300 bool ok = false;
289 301 if (directReturnValuePointer) {
290 302 *directReturnValuePointer = NULL;
291 303 }
292 304 if (info->nextInfo()) {
293 305 // overloaded slot call, try on all slots with strict conversion first
294 306 bool strict = true;
295 307 PythonQtSlotInfo* i = info;
296 308 while (i) {
297 309 bool skipFirst = i->isInstanceDecorator();
298 310 if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
299 311 PyErr_Clear();
300 312 ok = PythonQtCallSlot(classInfo, objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer);
301 313 if (PyErr_Occurred() || ok) break;
302 314 }
303 315 i = i->nextInfo();
304 316 if (!i) {
305 317 if (strict) {
306 318 // one more run without being strict
307 319 strict = false;
308 320 i = info;
309 321 }
310 322 }
311 323 }
312 324 if (!ok && !PyErr_Occurred()) {
313 325 QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n");
314 326 PythonQtSlotInfo* i = info;
315 327 while (i) {
316 328 e += QString(i->fullSignature()) + "\n";
317 329 i = i->nextInfo();
318 330 }
319 331 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
320 332 }
321 333 } else {
322 334 // simple (non-overloaded) slot call
323 335 bool skipFirst = info->isInstanceDecorator();
324 336 if (info->parameterCount()-1-(skipFirst?1:0) == argc) {
325 337 PyErr_Clear();
326 338 ok = PythonQtCallSlot(classInfo, objectToCall, args, false, info, firstArg, &r, directReturnValuePointer);
327 339 if (!ok && !PyErr_Occurred()) {
328 340 QString e = QString("Called ") + info->fullSignature() + " with wrong arguments: " + PythonQtConv::PyObjGetString(args);
329 341 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
330 342 }
331 343 } else {
332 344 QString e = QString("Called ") + info->fullSignature() + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args);
333 345 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
334 346 }
335 347 }
336 348
337 349 return r;
338 350 }
339 351
340 352 PyObject *
341 353 PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module)
342 354 {
343 355 PythonQtSlotFunctionObject *op;
344 356 op = pythonqtslot_free_list;
345 357 if (op != NULL) {
346 358 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self);
347 359 PyObject_INIT(op, &PythonQtSlotFunction_Type);
348 360 }
349 361 else {
350 362 op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type);
351 363 if (op == NULL)
352 364 return NULL;
353 365 }
354 366 op->m_ml = ml;
355 367 Py_XINCREF(self);
356 368 op->m_self = self;
357 369 Py_XINCREF(module);
358 370 op->m_module = module;
359 371 PyObject_GC_Track(op);
360 372 return (PyObject *)op;
361 373 }
362 374
363 375 PythonQtSlotInfo*
364 376 PythonQtSlotFunction_GetSlotInfo(PyObject *op)
365 377 {
366 378 if (!PythonQtSlotFunction_Check(op)) {
367 379 PyErr_Format(PyExc_SystemError, "%s:%d: bad argument to internal function", __FILE__, __LINE__);
368 380 return NULL;
369 381 }
370 382 return ((PythonQtSlotFunctionObject *)op) -> m_ml;
371 383 }
372 384
373 385 PyObject *
374 386 PythonQtSlotFunction_GetSelf(PyObject *op)
375 387 {
376 388 if (!PythonQtSlotFunction_Check(op)) {
377 389 PyErr_Format(PyExc_SystemError, "%s:%d: bad argument to internal function", __FILE__, __LINE__);
378 390 return NULL;
379 391 }
380 392 return ((PythonQtSlotFunctionObject *)op) -> m_self;
381 393 }
382 394
383 395 /* Methods (the standard built-in methods, that is) */
384 396
385 397 static void
386 398 meth_dealloc(PythonQtSlotFunctionObject *m)
387 399 {
388 400 PyObject_GC_UnTrack(m);
389 401 Py_XDECREF(m->m_self);
390 402 Py_XDECREF(m->m_module);
391 403 m->m_self = (PyObject *)pythonqtslot_free_list;
392 404 pythonqtslot_free_list = m;
393 405 }
394 406
395 407 static PyObject *
396 408 meth_get__doc__(PythonQtSlotFunctionObject * /*m*/, void * /*closure*/)
397 409 {
398 410 Py_INCREF(Py_None);
399 411 return Py_None;
400 412 }
401 413
402 414 static PyObject *
403 415 meth_get__name__(PythonQtSlotFunctionObject *m, void * /*closure*/)
404 416 {
405 417 return PyString_FromString(m->m_ml->metaMethod()->signature());
406 418 }
407 419
408 420 static int
409 421 meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg)
410 422 {
411 423 int err;
412 424 if (m->m_self != NULL) {
413 425 err = visit(m->m_self, arg);
414 426 if (err)
415 427 return err;
416 428 }
417 429 if (m->m_module != NULL) {
418 430 err = visit(m->m_module, arg);
419 431 if (err)
420 432 return err;
421 433 }
422 434 return 0;
423 435 }
424 436
425 437 static PyObject *
426 438 meth_get__self__(PythonQtSlotFunctionObject *m, void * /*closure*/)
427 439 {
428 440 PyObject *self;
429 441 if (PyEval_GetRestricted()) {
430 442 PyErr_SetString(PyExc_RuntimeError,
431 443 "method.__self__ not accessible in restricted mode");
432 444 return NULL;
433 445 }
434 446 self = m->m_self;
435 447 if (self == NULL)
436 448 self = Py_None;
437 449 Py_INCREF(self);
438 450 return self;
439 451 }
440 452
441 453 static PyGetSetDef meth_getsets [] = {
442 454 {const_cast<char*>("__doc__"), (getter)meth_get__doc__, NULL, NULL},
443 455 {const_cast<char*>("__name__"), (getter)meth_get__name__, NULL, NULL},
444 456 {const_cast<char*>("__self__"), (getter)meth_get__self__, NULL, NULL},
445 457 {NULL, NULL, NULL,NULL},
446 458 };
447 459
448 460 #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6
449 461 #define PY_WRITE_RESTRICTED WRITE_RESTRICTED
450 462 #endif
451 463
452 464 #define OFF(x) offsetof(PythonQtSlotFunctionObject, x)
453 465
454 466 static PyMemberDef meth_members[] = {
455 467 {const_cast<char*>("__module__"), T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED},
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 {
462 564 if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
463 565 PythonQtClassWrapper* self = (PythonQtClassWrapper*) f->m_self;
464 566 return PyString_FromFormat("<unbound qt slot %s of %s type>",
465 567 f->m_ml->slotName().data(),
466 568 self->classInfo()->className());
467 569 } else {
468 570 return PyString_FromFormat("<qt slot %s of %s instance at %p>",
469 571 f->m_ml->slotName().data(),
470 572 f->m_self->ob_type->tp_name,
471 573 f->m_self);
472 574 }
473 575 }
474 576
475 577 static int
476 578 meth_compare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b)
477 579 {
478 580 if (a->m_self != b->m_self)
479 581 return (a->m_self < b->m_self) ? -1 : 1;
480 582 if (a->m_ml == b->m_ml)
481 583 return 0;
482 584 if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0)
483 585 return -1;
484 586 else
485 587 return 1;
486 588 }
487 589
488 590 static long
489 591 meth_hash(PythonQtSlotFunctionObject *a)
490 592 {
491 593 long x,y;
492 594 if (a->m_self == NULL)
493 595 x = 0;
494 596 else {
495 597 x = PyObject_Hash(a->m_self);
496 598 if (x == -1)
497 599 return -1;
498 600 }
499 601 y = _Py_HashPointer((void*)(a->m_ml));
500 602 if (y == -1)
501 603 return -1;
502 604 x ^= y;
503 605 if (x == -1)
504 606 x = -2;
505 607 return x;
506 608 }
507 609
508 610
509 611 PyTypeObject PythonQtSlotFunction_Type = {
510 612 PyObject_HEAD_INIT(&PyType_Type)
511 613 0,
512 614 "builtin_qt_slot",
513 615 sizeof(PythonQtSlotFunctionObject),
514 616 0,
515 617 (destructor)meth_dealloc, /* tp_dealloc */
516 618 0, /* tp_print */
517 619 0, /* tp_getattr */
518 620 0, /* tp_setattr */
519 621 (cmpfunc)meth_compare, /* tp_compare */
520 622 (reprfunc)meth_repr, /* tp_repr */
521 623 0, /* tp_as_number */
522 624 0, /* tp_as_sequence */
523 625 0, /* tp_as_mapping */
524 626 (hashfunc)meth_hash, /* tp_hash */
525 627 PythonQtSlotFunction_Call, /* tp_call */
526 628 0, /* tp_str */
527 629 PyObject_GenericGetAttr, /* tp_getattro */
528 630 0, /* tp_setattro */
529 631 0, /* tp_as_buffer */
530 632 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
531 633 0, /* tp_doc */
532 634 (traverseproc)meth_traverse, /* tp_traverse */
533 635 0, /* tp_clear */
534 636 0, /* tp_richcompare */
535 637 0, /* tp_weaklistoffset */
536 638 0, /* tp_iter */
537 639 0, /* tp_iternext */
538 0, /* tp_methods */
640 meth_methods, /* tp_methods */
539 641 meth_members, /* tp_members */
540 642 meth_getsets, /* tp_getset */
541 643 0, /* tp_base */
542 644 0, /* tp_dict */
543 645 };
544 646
545 647 /* Clear out the free list */
546 648
547 649 void
548 650 PythonQtSlotFunction_Fini(void)
549 651 {
550 652 while (pythonqtslot_free_list) {
551 653 PythonQtSlotFunctionObject *v = pythonqtslot_free_list;
552 654 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(v->m_self);
553 655 PyObject_GC_Del(v);
554 656 }
555 657 }
556 658
@@ -1,81 +1,85
1 1 #ifndef _PYTHONQTSLOT_H
2 2 #define _PYTHONQTSLOT_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtSlot.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtPythonInclude.h"
46 46
47 47 #include "PythonQtSystem.h"
48 48 #include "structmember.h"
49 49
50 50 class PythonQtSlotInfo;
51 51
52 52 extern PYTHONQT_EXPORT PyTypeObject PythonQtSlotFunction_Type;
53 53
54 54 #define PythonQtSlotFunction_Check(op) ((op)->ob_type == &PythonQtSlotFunction_Type)
55 55
56 56 PythonQtSlotInfo* PythonQtSlotFunction_GetSlotInfo(PyObject *);
57 57 PyObject* PythonQtSlotFunction_GetSelf(PyObject *);
58 58
59 59 /* Macros for direct access to these values. Type checks are *not*
60 60 done, so use with care. */
61 61 #define PythonQtSlotFunction_GET_SELF(func) \
62 62 (((PythonQtSlotFunctionObject *)func) -> m_self)
63 63
64 64 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
75 79 PythonQtSlotInfo *m_ml; /* Description of the C function to call */
76 80 PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */
77 81 PyObject *m_module; /* The __module__ attribute, can be anything */
78 82 } PythonQtSlotFunctionObject;
79 83
80 84
81 85 #endif
@@ -1,315 +1,318
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtStdDecorators.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2007-04
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtStdDecorators.h"
43 43 #include "PythonQt.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include <QCoreApplication>
46 46
47 47 bool PythonQtStdDecorators::connect(QObject* sender, const QByteArray& signal, PyObject* callable)
48 48 {
49 49 bool result = false;
50 50 QByteArray signalTmp;
51 51 char first = signal.at(0);
52 52 if (first>='0' && first<='9') {
53 53 signalTmp = signal;
54 54 } else {
55 55 signalTmp = "2" + signal;
56 56 }
57 57
58 58 if (sender) {
59 59 result = PythonQt::self()->addSignalHandler(sender, signalTmp, callable);
60 60 if (!result) {
61 61 if (sender->metaObject()->indexOfSignal(QMetaObject::normalizedSignature(signalTmp.constData()+1)) == -1) {
62 62 qWarning("PythonQt: QObject::connect() signal '%s' does not exist on %s", signal.constData(), sender->metaObject()->className());
63 63 }
64 64 }
65 65 }
66 66 return result;
67 67 }
68 68
69 69 bool PythonQtStdDecorators::connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot)
70 70 {
71 71 bool r = false;
72 72 if (sender && receiver) {
73 73 QByteArray signalTmp;
74 74 char first = signal.at(0);
75 75 if (first>='0' && first<='9') {
76 76 signalTmp = signal;
77 77 } else {
78 78 signalTmp = "2" + signal;
79 79 }
80 80
81 81 QByteArray slotTmp;
82 82 first = slot.at(0);
83 83 if (first>='0' && first<='9') {
84 84 slotTmp = slot;
85 85 } else {
86 86 slotTmp = "1" + slot;
87 87 }
88 88 r = QObject::connect(sender, signalTmp, receiver, slotTmp);
89 89 }
90 90 return r;
91 91 }
92 92
93 93 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal, PyObject* callable)
94 94 {
95 95 bool result = false;
96 96 QByteArray signalTmp;
97 97 char first = signal.at(0);
98 98 if (first>='0' && first<='9') {
99 99 signalTmp = signal;
100 100 } else {
101 101 signalTmp = "2" + 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());
108 111 }
109 112 }
110 113 }
111 114 return result;
112 115 }
113 116
114 117 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot)
115 118 {
116 119 bool r = false;
117 120 if (sender && receiver) {
118 121 QByteArray signalTmp;
119 122 char first = signal.at(0);
120 123 if (first>='0' && first<='9') {
121 124 signalTmp = signal;
122 125 } else {
123 126 signalTmp = "2" + signal;
124 127 }
125 128
126 129 QByteArray slotTmp;
127 130 first = slot.at(0);
128 131 if (first>='0' && first<='9') {
129 132 slotTmp = slot;
130 133 } else {
131 134 slotTmp = "1" + slot;
132 135 }
133 136
134 137 r = QObject::disconnect(sender, signalTmp, receiver, slotTmp);
135 138 }
136 139 return r;
137 140 }
138 141
139 142 QObject* PythonQtStdDecorators::parent(QObject* o) {
140 143 return o->parent();
141 144 }
142 145
143 146 void PythonQtStdDecorators::setParent(QObject* o, QObject* parent)
144 147 {
145 148 o->setParent(parent);
146 149 }
147 150
148 151 const QObjectList* PythonQtStdDecorators::children(QObject* o)
149 152 {
150 153 return &o->children();
151 154 }
152 155
153 156 bool PythonQtStdDecorators::setProperty(QObject* o, const char* name, const QVariant& value)
154 157 {
155 158 return o->setProperty(name, value);
156 159 }
157 160
158 161 QVariant PythonQtStdDecorators::property(QObject* o, const char* name)
159 162 {
160 163 return o->property(name);
161 164 }
162 165
163 166 QString PythonQtStdDecorators::tr(QObject* obj, const QByteArray& text, const QByteArray& ambig, int n)
164 167 {
165 168 return QCoreApplication::translate(obj->metaObject()->className(), text.constData(), ambig.constData(), QCoreApplication::CodecForTr, n);
166 169 }
167 170
168 171 QObject* PythonQtStdDecorators::findChild(QObject* parent, PyObject* type, const QString& name)
169 172 {
170 173 const QMetaObject* meta = NULL;
171 174 const char* typeName = NULL;
172 175
173 176 if (PyObject_TypeCheck(type, &PythonQtClassWrapper_Type)) {
174 177 meta = ((PythonQtClassWrapper*)type)->classInfo()->metaObject();
175 178 } else if (PyObject_TypeCheck(type, &PythonQtInstanceWrapper_Type)) {
176 179 meta = ((PythonQtInstanceWrapper*)type)->classInfo()->metaObject();
177 180 } else if (PyString_Check(type)) {
178 181 typeName = PyString_AsString(type);
179 182 }
180 183
181 184 if (!typeName && !meta)
182 185 return NULL;
183 186
184 187 return findChild(parent, typeName, meta, name);
185 188 }
186 189
187 190 QList<QObject*> PythonQtStdDecorators::findChildren(QObject* parent, PyObject* type, const QString& name)
188 191 {
189 192 const QMetaObject* meta = NULL;
190 193 const char* typeName = NULL;
191 194
192 195 if (PyObject_TypeCheck(type, &PythonQtClassWrapper_Type)) {
193 196 meta = ((PythonQtClassWrapper*)type)->classInfo()->metaObject();
194 197 } else if (PyObject_TypeCheck(type, &PythonQtInstanceWrapper_Type)) {
195 198 meta = ((PythonQtInstanceWrapper*)type)->classInfo()->metaObject();
196 199 } else if (PyString_Check(type)) {
197 200 typeName = PyString_AsString(type);
198 201 }
199 202
200 203 QList<QObject*> list;
201 204
202 205 if (!typeName && !meta)
203 206 return list;
204 207
205 208 findChildren(parent, typeName, meta, name, list);
206 209
207 210 return list;
208 211 }
209 212
210 213 QList<QObject*> PythonQtStdDecorators::findChildren(QObject* parent, PyObject* type, const QRegExp& regExp)
211 214 {
212 215 const QMetaObject* meta = NULL;
213 216 const char* typeName = NULL;
214 217
215 218 if (PyObject_TypeCheck(type, &PythonQtClassWrapper_Type)) {
216 219 meta = ((PythonQtClassWrapper*)type)->classInfo()->metaObject();
217 220 } else if (PyObject_TypeCheck(type, &PythonQtInstanceWrapper_Type)) {
218 221 meta = ((PythonQtInstanceWrapper*)type)->classInfo()->metaObject();
219 222 } else if (PyString_Check(type)) {
220 223 typeName = PyString_AsString(type);
221 224 }
222 225
223 226 QList<QObject*> list;
224 227
225 228 if (!typeName && !meta)
226 229 return list;
227 230
228 231 findChildren(parent, typeName, meta, regExp, list);
229 232
230 233 return list;
231 234 }
232 235
233 236 QObject* PythonQtStdDecorators::findChild(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name)
234 237 {
235 238 const QObjectList &children = parent->children();
236 239
237 240 int i;
238 241 for (i = 0; i < children.size(); ++i) {
239 242 QObject* obj = children.at(i);
240 243
241 244 if (!obj)
242 245 return NULL;
243 246
244 247 // Skip if the name doesn't match.
245 248 if (!name.isNull() && obj->objectName() != name)
246 249 continue;
247 250
248 251 if ((typeName && obj->inherits(typeName)) ||
249 252 (meta && meta->cast(obj)))
250 253 return obj;
251 254 }
252 255
253 256 for (i = 0; i < children.size(); ++i) {
254 257 QObject* obj = findChild(children.at(i), typeName, meta, name);
255 258
256 259 if (obj != NULL)
257 260 return obj;
258 261 }
259 262
260 263 return NULL;
261 264 }
262 265
263 266 int PythonQtStdDecorators::findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name, QList<QObject*>& list)
264 267 {
265 268 const QObjectList& children = parent->children();
266 269 int i;
267 270
268 271 for (i = 0; i < children.size(); ++i) {
269 272 QObject* obj = children.at(i);
270 273
271 274 if (!obj)
272 275 return -1;
273 276
274 277 // Skip if the name doesn't match.
275 278 if (!name.isNull() && obj->objectName() != name)
276 279 continue;
277 280
278 281 if ((typeName && obj->inherits(typeName)) ||
279 282 (meta && meta->cast(obj))) {
280 283 list += obj;
281 284 }
282 285
283 286 if (findChildren(obj, typeName, meta, name, list) < 0)
284 287 return -1;
285 288 }
286 289
287 290 return 0;
288 291 }
289 292
290 293 int PythonQtStdDecorators::findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QRegExp& regExp, QList<QObject*>& list)
291 294 {
292 295 const QObjectList& children = parent->children();
293 296 int i;
294 297
295 298 for (i = 0; i < children.size(); ++i) {
296 299 QObject* obj = children.at(i);
297 300
298 301 if (!obj)
299 302 return -1;
300 303
301 304 // Skip if the name doesn't match.
302 305 if (regExp.indexIn(obj->objectName()) == -1)
303 306 continue;
304 307
305 308 if ((typeName && obj->inherits(typeName)) ||
306 309 (meta && meta->cast(obj))) {
307 310 list += obj;
308 311 }
309 312
310 313 if (findChildren(obj, typeName, meta, regExp, list) < 0)
311 314 return -1;
312 315 }
313 316
314 317 return 0;
315 318 }
@@ -1,109 +1,109
1 1 #ifndef _PYTHONQTSTDDECORATORS_H
2 2 #define _PYTHONQTSTDDECORATORS_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtStdDecorators.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2007-04
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtPythonInclude.h"
46 46
47 47 #include "PythonQtSystem.h"
48 48
49 49 #include <QObject>
50 50 #include <QVariantList>
51 51 #include <QTextDocument>
52 52 #include <QColor>
53 53 #include <QDateTime>
54 54 #include <QDate>
55 55 #include <QTime>
56 56
57 57 class PYTHONQT_EXPORT PythonQtStdDecorators : public QObject
58 58 {
59 59 Q_OBJECT
60 60
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);
68 68 void setParent(QObject* o, QObject* parent);
69 69
70 70 const QObjectList* children(QObject* o);
71 71 QObject* findChild(QObject* parent, PyObject* type, const QString& name = QString());
72 72 QList<QObject*> findChildren(QObject* parent, PyObject* type, const QString& name= QString());
73 73 QList<QObject*> findChildren(QObject* parent, PyObject* type, const QRegExp& regExp);
74 74
75 75 bool setProperty(QObject* o, const char* name, const QVariant& value);
76 76 QVariant property(QObject* o, const char* name);
77 77
78 78 double static_Qt_qAbs(double a) { return qAbs(a); }
79 79 double static_Qt_qBound(double a,double b,double c) { return qBound(a,b,c); }
80 80 void static_Qt_qDebug(const QByteArray& msg) { qDebug("%s", msg.constData()); }
81 81 // TODO: multi arg qDebug...
82 82 void static_Qt_qWarning(const QByteArray& msg) { qWarning("%s", msg.constData()); }
83 83 // TODO: multi arg qWarning...
84 84 void static_Qt_qCritical(const QByteArray& msg) { qCritical("%s", msg.constData()); }
85 85 // TODO: multi arg qCritical...
86 86 void static_Qt_qFatal(const QByteArray& msg) { qFatal("%s", msg.constData()); }
87 87 // TODO: multi arg qFatal...
88 88 bool static_Qt_qFuzzyCompare(double a, double b) { return qFuzzyCompare(a, b); }
89 89 double static_Qt_qMax(double a, double b) { return qMax(a, b); }
90 90 double static_Qt_qMin(double a, double b) { return qMin(a, b); }
91 91 int static_Qt_qRound(double a) { return qRound(a); }
92 92 qint64 static_Qt_qRound64(double a) { return qRound64(a); }
93 93 const char* static_Qt_qVersion() { return qVersion(); }
94 94 int static_Qt_qrand() { return qrand(); }
95 95 void static_Qt_qsrand(uint a) { qsrand(a); }
96 96
97 97 QString tr(QObject* obj, const QByteArray& text, const QByteArray& ambig = QByteArray(), int n = -1);
98 98
99 99 QByteArray static_Qt_SIGNAL(const QByteArray& s) { return QByteArray("2") + s; }
100 100 QByteArray static_Qt_SLOT(const QByteArray& s) { return QByteArray("1") + s; }
101 101
102 102 private:
103 103 QObject* findChild(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name);
104 104 int findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name, QList<QObject*>& list);
105 105 int findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QRegExp& regExp, QList<QObject*>& list);
106 106 };
107 107
108 108
109 109 #endif
@@ -1,45 +1,47
1 1 DEFINES += PYTHONQT_EXPORTS
2 2
3 3 HEADERS += \
4 4 $$PWD/PythonQt.h \
5 5 $$PWD/PythonQtStdDecorators.h \
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 \
12 13 $$PWD/PythonQtMisc.h \
13 14 $$PWD/PythonQtMethodInfo.h \
14 15 $$PWD/PythonQtImportFileInterface.h \
15 16 $$PWD/PythonQtConversion.h \
16 17 $$PWD/PythonQtSignalReceiver.h \
17 18 $$PWD/PythonQtInstanceWrapper.h \
18 19 $$PWD/PythonQtClassWrapper.h \
19 20 $$PWD/PythonQtCppWrapperFactory.h \
20 21 $$PWD/PythonQtQFileImporter.h \
21 22 $$PWD/PythonQtQFileImporter.h \
22 23 $$PWD/PythonQtVariants.h \
23 24 $$PWD/gui/PythonQtScriptingConsole.h \
24 25 $$PWD/PythonQtSystem.h
25 26
26 27 SOURCES += \
27 28 $$PWD/PythonQtStdDecorators.cpp \
28 29 $$PWD/PythonQt.cpp \
29 30 $$PWD/PythonQtClassInfo.cpp \
30 31 $$PWD/PythonQtImporter.cpp \
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 \
37 39 $$PWD/PythonQtConversion.cpp \
38 40 $$PWD/PythonQtSignalReceiver.cpp \
39 41 $$PWD/PythonQtInstanceWrapper.cpp \
40 42 $$PWD/PythonQtQFileImporter.cpp \
41 43 $$PWD/PythonQtClassWrapper.cpp \
42 44 $$PWD/gui/PythonQtScriptingConsole.cpp \
43 45
44 46 include($$PWD/../generated_cpp/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin.pri)
45 47 include($$PWD/../generated_cpp/com_trolltech_qt_gui_builtin/com_trolltech_qt_gui_builtin.pri)
General Comments 0
You need to be logged in to leave comments. Login now