##// END OF EJS Templates
removed implicit conversion of QByteArray to python str, use str() to convert to Python string or QByteArray::data()...
florianlink -
r125:50c6d9f6a6dd
parent child
Show More
@@ -1,1219 +1,1220
1 /*
1 /*
2 *
2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2006 MeVis Research GmbH 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 Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Research GmbH, 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(QDate);
85 PythonQtRegisterToolClassesTemplateConverter(QDate);
85 PythonQtRegisterToolClassesTemplateConverter(QTime);
86 PythonQtRegisterToolClassesTemplateConverter(QTime);
86 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
87 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
87 PythonQtRegisterToolClassesTemplateConverter(QUrl);
88 PythonQtRegisterToolClassesTemplateConverter(QUrl);
88 PythonQtRegisterToolClassesTemplateConverter(QLocale);
89 PythonQtRegisterToolClassesTemplateConverter(QLocale);
89 PythonQtRegisterToolClassesTemplateConverter(QRect);
90 PythonQtRegisterToolClassesTemplateConverter(QRect);
90 PythonQtRegisterToolClassesTemplateConverter(QRectF);
91 PythonQtRegisterToolClassesTemplateConverter(QRectF);
91 PythonQtRegisterToolClassesTemplateConverter(QSize);
92 PythonQtRegisterToolClassesTemplateConverter(QSize);
92 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
93 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
93 PythonQtRegisterToolClassesTemplateConverter(QLine);
94 PythonQtRegisterToolClassesTemplateConverter(QLine);
94 PythonQtRegisterToolClassesTemplateConverter(QLineF);
95 PythonQtRegisterToolClassesTemplateConverter(QLineF);
95 PythonQtRegisterToolClassesTemplateConverter(QPoint);
96 PythonQtRegisterToolClassesTemplateConverter(QPoint);
96 PythonQtRegisterToolClassesTemplateConverter(QPointF);
97 PythonQtRegisterToolClassesTemplateConverter(QPointF);
97 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
98 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
98
99
99 PythonQtRegisterToolClassesTemplateConverter(QFont);
100 PythonQtRegisterToolClassesTemplateConverter(QFont);
100 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
101 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
101 PythonQtRegisterToolClassesTemplateConverter(QBrush);
102 PythonQtRegisterToolClassesTemplateConverter(QBrush);
102 PythonQtRegisterToolClassesTemplateConverter(QColor);
103 PythonQtRegisterToolClassesTemplateConverter(QColor);
103 PythonQtRegisterToolClassesTemplateConverter(QPalette);
104 PythonQtRegisterToolClassesTemplateConverter(QPalette);
104 PythonQtRegisterToolClassesTemplateConverter(QIcon);
105 PythonQtRegisterToolClassesTemplateConverter(QIcon);
105 PythonQtRegisterToolClassesTemplateConverter(QImage);
106 PythonQtRegisterToolClassesTemplateConverter(QImage);
106 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
107 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
107 PythonQtRegisterToolClassesTemplateConverter(QRegion);
108 PythonQtRegisterToolClassesTemplateConverter(QRegion);
108 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
109 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
109 PythonQtRegisterToolClassesTemplateConverter(QCursor);
110 PythonQtRegisterToolClassesTemplateConverter(QCursor);
110 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
111 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
111 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
112 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
112 PythonQtRegisterToolClassesTemplateConverter(QPen);
113 PythonQtRegisterToolClassesTemplateConverter(QPen);
113 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
114 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
114 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
115 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
115 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
116 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
116
117
117
118
118 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
119 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
119 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
120 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
120 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
121 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
121 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"
122 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
123 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
123 for (unsigned int i = 0;i<16; i++) {
124 for (unsigned int i = 0;i<16; i++) {
124 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
125 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
125 if (obj) {
126 if (obj) {
126 PyModule_AddObject(pack, names[i], obj);
127 PyModule_AddObject(pack, names[i], obj);
127 Py_INCREF(obj);
128 Py_INCREF(obj);
128 PyModule_AddObject(pack2, names[i], obj);
129 PyModule_AddObject(pack2, names[i], obj);
129 } else {
130 } else {
130 std::cerr << "method not found " << names[i];
131 std::cerr << "method not found " << names[i];
131 }
132 }
132 }
133 }
133 }
134 }
134 }
135 }
135
136
136 void PythonQt::cleanup()
137 void PythonQt::cleanup()
137 {
138 {
138 if (_self) {
139 if (_self) {
139 delete _self;
140 delete _self;
140 _self = NULL;
141 _self = NULL;
141 }
142 }
142 }
143 }
143
144
144 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
145 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
145 {
146 {
146 _p = new PythonQtPrivate;
147 _p = new PythonQtPrivate;
147 _p->_initFlags = flags;
148 _p->_initFlags = flags;
148
149
149 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
150 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
150
151
151 Py_SetProgramName("PythonQt");
152 Py_SetProgramName("PythonQt");
152 if (flags & IgnoreSiteModule) {
153 if (flags & IgnoreSiteModule) {
153 // this prevents the automatic importing of Python site files
154 // this prevents the automatic importing of Python site files
154 Py_NoSiteFlag = 1;
155 Py_NoSiteFlag = 1;
155 }
156 }
156 Py_Initialize();
157 Py_Initialize();
157
158
158 // add our own python object types for qt object slots
159 // add our own python object types for qt object slots
159 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
160 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
160 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
161 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
161 }
162 }
162 Py_INCREF(&PythonQtSlotFunction_Type);
163 Py_INCREF(&PythonQtSlotFunction_Type);
163
164
164 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
165 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
165 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
166 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
166 // add our own python object types for classes
167 // add our own python object types for classes
167 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
168 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
168 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
169 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
169 }
170 }
170 Py_INCREF(&PythonQtClassWrapper_Type);
171 Py_INCREF(&PythonQtClassWrapper_Type);
171
172
172 // add our own python object types for CPP instances
173 // add our own python object types for CPP instances
173 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
174 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
174 PythonQt::handleError();
175 PythonQt::handleError();
175 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
176 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
176 }
177 }
177 Py_INCREF(&PythonQtInstanceWrapper_Type);
178 Py_INCREF(&PythonQtInstanceWrapper_Type);
178
179
179 // add our own python object types for redirection of stdout
180 // add our own python object types for redirection of stdout
180 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
181 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
181 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
182 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
182 }
183 }
183 Py_INCREF(&PythonQtStdOutRedirectType);
184 Py_INCREF(&PythonQtStdOutRedirectType);
184
185
185 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
186 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
186
187
187 _p->setupSharedLibrarySuffixes();
188 _p->setupSharedLibrarySuffixes();
188
189
189 }
190 }
190
191
191 PythonQt::~PythonQt() {
192 PythonQt::~PythonQt() {
192 delete _p;
193 delete _p;
193 _p = NULL;
194 _p = NULL;
194 }
195 }
195
196
196 PythonQtPrivate::~PythonQtPrivate() {
197 PythonQtPrivate::~PythonQtPrivate() {
197 delete _defaultImporter;
198 delete _defaultImporter;
198 _defaultImporter = NULL;
199 _defaultImporter = NULL;
199
200
200 {
201 {
201 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
202 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
202 while (i.hasNext()) {
203 while (i.hasNext()) {
203 delete i.next().value();
204 delete i.next().value();
204 }
205 }
205 }
206 }
206 PythonQtConv::global_valueStorage.clear();
207 PythonQtConv::global_valueStorage.clear();
207 PythonQtConv::global_ptrStorage.clear();
208 PythonQtConv::global_ptrStorage.clear();
208 PythonQtConv::global_variantStorage.clear();
209 PythonQtConv::global_variantStorage.clear();
209
210
210 PythonQtMethodInfo::cleanupCachedMethodInfos();
211 PythonQtMethodInfo::cleanupCachedMethodInfos();
211 }
212 }
212
213
213 PythonQtImportFileInterface* PythonQt::importInterface()
214 PythonQtImportFileInterface* PythonQt::importInterface()
214 {
215 {
215 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
216 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
216 }
217 }
217
218
218 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
219 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
219 {
220 {
220 if (_self->_p->_noLongerWrappedCB) {
221 if (_self->_p->_noLongerWrappedCB) {
221 (*_self->_p->_noLongerWrappedCB)(o);
222 (*_self->_p->_noLongerWrappedCB)(o);
222 };
223 };
223 }
224 }
224
225
225 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
226 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
226 {
227 {
227 _p->registerClass(metaobject, package, wrapperCreator, shell);
228 _p->registerClass(metaobject, package, wrapperCreator, shell);
228 }
229 }
229
230
230 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
231 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
231 {
232 {
232 // we register all classes in the hierarchy
233 // we register all classes in the hierarchy
233 const QMetaObject* m = metaobject;
234 const QMetaObject* m = metaobject;
234 bool first = true;
235 bool first = true;
235 while (m) {
236 while (m) {
236 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
237 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
237 if (!info->pythonQtClassWrapper()) {
238 if (!info->pythonQtClassWrapper()) {
238 info->setTypeSlots(typeSlots);
239 info->setTypeSlots(typeSlots);
239 info->setupQObject(m);
240 info->setupQObject(m);
240 createPythonQtClassWrapper(info, package, module);
241 createPythonQtClassWrapper(info, package, module);
241 if (m->superClass()) {
242 if (m->superClass()) {
242 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
243 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
243 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
244 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
244 }
245 }
245 }
246 }
246 if (first) {
247 if (first) {
247 first = false;
248 first = false;
248 if (wrapperCreator) {
249 if (wrapperCreator) {
249 info->setDecoratorProvider(wrapperCreator);
250 info->setDecoratorProvider(wrapperCreator);
250 }
251 }
251 if (shell) {
252 if (shell) {
252 info->setShellSetInstanceWrapperCB(shell);
253 info->setShellSetInstanceWrapperCB(shell);
253 }
254 }
254 }
255 }
255 m = m->superClass();
256 m = m->superClass();
256 }
257 }
257 }
258 }
258
259
259 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
260 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
260 {
261 {
261 PyObject* pack = module?module:packageByName(package);
262 PyObject* pack = module?module:packageByName(package);
262 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
263 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
263 PyModule_AddObject(pack, info->className(), pyobj);
264 PyModule_AddObject(pack, info->className(), pyobj);
264 if (!module && package && strncmp(package,"Qt",2)==0) {
265 if (!module && package && strncmp(package,"Qt",2)==0) {
265 // since PyModule_AddObject steals the reference, we need a incref once more...
266 // since PyModule_AddObject steals the reference, we need a incref once more...
266 Py_INCREF(pyobj);
267 Py_INCREF(pyobj);
267 // put all qt objects into Qt as well
268 // put all qt objects into Qt as well
268 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
269 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
269 }
270 }
270 info->setPythonQtClassWrapper(pyobj);
271 info->setPythonQtClassWrapper(pyobj);
271 }
272 }
272
273
273 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
274 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
274 {
275 {
275 if (!obj) {
276 if (!obj) {
276 Py_INCREF(Py_None);
277 Py_INCREF(Py_None);
277 return Py_None;
278 return Py_None;
278 }
279 }
279 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
280 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
280 if (!wrap) {
281 if (!wrap) {
281 // smuggling it in...
282 // smuggling it in...
282 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
283 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
283 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
284 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
284 registerClass(obj->metaObject());
285 registerClass(obj->metaObject());
285 classInfo = _knownClassInfos.value(obj->metaObject()->className());
286 classInfo = _knownClassInfos.value(obj->metaObject()->className());
286 }
287 }
287 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
288 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
288 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
289 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
289 } else {
290 } else {
290 Py_INCREF(wrap);
291 Py_INCREF(wrap);
291 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
292 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
292 }
293 }
293 return (PyObject*)wrap;
294 return (PyObject*)wrap;
294 }
295 }
295
296
296 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
297 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
297 {
298 {
298 if (!ptr) {
299 if (!ptr) {
299 Py_INCREF(Py_None);
300 Py_INCREF(Py_None);
300 return Py_None;
301 return Py_None;
301 }
302 }
302
303
303 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
304 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
304 if (!wrap) {
305 if (!wrap) {
305 PythonQtClassInfo* info = _knownClassInfos.value(name);
306 PythonQtClassInfo* info = _knownClassInfos.value(name);
306 if (!info) {
307 if (!info) {
307 // maybe it is a PyObject, which we can return directly
308 // maybe it is a PyObject, which we can return directly
308 if (name == "PyObject") {
309 if (name == "PyObject") {
309 PyObject* p = (PyObject*)ptr;
310 PyObject* p = (PyObject*)ptr;
310 Py_INCREF(p);
311 Py_INCREF(p);
311 return p;
312 return p;
312 }
313 }
313
314
314 // we do not know the metaobject yet, but we might know it by it's name:
315 // we do not know the metaobject yet, but we might know it by it's name:
315 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
316 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
316 // yes, we know it, so we can convert to QObject
317 // yes, we know it, so we can convert to QObject
317 QObject* qptr = (QObject*)ptr;
318 QObject* qptr = (QObject*)ptr;
318 registerClass(qptr->metaObject());
319 registerClass(qptr->metaObject());
319 info = _knownClassInfos.value(qptr->metaObject()->className());
320 info = _knownClassInfos.value(qptr->metaObject()->className());
320 }
321 }
321 }
322 }
322 if (info && info->isQObject()) {
323 if (info && info->isQObject()) {
323 QObject* qptr = (QObject*)ptr;
324 QObject* qptr = (QObject*)ptr;
324 // if the object is a derived object, we want to switch the class info to the one of the derived class:
325 // if the object is a derived object, we want to switch the class info to the one of the derived class:
325 if (name!=(qptr->metaObject()->className())) {
326 if (name!=(qptr->metaObject()->className())) {
326 registerClass(qptr->metaObject());
327 registerClass(qptr->metaObject());
327 info = _knownClassInfos.value(qptr->metaObject()->className());
328 info = _knownClassInfos.value(qptr->metaObject()->className());
328 }
329 }
329 wrap = createNewPythonQtInstanceWrapper(qptr, info);
330 wrap = createNewPythonQtInstanceWrapper(qptr, info);
330 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
331 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
331 return (PyObject*)wrap;
332 return (PyObject*)wrap;
332 }
333 }
333
334
334 // not a known QObject, so try our wrapper factory:
335 // not a known QObject, so try our wrapper factory:
335 QObject* wrapper = NULL;
336 QObject* wrapper = NULL;
336 for (int i=0; i<_cppWrapperFactories.size(); i++) {
337 for (int i=0; i<_cppWrapperFactories.size(); i++) {
337 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
338 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
338 if (wrapper) {
339 if (wrapper) {
339 break;
340 break;
340 }
341 }
341 }
342 }
342
343
343 if (info) {
344 if (info) {
344 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
345 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
345 ptr = info->castDownIfPossible(ptr, &info);
346 ptr = info->castDownIfPossible(ptr, &info);
346 }
347 }
347
348
348 if (!info || info->pythonQtClassWrapper()==NULL) {
349 if (!info || info->pythonQtClassWrapper()==NULL) {
349 // still unknown, register as CPP class
350 // still unknown, register as CPP class
350 registerCPPClass(name.constData());
351 registerCPPClass(name.constData());
351 info = _knownClassInfos.value(name);
352 info = _knownClassInfos.value(name);
352 }
353 }
353 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
354 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
354 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
355 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
355 info->setMetaObject(wrapper->metaObject());
356 info->setMetaObject(wrapper->metaObject());
356 }
357 }
357 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
358 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
358 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
359 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
359 } else {
360 } else {
360 Py_INCREF(wrap);
361 Py_INCREF(wrap);
361 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
362 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
362 }
363 }
363 return (PyObject*)wrap;
364 return (PyObject*)wrap;
364 }
365 }
365
366
366 PyObject* PythonQtPrivate::dummyTuple() {
367 PyObject* PythonQtPrivate::dummyTuple() {
367 static PyObject* dummyTuple = NULL;
368 static PyObject* dummyTuple = NULL;
368 if (dummyTuple==NULL) {
369 if (dummyTuple==NULL) {
369 dummyTuple = PyTuple_New(1);
370 dummyTuple = PyTuple_New(1);
370 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
371 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
371 }
372 }
372 return dummyTuple;
373 return dummyTuple;
373 }
374 }
374
375
375
376
376 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
377 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
377 // call the associated class type to create a new instance...
378 // call the associated class type to create a new instance...
378 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
379 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
379
380
380 result->setQObject(obj);
381 result->setQObject(obj);
381 result->_wrappedPtr = wrappedPtr;
382 result->_wrappedPtr = wrappedPtr;
382 result->_ownedByPythonQt = false;
383 result->_ownedByPythonQt = false;
383 result->_useQMetaTypeDestroy = false;
384 result->_useQMetaTypeDestroy = false;
384
385
385 if (wrappedPtr) {
386 if (wrappedPtr) {
386 _wrappedObjects.insert(wrappedPtr, result);
387 _wrappedObjects.insert(wrappedPtr, result);
387 } else {
388 } else {
388 _wrappedObjects.insert(obj, result);
389 _wrappedObjects.insert(obj, result);
389 if (obj->parent()== NULL && _wrappedCB) {
390 if (obj->parent()== NULL && _wrappedCB) {
390 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
391 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
391 (*_wrappedCB)(obj);
392 (*_wrappedCB)(obj);
392 }
393 }
393 }
394 }
394 return result;
395 return result;
395 }
396 }
396
397
397 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
398 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
398 PythonQtClassWrapper* result;
399 PythonQtClassWrapper* result;
399
400
400 PyObject* className = PyString_FromString(info->className());
401 PyObject* className = PyString_FromString(info->className());
401
402
402 PyObject* baseClasses = PyTuple_New(1);
403 PyObject* baseClasses = PyTuple_New(1);
403 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
404 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
404
405
405 PyObject* typeDict = PyDict_New();
406 PyObject* typeDict = PyDict_New();
406 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
407 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
407 PyDict_SetItemString(typeDict, "__module__", moduleName);
408 PyDict_SetItemString(typeDict, "__module__", moduleName);
408
409
409 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
410 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
410
411
411 // set the class info so that PythonQtClassWrapper_new can read it
412 // set the class info so that PythonQtClassWrapper_new can read it
412 _currentClassInfoForClassWrapperCreation = info;
413 _currentClassInfoForClassWrapperCreation = info;
413 // create the new type object by calling the type
414 // create the new type object by calling the type
414 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
415 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
415
416
416 Py_DECREF(baseClasses);
417 Py_DECREF(baseClasses);
417 Py_DECREF(typeDict);
418 Py_DECREF(typeDict);
418 Py_DECREF(args);
419 Py_DECREF(args);
419 Py_DECREF(className);
420 Py_DECREF(className);
420
421
421 return result;
422 return result;
422 }
423 }
423
424
424 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
425 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
425 {
426 {
426 PyObject* args = Py_BuildValue("(i)", enumValue);
427 PyObject* args = Py_BuildValue("(i)", enumValue);
427 PyObject* result = PyObject_Call(enumType, args, NULL);
428 PyObject* result = PyObject_Call(enumType, args, NULL);
428 Py_DECREF(args);
429 Py_DECREF(args);
429 return result;
430 return result;
430 }
431 }
431
432
432 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
433 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
433 PyObject* result;
434 PyObject* result;
434
435
435 PyObject* className = PyString_FromString(enumName);
436 PyObject* className = PyString_FromString(enumName);
436
437
437 PyObject* baseClasses = PyTuple_New(1);
438 PyObject* baseClasses = PyTuple_New(1);
438 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
439 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
439
440
440 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
441 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
441 PyObject* typeDict = PyDict_New();
442 PyObject* typeDict = PyDict_New();
442 PyDict_SetItemString(typeDict, "__module__", module);
443 PyDict_SetItemString(typeDict, "__module__", module);
443
444
444 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
445 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
445
446
446 // create the new int derived type object by calling the core type
447 // create the new int derived type object by calling the core type
447 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
448 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
448
449
449 Py_DECREF(baseClasses);
450 Py_DECREF(baseClasses);
450 Py_DECREF(typeDict);
451 Py_DECREF(typeDict);
451 Py_DECREF(args);
452 Py_DECREF(args);
452 Py_DECREF(className);
453 Py_DECREF(className);
453
454
454 return result;
455 return result;
455 }
456 }
456
457
457 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
458 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
458 {
459 {
459 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
460 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
460 if (!r) {
461 if (!r) {
461 r = new PythonQtSignalReceiver(obj);
462 r = new PythonQtSignalReceiver(obj);
462 _p->_signalReceivers.insert(obj, r);
463 _p->_signalReceivers.insert(obj, r);
463 }
464 }
464 return r;
465 return r;
465 }
466 }
466
467
467 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
468 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
468 {
469 {
469 bool flag = false;
470 bool flag = false;
470 PythonQtObjectPtr callable = lookupCallable(module, objectname);
471 PythonQtObjectPtr callable = lookupCallable(module, objectname);
471 if (callable) {
472 if (callable) {
472 PythonQtSignalReceiver* r = getSignalReceiver(obj);
473 PythonQtSignalReceiver* r = getSignalReceiver(obj);
473 flag = r->addSignalHandler(signal, callable);
474 flag = r->addSignalHandler(signal, callable);
474 if (!flag) {
475 if (!flag) {
475 // signal not found
476 // signal not found
476 }
477 }
477 } else {
478 } else {
478 // callable not found
479 // callable not found
479 }
480 }
480 return flag;
481 return flag;
481 }
482 }
482
483
483 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
484 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
484 {
485 {
485 bool flag = false;
486 bool flag = false;
486 PythonQtSignalReceiver* r = getSignalReceiver(obj);
487 PythonQtSignalReceiver* r = getSignalReceiver(obj);
487 if (r) {
488 if (r) {
488 flag = r->addSignalHandler(signal, receiver);
489 flag = r->addSignalHandler(signal, receiver);
489 }
490 }
490 return flag;
491 return flag;
491 }
492 }
492
493
493 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
494 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
494 {
495 {
495 bool flag = false;
496 bool flag = false;
496 PythonQtObjectPtr callable = lookupCallable(module, objectname);
497 PythonQtObjectPtr callable = lookupCallable(module, objectname);
497 if (callable) {
498 if (callable) {
498 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
499 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
499 if (r) {
500 if (r) {
500 flag = r->removeSignalHandler(signal, callable);
501 flag = r->removeSignalHandler(signal, callable);
501 }
502 }
502 } else {
503 } else {
503 // callable not found
504 // callable not found
504 }
505 }
505 return flag;
506 return flag;
506 }
507 }
507
508
508 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
509 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
509 {
510 {
510 bool flag = false;
511 bool flag = false;
511 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
512 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
512 if (r) {
513 if (r) {
513 flag = r->removeSignalHandler(signal, receiver);
514 flag = r->removeSignalHandler(signal, receiver);
514 }
515 }
515 return flag;
516 return flag;
516 }
517 }
517
518
518 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
519 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
519 {
520 {
520 PythonQtObjectPtr p = lookupObject(module, name);
521 PythonQtObjectPtr p = lookupObject(module, name);
521 if (p) {
522 if (p) {
522 if (PyCallable_Check(p)) {
523 if (PyCallable_Check(p)) {
523 return p;
524 return p;
524 }
525 }
525 }
526 }
526 PyErr_Clear();
527 PyErr_Clear();
527 return NULL;
528 return NULL;
528 }
529 }
529
530
530 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
531 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
531 {
532 {
532 QStringList l = name.split('.');
533 QStringList l = name.split('.');
533 PythonQtObjectPtr p = module;
534 PythonQtObjectPtr p = module;
534 PythonQtObjectPtr prev;
535 PythonQtObjectPtr prev;
535 QString s;
536 QString s;
536 QByteArray b;
537 QByteArray b;
537 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
538 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
538 prev = p;
539 prev = p;
539 b = (*i).toLatin1();
540 b = (*i).toLatin1();
540 if (PyDict_Check(p)) {
541 if (PyDict_Check(p)) {
541 p = PyDict_GetItemString(p, b.data());
542 p = PyDict_GetItemString(p, b.data());
542 } else {
543 } else {
543 p.setNewRef(PyObject_GetAttrString(p, b.data()));
544 p.setNewRef(PyObject_GetAttrString(p, b.data()));
544 }
545 }
545 }
546 }
546 PyErr_Clear();
547 PyErr_Clear();
547 return p;
548 return p;
548 }
549 }
549
550
550 PythonQtObjectPtr PythonQt::getMainModule() {
551 PythonQtObjectPtr PythonQt::getMainModule() {
551 //both borrowed
552 //both borrowed
552 PythonQtObjectPtr dict = PyImport_GetModuleDict();
553 PythonQtObjectPtr dict = PyImport_GetModuleDict();
553 return PyDict_GetItemString(dict, "__main__");
554 return PyDict_GetItemString(dict, "__main__");
554 }
555 }
555
556
556 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
557 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
557 QVariant result;
558 QVariant result;
558 if (pycode) {
559 if (pycode) {
559 PyObject* dict = NULL;
560 PyObject* dict = NULL;
560 if (PyModule_Check(object)) {
561 if (PyModule_Check(object)) {
561 dict = PyModule_GetDict(object);
562 dict = PyModule_GetDict(object);
562 } else if (PyDict_Check(object)) {
563 } else if (PyDict_Check(object)) {
563 dict = object;
564 dict = object;
564 }
565 }
565 PyObject* r = NULL;
566 PyObject* r = NULL;
566 if (dict) {
567 if (dict) {
567 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
568 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
568 }
569 }
569 if (r) {
570 if (r) {
570 result = PythonQtConv::PyObjToQVariant(r);
571 result = PythonQtConv::PyObjToQVariant(r);
571 Py_DECREF(r);
572 Py_DECREF(r);
572 } else {
573 } else {
573 handleError();
574 handleError();
574 }
575 }
575 } else {
576 } else {
576 handleError();
577 handleError();
577 }
578 }
578 return result;
579 return result;
579 }
580 }
580
581
581 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
582 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
582 {
583 {
583 QVariant result;
584 QVariant result;
584 PythonQtObjectPtr p;
585 PythonQtObjectPtr p;
585 PyObject* dict = NULL;
586 PyObject* dict = NULL;
586 if (PyModule_Check(object)) {
587 if (PyModule_Check(object)) {
587 dict = PyModule_GetDict(object);
588 dict = PyModule_GetDict(object);
588 } else if (PyDict_Check(object)) {
589 } else if (PyDict_Check(object)) {
589 dict = object;
590 dict = object;
590 }
591 }
591 if (dict) {
592 if (dict) {
592 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
593 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
593 }
594 }
594 if (p) {
595 if (p) {
595 result = PythonQtConv::PyObjToQVariant(p);
596 result = PythonQtConv::PyObjToQVariant(p);
596 } else {
597 } else {
597 handleError();
598 handleError();
598 }
599 }
599 return result;
600 return result;
600 }
601 }
601
602
602 void PythonQt::evalFile(PyObject* module, const QString& filename)
603 void PythonQt::evalFile(PyObject* module, const QString& filename)
603 {
604 {
604 PythonQtObjectPtr code = parseFile(filename);
605 PythonQtObjectPtr code = parseFile(filename);
605 if (code) {
606 if (code) {
606 evalCode(module, code);
607 evalCode(module, code);
607 } else {
608 } else {
608 handleError();
609 handleError();
609 }
610 }
610 }
611 }
611
612
612 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
613 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
613 {
614 {
614 PythonQtObjectPtr p;
615 PythonQtObjectPtr p;
615 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
616 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
616 if (!p) {
617 if (!p) {
617 handleError();
618 handleError();
618 }
619 }
619 return p;
620 return p;
620 }
621 }
621
622
622 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
623 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
623 {
624 {
624 PythonQtObjectPtr code = parseFile(filename);
625 PythonQtObjectPtr code = parseFile(filename);
625 PythonQtObjectPtr module = _p->createModule(name, code);
626 PythonQtObjectPtr module = _p->createModule(name, code);
626 return module;
627 return module;
627 }
628 }
628
629
629 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
630 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
630 {
631 {
631 PyErr_Clear();
632 PyErr_Clear();
632 QString scriptCode = script;
633 QString scriptCode = script;
633 if (scriptCode.isEmpty()) {
634 if (scriptCode.isEmpty()) {
634 // we always need at least a linefeed
635 // we always need at least a linefeed
635 scriptCode = "\n";
636 scriptCode = "\n";
636 }
637 }
637 PythonQtObjectPtr pycode;
638 PythonQtObjectPtr pycode;
638 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
639 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
639 PythonQtObjectPtr module = _p->createModule(name, pycode);
640 PythonQtObjectPtr module = _p->createModule(name, pycode);
640 return module;
641 return module;
641 }
642 }
642
643
643 PythonQtObjectPtr PythonQt::createUniqueModule()
644 PythonQtObjectPtr PythonQt::createUniqueModule()
644 {
645 {
645 static QString pyQtStr("PythonQt_module");
646 static QString pyQtStr("PythonQt_module");
646 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
647 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
647 return createModuleFromScript(moduleName);
648 return createModuleFromScript(moduleName);
648 }
649 }
649
650
650 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
651 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
651 {
652 {
652 if (PyModule_Check(object)) {
653 if (PyModule_Check(object)) {
653 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
654 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
654 } else if (PyDict_Check(object)) {
655 } else if (PyDict_Check(object)) {
655 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
656 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
656 } else {
657 } else {
657 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
658 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
658 }
659 }
659 }
660 }
660
661
661 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
662 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
662 {
663 {
663 if (PyModule_Check(object)) {
664 if (PyModule_Check(object)) {
664 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
665 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
665 } else if (PyDict_Check(object)) {
666 } else if (PyDict_Check(object)) {
666 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
667 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
667 } else {
668 } else {
668 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
669 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
669 }
670 }
670 }
671 }
671
672
672 void PythonQt::removeVariable(PyObject* object, const QString& name)
673 void PythonQt::removeVariable(PyObject* object, const QString& name)
673 {
674 {
674 if (PyDict_Check(object)) {
675 if (PyDict_Check(object)) {
675 PyDict_DelItemString(object, name.toLatin1().data());
676 PyDict_DelItemString(object, name.toLatin1().data());
676 } else {
677 } else {
677 PyObject_DelAttrString(object, name.toLatin1().data());
678 PyObject_DelAttrString(object, name.toLatin1().data());
678 }
679 }
679 }
680 }
680
681
681 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
682 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
682 {
683 {
683 QVariant result;
684 QVariant result;
684 PythonQtObjectPtr obj = lookupObject(object, objectname);
685 PythonQtObjectPtr obj = lookupObject(object, objectname);
685 if (obj) {
686 if (obj) {
686 result = PythonQtConv::PyObjToQVariant(obj);
687 result = PythonQtConv::PyObjToQVariant(obj);
687 }
688 }
688 return result;
689 return result;
689 }
690 }
690
691
691 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
692 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
692 {
693 {
693 QStringList results;
694 QStringList results;
694
695
695 PythonQtObjectPtr object;
696 PythonQtObjectPtr object;
696 if (objectname.isEmpty()) {
697 if (objectname.isEmpty()) {
697 object = module;
698 object = module;
698 } else {
699 } else {
699 object = lookupObject(module, objectname);
700 object = lookupObject(module, objectname);
700 if (!object && type == CallOverloads) {
701 if (!object && type == CallOverloads) {
701 PyObject* dict = lookupObject(module, "__builtins__");
702 PyObject* dict = lookupObject(module, "__builtins__");
702 if (dict) {
703 if (dict) {
703 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
704 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
704 }
705 }
705 }
706 }
706 }
707 }
707
708
708 if (object) {
709 if (object) {
709 if (type == CallOverloads) {
710 if (type == CallOverloads) {
710 if (PythonQtSlotFunction_Check(object)) {
711 if (PythonQtSlotFunction_Check(object)) {
711 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
712 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
712 PythonQtSlotInfo* info = o->m_ml;
713 PythonQtSlotInfo* info = o->m_ml;
713
714
714 while (info) {
715 while (info) {
715 results << info->fullSignature();
716 results << info->fullSignature();
716 info = info->nextInfo();
717 info = info->nextInfo();
717 }
718 }
718 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
719 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
719 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
720 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
720 PythonQtSlotInfo* info = o->classInfo()->constructors();
721 PythonQtSlotInfo* info = o->classInfo()->constructors();
721
722
722 while (info) {
723 while (info) {
723 results << info->fullSignature();
724 results << info->fullSignature();
724 info = info->nextInfo();
725 info = info->nextInfo();
725 }
726 }
726 } else {
727 } else {
727 //TODO: use pydoc!
728 //TODO: use pydoc!
728 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
729 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
729 if (doc) {
730 if (doc) {
730 results << PyString_AsString(doc);
731 results << PyString_AsString(doc);
731 Py_DECREF(doc);
732 Py_DECREF(doc);
732 }
733 }
733 }
734 }
734 } else {
735 } else {
735 PyObject* keys = NULL;
736 PyObject* keys = NULL;
736 bool isDict = false;
737 bool isDict = false;
737 if (PyDict_Check(object)) {
738 if (PyDict_Check(object)) {
738 keys = PyDict_Keys(object);
739 keys = PyDict_Keys(object);
739 isDict = true;
740 isDict = true;
740 } else {
741 } else {
741 keys = PyObject_Dir(object);
742 keys = PyObject_Dir(object);
742 }
743 }
743 if (keys) {
744 if (keys) {
744 int count = PyList_Size(keys);
745 int count = PyList_Size(keys);
745 PyObject* key;
746 PyObject* key;
746 PyObject* value;
747 PyObject* value;
747 QString keystr;
748 QString keystr;
748 for (int i = 0;i<count;i++) {
749 for (int i = 0;i<count;i++) {
749 key = PyList_GetItem(keys,i);
750 key = PyList_GetItem(keys,i);
750 if (isDict) {
751 if (isDict) {
751 value = PyDict_GetItem(object, key);
752 value = PyDict_GetItem(object, key);
752 Py_INCREF(value);
753 Py_INCREF(value);
753 } else {
754 } else {
754 value = PyObject_GetAttr(object, key);
755 value = PyObject_GetAttr(object, key);
755 }
756 }
756 if (!value) continue;
757 if (!value) continue;
757 keystr = PyString_AsString(key);
758 keystr = PyString_AsString(key);
758 static const QString underscoreStr("__tmp");
759 static const QString underscoreStr("__tmp");
759 if (!keystr.startsWith(underscoreStr)) {
760 if (!keystr.startsWith(underscoreStr)) {
760 switch (type) {
761 switch (type) {
761 case Anything:
762 case Anything:
762 results << keystr;
763 results << keystr;
763 break;
764 break;
764 case Class:
765 case Class:
765 if (value->ob_type == &PyClass_Type) {
766 if (value->ob_type == &PyClass_Type) {
766 results << keystr;
767 results << keystr;
767 }
768 }
768 break;
769 break;
769 case Variable:
770 case Variable:
770 if (value->ob_type != &PyClass_Type
771 if (value->ob_type != &PyClass_Type
771 && value->ob_type != &PyCFunction_Type
772 && value->ob_type != &PyCFunction_Type
772 && value->ob_type != &PyFunction_Type
773 && value->ob_type != &PyFunction_Type
773 && value->ob_type != &PyModule_Type
774 && value->ob_type != &PyModule_Type
774 ) {
775 ) {
775 results << keystr;
776 results << keystr;
776 }
777 }
777 break;
778 break;
778 case Function:
779 case Function:
779 if (value->ob_type == &PyFunction_Type ||
780 if (value->ob_type == &PyFunction_Type ||
780 value->ob_type == &PyMethod_Type
781 value->ob_type == &PyMethod_Type
781 ) {
782 ) {
782 results << keystr;
783 results << keystr;
783 }
784 }
784 break;
785 break;
785 case Module:
786 case Module:
786 if (value->ob_type == &PyModule_Type) {
787 if (value->ob_type == &PyModule_Type) {
787 results << keystr;
788 results << keystr;
788 }
789 }
789 break;
790 break;
790 default:
791 default:
791 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
792 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
792 }
793 }
793 }
794 }
794 Py_DECREF(value);
795 Py_DECREF(value);
795 }
796 }
796 Py_DECREF(keys);
797 Py_DECREF(keys);
797 }
798 }
798 }
799 }
799 }
800 }
800 return results;
801 return results;
801 }
802 }
802
803
803 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
804 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
804 {
805 {
805 PythonQtObjectPtr callable = lookupCallable(object, name);
806 PythonQtObjectPtr callable = lookupCallable(object, name);
806 if (callable) {
807 if (callable) {
807 return call(callable, args);
808 return call(callable, args);
808 } else {
809 } else {
809 return QVariant();
810 return QVariant();
810 }
811 }
811 }
812 }
812
813
813 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
814 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
814 {
815 {
815 QVariant r;
816 QVariant r;
816 PythonQtObjectPtr result;
817 PythonQtObjectPtr result;
817 result.setNewRef(callAndReturnPyObject(callable, args));
818 result.setNewRef(callAndReturnPyObject(callable, args));
818 if (result) {
819 if (result) {
819 r = PythonQtConv::PyObjToQVariant(result);
820 r = PythonQtConv::PyObjToQVariant(result);
820 } else {
821 } else {
821 PythonQt::self()->handleError();
822 PythonQt::self()->handleError();
822 }
823 }
823 return r;
824 return r;
824 }
825 }
825
826
826 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args)
827 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args)
827 {
828 {
828 PyObject* result = NULL;
829 PyObject* result = NULL;
829 if (callable) {
830 if (callable) {
830 PythonQtObjectPtr pargs;
831 PythonQtObjectPtr pargs;
831 int count = args.size();
832 int count = args.size();
832 if (count>0) {
833 if (count>0) {
833 pargs.setNewRef(PyTuple_New(count));
834 pargs.setNewRef(PyTuple_New(count));
834 }
835 }
835 bool err = false;
836 bool err = false;
836 // transform QVariants to Python
837 // transform QVariants to Python
837 for (int i = 0; i < count; i++) {
838 for (int i = 0; i < count; i++) {
838 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
839 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
839 if (arg) {
840 if (arg) {
840 // steals reference, no unref
841 // steals reference, no unref
841 PyTuple_SetItem(pargs, i,arg);
842 PyTuple_SetItem(pargs, i,arg);
842 } else {
843 } else {
843 err = true;
844 err = true;
844 break;
845 break;
845 }
846 }
846 }
847 }
847
848
848 if (!err) {
849 if (!err) {
849 PyErr_Clear();
850 PyErr_Clear();
850 result = PyObject_CallObject(callable, pargs);
851 result = PyObject_CallObject(callable, pargs);
851 }
852 }
852 }
853 }
853 return result;
854 return result;
854 }
855 }
855
856
856 void PythonQt::addInstanceDecorators(QObject* o)
857 void PythonQt::addInstanceDecorators(QObject* o)
857 {
858 {
858 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
859 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
859 }
860 }
860
861
861 void PythonQt::addClassDecorators(QObject* o)
862 void PythonQt::addClassDecorators(QObject* o)
862 {
863 {
863 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
864 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
864 }
865 }
865
866
866 void PythonQt::addDecorators(QObject* o)
867 void PythonQt::addDecorators(QObject* o)
867 {
868 {
868 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
869 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
869 }
870 }
870
871
871 void PythonQt::registerQObjectClassNames(const QStringList& names)
872 void PythonQt::registerQObjectClassNames(const QStringList& names)
872 {
873 {
873 _p->registerQObjectClassNames(names);
874 _p->registerQObjectClassNames(names);
874 }
875 }
875
876
876 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
877 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
877 {
878 {
878 _p->_importInterface = importInterface;
879 _p->_importInterface = importInterface;
879 PythonQtImport::init();
880 PythonQtImport::init();
880 }
881 }
881
882
882 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
883 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
883 {
884 {
884 _p->_importIgnorePaths = paths;
885 _p->_importIgnorePaths = paths;
885 }
886 }
886
887
887 const QStringList& PythonQt::getImporterIgnorePaths()
888 const QStringList& PythonQt::getImporterIgnorePaths()
888 {
889 {
889 return _p->_importIgnorePaths;
890 return _p->_importIgnorePaths;
890 }
891 }
891
892
892 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
893 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
893 {
894 {
894 _p->_cppWrapperFactories.append(factory);
895 _p->_cppWrapperFactories.append(factory);
895 }
896 }
896
897
897 //---------------------------------------------------------------------------------------------------
898 //---------------------------------------------------------------------------------------------------
898 PythonQtPrivate::PythonQtPrivate()
899 PythonQtPrivate::PythonQtPrivate()
899 {
900 {
900 _importInterface = NULL;
901 _importInterface = NULL;
901 _defaultImporter = new PythonQtQFileImporter;
902 _defaultImporter = new PythonQtQFileImporter;
902 _noLongerWrappedCB = NULL;
903 _noLongerWrappedCB = NULL;
903 _wrappedCB = NULL;
904 _wrappedCB = NULL;
904 _currentClassInfoForClassWrapperCreation = NULL;
905 _currentClassInfoForClassWrapperCreation = NULL;
905 }
906 }
906
907
907 void PythonQtPrivate::setupSharedLibrarySuffixes()
908 void PythonQtPrivate::setupSharedLibrarySuffixes()
908 {
909 {
909 _sharedLibrarySuffixes.clear();
910 _sharedLibrarySuffixes.clear();
910 PythonQtObjectPtr imp;
911 PythonQtObjectPtr imp;
911 imp.setNewRef(PyImport_ImportModule("imp"));
912 imp.setNewRef(PyImport_ImportModule("imp"));
912 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
913 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
913 QVariant result = imp.call("get_suffixes");
914 QVariant result = imp.call("get_suffixes");
914 foreach (QVariant entry, result.toList()) {
915 foreach (QVariant entry, result.toList()) {
915 QVariantList suffixEntry = entry.toList();
916 QVariantList suffixEntry = entry.toList();
916 if (suffixEntry.count()==3) {
917 if (suffixEntry.count()==3) {
917 int code = suffixEntry.at(2).toInt();
918 int code = suffixEntry.at(2).toInt();
918 if (code == cExtensionCode) {
919 if (code == cExtensionCode) {
919 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
920 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
920 }
921 }
921 }
922 }
922 }
923 }
923 }
924 }
924
925
925 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
926 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
926 {
927 {
927 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
928 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
928 _currentClassInfoForClassWrapperCreation = NULL;
929 _currentClassInfoForClassWrapperCreation = NULL;
929 return info;
930 return info;
930 }
931 }
931
932
932 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
933 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
933 {
934 {
934 o->setParent(this);
935 o->setParent(this);
935 int numMethods = o->metaObject()->methodCount();
936 int numMethods = o->metaObject()->methodCount();
936 for (int i = 0; i < numMethods; i++) {
937 for (int i = 0; i < numMethods; i++) {
937 QMetaMethod m = o->metaObject()->method(i);
938 QMetaMethod m = o->metaObject()->method(i);
938 if ((m.methodType() == QMetaMethod::Method ||
939 if ((m.methodType() == QMetaMethod::Method ||
939 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
940 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
940 if (qstrncmp(m.signature(), "new_", 4)==0) {
941 if (qstrncmp(m.signature(), "new_", 4)==0) {
941 if ((decoTypes & ConstructorDecorator) == 0) continue;
942 if ((decoTypes & ConstructorDecorator) == 0) continue;
942 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
943 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
943 if (info->parameters().at(0).isPointer) {
944 if (info->parameters().at(0).isPointer) {
944 QByteArray signature = m.signature();
945 QByteArray signature = m.signature();
945 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
946 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
946 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
947 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
947 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
948 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
948 classInfo->addConstructor(newSlot);
949 classInfo->addConstructor(newSlot);
949 }
950 }
950 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
951 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
951 if ((decoTypes & DestructorDecorator) == 0) continue;
952 if ((decoTypes & DestructorDecorator) == 0) continue;
952 QByteArray signature = m.signature();
953 QByteArray signature = m.signature();
953 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
954 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
954 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
955 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
955 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
956 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
956 classInfo->setDestructor(newSlot);
957 classInfo->setDestructor(newSlot);
957 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
958 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
958 if ((decoTypes & StaticDecorator) == 0) continue;
959 if ((decoTypes & StaticDecorator) == 0) continue;
959 QByteArray signature = m.signature();
960 QByteArray signature = m.signature();
960 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
961 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
961 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
962 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
962 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
963 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
963 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
964 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
964 classInfo->addDecoratorSlot(newSlot);
965 classInfo->addDecoratorSlot(newSlot);
965 } else {
966 } else {
966 if ((decoTypes & InstanceDecorator) == 0) continue;
967 if ((decoTypes & InstanceDecorator) == 0) continue;
967 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
968 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
968 if (info->parameters().count()>1) {
969 if (info->parameters().count()>1) {
969 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
970 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
970 if (p.isPointer) {
971 if (p.isPointer) {
971 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
972 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
972 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
973 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
973 classInfo->addDecoratorSlot(newSlot);
974 classInfo->addDecoratorSlot(newSlot);
974 }
975 }
975 }
976 }
976 }
977 }
977 }
978 }
978 }
979 }
979 }
980 }
980
981
981 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
982 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
982 {
983 {
983 foreach(QString name, names) {
984 foreach(QString name, names) {
984 _knownQObjectClassNames.insert(name.toLatin1(), true);
985 _knownQObjectClassNames.insert(name.toLatin1(), true);
985 }
986 }
986 }
987 }
987
988
988 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
989 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
989 {
990 {
990 _signalReceivers.remove(obj);
991 _signalReceivers.remove(obj);
991 }
992 }
992
993
993 bool PythonQt::handleError()
994 bool PythonQt::handleError()
994 {
995 {
995 bool flag = false;
996 bool flag = false;
996 if (PyErr_Occurred()) {
997 if (PyErr_Occurred()) {
997
998
998 // currently we just print the error and the stderr handler parses the errors
999 // currently we just print the error and the stderr handler parses the errors
999 PyErr_Print();
1000 PyErr_Print();
1000
1001
1001 /*
1002 /*
1002 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1003 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1003 PyObject *ptype;
1004 PyObject *ptype;
1004 PyObject *pvalue;
1005 PyObject *pvalue;
1005 PyObject *ptraceback;
1006 PyObject *ptraceback;
1006 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1007 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1007
1008
1008 Py_XDECREF(ptype);
1009 Py_XDECREF(ptype);
1009 Py_XDECREF(pvalue);
1010 Py_XDECREF(pvalue);
1010 Py_XDECREF(ptraceback);
1011 Py_XDECREF(ptraceback);
1011 */
1012 */
1012 PyErr_Clear();
1013 PyErr_Clear();
1013 flag = true;
1014 flag = true;
1014 }
1015 }
1015 return flag;
1016 return flag;
1016 }
1017 }
1017
1018
1018 void PythonQt::addSysPath(const QString& path)
1019 void PythonQt::addSysPath(const QString& path)
1019 {
1020 {
1020 PythonQtObjectPtr sys;
1021 PythonQtObjectPtr sys;
1021 sys.setNewRef(PyImport_ImportModule("sys"));
1022 sys.setNewRef(PyImport_ImportModule("sys"));
1022 PythonQtObjectPtr obj = lookupObject(sys, "path");
1023 PythonQtObjectPtr obj = lookupObject(sys, "path");
1023 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1024 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1024 }
1025 }
1025
1026
1026 void PythonQt::overwriteSysPath(const QStringList& paths)
1027 void PythonQt::overwriteSysPath(const QStringList& paths)
1027 {
1028 {
1028 PythonQtObjectPtr sys;
1029 PythonQtObjectPtr sys;
1029 sys.setNewRef(PyImport_ImportModule("sys"));
1030 sys.setNewRef(PyImport_ImportModule("sys"));
1030 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1031 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1031 }
1032 }
1032
1033
1033 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1034 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1034 {
1035 {
1035 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1036 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1036 }
1037 }
1037
1038
1038 void PythonQt::stdOutRedirectCB(const QString& str)
1039 void PythonQt::stdOutRedirectCB(const QString& str)
1039 {
1040 {
1040 emit PythonQt::self()->pythonStdOut(str);
1041 emit PythonQt::self()->pythonStdOut(str);
1041 }
1042 }
1042
1043
1043 void PythonQt::stdErrRedirectCB(const QString& str)
1044 void PythonQt::stdErrRedirectCB(const QString& str)
1044 {
1045 {
1045 emit PythonQt::self()->pythonStdErr(str);
1046 emit PythonQt::self()->pythonStdErr(str);
1046 }
1047 }
1047
1048
1048 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1049 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1049 {
1050 {
1050 _p->_wrappedCB = cb;
1051 _p->_wrappedCB = cb;
1051 }
1052 }
1052
1053
1053 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1054 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1054 {
1055 {
1055 _p->_noLongerWrappedCB = cb;
1056 _p->_noLongerWrappedCB = cb;
1056 }
1057 }
1057
1058
1058
1059
1059
1060
1060 static PyMethodDef PythonQtMethods[] = {
1061 static PyMethodDef PythonQtMethods[] = {
1061 {NULL, NULL, 0, NULL}
1062 {NULL, NULL, 0, NULL}
1062 };
1063 };
1063
1064
1064 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1065 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1065 {
1066 {
1066 QByteArray name = "PythonQt";
1067 QByteArray name = "PythonQt";
1067 if (!pythonQtModuleName.isEmpty()) {
1068 if (!pythonQtModuleName.isEmpty()) {
1068 name = pythonQtModuleName;
1069 name = pythonQtModuleName;
1069 }
1070 }
1070 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1071 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1071 _p->_pythonQtModuleName = name;
1072 _p->_pythonQtModuleName = name;
1072
1073
1073 if (redirectStdOut) {
1074 if (redirectStdOut) {
1074 PythonQtObjectPtr sys;
1075 PythonQtObjectPtr sys;
1075 PythonQtObjectPtr out;
1076 PythonQtObjectPtr out;
1076 PythonQtObjectPtr err;
1077 PythonQtObjectPtr err;
1077 sys.setNewRef(PyImport_ImportModule("sys"));
1078 sys.setNewRef(PyImport_ImportModule("sys"));
1078 // create a redirection object for stdout and stderr
1079 // create a redirection object for stdout and stderr
1079 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1080 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1080 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1081 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1081 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1082 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1082 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1083 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1083 // replace the built in file objects with our own objects
1084 // replace the built in file objects with our own objects
1084 PyModule_AddObject(sys, "stdout", out);
1085 PyModule_AddObject(sys, "stdout", out);
1085 PyModule_AddObject(sys, "stderr", err);
1086 PyModule_AddObject(sys, "stderr", err);
1086 }
1087 }
1087 }
1088 }
1088
1089
1089 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1090 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1090 {
1091 {
1091 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1092 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1092 }
1093 }
1093
1094
1094
1095
1095 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1096 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1096 {
1097 {
1097 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1098 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1098 if (!info) {
1099 if (!info) {
1099 info = new PythonQtClassInfo();
1100 info = new PythonQtClassInfo();
1100 info->setupCPPObject(typeName);
1101 info->setupCPPObject(typeName);
1101 _knownClassInfos.insert(typeName, info);
1102 _knownClassInfos.insert(typeName, info);
1102 }
1103 }
1103 return info;
1104 return info;
1104 }
1105 }
1105
1106
1106 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1107 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1107 {
1108 {
1108 _p->addPolymorphicHandler(typeName, cb);
1109 _p->addPolymorphicHandler(typeName, cb);
1109 }
1110 }
1110
1111
1111 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1112 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1112 {
1113 {
1113 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1114 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1114 info->addPolymorphicHandler(cb);
1115 info->addPolymorphicHandler(cb);
1115 }
1116 }
1116
1117
1117 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1118 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1118 {
1119 {
1119 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1120 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1120 }
1121 }
1121
1122
1122 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1123 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1123 {
1124 {
1124 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1125 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1125 if (info) {
1126 if (info) {
1126 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1127 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1127 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1128 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1128 return true;
1129 return true;
1129 } else {
1130 } else {
1130 return false;
1131 return false;
1131 }
1132 }
1132 }
1133 }
1133
1134
1134 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1135 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1135 {
1136 {
1136 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1137 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1137 if (!info->pythonQtClassWrapper()) {
1138 if (!info->pythonQtClassWrapper()) {
1138 info->setTypeSlots(typeSlots);
1139 info->setTypeSlots(typeSlots);
1139 info->setupCPPObject(typeName);
1140 info->setupCPPObject(typeName);
1140 createPythonQtClassWrapper(info, package, module);
1141 createPythonQtClassWrapper(info, package, module);
1141 }
1142 }
1142 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1143 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1143 addParentClass(typeName, parentTypeName, 0);
1144 addParentClass(typeName, parentTypeName, 0);
1144 }
1145 }
1145 if (wrapperCreator) {
1146 if (wrapperCreator) {
1146 info->setDecoratorProvider(wrapperCreator);
1147 info->setDecoratorProvider(wrapperCreator);
1147 }
1148 }
1148 if (shell) {
1149 if (shell) {
1149 info->setShellSetInstanceWrapperCB(shell);
1150 info->setShellSetInstanceWrapperCB(shell);
1150 }
1151 }
1151 }
1152 }
1152
1153
1153 PyObject* PythonQtPrivate::packageByName(const char* name)
1154 PyObject* PythonQtPrivate::packageByName(const char* name)
1154 {
1155 {
1155 if (name==NULL || name[0]==0) {
1156 if (name==NULL || name[0]==0) {
1156 name = "private";
1157 name = "private";
1157 }
1158 }
1158 PyObject* v = _packages.value(name);
1159 PyObject* v = _packages.value(name);
1159 if (!v) {
1160 if (!v) {
1160 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1161 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1161 _packages.insert(name, v);
1162 _packages.insert(name, v);
1162 // AddObject steals the reference, so increment it!
1163 // AddObject steals the reference, so increment it!
1163 Py_INCREF(v);
1164 Py_INCREF(v);
1164 PyModule_AddObject(_pythonQtModule, name, v);
1165 PyModule_AddObject(_pythonQtModule, name, v);
1165 }
1166 }
1166 return v;
1167 return v;
1167 }
1168 }
1168
1169
1169 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1170 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1170 {
1171 {
1171 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;
1172 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;
1172 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1173 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1173 PythonQt::self()->handleError();
1174 PythonQt::self()->handleError();
1174 }
1175 }
1175
1176
1176 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1177 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1177 {
1178 {
1178 if (_p->_initFlags & ExternalHelp) {
1179 if (_p->_initFlags & ExternalHelp) {
1179 emit pythonHelpRequest(QByteArray(info->className()));
1180 emit pythonHelpRequest(QByteArray(info->className()));
1180 return Py_BuildValue("");
1181 return Py_BuildValue("");
1181 } else {
1182 } else {
1182 return PyString_FromString(info->help().toLatin1().data());
1183 return PyString_FromString(info->help().toLatin1().data());
1183 }
1184 }
1184 }
1185 }
1185
1186
1186 void PythonQtPrivate::removeWrapperPointer(void* obj)
1187 void PythonQtPrivate::removeWrapperPointer(void* obj)
1187 {
1188 {
1188 _wrappedObjects.remove(obj);
1189 _wrappedObjects.remove(obj);
1189 }
1190 }
1190
1191
1191 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1192 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1192 {
1193 {
1193 _wrappedObjects.insert(obj, wrapper);
1194 _wrappedObjects.insert(obj, wrapper);
1194 }
1195 }
1195
1196
1196 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1197 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1197 {
1198 {
1198 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1199 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1199 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1200 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1200 // this is a wrapper whose QObject was already removed due to destruction
1201 // this is a wrapper whose QObject was already removed due to destruction
1201 // so the obj pointer has to be a new QObject with the same address...
1202 // so the obj pointer has to be a new QObject with the same address...
1202 // we remove the old one and set the copy to NULL
1203 // we remove the old one and set the copy to NULL
1203 wrap->_objPointerCopy = NULL;
1204 wrap->_objPointerCopy = NULL;
1204 removeWrapperPointer(obj);
1205 removeWrapperPointer(obj);
1205 wrap = NULL;
1206 wrap = NULL;
1206 }
1207 }
1207 return wrap;
1208 return wrap;
1208 }
1209 }
1209
1210
1210 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1211 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1211 {
1212 {
1212 PythonQtObjectPtr result;
1213 PythonQtObjectPtr result;
1213 if (pycode) {
1214 if (pycode) {
1214 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1215 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1215 } else {
1216 } else {
1216 PythonQt::self()->handleError();
1217 PythonQt::self()->handleError();
1217 }
1218 }
1218 return result;
1219 return result;
1219 }
1220 }
@@ -1,1226 +1,1228
1 /*
1 /*
2 *
2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2006 MeVis Research GmbH 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 Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Research GmbH, 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 PythonQtConversion.cpp
35 // \file PythonQtConversion.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 "PythonQtConversion.h"
42 #include "PythonQtConversion.h"
43 #include "PythonQtVariants.h"
43 #include "PythonQtVariants.h"
44 #include <QDateTime>
44 #include <QDateTime>
45 #include <QTime>
45 #include <QTime>
46 #include <QDate>
46 #include <QDate>
47
47
48 PythonQtValueStorage<qint64, 128> PythonQtConv::global_valueStorage;
48 PythonQtValueStorage<qint64, 128> PythonQtConv::global_valueStorage;
49 PythonQtValueStorage<void*, 128> PythonQtConv::global_ptrStorage;
49 PythonQtValueStorage<void*, 128> PythonQtConv::global_ptrStorage;
50 PythonQtValueStorage<QVariant, 32> PythonQtConv::global_variantStorage;
50 PythonQtValueStorage<QVariant, 32> PythonQtConv::global_variantStorage;
51
51
52 QHash<int, PythonQtConvertMetaTypeToPythonCB*> PythonQtConv::_metaTypeToPythonConverters;
52 QHash<int, PythonQtConvertMetaTypeToPythonCB*> PythonQtConv::_metaTypeToPythonConverters;
53 QHash<int, PythonQtConvertPythonToMetaTypeCB*> PythonQtConv::_pythonToMetaTypeConverters;
53 QHash<int, PythonQtConvertPythonToMetaTypeCB*> PythonQtConv::_pythonToMetaTypeConverters;
54
54
55 PyObject* PythonQtConv::GetPyBool(bool val)
55 PyObject* PythonQtConv::GetPyBool(bool val)
56 {
56 {
57 PyObject* r = val?Py_True:Py_False;
57 PyObject* r = val?Py_True:Py_False;
58 Py_INCREF(r);
58 Py_INCREF(r);
59 return r;
59 return r;
60 }
60 }
61
61
62 PyObject* PythonQtConv::ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data) {
62 PyObject* PythonQtConv::ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data) {
63 // is it an enum value?
63 // is it an enum value?
64 if (info.enumWrapper) {
64 if (info.enumWrapper) {
65 if (!info.isPointer) {
65 if (!info.isPointer) {
66 return PythonQtPrivate::createEnumValueInstance(info.enumWrapper, *((unsigned int*)data));
66 return PythonQtPrivate::createEnumValueInstance(info.enumWrapper, *((unsigned int*)data));
67 } else {
67 } else {
68 // we do not support pointers to enums (who needs them?)
68 // we do not support pointers to enums (who needs them?)
69 Py_INCREF(Py_None);
69 Py_INCREF(Py_None);
70 return Py_None;
70 return Py_None;
71 }
71 }
72 }
72 }
73
73
74 if (info.typeId == QMetaType::Void) {
74 if (info.typeId == QMetaType::Void) {
75 Py_INCREF(Py_None);
75 Py_INCREF(Py_None);
76 return Py_None;
76 return Py_None;
77 } else if (info.isPointer && (info.typeId == QMetaType::Char)) {
77 } else if (info.isPointer && (info.typeId == QMetaType::Char)) {
78 // a char ptr will probably be a null terminated string, so we support that:
78 // a char ptr will probably be a null terminated string, so we support that:
79 return PyString_FromString(*((char**)data));
79 return PyString_FromString(*((char**)data));
80 } else if ((info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) &&
80 } else if ((info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) &&
81 info.name.startsWith("QList<")) {
81 info.name.startsWith("QList<")) {
82 // it is a QList template:
82 // it is a QList template:
83 QByteArray innerType = info.name.mid(6,info.name.length()-7);
83 QByteArray innerType = info.name.mid(6,info.name.length()-7);
84 if (innerType.endsWith("*")) {
84 if (innerType.endsWith("*")) {
85 innerType.truncate(innerType.length()-1);
85 innerType.truncate(innerType.length()-1);
86 QList<void*>* listPtr;
86 QList<void*>* listPtr;
87 if (info.isPointer) {
87 if (info.isPointer) {
88 listPtr = *((QList<void*>**)data);
88 listPtr = *((QList<void*>**)data);
89 } else {
89 } else {
90 listPtr = (QList<void*>*)data;
90 listPtr = (QList<void*>*)data;
91 }
91 }
92 return ConvertQListOfPointerTypeToPythonList(listPtr, innerType);
92 return ConvertQListOfPointerTypeToPythonList(listPtr, innerType);
93 }
93 }
94 }
94 }
95
95
96 if (info.typeId >= QMetaType::User) {
96 if (info.typeId >= QMetaType::User) {
97 // if a converter is registered, we use is:
97 // if a converter is registered, we use is:
98 PythonQtConvertMetaTypeToPythonCB* converter = _metaTypeToPythonConverters.value(info.typeId);
98 PythonQtConvertMetaTypeToPythonCB* converter = _metaTypeToPythonConverters.value(info.typeId);
99 if (converter) {
99 if (converter) {
100 return (*converter)(data, info.typeId);
100 return (*converter)(data, info.typeId);
101 }
101 }
102 }
102 }
103
103
104 // special handling did not match, so we convert the usual way (either pointer or value version):
104 // special handling did not match, so we convert the usual way (either pointer or value version):
105 if (info.isPointer) {
105 if (info.isPointer) {
106 // convert the pointer to a Python Object (we can handle ANY C++ object, in the worst case we just know the type and the pointer)
106 // convert the pointer to a Python Object (we can handle ANY C++ object, in the worst case we just know the type and the pointer)
107 return PythonQt::priv()->wrapPtr(*((void**)data), info.name);
107 return PythonQt::priv()->wrapPtr(*((void**)data), info.name);
108 } else {
108 } else {
109 // handle values that are not yet handled and not pointers
109 // handle values that are not yet handled and not pointers
110 return ConvertQtValueToPythonInternal(info.typeId, data);
110 return ConvertQtValueToPythonInternal(info.typeId, data);
111 }
111 }
112 }
112 }
113
113
114 PyObject* PythonQtConv::ConvertQtValueToPythonInternal(int type, const void* data) {
114 PyObject* PythonQtConv::ConvertQtValueToPythonInternal(int type, const void* data) {
115 switch (type) {
115 switch (type) {
116 case QMetaType::Void:
116 case QMetaType::Void:
117 Py_INCREF(Py_None);
117 Py_INCREF(Py_None);
118 return Py_None;
118 return Py_None;
119 case QMetaType::Char:
119 case QMetaType::Char:
120 return PyInt_FromLong(*((char*)data));
120 return PyInt_FromLong(*((char*)data));
121 case QMetaType::UChar:
121 case QMetaType::UChar:
122 return PyInt_FromLong(*((unsigned char*)data));
122 return PyInt_FromLong(*((unsigned char*)data));
123 case QMetaType::Short:
123 case QMetaType::Short:
124 return PyInt_FromLong(*((short*)data));
124 return PyInt_FromLong(*((short*)data));
125 case QMetaType::UShort:
125 case QMetaType::UShort:
126 return PyInt_FromLong(*((unsigned short*)data));
126 return PyInt_FromLong(*((unsigned short*)data));
127 case QMetaType::Long:
127 case QMetaType::Long:
128 return PyInt_FromLong(*((long*)data));
128 return PyInt_FromLong(*((long*)data));
129 case QMetaType::ULong:
129 case QMetaType::ULong:
130 // does not fit into simple int of python
130 // does not fit into simple int of python
131 return PyLong_FromUnsignedLong(*((unsigned long*)data));
131 return PyLong_FromUnsignedLong(*((unsigned long*)data));
132 case QMetaType::Bool:
132 case QMetaType::Bool:
133 return PythonQtConv::GetPyBool(*((bool*)data));
133 return PythonQtConv::GetPyBool(*((bool*)data));
134 case QMetaType::Int:
134 case QMetaType::Int:
135 return PyInt_FromLong(*((int*)data));
135 return PyInt_FromLong(*((int*)data));
136 case QMetaType::UInt:
136 case QMetaType::UInt:
137 // does not fit into simple int of python
137 // does not fit into simple int of python
138 return PyLong_FromUnsignedLong(*((unsigned int*)data));
138 return PyLong_FromUnsignedLong(*((unsigned int*)data));
139 case QMetaType::QChar:
139 case QMetaType::QChar:
140 return PyInt_FromLong(*((short*)data));
140 return PyInt_FromLong(*((short*)data));
141 case QMetaType::Float:
141 case QMetaType::Float:
142 return PyFloat_FromDouble(*((float*)data));
142 return PyFloat_FromDouble(*((float*)data));
143 case QMetaType::Double:
143 case QMetaType::Double:
144 return PyFloat_FromDouble(*((double*)data));
144 return PyFloat_FromDouble(*((double*)data));
145 case QMetaType::LongLong:
145 case QMetaType::LongLong:
146 return PyLong_FromLongLong(*((qint64*)data));
146 return PyLong_FromLongLong(*((qint64*)data));
147 case QMetaType::ULongLong:
147 case QMetaType::ULongLong:
148 return PyLong_FromUnsignedLongLong(*((quint64*)data));
148 return PyLong_FromUnsignedLongLong(*((quint64*)data));
149 case QMetaType::QByteArray: {
149 // implicit conversion from QByteArray to str has been removed:
150 QByteArray* v = (QByteArray*) data;
150 //case QMetaType::QByteArray: {
151 return PyString_FromStringAndSize(*v, v->size());
151 // QByteArray* v = (QByteArray*) data;
152 }
152 // return PyString_FromStringAndSize(*v, v->size());
153 // }
153 case QMetaType::QVariantMap:
154 case QMetaType::QVariantMap:
154 return PythonQtConv::QVariantMapToPyObject(*((QVariantMap*)data));
155 return PythonQtConv::QVariantMapToPyObject(*((QVariantMap*)data));
155 case QMetaType::QVariantList:
156 case QMetaType::QVariantList:
156 return PythonQtConv::QVariantListToPyObject(*((QVariantList*)data));
157 return PythonQtConv::QVariantListToPyObject(*((QVariantList*)data));
157 case QMetaType::QString:
158 case QMetaType::QString:
158 return PythonQtConv::QStringToPyObject(*((QString*)data));
159 return PythonQtConv::QStringToPyObject(*((QString*)data));
159 case QMetaType::QStringList:
160 case QMetaType::QStringList:
160 return PythonQtConv::QStringListToPyObject(*((QStringList*)data));
161 return PythonQtConv::QStringListToPyObject(*((QStringList*)data));
161
162
162 case PythonQtMethodInfo::Variant:
163 case PythonQtMethodInfo::Variant:
163 return PythonQtConv::QVariantToPyObject(*((QVariant*)data));
164 return PythonQtConv::QVariantToPyObject(*((QVariant*)data));
164 case QMetaType::QObjectStar:
165 case QMetaType::QObjectStar:
165 case QMetaType::QWidgetStar:
166 case QMetaType::QWidgetStar:
166 return PythonQt::priv()->wrapQObject(*((QObject**)data));
167 return PythonQt::priv()->wrapQObject(*((QObject**)data));
167
168
168 default:
169 default:
169 if (PythonQt::priv()->isPythonQtObjectPtrMetaId(type)) {
170 if (PythonQt::priv()->isPythonQtObjectPtrMetaId(type)) {
170 // special case, it is a PythonQtObjectPtr which contains a PyObject, take it directly:
171 // special case, it is a PythonQtObjectPtr which contains a PyObject, take it directly:
171 PyObject* o = ((PythonQtObjectPtr*)data)->object();
172 PyObject* o = ((PythonQtObjectPtr*)data)->object();
172 Py_INCREF(o);
173 Py_INCREF(o);
173 return o;
174 return o;
174 } else {
175 } else {
175 if (type > 0) {
176 if (type > 0) {
176 // if the type is known, we can construct it via QMetaType::construct
177 // if the type is known, we can construct it via QMetaType::construct
177 void* newCPPObject = QMetaType::construct(type, data);
178 void* newCPPObject = QMetaType::construct(type, data);
178 // XXX this could be optimized by using metatypeid directly
179 // XXX this could be optimized by using metatypeid directly
179 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)PythonQt::priv()->wrapPtr(newCPPObject, QMetaType::typeName(type));
180 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)PythonQt::priv()->wrapPtr(newCPPObject, QMetaType::typeName(type));
180 wrap->_ownedByPythonQt = true;
181 wrap->_ownedByPythonQt = true;
181 wrap->_useQMetaTypeDestroy = true;
182 wrap->_useQMetaTypeDestroy = true;
182 return (PyObject*)wrap;
183 return (PyObject*)wrap;
183 }
184 }
184 std::cerr << "Unknown type that can not be converted to Python: " << type << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
185 std::cerr << "Unknown type that can not be converted to Python: " << type << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
185 }
186 }
186 }
187 }
187 Py_INCREF(Py_None);
188 Py_INCREF(Py_None);
188 return Py_None;
189 return Py_None;
189 }
190 }
190
191
191 void* PythonQtConv::CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info) {
192 void* PythonQtConv::CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info) {
192 void* ptr = NULL;
193 void* ptr = NULL;
193 if (info.isPointer) {
194 if (info.isPointer) {
194 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
195 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
195 } else if (info.enumWrapper) {
196 } else if (info.enumWrapper) {
196 // create enum return value
197 // create enum return value
197 PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, ptr);
198 PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, ptr);
198 } else {
199 } else {
199 switch (info.typeId) {
200 switch (info.typeId) {
200 case QMetaType::Char:
201 case QMetaType::Char:
201 case QMetaType::UChar:
202 case QMetaType::UChar:
202 case QMetaType::Short:
203 case QMetaType::Short:
203 case QMetaType::UShort:
204 case QMetaType::UShort:
204 case QMetaType::Long:
205 case QMetaType::Long:
205 case QMetaType::ULong:
206 case QMetaType::ULong:
206 case QMetaType::Bool:
207 case QMetaType::Bool:
207 case QMetaType::Int:
208 case QMetaType::Int:
208 case QMetaType::UInt:
209 case QMetaType::UInt:
209 case QMetaType::QChar:
210 case QMetaType::QChar:
210 case QMetaType::Float:
211 case QMetaType::Float:
211 case QMetaType::Double:
212 case QMetaType::Double:
212 PythonQtValueStorage_ADD_VALUE(global_valueStorage, qint64, 0, ptr);
213 PythonQtValueStorage_ADD_VALUE(global_valueStorage, qint64, 0, ptr);
213 break;
214 break;
214 case PythonQtMethodInfo::Variant:
215 case PythonQtMethodInfo::Variant:
215 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, 0, ptr);
216 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, 0, ptr);
216 // return the ptr to the variant
217 // return the ptr to the variant
217 break;
218 break;
218 default:
219 default:
219 if (info.typeId == PythonQtMethodInfo::Unknown) {
220 if (info.typeId == PythonQtMethodInfo::Unknown) {
220 // check if we have a QList of pointers, which we can circumvent with a QList<void*>
221 // check if we have a QList of pointers, which we can circumvent with a QList<void*>
221 if (info.name.startsWith("QList<")) {
222 if (info.name.startsWith("QList<")) {
222 QByteArray innerType = info.name.mid(6,info.name.length()-7);
223 QByteArray innerType = info.name.mid(6,info.name.length()-7);
223 if (innerType.endsWith("*")) {
224 if (innerType.endsWith("*")) {
224 static int id = QMetaType::type("QList<void*>");
225 static int id = QMetaType::type("QList<void*>");
225 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr);
226 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr);
226 // return the constData pointer that will be filled with the result value later on
227 // return the constData pointer that will be filled with the result value later on
227 ptr = (void*)((QVariant*)ptr)->constData();
228 ptr = (void*)((QVariant*)ptr)->constData();
228 }
229 }
229 }
230 }
230 }
231 }
231
232
232 if (!ptr && info.typeId!=PythonQtMethodInfo::Unknown) {
233 if (!ptr && info.typeId!=PythonQtMethodInfo::Unknown) {
233 // everything else is stored in a QVariant, if we know the meta type...
234 // everything else is stored in a QVariant, if we know the meta type...
234 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
235 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
235 // return the constData pointer that will be filled with the result value later on
236 // return the constData pointer that will be filled with the result value later on
236 ptr = (void*)((QVariant*)ptr)->constData();
237 ptr = (void*)((QVariant*)ptr)->constData();
237 }
238 }
238 }
239 }
239 }
240 }
240 return ptr;
241 return ptr;
241 }
242 }
242
243
243 void* PythonQtConv::castWrapperTo(PythonQtInstanceWrapper* wrapper, const QByteArray& className, bool& ok)
244 void* PythonQtConv::castWrapperTo(PythonQtInstanceWrapper* wrapper, const QByteArray& className, bool& ok)
244 {
245 {
245 void* object;
246 void* object;
246 if (wrapper->classInfo()->isCPPWrapper()) {
247 if (wrapper->classInfo()->isCPPWrapper()) {
247 object = wrapper->_wrappedPtr;
248 object = wrapper->_wrappedPtr;
248 } else {
249 } else {
249 QObject* tmp = wrapper->_obj;
250 QObject* tmp = wrapper->_obj;
250 object = tmp;
251 object = tmp;
251 }
252 }
252 if (object) {
253 if (object) {
253 // if we can be upcasted to the given name, we pass the casted pointer in:
254 // if we can be upcasted to the given name, we pass the casted pointer in:
254 object = wrapper->classInfo()->castTo(object, className);
255 object = wrapper->classInfo()->castTo(object, className);
255 ok = object!=NULL;
256 ok = object!=NULL;
256 } else {
257 } else {
257 // if it is a NULL ptr, we need to check if it inherits, so that we might pass the NULL ptr
258 // if it is a NULL ptr, we need to check if it inherits, so that we might pass the NULL ptr
258 ok = wrapper->classInfo()->inherits(className);
259 ok = wrapper->classInfo()->inherits(className);
259 }
260 }
260 return object;
261 return object;
261 }
262 }
262
263
263 void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject)
264 void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject)
264 {
265 {
265 void* ptr = alreadyAllocatedCPPObject;
266 void* ptr = alreadyAllocatedCPPObject;
266
267
267 static int penId = QMetaType::type("QPen");
268 static int penId = QMetaType::type("QPen");
268 static int brushId = QMetaType::type("QBrush");
269 static int brushId = QMetaType::type("QBrush");
269 static int cursorId = QMetaType::type("QCursor");
270 static int cursorId = QMetaType::type("QCursor");
270 static int colorId = QMetaType::type("QColor");
271 static int colorId = QMetaType::type("QColor");
271 static PyObject* qtGlobalColorEnum = PythonQtClassInfo::findEnumWrapper("Qt::GlobalColor", NULL);
272 static PyObject* qtGlobalColorEnum = PythonQtClassInfo::findEnumWrapper("Qt::GlobalColor", NULL);
272 if (typeId == cursorId) {
273 if (typeId == cursorId) {
273 static PyObject* qtCursorShapeEnum = PythonQtClassInfo::findEnumWrapper("Qt::CursorShape", NULL);
274 static PyObject* qtCursorShapeEnum = PythonQtClassInfo::findEnumWrapper("Qt::CursorShape", NULL);
274 if ((PyObject*)obj->ob_type == qtCursorShapeEnum) {
275 if ((PyObject*)obj->ob_type == qtCursorShapeEnum) {
275 Qt::CursorShape val = (Qt::CursorShape)PyInt_AS_LONG(obj);
276 Qt::CursorShape val = (Qt::CursorShape)PyInt_AS_LONG(obj);
276 if (!ptr) {
277 if (!ptr) {
277 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QCursor(), ptr);
278 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QCursor(), ptr);
278 ptr = (void*)((QVariant*)ptr)->constData();
279 ptr = (void*)((QVariant*)ptr)->constData();
279 }
280 }
280 *((QCursor*)ptr) = QCursor(val);
281 *((QCursor*)ptr) = QCursor(val);
281 return ptr;
282 return ptr;
282 }
283 }
283 } else if (typeId == penId) {
284 } else if (typeId == penId) {
284 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
285 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
285 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
286 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
286 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
287 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
287 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
288 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
288 if (!ptr) {
289 if (!ptr) {
289 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
290 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
290 ptr = (void*)((QVariant*)ptr)->constData();
291 ptr = (void*)((QVariant*)ptr)->constData();
291 }
292 }
292 *((QPen*)ptr) = QPen(QColor(val));
293 *((QPen*)ptr) = QPen(QColor(val));
293 return ptr;
294 return ptr;
294 } else if ((PyObject*)obj->ob_type == qtColorClass) {
295 } else if ((PyObject*)obj->ob_type == qtColorClass) {
295 if (!ptr) {
296 if (!ptr) {
296 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
297 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
297 ptr = (void*)((QVariant*)ptr)->constData();
298 ptr = (void*)((QVariant*)ptr)->constData();
298 }
299 }
299 *((QPen*)ptr) = QPen(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
300 *((QPen*)ptr) = QPen(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
300 return ptr;
301 return ptr;
301 }
302 }
302 } else if (typeId == brushId) {
303 } else if (typeId == brushId) {
303 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
304 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
304 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
305 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
305 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
306 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
306 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
307 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
307 if (!ptr) {
308 if (!ptr) {
308 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
309 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
309 ptr = (void*)((QVariant*)ptr)->constData();
310 ptr = (void*)((QVariant*)ptr)->constData();
310 }
311 }
311 *((QBrush*)ptr) = QBrush(QColor(val));
312 *((QBrush*)ptr) = QBrush(QColor(val));
312 return ptr;
313 return ptr;
313 } else if ((PyObject*)obj->ob_type == qtColorClass) {
314 } else if ((PyObject*)obj->ob_type == qtColorClass) {
314 if (!ptr) {
315 if (!ptr) {
315 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
316 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
316 ptr = (void*)((QVariant*)ptr)->constData();
317 ptr = (void*)((QVariant*)ptr)->constData();
317 }
318 }
318 *((QBrush*)ptr) = QBrush(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
319 *((QBrush*)ptr) = QBrush(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
319 return ptr;
320 return ptr;
320 }
321 }
321 } else if (typeId == colorId) {
322 } else if (typeId == colorId) {
322 // colors can be created from Qt::GlobalColor (and from colors, but that's the default)
323 // colors can be created from Qt::GlobalColor (and from colors, but that's the default)
323 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
324 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
324 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
325 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
325 if (!ptr) {
326 if (!ptr) {
326 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QColor(), ptr);
327 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QColor(), ptr);
327 ptr = (void*)((QVariant*)ptr)->constData();
328 ptr = (void*)((QVariant*)ptr)->constData();
328 }
329 }
329 *((QColor*)ptr) = QColor(val);
330 *((QColor*)ptr) = QColor(val);
330 return ptr;
331 return ptr;
331 }
332 }
332 }
333 }
333 return NULL;
334 return NULL;
334 }
335 }
335
336
336 void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* /*classInfo*/, void* alreadyAllocatedCPPObject)
337 void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* /*classInfo*/, void* alreadyAllocatedCPPObject)
337 {
338 {
338 bool ok = false;
339 bool ok = false;
339 void* ptr = NULL;
340 void* ptr = NULL;
340
341
341 // autoconversion of QPen/QBrush/QCursor/QColor from different type
342 // autoconversion of QPen/QBrush/QCursor/QColor from different type
342 if (!info.isPointer && !strict) {
343 if (!info.isPointer && !strict) {
343 ptr = handlePythonToQtAutoConversion(info.typeId, obj, alreadyAllocatedCPPObject);
344 ptr = handlePythonToQtAutoConversion(info.typeId, obj, alreadyAllocatedCPPObject);
344 if (ptr) {
345 if (ptr) {
345 return ptr;
346 return ptr;
346 }
347 }
347 }
348 }
348
349
349 if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) && info.typeId != PythonQtMethodInfo::Variant) {
350 if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) && info.typeId != PythonQtMethodInfo::Variant) {
350 // if we have a Qt wrapper object and if we do not need a QVariant, we do the following:
351 // if we have a Qt wrapper object and if we do not need a QVariant, we do the following:
351 // (the Variant case is handled below in a switch)
352 // (the Variant case is handled below in a switch)
352
353
353 // a C++ wrapper (can be passed as pointer or reference)
354 // a C++ wrapper (can be passed as pointer or reference)
354 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)obj;
355 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)obj;
355 void* object = castWrapperTo(wrap, info.name, ok);
356 void* object = castWrapperTo(wrap, info.name, ok);
356 if (ok) {
357 if (ok) {
357 if (info.isPointer) {
358 if (info.isPointer) {
358 // store the wrapped pointer in an extra pointer and let ptr point to the extra pointer
359 // store the wrapped pointer in an extra pointer and let ptr point to the extra pointer
359 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, object, ptr);
360 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, object, ptr);
360 } else {
361 } else {
361 // store the wrapped pointer directly, since we are a reference
362 // store the wrapped pointer directly, since we are a reference
362 ptr = object;
363 ptr = object;
363 }
364 }
364 } else {
365 } else {
365 // not matching
366 // not matching
366 }
367 }
367 } else if (info.isPointer) {
368 } else if (info.isPointer) {
368 // a pointer
369 // a pointer
369 if (info.typeId == QMetaType::Char || info.typeId == QMetaType::UChar)
370 if (info.typeId == QMetaType::Char || info.typeId == QMetaType::UChar)
370 {
371 {
371 QString str = PyObjGetString(obj, strict, ok);
372 QString str = PyObjGetString(obj, strict, ok);
372 if (ok) {
373 if (ok) {
373 void* ptr2 = NULL;
374 void* ptr2 = NULL;
374 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str.toUtf8()), ptr2);
375 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str.toUtf8()), ptr2);
375 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr);
376 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr);
376 }
377 }
377 } else if (info.name == "PyObject") {
378 } else if (info.name == "PyObject") {
378 // handle low level PyObject directly
379 // handle low level PyObject directly
379 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, obj, ptr);
380 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, obj, ptr);
380 } else if (obj == Py_None) {
381 } else if (obj == Py_None) {
381 // None is treated as a NULL ptr
382 // None is treated as a NULL ptr
382 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
383 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
383 } else {
384 } else {
384 // if we are not strict, we try if we are passed a 0 integer
385 // if we are not strict, we try if we are passed a 0 integer
385 if (!strict) {
386 if (!strict) {
386 bool ok;
387 bool ok;
387 int value = PyObjGetInt(obj, true, ok);
388 int value = PyObjGetInt(obj, true, ok);
388 if (ok && value==0) {
389 if (ok && value==0) {
389 // TODOXXX is this wise? or should it be expected from the programmer to use None?
390 // TODOXXX is this wise? or should it be expected from the programmer to use None?
390 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
391 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
391 }
392 }
392 }
393 }
393 }
394 }
394 } else {
395 } else {
395 // not a pointer
396 // not a pointer
396 switch (info.typeId) {
397 switch (info.typeId) {
397 case QMetaType::Char:
398 case QMetaType::Char:
398 {
399 {
399 int val = PyObjGetInt(obj, strict, ok);
400 int val = PyObjGetInt(obj, strict, ok);
400 if (ok) {
401 if (ok) {
401 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, char, val, ptr);
402 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, char, val, ptr);
402 }
403 }
403 }
404 }
404 break;
405 break;
405 case QMetaType::UChar:
406 case QMetaType::UChar:
406 {
407 {
407 int val = PyObjGetInt(obj, strict, ok);
408 int val = PyObjGetInt(obj, strict, ok);
408 if (ok) {
409 if (ok) {
409 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned char, val, ptr);
410 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned char, val, ptr);
410 }
411 }
411 }
412 }
412 break;
413 break;
413 case QMetaType::Short:
414 case QMetaType::Short:
414 {
415 {
415 int val = PyObjGetInt(obj, strict, ok);
416 int val = PyObjGetInt(obj, strict, ok);
416 if (ok) {
417 if (ok) {
417 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
418 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
418 }
419 }
419 }
420 }
420 break;
421 break;
421 case QMetaType::UShort:
422 case QMetaType::UShort:
422 {
423 {
423 int val = PyObjGetInt(obj, strict, ok);
424 int val = PyObjGetInt(obj, strict, ok);
424 if (ok) {
425 if (ok) {
425 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned short, val, ptr);
426 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned short, val, ptr);
426 }
427 }
427 }
428 }
428 break;
429 break;
429 case QMetaType::Long:
430 case QMetaType::Long:
430 {
431 {
431 long val = (long)PyObjGetLongLong(obj, strict, ok);
432 long val = (long)PyObjGetLongLong(obj, strict, ok);
432 if (ok) {
433 if (ok) {
433 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, long, val, ptr);
434 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, long, val, ptr);
434 }
435 }
435 }
436 }
436 break;
437 break;
437 case QMetaType::ULong:
438 case QMetaType::ULong:
438 {
439 {
439 unsigned long val = (unsigned long)PyObjGetLongLong(obj, strict, ok);
440 unsigned long val = (unsigned long)PyObjGetLongLong(obj, strict, ok);
440 if (ok) {
441 if (ok) {
441 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned long, val, ptr);
442 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned long, val, ptr);
442 }
443 }
443 }
444 }
444 break;
445 break;
445 case QMetaType::Bool:
446 case QMetaType::Bool:
446 {
447 {
447 bool val = PyObjGetBool(obj, strict, ok);
448 bool val = PyObjGetBool(obj, strict, ok);
448 if (ok) {
449 if (ok) {
449 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, bool, val, ptr);
450 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, bool, val, ptr);
450 }
451 }
451 }
452 }
452 break;
453 break;
453 case QMetaType::Int:
454 case QMetaType::Int:
454 {
455 {
455 int val = PyObjGetInt(obj, strict, ok);
456 int val = PyObjGetInt(obj, strict, ok);
456 if (ok) {
457 if (ok) {
457 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, int, val, ptr);
458 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, int, val, ptr);
458 }
459 }
459 }
460 }
460 break;
461 break;
461 case QMetaType::UInt:
462 case QMetaType::UInt:
462 {
463 {
463 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
464 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
464 if (ok) {
465 if (ok) {
465 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
466 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
466 }
467 }
467 }
468 }
468 break;
469 break;
469 case QMetaType::QChar:
470 case QMetaType::QChar:
470 {
471 {
471 int val = PyObjGetInt(obj, strict, ok);
472 int val = PyObjGetInt(obj, strict, ok);
472 if (ok) {
473 if (ok) {
473 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
474 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
474 }
475 }
475 }
476 }
476 break;
477 break;
477 case QMetaType::Float:
478 case QMetaType::Float:
478 {
479 {
479 float val = (float)PyObjGetDouble(obj, strict, ok);
480 float val = (float)PyObjGetDouble(obj, strict, ok);
480 if (ok) {
481 if (ok) {
481 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, float, val, ptr);
482 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, float, val, ptr);
482 }
483 }
483 }
484 }
484 break;
485 break;
485 case QMetaType::Double:
486 case QMetaType::Double:
486 {
487 {
487 double val = (double)PyObjGetDouble(obj, strict, ok);
488 double val = (double)PyObjGetDouble(obj, strict, ok);
488 if (ok) {
489 if (ok) {
489 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, double, val, ptr);
490 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, double, val, ptr);
490 }
491 }
491 }
492 }
492 break;
493 break;
493 case QMetaType::LongLong:
494 case QMetaType::LongLong:
494 {
495 {
495 qint64 val = PyObjGetLongLong(obj, strict, ok);
496 qint64 val = PyObjGetLongLong(obj, strict, ok);
496 if (ok) {
497 if (ok) {
497 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, qint64, val, ptr);
498 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, qint64, val, ptr);
498 }
499 }
499 }
500 }
500 break;
501 break;
501 case QMetaType::ULongLong:
502 case QMetaType::ULongLong:
502 {
503 {
503 quint64 val = PyObjGetULongLong(obj, strict, ok);
504 quint64 val = PyObjGetULongLong(obj, strict, ok);
504 if (ok) {
505 if (ok) {
505 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, quint64, val, ptr);
506 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, quint64, val, ptr);
506 }
507 }
507 }
508 }
508 break;
509 break;
509 case QMetaType::QByteArray:
510 case QMetaType::QByteArray:
510 {
511 {
511 QByteArray bytes = PyObjGetBytes(obj, strict, ok);
512 QByteArray bytes = PyObjGetBytes(obj, strict, ok);
512 if (ok) {
513 if (ok) {
513 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(bytes), ptr);
514 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(bytes), ptr);
514 ptr = (void*)((QVariant*)ptr)->constData();
515 ptr = (void*)((QVariant*)ptr)->constData();
515 }
516 }
516 }
517 }
517 break;
518 break;
518 case QMetaType::QString:
519 case QMetaType::QString:
519 {
520 {
520 QString str = PyObjGetString(obj, strict, ok);
521 QString str = PyObjGetString(obj, strict, ok);
521 if (ok) {
522 if (ok) {
522 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str), ptr);
523 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str), ptr);
523 ptr = (void*)((QVariant*)ptr)->constData();
524 ptr = (void*)((QVariant*)ptr)->constData();
524 }
525 }
525 }
526 }
526 break;
527 break;
527 case QMetaType::QStringList:
528 case QMetaType::QStringList:
528 {
529 {
529 QStringList l = PyObjToStringList(obj, strict, ok);
530 QStringList l = PyObjToStringList(obj, strict, ok);
530 if (ok) {
531 if (ok) {
531 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(l), ptr);
532 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(l), ptr);
532 ptr = (void*)((QVariant*)ptr)->constData();
533 ptr = (void*)((QVariant*)ptr)->constData();
533 }
534 }
534 }
535 }
535 break;
536 break;
536
537
537 case PythonQtMethodInfo::Variant:
538 case PythonQtMethodInfo::Variant:
538 {
539 {
539 QVariant v = PyObjToQVariant(obj);
540 QVariant v = PyObjToQVariant(obj);
540 // the only case where conversion can fail it None and we want to pass that to, e.g. setProperty(),
541 // the only case where conversion can fail it None and we want to pass that to, e.g. setProperty(),
541 // so we do not check v.isValid() here
542 // so we do not check v.isValid() here
542 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
543 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
543 }
544 }
544 break;
545 break;
545 default:
546 default:
546 {
547 {
547 // check for enum case
548 // check for enum case
548 if (info.enumWrapper) {
549 if (info.enumWrapper) {
549 unsigned int val;
550 unsigned int val;
550 ok = false;
551 ok = false;
551 if ((PyObject*)obj->ob_type == info.enumWrapper) {
552 if ((PyObject*)obj->ob_type == info.enumWrapper) {
552 // we have a exact enum type match:
553 // we have a exact enum type match:
553 val = PyInt_AS_LONG(obj);
554 val = PyInt_AS_LONG(obj);
554 ok = true;
555 ok = true;
555 } else if (!strict) {
556 } else if (!strict) {
556 // we try to get any integer, when not being strict. If we are strict, integers are not wanted because
557 // we try to get any integer, when not being strict. If we are strict, integers are not wanted because
557 // we want an integer overload to be taken first!
558 // we want an integer overload to be taken first!
558 val = (unsigned int)PyObjGetLongLong(obj, false, ok);
559 val = (unsigned int)PyObjGetLongLong(obj, false, ok);
559 }
560 }
560 if (ok) {
561 if (ok) {
561 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
562 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
562 return ptr;
563 return ptr;
563 } else {
564 } else {
564 return NULL;
565 return NULL;
565 }
566 }
566 }
567 }
567
568
568 if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
569 if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
569 // check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant
570 // check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant
570 if (info.name.startsWith("QList<")) {
571 if (info.name.startsWith("QList<")) {
571 QByteArray innerType = info.name.mid(6,info.name.length()-7);
572 QByteArray innerType = info.name.mid(6,info.name.length()-7);
572 if (innerType.endsWith("*")) {
573 if (innerType.endsWith("*")) {
573 innerType.truncate(innerType.length()-1);
574 innerType.truncate(innerType.length()-1);
574 static int id = QMetaType::type("QList<void*>");
575 static int id = QMetaType::type("QList<void*>");
575 if (!alreadyAllocatedCPPObject) {
576 if (!alreadyAllocatedCPPObject) {
576 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(id), ptr);
577 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(id), ptr);
577 ptr = (void*)((QVariant*)ptr)->constData();
578 ptr = (void*)((QVariant*)ptr)->constData();
578 } else {
579 } else {
579 ptr = alreadyAllocatedCPPObject;
580 ptr = alreadyAllocatedCPPObject;
580 }
581 }
581 ok = ConvertPythonListToQListOfPointerType(obj, (QList<void*>*)ptr, innerType, strict);
582 ok = ConvertPythonListToQListOfPointerType(obj, (QList<void*>*)ptr, innerType, strict);
582 if (ok) {
583 if (ok) {
583 return ptr;
584 return ptr;
584 } else {
585 } else {
585 return NULL;
586 return NULL;
586 }
587 }
587 }
588 }
588 }
589 }
589 }
590 }
590
591
591 // We only do this for registered type > QMetaType::User for performance reasons.
592 // We only do this for registered type > QMetaType::User for performance reasons.
592 if (info.typeId >= QMetaType::User) {
593 if (info.typeId >= QMetaType::User) {
593 // Maybe we have a special converter that is registered for that type:
594 // Maybe we have a special converter that is registered for that type:
594 PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(info.typeId);
595 PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(info.typeId);
595 if (converter) {
596 if (converter) {
596 if (!alreadyAllocatedCPPObject) {
597 if (!alreadyAllocatedCPPObject) {
597 // create a new empty variant of concrete type:
598 // create a new empty variant of concrete type:
598 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
599 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
599 ptr = (void*)((QVariant*)ptr)->constData();
600 ptr = (void*)((QVariant*)ptr)->constData();
600 } else {
601 } else {
601 ptr = alreadyAllocatedCPPObject;
602 ptr = alreadyAllocatedCPPObject;
602 }
603 }
603 // now call the converter, passing the internal object of the variant
604 // now call the converter, passing the internal object of the variant
604 ok = (*converter)(obj, ptr, info.typeId, strict);
605 ok = (*converter)(obj, ptr, info.typeId, strict);
605 if (ok) {
606 if (ok) {
606 return ptr;
607 return ptr;
607 } else {
608 } else {
608 return NULL;
609 return NULL;
609 }
610 }
610 }
611 }
611 }
612 }
612 // if no type id is available, conversion to a QVariant makes no sense/is not possible
613 // if no type id is available, conversion to a QVariant makes no sense/is not possible
613 if (info.typeId != PythonQtMethodInfo::Unknown) {
614 if (info.typeId != PythonQtMethodInfo::Unknown) {
614 // for all other types, we use the same qvariant conversion and pass out the constData of the variant:
615 // for all other types, we use the same qvariant conversion and pass out the constData of the variant:
615 QVariant v = PyObjToQVariant(obj, info.typeId);
616 QVariant v = PyObjToQVariant(obj, info.typeId);
616 if (v.isValid()) {
617 if (v.isValid()) {
617 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
618 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
618 ptr = (void*)((QVariant*)ptr)->constData();
619 ptr = (void*)((QVariant*)ptr)->constData();
619 }
620 }
620 }
621 }
621 }
622 }
622 }
623 }
623 }
624 }
624 return ptr;
625 return ptr;
625 }
626 }
626
627
627
628
628 QStringList PythonQtConv::PyObjToStringList(PyObject* val, bool strict, bool& ok) {
629 QStringList PythonQtConv::PyObjToStringList(PyObject* val, bool strict, bool& ok) {
629 QStringList v;
630 QStringList v;
630 ok = false;
631 ok = false;
631 // if we are strict, we do not want to convert a string to a stringlist
632 // if we are strict, we do not want to convert a string to a stringlist
632 // (strings in python are detected to be sequences)
633 // (strings in python are detected to be sequences)
633 if (strict &&
634 if (strict &&
634 (val->ob_type == &PyString_Type ||
635 (val->ob_type == &PyString_Type ||
635 PyUnicode_Check(val))) {
636 PyUnicode_Check(val))) {
636 ok = false;
637 ok = false;
637 return v;
638 return v;
638 }
639 }
639 if (PySequence_Check(val)) {
640 if (PySequence_Check(val)) {
640 int count = PySequence_Size(val);
641 int count = PySequence_Size(val);
641 for (int i = 0;i<count;i++) {
642 for (int i = 0;i<count;i++) {
642 PyObject* value = PySequence_GetItem(val,i);
643 PyObject* value = PySequence_GetItem(val,i);
643 v.append(PyObjGetString(value,false,ok));
644 v.append(PyObjGetString(value,false,ok));
644 }
645 }
645 ok = true;
646 ok = true;
646 }
647 }
647 return v;
648 return v;
648 }
649 }
649
650
650 QString PythonQtConv::PyObjGetRepresentation(PyObject* val)
651 QString PythonQtConv::PyObjGetRepresentation(PyObject* val)
651 {
652 {
652 QString r;
653 QString r;
653 PyObject* str = PyObject_Repr(val);
654 PyObject* str = PyObject_Repr(val);
654 if (str) {
655 if (str) {
655 r = QString(PyString_AS_STRING(str));
656 r = QString(PyString_AS_STRING(str));
656 Py_DECREF(str);
657 Py_DECREF(str);
657 }
658 }
658 return r;
659 return r;
659 }
660 }
660
661
661 QString PythonQtConv::PyObjGetString(PyObject* val, bool strict, bool& ok) {
662 QString PythonQtConv::PyObjGetString(PyObject* val, bool strict, bool& ok) {
662 QString r;
663 QString r;
663 ok = true;
664 ok = true;
664 if (val->ob_type == &PyString_Type) {
665 if (val->ob_type == &PyString_Type) {
665 r = QString(PyString_AS_STRING(val));
666 r = QString(PyString_AS_STRING(val));
666 } else if (PyUnicode_Check(val)) {
667 } else if (PyUnicode_Check(val)) {
667 #ifdef WIN32
668 #ifdef WIN32
668 r = QString::fromUtf16(PyUnicode_AS_UNICODE(val));
669 r = QString::fromUtf16(PyUnicode_AS_UNICODE(val));
669 #else
670 #else
670 PyObject *ptmp = PyUnicode_AsUTF8String(val);
671 PyObject *ptmp = PyUnicode_AsUTF8String(val);
671 if(ptmp) {
672 if(ptmp) {
672 r = QString::fromUtf8(PyString_AS_STRING(ptmp));
673 r = QString::fromUtf8(PyString_AS_STRING(ptmp));
673 Py_DECREF(ptmp);
674 Py_DECREF(ptmp);
674 }
675 }
675 #endif
676 #endif
676 } else if (!strict) {
677 } else if (!strict) {
677 // EXTRA: could also use _Unicode, but why should we?
678 // EXTRA: could also use _Unicode, but why should we?
678 PyObject* str = PyObject_Str(val);
679 PyObject* str = PyObject_Str(val);
679 if (str) {
680 if (str) {
680 r = QString(PyString_AS_STRING(str));
681 r = QString(PyString_AS_STRING(str));
681 Py_DECREF(str);
682 Py_DECREF(str);
682 } else {
683 } else {
683 ok = false;
684 ok = false;
684 }
685 }
685 } else {
686 } else {
686 ok = false;
687 ok = false;
687 }
688 }
688 return r;
689 return r;
689 }
690 }
690
691
691 QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) {
692 QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) {
693 // TODO: support buffer objects in general
692 QByteArray r;
694 QByteArray r;
693 ok = true;
695 ok = true;
694 if (val->ob_type == &PyString_Type) {
696 if (val->ob_type == &PyString_Type) {
695 long size = PyString_GET_SIZE(val);
697 long size = PyString_GET_SIZE(val);
696 r = QByteArray(PyString_AS_STRING(val), size);
698 r = QByteArray(PyString_AS_STRING(val), size);
697 } else {
699 } else {
698 ok = false;
700 ok = false;
699 }
701 }
700 return r;
702 return r;
701 }
703 }
702
704
703 bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) {
705 bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) {
704 bool d = false;
706 bool d = false;
705 ok = false;
707 ok = false;
706 if (val == Py_False) {
708 if (val == Py_False) {
707 d = false;
709 d = false;
708 ok = true;
710 ok = true;
709 } else if (val == Py_True) {
711 } else if (val == Py_True) {
710 d = true;
712 d = true;
711 ok = true;
713 ok = true;
712 } else if (!strict) {
714 } else if (!strict) {
713 d = PyObjGetInt(val, false, ok)!=0;
715 d = PyObjGetInt(val, false, ok)!=0;
714 ok = true;
716 ok = true;
715 }
717 }
716 return d;
718 return d;
717 }
719 }
718
720
719 int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) {
721 int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) {
720 int d = 0;
722 int d = 0;
721 ok = true;
723 ok = true;
722 if (val->ob_type == &PyInt_Type) {
724 if (val->ob_type == &PyInt_Type) {
723 d = PyInt_AS_LONG(val);
725 d = PyInt_AS_LONG(val);
724 } else if (!strict) {
726 } else if (!strict) {
725 if (PyObject_TypeCheck(val, &PyInt_Type)) {
727 if (PyObject_TypeCheck(val, &PyInt_Type)) {
726 // support for derived int classes, e.g. for our enums
728 // support for derived int classes, e.g. for our enums
727 d = PyInt_AS_LONG(val);
729 d = PyInt_AS_LONG(val);
728 } else if (val->ob_type == &PyFloat_Type) {
730 } else if (val->ob_type == &PyFloat_Type) {
729 d = floor(PyFloat_AS_DOUBLE(val));
731 d = floor(PyFloat_AS_DOUBLE(val));
730 } else if (val->ob_type == &PyLong_Type) {
732 } else if (val->ob_type == &PyLong_Type) {
731 // handle error on overflow!
733 // handle error on overflow!
732 d = PyLong_AsLong(val);
734 d = PyLong_AsLong(val);
733 } else if (val == Py_False) {
735 } else if (val == Py_False) {
734 d = 0;
736 d = 0;
735 } else if (val == Py_True) {
737 } else if (val == Py_True) {
736 d = 1;
738 d = 1;
737 } else {
739 } else {
738 ok = false;
740 ok = false;
739 }
741 }
740 } else {
742 } else {
741 ok = false;
743 ok = false;
742 }
744 }
743 return d;
745 return d;
744 }
746 }
745
747
746 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
748 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
747 qint64 d = 0;
749 qint64 d = 0;
748 ok = true;
750 ok = true;
749 if (val->ob_type == &PyInt_Type) {
751 if (val->ob_type == &PyInt_Type) {
750 d = PyInt_AS_LONG(val);
752 d = PyInt_AS_LONG(val);
751 } else if (val->ob_type == &PyLong_Type) {
753 } else if (val->ob_type == &PyLong_Type) {
752 d = PyLong_AsLongLong(val);
754 d = PyLong_AsLongLong(val);
753 } else if (!strict) {
755 } else if (!strict) {
754 if (PyObject_TypeCheck(val, &PyInt_Type)) {
756 if (PyObject_TypeCheck(val, &PyInt_Type)) {
755 // support for derived int classes, e.g. for our enums
757 // support for derived int classes, e.g. for our enums
756 d = PyInt_AS_LONG(val);
758 d = PyInt_AS_LONG(val);
757 } else if (val->ob_type == &PyFloat_Type) {
759 } else if (val->ob_type == &PyFloat_Type) {
758 d = floor(PyFloat_AS_DOUBLE(val));
760 d = floor(PyFloat_AS_DOUBLE(val));
759 } else if (val == Py_False) {
761 } else if (val == Py_False) {
760 d = 0;
762 d = 0;
761 } else if (val == Py_True) {
763 } else if (val == Py_True) {
762 d = 1;
764 d = 1;
763 } else {
765 } else {
764 ok = false;
766 ok = false;
765 }
767 }
766 } else {
768 } else {
767 ok = false;
769 ok = false;
768 }
770 }
769 return d;
771 return d;
770 }
772 }
771
773
772 quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) {
774 quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) {
773 quint64 d = 0;
775 quint64 d = 0;
774 ok = true;
776 ok = true;
775 if (PyObject_TypeCheck(val, &PyInt_Type)) {
777 if (PyObject_TypeCheck(val, &PyInt_Type)) {
776 d = PyInt_AS_LONG(val);
778 d = PyInt_AS_LONG(val);
777 } else if (val->ob_type == &PyLong_Type) {
779 } else if (val->ob_type == &PyLong_Type) {
778 d = PyLong_AsLongLong(val);
780 d = PyLong_AsLongLong(val);
779 } else if (!strict) {
781 } else if (!strict) {
780 if (PyObject_TypeCheck(val, &PyInt_Type)) {
782 if (PyObject_TypeCheck(val, &PyInt_Type)) {
781 // support for derived int classes, e.g. for our enums
783 // support for derived int classes, e.g. for our enums
782 d = PyInt_AS_LONG(val);
784 d = PyInt_AS_LONG(val);
783 } else if (val->ob_type == &PyFloat_Type) {
785 } else if (val->ob_type == &PyFloat_Type) {
784 d = floor(PyFloat_AS_DOUBLE(val));
786 d = floor(PyFloat_AS_DOUBLE(val));
785 } else if (val == Py_False) {
787 } else if (val == Py_False) {
786 d = 0;
788 d = 0;
787 } else if (val == Py_True) {
789 } else if (val == Py_True) {
788 d = 1;
790 d = 1;
789 } else {
791 } else {
790 ok = false;
792 ok = false;
791 }
793 }
792 } else {
794 } else {
793 ok = false;
795 ok = false;
794 }
796 }
795 return d;
797 return d;
796 }
798 }
797
799
798 double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) {
800 double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) {
799 double d = 0;
801 double d = 0;
800 ok = true;
802 ok = true;
801 if (val->ob_type == &PyFloat_Type) {
803 if (val->ob_type == &PyFloat_Type) {
802 d = PyFloat_AS_DOUBLE(val);
804 d = PyFloat_AS_DOUBLE(val);
803 } else if (!strict) {
805 } else if (!strict) {
804 if (PyObject_TypeCheck(val, &PyInt_Type)) {
806 if (PyObject_TypeCheck(val, &PyInt_Type)) {
805 d = PyInt_AS_LONG(val);
807 d = PyInt_AS_LONG(val);
806 } else if (val->ob_type == &PyLong_Type) {
808 } else if (val->ob_type == &PyLong_Type) {
807 d = PyLong_AsLong(val);
809 d = PyLong_AsLong(val);
808 } else if (val == Py_False) {
810 } else if (val == Py_False) {
809 d = 0;
811 d = 0;
810 } else if (val == Py_True) {
812 } else if (val == Py_True) {
811 d = 1;
813 d = 1;
812 } else {
814 } else {
813 ok = false;
815 ok = false;
814 }
816 }
815 } else {
817 } else {
816 ok = false;
818 ok = false;
817 }
819 }
818 return d;
820 return d;
819 }
821 }
820
822
821 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
823 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
822 {
824 {
823 QVariant v;
825 QVariant v;
824 bool ok = true;
826 bool ok = true;
825
827
826 if (type==-1) {
828 if (type==-1) {
827 // no special type requested
829 // no special type requested
828 if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) {
830 if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) {
829 type = QVariant::String;
831 type = QVariant::String;
830 } else if (PyObject_TypeCheck(val, &PyInt_Type)) {
832 } else if (PyObject_TypeCheck(val, &PyInt_Type)) {
831 type = QVariant::Int;
833 type = QVariant::Int;
832 } else if (val->ob_type==&PyLong_Type) {
834 } else if (val->ob_type==&PyLong_Type) {
833 type = QVariant::LongLong;
835 type = QVariant::LongLong;
834 } else if (val->ob_type==&PyFloat_Type) {
836 } else if (val->ob_type==&PyFloat_Type) {
835 type = QVariant::Double;
837 type = QVariant::Double;
836 } else if (val == Py_False || val == Py_True) {
838 } else if (val == Py_False || val == Py_True) {
837 type = QVariant::Bool;
839 type = QVariant::Bool;
838 } else if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
840 } else if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
839 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
841 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
840 // c++ wrapper, check if the class names of the c++ objects match
842 // c++ wrapper, check if the class names of the c++ objects match
841 if (wrap->classInfo()->isCPPWrapper()) {
843 if (wrap->classInfo()->isCPPWrapper()) {
842 if (wrap->classInfo()->metaTypeId()>0) {
844 if (wrap->classInfo()->metaTypeId()>0) {
843 // construct a new variant from the C++ object if it has a meta type (this will COPY the object!)
845 // construct a new variant from the C++ object if it has a meta type (this will COPY the object!)
844 v = QVariant(wrap->classInfo()->metaTypeId(), wrap->_wrappedPtr);
846 v = QVariant(wrap->classInfo()->metaTypeId(), wrap->_wrappedPtr);
845 } else {
847 } else {
846 // TODOXXX we could as well check if there is a registered meta type for "classname*", so that we may pass
848 // TODOXXX we could as well check if there is a registered meta type for "classname*", so that we may pass
847 // the pointer here...
849 // the pointer here...
848 // is this worth anything? we loose the knowledge of the cpp object type
850 // is this worth anything? we loose the knowledge of the cpp object type
849 v = qVariantFromValue(wrap->_wrappedPtr);
851 v = qVariantFromValue(wrap->_wrappedPtr);
850 }
852 }
851 } else {
853 } else {
852 // this gives us a QObject pointer
854 // this gives us a QObject pointer
853 QObject* myObject = wrap->_obj;
855 QObject* myObject = wrap->_obj;
854 v = qVariantFromValue(myObject);
856 v = qVariantFromValue(myObject);
855 }
857 }
856 return v;
858 return v;
857 } else if (val->ob_type==&PyDict_Type) {
859 } else if (val->ob_type==&PyDict_Type) {
858 type = QVariant::Map;
860 type = QVariant::Map;
859 } else if (val->ob_type==&PyList_Type || val->ob_type==&PyTuple_Type || PySequence_Check(val)) {
861 } else if (val->ob_type==&PyList_Type || val->ob_type==&PyTuple_Type || PySequence_Check(val)) {
860 type = QVariant::List;
862 type = QVariant::List;
861 } else if (val == Py_None) {
863 } else if (val == Py_None) {
862 // none is invalid
864 // none is invalid
863 type = QVariant::Invalid;
865 type = QVariant::Invalid;
864 } else {
866 } else {
865 // this used to be:
867 // this used to be:
866 // type = QVariant::String;
868 // type = QVariant::String;
867 // but now we want to transport the Python Objects directly:
869 // but now we want to transport the Python Objects directly:
868 PythonQtObjectPtr o(val);
870 PythonQtObjectPtr o(val);
869 v = qVariantFromValue(o);
871 v = qVariantFromValue(o);
870 return v;
872 return v;
871 }
873 }
872 }
874 }
873 // special type request:
875 // special type request:
874 switch (type) {
876 switch (type) {
875 case QVariant::Invalid:
877 case QVariant::Invalid:
876 return v;
878 return v;
877 break;
879 break;
878 case QVariant::Int:
880 case QVariant::Int:
879 {
881 {
880 int d = PyObjGetInt(val, false, ok);
882 int d = PyObjGetInt(val, false, ok);
881 if (ok) return QVariant(d);
883 if (ok) return QVariant(d);
882 }
884 }
883 break;
885 break;
884 case QVariant::UInt:
886 case QVariant::UInt:
885 {
887 {
886 int d = PyObjGetInt(val, false,ok);
888 int d = PyObjGetInt(val, false,ok);
887 if (ok) v = QVariant((unsigned int)d);
889 if (ok) v = QVariant((unsigned int)d);
888 }
890 }
889 break;
891 break;
890 case QVariant::Bool:
892 case QVariant::Bool:
891 {
893 {
892 int d = PyObjGetBool(val,false,ok);
894 int d = PyObjGetBool(val,false,ok);
893 if (ok) v = QVariant((bool)(d!=0));
895 if (ok) v = QVariant((bool)(d!=0));
894 }
896 }
895 break;
897 break;
896 case QVariant::Double:
898 case QVariant::Double:
897 {
899 {
898 double d = PyObjGetDouble(val,false,ok);
900 double d = PyObjGetDouble(val,false,ok);
899 if (ok) v = QVariant(d);
901 if (ok) v = QVariant(d);
900 break;
902 break;
901 }
903 }
902 case QMetaType::Float:
904 case QMetaType::Float:
903 {
905 {
904 float d = (float) PyObjGetDouble(val,false,ok);
906 float d = (float) PyObjGetDouble(val,false,ok);
905 if (ok) v = qVariantFromValue(d);
907 if (ok) v = qVariantFromValue(d);
906 break;
908 break;
907 }
909 }
908 case QMetaType::Long:
910 case QMetaType::Long:
909 {
911 {
910 long d = (long) PyObjGetLongLong(val,false,ok);
912 long d = (long) PyObjGetLongLong(val,false,ok);
911 if (ok) v = qVariantFromValue(d);
913 if (ok) v = qVariantFromValue(d);
912 break;
914 break;
913 }
915 }
914 case QMetaType::ULong:
916 case QMetaType::ULong:
915 {
917 {
916 unsigned long d = (unsigned long) PyObjGetLongLong(val,false,ok);
918 unsigned long d = (unsigned long) PyObjGetLongLong(val,false,ok);
917 if (ok) v = qVariantFromValue(d);
919 if (ok) v = qVariantFromValue(d);
918 break;
920 break;
919 }
921 }
920 case QMetaType::LongLong:
922 case QMetaType::LongLong:
921 {
923 {
922 qint64 d = PyObjGetLongLong(val, false, ok);
924 qint64 d = PyObjGetLongLong(val, false, ok);
923 if (ok) v = qVariantFromValue(d);
925 if (ok) v = qVariantFromValue(d);
924 }
926 }
925 break;
927 break;
926 case QMetaType::ULongLong:
928 case QMetaType::ULongLong:
927 {
929 {
928 quint64 d = PyObjGetULongLong(val, false, ok);
930 quint64 d = PyObjGetULongLong(val, false, ok);
929 if (ok) v = qVariantFromValue(d);
931 if (ok) v = qVariantFromValue(d);
930 }
932 }
931 break;
933 break;
932 case QMetaType::Short:
934 case QMetaType::Short:
933 {
935 {
934 short d = (short) PyObjGetInt(val,false,ok);
936 short d = (short) PyObjGetInt(val,false,ok);
935 if (ok) v = qVariantFromValue(d);
937 if (ok) v = qVariantFromValue(d);
936 break;
938 break;
937 }
939 }
938 case QMetaType::UShort:
940 case QMetaType::UShort:
939 {
941 {
940 unsigned short d = (unsigned short) PyObjGetInt(val,false,ok);
942 unsigned short d = (unsigned short) PyObjGetInt(val,false,ok);
941 if (ok) v = qVariantFromValue(d);
943 if (ok) v = qVariantFromValue(d);
942 break;
944 break;
943 }
945 }
944 case QMetaType::Char:
946 case QMetaType::Char:
945 {
947 {
946 char d = (char) PyObjGetInt(val,false,ok);
948 char d = (char) PyObjGetInt(val,false,ok);
947 if (ok) v = qVariantFromValue(d);
949 if (ok) v = qVariantFromValue(d);
948 break;
950 break;
949 }
951 }
950 case QMetaType::UChar:
952 case QMetaType::UChar:
951 {
953 {
952 unsigned char d = (unsigned char) PyObjGetInt(val,false,ok);
954 unsigned char d = (unsigned char) PyObjGetInt(val,false,ok);
953 if (ok) v = qVariantFromValue(d);
955 if (ok) v = qVariantFromValue(d);
954 break;
956 break;
955 }
957 }
956
958
957 case QVariant::ByteArray:
959 case QVariant::ByteArray:
958 case QVariant::String:
960 case QVariant::String:
959 {
961 {
960 bool ok;
962 bool ok;
961 v = QVariant(PyObjGetString(val, false, ok));
963 v = QVariant(PyObjGetString(val, false, ok));
962 }
964 }
963 break;
965 break;
964
966
965 // these are important for MeVisLab
967 // these are important for MeVisLab
966 case QVariant::Map:
968 case QVariant::Map:
967 {
969 {
968 if (PyMapping_Check(val)) {
970 if (PyMapping_Check(val)) {
969 QMap<QString,QVariant> map;
971 QMap<QString,QVariant> map;
970 PyObject* items = PyMapping_Items(val);
972 PyObject* items = PyMapping_Items(val);
971 if (items) {
973 if (items) {
972 int count = PyList_Size(items);
974 int count = PyList_Size(items);
973 PyObject* value;
975 PyObject* value;
974 PyObject* key;
976 PyObject* key;
975 PyObject* tuple;
977 PyObject* tuple;
976 for (int i = 0;i<count;i++) {
978 for (int i = 0;i<count;i++) {
977 tuple = PyList_GetItem(items,i);
979 tuple = PyList_GetItem(items,i);
978 key = PyTuple_GetItem(tuple, 0);
980 key = PyTuple_GetItem(tuple, 0);
979 value = PyTuple_GetItem(tuple, 1);
981 value = PyTuple_GetItem(tuple, 1);
980 map.insert(PyObjGetString(key), PyObjToQVariant(value,-1));
982 map.insert(PyObjGetString(key), PyObjToQVariant(value,-1));
981 }
983 }
982 Py_DECREF(items);
984 Py_DECREF(items);
983 v = map;
985 v = map;
984 }
986 }
985 }
987 }
986 }
988 }
987 break;
989 break;
988 case QVariant::List:
990 case QVariant::List:
989 if (PySequence_Check(val)) {
991 if (PySequence_Check(val)) {
990 QVariantList list;
992 QVariantList list;
991 int count = PySequence_Size(val);
993 int count = PySequence_Size(val);
992 PyObject* value;
994 PyObject* value;
993 for (int i = 0;i<count;i++) {
995 for (int i = 0;i<count;i++) {
994 value = PySequence_GetItem(val,i);
996 value = PySequence_GetItem(val,i);
995 list.append(PyObjToQVariant(value, -1));
997 list.append(PyObjToQVariant(value, -1));
996 }
998 }
997 v = list;
999 v = list;
998 }
1000 }
999 break;
1001 break;
1000 case QVariant::StringList:
1002 case QVariant::StringList:
1001 {
1003 {
1002 bool ok;
1004 bool ok;
1003 QStringList l = PyObjToStringList(val, false, ok);
1005 QStringList l = PyObjToStringList(val, false, ok);
1004 if (ok) {
1006 if (ok) {
1005 v = l;
1007 v = l;
1006 }
1008 }
1007 }
1009 }
1008 break;
1010 break;
1009
1011
1010 default:
1012 default:
1011 if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
1013 if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
1012 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
1014 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
1013 if (wrap->classInfo()->isCPPWrapper() && wrap->classInfo()->metaTypeId() == type) {
1015 if (wrap->classInfo()->isCPPWrapper() && wrap->classInfo()->metaTypeId() == type) {
1014 // construct a new variant from the C++ object if it has the same meta type
1016 // construct a new variant from the C++ object if it has the same meta type
1015 v = QVariant(type, wrap->_wrappedPtr);
1017 v = QVariant(type, wrap->_wrappedPtr);
1016 } else {
1018 } else {
1017 v = QVariant();
1019 v = QVariant();
1018 }
1020 }
1019 } else {
1021 } else {
1020 v = QVariant();
1022 v = QVariant();
1021 }
1023 }
1022 }
1024 }
1023 return v;
1025 return v;
1024 }
1026 }
1025
1027
1026 PyObject* PythonQtConv::QStringToPyObject(const QString& str)
1028 PyObject* PythonQtConv::QStringToPyObject(const QString& str)
1027 {
1029 {
1028 if (str.isNull()) {
1030 if (str.isNull()) {
1029 return PyString_FromString("");
1031 return PyString_FromString("");
1030 } else {
1032 } else {
1031 #ifdef WIN32
1033 #ifdef WIN32
1032 // return PyString_FromString(str.toLatin1().data());
1034 // return PyString_FromString(str.toLatin1().data());
1033 return PyUnicode_FromUnicode(str.utf16(), str.length());
1035 return PyUnicode_FromUnicode(str.utf16(), str.length());
1034 #else
1036 #else
1035 return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, NULL, NULL);
1037 return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, NULL, NULL);
1036 #endif
1038 #endif
1037 }
1039 }
1038 }
1040 }
1039
1041
1040 PyObject* PythonQtConv::QStringListToPyObject(const QStringList& list)
1042 PyObject* PythonQtConv::QStringListToPyObject(const QStringList& list)
1041 {
1043 {
1042 PyObject* result = PyTuple_New(list.count());
1044 PyObject* result = PyTuple_New(list.count());
1043 int i = 0;
1045 int i = 0;
1044 QString str;
1046 QString str;
1045 foreach (str, list) {
1047 foreach (str, list) {
1046 PyTuple_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(str));
1048 PyTuple_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(str));
1047 i++;
1049 i++;
1048 }
1050 }
1049 // why is the error state bad after this?
1051 // why is the error state bad after this?
1050 PyErr_Clear();
1052 PyErr_Clear();
1051 return result;
1053 return result;
1052 }
1054 }
1053
1055
1054 PyObject* PythonQtConv::QStringListToPyList(const QStringList& list)
1056 PyObject* PythonQtConv::QStringListToPyList(const QStringList& list)
1055 {
1057 {
1056 PyObject* result = PyList_New(list.count());
1058 PyObject* result = PyList_New(list.count());
1057 int i = 0;
1059 int i = 0;
1058 for (QStringList::ConstIterator it = list.begin(); it!=list.end(); ++it) {
1060 for (QStringList::ConstIterator it = list.begin(); it!=list.end(); ++it) {
1059 PyList_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(*it));
1061 PyList_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(*it));
1060 i++;
1062 i++;
1061 }
1063 }
1062 return result;
1064 return result;
1063 }
1065 }
1064
1066
1065 PyObject* PythonQtConv::QVariantToPyObject(const QVariant& v)
1067 PyObject* PythonQtConv::QVariantToPyObject(const QVariant& v)
1066 {
1068 {
1067 return ConvertQtValueToPythonInternal(v.userType(), (void*)v.constData());
1069 return ConvertQtValueToPythonInternal(v.userType(), (void*)v.constData());
1068 }
1070 }
1069
1071
1070 PyObject* PythonQtConv::QVariantMapToPyObject(const QVariantMap& m) {
1072 PyObject* PythonQtConv::QVariantMapToPyObject(const QVariantMap& m) {
1071 PyObject* result = PyDict_New();
1073 PyObject* result = PyDict_New();
1072 QVariantMap::const_iterator t = m.constBegin();
1074 QVariantMap::const_iterator t = m.constBegin();
1073 PyObject* key;
1075 PyObject* key;
1074 PyObject* val;
1076 PyObject* val;
1075 for (;t!=m.end();t++) {
1077 for (;t!=m.end();t++) {
1076 key = QStringToPyObject(t.key());
1078 key = QStringToPyObject(t.key());
1077 val = QVariantToPyObject(t.value());
1079 val = QVariantToPyObject(t.value());
1078 PyDict_SetItem(result, key, val);
1080 PyDict_SetItem(result, key, val);
1079 Py_DECREF(key);
1081 Py_DECREF(key);
1080 Py_DECREF(val);
1082 Py_DECREF(val);
1081 }
1083 }
1082 return result;
1084 return result;
1083 }
1085 }
1084
1086
1085 PyObject* PythonQtConv::QVariantListToPyObject(const QVariantList& l) {
1087 PyObject* PythonQtConv::QVariantListToPyObject(const QVariantList& l) {
1086 PyObject* result = PyTuple_New(l.count());
1088 PyObject* result = PyTuple_New(l.count());
1087 int i = 0;
1089 int i = 0;
1088 QVariant v;
1090 QVariant v;
1089 foreach (v, l) {
1091 foreach (v, l) {
1090 PyTuple_SET_ITEM(result, i, PythonQtConv::QVariantToPyObject(v));
1092 PyTuple_SET_ITEM(result, i, PythonQtConv::QVariantToPyObject(v));
1091 i++;
1093 i++;
1092 }
1094 }
1093 // why is the error state bad after this?
1095 // why is the error state bad after this?
1094 PyErr_Clear();
1096 PyErr_Clear();
1095 return result;
1097 return result;
1096 }
1098 }
1097
1099
1098 PyObject* PythonQtConv::ConvertQListOfPointerTypeToPythonList(QList<void*>* list, const QByteArray& typeName)
1100 PyObject* PythonQtConv::ConvertQListOfPointerTypeToPythonList(QList<void*>* list, const QByteArray& typeName)
1099 {
1101 {
1100 PyObject* result = PyTuple_New(list->count());
1102 PyObject* result = PyTuple_New(list->count());
1101 int i = 0;
1103 int i = 0;
1102 foreach (void* value, *list) {
1104 foreach (void* value, *list) {
1103 PyTuple_SET_ITEM(result, i, PythonQt::priv()->wrapPtr(value, typeName));
1105 PyTuple_SET_ITEM(result, i, PythonQt::priv()->wrapPtr(value, typeName));
1104 i++;
1106 i++;
1105 }
1107 }
1106 return result;
1108 return result;
1107 }
1109 }
1108
1110
1109 bool PythonQtConv::ConvertPythonListToQListOfPointerType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool /*strict*/)
1111 bool PythonQtConv::ConvertPythonListToQListOfPointerType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool /*strict*/)
1110 {
1112 {
1111 bool result = false;
1113 bool result = false;
1112 if (PySequence_Check(obj)) {
1114 if (PySequence_Check(obj)) {
1113 result = true;
1115 result = true;
1114 int count = PySequence_Size(obj);
1116 int count = PySequence_Size(obj);
1115 PyObject* value;
1117 PyObject* value;
1116 for (int i = 0;i<count;i++) {
1118 for (int i = 0;i<count;i++) {
1117 value = PySequence_GetItem(obj,i);
1119 value = PySequence_GetItem(obj,i);
1118 if (PyObject_TypeCheck(value, &PythonQtInstanceWrapper_Type)) {
1120 if (PyObject_TypeCheck(value, &PythonQtInstanceWrapper_Type)) {
1119 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)value;
1121 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)value;
1120 bool ok;
1122 bool ok;
1121 void* object = castWrapperTo(wrap, type, ok);
1123 void* object = castWrapperTo(wrap, type, ok);
1122 if (ok) {
1124 if (ok) {
1123 list->append(object);
1125 list->append(object);
1124 } else {
1126 } else {
1125 result = false;
1127 result = false;
1126 break;
1128 break;
1127 }
1129 }
1128 }
1130 }
1129 }
1131 }
1130 }
1132 }
1131 return result;
1133 return result;
1132 }
1134 }
1133
1135
1134 int PythonQtConv::getInnerTemplateMetaType(const QByteArray& typeName)
1136 int PythonQtConv::getInnerTemplateMetaType(const QByteArray& typeName)
1135 {
1137 {
1136 int idx = typeName.indexOf("<");
1138 int idx = typeName.indexOf("<");
1137 if (idx>0) {
1139 if (idx>0) {
1138 int idx2 = typeName.indexOf(">");
1140 int idx2 = typeName.indexOf(">");
1139 if (idx2>0) {
1141 if (idx2>0) {
1140 QByteArray innerType = typeName.mid(idx+1,idx2-idx-1);
1142 QByteArray innerType = typeName.mid(idx+1,idx2-idx-1);
1141 return QMetaType::type(innerType.constData());
1143 return QMetaType::type(innerType.constData());
1142 }
1144 }
1143 }
1145 }
1144 return QMetaType::Void;
1146 return QMetaType::Void;
1145 }
1147 }
1146
1148
1147
1149
1148 QString PythonQtConv::CPPObjectToString(int type, const void* data) {
1150 QString PythonQtConv::CPPObjectToString(int type, const void* data) {
1149 QString r;
1151 QString r;
1150 switch (type) {
1152 switch (type) {
1151 case QVariant::Size: {
1153 case QVariant::Size: {
1152 const QSize* s = static_cast<const QSize*>(data);
1154 const QSize* s = static_cast<const QSize*>(data);
1153 r = QString::number(s->width()) + ", " + QString::number(s->height());
1155 r = QString::number(s->width()) + ", " + QString::number(s->height());
1154 }
1156 }
1155 break;
1157 break;
1156 case QVariant::SizeF: {
1158 case QVariant::SizeF: {
1157 const QSizeF* s = static_cast<const QSizeF*>(data);
1159 const QSizeF* s = static_cast<const QSizeF*>(data);
1158 r = QString::number(s->width()) + ", " + QString::number(s->height());
1160 r = QString::number(s->width()) + ", " + QString::number(s->height());
1159 }
1161 }
1160 break;
1162 break;
1161 case QVariant::Point: {
1163 case QVariant::Point: {
1162 const QPoint* s = static_cast<const QPoint*>(data);
1164 const QPoint* s = static_cast<const QPoint*>(data);
1163 r = QString::number(s->x()) + ", " + QString::number(s->y());
1165 r = QString::number(s->x()) + ", " + QString::number(s->y());
1164 }
1166 }
1165 break;
1167 break;
1166 case QVariant::PointF: {
1168 case QVariant::PointF: {
1167 const QPointF* s = static_cast<const QPointF*>(data);
1169 const QPointF* s = static_cast<const QPointF*>(data);
1168 r = QString::number(s->x()) + ", " + QString::number(s->y());
1170 r = QString::number(s->x()) + ", " + QString::number(s->y());
1169 }
1171 }
1170 break;
1172 break;
1171 case QVariant::Rect: {
1173 case QVariant::Rect: {
1172 const QRect* s = static_cast<const QRect*>(data);
1174 const QRect* s = static_cast<const QRect*>(data);
1173 r = QString::number(s->x()) + ", " + QString::number(s->y());
1175 r = QString::number(s->x()) + ", " + QString::number(s->y());
1174 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1176 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1175 }
1177 }
1176 break;
1178 break;
1177 case QVariant::RectF: {
1179 case QVariant::RectF: {
1178 const QRectF* s = static_cast<const QRectF*>(data);
1180 const QRectF* s = static_cast<const QRectF*>(data);
1179 r = QString::number(s->x()) + ", " + QString::number(s->y());
1181 r = QString::number(s->x()) + ", " + QString::number(s->y());
1180 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1182 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1181 }
1183 }
1182 break;
1184 break;
1183 case QVariant::Date: {
1185 case QVariant::Date: {
1184 const QDate* s = static_cast<const QDate*>(data);
1186 const QDate* s = static_cast<const QDate*>(data);
1185 r = s->toString(Qt::ISODate);
1187 r = s->toString(Qt::ISODate);
1186 }
1188 }
1187 break;
1189 break;
1188 case QVariant::DateTime: {
1190 case QVariant::DateTime: {
1189 const QDateTime* s = static_cast<const QDateTime*>(data);
1191 const QDateTime* s = static_cast<const QDateTime*>(data);
1190 r = s->toString(Qt::ISODate);
1192 r = s->toString(Qt::ISODate);
1191 }
1193 }
1192 break;
1194 break;
1193 case QVariant::Time: {
1195 case QVariant::Time: {
1194 const QTime* s = static_cast<const QTime*>(data);
1196 const QTime* s = static_cast<const QTime*>(data);
1195 r = s->toString(Qt::ISODate);
1197 r = s->toString(Qt::ISODate);
1196 }
1198 }
1197 break;
1199 break;
1198 case QVariant::Pixmap:
1200 case QVariant::Pixmap:
1199 {
1201 {
1200 const QPixmap* s = static_cast<const QPixmap*>(data);
1202 const QPixmap* s = static_cast<const QPixmap*>(data);
1201 r = QString("Pixmap ") + QString::number(s->width()) + ", " + QString::number(s->height());
1203 r = QString("Pixmap ") + QString::number(s->width()) + ", " + QString::number(s->height());
1202 }
1204 }
1203 break;
1205 break;
1204 case QVariant::Image:
1206 case QVariant::Image:
1205 {
1207 {
1206 const QImage* s = static_cast<const QImage*>(data);
1208 const QImage* s = static_cast<const QImage*>(data);
1207 r = QString("Image ") + QString::number(s->width()) + ", " + QString::number(s->height());
1209 r = QString("Image ") + QString::number(s->width()) + ", " + QString::number(s->height());
1208 }
1210 }
1209 break;
1211 break;
1210 case QVariant::Url:
1212 case QVariant::Url:
1211 {
1213 {
1212 const QUrl* s = static_cast<const QUrl*>(data);
1214 const QUrl* s = static_cast<const QUrl*>(data);
1213 r = s->toString();
1215 r = s->toString();
1214 }
1216 }
1215 break;
1217 break;
1216 //TODO: add more printing for other variant types
1218 //TODO: add more printing for other variant types
1217 default:
1219 default:
1218 // this creates a copy, but that should not be expensive for typical simple variants
1220 // this creates a copy, but that should not be expensive for typical simple variants
1219 // (but we do not want to do this for our won user types!
1221 // (but we do not want to do this for our won user types!
1220 if (type>0 && type < (int)QVariant::UserType) {
1222 if (type>0 && type < (int)QVariant::UserType) {
1221 QVariant v(type, data);
1223 QVariant v(type, data);
1222 r = v.toString();
1224 r = v.toString();
1223 }
1225 }
1224 }
1226 }
1225 return r;
1227 return r;
1226 }
1228 }
@@ -1,509 +1,509
1 #ifndef _PYTHONQTDOC_H
1 #ifndef _PYTHONQTDOC_H
2 #define _PYTHONQTDOC_H
2 #define _PYTHONQTDOC_H
3
3
4 /*
4 /*
5 *
5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
7 *
7 *
8 * This library is free software; you can redistribute it and/or
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
11 * version 2.1 of the License, or (at your option) any later version.
12 *
12 *
13 * This library is distributed in the hope that it will be useful,
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
16 * Lesser General Public License for more details.
17 *
17 *
18 * Further, this software is distributed without any warranty that it is
18 * Further, this software is distributed without any warranty that it is
19 * free of the rightful claim of any third person regarding infringement
19 * free of the rightful claim of any third person regarding infringement
20 * or the like. Any license provided herein, whether implied or
20 * or the like. Any license provided herein, whether implied or
21 * otherwise, applies only to this software file. Patent licenses, if
21 * otherwise, applies only to this software file. Patent licenses, if
22 * any, provided herein do not apply to combinations of this program with
22 * any, provided herein do not apply to combinations of this program with
23 * other software, or any other product whatsoever.
23 * other software, or any other product whatsoever.
24 *
24 *
25 * You should have received a copy of the GNU Lesser General Public
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
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
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
30 * 28359 Bremen, Germany or:
30 * 28359 Bremen, Germany or:
31 *
31 *
32 * http://www.mevis.de
32 * http://www.mevis.de
33 *
33 *
34 */
34 */
35
35
36 //----------------------------------------------------------------------------------
36 //----------------------------------------------------------------------------------
37 /*!
37 /*!
38 // \file PythonQtDoc.h
38 // \file PythonQtDoc.h
39 // \author Florian Link
39 // \author Florian Link
40 // \author Last changed by $Author: florian $
40 // \author Last changed by $Author: florian $
41 // \date 2006-10
41 // \date 2006-10
42 */
42 */
43 //----------------------------------------------------------------------------------
43 //----------------------------------------------------------------------------------
44
44
45 /*!
45 /*!
46 \if USE_GLOBAL_DOXYGEN_DOC
46 \if USE_GLOBAL_DOXYGEN_DOC
47 \page PythonQtPage PythonQt Overview
47 \page PythonQtPage PythonQt Overview
48 \else
48 \else
49 \mainpage PythonQt Overview
49 \mainpage PythonQt Overview
50 \endif
50 \endif
51
51
52 \section Introduction
52 \section Introduction
53
53
54 \b PythonQt is a dynamic Python (http://www.python.org) binding for the Qt framework (http://qt.nokia.com).
54 \b PythonQt is a dynamic Python (http://www.python.org) binding for the Qt framework (http://qt.nokia.com).
55 It offers an easy way to embed the Python scripting language into
55 It offers an easy way to embed the Python scripting language into
56 your C++ Qt applications. It makes heavy use of the QMetaObject system and thus requires Qt4.x.
56 your C++ Qt applications. It makes heavy use of the QMetaObject system and thus requires Qt4.x.
57
57
58 The focus of PythonQt is on embedding Python into an existing C++ application, not on writing the whole
58 The focus of PythonQt is on embedding Python into an existing C++ application, not on writing the whole
59 application completely in Python. If you want to write your whole application in Python,
59 application completely in Python. If you want to write your whole application in Python,
60 you should use <a href="http://www.riverbankcomputing.co.uk/pyqt/">PyQt</a> or <a href="http://www.pyside.org">PySide</a> instead.
60 you should use <a href="http://www.riverbankcomputing.co.uk/pyqt/">PyQt</a> or <a href="http://www.pyside.org">PySide</a> instead.
61
61
62 If you are looking for a simple way to embed Python objects into your C++/Qt Application
62 If you are looking for a simple way to embed Python objects into your C++/Qt Application
63 and to script parts of your application via Python, PythonQt is the way to go!
63 and to script parts of your application via Python, PythonQt is the way to go!
64
64
65 PythonQt is a stable library that was developed to make the
65 PythonQt is a stable library that was developed to make the
66 Image Processing and Visualization platform MeVisLab (http://www.mevislab.de)
66 Image Processing and Visualization platform MeVisLab (http://www.mevislab.de)
67 scriptable from Python.
67 scriptable from Python.
68
68
69 \section Download
69 \section Download
70
70
71 PythonQt is hosted on SourceForge at http://sourceforge.net/projects/pythonqt , you can access it via SVN
71 PythonQt is hosted on SourceForge at http://sourceforge.net/projects/pythonqt , you can access it via SVN
72 or download a tarball.
72 or download a tarball.
73
73
74 \section Licensing
74 \section Licensing
75
75
76 PythonQt is distributed under the LGPL license, so it pairs well with the LGPL of the Qt 4.5 release and allows
76 PythonQt is distributed under the LGPL license, so it pairs well with the LGPL of the Qt 4.5 release and allows
77 to be used in commercial applications when following the LGPL 2.1 obligations.
77 to be used in commercial applications when following the LGPL 2.1 obligations.
78
78
79 \section LicensingWrapper Licensing of Wrapper Generator
79 \section LicensingWrapper Licensing of Wrapper Generator
80
80
81 The build system of PythonQt makes use of a modified version of the LGPL'ed QtScript generator,
81 The build system of PythonQt makes use of a modified version of the LGPL'ed QtScript generator,
82 located in the "generator" directory.
82 located in the "generator" directory.
83
83
84 See http://qt.gitorious.org/qt-labs/qtscriptgenerator for details on the original project.
84 See http://qt.gitorious.org/qt-labs/qtscriptgenerator for details on the original project.
85 Thanks a lot to the QtJambi guys and the QtScript Generator project for the C++ parser and
85 Thanks a lot to the QtJambi guys and the QtScript Generator project for the C++ parser and
86 Qt typesystem files!
86 Qt typesystem files!
87
87
88 The PythonQt wrappers generated by the generator located in the "generated_cpp" directory are free to be used without any licensing restrictions.
88 The PythonQt wrappers generated by the generator located in the "generated_cpp" directory are free to be used without any licensing restrictions.
89
89
90 The generated wrappers are pre-generated and checked-in for Qt 4.6.1, so you only need to build and run the
90 The generated wrappers are pre-generated and checked-in for Qt 4.6.1, so you only need to build and run the
91 generator when you want to build additional wrappers or you want to upgrade/downgrade to another Qt version.
91 generator when you want to build additional wrappers or you want to upgrade/downgrade to another Qt version.
92 You may use the generator to generate C++ bindings for your own C++ classes (e.g., to make them inheritable in Python),
92 You may use the generator to generate C++ bindings for your own C++ classes (e.g., to make them inheritable in Python),
93 , but this is currently not documented and involves creating your own typesystem files (although the Qt Jambi examples might help you).
93 , but this is currently not documented and involves creating your own typesystem files (although the Qt Jambi examples might help you).
94
94
95 \section Features
95 \section Features
96
96
97 The following are the built-in features of the PythonQt library:
97 The following are the built-in features of the PythonQt library:
98
98
99 - Access all \b slots, \b properties, children and registered enums of any QObject derived class from Python
99 - Access all \b slots, \b properties, children and registered enums of any QObject derived class from Python
100 - Connecting Qt Signals to Python functions (both from within Python and from C++)
100 - Connecting Qt Signals to Python functions (both from within Python and from C++)
101 - Easy wrapping of Python objects from C++ with smart, reference-counting PythonQtObjectPtr.
101 - Easy wrapping of Python objects from C++ with smart, reference-counting PythonQtObjectPtr.
102 - Convenient conversions to/from QVariant for PythonQtObjectPtr.
102 - Convenient conversions to/from QVariant for PythonQtObjectPtr.
103 - Wrapping of C++ objects (which are not derived from QObject) via PythonQtCppWrapperFactory
103 - Wrapping of C++ objects (which are not derived from QObject) via PythonQtCppWrapperFactory
104 - Extending C++ and QObject derived classes with additional slots, static methods and constructors (see Decorators)
104 - Extending C++ and QObject derived classes with additional slots, static methods and constructors (see Decorators)
105 - StdOut/Err redirection to Qt signals instead of cout
105 - StdOut/Err redirection to Qt signals instead of cout
106 - Interface for creating your own \c import replacement, so that Python scripts can be e.g. signed/verified before they are executed (PythonQtImportFileInterface)
106 - Interface for creating your own \c import replacement, so that Python scripts can be e.g. signed/verified before they are executed (PythonQtImportFileInterface)
107 - Mapping of plain-old-datatypes and ALL QVariant types to and from Python
107 - Mapping of plain-old-datatypes and ALL QVariant types to and from Python
108 - Support for wrapping of user QVariant types which are registerd via QMetaType
108 - Support for wrapping of user QVariant types which are registerd via QMetaType
109 - Support for Qt namespace (with all enumerators)
109 - Support for Qt namespace (with all enumerators)
110 - All PythonQt wrapped objects support the dir() statement, so that you can see easily which attributes a QObject, CPP object or QVariant has
110 - All PythonQt wrapped objects support the dir() statement, so that you can see easily which attributes a QObject, CPP object or QVariant has
111 - No preprocessing/wrapping tool needs to be started, PythonQt can script any QObject without prior knowledge about it (except for the MetaObject information from the \b moc)
111 - No preprocessing/wrapping tool needs to be started, PythonQt can script any QObject without prior knowledge about it (except for the MetaObject information from the \b moc)
112 - Multiple inheritance for C++ objects (e.g. a QWidget is derived from QObject and QPaintDevice, PythonQt will automatically cast a QWidget to a QPaintDevice when needed)
112 - Multiple inheritance for C++ objects (e.g. a QWidget is derived from QObject and QPaintDevice, PythonQt will automatically cast a QWidget to a QPaintDevice when needed)
113 - Polymorphic downcasting (if e.g. PythonQt sees a QEvent, it can downcast it depending on the type(), so the Python e.g. sees a QPaintEvent instead of a plain QEvent)
113 - Polymorphic downcasting (if e.g. PythonQt sees a QEvent, it can downcast it depending on the type(), so the Python e.g. sees a QPaintEvent instead of a plain QEvent)
114 - Deriving C++ objects from Python and overwriting virtual method with a Python implementation (requires usage of wrapper generator or manual work!)
114 - Deriving C++ objects from Python and overwriting virtual method with a Python implementation (requires usage of wrapper generator or manual work!)
115 - Extensible handler for Python/C++ conversion of complex types, e.g. mapping of QVector<SomeObject> to/from a Python array
115 - Extensible handler for Python/C++ conversion of complex types, e.g. mapping of QVector<SomeObject> to/from a Python array
116
116
117 \section FeaturesQtAll Features (with PythonQt_QtAll linked in)
117 \section FeaturesQtAll Features (with PythonQt_QtAll linked in)
118
118
119 Thanks to the new wrapper generator, PythonQt now offers the additional PythonQt_QtAll library which wraps the complete Qt API, including all C++ classes and all non-slots on QObject derived classes.
119 Thanks to the new wrapper generator, PythonQt now offers the additional PythonQt_QtAll library which wraps the complete Qt API, including all C++ classes and all non-slots on QObject derived classes.
120 This offers the following features:
120 This offers the following features:
121
121
122 - Complete Qt API wrapped and accessible
122 - Complete Qt API wrapped and accessible
123 - The following modules are available as submodules of the PythonQt module:
123 - The following modules are available as submodules of the PythonQt module:
124 - QtCore
124 - QtCore
125 - QtGui
125 - QtGui
126 - QtNetwork
126 - QtNetwork
127 - QtOpenGL
127 - QtOpenGL
128 - QtSql
128 - QtSql
129 - QtSvg
129 - QtSvg
130 - QtUiTools
130 - QtUiTools
131 - QtWebKit
131 - QtWebKit
132 - QtXml
132 - QtXml
133 - QtXmlPatterns
133 - QtXmlPatterns
134 - (phonon, QtHelp, assistant, designer are currently not supported, this would require some additional effort on the code generator)
134 - (phonon, QtHelp, assistant, designer are currently not supported, this would require some additional effort on the code generator)
135 - For convenience, all classes are also available in the PythonQt.Qt module, for people who do not care in which module a class is located
135 - For convenience, all classes are also available in the PythonQt.Qt module, for people who do not care in which module a class is located
136 - Any Qt class that has virtual methods can be easily derived from Python and the virtual methods can be reimplemented in Python
136 - Any Qt class that has virtual methods can be easily derived from Python and the virtual methods can be reimplemented in Python
137 - Polymorphic downcasting on QEvent, QGraphicsItem, QStyleOption, ...
137 - Polymorphic downcasting on QEvent, QGraphicsItem, QStyleOption, ...
138 - Multiple inheritance support (e.g., QGraphicsTextItem is a QObject AND a QGraphicsItem, PythonQt will handle this well)
138 - Multiple inheritance support (e.g., QGraphicsTextItem is a QObject AND a QGraphicsItem, PythonQt will handle this well)
139
139
140 \section Comparision Comparision with PyQt/PySide
140 \section Comparision Comparision with PyQt/PySide
141
141
142 - PythonQt is not as Pythonic as PyQt in many details (e.g. buffer protocol, pickling, translation support, ...) and it is mainly thought for embedding and intercommunication between Qt/Cpp and Python
142 - PythonQt is not as Pythonic as PyQt in many details (e.g. buffer protocol, pickling, translation support, ...) and it is mainly thought for embedding and intercommunication between Qt/Cpp and Python
143 - PythonQt allows to communicate in both directions, e.g., calling a Python object from C++ AND calling a C++ method from Python, while PyQt only handles the Python->C++ direction
143 - PythonQt allows to communicate in both directions, e.g., calling a Python object from C++ AND calling a C++ method from Python, while PyQt only handles the Python->C++ direction
144 - PythonQt offers properties as Python attributes, while PyQt offers them as setter/getter methods (e.g. QWidget.width is a property in PythonQt and a method in PyQt)
144 - PythonQt offers properties as Python attributes, while PyQt offers them as setter/getter methods (e.g. QWidget.width is a property in PythonQt and a method in PyQt)
145 - PythonQt does not support instanceof checks for Qt classes, except for the exact match and derived Python classes
145 - PythonQt does not support instanceof checks for Qt classes, except for the exact match and derived Python classes
146 - QObject.emit to emit Qt signals from Python is not yet implemented but PythonQt allows to just emit a signal by calling it
146 - QObject.emit to emit Qt signals from Python is not yet implemented but PythonQt allows to just emit a signal by calling it
147 - PythonQt does not (yet) offer to add new signals to Python/C++ objects
147 - PythonQt does not (yet) offer to add new signals to Python/C++ objects
148 - Ownership of objects is a bit different in PythonQt, currently Python classes derived from a C++ class need to be manually referenced in Python to not get deleted too early (this will be fixed)
148 - Ownership of objects is a bit different in PythonQt, currently Python classes derived from a C++ class need to be manually referenced in Python to not get deleted too early (this will be fixed)
149 - QString and QBytearray are always converted to unicode and str Python objects (PyQt returns QString and QByteArray instead).
149 - QStrings are always converted to unicode Python objects (PyQt returns QString instead), we prefered to return Python strings.
150 - Probably there are lots of details that differ, I do not know PyQt that well to list them all.
150 - Probably there are lots of details that differ, I do not know PyQt that well to list them all.
151
151
152 \section Interface
152 \section Interface
153
153
154 The main interface to PythonQt is the PythonQt singleton.
154 The main interface to PythonQt is the PythonQt singleton.
155 PythonQt needs to be initialized via PythonQt::init() once.
155 PythonQt needs to be initialized via PythonQt::init() once.
156 Afterwards you communicate with the singleton via PythonQt::self().
156 Afterwards you communicate with the singleton via PythonQt::self().
157 PythonQt offers a complete Qt binding, which
157 PythonQt offers a complete Qt binding, which
158 needs to be enabled via PythonQt_QtAll::init().
158 needs to be enabled via PythonQt_QtAll::init().
159
159
160
160
161 \section Datatype Datatype Mapping
161 \section Datatype Datatype Mapping
162
162
163 The following table shows the mapping between Python and Qt objects:
163 The following table shows the mapping between Python and Qt objects:
164 <table>
164 <table>
165 <tr><th>Qt/C++</th><th>Python</th></tr>
165 <tr><th>Qt/C++</th><th>Python</th></tr>
166 <tr><td>bool</td><td>bool</td></tr>
166 <tr><td>bool</td><td>bool</td></tr>
167 <tr><td>double</td><td>float</td></tr>
167 <tr><td>double</td><td>float</td></tr>
168 <tr><td>float</td><td>float</td></tr>
168 <tr><td>float</td><td>float</td></tr>
169 <tr><td>char/uchar,int/uint,short,ushort,QChar</td><td>integer</td></tr>
169 <tr><td>char/uchar,int/uint,short,ushort,QChar</td><td>integer</td></tr>
170 <tr><td>long</td><td>integer</td></tr>
170 <tr><td>long</td><td>integer</td></tr>
171 <tr><td>ulong,longlong,ulonglong</td><td>long</td></tr>
171 <tr><td>ulong,longlong,ulonglong</td><td>long</td></tr>
172 <tr><td>QString</td><td>unicode string</td></tr>
172 <tr><td>QString</td><td>unicode string</td></tr>
173 <tr><td>QByteArray</td><td>str</td></tr>
173 <tr><td>QByteArray</td><td>str</td></tr>
174 <tr><td>char*</td><td>str</td></tr>
174 <tr><td>char*</td><td>str</td></tr>
175 <tr><td>QStringList</td><td>tuple of unicode strings</td></tr>
175 <tr><td>QStringList</td><td>tuple of unicode strings</td></tr>
176 <tr><td>QVariantList</td><td>tuple of objects</td></tr>
176 <tr><td>QVariantList</td><td>tuple of objects</td></tr>
177 <tr><td>QVariantMap</td><td>dict of objects</td></tr>
177 <tr><td>QVariantMap</td><td>dict of objects</td></tr>
178 <tr><td>QVariant</td><td>depends on type, see below</td></tr>
178 <tr><td>QVariant</td><td>depends on type, see below</td></tr>
179 <tr><td>QSize, QRect and all other standard Qt QVariants</td><td>variant wrapper that supports complete API of the respective Qt classes</td></tr>
179 <tr><td>QSize, QRect and all other standard Qt QVariants</td><td>variant wrapper that supports complete API of the respective Qt classes</td></tr>
180 <tr><td>OwnRegisteredMetaType</td><td>C++ wrapper, optionally with additional information/wrapping provided by registerCPPClass()</td></tr>
180 <tr><td>OwnRegisteredMetaType</td><td>C++ wrapper, optionally with additional information/wrapping provided by registerCPPClass()</td></tr>
181 <tr><td>QList<AnyObject*></td><td>converts to a list of CPP wrappers</td></tr>
181 <tr><td>QList<AnyObject*></td><td>converts to a list of CPP wrappers</td></tr>
182 <tr><td>EnumType</td><td>integer (all enums that are known via the moc and the Qt namespace are supported)</td></tr>
182 <tr><td>EnumType</td><td>integer (all enums that are known via the moc and the Qt namespace are supported)</td></tr>
183 <tr><td>QObject (and derived classes)</td><td>QObject wrapper</td></tr>
183 <tr><td>QObject (and derived classes)</td><td>QObject wrapper</td></tr>
184 <tr><td>C++ object</td><td>CPP wrapper, either wrapped via PythonQtCppWrapperFactory or just decorated with decorators</td></tr>
184 <tr><td>C++ object</td><td>CPP wrapper, either wrapped via PythonQtCppWrapperFactory or just decorated with decorators</td></tr>
185 <tr><td>PyObject</td><td>PyObject</td></tr>
185 <tr><td>PyObject</td><td>PyObject</td></tr>
186 </table>
186 </table>
187
187
188 PyObject is passed as simple pointer, which allows to pass/return any Python Object directly to/from
188 PyObject is passed as simple pointer, which allows to pass/return any Python Object directly to/from
189 a Qt slot.
189 a Qt slot.
190 QVariants are mapped recursively as given above, e.g. a dictionary can
190 QVariants are mapped recursively as given above, e.g. a dictionary can
191 contain lists of dictionaries of doubles.
191 contain lists of dictionaries of doubles.
192 For example a QVariant of type "String" is mapped to a python unicode string.
192 For example a QVariant of type "String" is mapped to a python unicode string.
193 All Qt QVariant types are implemented, PythonQt supports the complete Qt API for these object.
193 All Qt QVariant types are implemented, PythonQt supports the complete Qt API for these object.
194
194
195 \section QObject QObject Wrapping
195 \section QObject QObject Wrapping
196
196
197 All classes derived from QObject are automatically wrapped with a python wrapper class
197 All classes derived from QObject are automatically wrapped with a python wrapper class
198 when they become visible to the Python interpreter. This can happen via
198 when they become visible to the Python interpreter. This can happen via
199 - the PythonQt::addObject() method
199 - the PythonQt::addObject() method
200 - when a Qt \b slot returns a QObject derived object to python
200 - when a Qt \b slot returns a QObject derived object to python
201 - when a Qt \b signal contains a QObject and is connected to a python function
201 - when a Qt \b signal contains a QObject and is connected to a python function
202
202
203 It is important that you call PythonQt::registerClass() for any QObject derived class
203 It is important that you call PythonQt::registerClass() for any QObject derived class
204 that may become visible to Python, except when you add it via PythonQt::addObject().
204 that may become visible to Python, except when you add it via PythonQt::addObject().
205 This will register the complete parent hierachy of the registered class, so that
205 This will register the complete parent hierachy of the registered class, so that
206 when you register e.g. a QPushButton, QWidget will be registered as well (and all intermediate
206 when you register e.g. a QPushButton, QWidget will be registered as well (and all intermediate
207 parents).
207 parents).
208
208
209 From Python, you can talk to the returned QObjects in a natural way by calling
209 From Python, you can talk to the returned QObjects in a natural way by calling
210 their slots and receiving the return values. You can also read/write all
210 their slots and receiving the return values. You can also read/write all
211 properties of the objects as if they where normal python properties.
211 properties of the objects as if they where normal python properties.
212
212
213 In addition to this, the wrapped objects support
213 In addition to this, the wrapped objects support
214 - className() - returns a string that reprents the classname of the QObject
214 - className() - returns a string that reprents the classname of the QObject
215 - help() - shows all properties, slots, enums, decorator slots and constructors of the object, in a printable form
215 - help() - shows all properties, slots, enums, decorator slots and constructors of the object, in a printable form
216 - delete() - deletes the object (use with care, especially if you passed the ownership to C++)
216 - delete() - deletes the object (use with care, especially if you passed the ownership to C++)
217 - connect(signal, function) - connect the signal of the given object to a python function
217 - connect(signal, function) - connect the signal of the given object to a python function
218 - connect(signal, qobject, slot) - connect the signal of the given object to a slot of another QObject
218 - connect(signal, qobject, slot) - connect the signal of the given object to a slot of another QObject
219 - disconnect(signal, function) - disconnect the signal of the given object from a python function
219 - disconnect(signal, function) - disconnect the signal of the given object from a python function
220 - disconnect(signal, qobject, slot) - disconnect the signal of the given object from a slot of another QObject
220 - disconnect(signal, qobject, slot) - disconnect the signal of the given object from a slot of another QObject
221 - children() - returns the children of the object
221 - children() - returns the children of the object
222 - setParent(QObject) - set the parent
222 - setParent(QObject) - set the parent
223 - QObject* parent() - get the parent
223 - QObject* parent() - get the parent
224
224
225 The below example shows how to connect signals in Python:
225 The below example shows how to connect signals in Python:
226
226
227 \code
227 \code
228 # define a signal handler function
228 # define a signal handler function
229 def someFunction(flag):
229 def someFunction(flag):
230 print flag
230 print flag
231
231
232 # button1 is a QPushButton that has been added to Python via addObject()
232 # button1 is a QPushButton that has been added to Python via addObject()
233 # connect the clicked signal to a python function:
233 # connect the clicked signal to a python function:
234 button1.connect("clicked(bool)", someFunction)
234 button1.connect("clicked(bool)", someFunction)
235
235
236 \endcode
236 \endcode
237
237
238 \section CPP CPP Wrapping
238 \section CPP CPP Wrapping
239
239
240 You can create dedicated wrapper QObjects for any C++ class. This is done by deriving from PythonQtCppWrapperFactory
240 You can create dedicated wrapper QObjects for any C++ class. This is done by deriving from PythonQtCppWrapperFactory
241 and adding your factory via addWrapperFactory().
241 and adding your factory via addWrapperFactory().
242 Whenever PythonQt encounters a CPP pointer (e.g. on a slot or signal)
242 Whenever PythonQt encounters a CPP pointer (e.g. on a slot or signal)
243 and it does not known it as a QObject derived class, it will create a generic CPP wrapper. So even unknown C++ objects
243 and it does not known it as a QObject derived class, it will create a generic CPP wrapper. So even unknown C++ objects
244 can be passed through Python. If the wrapper factory supports the CPP class, a QObject wrapper will be created for each
244 can be passed through Python. If the wrapper factory supports the CPP class, a QObject wrapper will be created for each
245 instance that enters Python. An alternative to a complete wrapper via the wrapper factory are decorators, see \ref Decorators
245 instance that enters Python. An alternative to a complete wrapper via the wrapper factory are decorators, see \ref Decorators
246
246
247 \section MetaObject Meta Object/Class access
247 \section MetaObject Meta Object/Class access
248
248
249 For each known C++ class, PythonQt provides a Python class. These classes are visible
249 For each known C++ class, PythonQt provides a Python class. These classes are visible
250 inside of the "PythonQt" python module or in subpackages if a package is given when the class is registered.
250 inside of the "PythonQt" python module or in subpackages if a package is given when the class is registered.
251
251
252 A Meta class supports:
252 A Meta class supports:
253
253
254 - access to all declared enum values
254 - access to all declared enum values
255 - constructors
255 - constructors
256 - static methods
256 - static methods
257 - unbound non-static methods
257 - unbound non-static methods
258 - help() and className()
258 - help() and className()
259
259
260 From within Python, you can import the module "PythonQt" to access these classes and the Qt namespace.
260 From within Python, you can import the module "PythonQt" to access these classes and the Qt namespace.
261
261
262 \code
262 \code
263 from PythonQt import QtCore
263 from PythonQt import QtCore
264
264
265 # namespace access:
265 # namespace access:
266 print QtCore.Qt.AlignLeft
266 print QtCore.Qt.AlignLeft
267
267
268 # constructors
268 # constructors
269 a = QtCore.QSize(12,13)
269 a = QtCore.QSize(12,13)
270 b = QtCore.QFont()
270 b = QtCore.QFont()
271
271
272 # static method
272 # static method
273 QtCore.QDate.currentDate()
273 QtCore.QDate.currentDate()
274
274
275 # enum value
275 # enum value
276 QtCore.QFont.UltraCondensed
276 QtCore.QFont.UltraCondensed
277
277
278 \endcode
278 \endcode
279
279
280 \section Decorators Decorator slots
280 \section Decorators Decorator slots
281
281
282 PythonQt introduces a new generic approach to extend any wrapped QObject or CPP object with
282 PythonQt introduces a new generic approach to extend any wrapped QObject or CPP object with
283
283
284 - constructors
284 - constructors
285 - destructors (for CPP objects)
285 - destructors (for CPP objects)
286 - additional slots
286 - additional slots
287 - static slots (callable on both the Meta object and the instances)
287 - static slots (callable on both the Meta object and the instances)
288
288
289 The idea behind decorators is that we wanted to make it as easy as possible to extend
289 The idea behind decorators is that we wanted to make it as easy as possible to extend
290 wrapped objects. Since we already have an implementation for invoking any Qt Slot from
290 wrapped objects. Since we already have an implementation for invoking any Qt Slot from
291 Python, it looked promising to use this approach for the extension of wrapped objects as well.
291 Python, it looked promising to use this approach for the extension of wrapped objects as well.
292 This avoids that the PythonQt user needs to care about how Python arguments are mapped from/to
292 This avoids that the PythonQt user needs to care about how Python arguments are mapped from/to
293 Qt when he wants to create static methods, constructors and additional member functions.
293 Qt when he wants to create static methods, constructors and additional member functions.
294
294
295 The basic idea about decorators is to create a QObject derived class that implements slots
295 The basic idea about decorators is to create a QObject derived class that implements slots
296 which take one of the above roles (e.g. constructor, destructor etc.) via a naming convention.
296 which take one of the above roles (e.g. constructor, destructor etc.) via a naming convention.
297 These slots are then assigned to other classes via the naming convention.
297 These slots are then assigned to other classes via the naming convention.
298
298
299 - SomeClassName* new_SomeClassName(...) - defines a constructor for "SomeClassName" that returns a new object of type SomeClassName (where SomeClassName can be any CPP class, not just QObject classes)
299 - SomeClassName* new_SomeClassName(...) - defines a constructor for "SomeClassName" that returns a new object of type SomeClassName (where SomeClassName can be any CPP class, not just QObject classes)
300 - void delete_SomeClassName(SomeClassName* o) - defines a destructor, which should delete the passed in object o
300 - void delete_SomeClassName(SomeClassName* o) - defines a destructor, which should delete the passed in object o
301 - anything static_SomeClassName_someMethodName(...) - defines a static method that is callable on instances and the meta class
301 - anything static_SomeClassName_someMethodName(...) - defines a static method that is callable on instances and the meta class
302 - anything someMethodName(SomeClassName* o, ...) - defines a slot that will be available on SomeClassName instances (and derived instances). When such a slot is called the first argument is the pointer to the instance and the rest of the arguments can be used to make a call on the instance.
302 - anything someMethodName(SomeClassName* o, ...) - defines a slot that will be available on SomeClassName instances (and derived instances). When such a slot is called the first argument is the pointer to the instance and the rest of the arguments can be used to make a call on the instance.
303
303
304 The below example shows all kinds of decorators in action:
304 The below example shows all kinds of decorators in action:
305
305
306 \code
306 \code
307
307
308 // an example CPP object
308 // an example CPP object
309 class YourCPPObject {
309 class YourCPPObject {
310 public:
310 public:
311 YourCPPObject(int arg1, float arg2) { a = arg1; b = arg2; }
311 YourCPPObject(int arg1, float arg2) { a = arg1; b = arg2; }
312
312
313 float doSomething(int arg1) { return arg1*a*b; };
313 float doSomething(int arg1) { return arg1*a*b; };
314
314
315 private:
315 private:
316
316
317 int a;
317 int a;
318 float b;
318 float b;
319 };
319 };
320
320
321 // an example decorator
321 // an example decorator
322 class ExampleDecorator : public QObject
322 class ExampleDecorator : public QObject
323 {
323 {
324 Q_OBJECT
324 Q_OBJECT
325
325
326 public slots:
326 public slots:
327 // add a constructor to QSize that takes a QPoint
327 // add a constructor to QSize that takes a QPoint
328 QSize* new_QSize(const QPoint& p) { return new QSize(p.x(), p.y()); }
328 QSize* new_QSize(const QPoint& p) { return new QSize(p.x(), p.y()); }
329
329
330 // add a constructor for QPushButton that takes a text and a parent widget
330 // add a constructor for QPushButton that takes a text and a parent widget
331 QPushButton* new_QPushButton(const QString& text, QWidget* parent=NULL) { return new QPushButton(text, parent); }
331 QPushButton* new_QPushButton(const QString& text, QWidget* parent=NULL) { return new QPushButton(text, parent); }
332
332
333 // add a constructor for a CPP object
333 // add a constructor for a CPP object
334 YourCPPObject* new_YourCPPObject(int arg1, float arg2) { return new YourCPPObject(arg1, arg2); }
334 YourCPPObject* new_YourCPPObject(int arg1, float arg2) { return new YourCPPObject(arg1, arg2); }
335
335
336 // add a destructor for a CPP object
336 // add a destructor for a CPP object
337 void delete_YourCPPObject(YourCPPObject* obj) { delete obj; }
337 void delete_YourCPPObject(YourCPPObject* obj) { delete obj; }
338
338
339 // add a static method to QWidget
339 // add a static method to QWidget
340 QWidget* static_QWidget_mouseGrabber() { return QWidget::mouseGrabber(); }
340 QWidget* static_QWidget_mouseGrabber() { return QWidget::mouseGrabber(); }
341
341
342 // add an additional slot to QWidget (make move() callable, which is not declared as a slot in QWidget)
342 // add an additional slot to QWidget (make move() callable, which is not declared as a slot in QWidget)
343 void move(QWidget* w, const QPoint& p) { w->move(p); }
343 void move(QWidget* w, const QPoint& p) { w->move(p); }
344
344
345 // add an additional slot to QWidget, overloading the above move method
345 // add an additional slot to QWidget, overloading the above move method
346 void move(QWidget* w, int x, int y) { w->move(x,y); }
346 void move(QWidget* w, int x, int y) { w->move(x,y); }
347
347
348 // add a method to your own CPP object
348 // add a method to your own CPP object
349 int doSomething(YourCPPObject* obj, int arg1) { return obj->doSomething(arg1); }
349 int doSomething(YourCPPObject* obj, int arg1) { return obj->doSomething(arg1); }
350 };
350 };
351
351
352 ...
352 ...
353
353
354 PythonQt::self()->addDecorators(new ExampleDecorator());
354 PythonQt::self()->addDecorators(new ExampleDecorator());
355 PythonQt::self()->registerCPPClass("YourCPPObject");
355 PythonQt::self()->registerCPPClass("YourCPPObject");
356
356
357 \endcode
357 \endcode
358
358
359 After you have registered an instance of the above ExampleDecorator, you can do the following from Python
359 After you have registered an instance of the above ExampleDecorator, you can do the following from Python
360 (all these calls are mapped to the above decorator slots):
360 (all these calls are mapped to the above decorator slots):
361
361
362 \code
362 \code
363 from PythonQt import QtCore, QtGui, YourCPPObject
363 from PythonQt import QtCore, QtGui, YourCPPObject
364
364
365 # call our new constructor of QSize
365 # call our new constructor of QSize
366 size = QtCore.QSize(QPoint(1,2));
366 size = QtCore.QSize(QPoint(1,2));
367
367
368 # call our new QPushButton constructor
368 # call our new QPushButton constructor
369 button = QtGui.QPushButton("sometext");
369 button = QtGui.QPushButton("sometext");
370
370
371 # call the move slot (overload1)
371 # call the move slot (overload1)
372 button.move(QPoint(0,0))
372 button.move(QPoint(0,0))
373
373
374 # call the move slot (overload2)
374 # call the move slot (overload2)
375 button.move(0,0)
375 button.move(0,0)
376
376
377 # call the static method
377 # call the static method
378 grabber = QtGui.QWidget.mouseWrapper();
378 grabber = QtGui.QWidget.mouseWrapper();
379
379
380 # create a CPP object via constructor
380 # create a CPP object via constructor
381 yourCpp = YourCPPObject(1,11.5)
381 yourCpp = YourCPPObject(1,11.5)
382
382
383 # call the wrapped method on CPP object
383 # call the wrapped method on CPP object
384 print yourCpp.doSomething(1);
384 print yourCpp.doSomething(1);
385
385
386 # destructor will be called:
386 # destructor will be called:
387 yourCpp = None
387 yourCpp = None
388
388
389 \endcode
389 \endcode
390
390
391 \section Building
391 \section Building
392
392
393 PythonQt requires Qt 4.6.1 (or higher) and Python 2.5 or 2.6 on Windows, Linux and MacOS X. It has not yet been tested with Python 3.x, but it should only require minor changes.
393 PythonQt requires Qt 4.6.1 (or higher) and Python 2.5 or 2.6 on Windows, Linux and MacOS X. It has not yet been tested with Python 3.x, but it should only require minor changes.
394 To compile PythonQt, you will need a python developer installation which includes Python's header files and
394 To compile PythonQt, you will need a python developer installation which includes Python's header files and
395 the python2x.[lib | dll | so | dynlib].
395 the python2x.[lib | dll | so | dynlib].
396 The build scripts a currently set to use Python 2.5.
396 The build scripts a currently set to use Python 2.5.
397 You may need to tweak the \b build/python.prf file to set the correct Python includes and libs on your system.
397 You may need to tweak the \b build/python.prf file to set the correct Python includes and libs on your system.
398
398
399 \subsection Windows
399 \subsection Windows
400
400
401 On Windows, the (non-source) Python Windows installer can be used.
401 On Windows, the (non-source) Python Windows installer can be used.
402 Make sure that you use the same compiler, the current Python distribution is built
402 Make sure that you use the same compiler, the current Python distribution is built
403 with Visual Studio 2003. If you want to use another compiler, you will need to build
403 with Visual Studio 2003. If you want to use another compiler, you will need to build
404 Python yourself, using your compiler.
404 Python yourself, using your compiler.
405
405
406 To build PythonQt, you need to set the environment variable \b PYTHON_PATH to point to the root
406 To build PythonQt, you need to set the environment variable \b PYTHON_PATH to point to the root
407 dir of the python installation and \b PYTHON_LIB to point to
407 dir of the python installation and \b PYTHON_LIB to point to
408 the directory where the python lib file is located.
408 the directory where the python lib file is located.
409
409
410 When using the prebuild Python installer, this will be:
410 When using the prebuild Python installer, this will be:
411
411
412 \code
412 \code
413 > set PYTHON_PATH = c:\Python25
413 > set PYTHON_PATH = c:\Python25
414 > set PYTHON_LIB = c:\Python25\libs
414 > set PYTHON_LIB = c:\Python25\libs
415 \endcode
415 \endcode
416
416
417 When using the python sources, this will be something like:
417 When using the python sources, this will be something like:
418
418
419 \code
419 \code
420 > set PYTHON_PATH = c:\yourDir\Python-2.5.1\
420 > set PYTHON_PATH = c:\yourDir\Python-2.5.1\
421 > set PYTHON_LIB = c:\yourDir\Python-2.5.1\PCbuild8\Win32
421 > set PYTHON_LIB = c:\yourDir\Python-2.5.1\PCbuild8\Win32
422 \endcode
422 \endcode
423
423
424 To build all, do the following (after setting the above variables):
424 To build all, do the following (after setting the above variables):
425
425
426 \code
426 \code
427 > cd PythonQtRoot
427 > cd PythonQtRoot
428 > vcvars32
428 > vcvars32
429 > qmake
429 > qmake
430 > nmake
430 > nmake
431 \endcode
431 \endcode
432
432
433 This should build everything. If Python can not be linked or include files can not be found,
433 This should build everything. If Python can not be linked or include files can not be found,
434 you probably need to tweak \b build/python.prf
434 you probably need to tweak \b build/python.prf
435
435
436 The tests and examples are located in PythonQt/lib.
436 The tests and examples are located in PythonQt/lib.
437
437
438 \subsection Linux
438 \subsection Linux
439
439
440 On Linux, you need to install a Python-dev package.
440 On Linux, you need to install a Python-dev package.
441 If Python can not be linked or include files can not be found,
441 If Python can not be linked or include files can not be found,
442 you probably need to tweak \b build/python.prf
442 you probably need to tweak \b build/python.prf
443
443
444 To build PythonQt, just do a:
444 To build PythonQt, just do a:
445
445
446 \code
446 \code
447 > cd PythonQtRoot
447 > cd PythonQtRoot
448 > qmake
448 > qmake
449 > make all
449 > make all
450 \endcode
450 \endcode
451
451
452 The tests and examples are located in PythonQt/lib.
452 The tests and examples are located in PythonQt/lib.
453 You should add PythonQt/lib to your LD_LIBRARY_PATH so that the runtime
453 You should add PythonQt/lib to your LD_LIBRARY_PATH so that the runtime
454 linker can find the *.so files.
454 linker can find the *.so files.
455
455
456 \subsection MacOsX
456 \subsection MacOsX
457
457
458 On Mac, Python is installed as a Framework, so you should not need to install it.
458 On Mac, Python is installed as a Framework, so you should not need to install it.
459 To build PythonQt, just do a:
459 To build PythonQt, just do a:
460
460
461 \code
461 \code
462 > cd PythonQtRoot
462 > cd PythonQtRoot
463 > qmake
463 > qmake
464 > make all
464 > make all
465 \endcode
465 \endcode
466
466
467 \section Tests
467 \section Tests
468
468
469 There is a unit test that tests most features of PythonQt, see the \b tests subdirectory for details.
469 There is a unit test that tests most features of PythonQt, see the \b tests subdirectory for details.
470
470
471 \section Examples
471 \section Examples
472
472
473 Examples are available in the \b examples directory. The PyScriptingConsole implements a simple
473 Examples are available in the \b examples directory. The PyScriptingConsole implements a simple
474 interactive scripting console that shows how to script a simple application.
474 interactive scripting console that shows how to script a simple application.
475
475
476 The following shows how to integrate PythonQt into you Qt application:
476 The following shows how to integrate PythonQt into you Qt application:
477
477
478 \code
478 \code
479 #include "PythonQt.h"
479 #include "PythonQt.h"
480 #include <QApplication>
480 #include <QApplication>
481 ...
481 ...
482
482
483 int main( int argc, char **argv )
483 int main( int argc, char **argv )
484 {
484 {
485
485
486 QApplication qapp(argc, argv);
486 QApplication qapp(argc, argv);
487
487
488 // init PythonQt and Python itself
488 // init PythonQt and Python itself
489 PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
489 PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
490
490
491
491
492 // get a smart pointer to the __main__ module of the Python interpreter
492 // get a smart pointer to the __main__ module of the Python interpreter
493 PythonQtObjectPtr mainContext = PythonQt::self()->getMainModule();
493 PythonQtObjectPtr mainContext = PythonQt::self()->getMainModule();
494
494
495 // add a QObject as variable of name "example" to the namespace of the __main__ module
495 // add a QObject as variable of name "example" to the namespace of the __main__ module
496 PyExampleObject example;
496 PyExampleObject example;
497 PythonQt::self()->addObject(mainContext, "example", &example);
497 PythonQt::self()->addObject(mainContext, "example", &example);
498
498
499 // do something
499 // do something
500 PythonQt::self()->runScript(mainContext, "print example\n");
500 PythonQt::self()->runScript(mainContext, "print example\n");
501 PythonQt::self()->runScript(mainContext, "def multiply(a,b):\n return a*b;\n");
501 PythonQt::self()->runScript(mainContext, "def multiply(a,b):\n return a*b;\n");
502 QVariantList args;
502 QVariantList args;
503 args << 42 << 47;
503 args << 42 << 47;
504 QVariant result = PythonQt::self()->call(mainContext,"multiply", args);
504 QVariant result = PythonQt::self()->call(mainContext,"multiply", args);
505 ...
505 ...
506 \endcode
506 \endcode
507
507
508
508
509 */
509 */
@@ -1,715 +1,726
1 /*
1 /*
2 *
2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2006 MeVis Research GmbH 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 Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Research GmbH, 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 PythonQtInstanceWrapper.cpp
35 // \file PythonQtInstanceWrapper.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 "PythonQtInstanceWrapper.h"
42 #include "PythonQtInstanceWrapper.h"
43 #include <QObject>
43 #include <QObject>
44 #include "PythonQt.h"
44 #include "PythonQt.h"
45 #include "PythonQtSlot.h"
45 #include "PythonQtSlot.h"
46 #include "PythonQtClassInfo.h"
46 #include "PythonQtClassInfo.h"
47 #include "PythonQtConversion.h"
47 #include "PythonQtConversion.h"
48 #include "PythonQtClassWrapper.h"
48 #include "PythonQtClassWrapper.h"
49
49
50 PythonQtClassInfo* PythonQtInstanceWrapperStruct::classInfo()
50 PythonQtClassInfo* PythonQtInstanceWrapperStruct::classInfo()
51 {
51 {
52 // take the class info from our type object
52 // take the class info from our type object
53 return ((PythonQtClassWrapper*)ob_type)->_classInfo;
53 return ((PythonQtClassWrapper*)ob_type)->_classInfo;
54 }
54 }
55
55
56 static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, bool force = false) {
56 static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, bool force = false) {
57
57
58 // is this a C++ wrapper?
58 // is this a C++ wrapper?
59 if (self->_wrappedPtr) {
59 if (self->_wrappedPtr) {
60 //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
60 //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
61
61
62 PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr);
62 PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr);
63 // we own our qobject, so we delete it now:
63 // we own our qobject, so we delete it now:
64 delete self->_obj;
64 delete self->_obj;
65 self->_obj = NULL;
65 self->_obj = NULL;
66 if (force || self->classInfo()->hasOwnerMethodButNoOwner(self->_wrappedPtr) || self->_ownedByPythonQt) {
66 if (force || self->classInfo()->hasOwnerMethodButNoOwner(self->_wrappedPtr) || self->_ownedByPythonQt) {
67 int type = self->classInfo()->metaTypeId();
67 int type = self->classInfo()->metaTypeId();
68 if (self->_useQMetaTypeDestroy && type>=0) {
68 if (self->_useQMetaTypeDestroy && type>=0) {
69 // use QMetaType to destroy the object
69 // use QMetaType to destroy the object
70 QMetaType::destroy(type, self->_wrappedPtr);
70 QMetaType::destroy(type, self->_wrappedPtr);
71 } else {
71 } else {
72 PythonQtSlotInfo* slot = self->classInfo()->destructor();
72 PythonQtSlotInfo* slot = self->classInfo()->destructor();
73 if (slot) {
73 if (slot) {
74 void* args[2];
74 void* args[2];
75 args[0] = NULL;
75 args[0] = NULL;
76 args[1] = &self->_wrappedPtr;
76 args[1] = &self->_wrappedPtr;
77 slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, slot->slotIndex(), args);
77 slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, slot->slotIndex(), args);
78 self->_wrappedPtr = NULL;
78 self->_wrappedPtr = NULL;
79 } else {
79 } else {
80 if (type>=0) {
80 if (type>=0) {
81 // use QMetaType to destroy the object
81 // use QMetaType to destroy the object
82 QMetaType::destroy(type, self->_wrappedPtr);
82 QMetaType::destroy(type, self->_wrappedPtr);
83 } else {
83 } else {
84 // TODO: warn about not being able to destroy the object?
84 // TODO: warn about not being able to destroy the object?
85 }
85 }
86 }
86 }
87 }
87 }
88 }
88 }
89 } else {
89 } else {
90 //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
90 //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
91 if (self->_objPointerCopy) {
91 if (self->_objPointerCopy) {
92 PythonQt::priv()->removeWrapperPointer(self->_objPointerCopy);
92 PythonQt::priv()->removeWrapperPointer(self->_objPointerCopy);
93 }
93 }
94 if (self->_obj) {
94 if (self->_obj) {
95 if (force || self->_ownedByPythonQt) {
95 if (force || self->_ownedByPythonQt) {
96 if (force || !self->_obj->parent()) {
96 if (force || !self->_obj->parent()) {
97 delete self->_obj;
97 delete self->_obj;
98 }
98 }
99 } else {
99 } else {
100 if (self->_obj->parent()==NULL) {
100 if (self->_obj->parent()==NULL) {
101 // tell someone who is interested that the qobject is no longer wrapped, if it has no parent
101 // tell someone who is interested that the qobject is no longer wrapped, if it has no parent
102 PythonQt::qObjectNoLongerWrappedCB(self->_obj);
102 PythonQt::qObjectNoLongerWrappedCB(self->_obj);
103 }
103 }
104 }
104 }
105 }
105 }
106 }
106 }
107 self->_obj = NULL;
107 self->_obj = NULL;
108 }
108 }
109
109
110 static void PythonQtInstanceWrapper_dealloc(PythonQtInstanceWrapper* self)
110 static void PythonQtInstanceWrapper_dealloc(PythonQtInstanceWrapper* self)
111 {
111 {
112 PythonQtInstanceWrapper_deleteObject(self);
112 PythonQtInstanceWrapper_deleteObject(self);
113 self->_obj.~QPointer<QObject>();
113 self->_obj.~QPointer<QObject>();
114 self->ob_type->tp_free((PyObject*)self);
114 self->ob_type->tp_free((PyObject*)self);
115 }
115 }
116
116
117 static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
117 static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
118 {
118 {
119 //PythonQtClassWrapper *classType = (PythonQtClassWrapper*)type;
119 //PythonQtClassWrapper *classType = (PythonQtClassWrapper*)type;
120 PythonQtInstanceWrapper *self;
120 PythonQtInstanceWrapper *self;
121 static PyObject* emptyTuple = NULL;
121 static PyObject* emptyTuple = NULL;
122 if (emptyTuple==NULL) {
122 if (emptyTuple==NULL) {
123 emptyTuple = PyTuple_New(0);
123 emptyTuple = PyTuple_New(0);
124 }
124 }
125
125
126 self = (PythonQtInstanceWrapper*)PyBaseObject_Type.tp_new(type, emptyTuple, NULL);
126 self = (PythonQtInstanceWrapper*)PyBaseObject_Type.tp_new(type, emptyTuple, NULL);
127
127
128 if (self != NULL) {
128 if (self != NULL) {
129 new (&self->_obj) QPointer<QObject>();
129 new (&self->_obj) QPointer<QObject>();
130 self->_wrappedPtr = NULL;
130 self->_wrappedPtr = NULL;
131 self->_ownedByPythonQt = false;
131 self->_ownedByPythonQt = false;
132 self->_useQMetaTypeDestroy = false;
132 self->_useQMetaTypeDestroy = false;
133 self->_isShellInstance = false;
133 self->_isShellInstance = false;
134 }
134 }
135 return (PyObject *)self;
135 return (PyObject *)self;
136 }
136 }
137
137
138 int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds)
138 int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds)
139 {
139 {
140 if (args == PythonQtPrivate::dummyTuple()) {
140 if (args == PythonQtPrivate::dummyTuple()) {
141 // we are called from the internal PythonQt API, so our data will be filled later on...
141 // we are called from the internal PythonQt API, so our data will be filled later on...
142 return 0;
142 return 0;
143 }
143 }
144
144
145 // we are called from python, try to construct our object
145 // we are called from python, try to construct our object
146 if (self->classInfo()->constructors()) {
146 if (self->classInfo()->constructors()) {
147 void* directCPPPointer = NULL;
147 void* directCPPPointer = NULL;
148 PythonQtSlotFunction_CallImpl(self->classInfo(), NULL, self->classInfo()->constructors(), args, kwds, NULL, &directCPPPointer);
148 PythonQtSlotFunction_CallImpl(self->classInfo(), NULL, self->classInfo()->constructors(), args, kwds, NULL, &directCPPPointer);
149 if (PyErr_Occurred()) {
149 if (PyErr_Occurred()) {
150 return -1;
150 return -1;
151 }
151 }
152 if (directCPPPointer) {
152 if (directCPPPointer) {
153 // change ownershipflag to be owned by PythonQt
153 // change ownershipflag to be owned by PythonQt
154 self->_ownedByPythonQt = true;
154 self->_ownedByPythonQt = true;
155 self->_useQMetaTypeDestroy = false;
155 self->_useQMetaTypeDestroy = false;
156 if (self->classInfo()->isCPPWrapper()) {
156 if (self->classInfo()->isCPPWrapper()) {
157 self->_wrappedPtr = directCPPPointer;
157 self->_wrappedPtr = directCPPPointer;
158 // TODO xxx: if there is a wrapper factory, we might want to generate a wrapper for our class?!
158 // TODO xxx: if there is a wrapper factory, we might want to generate a wrapper for our class?!
159 } else {
159 } else {
160 self->setQObject((QObject*)directCPPPointer);
160 self->setQObject((QObject*)directCPPPointer);
161 }
161 }
162 // register with PythonQt
162 // register with PythonQt
163 PythonQt::priv()->addWrapperPointer(directCPPPointer, self);
163 PythonQt::priv()->addWrapperPointer(directCPPPointer, self);
164
164
165 PythonQtShellSetInstanceWrapperCB* cb = self->classInfo()->shellSetInstanceWrapperCB();
165 PythonQtShellSetInstanceWrapperCB* cb = self->classInfo()->shellSetInstanceWrapperCB();
166 if (cb) {
166 if (cb) {
167 // if we are a derived python class, we set the wrapper
167 // if we are a derived python class, we set the wrapper
168 // to activate the shell class, otherwise we just ignore that it is a shell...
168 // to activate the shell class, otherwise we just ignore that it is a shell...
169 // we detect it be checking if the type does not have PythonQtInstanceWrapper_Type as direct base class,
169 // we detect it be checking if the type does not have PythonQtInstanceWrapper_Type as direct base class,
170 // which is the case for all non-python derived types
170 // which is the case for all non-python derived types
171 if (((PyObject*)self)->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
171 if (((PyObject*)self)->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
172 // set the wrapper and remember that we have a shell instance!
172 // set the wrapper and remember that we have a shell instance!
173 (*cb)(directCPPPointer, self);
173 (*cb)(directCPPPointer, self);
174 self->_isShellInstance = true;
174 self->_isShellInstance = true;
175 }
175 }
176 }
176 }
177 }
177 }
178 } else {
178 } else {
179 QString error = QString("No constructors available for ") + self->classInfo()->className();
179 QString error = QString("No constructors available for ") + self->classInfo()->className();
180 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
180 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
181 return -1;
181 return -1;
182 }
182 }
183 return 0;
183 return 0;
184 }
184 }
185
185
186 static PyObject *PythonQtInstanceWrapper_richcompare(PythonQtInstanceWrapper* wrapper, PyObject* other, int code)
186 static PyObject *PythonQtInstanceWrapper_richcompare(PythonQtInstanceWrapper* wrapper, PyObject* other, int code)
187 {
187 {
188 bool validPtrs = false;
188 bool validPtrs = false;
189 bool areSamePtrs = false;
189 bool areSamePtrs = false;
190 if (PyObject_TypeCheck((PyObject*)wrapper, &PythonQtInstanceWrapper_Type)) {
190 if (PyObject_TypeCheck((PyObject*)wrapper, &PythonQtInstanceWrapper_Type)) {
191 if (PyObject_TypeCheck(other, &PythonQtInstanceWrapper_Type)) {
191 if (PyObject_TypeCheck(other, &PythonQtInstanceWrapper_Type)) {
192 validPtrs = true;
192 validPtrs = true;
193 PythonQtInstanceWrapper* w1 = wrapper;
193 PythonQtInstanceWrapper* w1 = wrapper;
194 PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)other;
194 PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)other;
195 // check pointers directly
195 // check pointers directly
196 if (w1->_wrappedPtr != NULL) {
196 if (w1->_wrappedPtr != NULL) {
197 if (w1->_wrappedPtr == w2->_wrappedPtr) {
197 if (w1->_wrappedPtr == w2->_wrappedPtr) {
198 areSamePtrs = true;
198 areSamePtrs = true;
199 }
199 }
200 } else if (w1->_obj == w2->_obj) {
200 } else if (w1->_obj == w2->_obj) {
201 areSamePtrs = true;
201 areSamePtrs = true;
202 }
202 }
203 } else if (other == Py_None) {
203 } else if (other == Py_None) {
204 validPtrs = true;
204 validPtrs = true;
205 if (wrapper->_obj || wrapper->_wrappedPtr) {
205 if (wrapper->_obj || wrapper->_wrappedPtr) {
206 areSamePtrs = false;
206 areSamePtrs = false;
207 } else {
207 } else {
208 areSamePtrs = true;
208 areSamePtrs = true;
209 }
209 }
210 }
210 }
211 }
211 }
212
212
213 if ((wrapper->classInfo()->typeSlots() & PythonQt::Type_RichCompare) == 0) {
213 if ((wrapper->classInfo()->typeSlots() & PythonQt::Type_RichCompare) == 0) {
214 // shortcut if richcompare is not supported:
214 // shortcut if richcompare is not supported:
215 if (validPtrs && code == Py_EQ) {
215 if (validPtrs && code == Py_EQ) {
216 return PythonQtConv::GetPyBool(areSamePtrs);
216 return PythonQtConv::GetPyBool(areSamePtrs);
217 } else if (validPtrs && code == Py_NE) {
217 } else if (validPtrs && code == Py_NE) {
218 return PythonQtConv::GetPyBool(!areSamePtrs);
218 return PythonQtConv::GetPyBool(!areSamePtrs);
219 }
219 }
220 Py_INCREF(Py_NotImplemented);
220 Py_INCREF(Py_NotImplemented);
221 return Py_NotImplemented;
221 return Py_NotImplemented;
222 }
222 }
223
223
224 QByteArray memberName;
224 QByteArray memberName;
225 switch (code) {
225 switch (code) {
226 case Py_LT:
226 case Py_LT:
227 {
227 {
228 static QByteArray name = "__lt__";
228 static QByteArray name = "__lt__";
229 memberName = name;
229 memberName = name;
230 }
230 }
231 break;
231 break;
232
232
233 case Py_LE:
233 case Py_LE:
234 {
234 {
235 static QByteArray name = "__le__";
235 static QByteArray name = "__le__";
236 memberName = name;
236 memberName = name;
237 }
237 }
238 break;
238 break;
239
239
240 case Py_EQ:
240 case Py_EQ:
241 {
241 {
242 static QByteArray name = "__eq__";
242 static QByteArray name = "__eq__";
243 memberName = name;
243 memberName = name;
244 }
244 }
245 break;
245 break;
246
246
247 case Py_NE:
247 case Py_NE:
248 {
248 {
249 static QByteArray name = "__ne__";
249 static QByteArray name = "__ne__";
250 memberName = name;
250 memberName = name;
251 }
251 }
252 break;
252 break;
253
253
254 case Py_GT:
254 case Py_GT:
255 {
255 {
256 static QByteArray name = "__gt__";
256 static QByteArray name = "__gt__";
257 memberName = name;
257 memberName = name;
258 }
258 }
259 break;
259 break;
260
260
261 case Py_GE:
261 case Py_GE:
262 {
262 {
263 static QByteArray name = "__ge__";
263 static QByteArray name = "__ge__";
264 memberName = name;
264 memberName = name;
265 }
265 }
266 break;
266 break;
267 }
267 }
268
268
269 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
269 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
270 if (opSlot._type == PythonQtMemberInfo::Slot) {
270 if (opSlot._type == PythonQtMemberInfo::Slot) {
271 // TODO get rid of tuple
271 // TODO get rid of tuple
272 PyObject* args = PyTuple_New(1);
272 PyObject* args = PyTuple_New(1);
273 Py_INCREF(other);
273 Py_INCREF(other);
274 PyTuple_SET_ITEM(args, 0, other);
274 PyTuple_SET_ITEM(args, 0, other);
275 PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr);
275 PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr);
276 Py_DECREF(args);
276 Py_DECREF(args);
277 return result;
277 return result;
278 } else {
278 } else {
279 // not implemented, let python try something else!
279 // not implemented, let python try something else!
280 Py_INCREF(Py_NotImplemented);
280 Py_INCREF(Py_NotImplemented);
281 return Py_NotImplemented;
281 return Py_NotImplemented;
282 }
282 }
283 }
283 }
284
284
285
285
286 static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* obj)
286 static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* obj)
287 {
287 {
288 return PyString_FromString(obj->ob_type->tp_name);
288 return PyString_FromString(obj->ob_type->tp_name);
289 }
289 }
290
290
291 static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* obj)
291 static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* obj)
292 {
292 {
293 return PythonQt::self()->helpCalled(obj->classInfo());
293 return PythonQt::self()->helpCalled(obj->classInfo());
294 }
294 }
295
295
296 static PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self)
296 static PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self)
297 {
297 {
298 PythonQtInstanceWrapper_deleteObject(self, true);
298 PythonQtInstanceWrapper_deleteObject(self, true);
299 Py_INCREF(Py_None);
299 Py_INCREF(Py_None);
300 return Py_None;
300 return Py_None;
301 }
301 }
302
302
303
303
304 static PyMethodDef PythonQtInstanceWrapper_methods[] = {
304 static PyMethodDef PythonQtInstanceWrapper_methods[] = {
305 {"className", (PyCFunction)PythonQtInstanceWrapper_classname, METH_NOARGS,
305 {"className", (PyCFunction)PythonQtInstanceWrapper_classname, METH_NOARGS,
306 "Return the classname of the object"
306 "Return the classname of the object"
307 },
307 },
308 {"help", (PyCFunction)PythonQtInstanceWrapper_help, METH_NOARGS,
308 {"help", (PyCFunction)PythonQtInstanceWrapper_help, METH_NOARGS,
309 "Shows the help of available methods for this class"
309 "Shows the help of available methods for this class"
310 },
310 },
311 {"delete", (PyCFunction)PythonQtInstanceWrapper_delete, METH_NOARGS,
311 {"delete", (PyCFunction)PythonQtInstanceWrapper_delete, METH_NOARGS,
312 "Deletes the C++ object (at your own risk, my friend!)"
312 "Deletes the C++ object (at your own risk, my friend!)"
313 },
313 },
314 {NULL, NULL, 0, NULL} /* Sentinel */
314 {NULL, NULL, 0, NULL} /* Sentinel */
315 };
315 };
316
316
317
317
318 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
318 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
319 {
319 {
320 const char *attributeName;
320 const char *attributeName;
321 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
321 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
322
322
323 if ((attributeName = PyString_AsString(name)) == NULL) {
323 if ((attributeName = PyString_AsString(name)) == NULL) {
324 return NULL;
324 return NULL;
325 }
325 }
326
326
327 if (qstrcmp(attributeName, "__dict__")==0) {
327 if (qstrcmp(attributeName, "__dict__")==0) {
328 PyObject* dict = PyBaseObject_Type.tp_getattro(obj, name);
328 PyObject* dict = PyBaseObject_Type.tp_getattro(obj, name);
329 dict = PyDict_Copy(dict);
329 dict = PyDict_Copy(dict);
330
330
331 if (wrapper->_obj) {
331 if (wrapper->_obj) {
332 // only the properties are missing, the rest is already available from
332 // only the properties are missing, the rest is already available from
333 // PythonQtClassWrapper...
333 // PythonQtClassWrapper...
334 QStringList l = wrapper->classInfo()->propertyList();
334 QStringList l = wrapper->classInfo()->propertyList();
335 foreach (QString name, l) {
335 foreach (QString name, l) {
336 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
336 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
337 if (o) {
337 if (o) {
338 PyDict_SetItemString(dict, name.toLatin1().data(), o);
338 PyDict_SetItemString(dict, name.toLatin1().data(), o);
339 Py_DECREF(o);
339 Py_DECREF(o);
340 } else {
340 } else {
341 std::cerr << "PythonQtInstanceWrapper: something is wrong, could not get attribute " << name.toLatin1().data();
341 std::cerr << "PythonQtInstanceWrapper: something is wrong, could not get attribute " << name.toLatin1().data();
342 }
342 }
343 }
343 }
344
344
345 QList<QByteArray> dynamicProps = wrapper->_obj->dynamicPropertyNames();
345 QList<QByteArray> dynamicProps = wrapper->_obj->dynamicPropertyNames();
346 foreach (QByteArray name, dynamicProps) {
346 foreach (QByteArray name, dynamicProps) {
347 PyObject* o = PyObject_GetAttrString(obj, name.data());
347 PyObject* o = PyObject_GetAttrString(obj, name.data());
348 if (o) {
348 if (o) {
349 PyDict_SetItemString(dict, name.data(), o);
349 PyDict_SetItemString(dict, name.data(), o);
350 Py_DECREF(o);
350 Py_DECREF(o);
351 } else {
351 } else {
352 std::cerr << "PythonQtInstanceWrapper: dynamic property could not be read " << name.data();
352 std::cerr << "PythonQtInstanceWrapper: dynamic property could not be read " << name.data();
353 }
353 }
354 }
354 }
355 }
355 }
356 // Note: we do not put children into the dict, is would look confusing?!
356 // Note: we do not put children into the dict, is would look confusing?!
357 return dict;
357 return dict;
358 }
358 }
359
359
360 // first look in super, to return derived methods from base object first
360 // first look in super, to return derived methods from base object first
361 PyObject* superAttr = PyBaseObject_Type.tp_getattro(obj, name);
361 PyObject* superAttr = PyBaseObject_Type.tp_getattro(obj, name);
362 if (superAttr) {
362 if (superAttr) {
363 return superAttr;
363 return superAttr;
364 }
364 }
365 PyErr_Clear();
365 PyErr_Clear();
366
366
367 // mlabDebugConst("Python","get " << attributeName);
367 // mlabDebugConst("Python","get " << attributeName);
368
368
369 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
369 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
370 switch (member._type) {
370 switch (member._type) {
371 case PythonQtMemberInfo::Property:
371 case PythonQtMemberInfo::Property:
372 if (wrapper->_obj) {
372 if (wrapper->_obj) {
373 if (member._property.userType() != QVariant::Invalid) {
373 if (member._property.userType() != QVariant::Invalid) {
374 return PythonQtConv::QVariantToPyObject(member._property.read(wrapper->_obj));
374 return PythonQtConv::QVariantToPyObject(member._property.read(wrapper->_obj));
375 } else {
375 } else {
376 Py_INCREF(Py_None);
376 Py_INCREF(Py_None);
377 return Py_None;
377 return Py_None;
378 }
378 }
379 } else {
379 } else {
380 QString error = QString("Trying to read property '") + attributeName + "' from a destroyed " + wrapper->classInfo()->className() + " object";
380 QString error = QString("Trying to read property '") + attributeName + "' from a destroyed " + wrapper->classInfo()->className() + " object";
381 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
381 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
382 return NULL;
382 return NULL;
383 }
383 }
384 break;
384 break;
385 case PythonQtMemberInfo::Slot:
385 case PythonQtMemberInfo::Slot:
386 return PythonQtSlotFunction_New(member._slot, obj, NULL);
386 return PythonQtSlotFunction_New(member._slot, obj, NULL);
387 break;
387 break;
388 case PythonQtMemberInfo::EnumValue:
388 case PythonQtMemberInfo::EnumValue:
389 {
389 {
390 PyObject* enumValue = member._enumValue;
390 PyObject* enumValue = member._enumValue;
391 Py_INCREF(enumValue);
391 Py_INCREF(enumValue);
392 return enumValue;
392 return enumValue;
393 }
393 }
394 break;
394 break;
395 case PythonQtMemberInfo::EnumWrapper:
395 case PythonQtMemberInfo::EnumWrapper:
396 {
396 {
397 PyObject* enumWrapper = member._enumWrapper;
397 PyObject* enumWrapper = member._enumWrapper;
398 Py_INCREF(enumWrapper);
398 Py_INCREF(enumWrapper);
399 return enumWrapper;
399 return enumWrapper;
400 }
400 }
401 break;
401 break;
402 case PythonQtMemberInfo::NotFound:
402 case PythonQtMemberInfo::NotFound:
403 {
403 {
404 static const QByteArray getterString("py_get_");
404 static const QByteArray getterString("py_get_");
405 // check for a getter slot
405 // check for a getter slot
406 PythonQtMemberInfo member = wrapper->classInfo()->member(getterString + attributeName);
406 PythonQtMemberInfo member = wrapper->classInfo()->member(getterString + attributeName);
407 if (member._type == PythonQtMemberInfo::Slot) {
407 if (member._type == PythonQtMemberInfo::Slot) {
408 return PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, member._slot, NULL, NULL, wrapper->_wrappedPtr);
408 return PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, member._slot, NULL, NULL, wrapper->_wrappedPtr);
409 }
409 }
410
410
411 // handle dynamic properties
411 // handle dynamic properties
412 if (wrapper->_obj) {
412 if (wrapper->_obj) {
413 QVariant v = wrapper->_obj->property(attributeName);
413 QVariant v = wrapper->_obj->property(attributeName);
414 if (v.isValid()) {
414 if (v.isValid()) {
415 return PythonQtConv::QVariantToPyObject(v);
415 return PythonQtConv::QVariantToPyObject(v);
416 }
416 }
417 }
417 }
418 }
418 }
419 break;
419 break;
420 default:
420 default:
421 // is an invalid type, go on
421 // is an invalid type, go on
422 break;
422 break;
423 }
423 }
424
424
425 // look for the internal methods (className(), help())
425 // look for the internal methods (className(), help())
426 PyObject* internalMethod = Py_FindMethod( PythonQtInstanceWrapper_methods, obj, (char*)attributeName);
426 PyObject* internalMethod = Py_FindMethod( PythonQtInstanceWrapper_methods, obj, (char*)attributeName);
427 if (internalMethod) {
427 if (internalMethod) {
428 return internalMethod;
428 return internalMethod;
429 }
429 }
430 PyErr_Clear();
430 PyErr_Clear();
431
431
432 if (wrapper->_obj) {
432 if (wrapper->_obj) {
433 // look for a child
433 // look for a child
434 QObjectList children = wrapper->_obj->children();
434 QObjectList children = wrapper->_obj->children();
435 for (int i = 0; i < children.count(); i++) {
435 for (int i = 0; i < children.count(); i++) {
436 QObject *child = children.at(i);
436 QObject *child = children.at(i);
437 if (child->objectName() == attributeName) {
437 if (child->objectName() == attributeName) {
438 return PythonQt::priv()->wrapQObject(child);
438 return PythonQt::priv()->wrapQObject(child);
439 }
439 }
440 }
440 }
441 }
441 }
442
442
443 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
443 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
444 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
444 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
445 return NULL;
445 return NULL;
446 }
446 }
447
447
448 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
448 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
449 {
449 {
450 QString error;
450 QString error;
451 const char *attributeName;
451 const char *attributeName;
452 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
452 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
453
453
454 if ((attributeName = PyString_AsString(name)) == NULL)
454 if ((attributeName = PyString_AsString(name)) == NULL)
455 return -1;
455 return -1;
456
456
457 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
457 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
458 if (member._type == PythonQtMemberInfo::Property) {
458 if (member._type == PythonQtMemberInfo::Property) {
459
459
460 if (!wrapper->_obj) {
460 if (!wrapper->_obj) {
461 error = QString("Trying to set property '") + attributeName + "' on a destroyed " + wrapper->classInfo()->className() + " object";
461 error = QString("Trying to set property '") + attributeName + "' on a destroyed " + wrapper->classInfo()->className() + " object";
462 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
462 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
463 return -1;
463 return -1;
464 }
464 }
465
465
466 QMetaProperty prop = member._property;
466 QMetaProperty prop = member._property;
467 if (prop.isWritable()) {
467 if (prop.isWritable()) {
468 QVariant v;
468 QVariant v;
469 if (prop.isEnumType()) {
469 if (prop.isEnumType()) {
470 // this will give us either a string or an int, everything else will probably be an error
470 // this will give us either a string or an int, everything else will probably be an error
471 v = PythonQtConv::PyObjToQVariant(value);
471 v = PythonQtConv::PyObjToQVariant(value);
472 } else {
472 } else {
473 int t = prop.userType();
473 int t = prop.userType();
474 v = PythonQtConv::PyObjToQVariant(value, t);
474 v = PythonQtConv::PyObjToQVariant(value, t);
475 }
475 }
476 bool success = false;
476 bool success = false;
477 if (v.isValid()) {
477 if (v.isValid()) {
478 success = prop.write(wrapper->_obj, v);
478 success = prop.write(wrapper->_obj, v);
479 }
479 }
480 if (success) {
480 if (success) {
481 return 0;
481 return 0;
482 } else {
482 } else {
483 error = QString("Property '") + attributeName + "' of type '" +
483 error = QString("Property '") + attributeName + "' of type '" +
484 prop.typeName() + "' does not accept an object of type "
484 prop.typeName() + "' does not accept an object of type "
485 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
485 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
486 }
486 }
487 } else {
487 } else {
488 error = QString("Property '") + attributeName + "' of " + obj->ob_type->tp_name + " object is not writable";
488 error = QString("Property '") + attributeName + "' of " + obj->ob_type->tp_name + " object is not writable";
489 }
489 }
490 } else if (member._type == PythonQtMemberInfo::Slot) {
490 } else if (member._type == PythonQtMemberInfo::Slot) {
491 error = QString("Slot '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
491 error = QString("Slot '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
492 } else if (member._type == PythonQtMemberInfo::EnumValue) {
492 } else if (member._type == PythonQtMemberInfo::EnumValue) {
493 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
493 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
494 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
494 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
495 error = QString("Enum '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
495 error = QString("Enum '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
496 } else if (member._type == PythonQtMemberInfo::NotFound) {
496 } else if (member._type == PythonQtMemberInfo::NotFound) {
497 // check for a setter slot
497 // check for a setter slot
498 static const QByteArray setterString("py_set_");
498 static const QByteArray setterString("py_set_");
499 PythonQtMemberInfo setter = wrapper->classInfo()->member(setterString + attributeName);
499 PythonQtMemberInfo setter = wrapper->classInfo()->member(setterString + attributeName);
500 if (setter._type == PythonQtMemberInfo::Slot) {
500 if (setter._type == PythonQtMemberInfo::Slot) {
501 // call the setter and ignore the result value
501 // call the setter and ignore the result value
502 void* result;
502 void* result;
503 PyObject* args = PyTuple_New(1);
503 PyObject* args = PyTuple_New(1);
504 Py_INCREF(value);
504 Py_INCREF(value);
505 PyTuple_SET_ITEM(args, 0, value);
505 PyTuple_SET_ITEM(args, 0, value);
506 PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, setter._slot, args, NULL, wrapper->_wrappedPtr, &result);
506 PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, setter._slot, args, NULL, wrapper->_wrappedPtr, &result);
507 Py_DECREF(args);
507 Py_DECREF(args);
508 return 0;
508 return 0;
509 }
509 }
510
510
511 // handle dynamic properties
511 // handle dynamic properties
512 if (wrapper->_obj) {
512 if (wrapper->_obj) {
513 QVariant prop = wrapper->_obj->property(attributeName);
513 QVariant prop = wrapper->_obj->property(attributeName);
514 if (prop.isValid()) {
514 if (prop.isValid()) {
515 QVariant v = PythonQtConv::PyObjToQVariant(value);
515 QVariant v = PythonQtConv::PyObjToQVariant(value);
516 if (v.isValid()) {
516 if (v.isValid()) {
517 wrapper->_obj->setProperty(attributeName, v);
517 wrapper->_obj->setProperty(attributeName, v);
518 return 0;
518 return 0;
519 } else {
519 } else {
520 error = QString("Dynamic property '") + attributeName + "' does not accept an object of type "
520 error = QString("Dynamic property '") + attributeName + "' does not accept an object of type "
521 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
521 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
522 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
522 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
523 return -1;
523 return -1;
524 }
524 }
525 }
525 }
526 }
526 }
527
527
528 // if we are a derived python class, we allow setting attributes.
528 // if we are a derived python class, we allow setting attributes.
529 // if we are a direct CPP wrapper, we do NOT allow it, since
529 // if we are a direct CPP wrapper, we do NOT allow it, since
530 // it would be confusing to allow it because a wrapper will go away when it is not seen by python anymore
530 // it would be confusing to allow it because a wrapper will go away when it is not seen by python anymore
531 // and when it is recreated from a CPP pointer the attributes are gone...
531 // and when it is recreated from a CPP pointer the attributes are gone...
532 if (obj->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
532 if (obj->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
533 return PyBaseObject_Type.tp_setattro(obj,name,value);
533 return PyBaseObject_Type.tp_setattro(obj,name,value);
534 } else {
534 } else {
535 error = QString("'") + attributeName + "' does not exist on " + obj->ob_type->tp_name + " and creating new attributes on C++ objects is not allowed";
535 error = QString("'") + attributeName + "' does not exist on " + obj->ob_type->tp_name + " and creating new attributes on C++ objects is not allowed";
536 }
536 }
537 }
537 }
538
538
539 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
539 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
540 return -1;
540 return -1;
541 }
541 }
542
542
543 static QString getStringFromObject(PythonQtInstanceWrapper* wrapper) {
543 static QString getStringFromObject(PythonQtInstanceWrapper* wrapper) {
544 QString result;
544 QString result;
545 if (wrapper->_wrappedPtr) {
545 if (wrapper->_wrappedPtr) {
546 // first try some manually string conversions for some variants
546 // first try some manually string conversions for some variants
547 int metaid = wrapper->classInfo()->metaTypeId();
547 int metaid = wrapper->classInfo()->metaTypeId();
548 result = PythonQtConv::CPPObjectToString(metaid, wrapper->_wrappedPtr);
548 result = PythonQtConv::CPPObjectToString(metaid, wrapper->_wrappedPtr);
549 if (!result.isEmpty()) {
549 if (!result.isEmpty()) {
550 return result;
550 return result;
551 }
551 }
552 }
552 }
553 // next, try to call py_toString
553 // next, try to call py_toString
554 PythonQtMemberInfo info = wrapper->classInfo()->member("py_toString");
554 PythonQtMemberInfo info = wrapper->classInfo()->member("py_toString");
555 if (info._type == PythonQtMemberInfo::Slot) {
555 if (info._type == PythonQtMemberInfo::Slot) {
556 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, NULL, NULL, wrapper->_wrappedPtr);
556 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, NULL, NULL, wrapper->_wrappedPtr);
557 if (resultObj) {
557 if (resultObj) {
558 // TODO this is one conversion too much, would be nicer to call the slot directly...
558 // TODO this is one conversion too much, would be nicer to call the slot directly...
559 result = PythonQtConv::PyObjGetString(resultObj);
559 result = PythonQtConv::PyObjGetString(resultObj);
560 Py_DECREF(resultObj);
560 Py_DECREF(resultObj);
561 }
561 }
562 }
562 }
563 return result;
563 return result;
564 }
564 }
565
565
566 static PyObject * PythonQtInstanceWrapper_str(PyObject * obj)
566 static PyObject * PythonQtInstanceWrapper_str(PyObject * obj)
567 {
567 {
568 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
568 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
569
570 // QByteArray should be directly returned as a str
571 if (wrapper->classInfo()->metaTypeId()==QVariant::ByteArray) {
572 QByteArray* b = (QByteArray*) wrapper->_wrappedPtr;
573 if (b->data()) {
574 return PyString_FromStringAndSize(b->data(), b->size());
575 } else {
576 return PyString_FromString("");
577 }
578 }
579
569 const char* typeName = obj->ob_type->tp_name;
580 const char* typeName = obj->ob_type->tp_name;
570 QObject *qobj = wrapper->_obj;
581 QObject *qobj = wrapper->_obj;
571 QString str = getStringFromObject(wrapper);
582 QString str = getStringFromObject(wrapper);
572 if (!str.isEmpty()) {
583 if (!str.isEmpty()) {
573 return PyString_FromFormat("%s", str.toLatin1().constData());
584 return PyString_FromFormat("%s", str.toLatin1().constData());
574 }
585 }
575 if (wrapper->_wrappedPtr) {
586 if (wrapper->_wrappedPtr) {
576 if (wrapper->_obj) {
587 if (wrapper->_obj) {
577 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
588 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
578 } else {
589 } else {
579 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
590 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
580 }
591 }
581 } else {
592 } else {
582 return PyString_FromFormat("%s (QObject %p)", typeName, qobj);
593 return PyString_FromFormat("%s (QObject %p)", typeName, qobj);
583 }
594 }
584 }
595 }
585
596
586 static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj)
597 static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj)
587 {
598 {
588 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
599 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
589 const char* typeName = obj->ob_type->tp_name;
600 const char* typeName = obj->ob_type->tp_name;
590
601
591 QObject *qobj = wrapper->_obj;
602 QObject *qobj = wrapper->_obj;
592 QString str = getStringFromObject(wrapper);
603 QString str = getStringFromObject(wrapper);
593 if (!str.isEmpty()) {
604 if (!str.isEmpty()) {
594 if (str.startsWith(typeName)) {
605 if (str.startsWith(typeName)) {
595 return PyString_FromFormat("%s", str.toLatin1().constData());
606 return PyString_FromFormat("%s", str.toLatin1().constData());
596 } else {
607 } else {
597 return PyString_FromFormat("%s(%s, %p)", typeName, str.toLatin1().constData(), wrapper->_wrappedPtr);
608 return PyString_FromFormat("%s(%s, %p)", typeName, str.toLatin1().constData(), wrapper->_wrappedPtr);
598 }
609 }
599 }
610 }
600 if (wrapper->_wrappedPtr) {
611 if (wrapper->_wrappedPtr) {
601 if (wrapper->_obj) {
612 if (wrapper->_obj) {
602 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
613 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
603 } else {
614 } else {
604 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
615 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
605 }
616 }
606 } else {
617 } else {
607 return PyString_FromFormat("%s (%s %p)", typeName, wrapper->classInfo()->className(), qobj);
618 return PyString_FromFormat("%s (%s %p)", typeName, wrapper->classInfo()->className(), qobj);
608 }
619 }
609 }
620 }
610
621
611 static int PythonQtInstanceWrapper_builtin_nonzero(PyObject *obj)
622 static int PythonQtInstanceWrapper_builtin_nonzero(PyObject *obj)
612 {
623 {
613 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
624 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
614 return (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
625 return (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
615 }
626 }
616
627
617
628
618 static long PythonQtInstanceWrapper_hash(PythonQtInstanceWrapper *obj)
629 static long PythonQtInstanceWrapper_hash(PythonQtInstanceWrapper *obj)
619 {
630 {
620 if (obj->_wrappedPtr != NULL) {
631 if (obj->_wrappedPtr != NULL) {
621 return reinterpret_cast<long>(obj->_wrappedPtr);
632 return reinterpret_cast<long>(obj->_wrappedPtr);
622 } else {
633 } else {
623 QObject* qobj = obj->_obj; // get pointer from QPointer wrapper
634 QObject* qobj = obj->_obj; // get pointer from QPointer wrapper
624 return reinterpret_cast<long>(qobj);
635 return reinterpret_cast<long>(qobj);
625 }
636 }
626 }
637 }
627
638
628
639
629
640
630 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
641 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
631 static PyNumberMethods PythonQtInstanceWrapper_as_number = {
642 static PyNumberMethods PythonQtInstanceWrapper_as_number = {
632 0, /* nb_add */
643 0, /* nb_add */
633 0, /* nb_subtract */
644 0, /* nb_subtract */
634 0, /* nb_multiply */
645 0, /* nb_multiply */
635 0, /* nb_divide */
646 0, /* nb_divide */
636 0, /* nb_remainder */
647 0, /* nb_remainder */
637 0, /* nb_divmod */
648 0, /* nb_divmod */
638 0, /* nb_power */
649 0, /* nb_power */
639 0, /* nb_negative */
650 0, /* nb_negative */
640 0, /* nb_positive */
651 0, /* nb_positive */
641 0, /* nb_absolute */
652 0, /* nb_absolute */
642 PythonQtInstanceWrapper_builtin_nonzero, /* nb_nonzero */
653 PythonQtInstanceWrapper_builtin_nonzero, /* nb_nonzero */
643 0, /* nb_invert */
654 0, /* nb_invert */
644 0, /* nb_lshift */
655 0, /* nb_lshift */
645 0, /* nb_rshift */
656 0, /* nb_rshift */
646 0, /* nb_and */
657 0, /* nb_and */
647 0, /* nb_xor */
658 0, /* nb_xor */
648 0, /* nb_or */
659 0, /* nb_or */
649 0, /* nb_coerce */
660 0, /* nb_coerce */
650 0, /* nb_int */
661 0, /* nb_int */
651 0, /* nb_long */
662 0, /* nb_long */
652 0, /* nb_float */
663 0, /* nb_float */
653 0, /* nb_oct */
664 0, /* nb_oct */
654 0, /* nb_hex */
665 0, /* nb_hex */
655 0, /* nb_inplace_add */
666 0, /* nb_inplace_add */
656 0, /* nb_inplace_subtract */
667 0, /* nb_inplace_subtract */
657 0, /* nb_inplace_multiply */
668 0, /* nb_inplace_multiply */
658 0, /* nb_inplace_divide */
669 0, /* nb_inplace_divide */
659 0, /* nb_inplace_remainder */
670 0, /* nb_inplace_remainder */
660 0, /* nb_inplace_power */
671 0, /* nb_inplace_power */
661 0, /* nb_inplace_lshift */
672 0, /* nb_inplace_lshift */
662 0, /* nb_inplace_rshift */
673 0, /* nb_inplace_rshift */
663 0, /* nb_inplace_and */
674 0, /* nb_inplace_and */
664 0, /* nb_inplace_xor */
675 0, /* nb_inplace_xor */
665 0, /* nb_inplace_or */
676 0, /* nb_inplace_or */
666 0, /* nb_floor_divide */
677 0, /* nb_floor_divide */
667 0, /* nb_true_divide */
678 0, /* nb_true_divide */
668 0, /* nb_inplace_floor_divide */
679 0, /* nb_inplace_floor_divide */
669 0, /* nb_inplace_true_divide */
680 0, /* nb_inplace_true_divide */
670 };
681 };
671
682
672 PyTypeObject PythonQtInstanceWrapper_Type = {
683 PyTypeObject PythonQtInstanceWrapper_Type = {
673 PyObject_HEAD_INIT(&PythonQtClassWrapper_Type)
684 PyObject_HEAD_INIT(&PythonQtClassWrapper_Type)
674 0, /*ob_size*/
685 0, /*ob_size*/
675 "PythonQt.PythonQtInstanceWrapper", /*tp_name*/
686 "PythonQt.PythonQtInstanceWrapper", /*tp_name*/
676 sizeof(PythonQtInstanceWrapper), /*tp_basicsize*/
687 sizeof(PythonQtInstanceWrapper), /*tp_basicsize*/
677 0, /*tp_itemsize*/
688 0, /*tp_itemsize*/
678 (destructor)PythonQtInstanceWrapper_dealloc, /*tp_dealloc*/
689 (destructor)PythonQtInstanceWrapper_dealloc, /*tp_dealloc*/
679 0, /*tp_print*/
690 0, /*tp_print*/
680 0, /*tp_getattr*/
691 0, /*tp_getattr*/
681 0, /*tp_setattr*/
692 0, /*tp_setattr*/
682 0, /*tp_compare*/
693 0, /*tp_compare*/
683 PythonQtInstanceWrapper_repr, /*tp_repr*/
694 PythonQtInstanceWrapper_repr, /*tp_repr*/
684 &PythonQtInstanceWrapper_as_number, /*tp_as_number*/
695 &PythonQtInstanceWrapper_as_number, /*tp_as_number*/
685 0, /*tp_as_sequence*/
696 0, /*tp_as_sequence*/
686 0, /*tp_as_mapping*/
697 0, /*tp_as_mapping*/
687 (hashfunc)PythonQtInstanceWrapper_hash, /*tp_hash */
698 (hashfunc)PythonQtInstanceWrapper_hash, /*tp_hash */
688 0, /*tp_call*/
699 0, /*tp_call*/
689 PythonQtInstanceWrapper_str, /*tp_str*/
700 PythonQtInstanceWrapper_str, /*tp_str*/
690 PythonQtInstanceWrapper_getattro, /*tp_getattro*/
701 PythonQtInstanceWrapper_getattro, /*tp_getattro*/
691 PythonQtInstanceWrapper_setattro, /*tp_setattro*/
702 PythonQtInstanceWrapper_setattro, /*tp_setattro*/
692 0, /*tp_as_buffer*/
703 0, /*tp_as_buffer*/
693 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
704 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
694 "PythonQtInstanceWrapper object", /* tp_doc */
705 "PythonQtInstanceWrapper object", /* tp_doc */
695 0, /* tp_traverse */
706 0, /* tp_traverse */
696 0, /* tp_clear */
707 0, /* tp_clear */
697 (richcmpfunc)PythonQtInstanceWrapper_richcompare, /* tp_richcompare */
708 (richcmpfunc)PythonQtInstanceWrapper_richcompare, /* tp_richcompare */
698 0, /* tp_weaklistoffset */
709 0, /* tp_weaklistoffset */
699 0, /* tp_iter */
710 0, /* tp_iter */
700 0, /* tp_iternext */
711 0, /* tp_iternext */
701 0, /* tp_methods */
712 0, /* tp_methods */
702 0, /* tp_members */
713 0, /* tp_members */
703 0, /* tp_getset */
714 0, /* tp_getset */
704 0, /* tp_base */
715 0, /* tp_base */
705 0, /* tp_dict */
716 0, /* tp_dict */
706 0, /* tp_descr_get */
717 0, /* tp_descr_get */
707 0, /* tp_descr_set */
718 0, /* tp_descr_set */
708 0, /* tp_dictoffset */
719 0, /* tp_dictoffset */
709 (initproc)PythonQtInstanceWrapper_init, /* tp_init */
720 (initproc)PythonQtInstanceWrapper_init, /* tp_init */
710 0, /* tp_alloc */
721 0, /* tp_alloc */
711 PythonQtInstanceWrapper_new, /* tp_new */
722 PythonQtInstanceWrapper_new, /* tp_new */
712 };
723 };
713
724
714 //-------------------------------------------------------
725 //-------------------------------------------------------
715
726
General Comments 0
You need to be logged in to leave comments. Login now