##// END OF EJS Templates
added missing parenthesis...
florianlink -
r150:aaf00f610021
parent child
Show More
@@ -1,1230 +1,1230
1 /*
1 /*
2 *
2 *
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 *
4 *
5 * This library is free software; you can redistribute it and/or
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
8 * version 2.1 of the License, or (at your option) any later version.
9 *
9 *
10 * This library is distributed in the hope that it will be useful,
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
13 * Lesser General Public License for more details.
14 *
14 *
15 * Further, this software is distributed without any warranty that it is
15 * Further, this software is distributed without any warranty that it is
16 * free of the rightful claim of any third person regarding infringement
16 * free of the rightful claim of any third person regarding infringement
17 * or the like. Any license provided herein, whether implied or
17 * or the like. Any license provided herein, whether implied or
18 * otherwise, applies only to this software file. Patent licenses, if
18 * otherwise, applies only to this software file. Patent licenses, if
19 * any, provided herein do not apply to combinations of this program with
19 * any, provided herein do not apply to combinations of this program with
20 * other software, or any other product whatsoever.
20 * other software, or any other product whatsoever.
21 *
21 *
22 * You should have received a copy of the GNU Lesser General Public
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
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
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
25 *
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 * 28359 Bremen, Germany or:
27 * 28359 Bremen, Germany or:
28 *
28 *
29 * http://www.mevis.de
29 * http://www.mevis.de
30 *
30 *
31 */
31 */
32
32
33 //----------------------------------------------------------------------------------
33 //----------------------------------------------------------------------------------
34 /*!
34 /*!
35 // \file PythonQt.cpp
35 // \file PythonQt.cpp
36 // \author Florian Link
36 // \author Florian Link
37 // \author Last changed by $Author: florian $
37 // \author Last changed by $Author: florian $
38 // \date 2006-05
38 // \date 2006-05
39 */
39 */
40 //----------------------------------------------------------------------------------
40 //----------------------------------------------------------------------------------
41
41
42 #include "PythonQt.h"
42 #include "PythonQt.h"
43 #include "PythonQtImporter.h"
43 #include "PythonQtImporter.h"
44 #include "PythonQtClassInfo.h"
44 #include "PythonQtClassInfo.h"
45 #include "PythonQtMethodInfo.h"
45 #include "PythonQtMethodInfo.h"
46 #include "PythonQtSignalReceiver.h"
46 #include "PythonQtSignalReceiver.h"
47 #include "PythonQtConversion.h"
47 #include "PythonQtConversion.h"
48 #include "PythonQtStdOut.h"
48 #include "PythonQtStdOut.h"
49 #include "PythonQtCppWrapperFactory.h"
49 #include "PythonQtCppWrapperFactory.h"
50 #include "PythonQtVariants.h"
50 #include "PythonQtVariants.h"
51 #include "PythonQtStdDecorators.h"
51 #include "PythonQtStdDecorators.h"
52 #include "PythonQtQFileImporter.h"
52 #include "PythonQtQFileImporter.h"
53 #include <pydebug.h>
53 #include <pydebug.h>
54 #include <vector>
54 #include <vector>
55
55
56 PythonQt* PythonQt::_self = NULL;
56 PythonQt* PythonQt::_self = NULL;
57 int PythonQt::_uniqueModuleCount = 0;
57 int PythonQt::_uniqueModuleCount = 0;
58
58
59 void PythonQt_init_QtGuiBuiltin(PyObject*);
59 void PythonQt_init_QtGuiBuiltin(PyObject*);
60 void PythonQt_init_QtCoreBuiltin(PyObject*);
60 void PythonQt_init_QtCoreBuiltin(PyObject*);
61
61
62 void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
62 void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
63 {
63 {
64 if (!_self) {
64 if (!_self) {
65 _self = new PythonQt(flags, pythonQtModuleName);
65 _self = new PythonQt(flags, pythonQtModuleName);
66
66
67 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
67 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
68 qRegisterMetaType<QList<QObject*> >("QList<void*>");
68 qRegisterMetaType<QList<QObject*> >("QList<void*>");
69
69
70 PythonQtRegisterToolClassesTemplateConverter(int);
70 PythonQtRegisterToolClassesTemplateConverter(int);
71 PythonQtRegisterToolClassesTemplateConverter(float);
71 PythonQtRegisterToolClassesTemplateConverter(float);
72 PythonQtRegisterToolClassesTemplateConverter(double);
72 PythonQtRegisterToolClassesTemplateConverter(double);
73 PythonQtRegisterToolClassesTemplateConverter(qint32);
73 PythonQtRegisterToolClassesTemplateConverter(qint32);
74 PythonQtRegisterToolClassesTemplateConverter(quint32);
74 PythonQtRegisterToolClassesTemplateConverter(quint32);
75 PythonQtRegisterToolClassesTemplateConverter(qint64);
75 PythonQtRegisterToolClassesTemplateConverter(qint64);
76 PythonQtRegisterToolClassesTemplateConverter(quint64);
76 PythonQtRegisterToolClassesTemplateConverter(quint64);
77 // TODO: which other POD types should be available for QList etc.
77 // TODO: which other POD types should be available for QList etc.
78
78
79 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
79 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
80
80
81 PythonQt_init_QtCoreBuiltin(NULL);
81 PythonQt_init_QtCoreBuiltin(NULL);
82 PythonQt_init_QtGuiBuiltin(NULL);
82 PythonQt_init_QtGuiBuiltin(NULL);
83
83
84 PythonQtRegisterToolClassesTemplateConverter(QByteArray);
84 PythonQtRegisterToolClassesTemplateConverter(QByteArray);
85 PythonQtRegisterToolClassesTemplateConverter(QDate);
85 PythonQtRegisterToolClassesTemplateConverter(QDate);
86 PythonQtRegisterToolClassesTemplateConverter(QTime);
86 PythonQtRegisterToolClassesTemplateConverter(QTime);
87 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
87 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
88 PythonQtRegisterToolClassesTemplateConverter(QUrl);
88 PythonQtRegisterToolClassesTemplateConverter(QUrl);
89 PythonQtRegisterToolClassesTemplateConverter(QLocale);
89 PythonQtRegisterToolClassesTemplateConverter(QLocale);
90 PythonQtRegisterToolClassesTemplateConverter(QRect);
90 PythonQtRegisterToolClassesTemplateConverter(QRect);
91 PythonQtRegisterToolClassesTemplateConverter(QRectF);
91 PythonQtRegisterToolClassesTemplateConverter(QRectF);
92 PythonQtRegisterToolClassesTemplateConverter(QSize);
92 PythonQtRegisterToolClassesTemplateConverter(QSize);
93 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
93 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
94 PythonQtRegisterToolClassesTemplateConverter(QLine);
94 PythonQtRegisterToolClassesTemplateConverter(QLine);
95 PythonQtRegisterToolClassesTemplateConverter(QLineF);
95 PythonQtRegisterToolClassesTemplateConverter(QLineF);
96 PythonQtRegisterToolClassesTemplateConverter(QPoint);
96 PythonQtRegisterToolClassesTemplateConverter(QPoint);
97 PythonQtRegisterToolClassesTemplateConverter(QPointF);
97 PythonQtRegisterToolClassesTemplateConverter(QPointF);
98 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
98 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
99
99
100 PythonQtRegisterToolClassesTemplateConverter(QFont);
100 PythonQtRegisterToolClassesTemplateConverter(QFont);
101 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
101 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
102 PythonQtRegisterToolClassesTemplateConverter(QBrush);
102 PythonQtRegisterToolClassesTemplateConverter(QBrush);
103 PythonQtRegisterToolClassesTemplateConverter(QColor);
103 PythonQtRegisterToolClassesTemplateConverter(QColor);
104 PythonQtRegisterToolClassesTemplateConverter(QPalette);
104 PythonQtRegisterToolClassesTemplateConverter(QPalette);
105 PythonQtRegisterToolClassesTemplateConverter(QIcon);
105 PythonQtRegisterToolClassesTemplateConverter(QIcon);
106 PythonQtRegisterToolClassesTemplateConverter(QImage);
106 PythonQtRegisterToolClassesTemplateConverter(QImage);
107 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
107 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
108 PythonQtRegisterToolClassesTemplateConverter(QRegion);
108 PythonQtRegisterToolClassesTemplateConverter(QRegion);
109 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
109 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
110 PythonQtRegisterToolClassesTemplateConverter(QCursor);
110 PythonQtRegisterToolClassesTemplateConverter(QCursor);
111 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
111 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
112 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
112 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
113 PythonQtRegisterToolClassesTemplateConverter(QPen);
113 PythonQtRegisterToolClassesTemplateConverter(QPen);
114 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
114 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
115 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
115 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
116 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
116 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
117
117
118
118
119 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
119 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
120 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
120 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
121 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
121 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
122 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
122 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
123 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
123 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
124 for (unsigned int i = 0;i<16; i++) {
124 for (unsigned int i = 0;i<16; i++) {
125 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
125 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
126 if (obj) {
126 if (obj) {
127 PyModule_AddObject(pack, names[i], obj);
127 PyModule_AddObject(pack, names[i], obj);
128 Py_INCREF(obj);
128 Py_INCREF(obj);
129 PyModule_AddObject(pack2, names[i], obj);
129 PyModule_AddObject(pack2, names[i], obj);
130 } else {
130 } else {
131 std::cerr << "method not found " << names[i];
131 std::cerr << "method not found " << names[i];
132 }
132 }
133 }
133 }
134 }
134 }
135 }
135 }
136
136
137 void PythonQt::cleanup()
137 void PythonQt::cleanup()
138 {
138 {
139 if (_self) {
139 if (_self) {
140 delete _self;
140 delete _self;
141 _self = NULL;
141 _self = NULL;
142 }
142 }
143 }
143 }
144
144
145 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
145 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
146 {
146 {
147 _p = new PythonQtPrivate;
147 _p = new PythonQtPrivate;
148 _p->_initFlags = flags;
148 _p->_initFlags = flags;
149
149
150 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
150 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
151
151
152 if (flags & PythonAlreadyInitialized == 0) {
152 if ((flags & PythonAlreadyInitialized) == 0) {
153 Py_SetProgramName("PythonQt");
153 Py_SetProgramName("PythonQt");
154 if (flags & IgnoreSiteModule) {
154 if (flags & IgnoreSiteModule) {
155 // this prevents the automatic importing of Python site files
155 // this prevents the automatic importing of Python site files
156 Py_NoSiteFlag = 1;
156 Py_NoSiteFlag = 1;
157 }
157 }
158 Py_Initialize();
158 Py_Initialize();
159 }
159 }
160
160
161 // add our own python object types for qt object slots
161 // add our own python object types for qt object slots
162 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
162 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
163 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
163 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
164 }
164 }
165 Py_INCREF(&PythonQtSlotFunction_Type);
165 Py_INCREF(&PythonQtSlotFunction_Type);
166
166
167 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
167 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
168 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
168 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
169 // add our own python object types for classes
169 // add our own python object types for classes
170 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
170 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
171 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
171 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
172 }
172 }
173 Py_INCREF(&PythonQtClassWrapper_Type);
173 Py_INCREF(&PythonQtClassWrapper_Type);
174
174
175 // add our own python object types for CPP instances
175 // add our own python object types for CPP instances
176 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
176 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
177 PythonQt::handleError();
177 PythonQt::handleError();
178 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
178 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
179 }
179 }
180 Py_INCREF(&PythonQtInstanceWrapper_Type);
180 Py_INCREF(&PythonQtInstanceWrapper_Type);
181
181
182 // add our own python object types for redirection of stdout
182 // add our own python object types for redirection of stdout
183 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
183 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
184 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
184 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
185 }
185 }
186 Py_INCREF(&PythonQtStdOutRedirectType);
186 Py_INCREF(&PythonQtStdOutRedirectType);
187
187
188 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
188 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
189
189
190 _p->setupSharedLibrarySuffixes();
190 _p->setupSharedLibrarySuffixes();
191
191
192 }
192 }
193
193
194 PythonQt::~PythonQt() {
194 PythonQt::~PythonQt() {
195 delete _p;
195 delete _p;
196 _p = NULL;
196 _p = NULL;
197 }
197 }
198
198
199 PythonQtPrivate::~PythonQtPrivate() {
199 PythonQtPrivate::~PythonQtPrivate() {
200 delete _defaultImporter;
200 delete _defaultImporter;
201 _defaultImporter = NULL;
201 _defaultImporter = NULL;
202
202
203 {
203 {
204 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
204 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
205 while (i.hasNext()) {
205 while (i.hasNext()) {
206 delete i.next().value();
206 delete i.next().value();
207 }
207 }
208 }
208 }
209 PythonQtConv::global_valueStorage.clear();
209 PythonQtConv::global_valueStorage.clear();
210 PythonQtConv::global_ptrStorage.clear();
210 PythonQtConv::global_ptrStorage.clear();
211 PythonQtConv::global_variantStorage.clear();
211 PythonQtConv::global_variantStorage.clear();
212
212
213 PythonQtMethodInfo::cleanupCachedMethodInfos();
213 PythonQtMethodInfo::cleanupCachedMethodInfos();
214 }
214 }
215
215
216 PythonQtImportFileInterface* PythonQt::importInterface()
216 PythonQtImportFileInterface* PythonQt::importInterface()
217 {
217 {
218 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
218 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
219 }
219 }
220
220
221 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
221 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
222 {
222 {
223 if (_self->_p->_noLongerWrappedCB) {
223 if (_self->_p->_noLongerWrappedCB) {
224 (*_self->_p->_noLongerWrappedCB)(o);
224 (*_self->_p->_noLongerWrappedCB)(o);
225 };
225 };
226 }
226 }
227
227
228 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
228 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
229 {
229 {
230 _p->registerClass(metaobject, package, wrapperCreator, shell);
230 _p->registerClass(metaobject, package, wrapperCreator, shell);
231 }
231 }
232
232
233 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
233 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
234 {
234 {
235 // we register all classes in the hierarchy
235 // we register all classes in the hierarchy
236 const QMetaObject* m = metaobject;
236 const QMetaObject* m = metaobject;
237 bool first = true;
237 bool first = true;
238 while (m) {
238 while (m) {
239 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
239 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
240 if (!info->pythonQtClassWrapper()) {
240 if (!info->pythonQtClassWrapper()) {
241 info->setTypeSlots(typeSlots);
241 info->setTypeSlots(typeSlots);
242 info->setupQObject(m);
242 info->setupQObject(m);
243 createPythonQtClassWrapper(info, package, module);
243 createPythonQtClassWrapper(info, package, module);
244 if (m->superClass()) {
244 if (m->superClass()) {
245 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
245 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
246 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
246 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
247 }
247 }
248 }
248 }
249 if (first) {
249 if (first) {
250 first = false;
250 first = false;
251 if (wrapperCreator) {
251 if (wrapperCreator) {
252 info->setDecoratorProvider(wrapperCreator);
252 info->setDecoratorProvider(wrapperCreator);
253 }
253 }
254 if (shell) {
254 if (shell) {
255 info->setShellSetInstanceWrapperCB(shell);
255 info->setShellSetInstanceWrapperCB(shell);
256 }
256 }
257 }
257 }
258 m = m->superClass();
258 m = m->superClass();
259 }
259 }
260 }
260 }
261
261
262 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
262 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
263 {
263 {
264 PyObject* pack = module?module:packageByName(package);
264 PyObject* pack = module?module:packageByName(package);
265 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
265 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
266 PyModule_AddObject(pack, info->className(), pyobj);
266 PyModule_AddObject(pack, info->className(), pyobj);
267 if (!module && package && strncmp(package,"Qt",2)==0) {
267 if (!module && package && strncmp(package,"Qt",2)==0) {
268 // since PyModule_AddObject steals the reference, we need a incref once more...
268 // since PyModule_AddObject steals the reference, we need a incref once more...
269 Py_INCREF(pyobj);
269 Py_INCREF(pyobj);
270 // put all qt objects into Qt as well
270 // put all qt objects into Qt as well
271 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
271 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
272 }
272 }
273 info->setPythonQtClassWrapper(pyobj);
273 info->setPythonQtClassWrapper(pyobj);
274 }
274 }
275
275
276 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
276 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
277 {
277 {
278 if (!obj) {
278 if (!obj) {
279 Py_INCREF(Py_None);
279 Py_INCREF(Py_None);
280 return Py_None;
280 return Py_None;
281 }
281 }
282 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
282 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
283 if (!wrap) {
283 if (!wrap) {
284 // smuggling it in...
284 // smuggling it in...
285 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
285 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
286 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
286 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
287 registerClass(obj->metaObject());
287 registerClass(obj->metaObject());
288 classInfo = _knownClassInfos.value(obj->metaObject()->className());
288 classInfo = _knownClassInfos.value(obj->metaObject()->className());
289 }
289 }
290 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
290 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
291 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
291 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
292 } else {
292 } else {
293 Py_INCREF(wrap);
293 Py_INCREF(wrap);
294 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
294 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
295 }
295 }
296 return (PyObject*)wrap;
296 return (PyObject*)wrap;
297 }
297 }
298
298
299 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
299 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
300 {
300 {
301 if (!ptr) {
301 if (!ptr) {
302 Py_INCREF(Py_None);
302 Py_INCREF(Py_None);
303 return Py_None;
303 return Py_None;
304 }
304 }
305
305
306 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
306 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
307 if (!wrap) {
307 if (!wrap) {
308 PythonQtClassInfo* info = _knownClassInfos.value(name);
308 PythonQtClassInfo* info = _knownClassInfos.value(name);
309 if (!info) {
309 if (!info) {
310 // maybe it is a PyObject, which we can return directly
310 // maybe it is a PyObject, which we can return directly
311 if (name == "PyObject") {
311 if (name == "PyObject") {
312 PyObject* p = (PyObject*)ptr;
312 PyObject* p = (PyObject*)ptr;
313 Py_INCREF(p);
313 Py_INCREF(p);
314 return p;
314 return p;
315 }
315 }
316
316
317 // we do not know the metaobject yet, but we might know it by it's name:
317 // we do not know the metaobject yet, but we might know it by it's name:
318 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
318 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
319 // yes, we know it, so we can convert to QObject
319 // yes, we know it, so we can convert to QObject
320 QObject* qptr = (QObject*)ptr;
320 QObject* qptr = (QObject*)ptr;
321 registerClass(qptr->metaObject());
321 registerClass(qptr->metaObject());
322 info = _knownClassInfos.value(qptr->metaObject()->className());
322 info = _knownClassInfos.value(qptr->metaObject()->className());
323 }
323 }
324 }
324 }
325 if (info && info->isQObject()) {
325 if (info && info->isQObject()) {
326 QObject* qptr = (QObject*)ptr;
326 QObject* qptr = (QObject*)ptr;
327 // if the object is a derived object, we want to switch the class info to the one of the derived class:
327 // if the object is a derived object, we want to switch the class info to the one of the derived class:
328 if (name!=(qptr->metaObject()->className())) {
328 if (name!=(qptr->metaObject()->className())) {
329 registerClass(qptr->metaObject());
329 registerClass(qptr->metaObject());
330 info = _knownClassInfos.value(qptr->metaObject()->className());
330 info = _knownClassInfos.value(qptr->metaObject()->className());
331 }
331 }
332 wrap = createNewPythonQtInstanceWrapper(qptr, info);
332 wrap = createNewPythonQtInstanceWrapper(qptr, info);
333 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
333 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
334 return (PyObject*)wrap;
334 return (PyObject*)wrap;
335 }
335 }
336
336
337 // not a known QObject, so try our wrapper factory:
337 // not a known QObject, so try our wrapper factory:
338 QObject* wrapper = NULL;
338 QObject* wrapper = NULL;
339 for (int i=0; i<_cppWrapperFactories.size(); i++) {
339 for (int i=0; i<_cppWrapperFactories.size(); i++) {
340 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
340 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
341 if (wrapper) {
341 if (wrapper) {
342 break;
342 break;
343 }
343 }
344 }
344 }
345
345
346 if (info) {
346 if (info) {
347 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
347 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
348 ptr = info->castDownIfPossible(ptr, &info);
348 ptr = info->castDownIfPossible(ptr, &info);
349 }
349 }
350
350
351 if (!info || info->pythonQtClassWrapper()==NULL) {
351 if (!info || info->pythonQtClassWrapper()==NULL) {
352 // still unknown, register as CPP class
352 // still unknown, register as CPP class
353 registerCPPClass(name.constData());
353 registerCPPClass(name.constData());
354 info = _knownClassInfos.value(name);
354 info = _knownClassInfos.value(name);
355 }
355 }
356 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
356 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
357 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
357 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
358 info->setMetaObject(wrapper->metaObject());
358 info->setMetaObject(wrapper->metaObject());
359 }
359 }
360 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
360 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
361 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
361 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
362 } else {
362 } else {
363 Py_INCREF(wrap);
363 Py_INCREF(wrap);
364 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
364 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
365 }
365 }
366 return (PyObject*)wrap;
366 return (PyObject*)wrap;
367 }
367 }
368
368
369 PyObject* PythonQtPrivate::dummyTuple() {
369 PyObject* PythonQtPrivate::dummyTuple() {
370 static PyObject* dummyTuple = NULL;
370 static PyObject* dummyTuple = NULL;
371 if (dummyTuple==NULL) {
371 if (dummyTuple==NULL) {
372 dummyTuple = PyTuple_New(1);
372 dummyTuple = PyTuple_New(1);
373 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
373 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
374 }
374 }
375 return dummyTuple;
375 return dummyTuple;
376 }
376 }
377
377
378
378
379 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
379 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
380 // call the associated class type to create a new instance...
380 // call the associated class type to create a new instance...
381 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
381 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
382
382
383 result->setQObject(obj);
383 result->setQObject(obj);
384 result->_wrappedPtr = wrappedPtr;
384 result->_wrappedPtr = wrappedPtr;
385 result->_ownedByPythonQt = false;
385 result->_ownedByPythonQt = false;
386 result->_useQMetaTypeDestroy = false;
386 result->_useQMetaTypeDestroy = false;
387
387
388 if (wrappedPtr) {
388 if (wrappedPtr) {
389 _wrappedObjects.insert(wrappedPtr, result);
389 _wrappedObjects.insert(wrappedPtr, result);
390 } else {
390 } else {
391 _wrappedObjects.insert(obj, result);
391 _wrappedObjects.insert(obj, result);
392 if (obj->parent()== NULL && _wrappedCB) {
392 if (obj->parent()== NULL && _wrappedCB) {
393 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
393 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
394 (*_wrappedCB)(obj);
394 (*_wrappedCB)(obj);
395 }
395 }
396 }
396 }
397 return result;
397 return result;
398 }
398 }
399
399
400 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
400 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
401 PythonQtClassWrapper* result;
401 PythonQtClassWrapper* result;
402
402
403 PyObject* className = PyString_FromString(info->className());
403 PyObject* className = PyString_FromString(info->className());
404
404
405 PyObject* baseClasses = PyTuple_New(1);
405 PyObject* baseClasses = PyTuple_New(1);
406 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
406 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
407
407
408 PyObject* typeDict = PyDict_New();
408 PyObject* typeDict = PyDict_New();
409 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
409 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
410 PyDict_SetItemString(typeDict, "__module__", moduleName);
410 PyDict_SetItemString(typeDict, "__module__", moduleName);
411
411
412 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
412 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
413
413
414 // set the class info so that PythonQtClassWrapper_new can read it
414 // set the class info so that PythonQtClassWrapper_new can read it
415 _currentClassInfoForClassWrapperCreation = info;
415 _currentClassInfoForClassWrapperCreation = info;
416 // create the new type object by calling the type
416 // create the new type object by calling the type
417 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
417 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
418
418
419 Py_DECREF(baseClasses);
419 Py_DECREF(baseClasses);
420 Py_DECREF(typeDict);
420 Py_DECREF(typeDict);
421 Py_DECREF(args);
421 Py_DECREF(args);
422 Py_DECREF(className);
422 Py_DECREF(className);
423
423
424 return result;
424 return result;
425 }
425 }
426
426
427 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
427 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
428 {
428 {
429 PyObject* args = Py_BuildValue("(i)", enumValue);
429 PyObject* args = Py_BuildValue("(i)", enumValue);
430 PyObject* result = PyObject_Call(enumType, args, NULL);
430 PyObject* result = PyObject_Call(enumType, args, NULL);
431 Py_DECREF(args);
431 Py_DECREF(args);
432 return result;
432 return result;
433 }
433 }
434
434
435 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
435 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
436 PyObject* result;
436 PyObject* result;
437
437
438 PyObject* className = PyString_FromString(enumName);
438 PyObject* className = PyString_FromString(enumName);
439
439
440 PyObject* baseClasses = PyTuple_New(1);
440 PyObject* baseClasses = PyTuple_New(1);
441 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
441 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
442
442
443 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
443 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
444 PyObject* typeDict = PyDict_New();
444 PyObject* typeDict = PyDict_New();
445 PyDict_SetItemString(typeDict, "__module__", module);
445 PyDict_SetItemString(typeDict, "__module__", module);
446
446
447 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
447 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
448
448
449 // create the new int derived type object by calling the core type
449 // create the new int derived type object by calling the core type
450 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
450 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
451
451
452 Py_DECREF(baseClasses);
452 Py_DECREF(baseClasses);
453 Py_DECREF(typeDict);
453 Py_DECREF(typeDict);
454 Py_DECREF(args);
454 Py_DECREF(args);
455 Py_DECREF(className);
455 Py_DECREF(className);
456
456
457 return result;
457 return result;
458 }
458 }
459
459
460 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
460 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
461 {
461 {
462 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
462 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
463 if (!r) {
463 if (!r) {
464 r = new PythonQtSignalReceiver(obj);
464 r = new PythonQtSignalReceiver(obj);
465 _p->_signalReceivers.insert(obj, r);
465 _p->_signalReceivers.insert(obj, r);
466 }
466 }
467 return r;
467 return r;
468 }
468 }
469
469
470 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
470 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
471 {
471 {
472 bool flag = false;
472 bool flag = false;
473 PythonQtObjectPtr callable = lookupCallable(module, objectname);
473 PythonQtObjectPtr callable = lookupCallable(module, objectname);
474 if (callable) {
474 if (callable) {
475 PythonQtSignalReceiver* r = getSignalReceiver(obj);
475 PythonQtSignalReceiver* r = getSignalReceiver(obj);
476 flag = r->addSignalHandler(signal, callable);
476 flag = r->addSignalHandler(signal, callable);
477 if (!flag) {
477 if (!flag) {
478 // signal not found
478 // signal not found
479 }
479 }
480 } else {
480 } else {
481 // callable not found
481 // callable not found
482 }
482 }
483 return flag;
483 return flag;
484 }
484 }
485
485
486 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
486 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
487 {
487 {
488 bool flag = false;
488 bool flag = false;
489 PythonQtSignalReceiver* r = getSignalReceiver(obj);
489 PythonQtSignalReceiver* r = getSignalReceiver(obj);
490 if (r) {
490 if (r) {
491 flag = r->addSignalHandler(signal, receiver);
491 flag = r->addSignalHandler(signal, receiver);
492 }
492 }
493 return flag;
493 return flag;
494 }
494 }
495
495
496 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
496 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
497 {
497 {
498 bool flag = false;
498 bool flag = false;
499 PythonQtObjectPtr callable = lookupCallable(module, objectname);
499 PythonQtObjectPtr callable = lookupCallable(module, objectname);
500 if (callable) {
500 if (callable) {
501 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
501 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
502 if (r) {
502 if (r) {
503 flag = r->removeSignalHandler(signal, callable);
503 flag = r->removeSignalHandler(signal, callable);
504 }
504 }
505 } else {
505 } else {
506 // callable not found
506 // callable not found
507 }
507 }
508 return flag;
508 return flag;
509 }
509 }
510
510
511 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
511 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
512 {
512 {
513 bool flag = false;
513 bool flag = false;
514 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
514 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
515 if (r) {
515 if (r) {
516 flag = r->removeSignalHandler(signal, receiver);
516 flag = r->removeSignalHandler(signal, receiver);
517 }
517 }
518 return flag;
518 return flag;
519 }
519 }
520
520
521 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
521 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
522 {
522 {
523 PythonQtObjectPtr p = lookupObject(module, name);
523 PythonQtObjectPtr p = lookupObject(module, name);
524 if (p) {
524 if (p) {
525 if (PyCallable_Check(p)) {
525 if (PyCallable_Check(p)) {
526 return p;
526 return p;
527 }
527 }
528 }
528 }
529 PyErr_Clear();
529 PyErr_Clear();
530 return NULL;
530 return NULL;
531 }
531 }
532
532
533 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
533 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
534 {
534 {
535 QStringList l = name.split('.');
535 QStringList l = name.split('.');
536 PythonQtObjectPtr p = module;
536 PythonQtObjectPtr p = module;
537 PythonQtObjectPtr prev;
537 PythonQtObjectPtr prev;
538 QString s;
538 QString s;
539 QByteArray b;
539 QByteArray b;
540 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
540 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
541 prev = p;
541 prev = p;
542 b = (*i).toLatin1();
542 b = (*i).toLatin1();
543 if (PyDict_Check(p)) {
543 if (PyDict_Check(p)) {
544 p = PyDict_GetItemString(p, b.data());
544 p = PyDict_GetItemString(p, b.data());
545 } else {
545 } else {
546 p.setNewRef(PyObject_GetAttrString(p, b.data()));
546 p.setNewRef(PyObject_GetAttrString(p, b.data()));
547 }
547 }
548 }
548 }
549 PyErr_Clear();
549 PyErr_Clear();
550 return p;
550 return p;
551 }
551 }
552
552
553 PythonQtObjectPtr PythonQt::getMainModule() {
553 PythonQtObjectPtr PythonQt::getMainModule() {
554 //both borrowed
554 //both borrowed
555 PythonQtObjectPtr dict = PyImport_GetModuleDict();
555 PythonQtObjectPtr dict = PyImport_GetModuleDict();
556 return PyDict_GetItemString(dict, "__main__");
556 return PyDict_GetItemString(dict, "__main__");
557 }
557 }
558
558
559 PythonQtObjectPtr PythonQt::importModule(const QString& name)
559 PythonQtObjectPtr PythonQt::importModule(const QString& name)
560 {
560 {
561 PythonQtObjectPtr mod;
561 PythonQtObjectPtr mod;
562 mod.setNewRef(PyImport_ImportModule(name.toLatin1().constData()));
562 mod.setNewRef(PyImport_ImportModule(name.toLatin1().constData()));
563 return mod;
563 return mod;
564 }
564 }
565
565
566
566
567 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
567 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
568 QVariant result;
568 QVariant result;
569 if (pycode) {
569 if (pycode) {
570 PyObject* dict = NULL;
570 PyObject* dict = NULL;
571 if (PyModule_Check(object)) {
571 if (PyModule_Check(object)) {
572 dict = PyModule_GetDict(object);
572 dict = PyModule_GetDict(object);
573 } else if (PyDict_Check(object)) {
573 } else if (PyDict_Check(object)) {
574 dict = object;
574 dict = object;
575 }
575 }
576 PyObject* r = NULL;
576 PyObject* r = NULL;
577 if (dict) {
577 if (dict) {
578 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
578 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
579 }
579 }
580 if (r) {
580 if (r) {
581 result = PythonQtConv::PyObjToQVariant(r);
581 result = PythonQtConv::PyObjToQVariant(r);
582 Py_DECREF(r);
582 Py_DECREF(r);
583 } else {
583 } else {
584 handleError();
584 handleError();
585 }
585 }
586 } else {
586 } else {
587 handleError();
587 handleError();
588 }
588 }
589 return result;
589 return result;
590 }
590 }
591
591
592 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
592 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
593 {
593 {
594 QVariant result;
594 QVariant result;
595 PythonQtObjectPtr p;
595 PythonQtObjectPtr p;
596 PyObject* dict = NULL;
596 PyObject* dict = NULL;
597 if (PyModule_Check(object)) {
597 if (PyModule_Check(object)) {
598 dict = PyModule_GetDict(object);
598 dict = PyModule_GetDict(object);
599 } else if (PyDict_Check(object)) {
599 } else if (PyDict_Check(object)) {
600 dict = object;
600 dict = object;
601 }
601 }
602 if (dict) {
602 if (dict) {
603 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
603 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
604 }
604 }
605 if (p) {
605 if (p) {
606 result = PythonQtConv::PyObjToQVariant(p);
606 result = PythonQtConv::PyObjToQVariant(p);
607 } else {
607 } else {
608 handleError();
608 handleError();
609 }
609 }
610 return result;
610 return result;
611 }
611 }
612
612
613 void PythonQt::evalFile(PyObject* module, const QString& filename)
613 void PythonQt::evalFile(PyObject* module, const QString& filename)
614 {
614 {
615 PythonQtObjectPtr code = parseFile(filename);
615 PythonQtObjectPtr code = parseFile(filename);
616 if (code) {
616 if (code) {
617 evalCode(module, code);
617 evalCode(module, code);
618 } else {
618 } else {
619 handleError();
619 handleError();
620 }
620 }
621 }
621 }
622
622
623 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
623 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
624 {
624 {
625 PythonQtObjectPtr p;
625 PythonQtObjectPtr p;
626 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
626 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
627 if (!p) {
627 if (!p) {
628 handleError();
628 handleError();
629 }
629 }
630 return p;
630 return p;
631 }
631 }
632
632
633 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
633 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
634 {
634 {
635 PythonQtObjectPtr code = parseFile(filename);
635 PythonQtObjectPtr code = parseFile(filename);
636 PythonQtObjectPtr module = _p->createModule(name, code);
636 PythonQtObjectPtr module = _p->createModule(name, code);
637 return module;
637 return module;
638 }
638 }
639
639
640 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
640 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
641 {
641 {
642 PyErr_Clear();
642 PyErr_Clear();
643 QString scriptCode = script;
643 QString scriptCode = script;
644 if (scriptCode.isEmpty()) {
644 if (scriptCode.isEmpty()) {
645 // we always need at least a linefeed
645 // we always need at least a linefeed
646 scriptCode = "\n";
646 scriptCode = "\n";
647 }
647 }
648 PythonQtObjectPtr pycode;
648 PythonQtObjectPtr pycode;
649 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
649 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
650 PythonQtObjectPtr module = _p->createModule(name, pycode);
650 PythonQtObjectPtr module = _p->createModule(name, pycode);
651 return module;
651 return module;
652 }
652 }
653
653
654 PythonQtObjectPtr PythonQt::createUniqueModule()
654 PythonQtObjectPtr PythonQt::createUniqueModule()
655 {
655 {
656 static QString pyQtStr("PythonQt_module");
656 static QString pyQtStr("PythonQt_module");
657 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
657 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
658 return createModuleFromScript(moduleName);
658 return createModuleFromScript(moduleName);
659 }
659 }
660
660
661 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
661 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
662 {
662 {
663 if (PyModule_Check(object)) {
663 if (PyModule_Check(object)) {
664 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
664 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
665 } else if (PyDict_Check(object)) {
665 } else if (PyDict_Check(object)) {
666 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
666 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
667 } else {
667 } else {
668 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
668 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
669 }
669 }
670 }
670 }
671
671
672 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
672 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
673 {
673 {
674 if (PyModule_Check(object)) {
674 if (PyModule_Check(object)) {
675 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
675 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
676 } else if (PyDict_Check(object)) {
676 } else if (PyDict_Check(object)) {
677 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
677 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
678 } else {
678 } else {
679 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
679 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
680 }
680 }
681 }
681 }
682
682
683 void PythonQt::removeVariable(PyObject* object, const QString& name)
683 void PythonQt::removeVariable(PyObject* object, const QString& name)
684 {
684 {
685 if (PyDict_Check(object)) {
685 if (PyDict_Check(object)) {
686 PyDict_DelItemString(object, name.toLatin1().data());
686 PyDict_DelItemString(object, name.toLatin1().data());
687 } else {
687 } else {
688 PyObject_DelAttrString(object, name.toLatin1().data());
688 PyObject_DelAttrString(object, name.toLatin1().data());
689 }
689 }
690 }
690 }
691
691
692 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
692 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
693 {
693 {
694 QVariant result;
694 QVariant result;
695 PythonQtObjectPtr obj = lookupObject(object, objectname);
695 PythonQtObjectPtr obj = lookupObject(object, objectname);
696 if (obj) {
696 if (obj) {
697 result = PythonQtConv::PyObjToQVariant(obj);
697 result = PythonQtConv::PyObjToQVariant(obj);
698 }
698 }
699 return result;
699 return result;
700 }
700 }
701
701
702 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
702 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
703 {
703 {
704 QStringList results;
704 QStringList results;
705
705
706 PythonQtObjectPtr object;
706 PythonQtObjectPtr object;
707 if (objectname.isEmpty()) {
707 if (objectname.isEmpty()) {
708 object = module;
708 object = module;
709 } else {
709 } else {
710 object = lookupObject(module, objectname);
710 object = lookupObject(module, objectname);
711 if (!object && type == CallOverloads) {
711 if (!object && type == CallOverloads) {
712 PyObject* dict = lookupObject(module, "__builtins__");
712 PyObject* dict = lookupObject(module, "__builtins__");
713 if (dict) {
713 if (dict) {
714 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
714 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
715 }
715 }
716 }
716 }
717 }
717 }
718
718
719 if (object) {
719 if (object) {
720 if (type == CallOverloads) {
720 if (type == CallOverloads) {
721 if (PythonQtSlotFunction_Check(object)) {
721 if (PythonQtSlotFunction_Check(object)) {
722 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
722 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
723 PythonQtSlotInfo* info = o->m_ml;
723 PythonQtSlotInfo* info = o->m_ml;
724
724
725 while (info) {
725 while (info) {
726 results << info->fullSignature();
726 results << info->fullSignature();
727 info = info->nextInfo();
727 info = info->nextInfo();
728 }
728 }
729 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
729 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
730 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
730 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
731 PythonQtSlotInfo* info = o->classInfo()->constructors();
731 PythonQtSlotInfo* info = o->classInfo()->constructors();
732
732
733 while (info) {
733 while (info) {
734 results << info->fullSignature();
734 results << info->fullSignature();
735 info = info->nextInfo();
735 info = info->nextInfo();
736 }
736 }
737 } else {
737 } else {
738 //TODO: use pydoc!
738 //TODO: use pydoc!
739 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
739 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
740 if (doc) {
740 if (doc) {
741 results << PyString_AsString(doc);
741 results << PyString_AsString(doc);
742 Py_DECREF(doc);
742 Py_DECREF(doc);
743 }
743 }
744 }
744 }
745 } else {
745 } else {
746 PyObject* keys = NULL;
746 PyObject* keys = NULL;
747 bool isDict = false;
747 bool isDict = false;
748 if (PyDict_Check(object)) {
748 if (PyDict_Check(object)) {
749 keys = PyDict_Keys(object);
749 keys = PyDict_Keys(object);
750 isDict = true;
750 isDict = true;
751 } else {
751 } else {
752 keys = PyObject_Dir(object);
752 keys = PyObject_Dir(object);
753 }
753 }
754 if (keys) {
754 if (keys) {
755 int count = PyList_Size(keys);
755 int count = PyList_Size(keys);
756 PyObject* key;
756 PyObject* key;
757 PyObject* value;
757 PyObject* value;
758 QString keystr;
758 QString keystr;
759 for (int i = 0;i<count;i++) {
759 for (int i = 0;i<count;i++) {
760 key = PyList_GetItem(keys,i);
760 key = PyList_GetItem(keys,i);
761 if (isDict) {
761 if (isDict) {
762 value = PyDict_GetItem(object, key);
762 value = PyDict_GetItem(object, key);
763 Py_INCREF(value);
763 Py_INCREF(value);
764 } else {
764 } else {
765 value = PyObject_GetAttr(object, key);
765 value = PyObject_GetAttr(object, key);
766 }
766 }
767 if (!value) continue;
767 if (!value) continue;
768 keystr = PyString_AsString(key);
768 keystr = PyString_AsString(key);
769 static const QString underscoreStr("__tmp");
769 static const QString underscoreStr("__tmp");
770 if (!keystr.startsWith(underscoreStr)) {
770 if (!keystr.startsWith(underscoreStr)) {
771 switch (type) {
771 switch (type) {
772 case Anything:
772 case Anything:
773 results << keystr;
773 results << keystr;
774 break;
774 break;
775 case Class:
775 case Class:
776 if (value->ob_type == &PyClass_Type) {
776 if (value->ob_type == &PyClass_Type) {
777 results << keystr;
777 results << keystr;
778 }
778 }
779 break;
779 break;
780 case Variable:
780 case Variable:
781 if (value->ob_type != &PyClass_Type
781 if (value->ob_type != &PyClass_Type
782 && value->ob_type != &PyCFunction_Type
782 && value->ob_type != &PyCFunction_Type
783 && value->ob_type != &PyFunction_Type
783 && value->ob_type != &PyFunction_Type
784 && value->ob_type != &PyModule_Type
784 && value->ob_type != &PyModule_Type
785 ) {
785 ) {
786 results << keystr;
786 results << keystr;
787 }
787 }
788 break;
788 break;
789 case Function:
789 case Function:
790 if (value->ob_type == &PyFunction_Type ||
790 if (value->ob_type == &PyFunction_Type ||
791 value->ob_type == &PyMethod_Type
791 value->ob_type == &PyMethod_Type
792 ) {
792 ) {
793 results << keystr;
793 results << keystr;
794 }
794 }
795 break;
795 break;
796 case Module:
796 case Module:
797 if (value->ob_type == &PyModule_Type) {
797 if (value->ob_type == &PyModule_Type) {
798 results << keystr;
798 results << keystr;
799 }
799 }
800 break;
800 break;
801 default:
801 default:
802 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
802 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
803 }
803 }
804 }
804 }
805 Py_DECREF(value);
805 Py_DECREF(value);
806 }
806 }
807 Py_DECREF(keys);
807 Py_DECREF(keys);
808 }
808 }
809 }
809 }
810 }
810 }
811 return results;
811 return results;
812 }
812 }
813
813
814 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
814 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
815 {
815 {
816 PythonQtObjectPtr callable = lookupCallable(object, name);
816 PythonQtObjectPtr callable = lookupCallable(object, name);
817 if (callable) {
817 if (callable) {
818 return call(callable, args);
818 return call(callable, args);
819 } else {
819 } else {
820 return QVariant();
820 return QVariant();
821 }
821 }
822 }
822 }
823
823
824 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
824 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
825 {
825 {
826 QVariant r;
826 QVariant r;
827 PythonQtObjectPtr result;
827 PythonQtObjectPtr result;
828 result.setNewRef(callAndReturnPyObject(callable, args));
828 result.setNewRef(callAndReturnPyObject(callable, args));
829 if (result) {
829 if (result) {
830 r = PythonQtConv::PyObjToQVariant(result);
830 r = PythonQtConv::PyObjToQVariant(result);
831 } else {
831 } else {
832 PythonQt::self()->handleError();
832 PythonQt::self()->handleError();
833 }
833 }
834 return r;
834 return r;
835 }
835 }
836
836
837 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args)
837 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args)
838 {
838 {
839 PyObject* result = NULL;
839 PyObject* result = NULL;
840 if (callable) {
840 if (callable) {
841 PythonQtObjectPtr pargs;
841 PythonQtObjectPtr pargs;
842 int count = args.size();
842 int count = args.size();
843 if (count>0) {
843 if (count>0) {
844 pargs.setNewRef(PyTuple_New(count));
844 pargs.setNewRef(PyTuple_New(count));
845 }
845 }
846 bool err = false;
846 bool err = false;
847 // transform QVariants to Python
847 // transform QVariants to Python
848 for (int i = 0; i < count; i++) {
848 for (int i = 0; i < count; i++) {
849 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
849 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
850 if (arg) {
850 if (arg) {
851 // steals reference, no unref
851 // steals reference, no unref
852 PyTuple_SetItem(pargs, i,arg);
852 PyTuple_SetItem(pargs, i,arg);
853 } else {
853 } else {
854 err = true;
854 err = true;
855 break;
855 break;
856 }
856 }
857 }
857 }
858
858
859 if (!err) {
859 if (!err) {
860 PyErr_Clear();
860 PyErr_Clear();
861 result = PyObject_CallObject(callable, pargs);
861 result = PyObject_CallObject(callable, pargs);
862 }
862 }
863 }
863 }
864 return result;
864 return result;
865 }
865 }
866
866
867 void PythonQt::addInstanceDecorators(QObject* o)
867 void PythonQt::addInstanceDecorators(QObject* o)
868 {
868 {
869 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
869 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
870 }
870 }
871
871
872 void PythonQt::addClassDecorators(QObject* o)
872 void PythonQt::addClassDecorators(QObject* o)
873 {
873 {
874 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
874 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
875 }
875 }
876
876
877 void PythonQt::addDecorators(QObject* o)
877 void PythonQt::addDecorators(QObject* o)
878 {
878 {
879 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
879 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
880 }
880 }
881
881
882 void PythonQt::registerQObjectClassNames(const QStringList& names)
882 void PythonQt::registerQObjectClassNames(const QStringList& names)
883 {
883 {
884 _p->registerQObjectClassNames(names);
884 _p->registerQObjectClassNames(names);
885 }
885 }
886
886
887 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
887 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
888 {
888 {
889 _p->_importInterface = importInterface;
889 _p->_importInterface = importInterface;
890 PythonQtImport::init();
890 PythonQtImport::init();
891 }
891 }
892
892
893 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
893 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
894 {
894 {
895 _p->_importIgnorePaths = paths;
895 _p->_importIgnorePaths = paths;
896 }
896 }
897
897
898 const QStringList& PythonQt::getImporterIgnorePaths()
898 const QStringList& PythonQt::getImporterIgnorePaths()
899 {
899 {
900 return _p->_importIgnorePaths;
900 return _p->_importIgnorePaths;
901 }
901 }
902
902
903 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
903 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
904 {
904 {
905 _p->_cppWrapperFactories.append(factory);
905 _p->_cppWrapperFactories.append(factory);
906 }
906 }
907
907
908 //---------------------------------------------------------------------------------------------------
908 //---------------------------------------------------------------------------------------------------
909 PythonQtPrivate::PythonQtPrivate()
909 PythonQtPrivate::PythonQtPrivate()
910 {
910 {
911 _importInterface = NULL;
911 _importInterface = NULL;
912 _defaultImporter = new PythonQtQFileImporter;
912 _defaultImporter = new PythonQtQFileImporter;
913 _noLongerWrappedCB = NULL;
913 _noLongerWrappedCB = NULL;
914 _wrappedCB = NULL;
914 _wrappedCB = NULL;
915 _currentClassInfoForClassWrapperCreation = NULL;
915 _currentClassInfoForClassWrapperCreation = NULL;
916 }
916 }
917
917
918 void PythonQtPrivate::setupSharedLibrarySuffixes()
918 void PythonQtPrivate::setupSharedLibrarySuffixes()
919 {
919 {
920 _sharedLibrarySuffixes.clear();
920 _sharedLibrarySuffixes.clear();
921 PythonQtObjectPtr imp;
921 PythonQtObjectPtr imp;
922 imp.setNewRef(PyImport_ImportModule("imp"));
922 imp.setNewRef(PyImport_ImportModule("imp"));
923 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
923 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
924 QVariant result = imp.call("get_suffixes");
924 QVariant result = imp.call("get_suffixes");
925 foreach (QVariant entry, result.toList()) {
925 foreach (QVariant entry, result.toList()) {
926 QVariantList suffixEntry = entry.toList();
926 QVariantList suffixEntry = entry.toList();
927 if (suffixEntry.count()==3) {
927 if (suffixEntry.count()==3) {
928 int code = suffixEntry.at(2).toInt();
928 int code = suffixEntry.at(2).toInt();
929 if (code == cExtensionCode) {
929 if (code == cExtensionCode) {
930 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
930 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
931 }
931 }
932 }
932 }
933 }
933 }
934 }
934 }
935
935
936 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
936 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
937 {
937 {
938 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
938 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
939 _currentClassInfoForClassWrapperCreation = NULL;
939 _currentClassInfoForClassWrapperCreation = NULL;
940 return info;
940 return info;
941 }
941 }
942
942
943 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
943 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
944 {
944 {
945 o->setParent(this);
945 o->setParent(this);
946 int numMethods = o->metaObject()->methodCount();
946 int numMethods = o->metaObject()->methodCount();
947 for (int i = 0; i < numMethods; i++) {
947 for (int i = 0; i < numMethods; i++) {
948 QMetaMethod m = o->metaObject()->method(i);
948 QMetaMethod m = o->metaObject()->method(i);
949 if ((m.methodType() == QMetaMethod::Method ||
949 if ((m.methodType() == QMetaMethod::Method ||
950 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
950 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
951 if (qstrncmp(m.signature(), "new_", 4)==0) {
951 if (qstrncmp(m.signature(), "new_", 4)==0) {
952 if ((decoTypes & ConstructorDecorator) == 0) continue;
952 if ((decoTypes & ConstructorDecorator) == 0) continue;
953 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
953 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
954 if (info->parameters().at(0).pointerCount == 1) {
954 if (info->parameters().at(0).pointerCount == 1) {
955 QByteArray signature = m.signature();
955 QByteArray signature = m.signature();
956 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
956 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
957 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
957 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
958 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
958 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
959 classInfo->addConstructor(newSlot);
959 classInfo->addConstructor(newSlot);
960 }
960 }
961 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
961 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
962 if ((decoTypes & DestructorDecorator) == 0) continue;
962 if ((decoTypes & DestructorDecorator) == 0) continue;
963 QByteArray signature = m.signature();
963 QByteArray signature = m.signature();
964 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
964 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
965 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
965 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
966 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
966 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
967 classInfo->setDestructor(newSlot);
967 classInfo->setDestructor(newSlot);
968 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
968 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
969 if ((decoTypes & StaticDecorator) == 0) continue;
969 if ((decoTypes & StaticDecorator) == 0) continue;
970 QByteArray signature = m.signature();
970 QByteArray signature = m.signature();
971 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
971 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
972 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
972 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
973 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
973 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
974 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
974 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
975 classInfo->addDecoratorSlot(newSlot);
975 classInfo->addDecoratorSlot(newSlot);
976 } else {
976 } else {
977 if ((decoTypes & InstanceDecorator) == 0) continue;
977 if ((decoTypes & InstanceDecorator) == 0) continue;
978 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
978 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
979 if (info->parameters().count()>1) {
979 if (info->parameters().count()>1) {
980 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
980 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
981 if (p.pointerCount==1) {
981 if (p.pointerCount==1) {
982 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
982 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
983 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
983 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
984 classInfo->addDecoratorSlot(newSlot);
984 classInfo->addDecoratorSlot(newSlot);
985 }
985 }
986 }
986 }
987 }
987 }
988 }
988 }
989 }
989 }
990 }
990 }
991
991
992 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
992 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
993 {
993 {
994 foreach(QString name, names) {
994 foreach(QString name, names) {
995 _knownQObjectClassNames.insert(name.toLatin1(), true);
995 _knownQObjectClassNames.insert(name.toLatin1(), true);
996 }
996 }
997 }
997 }
998
998
999 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
999 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
1000 {
1000 {
1001 _signalReceivers.remove(obj);
1001 _signalReceivers.remove(obj);
1002 }
1002 }
1003
1003
1004 bool PythonQt::handleError()
1004 bool PythonQt::handleError()
1005 {
1005 {
1006 bool flag = false;
1006 bool flag = false;
1007 if (PyErr_Occurred()) {
1007 if (PyErr_Occurred()) {
1008
1008
1009 // currently we just print the error and the stderr handler parses the errors
1009 // currently we just print the error and the stderr handler parses the errors
1010 PyErr_Print();
1010 PyErr_Print();
1011
1011
1012 /*
1012 /*
1013 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1013 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1014 PyObject *ptype;
1014 PyObject *ptype;
1015 PyObject *pvalue;
1015 PyObject *pvalue;
1016 PyObject *ptraceback;
1016 PyObject *ptraceback;
1017 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1017 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1018
1018
1019 Py_XDECREF(ptype);
1019 Py_XDECREF(ptype);
1020 Py_XDECREF(pvalue);
1020 Py_XDECREF(pvalue);
1021 Py_XDECREF(ptraceback);
1021 Py_XDECREF(ptraceback);
1022 */
1022 */
1023 PyErr_Clear();
1023 PyErr_Clear();
1024 flag = true;
1024 flag = true;
1025 }
1025 }
1026 return flag;
1026 return flag;
1027 }
1027 }
1028
1028
1029 void PythonQt::addSysPath(const QString& path)
1029 void PythonQt::addSysPath(const QString& path)
1030 {
1030 {
1031 PythonQtObjectPtr sys;
1031 PythonQtObjectPtr sys;
1032 sys.setNewRef(PyImport_ImportModule("sys"));
1032 sys.setNewRef(PyImport_ImportModule("sys"));
1033 PythonQtObjectPtr obj = lookupObject(sys, "path");
1033 PythonQtObjectPtr obj = lookupObject(sys, "path");
1034 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1034 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1035 }
1035 }
1036
1036
1037 void PythonQt::overwriteSysPath(const QStringList& paths)
1037 void PythonQt::overwriteSysPath(const QStringList& paths)
1038 {
1038 {
1039 PythonQtObjectPtr sys;
1039 PythonQtObjectPtr sys;
1040 sys.setNewRef(PyImport_ImportModule("sys"));
1040 sys.setNewRef(PyImport_ImportModule("sys"));
1041 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1041 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1042 }
1042 }
1043
1043
1044 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1044 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1045 {
1045 {
1046 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1046 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1047 }
1047 }
1048
1048
1049 void PythonQt::stdOutRedirectCB(const QString& str)
1049 void PythonQt::stdOutRedirectCB(const QString& str)
1050 {
1050 {
1051 emit PythonQt::self()->pythonStdOut(str);
1051 emit PythonQt::self()->pythonStdOut(str);
1052 }
1052 }
1053
1053
1054 void PythonQt::stdErrRedirectCB(const QString& str)
1054 void PythonQt::stdErrRedirectCB(const QString& str)
1055 {
1055 {
1056 emit PythonQt::self()->pythonStdErr(str);
1056 emit PythonQt::self()->pythonStdErr(str);
1057 }
1057 }
1058
1058
1059 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1059 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1060 {
1060 {
1061 _p->_wrappedCB = cb;
1061 _p->_wrappedCB = cb;
1062 }
1062 }
1063
1063
1064 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1064 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1065 {
1065 {
1066 _p->_noLongerWrappedCB = cb;
1066 _p->_noLongerWrappedCB = cb;
1067 }
1067 }
1068
1068
1069
1069
1070
1070
1071 static PyMethodDef PythonQtMethods[] = {
1071 static PyMethodDef PythonQtMethods[] = {
1072 {NULL, NULL, 0, NULL}
1072 {NULL, NULL, 0, NULL}
1073 };
1073 };
1074
1074
1075 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1075 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1076 {
1076 {
1077 QByteArray name = "PythonQt";
1077 QByteArray name = "PythonQt";
1078 if (!pythonQtModuleName.isEmpty()) {
1078 if (!pythonQtModuleName.isEmpty()) {
1079 name = pythonQtModuleName;
1079 name = pythonQtModuleName;
1080 }
1080 }
1081 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1081 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1082 _p->_pythonQtModuleName = name;
1082 _p->_pythonQtModuleName = name;
1083
1083
1084 if (redirectStdOut) {
1084 if (redirectStdOut) {
1085 PythonQtObjectPtr sys;
1085 PythonQtObjectPtr sys;
1086 PythonQtObjectPtr out;
1086 PythonQtObjectPtr out;
1087 PythonQtObjectPtr err;
1087 PythonQtObjectPtr err;
1088 sys.setNewRef(PyImport_ImportModule("sys"));
1088 sys.setNewRef(PyImport_ImportModule("sys"));
1089 // create a redirection object for stdout and stderr
1089 // create a redirection object for stdout and stderr
1090 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1090 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1091 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1091 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1092 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1092 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1093 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1093 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1094 // replace the built in file objects with our own objects
1094 // replace the built in file objects with our own objects
1095 PyModule_AddObject(sys, "stdout", out);
1095 PyModule_AddObject(sys, "stdout", out);
1096 PyModule_AddObject(sys, "stderr", err);
1096 PyModule_AddObject(sys, "stderr", err);
1097 }
1097 }
1098 }
1098 }
1099
1099
1100 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1100 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1101 {
1101 {
1102 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1102 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1103 }
1103 }
1104
1104
1105
1105
1106 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1106 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1107 {
1107 {
1108 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1108 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1109 if (!info) {
1109 if (!info) {
1110 info = new PythonQtClassInfo();
1110 info = new PythonQtClassInfo();
1111 info->setupCPPObject(typeName);
1111 info->setupCPPObject(typeName);
1112 _knownClassInfos.insert(typeName, info);
1112 _knownClassInfos.insert(typeName, info);
1113 }
1113 }
1114 return info;
1114 return info;
1115 }
1115 }
1116
1116
1117 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1117 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1118 {
1118 {
1119 _p->addPolymorphicHandler(typeName, cb);
1119 _p->addPolymorphicHandler(typeName, cb);
1120 }
1120 }
1121
1121
1122 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1122 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1123 {
1123 {
1124 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1124 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1125 info->addPolymorphicHandler(cb);
1125 info->addPolymorphicHandler(cb);
1126 }
1126 }
1127
1127
1128 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1128 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1129 {
1129 {
1130 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1130 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1131 }
1131 }
1132
1132
1133 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1133 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1134 {
1134 {
1135 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1135 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1136 if (info) {
1136 if (info) {
1137 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1137 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1138 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1138 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1139 return true;
1139 return true;
1140 } else {
1140 } else {
1141 return false;
1141 return false;
1142 }
1142 }
1143 }
1143 }
1144
1144
1145 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1145 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1146 {
1146 {
1147 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1147 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1148 if (!info->pythonQtClassWrapper()) {
1148 if (!info->pythonQtClassWrapper()) {
1149 info->setTypeSlots(typeSlots);
1149 info->setTypeSlots(typeSlots);
1150 info->setupCPPObject(typeName);
1150 info->setupCPPObject(typeName);
1151 createPythonQtClassWrapper(info, package, module);
1151 createPythonQtClassWrapper(info, package, module);
1152 }
1152 }
1153 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1153 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1154 addParentClass(typeName, parentTypeName, 0);
1154 addParentClass(typeName, parentTypeName, 0);
1155 }
1155 }
1156 if (wrapperCreator) {
1156 if (wrapperCreator) {
1157 info->setDecoratorProvider(wrapperCreator);
1157 info->setDecoratorProvider(wrapperCreator);
1158 }
1158 }
1159 if (shell) {
1159 if (shell) {
1160 info->setShellSetInstanceWrapperCB(shell);
1160 info->setShellSetInstanceWrapperCB(shell);
1161 }
1161 }
1162 }
1162 }
1163
1163
1164 PyObject* PythonQtPrivate::packageByName(const char* name)
1164 PyObject* PythonQtPrivate::packageByName(const char* name)
1165 {
1165 {
1166 if (name==NULL || name[0]==0) {
1166 if (name==NULL || name[0]==0) {
1167 name = "private";
1167 name = "private";
1168 }
1168 }
1169 PyObject* v = _packages.value(name);
1169 PyObject* v = _packages.value(name);
1170 if (!v) {
1170 if (!v) {
1171 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1171 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1172 _packages.insert(name, v);
1172 _packages.insert(name, v);
1173 // AddObject steals the reference, so increment it!
1173 // AddObject steals the reference, so increment it!
1174 Py_INCREF(v);
1174 Py_INCREF(v);
1175 PyModule_AddObject(_pythonQtModule, name, v);
1175 PyModule_AddObject(_pythonQtModule, name, v);
1176 }
1176 }
1177 return v;
1177 return v;
1178 }
1178 }
1179
1179
1180 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1180 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1181 {
1181 {
1182 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;
1182 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;
1183 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1183 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1184 PythonQt::self()->handleError();
1184 PythonQt::self()->handleError();
1185 }
1185 }
1186
1186
1187 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1187 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1188 {
1188 {
1189 if (_p->_initFlags & ExternalHelp) {
1189 if (_p->_initFlags & ExternalHelp) {
1190 emit pythonHelpRequest(QByteArray(info->className()));
1190 emit pythonHelpRequest(QByteArray(info->className()));
1191 return Py_BuildValue("");
1191 return Py_BuildValue("");
1192 } else {
1192 } else {
1193 return PyString_FromString(info->help().toLatin1().data());
1193 return PyString_FromString(info->help().toLatin1().data());
1194 }
1194 }
1195 }
1195 }
1196
1196
1197 void PythonQtPrivate::removeWrapperPointer(void* obj)
1197 void PythonQtPrivate::removeWrapperPointer(void* obj)
1198 {
1198 {
1199 _wrappedObjects.remove(obj);
1199 _wrappedObjects.remove(obj);
1200 }
1200 }
1201
1201
1202 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1202 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1203 {
1203 {
1204 _wrappedObjects.insert(obj, wrapper);
1204 _wrappedObjects.insert(obj, wrapper);
1205 }
1205 }
1206
1206
1207 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1207 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1208 {
1208 {
1209 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1209 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1210 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1210 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1211 // this is a wrapper whose QObject was already removed due to destruction
1211 // this is a wrapper whose QObject was already removed due to destruction
1212 // so the obj pointer has to be a new QObject with the same address...
1212 // so the obj pointer has to be a new QObject with the same address...
1213 // we remove the old one and set the copy to NULL
1213 // we remove the old one and set the copy to NULL
1214 wrap->_objPointerCopy = NULL;
1214 wrap->_objPointerCopy = NULL;
1215 removeWrapperPointer(obj);
1215 removeWrapperPointer(obj);
1216 wrap = NULL;
1216 wrap = NULL;
1217 }
1217 }
1218 return wrap;
1218 return wrap;
1219 }
1219 }
1220
1220
1221 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1221 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1222 {
1222 {
1223 PythonQtObjectPtr result;
1223 PythonQtObjectPtr result;
1224 if (pycode) {
1224 if (pycode) {
1225 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1225 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1226 } else {
1226 } else {
1227 PythonQt::self()->handleError();
1227 PythonQt::self()->handleError();
1228 }
1228 }
1229 return result;
1229 return result;
1230 }
1230 }
General Comments 0
You need to be logged in to leave comments. Login now