##// END OF EJS Templates
adapted to new generator files...
florianlink -
r193:65af4461ce48
parent child
Show More
@@ -1,1781 +1,1793
1 /*
1 /*
2 *
2 *
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 *
4 *
5 * This library is free software; you can redistribute it and/or
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
8 * version 2.1 of the License, or (at your option) any later version.
9 *
9 *
10 * This library is distributed in the hope that it will be useful,
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
13 * Lesser General Public License for more details.
14 *
14 *
15 * Further, this software is distributed without any warranty that it is
15 * Further, this software is distributed without any warranty that it is
16 * free of the rightful claim of any third person regarding infringement
16 * free of the rightful claim of any third person regarding infringement
17 * or the like. Any license provided herein, whether implied or
17 * or the like. Any license provided herein, whether implied or
18 * otherwise, applies only to this software file. Patent licenses, if
18 * otherwise, applies only to this software file. Patent licenses, if
19 * any, provided herein do not apply to combinations of this program with
19 * any, provided herein do not apply to combinations of this program with
20 * other software, or any other product whatsoever.
20 * other software, or any other product whatsoever.
21 *
21 *
22 * You should have received a copy of the GNU Lesser General Public
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
25 *
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 * 28359 Bremen, Germany or:
27 * 28359 Bremen, Germany or:
28 *
28 *
29 * http://www.mevis.de
29 * http://www.mevis.de
30 *
30 *
31 */
31 */
32
32
33 //----------------------------------------------------------------------------------
33 //----------------------------------------------------------------------------------
34 /*!
34 /*!
35 // \file PythonQt.cpp
35 // \file PythonQt.cpp
36 // \author Florian Link
36 // \author Florian Link
37 // \author Last changed by $Author: florian $
37 // \author Last changed by $Author: florian $
38 // \date 2006-05
38 // \date 2006-05
39 */
39 */
40 //----------------------------------------------------------------------------------
40 //----------------------------------------------------------------------------------
41
41
42 #include "PythonQt.h"
42 #include "PythonQt.h"
43 #include "PythonQtImporter.h"
43 #include "PythonQtImporter.h"
44 #include "PythonQtClassInfo.h"
44 #include "PythonQtClassInfo.h"
45 #include "PythonQtMethodInfo.h"
45 #include "PythonQtMethodInfo.h"
46 #include "PythonQtSignal.h"
46 #include "PythonQtSignal.h"
47 #include "PythonQtSignalReceiver.h"
47 #include "PythonQtSignalReceiver.h"
48 #include "PythonQtConversion.h"
48 #include "PythonQtConversion.h"
49 #include "PythonQtStdIn.h"
49 #include "PythonQtStdIn.h"
50 #include "PythonQtStdOut.h"
50 #include "PythonQtStdOut.h"
51 #include "PythonQtCppWrapperFactory.h"
51 #include "PythonQtCppWrapperFactory.h"
52 #include "PythonQtVariants.h"
52 #include "PythonQtVariants.h"
53 #include "PythonQtStdDecorators.h"
53 #include "PythonQtStdDecorators.h"
54 #include "PythonQtQFileImporter.h"
54 #include "PythonQtQFileImporter.h"
55 #include <pydebug.h>
55 #include <pydebug.h>
56 #include <vector>
56 #include <vector>
57
57
58 PythonQt* PythonQt::_self = NULL;
58 PythonQt* PythonQt::_self = NULL;
59 int PythonQt::_uniqueModuleCount = 0;
59 int PythonQt::_uniqueModuleCount = 0;
60
60
61 void PythonQt_init_QtGuiBuiltin(PyObject*);
61 void PythonQt_init_QtGuiBuiltin(PyObject*);
62 void PythonQt_init_QtCoreBuiltin(PyObject*);
62 void PythonQt_init_QtCoreBuiltin(PyObject*);
63
63
64
64
65 PyObject* PythonQtConvertFromStringRef(const void* inObject, int /*metaTypeId*/)
65 PyObject* PythonQtConvertFromStringRef(const void* inObject, int /*metaTypeId*/)
66 {
66 {
67 return PythonQtConv::QStringToPyObject(((QStringRef*)inObject)->toString());
67 return PythonQtConv::QStringToPyObject(((QStringRef*)inObject)->toString());
68 }
68 }
69
69
70 void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
70 void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
71 {
71 {
72 if (!_self) {
72 if (!_self) {
73 _self = new PythonQt(flags, pythonQtModuleName);
73 _self = new PythonQt(flags, pythonQtModuleName);
74
74
75 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
75 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
76 qRegisterMetaType<QList<QObject*> >("QList<void*>");
76 qRegisterMetaType<QList<QObject*> >("QList<void*>");
77
77
78 int stringRefId = qRegisterMetaType<QStringRef>("QStringRef");
78 int stringRefId = qRegisterMetaType<QStringRef>("QStringRef");
79 PythonQtConv::registerMetaTypeToPythonConverter(stringRefId, PythonQtConvertFromStringRef);
79 PythonQtConv::registerMetaTypeToPythonConverter(stringRefId, PythonQtConvertFromStringRef);
80
80
81 PythonQtRegisterToolClassesTemplateConverter(int);
81 PythonQtRegisterToolClassesTemplateConverter(int);
82 PythonQtRegisterToolClassesTemplateConverter(float);
82 PythonQtRegisterToolClassesTemplateConverter(float);
83 PythonQtRegisterToolClassesTemplateConverter(double);
83 PythonQtRegisterToolClassesTemplateConverter(double);
84 PythonQtRegisterToolClassesTemplateConverter(qint32);
84 PythonQtRegisterToolClassesTemplateConverter(qint32);
85 PythonQtRegisterToolClassesTemplateConverter(quint32);
85 PythonQtRegisterToolClassesTemplateConverter(quint32);
86 PythonQtRegisterToolClassesTemplateConverter(qint64);
86 PythonQtRegisterToolClassesTemplateConverter(qint64);
87 PythonQtRegisterToolClassesTemplateConverter(quint64);
87 PythonQtRegisterToolClassesTemplateConverter(quint64);
88 // TODO: which other POD types should be available for QList etc.
88 // TODO: which other POD types should be available for QList etc.
89
89
90 PythonQt_init_QtCoreBuiltin(NULL);
90 PythonQt_init_QtCoreBuiltin(NULL);
91 PythonQt_init_QtGuiBuiltin(NULL);
91 PythonQt_init_QtGuiBuiltin(NULL);
92
92
93 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
93 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
94 PythonQt::self()->registerCPPClass("QMetaObject",0, "QtCore", PythonQtCreateObject<PythonQtWrapper_QMetaObject>);
94 PythonQt::self()->registerCPPClass("QMetaObject",0, "QtCore", PythonQtCreateObject<PythonQtWrapper_QMetaObject>);
95
95
96 PythonQtRegisterToolClassesTemplateConverter(QByteArray);
96 PythonQtRegisterToolClassesTemplateConverter(QByteArray);
97 PythonQtRegisterToolClassesTemplateConverter(QDate);
97 PythonQtRegisterToolClassesTemplateConverter(QDate);
98 PythonQtRegisterToolClassesTemplateConverter(QTime);
98 PythonQtRegisterToolClassesTemplateConverter(QTime);
99 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
99 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
100 PythonQtRegisterToolClassesTemplateConverter(QUrl);
100 PythonQtRegisterToolClassesTemplateConverter(QUrl);
101 PythonQtRegisterToolClassesTemplateConverter(QLocale);
101 PythonQtRegisterToolClassesTemplateConverter(QLocale);
102 PythonQtRegisterToolClassesTemplateConverter(QRect);
102 PythonQtRegisterToolClassesTemplateConverter(QRect);
103 PythonQtRegisterToolClassesTemplateConverter(QRectF);
103 PythonQtRegisterToolClassesTemplateConverter(QRectF);
104 PythonQtRegisterToolClassesTemplateConverter(QSize);
104 PythonQtRegisterToolClassesTemplateConverter(QSize);
105 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
105 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
106 PythonQtRegisterToolClassesTemplateConverter(QLine);
106 PythonQtRegisterToolClassesTemplateConverter(QLine);
107 PythonQtRegisterToolClassesTemplateConverter(QLineF);
107 PythonQtRegisterToolClassesTemplateConverter(QLineF);
108 PythonQtRegisterToolClassesTemplateConverter(QPoint);
108 PythonQtRegisterToolClassesTemplateConverter(QPoint);
109 PythonQtRegisterToolClassesTemplateConverter(QPointF);
109 PythonQtRegisterToolClassesTemplateConverter(QPointF);
110 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
110 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
111
111
112 PythonQtRegisterToolClassesTemplateConverter(QFont);
112 PythonQtRegisterToolClassesTemplateConverter(QFont);
113 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
113 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
114 PythonQtRegisterToolClassesTemplateConverter(QBrush);
114 PythonQtRegisterToolClassesTemplateConverter(QBrush);
115 PythonQtRegisterToolClassesTemplateConverter(QColor);
115 PythonQtRegisterToolClassesTemplateConverter(QColor);
116 PythonQtRegisterToolClassesTemplateConverter(QPalette);
116 PythonQtRegisterToolClassesTemplateConverter(QPalette);
117 PythonQtRegisterToolClassesTemplateConverter(QIcon);
117 PythonQtRegisterToolClassesTemplateConverter(QIcon);
118 PythonQtRegisterToolClassesTemplateConverter(QImage);
118 PythonQtRegisterToolClassesTemplateConverter(QImage);
119 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
119 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
120 PythonQtRegisterToolClassesTemplateConverter(QRegion);
120 PythonQtRegisterToolClassesTemplateConverter(QRegion);
121 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
121 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
122 PythonQtRegisterToolClassesTemplateConverter(QCursor);
122 PythonQtRegisterToolClassesTemplateConverter(QCursor);
123 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
123 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
124 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
124 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
125 PythonQtRegisterToolClassesTemplateConverter(QPen);
125 PythonQtRegisterToolClassesTemplateConverter(QPen);
126 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
126 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
127 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
127 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
128 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
128 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
129
129
130
130
131 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
131 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
132 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
132 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
133 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
133 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
134 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
134 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
135 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
135 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
136 for (unsigned int i = 0;i<16; i++) {
136 for (unsigned int i = 0;i<16; i++) {
137 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
137 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
138 if (obj) {
138 if (obj) {
139 PyModule_AddObject(pack, names[i], obj);
139 PyModule_AddObject(pack, names[i], obj);
140 Py_INCREF(obj);
140 Py_INCREF(obj);
141 PyModule_AddObject(pack2, names[i], obj);
141 PyModule_AddObject(pack2, names[i], obj);
142 } else {
142 } else {
143 std::cerr << "method not found " << names[i];
143 std::cerr << "method not found " << names[i];
144 }
144 }
145 }
145 }
146 }
146 }
147 }
147 }
148
148
149 void PythonQt::cleanup()
149 void PythonQt::cleanup()
150 {
150 {
151 if (_self) {
151 if (_self) {
152 delete _self;
152 delete _self;
153 _self = NULL;
153 _self = NULL;
154 }
154 }
155 }
155 }
156
156
157 PythonQt* PythonQt::self() { return _self; }
157 PythonQt* PythonQt::self() { return _self; }
158
158
159 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
159 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
160 {
160 {
161 _p = new PythonQtPrivate;
161 _p = new PythonQtPrivate;
162 _p->_initFlags = flags;
162 _p->_initFlags = flags;
163
163
164 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
164 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
165
165
166 if ((flags & PythonAlreadyInitialized) == 0) {
166 if ((flags & PythonAlreadyInitialized) == 0) {
167 Py_SetProgramName(const_cast<char*>("PythonQt"));
167 Py_SetProgramName(const_cast<char*>("PythonQt"));
168 if (flags & IgnoreSiteModule) {
168 if (flags & IgnoreSiteModule) {
169 // this prevents the automatic importing of Python site files
169 // this prevents the automatic importing of Python site files
170 Py_NoSiteFlag = 1;
170 Py_NoSiteFlag = 1;
171 }
171 }
172 Py_Initialize();
172 Py_Initialize();
173 }
173 }
174
174
175 // add our own python object types for qt object slots
175 // add our own python object types for qt object slots
176 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
176 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
177 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
177 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
178 }
178 }
179 Py_INCREF(&PythonQtSlotFunction_Type);
179 Py_INCREF(&PythonQtSlotFunction_Type);
180
180
181 if (PyType_Ready(&PythonQtSignalFunction_Type) < 0) {
181 if (PyType_Ready(&PythonQtSignalFunction_Type) < 0) {
182 std::cerr << "could not initialize PythonQtSignalFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
182 std::cerr << "could not initialize PythonQtSignalFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
183 }
183 }
184 Py_INCREF(&PythonQtSignalFunction_Type);
184 Py_INCREF(&PythonQtSignalFunction_Type);
185
185
186 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
186 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
187 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
187 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
188 // add our own python object types for classes
188 // add our own python object types for classes
189 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
189 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
190 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
190 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
191 }
191 }
192 Py_INCREF(&PythonQtClassWrapper_Type);
192 Py_INCREF(&PythonQtClassWrapper_Type);
193
193
194 // add our own python object types for CPP instances
194 // add our own python object types for CPP instances
195 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
195 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
196 PythonQt::handleError();
196 PythonQt::handleError();
197 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
197 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
198 }
198 }
199 Py_INCREF(&PythonQtInstanceWrapper_Type);
199 Py_INCREF(&PythonQtInstanceWrapper_Type);
200
200
201 // add our own python object types for redirection of stdout
201 // add our own python object types for redirection of stdout
202 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
202 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
203 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
203 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
204 }
204 }
205 Py_INCREF(&PythonQtStdOutRedirectType);
205 Py_INCREF(&PythonQtStdOutRedirectType);
206
206
207 // add our own python object types for redirection of stdin
207 // add our own python object types for redirection of stdin
208 if (PyType_Ready(&PythonQtStdInRedirectType) < 0) {
208 if (PyType_Ready(&PythonQtStdInRedirectType) < 0) {
209 std::cerr << "could not initialize PythonQtStdInRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
209 std::cerr << "could not initialize PythonQtStdInRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
210 }
210 }
211 Py_INCREF(&PythonQtStdInRedirectType);
211 Py_INCREF(&PythonQtStdInRedirectType);
212
212
213 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
213 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
214
214
215 _p->setupSharedLibrarySuffixes();
215 _p->setupSharedLibrarySuffixes();
216
216
217 }
217 }
218
218
219 PythonQt::~PythonQt() {
219 PythonQt::~PythonQt() {
220 delete _p;
220 delete _p;
221 _p = NULL;
221 _p = NULL;
222 }
222 }
223
223
224 PythonQtPrivate::~PythonQtPrivate() {
224 PythonQtPrivate::~PythonQtPrivate() {
225 delete _defaultImporter;
225 delete _defaultImporter;
226 _defaultImporter = NULL;
226 _defaultImporter = NULL;
227
227
228 {
228 {
229 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
229 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
230 while (i.hasNext()) {
230 while (i.hasNext()) {
231 delete i.next().value();
231 delete i.next().value();
232 }
232 }
233 }
233 }
234 PythonQtConv::global_valueStorage.clear();
234 PythonQtConv::global_valueStorage.clear();
235 PythonQtConv::global_ptrStorage.clear();
235 PythonQtConv::global_ptrStorage.clear();
236 PythonQtConv::global_variantStorage.clear();
236 PythonQtConv::global_variantStorage.clear();
237
237
238 PythonQtMethodInfo::cleanupCachedMethodInfos();
238 PythonQtMethodInfo::cleanupCachedMethodInfos();
239 }
239 }
240
240
241 void PythonQt::setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData)
241 void PythonQt::setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData)
242 {
242 {
243 if (!callback)
243 if (!callback)
244 {
244 {
245 std::cerr << "PythonQt::setRedirectStdInCallback - callback parameter is NULL !" << std::endl;
245 std::cerr << "PythonQt::setRedirectStdInCallback - callback parameter is NULL !" << std::endl;
246 return;
246 return;
247 }
247 }
248
248
249 PythonQtObjectPtr sys;
249 PythonQtObjectPtr sys;
250 PythonQtObjectPtr in;
250 PythonQtObjectPtr in;
251 sys.setNewRef(PyImport_ImportModule("sys"));
251 sys.setNewRef(PyImport_ImportModule("sys"));
252
252
253 // Backup original 'sys.stdin' if not yet done
253 // Backup original 'sys.stdin' if not yet done
254 PyRun_SimpleString("if not hasattr(sys, 'pythonqt_original_stdin'):"
254 PyRun_SimpleString("if not hasattr(sys, 'pythonqt_original_stdin'):"
255 "sys.pythonqt_original_stdin = sys.stdin");
255 "sys.pythonqt_original_stdin = sys.stdin");
256
256
257 in = PythonQtStdInRedirectType.tp_new(&PythonQtStdInRedirectType, NULL, NULL);
257 in = PythonQtStdInRedirectType.tp_new(&PythonQtStdInRedirectType, NULL, NULL);
258 ((PythonQtStdInRedirect*)in.object())->_cb = callback;
258 ((PythonQtStdInRedirect*)in.object())->_cb = callback;
259 ((PythonQtStdInRedirect*)in.object())->_callData = callbackData;
259 ((PythonQtStdInRedirect*)in.object())->_callData = callbackData;
260 // replace the built in file objects with our own objects
260 // replace the built in file objects with our own objects
261 PyModule_AddObject(sys, "stdin", in);
261 PyModule_AddObject(sys, "stdin", in);
262
262
263 // Backup custom 'stdin' into 'pythonqt_stdin'
263 // Backup custom 'stdin' into 'pythonqt_stdin'
264 PyRun_SimpleString("sys.pythonqt_stdin = sys.stdin");
264 PyRun_SimpleString("sys.pythonqt_stdin = sys.stdin");
265 }
265 }
266
266
267 void PythonQt::setRedirectStdInCallbackEnabled(bool enabled)
267 void PythonQt::setRedirectStdInCallbackEnabled(bool enabled)
268 {
268 {
269 if (enabled)
269 if (enabled)
270 {
270 {
271 PyRun_SimpleString("if hasattr(sys, 'pythonqt_stdin'):"
271 PyRun_SimpleString("if hasattr(sys, 'pythonqt_stdin'):"
272 "sys.stdin = sys.pythonqt_stdin");
272 "sys.stdin = sys.pythonqt_stdin");
273 }
273 }
274 else
274 else
275 {
275 {
276 PyRun_SimpleString("if hasattr(sys,'pythonqt_original_stdin'):"
276 PyRun_SimpleString("if hasattr(sys,'pythonqt_original_stdin'):"
277 "sys.stdin = sys.pythonqt_original_stdin");
277 "sys.stdin = sys.pythonqt_original_stdin");
278 }
278 }
279 }
279 }
280
280
281 PythonQtImportFileInterface* PythonQt::importInterface()
281 PythonQtImportFileInterface* PythonQt::importInterface()
282 {
282 {
283 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
283 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
284 }
284 }
285
285
286 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
286 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
287 {
287 {
288 if (_self->_p->_noLongerWrappedCB) {
288 if (_self->_p->_noLongerWrappedCB) {
289 (*_self->_p->_noLongerWrappedCB)(o);
289 (*_self->_p->_noLongerWrappedCB)(o);
290 };
290 };
291 }
291 }
292
292
293 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
293 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
294 {
294 {
295 _p->registerClass(metaobject, package, wrapperCreator, shell);
295 _p->registerClass(metaobject, package, wrapperCreator, shell);
296 }
296 }
297
297
298 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
298 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
299 {
299 {
300 // we register all classes in the hierarchy
300 // we register all classes in the hierarchy
301 const QMetaObject* m = metaobject;
301 const QMetaObject* m = metaobject;
302 bool first = true;
302 bool first = true;
303 while (m) {
303 while (m) {
304 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
304 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
305 if (!info->pythonQtClassWrapper()) {
305 if (!info->pythonQtClassWrapper()) {
306 info->setTypeSlots(typeSlots);
306 info->setTypeSlots(typeSlots);
307 info->setupQObject(m);
307 info->setupQObject(m);
308 createPythonQtClassWrapper(info, package, module);
308 createPythonQtClassWrapper(info, package, module);
309 if (m->superClass()) {
309 if (m->superClass()) {
310 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
310 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
311 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
311 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
312 }
312 }
313 } else if (first && module) {
313 } else if (first && module) {
314 // There is a wrapper already, but if we got a module, we want to place the wrapper into that module as well,
314 // There is a wrapper already, but if we got a module, we want to place the wrapper into that module as well,
315 // since it might have been placed into "private" earlier on.
315 // since it might have been placed into "private" earlier on.
316 // If the wrapper was already added to module before, it is just readded, which does no harm.
316 // If the wrapper was already added to module before, it is just readded, which does no harm.
317 PyObject* classWrapper = info->pythonQtClassWrapper();
317 PyObject* classWrapper = info->pythonQtClassWrapper();
318 // AddObject steals a reference, so we need to INCREF
318 // AddObject steals a reference, so we need to INCREF
319 Py_INCREF(classWrapper);
319 Py_INCREF(classWrapper);
320 PyModule_AddObject(module, info->className(), classWrapper);
320 PyModule_AddObject(module, info->className(), classWrapper);
321 }
321 }
322 if (first) {
322 if (first) {
323 first = false;
323 first = false;
324 if (wrapperCreator) {
324 if (wrapperCreator) {
325 info->setDecoratorProvider(wrapperCreator);
325 info->setDecoratorProvider(wrapperCreator);
326 }
326 }
327 if (shell) {
327 if (shell) {
328 info->setShellSetInstanceWrapperCB(shell);
328 info->setShellSetInstanceWrapperCB(shell);
329 }
329 }
330 }
330 }
331 m = m->superClass();
331 m = m->superClass();
332 }
332 }
333 }
333 }
334
334
335 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
335 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
336 {
336 {
337 PyObject* pack = module?module:packageByName(package);
337 PyObject* pack = module?module:packageByName(package);
338 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
338 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
339 PyModule_AddObject(pack, info->className(), pyobj);
339 PyModule_AddObject(pack, info->className(), pyobj);
340 if (!module && package && strncmp(package,"Qt",2)==0) {
340 if (!module && package && strncmp(package,"Qt",2)==0) {
341 // since PyModule_AddObject steals the reference, we need a incref once more...
341 // since PyModule_AddObject steals the reference, we need a incref once more...
342 Py_INCREF(pyobj);
342 Py_INCREF(pyobj);
343 // put all qt objects into Qt as well
343 // put all qt objects into Qt as well
344 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
344 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
345 }
345 }
346 info->setPythonQtClassWrapper(pyobj);
346 info->setPythonQtClassWrapper(pyobj);
347 }
347 }
348
348
349 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
349 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
350 {
350 {
351 if (!obj) {
351 if (!obj) {
352 Py_INCREF(Py_None);
352 Py_INCREF(Py_None);
353 return Py_None;
353 return Py_None;
354 }
354 }
355 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
355 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
356 if (wrap && wrap->_wrappedPtr) {
356 if (wrap && wrap->_wrappedPtr) {
357 // uh oh, we want to wrap a QObject, but have a C++ wrapper at that
357 // uh oh, we want to wrap a QObject, but have a C++ wrapper at that
358 // address, so probably that C++ wrapper has been deleted earlier and
358 // address, so probably that C++ wrapper has been deleted earlier and
359 // now we see a QObject with the same address.
359 // now we see a QObject with the same address.
360 // Do not use the old wrapper anymore.
360 // Do not use the old wrapper anymore.
361 wrap = NULL;
361 wrap = NULL;
362 }
362 }
363 if (!wrap) {
363 if (!wrap) {
364 // smuggling it in...
364 // smuggling it in...
365 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
365 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
366 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
366 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
367 registerClass(obj->metaObject());
367 registerClass(obj->metaObject());
368 classInfo = _knownClassInfos.value(obj->metaObject()->className());
368 classInfo = _knownClassInfos.value(obj->metaObject()->className());
369 }
369 }
370 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
370 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
371 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
371 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
372 } else {
372 } else {
373 Py_INCREF(wrap);
373 Py_INCREF(wrap);
374 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
374 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
375 }
375 }
376 return (PyObject*)wrap;
376 return (PyObject*)wrap;
377 }
377 }
378
378
379 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
379 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
380 {
380 {
381 if (!ptr) {
381 if (!ptr) {
382 Py_INCREF(Py_None);
382 Py_INCREF(Py_None);
383 return Py_None;
383 return Py_None;
384 }
384 }
385
385
386 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
386 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
387 PythonQtInstanceWrapper* possibleStillAliveWrapper = NULL;
387 PythonQtInstanceWrapper* possibleStillAliveWrapper = NULL;
388 if (wrap && wrap->_wrappedPtr) {
388 if (wrap && wrap->_wrappedPtr) {
389 // we have a previous C++ wrapper... if the wrapper is for a C++ object,
389 // we have a previous C++ wrapper... if the wrapper is for a C++ object,
390 // we are not sure if it may have been deleted earlier and we just see the same C++
390 // we are not sure if it may have been deleted earlier and we just see the same C++
391 // pointer once again. To make sure that we do not reuse a wrapper of the wrong type,
391 // pointer once again. To make sure that we do not reuse a wrapper of the wrong type,
392 // we compare the classInfo() pointer and only reuse the wrapper if it has the same
392 // we compare the classInfo() pointer and only reuse the wrapper if it has the same
393 // info. This is only needed for non-QObjects, since we know it when a QObject gets deleted.
393 // info. This is only needed for non-QObjects, since we know it when a QObject gets deleted.
394 possibleStillAliveWrapper = wrap;
394 possibleStillAliveWrapper = wrap;
395 wrap = NULL;
395 wrap = NULL;
396 }
396 }
397 if (!wrap) {
397 if (!wrap) {
398 PythonQtClassInfo* info = _knownClassInfos.value(name);
398 PythonQtClassInfo* info = _knownClassInfos.value(name);
399 if (!info) {
399 if (!info) {
400 // maybe it is a PyObject, which we can return directly
400 // maybe it is a PyObject, which we can return directly
401 if (name == "PyObject") {
401 if (name == "PyObject") {
402 PyObject* p = (PyObject*)ptr;
402 PyObject* p = (PyObject*)ptr;
403 Py_INCREF(p);
403 Py_INCREF(p);
404 return p;
404 return p;
405 }
405 }
406
406
407 // we do not know the metaobject yet, but we might know it by its name:
407 // we do not know the metaobject yet, but we might know it by its name:
408 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
408 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
409 // yes, we know it, so we can convert to QObject
409 // yes, we know it, so we can convert to QObject
410 QObject* qptr = (QObject*)ptr;
410 QObject* qptr = (QObject*)ptr;
411 registerClass(qptr->metaObject());
411 registerClass(qptr->metaObject());
412 info = _knownClassInfos.value(qptr->metaObject()->className());
412 info = _knownClassInfos.value(qptr->metaObject()->className());
413 }
413 }
414 }
414 }
415 if (info && info->isQObject()) {
415 if (info && info->isQObject()) {
416 QObject* qptr = (QObject*)ptr;
416 QObject* qptr = (QObject*)ptr;
417 // if the object is a derived object, we want to switch the class info to the one of the derived class:
417 // if the object is a derived object, we want to switch the class info to the one of the derived class:
418 if (name!=(qptr->metaObject()->className())) {
418 if (name!=(qptr->metaObject()->className())) {
419 registerClass(qptr->metaObject());
419 registerClass(qptr->metaObject());
420 info = _knownClassInfos.value(qptr->metaObject()->className());
420 info = _knownClassInfos.value(qptr->metaObject()->className());
421 }
421 }
422 wrap = createNewPythonQtInstanceWrapper(qptr, info);
422 wrap = createNewPythonQtInstanceWrapper(qptr, info);
423 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
423 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
424 return (PyObject*)wrap;
424 return (PyObject*)wrap;
425 }
425 }
426
426
427 // not a known QObject, try to wrap via foreign wrapper factories
427 // not a known QObject, try to wrap via foreign wrapper factories
428 PyObject* foreignWrapper = NULL;
428 PyObject* foreignWrapper = NULL;
429 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
429 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
430 foreignWrapper = _foreignWrapperFactories.at(i)->wrap(name, ptr);
430 foreignWrapper = _foreignWrapperFactories.at(i)->wrap(name, ptr);
431 if (foreignWrapper) {
431 if (foreignWrapper) {
432 return foreignWrapper;
432 return foreignWrapper;
433 }
433 }
434 }
434 }
435
435
436 // not a known QObject, so try our wrapper factory:
436 // not a known QObject, so try our wrapper factory:
437 QObject* wrapper = NULL;
437 QObject* wrapper = NULL;
438 for (int i=0; i<_cppWrapperFactories.size(); i++) {
438 for (int i=0; i<_cppWrapperFactories.size(); i++) {
439 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
439 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
440 if (wrapper) {
440 if (wrapper) {
441 break;
441 break;
442 }
442 }
443 }
443 }
444
444
445 if (info) {
445 if (info) {
446 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
446 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
447 ptr = info->castDownIfPossible(ptr, &info);
447 ptr = info->castDownIfPossible(ptr, &info);
448
448
449 // if downcasting found out that the object is a QObject,
449 // if downcasting found out that the object is a QObject,
450 // handle it like one:
450 // handle it like one:
451 if (info && info->isQObject()) {
451 if (info && info->isQObject()) {
452 QObject* qptr = (QObject*)ptr;
452 QObject* qptr = (QObject*)ptr;
453 // if the object is a derived object, we want to switch the class info to the one of the derived class:
453 // if the object is a derived object, we want to switch the class info to the one of the derived class:
454 if (name!=(qptr->metaObject()->className())) {
454 if (name!=(qptr->metaObject()->className())) {
455 registerClass(qptr->metaObject());
455 registerClass(qptr->metaObject());
456 info = _knownClassInfos.value(qptr->metaObject()->className());
456 info = _knownClassInfos.value(qptr->metaObject()->className());
457 }
457 }
458 wrap = createNewPythonQtInstanceWrapper(qptr, info);
458 wrap = createNewPythonQtInstanceWrapper(qptr, info);
459 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
459 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
460 return (PyObject*)wrap;
460 return (PyObject*)wrap;
461 }
461 }
462 }
462 }
463
463
464 if (!info || info->pythonQtClassWrapper()==NULL) {
464 if (!info || info->pythonQtClassWrapper()==NULL) {
465 // still unknown, register as CPP class
465 // still unknown, register as CPP class
466 registerCPPClass(name.constData());
466 registerCPPClass(name.constData());
467 info = _knownClassInfos.value(name);
467 info = _knownClassInfos.value(name);
468 }
468 }
469 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
469 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
470 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
470 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
471 info->setMetaObject(wrapper->metaObject());
471 info->setMetaObject(wrapper->metaObject());
472 }
472 }
473
473
474 if (possibleStillAliveWrapper && possibleStillAliveWrapper->classInfo() == info) {
474 if (possibleStillAliveWrapper && possibleStillAliveWrapper->classInfo() == info) {
475 wrap = possibleStillAliveWrapper;
475 wrap = possibleStillAliveWrapper;
476 Py_INCREF(wrap);
476 Py_INCREF(wrap);
477 } else {
477 } else {
478 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
478 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
479 }
479 }
480 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
480 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
481 } else {
481 } else {
482 Py_INCREF(wrap);
482 Py_INCREF(wrap);
483 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
483 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
484 }
484 }
485 return (PyObject*)wrap;
485 return (PyObject*)wrap;
486 }
486 }
487
487
488 PyObject* PythonQtPrivate::dummyTuple() {
488 PyObject* PythonQtPrivate::dummyTuple() {
489 static PyObject* dummyTuple = NULL;
489 static PyObject* dummyTuple = NULL;
490 if (dummyTuple==NULL) {
490 if (dummyTuple==NULL) {
491 dummyTuple = PyTuple_New(1);
491 dummyTuple = PyTuple_New(1);
492 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
492 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
493 }
493 }
494 return dummyTuple;
494 return dummyTuple;
495 }
495 }
496
496
497
497
498 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
498 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
499 // call the associated class type to create a new instance...
499 // call the associated class type to create a new instance...
500 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
500 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
501
501
502 result->setQObject(obj);
502 result->setQObject(obj);
503 result->_wrappedPtr = wrappedPtr;
503 result->_wrappedPtr = wrappedPtr;
504 result->_ownedByPythonQt = false;
504 result->_ownedByPythonQt = false;
505 result->_useQMetaTypeDestroy = false;
505 result->_useQMetaTypeDestroy = false;
506
506
507 if (wrappedPtr) {
507 if (wrappedPtr) {
508 _wrappedObjects.insert(wrappedPtr, result);
508 _wrappedObjects.insert(wrappedPtr, result);
509 } else {
509 } else {
510 _wrappedObjects.insert(obj, result);
510 _wrappedObjects.insert(obj, result);
511 if (obj->parent()== NULL && _wrappedCB) {
511 if (obj->parent()== NULL && _wrappedCB) {
512 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
512 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
513 (*_wrappedCB)(obj);
513 (*_wrappedCB)(obj);
514 }
514 }
515 }
515 }
516 return result;
516 return result;
517 }
517 }
518
518
519 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
519 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
520 PythonQtClassWrapper* result;
520 PythonQtClassWrapper* result;
521
521
522 PyObject* className = PyString_FromString(info->className());
522 PyObject* className = PyString_FromString(info->className());
523
523
524 PyObject* baseClasses = PyTuple_New(1);
524 PyObject* baseClasses = PyTuple_New(1);
525 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
525 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
526
526
527 PyObject* typeDict = PyDict_New();
527 PyObject* typeDict = PyDict_New();
528 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
528 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
529 PyDict_SetItemString(typeDict, "__module__", moduleName);
529 PyDict_SetItemString(typeDict, "__module__", moduleName);
530
530
531 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
531 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
532
532
533 // set the class info so that PythonQtClassWrapper_new can read it
533 // set the class info so that PythonQtClassWrapper_new can read it
534 _currentClassInfoForClassWrapperCreation = info;
534 _currentClassInfoForClassWrapperCreation = info;
535 // create the new type object by calling the type
535 // create the new type object by calling the type
536 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
536 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
537
537
538 Py_DECREF(baseClasses);
538 Py_DECREF(baseClasses);
539 Py_DECREF(typeDict);
539 Py_DECREF(typeDict);
540 Py_DECREF(args);
540 Py_DECREF(args);
541 Py_DECREF(className);
541 Py_DECREF(className);
542
542
543 return result;
543 return result;
544 }
544 }
545
545
546 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
546 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
547 {
547 {
548 PyObject* args = Py_BuildValue("(i)", enumValue);
548 PyObject* args = Py_BuildValue("(i)", enumValue);
549 PyObject* result = PyObject_Call(enumType, args, NULL);
549 PyObject* result = PyObject_Call(enumType, args, NULL);
550 Py_DECREF(args);
550 Py_DECREF(args);
551 return result;
551 return result;
552 }
552 }
553
553
554 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
554 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
555 PyObject* result;
555 PyObject* result;
556
556
557 PyObject* className = PyString_FromString(enumName);
557 PyObject* className = PyString_FromString(enumName);
558
558
559 PyObject* baseClasses = PyTuple_New(1);
559 PyObject* baseClasses = PyTuple_New(1);
560 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
560 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
561
561
562 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
562 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
563 PyObject* typeDict = PyDict_New();
563 PyObject* typeDict = PyDict_New();
564 PyDict_SetItemString(typeDict, "__module__", module);
564 PyDict_SetItemString(typeDict, "__module__", module);
565
565
566 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
566 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
567
567
568 // create the new int derived type object by calling the core type
568 // create the new int derived type object by calling the core type
569 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
569 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
570
570
571 Py_DECREF(baseClasses);
571 Py_DECREF(baseClasses);
572 Py_DECREF(typeDict);
572 Py_DECREF(typeDict);
573 Py_DECREF(args);
573 Py_DECREF(args);
574 Py_DECREF(className);
574 Py_DECREF(className);
575
575
576 return result;
576 return result;
577 }
577 }
578
578
579 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
579 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
580 {
580 {
581 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
581 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
582 if (!r) {
582 if (!r) {
583 r = new PythonQtSignalReceiver(obj);
583 r = new PythonQtSignalReceiver(obj);
584 _p->_signalReceivers.insert(obj, r);
584 _p->_signalReceivers.insert(obj, r);
585 }
585 }
586 return r;
586 return r;
587 }
587 }
588
588
589 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
589 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
590 {
590 {
591 bool flag = false;
591 bool flag = false;
592 PythonQtObjectPtr callable = lookupCallable(module, objectname);
592 PythonQtObjectPtr callable = lookupCallable(module, objectname);
593 if (callable) {
593 if (callable) {
594 PythonQtSignalReceiver* r = getSignalReceiver(obj);
594 PythonQtSignalReceiver* r = getSignalReceiver(obj);
595 flag = r->addSignalHandler(signal, callable);
595 flag = r->addSignalHandler(signal, callable);
596 if (!flag) {
596 if (!flag) {
597 // signal not found
597 // signal not found
598 }
598 }
599 } else {
599 } else {
600 // callable not found
600 // callable not found
601 }
601 }
602 return flag;
602 return flag;
603 }
603 }
604
604
605 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
605 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
606 {
606 {
607 bool flag = false;
607 bool flag = false;
608 PythonQtSignalReceiver* r = getSignalReceiver(obj);
608 PythonQtSignalReceiver* r = getSignalReceiver(obj);
609 if (r) {
609 if (r) {
610 flag = r->addSignalHandler(signal, receiver);
610 flag = r->addSignalHandler(signal, receiver);
611 }
611 }
612 return flag;
612 return flag;
613 }
613 }
614
614
615 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
615 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
616 {
616 {
617 bool flag = false;
617 bool flag = false;
618 PythonQtObjectPtr callable = lookupCallable(module, objectname);
618 PythonQtObjectPtr callable = lookupCallable(module, objectname);
619 if (callable) {
619 if (callable) {
620 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
620 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
621 if (r) {
621 if (r) {
622 flag = r->removeSignalHandler(signal, callable);
622 flag = r->removeSignalHandler(signal, callable);
623 }
623 }
624 } else {
624 } else {
625 // callable not found
625 // callable not found
626 }
626 }
627 return flag;
627 return flag;
628 }
628 }
629
629
630 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
630 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
631 {
631 {
632 bool flag = false;
632 bool flag = false;
633 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
633 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
634 if (r) {
634 if (r) {
635 flag = r->removeSignalHandler(signal, receiver);
635 flag = r->removeSignalHandler(signal, receiver);
636 }
636 }
637 return flag;
637 return flag;
638 }
638 }
639
639
640 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
640 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
641 {
641 {
642 PythonQtObjectPtr p = lookupObject(module, name);
642 PythonQtObjectPtr p = lookupObject(module, name);
643 if (p) {
643 if (p) {
644 if (PyCallable_Check(p)) {
644 if (PyCallable_Check(p)) {
645 return p;
645 return p;
646 }
646 }
647 }
647 }
648 PyErr_Clear();
648 PyErr_Clear();
649 return NULL;
649 return NULL;
650 }
650 }
651
651
652 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
652 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
653 {
653 {
654 QStringList l = name.split('.');
654 QStringList l = name.split('.');
655 PythonQtObjectPtr p = module;
655 PythonQtObjectPtr p = module;
656 PythonQtObjectPtr prev;
656 PythonQtObjectPtr prev;
657 QByteArray b;
657 QByteArray b;
658 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
658 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
659 prev = p;
659 prev = p;
660 b = (*i).toLatin1();
660 b = (*i).toLatin1();
661 if (PyDict_Check(p)) {
661 if (PyDict_Check(p)) {
662 p = PyDict_GetItemString(p, b.data());
662 p = PyDict_GetItemString(p, b.data());
663 } else {
663 } else {
664 p.setNewRef(PyObject_GetAttrString(p, b.data()));
664 p.setNewRef(PyObject_GetAttrString(p, b.data()));
665 }
665 }
666 }
666 }
667 PyErr_Clear();
667 PyErr_Clear();
668 return p;
668 return p;
669 }
669 }
670
670
671 PythonQtObjectPtr PythonQt::getMainModule() {
671 PythonQtObjectPtr PythonQt::getMainModule() {
672 //both borrowed
672 //both borrowed
673 PythonQtObjectPtr dict = PyImport_GetModuleDict();
673 PythonQtObjectPtr dict = PyImport_GetModuleDict();
674 return PyDict_GetItemString(dict, "__main__");
674 return PyDict_GetItemString(dict, "__main__");
675 }
675 }
676
676
677 PythonQtObjectPtr PythonQt::importModule(const QString& name)
677 PythonQtObjectPtr PythonQt::importModule(const QString& name)
678 {
678 {
679 PythonQtObjectPtr mod;
679 PythonQtObjectPtr mod;
680 mod.setNewRef(PyImport_ImportModule(name.toLatin1().constData()));
680 mod.setNewRef(PyImport_ImportModule(name.toLatin1().constData()));
681 return mod;
681 return mod;
682 }
682 }
683
683
684
684
685 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
685 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
686 QVariant result;
686 QVariant result;
687 if (pycode) {
687 if (pycode) {
688 PyObject* dict = NULL;
688 PyObject* dict = NULL;
689 PyObject* globals = NULL;
689 PyObject* globals = NULL;
690 if (PyModule_Check(object)) {
690 if (PyModule_Check(object)) {
691 dict = PyModule_GetDict(object);
691 dict = PyModule_GetDict(object);
692 globals = dict;
692 globals = dict;
693 } else if (PyDict_Check(object)) {
693 } else if (PyDict_Check(object)) {
694 dict = object;
694 dict = object;
695 globals = dict;
695 globals = dict;
696 } else {
696 } else {
697 dict = PyObject_GetAttrString(object, "__dict__");
697 dict = PyObject_GetAttrString(object, "__dict__");
698 globals = PyObject_GetAttrString(PyImport_ImportModule(PyString_AS_STRING(PyObject_GetAttrString(object, "__module__"))),"__dict__");
698 globals = PyObject_GetAttrString(PyImport_ImportModule(PyString_AS_STRING(PyObject_GetAttrString(object, "__module__"))),"__dict__");
699 }
699 }
700 PyObject* r = NULL;
700 PyObject* r = NULL;
701 if (dict) {
701 if (dict) {
702 r = PyEval_EvalCode((PyCodeObject*)pycode, globals , dict);
702 r = PyEval_EvalCode((PyCodeObject*)pycode, globals , dict);
703 }
703 }
704 if (r) {
704 if (r) {
705 result = PythonQtConv::PyObjToQVariant(r);
705 result = PythonQtConv::PyObjToQVariant(r);
706 Py_DECREF(r);
706 Py_DECREF(r);
707 } else {
707 } else {
708 handleError();
708 handleError();
709 }
709 }
710 } else {
710 } else {
711 handleError();
711 handleError();
712 }
712 }
713 return result;
713 return result;
714 }
714 }
715
715
716 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
716 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
717 {
717 {
718 QVariant result;
718 QVariant result;
719 PythonQtObjectPtr p;
719 PythonQtObjectPtr p;
720 PyObject* dict = NULL;
720 PyObject* dict = NULL;
721 if (PyModule_Check(object)) {
721 if (PyModule_Check(object)) {
722 dict = PyModule_GetDict(object);
722 dict = PyModule_GetDict(object);
723 } else if (PyDict_Check(object)) {
723 } else if (PyDict_Check(object)) {
724 dict = object;
724 dict = object;
725 }
725 }
726 if (dict) {
726 if (dict) {
727 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
727 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
728 }
728 }
729 if (p) {
729 if (p) {
730 result = PythonQtConv::PyObjToQVariant(p);
730 result = PythonQtConv::PyObjToQVariant(p);
731 } else {
731 } else {
732 handleError();
732 handleError();
733 }
733 }
734 return result;
734 return result;
735 }
735 }
736
736
737 void PythonQt::evalFile(PyObject* module, const QString& filename)
737 void PythonQt::evalFile(PyObject* module, const QString& filename)
738 {
738 {
739 PythonQtObjectPtr code = parseFile(filename);
739 PythonQtObjectPtr code = parseFile(filename);
740 if (code) {
740 if (code) {
741 evalCode(module, code);
741 evalCode(module, code);
742 } else {
742 } else {
743 handleError();
743 handleError();
744 }
744 }
745 }
745 }
746
746
747 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
747 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
748 {
748 {
749 PythonQtObjectPtr p;
749 PythonQtObjectPtr p;
750 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
750 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
751 if (!p) {
751 if (!p) {
752 handleError();
752 handleError();
753 }
753 }
754 return p;
754 return p;
755 }
755 }
756
756
757 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
757 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
758 {
758 {
759 PythonQtObjectPtr code = parseFile(filename);
759 PythonQtObjectPtr code = parseFile(filename);
760 PythonQtObjectPtr module = _p->createModule(name, code);
760 PythonQtObjectPtr module = _p->createModule(name, code);
761 return module;
761 return module;
762 }
762 }
763
763
764 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
764 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
765 {
765 {
766 PyErr_Clear();
766 PyErr_Clear();
767 QString scriptCode = script;
767 QString scriptCode = script;
768 if (scriptCode.isEmpty()) {
768 if (scriptCode.isEmpty()) {
769 // we always need at least a linefeed
769 // we always need at least a linefeed
770 scriptCode = "\n";
770 scriptCode = "\n";
771 }
771 }
772 PythonQtObjectPtr pycode;
772 PythonQtObjectPtr pycode;
773 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
773 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
774 PythonQtObjectPtr module = _p->createModule(name, pycode);
774 PythonQtObjectPtr module = _p->createModule(name, pycode);
775 return module;
775 return module;
776 }
776 }
777
777
778 PythonQtObjectPtr PythonQt::createUniqueModule()
778 PythonQtObjectPtr PythonQt::createUniqueModule()
779 {
779 {
780 static QString pyQtStr("PythonQt_module");
780 static QString pyQtStr("PythonQt_module");
781 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
781 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
782 return createModuleFromScript(moduleName);
782 return createModuleFromScript(moduleName);
783 }
783 }
784
784
785 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
785 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
786 {
786 {
787 if (PyModule_Check(object)) {
787 if (PyModule_Check(object)) {
788 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
788 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
789 } else if (PyDict_Check(object)) {
789 } else if (PyDict_Check(object)) {
790 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
790 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
791 } else {
791 } else {
792 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
792 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
793 }
793 }
794 }
794 }
795
795
796 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
796 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
797 {
797 {
798 if (PyModule_Check(object)) {
798 if (PyModule_Check(object)) {
799 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
799 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
800 } else if (PyDict_Check(object)) {
800 } else if (PyDict_Check(object)) {
801 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
801 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
802 } else {
802 } else {
803 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
803 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
804 }
804 }
805 }
805 }
806
806
807 void PythonQt::removeVariable(PyObject* object, const QString& name)
807 void PythonQt::removeVariable(PyObject* object, const QString& name)
808 {
808 {
809 if (PyDict_Check(object)) {
809 if (PyDict_Check(object)) {
810 PyDict_DelItemString(object, name.toLatin1().data());
810 PyDict_DelItemString(object, name.toLatin1().data());
811 } else {
811 } else {
812 PyObject_DelAttrString(object, name.toLatin1().data());
812 PyObject_DelAttrString(object, name.toLatin1().data());
813 }
813 }
814 }
814 }
815
815
816 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
816 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
817 {
817 {
818 QVariant result;
818 QVariant result;
819 PythonQtObjectPtr obj = lookupObject(object, objectname);
819 PythonQtObjectPtr obj = lookupObject(object, objectname);
820 if (obj) {
820 if (obj) {
821 result = PythonQtConv::PyObjToQVariant(obj);
821 result = PythonQtConv::PyObjToQVariant(obj);
822 }
822 }
823 return result;
823 return result;
824 }
824 }
825
825
826 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
826 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
827 {
827 {
828 QStringList results;
828 QStringList results;
829
829
830 PythonQtObjectPtr object;
830 PythonQtObjectPtr object;
831 if (objectname.isEmpty()) {
831 if (objectname.isEmpty()) {
832 object = module;
832 object = module;
833 } else {
833 } else {
834 object = lookupObject(module, objectname);
834 object = lookupObject(module, objectname);
835 if (!object && type == CallOverloads) {
835 if (!object && type == CallOverloads) {
836 PyObject* dict = lookupObject(module, "__builtins__");
836 PyObject* dict = lookupObject(module, "__builtins__");
837 if (dict) {
837 if (dict) {
838 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
838 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
839 }
839 }
840 }
840 }
841 }
841 }
842
842
843 if (object) {
843 if (object) {
844 results = introspectObject(object, type);
844 results = introspectObject(object, type);
845 }
845 }
846
846
847 return results;
847 return results;
848 }
848 }
849
849
850 QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
850 QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
851 {
851 {
852 QStringList results;
852 QStringList results;
853
853
854 if (type == CallOverloads) {
854 if (type == CallOverloads) {
855 if (PythonQtSlotFunction_Check(object)) {
855 if (PythonQtSlotFunction_Check(object)) {
856 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object;
856 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object;
857 PythonQtSlotInfo* info = o->m_ml;
857 PythonQtSlotInfo* info = o->m_ml;
858
858
859 while (info) {
859 while (info) {
860 results << info->fullSignature();
860 results << info->fullSignature();
861 info = info->nextInfo();
861 info = info->nextInfo();
862 }
862 }
863 } else if (PythonQtSignalFunction_Check(object)) {
863 } else if (PythonQtSignalFunction_Check(object)) {
864 PythonQtSignalFunctionObject* o = (PythonQtSignalFunctionObject*)object;
864 PythonQtSignalFunctionObject* o = (PythonQtSignalFunctionObject*)object;
865 PythonQtSlotInfo* info = o->m_ml;
865 PythonQtSlotInfo* info = o->m_ml;
866
866
867 while (info) {
867 while (info) {
868 results << info->fullSignature();
868 results << info->fullSignature();
869 info = info->nextInfo();
869 info = info->nextInfo();
870 }
870 }
871 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
871 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
872 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
872 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
873 PythonQtSlotInfo* info = o->classInfo()->constructors();
873 PythonQtSlotInfo* info = o->classInfo()->constructors();
874
874
875 while (info) {
875 while (info) {
876 results << info->fullSignature();
876 results << info->fullSignature();
877 info = info->nextInfo();
877 info = info->nextInfo();
878 }
878 }
879 } else {
879 } else {
880 QString signature = _p->getSignature(object);
880 QString signature = _p->getSignature(object);
881 if (!signature.isEmpty()) {
881 if (!signature.isEmpty()) {
882 results << signature;
882 results << signature;
883 } else {
883 } else {
884 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
884 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
885 if (doc) {
885 if (doc) {
886 results << PyString_AsString(doc);
886 results << PyString_AsString(doc);
887 Py_DECREF(doc);
887 Py_DECREF(doc);
888 }
888 }
889 }
889 }
890 }
890 }
891 } else {
891 } else {
892 PyObject* keys = NULL;
892 PyObject* keys = NULL;
893 bool isDict = false;
893 bool isDict = false;
894 if (PyDict_Check(object)) {
894 if (PyDict_Check(object)) {
895 keys = PyDict_Keys(object);
895 keys = PyDict_Keys(object);
896 isDict = true;
896 isDict = true;
897 } else {
897 } else {
898 keys = PyObject_Dir(object);
898 keys = PyObject_Dir(object);
899 }
899 }
900 if (keys) {
900 if (keys) {
901 int count = PyList_Size(keys);
901 int count = PyList_Size(keys);
902 PyObject* key;
902 PyObject* key;
903 PyObject* value;
903 PyObject* value;
904 QString keystr;
904 QString keystr;
905 for (int i = 0;i<count;i++) {
905 for (int i = 0;i<count;i++) {
906 key = PyList_GetItem(keys,i);
906 key = PyList_GetItem(keys,i);
907 if (isDict) {
907 if (isDict) {
908 value = PyDict_GetItem(object, key);
908 value = PyDict_GetItem(object, key);
909 Py_INCREF(value);
909 Py_INCREF(value);
910 } else {
910 } else {
911 value = PyObject_GetAttr(object, key);
911 value = PyObject_GetAttr(object, key);
912 }
912 }
913 if (!value) continue;
913 if (!value) continue;
914 keystr = PyString_AsString(key);
914 keystr = PyString_AsString(key);
915 static const QString underscoreStr("__tmp");
915 static const QString underscoreStr("__tmp");
916 if (!keystr.startsWith(underscoreStr)) {
916 if (!keystr.startsWith(underscoreStr)) {
917 switch (type) {
917 switch (type) {
918 case Anything:
918 case Anything:
919 results << keystr;
919 results << keystr;
920 break;
920 break;
921 case Class:
921 case Class:
922 if (value->ob_type == &PyClass_Type || value->ob_type == &PyType_Type) {
922 if (value->ob_type == &PyClass_Type || value->ob_type == &PyType_Type) {
923 results << keystr;
923 results << keystr;
924 }
924 }
925 break;
925 break;
926 case Variable:
926 case Variable:
927 if (value->ob_type != &PyClass_Type
927 if (value->ob_type != &PyClass_Type
928 && value->ob_type != &PyCFunction_Type
928 && value->ob_type != &PyCFunction_Type
929 && value->ob_type != &PyFunction_Type
929 && value->ob_type != &PyFunction_Type
930 && value->ob_type != &PyMethod_Type
930 && value->ob_type != &PyMethod_Type
931 && value->ob_type != &PyModule_Type
931 && value->ob_type != &PyModule_Type
932 && value->ob_type != &PyType_Type
932 && value->ob_type != &PyType_Type
933 && value->ob_type != &PythonQtSlotFunction_Type
933 && value->ob_type != &PythonQtSlotFunction_Type
934 ) {
934 ) {
935 results << keystr;
935 results << keystr;
936 }
936 }
937 break;
937 break;
938 case Function:
938 case Function:
939 if (value->ob_type == &PyCFunction_Type ||
939 if (value->ob_type == &PyCFunction_Type ||
940 value->ob_type == &PyFunction_Type ||
940 value->ob_type == &PyFunction_Type ||
941 value->ob_type == &PyMethod_Type ||
941 value->ob_type == &PyMethod_Type ||
942 value->ob_type == &PythonQtSlotFunction_Type
942 value->ob_type == &PythonQtSlotFunction_Type
943 ) {
943 ) {
944 results << keystr;
944 results << keystr;
945 }
945 }
946 break;
946 break;
947 case Module:
947 case Module:
948 if (value->ob_type == &PyModule_Type) {
948 if (value->ob_type == &PyModule_Type) {
949 results << keystr;
949 results << keystr;
950 }
950 }
951 break;
951 break;
952 default:
952 default:
953 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
953 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
954 }
954 }
955 }
955 }
956 Py_DECREF(value);
956 Py_DECREF(value);
957 }
957 }
958 Py_DECREF(keys);
958 Py_DECREF(keys);
959 }
959 }
960 if ((type == Anything) || (type == Variable)) {
960 if ((type == Anything) || (type == Variable)) {
961 if (object->ob_type == &PythonQtClassWrapper_Type) {
961 if (object->ob_type == &PythonQtClassWrapper_Type) {
962 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
962 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
963 PythonQtClassInfo* info = o->classInfo();
963 PythonQtClassInfo* info = o->classInfo();
964 results += info->propertyList();
964 results += info->propertyList();
965 }
965 }
966 }
966 }
967 }
967 }
968 return results;
968 return results;
969 }
969 }
970
970
971 PyObject* PythonQt::getObjectByType(const QString& typeName)
971 PyObject* PythonQt::getObjectByType(const QString& typeName)
972 {
972 {
973 PythonQtObjectPtr sys;
973 PythonQtObjectPtr sys;
974 sys.setNewRef(PyImport_ImportModule("sys"));
974 sys.setNewRef(PyImport_ImportModule("sys"));
975 PythonQtObjectPtr modules = lookupObject(sys, "modules");
975 PythonQtObjectPtr modules = lookupObject(sys, "modules");
976 Q_ASSERT(PyDict_Check(modules));
976 Q_ASSERT(PyDict_Check(modules));
977
977
978 QStringList tmp = typeName.split(".");
978 QStringList tmp = typeName.split(".");
979 QString simpleTypeName = tmp.takeLast();
979 QString simpleTypeName = tmp.takeLast();
980 QString moduleName = tmp.join(".");
980 QString moduleName = tmp.join(".");
981
981
982 PyObject* object = NULL;
982 PyObject* object = NULL;
983 PyObject* moduleObject = PyDict_GetItemString(modules, moduleName.toLatin1().constData());
983 PyObject* moduleObject = PyDict_GetItemString(modules, moduleName.toLatin1().constData());
984 if (moduleObject) {
984 if (moduleObject) {
985 object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
985 object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
986 }
986 }
987
987
988 if (!object) {
988 if (!object) {
989 moduleObject = PyDict_GetItemString(modules, "__builtin__");
989 moduleObject = PyDict_GetItemString(modules, "__builtin__");
990 if (moduleObject) {
990 if (moduleObject) {
991 object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
991 object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
992 }
992 }
993 }
993 }
994
994
995 return object;
995 return object;
996 }
996 }
997
997
998 QStringList PythonQt::introspectType(const QString& typeName, ObjectType type)
998 QStringList PythonQt::introspectType(const QString& typeName, ObjectType type)
999 {
999 {
1000 QStringList results;
1000 QStringList results;
1001 PyObject* object = getObjectByType(typeName);
1001 PyObject* object = getObjectByType(typeName);
1002 if (!object) {
1002 if (!object) {
1003 // the last item may be a member, split it away and try again
1003 // the last item may be a member, split it away and try again
1004 QStringList tmp = typeName.split(".");
1004 QStringList tmp = typeName.split(".");
1005 QString memberName = tmp.takeLast();
1005 QString memberName = tmp.takeLast();
1006 QString typeName;
1006 QString typeName;
1007 if (tmp.isEmpty()) {
1007 if (tmp.isEmpty()) {
1008 typeName = memberName;
1008 typeName = memberName;
1009 memberName.clear();
1009 memberName.clear();
1010 } else {
1010 } else {
1011 typeName = tmp.takeLast();
1011 typeName = tmp.takeLast();
1012 }
1012 }
1013 PyObject* typeObject = getObjectByType(typeName);
1013 PyObject* typeObject = getObjectByType(typeName);
1014 if (typeObject) {
1014 if (typeObject) {
1015 object = PyObject_GetAttrString(typeObject, memberName.toLatin1().constData());
1015 object = PyObject_GetAttrString(typeObject, memberName.toLatin1().constData());
1016 }
1016 }
1017 }
1017 }
1018 if (object) {
1018 if (object) {
1019 results = introspectObject(object, type);
1019 results = introspectObject(object, type);
1020 Py_DECREF(object);
1020 Py_DECREF(object);
1021 }
1021 }
1022 return results;
1022 return results;
1023 }
1023 }
1024
1024
1025 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args, const QVariantMap& kwargs)
1025 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args, const QVariantMap& kwargs)
1026 {
1026 {
1027 PythonQtObjectPtr callable = lookupCallable(object, name);
1027 PythonQtObjectPtr callable = lookupCallable(object, name);
1028 if (callable) {
1028 if (callable) {
1029 return call(callable, args, kwargs);
1029 return call(callable, args, kwargs);
1030 } else {
1030 } else {
1031 return QVariant();
1031 return QVariant();
1032 }
1032 }
1033 }
1033 }
1034
1034
1035 QVariant PythonQt::call(PyObject* callable, const QVariantList& args, const QVariantMap& kwargs)
1035 QVariant PythonQt::call(PyObject* callable, const QVariantList& args, const QVariantMap& kwargs)
1036 {
1036 {
1037 QVariant r;
1037 QVariant r;
1038 PythonQtObjectPtr result;
1038 PythonQtObjectPtr result;
1039 result.setNewRef(callAndReturnPyObject(callable, args, kwargs));
1039 result.setNewRef(callAndReturnPyObject(callable, args, kwargs));
1040 if (result) {
1040 if (result) {
1041 r = PythonQtConv::PyObjToQVariant(result);
1041 r = PythonQtConv::PyObjToQVariant(result);
1042 } else {
1042 } else {
1043 PythonQt::self()->handleError();
1043 PythonQt::self()->handleError();
1044 }
1044 }
1045 return r;
1045 return r;
1046 }
1046 }
1047
1047
1048 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args, const QVariantMap& kwargs)
1048 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args, const QVariantMap& kwargs)
1049 {
1049 {
1050 PyObject* result = NULL;
1050 PyObject* result = NULL;
1051 if (callable) {
1051 if (callable) {
1052 bool err = false;
1052 bool err = false;
1053 PythonQtObjectPtr pargs;
1053 PythonQtObjectPtr pargs;
1054 int count = args.size();
1054 int count = args.size();
1055 if ((count > 0) || (kwargs.count() > 0)) { // create empty tuple if kwargs are given
1055 if ((count > 0) || (kwargs.count() > 0)) { // create empty tuple if kwargs are given
1056 pargs.setNewRef(PyTuple_New(count));
1056 pargs.setNewRef(PyTuple_New(count));
1057
1057
1058 // transform QVariant arguments to Python
1058 // transform QVariant arguments to Python
1059 for (int i = 0; i < count; i++) {
1059 for (int i = 0; i < count; i++) {
1060 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
1060 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
1061 if (arg) {
1061 if (arg) {
1062 // steals reference, no unref
1062 // steals reference, no unref
1063 PyTuple_SetItem(pargs, i,arg);
1063 PyTuple_SetItem(pargs, i,arg);
1064 } else {
1064 } else {
1065 err = true;
1065 err = true;
1066 break;
1066 break;
1067 }
1067 }
1068 }
1068 }
1069 }
1069 }
1070 if (!err) {
1070 if (!err) {
1071 if (kwargs.isEmpty()) {
1071 if (kwargs.isEmpty()) {
1072 // do a direct call if we have no keyword arguments
1072 // do a direct call if we have no keyword arguments
1073 PyErr_Clear();
1073 PyErr_Clear();
1074 result = PyObject_CallObject(callable, pargs);
1074 result = PyObject_CallObject(callable, pargs);
1075 } else {
1075 } else {
1076 // convert keyword arguments to Python
1076 // convert keyword arguments to Python
1077 PythonQtObjectPtr pkwargs;
1077 PythonQtObjectPtr pkwargs;
1078 pkwargs.setNewRef(PyDict_New());
1078 pkwargs.setNewRef(PyDict_New());
1079 QMapIterator<QString, QVariant> it(kwargs);
1079 QMapIterator<QString, QVariant> it(kwargs);
1080 while (it.hasNext()) {
1080 while (it.hasNext()) {
1081 it.next();
1081 it.next();
1082 PyObject* arg = PythonQtConv::QVariantToPyObject(it.value());
1082 PyObject* arg = PythonQtConv::QVariantToPyObject(it.value());
1083 if (arg) {
1083 if (arg) {
1084 PyDict_SetItemString(pkwargs, it.key().toLatin1().constData(), arg);
1084 PyDict_SetItemString(pkwargs, it.key().toLatin1().constData(), arg);
1085 } else {
1085 } else {
1086 err = true;
1086 err = true;
1087 break;
1087 break;
1088 }
1088 }
1089 }
1089 }
1090 if (!err) {
1090 if (!err) {
1091 // call with arguments and keyword arguments
1091 // call with arguments and keyword arguments
1092 PyErr_Clear();
1092 PyErr_Clear();
1093 result = PyObject_Call(callable, pargs, pkwargs);
1093 result = PyObject_Call(callable, pargs, pkwargs);
1094 }
1094 }
1095 }
1095 }
1096 }
1096 }
1097 }
1097 }
1098 return result;
1098 return result;
1099 }
1099 }
1100
1100
1101 void PythonQt::addInstanceDecorators(QObject* o)
1101 void PythonQt::addInstanceDecorators(QObject* o)
1102 {
1102 {
1103 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
1103 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
1104 }
1104 }
1105
1105
1106 void PythonQt::addClassDecorators(QObject* o)
1106 void PythonQt::addClassDecorators(QObject* o)
1107 {
1107 {
1108 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
1108 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
1109 }
1109 }
1110
1110
1111 void PythonQt::addDecorators(QObject* o)
1111 void PythonQt::addDecorators(QObject* o)
1112 {
1112 {
1113 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
1113 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
1114 }
1114 }
1115
1115
1116 void PythonQt::registerQObjectClassNames(const QStringList& names)
1116 void PythonQt::registerQObjectClassNames(const QStringList& names)
1117 {
1117 {
1118 _p->registerQObjectClassNames(names);
1118 _p->registerQObjectClassNames(names);
1119 }
1119 }
1120
1120
1121 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
1121 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
1122 {
1122 {
1123 _p->_importInterface = importInterface;
1123 _p->_importInterface = importInterface;
1124 PythonQtImport::init();
1124 PythonQtImport::init();
1125 }
1125 }
1126
1126
1127 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
1127 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
1128 {
1128 {
1129 _p->_importIgnorePaths = paths;
1129 _p->_importIgnorePaths = paths;
1130 }
1130 }
1131
1131
1132 const QStringList& PythonQt::getImporterIgnorePaths()
1132 const QStringList& PythonQt::getImporterIgnorePaths()
1133 {
1133 {
1134 return _p->_importIgnorePaths;
1134 return _p->_importIgnorePaths;
1135 }
1135 }
1136
1136
1137 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
1137 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
1138 {
1138 {
1139 _p->_cppWrapperFactories.append(factory);
1139 _p->_cppWrapperFactories.append(factory);
1140 }
1140 }
1141
1141
1142 void PythonQt::addWrapperFactory( PythonQtForeignWrapperFactory* factory )
1142 void PythonQt::addWrapperFactory( PythonQtForeignWrapperFactory* factory )
1143 {
1143 {
1144 _p->_foreignWrapperFactories.append(factory);
1144 _p->_foreignWrapperFactories.append(factory);
1145 }
1145 }
1146
1146
1147 //---------------------------------------------------------------------------------------------------
1147 //---------------------------------------------------------------------------------------------------
1148 PythonQtPrivate::PythonQtPrivate()
1148 PythonQtPrivate::PythonQtPrivate()
1149 {
1149 {
1150 _importInterface = NULL;
1150 _importInterface = NULL;
1151 _defaultImporter = new PythonQtQFileImporter;
1151 _defaultImporter = new PythonQtQFileImporter;
1152 _noLongerWrappedCB = NULL;
1152 _noLongerWrappedCB = NULL;
1153 _wrappedCB = NULL;
1153 _wrappedCB = NULL;
1154 _currentClassInfoForClassWrapperCreation = NULL;
1154 _currentClassInfoForClassWrapperCreation = NULL;
1155 _profilingCB = NULL;
1155 _profilingCB = NULL;
1156 }
1156 }
1157
1157
1158 void PythonQtPrivate::setupSharedLibrarySuffixes()
1158 void PythonQtPrivate::setupSharedLibrarySuffixes()
1159 {
1159 {
1160 _sharedLibrarySuffixes.clear();
1160 _sharedLibrarySuffixes.clear();
1161 PythonQtObjectPtr imp;
1161 PythonQtObjectPtr imp;
1162 imp.setNewRef(PyImport_ImportModule("imp"));
1162 imp.setNewRef(PyImport_ImportModule("imp"));
1163 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
1163 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
1164 QVariant result = imp.call("get_suffixes");
1164 QVariant result = imp.call("get_suffixes");
1165 #ifdef __linux
1165 #ifdef __linux
1166 #ifdef _DEBUG
1166 #ifdef _DEBUG
1167 // First look for shared libraries with the '_d' suffix in debug mode on Linux.
1167 // First look for shared libraries with the '_d' suffix in debug mode on Linux.
1168 // This is a workaround, because python does not append the '_d' suffix on Linux
1168 // This is a workaround, because python does not append the '_d' suffix on Linux
1169 // and would always load the release library otherwise.
1169 // and would always load the release library otherwise.
1170 _sharedLibrarySuffixes << "_d.so";
1170 _sharedLibrarySuffixes << "_d.so";
1171 #endif
1171 #endif
1172 #endif
1172 #endif
1173 foreach (QVariant entry, result.toList()) {
1173 foreach (QVariant entry, result.toList()) {
1174 QVariantList suffixEntry = entry.toList();
1174 QVariantList suffixEntry = entry.toList();
1175 if (suffixEntry.count()==3) {
1175 if (suffixEntry.count()==3) {
1176 int code = suffixEntry.at(2).toInt();
1176 int code = suffixEntry.at(2).toInt();
1177 if (code == cExtensionCode) {
1177 if (code == cExtensionCode) {
1178 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
1178 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
1179 }
1179 }
1180 }
1180 }
1181 }
1181 }
1182 }
1182 }
1183
1183
1184 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
1184 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
1185 {
1185 {
1186 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
1186 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
1187 _currentClassInfoForClassWrapperCreation = NULL;
1187 _currentClassInfoForClassWrapperCreation = NULL;
1188 return info;
1188 return info;
1189 }
1189 }
1190
1190
1191 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
1191 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
1192 {
1192 {
1193 o->setParent(this);
1193 o->setParent(this);
1194 int numMethods = o->metaObject()->methodCount();
1194 int numMethods = o->metaObject()->methodCount();
1195 for (int i = 0; i < numMethods; i++) {
1195 for (int i = 0; i < numMethods; i++) {
1196 QMetaMethod m = o->metaObject()->method(i);
1196 QMetaMethod m = o->metaObject()->method(i);
1197 if ((m.methodType() == QMetaMethod::Method ||
1197 if ((m.methodType() == QMetaMethod::Method ||
1198 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
1198 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
1199 if (qstrncmp(m.signature(), "new_", 4)==0) {
1199 if (qstrncmp(m.signature(), "new_", 4)==0) {
1200 if ((decoTypes & ConstructorDecorator) == 0) continue;
1200 if ((decoTypes & ConstructorDecorator) == 0) continue;
1201 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1201 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1202 if (info->parameters().at(0).pointerCount == 1) {
1202 if (info->parameters().at(0).pointerCount == 1) {
1203 QByteArray signature = m.signature();
1203 QByteArray signature = m.signature();
1204 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
1204 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
1205 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1205 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1206 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1206 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1207 classInfo->addConstructor(newSlot);
1207 classInfo->addConstructor(newSlot);
1208 }
1208 }
1209 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
1209 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
1210 if ((decoTypes & DestructorDecorator) == 0) continue;
1210 if ((decoTypes & DestructorDecorator) == 0) continue;
1211 QByteArray signature = m.signature();
1211 QByteArray signature = m.signature();
1212 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
1212 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
1213 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1213 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1214 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1214 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1215 classInfo->setDestructor(newSlot);
1215 classInfo->setDestructor(newSlot);
1216 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
1216 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
1217 if ((decoTypes & StaticDecorator) == 0) continue;
1217 if ((decoTypes & StaticDecorator) == 0) continue;
1218 QByteArray signature = m.signature();
1218 QByteArray signature = m.signature();
1219 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
1219 QByteArray nameOfClass = signature.mid(7);
1220 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
1220 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
1221 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1221 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1222 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1222 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1223 classInfo->addDecoratorSlot(newSlot);
1223 classInfo->addDecoratorSlot(newSlot);
1224 } else {
1224 } else {
1225 if ((decoTypes & InstanceDecorator) == 0) continue;
1225 if ((decoTypes & InstanceDecorator) == 0) continue;
1226 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1226 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1227 if (info->parameters().count()>1) {
1227 if (info->parameters().count()>1) {
1228 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
1228 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
1229 if (p.pointerCount==1) {
1229 if (p.pointerCount==1) {
1230 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
1230 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
1231 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
1231 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
1232 classInfo->addDecoratorSlot(newSlot);
1232 classInfo->addDecoratorSlot(newSlot);
1233 }
1233 }
1234 }
1234 }
1235 }
1235 }
1236 }
1236 }
1237 }
1237 }
1238 }
1238 }
1239
1239
1240 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
1240 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
1241 {
1241 {
1242 foreach(QString name, names) {
1242 foreach(QString name, names) {
1243 _knownQObjectClassNames.insert(name.toLatin1(), true);
1243 _knownQObjectClassNames.insert(name.toLatin1(), true);
1244 }
1244 }
1245 }
1245 }
1246
1246
1247 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
1247 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
1248 {
1248 {
1249 _signalReceivers.remove(obj);
1249 _signalReceivers.remove(obj);
1250 }
1250 }
1251
1251
1252 bool PythonQt::handleError()
1252 bool PythonQt::handleError()
1253 {
1253 {
1254 bool flag = false;
1254 bool flag = false;
1255 if (PyErr_Occurred()) {
1255 if (PyErr_Occurred()) {
1256
1256
1257 // currently we just print the error and the stderr handler parses the errors
1257 // currently we just print the error and the stderr handler parses the errors
1258 PyErr_Print();
1258 PyErr_Print();
1259
1259
1260 /*
1260 /*
1261 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1261 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1262 PyObject *ptype;
1262 PyObject *ptype;
1263 PyObject *pvalue;
1263 PyObject *pvalue;
1264 PyObject *ptraceback;
1264 PyObject *ptraceback;
1265 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1265 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1266
1266
1267 Py_XDECREF(ptype);
1267 Py_XDECREF(ptype);
1268 Py_XDECREF(pvalue);
1268 Py_XDECREF(pvalue);
1269 Py_XDECREF(ptraceback);
1269 Py_XDECREF(ptraceback);
1270 */
1270 */
1271 PyErr_Clear();
1271 PyErr_Clear();
1272 flag = true;
1272 flag = true;
1273 }
1273 }
1274 return flag;
1274 return flag;
1275 }
1275 }
1276
1276
1277 void PythonQt::addSysPath(const QString& path)
1277 void PythonQt::addSysPath(const QString& path)
1278 {
1278 {
1279 PythonQtObjectPtr sys;
1279 PythonQtObjectPtr sys;
1280 sys.setNewRef(PyImport_ImportModule("sys"));
1280 sys.setNewRef(PyImport_ImportModule("sys"));
1281 PythonQtObjectPtr obj = lookupObject(sys, "path");
1281 PythonQtObjectPtr obj = lookupObject(sys, "path");
1282 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1282 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1283 }
1283 }
1284
1284
1285 void PythonQt::overwriteSysPath(const QStringList& paths)
1285 void PythonQt::overwriteSysPath(const QStringList& paths)
1286 {
1286 {
1287 PythonQtObjectPtr sys;
1287 PythonQtObjectPtr sys;
1288 sys.setNewRef(PyImport_ImportModule("sys"));
1288 sys.setNewRef(PyImport_ImportModule("sys"));
1289 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1289 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1290 }
1290 }
1291
1291
1292 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1292 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1293 {
1293 {
1294 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1294 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1295 }
1295 }
1296
1296
1297 void PythonQt::stdOutRedirectCB(const QString& str)
1297 void PythonQt::stdOutRedirectCB(const QString& str)
1298 {
1298 {
1299 if (!PythonQt::self()) {
1299 if (!PythonQt::self()) {
1300 std::cout << str.toLatin1().data() << std::endl;
1300 std::cout << str.toLatin1().data() << std::endl;
1301 return;
1301 return;
1302 }
1302 }
1303 emit PythonQt::self()->pythonStdOut(str);
1303 emit PythonQt::self()->pythonStdOut(str);
1304 }
1304 }
1305
1305
1306 void PythonQt::stdErrRedirectCB(const QString& str)
1306 void PythonQt::stdErrRedirectCB(const QString& str)
1307 {
1307 {
1308 if (!PythonQt::self()) {
1308 if (!PythonQt::self()) {
1309 std::cerr << str.toLatin1().data() << std::endl;
1309 std::cerr << str.toLatin1().data() << std::endl;
1310 return;
1310 return;
1311 }
1311 }
1312 emit PythonQt::self()->pythonStdErr(str);
1312 emit PythonQt::self()->pythonStdErr(str);
1313 }
1313 }
1314
1314
1315 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1315 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1316 {
1316 {
1317 _p->_wrappedCB = cb;
1317 _p->_wrappedCB = cb;
1318 }
1318 }
1319
1319
1320 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1320 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1321 {
1321 {
1322 _p->_noLongerWrappedCB = cb;
1322 _p->_noLongerWrappedCB = cb;
1323 }
1323 }
1324
1324
1325 void PythonQt::setProfilingCallback(ProfilingCB* cb)
1325 void PythonQt::setProfilingCallback(ProfilingCB* cb)
1326 {
1326 {
1327 _p->_profilingCB = cb;
1327 _p->_profilingCB = cb;
1328 }
1328 }
1329
1329
1330
1330
1331 static PyMethodDef PythonQtMethods[] = {
1331 static PyMethodDef PythonQtMethods[] = {
1332 {NULL, NULL, 0, NULL}
1332 {NULL, NULL, 0, NULL}
1333 };
1333 };
1334
1334
1335 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1335 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1336 {
1336 {
1337 QByteArray name = "PythonQt";
1337 QByteArray name = "PythonQt";
1338 if (!pythonQtModuleName.isEmpty()) {
1338 if (!pythonQtModuleName.isEmpty()) {
1339 name = pythonQtModuleName;
1339 name = pythonQtModuleName;
1340 }
1340 }
1341 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1341 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1342 _p->_pythonQtModuleName = name;
1342 _p->_pythonQtModuleName = name;
1343
1343
1344 if (redirectStdOut) {
1344 if (redirectStdOut) {
1345 PythonQtObjectPtr sys;
1345 PythonQtObjectPtr sys;
1346 PythonQtObjectPtr out;
1346 PythonQtObjectPtr out;
1347 PythonQtObjectPtr err;
1347 PythonQtObjectPtr err;
1348 sys.setNewRef(PyImport_ImportModule("sys"));
1348 sys.setNewRef(PyImport_ImportModule("sys"));
1349 // create a redirection object for stdout and stderr
1349 // create a redirection object for stdout and stderr
1350 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1350 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1351 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1351 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1352 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1352 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1353 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1353 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1354 // replace the built in file objects with our own objects
1354 // replace the built in file objects with our own objects
1355 PyModule_AddObject(sys, "stdout", out);
1355 PyModule_AddObject(sys, "stdout", out);
1356 PyModule_AddObject(sys, "stderr", err);
1356 PyModule_AddObject(sys, "stderr", err);
1357 }
1357 }
1358 }
1358 }
1359
1359
1360 QString PythonQt::getReturnTypeOfWrappedMethod(PyObject* module, const QString& name)
1360 QString PythonQt::getReturnTypeOfWrappedMethod(PyObject* module, const QString& name)
1361 {
1361 {
1362 QStringList tmp = name.split(".");
1362 QStringList tmp = name.split(".");
1363 QString methodName = tmp.takeLast();
1363 QString methodName = tmp.takeLast();
1364 QString variableName = tmp.join(".");
1364 QString variableName = tmp.join(".");
1365 // TODO: the variableName may be a type name, this needs to be handled differently,
1365 // TODO: the variableName may be a type name, this needs to be handled differently,
1366 // because it is not necessarily known in the module context
1366 // because it is not necessarily known in the module context
1367 PythonQtObjectPtr variableObject = lookupObject(module, variableName);
1367 PythonQtObjectPtr variableObject = lookupObject(module, variableName);
1368 if (variableObject.isNull()) {
1368 if (variableObject.isNull()) {
1369 return "";
1369 return "";
1370 }
1370 }
1371
1371
1372 return getReturnTypeOfWrappedMethodHelper(variableObject, methodName, name);
1372 return getReturnTypeOfWrappedMethodHelper(variableObject, methodName, name);
1373 }
1373 }
1374
1374
1375 QString PythonQt::getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName)
1375 QString PythonQt::getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName)
1376 {
1376 {
1377 PythonQtObjectPtr typeObject = getObjectByType(typeName);
1377 PythonQtObjectPtr typeObject = getObjectByType(typeName);
1378 if (typeObject.isNull()) {
1378 if (typeObject.isNull()) {
1379 return "";
1379 return "";
1380 }
1380 }
1381 return getReturnTypeOfWrappedMethodHelper(typeObject, methodName, typeName + "." + methodName);
1381 return getReturnTypeOfWrappedMethodHelper(typeObject, methodName, typeName + "." + methodName);
1382 }
1382 }
1383
1383
1384 QString PythonQt::getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context)
1384 QString PythonQt::getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context)
1385 {
1385 {
1386 PythonQtObjectPtr methodObject;
1386 PythonQtObjectPtr methodObject;
1387 if (PyDict_Check(variableObject)) {
1387 if (PyDict_Check(variableObject)) {
1388 methodObject = PyDict_GetItemString(variableObject, methodName.toLatin1().constData());
1388 methodObject = PyDict_GetItemString(variableObject, methodName.toLatin1().constData());
1389 } else {
1389 } else {
1390 methodObject.setNewRef(PyObject_GetAttrString(variableObject, methodName.toLatin1().constData()));
1390 methodObject.setNewRef(PyObject_GetAttrString(variableObject, methodName.toLatin1().constData()));
1391 }
1391 }
1392 if (methodObject.isNull()) {
1392 if (methodObject.isNull()) {
1393 return "";
1393 return "";
1394 }
1394 }
1395
1395
1396 QString type;
1396 QString type;
1397
1397
1398 if (methodObject->ob_type == &PyClass_Type || methodObject->ob_type == &PyType_Type) {
1398 if (methodObject->ob_type == &PyClass_Type || methodObject->ob_type == &PyType_Type) {
1399 // the methodObject is not a method, but the name of a type/class. This means
1399 // the methodObject is not a method, but the name of a type/class. This means
1400 // a constructor is called. Return the context.
1400 // a constructor is called. Return the context.
1401 type = context;
1401 type = context;
1402 } else if (methodObject->ob_type == &PythonQtSlotFunction_Type) {
1402 } else if (methodObject->ob_type == &PythonQtSlotFunction_Type) {
1403 QString className;
1403 QString className;
1404
1404
1405 if (PyObject_TypeCheck(variableObject, &PythonQtInstanceWrapper_Type)) {
1405 if (PyObject_TypeCheck(variableObject, &PythonQtInstanceWrapper_Type)) {
1406 // the type name of wrapped instance is the class name
1406 // the type name of wrapped instance is the class name
1407 className = variableObject->ob_type->tp_name;
1407 className = variableObject->ob_type->tp_name;
1408 } else {
1408 } else {
1409 PyObject* classNameObject = PyObject_GetAttrString(variableObject, "__name__");
1409 PyObject* classNameObject = PyObject_GetAttrString(variableObject, "__name__");
1410 if (classNameObject) {
1410 if (classNameObject) {
1411 Q_ASSERT(PyString_Check(classNameObject));
1411 Q_ASSERT(PyString_Check(classNameObject));
1412 className = PyString_AsString(classNameObject);
1412 className = PyString_AsString(classNameObject);
1413 Py_DECREF(classNameObject);
1413 Py_DECREF(classNameObject);
1414 }
1414 }
1415 }
1415 }
1416
1416
1417 if (!className.isEmpty()) {
1417 if (!className.isEmpty()) {
1418 PythonQtClassInfo* info = _p->_knownClassInfos.value(className.toLatin1().constData());
1418 PythonQtClassInfo* info = _p->_knownClassInfos.value(className.toLatin1().constData());
1419 if (info) {
1419 if (info) {
1420 PythonQtSlotInfo* slotInfo = info->member(methodName.toLatin1().constData())._slot;
1420 PythonQtSlotInfo* slotInfo = info->member(methodName.toLatin1().constData())._slot;
1421 if (slotInfo) {
1421 if (slotInfo) {
1422 if (slotInfo->metaMethod()) {
1422 if (slotInfo->metaMethod()) {
1423 type = slotInfo->metaMethod()->typeName();
1423 type = slotInfo->metaMethod()->typeName();
1424 if (!type.isEmpty()) {
1424 if (!type.isEmpty()) {
1425 QChar c = type.at(type.length()-1);
1425 QChar c = type.at(type.length()-1);
1426 while (c == '*' || c == '&') {
1426 while (c == '*' || c == '&') {
1427 type.truncate(type.length()-1);
1427 type.truncate(type.length()-1);
1428 if (!type.isEmpty()) {
1428 if (!type.isEmpty()) {
1429 c = type.at(type.length()-1);
1429 c = type.at(type.length()-1);
1430 } else {
1430 } else {
1431 break;
1431 break;
1432 }
1432 }
1433 }
1433 }
1434 // split away template arguments
1434 // split away template arguments
1435 type = type.split("<").first();
1435 type = type.split("<").first();
1436 // split away const
1436 // split away const
1437 type = type.split(" ").last().trimmed();
1437 type = type.split(" ").last().trimmed();
1438
1438
1439 // if the type is a known class info, then create the full type name, i.e. include the
1439 // if the type is a known class info, then create the full type name, i.e. include the
1440 // module name. For example, the slot may return a QDate, then this looks up the
1440 // module name. For example, the slot may return a QDate, then this looks up the
1441 // name _PythonQt.QtCore.QDate.
1441 // name _PythonQt.QtCore.QDate.
1442 PythonQtClassInfo* typeInfo = _p->_knownClassInfos.value(type.toLatin1().constData());
1442 PythonQtClassInfo* typeInfo = _p->_knownClassInfos.value(type.toLatin1().constData());
1443 if (typeInfo && typeInfo->pythonQtClassWrapper()) {
1443 if (typeInfo && typeInfo->pythonQtClassWrapper()) {
1444 PyObject* s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__module__");
1444 PyObject* s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__module__");
1445 Q_ASSERT(PyString_Check(s));
1445 Q_ASSERT(PyString_Check(s));
1446 type = QString(PyString_AsString(s)) + "." + type;
1446 type = QString(PyString_AsString(s)) + "." + type;
1447 Py_DECREF(s);
1447 Py_DECREF(s);
1448 s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__name__");
1448 s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__name__");
1449 Q_ASSERT(PyString_Check(s));
1449 Q_ASSERT(PyString_Check(s));
1450 Py_DECREF(s);
1450 Py_DECREF(s);
1451 }
1451 }
1452 }
1452 }
1453 }
1453 }
1454 }
1454 }
1455 }
1455 }
1456 }
1456 }
1457 }
1457 }
1458 return type;
1458 return type;
1459 }
1459 }
1460
1460
1461 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1461 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1462 {
1462 {
1463 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1463 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1464 }
1464 }
1465
1465
1466
1466
1467 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1467 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1468 {
1468 {
1469 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1469 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1470 if (!info) {
1470 if (!info) {
1471 info = new PythonQtClassInfo();
1471 info = new PythonQtClassInfo();
1472 info->setupCPPObject(typeName);
1472 info->setupCPPObject(typeName);
1473 _knownClassInfos.insert(typeName, info);
1473 _knownClassInfos.insert(typeName, info);
1474 }
1474 }
1475 return info;
1475 return info;
1476 }
1476 }
1477
1477
1478 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1478 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1479 {
1479 {
1480 _p->addPolymorphicHandler(typeName, cb);
1480 _p->addPolymorphicHandler(typeName, cb);
1481 }
1481 }
1482
1482
1483 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1483 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1484 {
1484 {
1485 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1485 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1486 info->addPolymorphicHandler(cb);
1486 info->addPolymorphicHandler(cb);
1487 }
1487 }
1488
1488
1489 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1489 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1490 {
1490 {
1491 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1491 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1492 }
1492 }
1493
1493
1494 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1494 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1495 {
1495 {
1496 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1496 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1497 if (info) {
1497 if (info) {
1498 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1498 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1499 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1499 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1500 return true;
1500 return true;
1501 } else {
1501 } else {
1502 return false;
1502 return false;
1503 }
1503 }
1504 }
1504 }
1505
1505
1506 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1506 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1507 {
1507 {
1508 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1508 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1509 if (!info->pythonQtClassWrapper()) {
1509 if (!info->pythonQtClassWrapper()) {
1510 info->setTypeSlots(typeSlots);
1510 info->setTypeSlots(typeSlots);
1511 info->setupCPPObject(typeName);
1511 info->setupCPPObject(typeName);
1512 createPythonQtClassWrapper(info, package, module);
1512 createPythonQtClassWrapper(info, package, module);
1513 }
1513 }
1514 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1514 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1515 addParentClass(typeName, parentTypeName, 0);
1515 addParentClass(typeName, parentTypeName, 0);
1516 }
1516 }
1517 if (wrapperCreator) {
1517 if (wrapperCreator) {
1518 info->setDecoratorProvider(wrapperCreator);
1518 info->setDecoratorProvider(wrapperCreator);
1519 }
1519 }
1520 if (shell) {
1520 if (shell) {
1521 info->setShellSetInstanceWrapperCB(shell);
1521 info->setShellSetInstanceWrapperCB(shell);
1522 }
1522 }
1523 }
1523 }
1524
1524
1525 PyObject* PythonQtPrivate::packageByName(const char* name)
1525 PyObject* PythonQtPrivate::packageByName(const char* name)
1526 {
1526 {
1527 if (name==NULL || name[0]==0) {
1527 if (name==NULL || name[0]==0) {
1528 name = "private";
1528 name = "private";
1529 }
1529 }
1530 PyObject* v = _packages.value(name);
1530 PyObject* v = _packages.value(name);
1531 if (!v) {
1531 if (!v) {
1532 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1532 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1533 _packages.insert(name, v);
1533 _packages.insert(name, v);
1534 // AddObject steals the reference, so increment it!
1534 // AddObject steals the reference, so increment it!
1535 Py_INCREF(v);
1535 Py_INCREF(v);
1536 PyModule_AddObject(_pythonQtModule, name, v);
1536 PyModule_AddObject(_pythonQtModule, name, v);
1537 }
1537 }
1538 return v;
1538 return v;
1539 }
1539 }
1540
1540
1541 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1541 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1542 {
1542 {
1543 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;
1543 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;
1544 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1544 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1545 PythonQt::self()->handleError();
1545 PythonQt::self()->handleError();
1546 }
1546 }
1547
1547
1548 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1548 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1549 {
1549 {
1550 if (_p->_initFlags & ExternalHelp) {
1550 if (_p->_initFlags & ExternalHelp) {
1551 emit pythonHelpRequest(QByteArray(info->className()));
1551 emit pythonHelpRequest(QByteArray(info->className()));
1552 return Py_BuildValue("");
1552 return Py_BuildValue("");
1553 } else {
1553 } else {
1554 return PyString_FromString(info->help().toLatin1().data());
1554 return PyString_FromString(info->help().toLatin1().data());
1555 }
1555 }
1556 }
1556 }
1557
1557
1558 void PythonQt::clearNotFoundCachedMembers()
1558 void PythonQt::clearNotFoundCachedMembers()
1559 {
1559 {
1560 foreach(PythonQtClassInfo* info, _p->_knownClassInfos) {
1560 foreach(PythonQtClassInfo* info, _p->_knownClassInfos) {
1561 info->clearNotFoundCachedMembers();
1561 info->clearNotFoundCachedMembers();
1562 }
1562 }
1563 }
1563 }
1564
1564
1565 void PythonQt::removeWrapperFactory( PythonQtCppWrapperFactory* factory )
1565 void PythonQt::removeWrapperFactory( PythonQtCppWrapperFactory* factory )
1566 {
1566 {
1567 _p->_cppWrapperFactories.removeAll(factory);
1567 _p->_cppWrapperFactories.removeAll(factory);
1568 }
1568 }
1569
1569
1570 void PythonQt::removeWrapperFactory( PythonQtForeignWrapperFactory* factory )
1570 void PythonQt::removeWrapperFactory( PythonQtForeignWrapperFactory* factory )
1571 {
1571 {
1572 _p->_foreignWrapperFactories.removeAll(factory);
1572 _p->_foreignWrapperFactories.removeAll(factory);
1573 }
1573 }
1574
1574
1575 void PythonQtPrivate::removeWrapperPointer(void* obj)
1575 void PythonQtPrivate::removeWrapperPointer(void* obj)
1576 {
1576 {
1577 _wrappedObjects.remove(obj);
1577 _wrappedObjects.remove(obj);
1578 }
1578 }
1579
1579
1580 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1580 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1581 {
1581 {
1582 _wrappedObjects.insert(obj, wrapper);
1582 _wrappedObjects.insert(obj, wrapper);
1583 }
1583 }
1584
1584
1585 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1585 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1586 {
1586 {
1587 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1587 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1588 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1588 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1589 // this is a wrapper whose QObject was already removed due to destruction
1589 // this is a wrapper whose QObject was already removed due to destruction
1590 // so the obj pointer has to be a new QObject with the same address...
1590 // so the obj pointer has to be a new QObject with the same address...
1591 // we remove the old one and set the copy to NULL
1591 // we remove the old one and set the copy to NULL
1592 wrap->_objPointerCopy = NULL;
1592 wrap->_objPointerCopy = NULL;
1593 removeWrapperPointer(obj);
1593 removeWrapperPointer(obj);
1594 wrap = NULL;
1594 wrap = NULL;
1595 }
1595 }
1596 return wrap;
1596 return wrap;
1597 }
1597 }
1598
1598
1599 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1599 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1600 {
1600 {
1601 PythonQtObjectPtr result;
1601 PythonQtObjectPtr result;
1602 if (pycode) {
1602 if (pycode) {
1603 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1603 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1604 } else {
1604 } else {
1605 PythonQt::self()->handleError();
1605 PythonQt::self()->handleError();
1606 }
1606 }
1607 return result;
1607 return result;
1608 }
1608 }
1609
1609
1610 void* PythonQtPrivate::unwrapForeignWrapper( const QByteArray& classname, PyObject* obj )
1610 void* PythonQtPrivate::unwrapForeignWrapper( const QByteArray& classname, PyObject* obj )
1611 {
1611 {
1612 void* foreignObject = NULL;
1612 void* foreignObject = NULL;
1613 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
1613 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
1614 foreignObject = _foreignWrapperFactories.at(i)->unwrap(classname, obj);
1614 foreignObject = _foreignWrapperFactories.at(i)->unwrap(classname, obj);
1615 if (foreignObject) {
1615 if (foreignObject) {
1616 return foreignObject;
1616 return foreignObject;
1617 }
1617 }
1618 }
1618 }
1619 return NULL;
1619 return NULL;
1620 }
1620 }
1621
1621
1622 bool PythonQtPrivate::isMethodDescriptor(PyObject* object) const
1622 bool PythonQtPrivate::isMethodDescriptor(PyObject* object) const
1623 {
1623 {
1624 // This implementation is the same as in inspect.ismethoddescriptor(), inspect.py.
1624 // This implementation is the same as in inspect.ismethoddescriptor(), inspect.py.
1625 if (PyObject_HasAttrString(object, "__get__") &&
1625 if (PyObject_HasAttrString(object, "__get__") &&
1626 !PyObject_HasAttrString(object, "__set__") &&
1626 !PyObject_HasAttrString(object, "__set__") &&
1627 !PyMethod_Check(object) &&
1627 !PyMethod_Check(object) &&
1628 !PyFunction_Check(object) &&
1628 !PyFunction_Check(object) &&
1629 !PyClass_Check(object)) {
1629 !PyClass_Check(object)) {
1630 return true;
1630 return true;
1631 }
1631 }
1632 return false;
1632 return false;
1633 }
1633 }
1634
1634
1635 QString PythonQtPrivate::getSignature(PyObject* object)
1635 QString PythonQtPrivate::getSignature(PyObject* object)
1636 {
1636 {
1637 QString signature;
1637 QString signature;
1638
1638
1639 if (object) {
1639 if (object) {
1640 PyMethodObject* method = NULL;
1640 PyMethodObject* method = NULL;
1641 PyFunctionObject* func = NULL;
1641 PyFunctionObject* func = NULL;
1642
1642
1643 bool decrefMethod = false;
1643 bool decrefMethod = false;
1644
1644
1645 if (object->ob_type == &PyClass_Type || object->ob_type == &PyType_Type) {
1645 if (object->ob_type == &PyClass_Type || object->ob_type == &PyType_Type) {
1646 method = (PyMethodObject*)PyObject_GetAttrString(object, "__init__");
1646 method = (PyMethodObject*)PyObject_GetAttrString(object, "__init__");
1647 decrefMethod = true;
1647 decrefMethod = true;
1648 } else if (object->ob_type == &PyFunction_Type) {
1648 } else if (object->ob_type == &PyFunction_Type) {
1649 func = (PyFunctionObject*)object;
1649 func = (PyFunctionObject*)object;
1650 } else if (object->ob_type == &PyMethod_Type) {
1650 } else if (object->ob_type == &PyMethod_Type) {
1651 method = (PyMethodObject*)object;
1651 method = (PyMethodObject*)object;
1652 }
1652 }
1653 if (method) {
1653 if (method) {
1654 if (PyFunction_Check(method->im_func)) {
1654 if (PyFunction_Check(method->im_func)) {
1655 func = (PyFunctionObject*)method->im_func;
1655 func = (PyFunctionObject*)method->im_func;
1656 } else if (isMethodDescriptor((PyObject*)method)) {
1656 } else if (isMethodDescriptor((PyObject*)method)) {
1657 QString docstr;
1657 QString docstr;
1658 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
1658 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
1659 if (doc) {
1659 if (doc) {
1660 docstr = PyString_AsString(doc);
1660 docstr = PyString_AsString(doc);
1661 Py_DECREF(doc);
1661 Py_DECREF(doc);
1662 }
1662 }
1663
1663
1664 PyObject* s = PyObject_GetAttrString(object, "__name__");
1664 PyObject* s = PyObject_GetAttrString(object, "__name__");
1665 if (s) {
1665 if (s) {
1666 Q_ASSERT(PyString_Check(s));
1666 Q_ASSERT(PyString_Check(s));
1667 signature = PyString_AsString(s);
1667 signature = PyString_AsString(s);
1668 if (docstr.startsWith(signature + "(")) {
1668 if (docstr.startsWith(signature + "(")) {
1669 signature = docstr;
1669 signature = docstr;
1670 } else {
1670 } else {
1671 signature += "(...)";
1671 signature += "(...)";
1672 if (!docstr.isEmpty()) {
1672 if (!docstr.isEmpty()) {
1673 signature += "\n\n" + docstr;
1673 signature += "\n\n" + docstr;
1674 }
1674 }
1675 }
1675 }
1676 Py_DECREF(s);
1676 Py_DECREF(s);
1677 }
1677 }
1678 }
1678 }
1679 }
1679 }
1680
1680
1681 if (func) {
1681 if (func) {
1682 QString funcName;
1682 QString funcName;
1683 PyObject* s = PyObject_GetAttrString((PyObject*)func, "__name__");
1683 PyObject* s = PyObject_GetAttrString((PyObject*)func, "__name__");
1684 if (s) {
1684 if (s) {
1685 Q_ASSERT(PyString_Check(s));
1685 Q_ASSERT(PyString_Check(s));
1686 funcName = PyString_AsString(s);
1686 funcName = PyString_AsString(s);
1687 Py_DECREF(s);
1687 Py_DECREF(s);
1688 }
1688 }
1689 if (method && funcName == "__init__") {
1689 if (method && funcName == "__init__") {
1690 PyObject* s = PyObject_GetAttrString(object, "__name__");
1690 PyObject* s = PyObject_GetAttrString(object, "__name__");
1691 if (s) {
1691 if (s) {
1692 Q_ASSERT(PyString_Check(s));
1692 Q_ASSERT(PyString_Check(s));
1693 funcName = PyString_AsString(s);
1693 funcName = PyString_AsString(s);
1694 Py_DECREF(s);
1694 Py_DECREF(s);
1695 }
1695 }
1696 }
1696 }
1697
1697
1698 QStringList arguments;
1698 QStringList arguments;
1699 QStringList defaults;
1699 QStringList defaults;
1700 QString varargs;
1700 QString varargs;
1701 QString varkeywords;
1701 QString varkeywords;
1702 // NOTE: This implementation is based on function getargs() in inspect.py.
1702 // NOTE: This implementation is based on function getargs() in inspect.py.
1703 // inspect.getargs() can handle anonymous (tuple) arguments, while this code does not.
1703 // inspect.getargs() can handle anonymous (tuple) arguments, while this code does not.
1704 // It can be implemented, but it may be rarely needed and not necessary.
1704 // It can be implemented, but it may be rarely needed and not necessary.
1705 PyCodeObject* code = (PyCodeObject*)func->func_code;
1705 PyCodeObject* code = (PyCodeObject*)func->func_code;
1706 if (code->co_varnames) {
1706 if (code->co_varnames) {
1707 int nargs = code->co_argcount;
1707 int nargs = code->co_argcount;
1708 Q_ASSERT(PyTuple_Check(code->co_varnames));
1708 Q_ASSERT(PyTuple_Check(code->co_varnames));
1709 for (int i=0; i<nargs; i++) {
1709 for (int i=0; i<nargs; i++) {
1710 PyObject* name = PyTuple_GetItem(code->co_varnames, i);
1710 PyObject* name = PyTuple_GetItem(code->co_varnames, i);
1711 Q_ASSERT(PyString_Check(name));
1711 Q_ASSERT(PyString_Check(name));
1712 arguments << PyString_AsString(name);
1712 arguments << PyString_AsString(name);
1713 }
1713 }
1714 if (code->co_flags & CO_VARARGS) {
1714 if (code->co_flags & CO_VARARGS) {
1715 PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
1715 PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
1716 Q_ASSERT(PyString_Check(s));
1716 Q_ASSERT(PyString_Check(s));
1717 varargs = PyString_AsString(s);
1717 varargs = PyString_AsString(s);
1718 nargs += 1;
1718 nargs += 1;
1719 }
1719 }
1720 if (code->co_flags & CO_VARKEYWORDS) {
1720 if (code->co_flags & CO_VARKEYWORDS) {
1721 PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
1721 PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
1722 Q_ASSERT(PyString_Check(s));
1722 Q_ASSERT(PyString_Check(s));
1723 varkeywords = PyString_AsString(s);
1723 varkeywords = PyString_AsString(s);
1724 }
1724 }
1725 }
1725 }
1726
1726
1727 PyObject* defaultsTuple = func->func_defaults;
1727 PyObject* defaultsTuple = func->func_defaults;
1728 if (defaultsTuple) {
1728 if (defaultsTuple) {
1729 Q_ASSERT(PyTuple_Check(defaultsTuple));
1729 Q_ASSERT(PyTuple_Check(defaultsTuple));
1730 for (Py_ssize_t i=0; i<PyTuple_Size(defaultsTuple); i++) {
1730 for (Py_ssize_t i=0; i<PyTuple_Size(defaultsTuple); i++) {
1731 PyObject* d = PyTuple_GetItem(defaultsTuple, i);
1731 PyObject* d = PyTuple_GetItem(defaultsTuple, i);
1732 PyObject* s = PyObject_Repr(d);
1732 PyObject* s = PyObject_Repr(d);
1733 Q_ASSERT(PyString_Check(s));
1733 Q_ASSERT(PyString_Check(s));
1734 defaults << PyString_AsString(s);
1734 defaults << PyString_AsString(s);
1735 Py_DECREF(s);
1735 Py_DECREF(s);
1736 }
1736 }
1737 }
1737 }
1738
1738
1739 int firstdefault = arguments.size() - defaults.size();
1739 int firstdefault = arguments.size() - defaults.size();
1740 for (int i=0; i<arguments.size(); i++) {
1740 for (int i=0; i<arguments.size(); i++) {
1741 if (!signature.isEmpty()) { signature += ", "; }
1741 if (!signature.isEmpty()) { signature += ", "; }
1742 if (!method || i>0 || arguments[i] != "self") {
1742 if (!method || i>0 || arguments[i] != "self") {
1743 signature += arguments[i];
1743 signature += arguments[i];
1744 if (i >= firstdefault) {
1744 if (i >= firstdefault) {
1745 signature += "=" + defaults[i-firstdefault];
1745 signature += "=" + defaults[i-firstdefault];
1746 }
1746 }
1747 }
1747 }
1748 }
1748 }
1749 if (!varargs.isEmpty()) {
1749 if (!varargs.isEmpty()) {
1750 if (!signature.isEmpty()) { signature += ", "; }
1750 if (!signature.isEmpty()) { signature += ", "; }
1751 signature += "*" + varargs;
1751 signature += "*" + varargs;
1752 }
1752 }
1753 if (!varkeywords.isEmpty()) {
1753 if (!varkeywords.isEmpty()) {
1754 if (!signature.isEmpty()) { signature += ", "; }
1754 if (!signature.isEmpty()) { signature += ", "; }
1755 signature += "**" + varkeywords;
1755 signature += "**" + varkeywords;
1756 }
1756 }
1757 signature = funcName + "(" + signature + ")";
1757 signature = funcName + "(" + signature + ")";
1758 }
1758 }
1759
1759
1760 if (method && decrefMethod) {
1760 if (method && decrefMethod) {
1761 Py_DECREF(method);
1761 Py_DECREF(method);
1762 }
1762 }
1763 }
1763 }
1764
1764
1765 return signature;
1765 return signature;
1766 }
1766 }
1767
1767
1768 void PythonQtPrivate::shellClassDeleted( void* shellClass )
1768 void PythonQtPrivate::shellClassDeleted( void* shellClass )
1769 {
1769 {
1770 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(shellClass);
1770 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(shellClass);
1771 if (wrap && wrap->_wrappedPtr) {
1771 if (wrap && wrap->_wrappedPtr) {
1772 // this is a pure C++ wrapper and the shell has gone, so we need
1772 // this is a pure C++ wrapper and the shell has gone, so we need
1773 // to set the _wrappedPtr to NULL on the wrapper
1773 // to set the _wrappedPtr to NULL on the wrapper
1774 wrap->_wrappedPtr = NULL;
1774 wrap->_wrappedPtr = NULL;
1775 // and then we remove the wrapper, since the wrapped class is gone
1775 // and then we remove the wrapper, since the wrapped class is gone
1776 _wrappedObjects.remove(shellClass);
1776 _wrappedObjects.remove(shellClass);
1777 }
1777 }
1778 // if the wrapper is a QObject, we do not handle this here,
1778 // if the wrapper is a QObject, we do not handle this here,
1779 // it will be handled by the QPointer<> to the QObject, which becomes NULL
1779 // it will be handled by the QPointer<> to the QObject, which becomes NULL
1780 // via the QObject destructor.
1780 // via the QObject destructor.
1781 }
1781 }
1782
1783 PyObject* PythonQtPrivate::wrapMemoryAsBuffer( const void* data, Py_ssize_t size )
1784 {
1785 // P3K port needed later on!
1786 return PyBuffer_FromMemory((void*)data, size);
1787 }
1788
1789 PyObject* PythonQtPrivate::wrapMemoryAsBuffer( void* data, Py_ssize_t size )
1790 {
1791 // P3K port needed later on!
1792 return PyBuffer_FromReadWriteMemory(data, size);
1793 } No newline at end of file
@@ -1,714 +1,720
1 #ifndef _PYTHONQT_H
1 #ifndef _PYTHONQT_H
2 #define _PYTHONQT_H
2 #define _PYTHONQT_H
3
3
4 /*
4 /*
5 *
5 *
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, 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 PythonQt.h
38 // \file PythonQt.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-05
41 // \date 2006-05
42 */
42 */
43 //----------------------------------------------------------------------------------
43 //----------------------------------------------------------------------------------
44
44
45 #include "PythonQtSystem.h"
45 #include "PythonQtSystem.h"
46 #include "PythonQtInstanceWrapper.h"
46 #include "PythonQtInstanceWrapper.h"
47 #include "PythonQtClassWrapper.h"
47 #include "PythonQtClassWrapper.h"
48 #include "PythonQtSlot.h"
48 #include "PythonQtSlot.h"
49 #include "PythonQtObjectPtr.h"
49 #include "PythonQtObjectPtr.h"
50 #include "PythonQtStdIn.h"
50 #include "PythonQtStdIn.h"
51 #include <QObject>
51 #include <QObject>
52 #include <QVariant>
52 #include <QVariant>
53 #include <QList>
53 #include <QList>
54 #include <QHash>
54 #include <QHash>
55 #include <QByteArray>
55 #include <QByteArray>
56 #include <QStringList>
56 #include <QStringList>
57 #include <QtDebug>
57 #include <QtDebug>
58 #include <iostream>
58 #include <iostream>
59
59
60
60
61 class PythonQtClassInfo;
61 class PythonQtClassInfo;
62 class PythonQtPrivate;
62 class PythonQtPrivate;
63 class PythonQtMethodInfo;
63 class PythonQtMethodInfo;
64 class PythonQtSignalReceiver;
64 class PythonQtSignalReceiver;
65 class PythonQtImportFileInterface;
65 class PythonQtImportFileInterface;
66 class PythonQtCppWrapperFactory;
66 class PythonQtCppWrapperFactory;
67 class PythonQtForeignWrapperFactory;
67 class PythonQtForeignWrapperFactory;
68 class PythonQtQFileImporter;
68 class PythonQtQFileImporter;
69
69
70 typedef void PythonQtQObjectWrappedCB(QObject* object);
70 typedef void PythonQtQObjectWrappedCB(QObject* object);
71 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
71 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
72 typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, const char **class_name);
72 typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, const char **class_name);
73
73
74 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
74 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
75
75
76 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) {
76 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) {
77 (reinterpret_cast<T*>(object))->_wrapper = wrapper;
77 (reinterpret_cast<T*>(object))->_wrapper = wrapper;
78 }
78 }
79
79
80 //! returns the offset that needs to be added to upcast an object of type T1 to T2
80 //! returns the offset that needs to be added to upcast an object of type T1 to T2
81 template<class T1, class T2> int PythonQtUpcastingOffset() {
81 template<class T1, class T2> int PythonQtUpcastingOffset() {
82 return ((reinterpret_cast<char*>(static_cast<T2*>(reinterpret_cast<T1*>(0x100))))
82 return ((reinterpret_cast<char*>(static_cast<T2*>(reinterpret_cast<T1*>(0x100))))
83 - (reinterpret_cast<char*>(reinterpret_cast<T1*>(0x100))));
83 - (reinterpret_cast<char*>(reinterpret_cast<T1*>(0x100))));
84 }
84 }
85
85
86 //! callback to create a QObject lazily
86 //! callback to create a QObject lazily
87 typedef QObject* PythonQtQObjectCreatorFunctionCB();
87 typedef QObject* PythonQtQObjectCreatorFunctionCB();
88
88
89 //! helper template to create a derived QObject class
89 //! helper template to create a derived QObject class
90 template<class T> QObject* PythonQtCreateObject() { return new T(); };
90 template<class T> QObject* PythonQtCreateObject() { return new T(); };
91
91
92 //! The main interface to the Python Qt binding, realized as a singleton
92 //! The main interface to the Python Qt binding, realized as a singleton
93 /*!
93 /*!
94 Use PythonQt::init() to initialize the singleton and PythonQt::self() to access it.
94 Use PythonQt::init() to initialize the singleton and PythonQt::self() to access it.
95 While there can be only one PythonQt instance, you can have any number of Python context to do scripting in.
95 While there can be only one PythonQt instance, you can have any number of Python context to do scripting in.
96 One possibility is to use createModuleFromFile(), createModuleFromScript() or createUniqueModule() to get a context
96 One possibility is to use createModuleFromFile(), createModuleFromScript() or createUniqueModule() to get a context
97 that is separated from the other contexts. Alternatively you can use Python dicts as contexts for script evaluation,
97 that is separated from the other contexts. Alternatively you can use Python dicts as contexts for script evaluation,
98 but you will need to populate the dict with the __builtins__ instance to have all Pythons available when running
98 but you will need to populate the dict with the __builtins__ instance to have all Pythons available when running
99 code in the scope of a dict.
99 code in the scope of a dict.
100 */
100 */
101 class PYTHONQT_EXPORT PythonQt : public QObject {
101 class PYTHONQT_EXPORT PythonQt : public QObject {
102
102
103 Q_OBJECT
103 Q_OBJECT
104
104
105 public:
105 public:
106
106
107 //! flags that can be passed to PythonQt::init()
107 //! flags that can be passed to PythonQt::init()
108 enum InitFlags {
108 enum InitFlags {
109 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
109 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
110 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
110 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
111 ExternalHelp = 4, //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
111 ExternalHelp = 4, //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
112 PythonAlreadyInitialized = 8 //!<< sets that PythonQt should not can PyInitialize, since it is already done
112 PythonAlreadyInitialized = 8 //!<< sets that PythonQt should not can PyInitialize, since it is already done
113 };
113 };
114
114
115 //! flags that tell PythonQt which operators to expect on the registered type
115 //! flags that tell PythonQt which operators to expect on the registered type
116 enum TypeSlots {
116 enum TypeSlots {
117 Type_Add = 1,
117 Type_Add = 1,
118 Type_Subtract = 1 << 1,
118 Type_Subtract = 1 << 1,
119 Type_Multiply = 1 << 2,
119 Type_Multiply = 1 << 2,
120 Type_Divide = 1 << 3,
120 Type_Divide = 1 << 3,
121 Type_Mod = 1 << 4,
121 Type_Mod = 1 << 4,
122 Type_And = 1 << 5,
122 Type_And = 1 << 5,
123 Type_Or = 1 << 6,
123 Type_Or = 1 << 6,
124 Type_Xor = 1 << 7,
124 Type_Xor = 1 << 7,
125 Type_LShift = 1 << 8,
125 Type_LShift = 1 << 8,
126 Type_RShift = 1 << 9,
126 Type_RShift = 1 << 9,
127
127
128 Type_InplaceAdd = 1 << 10,
128 Type_InplaceAdd = 1 << 10,
129 Type_InplaceSubtract = 1 << 11,
129 Type_InplaceSubtract = 1 << 11,
130 Type_InplaceMultiply = 1 << 12,
130 Type_InplaceMultiply = 1 << 12,
131 Type_InplaceDivide = 1 << 13,
131 Type_InplaceDivide = 1 << 13,
132 Type_InplaceMod = 1 << 14,
132 Type_InplaceMod = 1 << 14,
133 Type_InplaceAnd = 1 << 15,
133 Type_InplaceAnd = 1 << 15,
134 Type_InplaceOr = 1 << 16,
134 Type_InplaceOr = 1 << 16,
135 Type_InplaceXor = 1 << 17,
135 Type_InplaceXor = 1 << 17,
136 Type_InplaceLShift = 1 << 18,
136 Type_InplaceLShift = 1 << 18,
137 Type_InplaceRShift = 1 << 19,
137 Type_InplaceRShift = 1 << 19,
138
138
139 // Not yet needed/nicely mappable/generated...
139 // Not yet needed/nicely mappable/generated...
140 //Type_Positive = 1 << 29,
140 //Type_Positive = 1 << 29,
141 //Type_Negative = 1 << 29,
141 //Type_Negative = 1 << 29,
142 //Type_Abs = 1 << 29,
142 //Type_Abs = 1 << 29,
143 //Type_Hash = 1 << 29,
143 //Type_Hash = 1 << 29,
144
144
145 Type_Invert = 1 << 29,
145 Type_Invert = 1 << 29,
146 Type_RichCompare = 1 << 30,
146 Type_RichCompare = 1 << 30,
147 Type_NonZero = 1 << 31,
147 Type_NonZero = 1 << 31,
148
148
149 };
149 };
150
150
151 //! enum for profiling callback
151 //! enum for profiling callback
152 enum ProfilingCallbackState {
152 enum ProfilingCallbackState {
153 Enter = 1,
153 Enter = 1,
154 Leave = 2
154 Leave = 2
155 };
155 };
156
156
157 //! callback for profiling. className and methodName are only passed when state == Enter, otherwise
157 //! callback for profiling. className and methodName are only passed when state == Enter, otherwise
158 //! they are NULL.
158 //! they are NULL.
159 typedef void ProfilingCB(ProfilingCallbackState state, const char* className, const char* methodName);
159 typedef void ProfilingCB(ProfilingCallbackState state, const char* className, const char* methodName);
160
160
161 //---------------------------------------------------------------------------
161 //---------------------------------------------------------------------------
162 //! \name Singleton Initialization
162 //! \name Singleton Initialization
163 //@{
163 //@{
164
164
165 //! initialize the python qt binding (flags are a or combination of PythonQt::InitFlags), if \c pythonQtModuleName is given
165 //! initialize the python qt binding (flags are a or combination of PythonQt::InitFlags), if \c pythonQtModuleName is given
166 //! it defines the name of the python module that PythonQt will add, otherwise "PythonQt" is used.
166 //! it defines the name of the python module that PythonQt will add, otherwise "PythonQt" is used.
167 //! This can be used to e.g. pass in PySide or PyQt4 to make it more compatible.
167 //! This can be used to e.g. pass in PySide or PyQt4 to make it more compatible.
168 static void init(int flags = IgnoreSiteModule | RedirectStdOut, const QByteArray& pythonQtModuleName = QByteArray());
168 static void init(int flags = IgnoreSiteModule | RedirectStdOut, const QByteArray& pythonQtModuleName = QByteArray());
169
169
170 //! cleanup of the singleton
170 //! cleanup of the singleton
171 static void cleanup();
171 static void cleanup();
172
172
173 //! get the singleton instance
173 //! get the singleton instance
174 static PythonQt* self();
174 static PythonQt* self();
175
175
176 //@}
176 //@}
177
177
178 //! defines the object types for introspection
178 //! defines the object types for introspection
179 enum ObjectType {
179 enum ObjectType {
180 Class,
180 Class,
181 Function,
181 Function,
182 Variable,
182 Variable,
183 Module,
183 Module,
184 Anything,
184 Anything,
185 CallOverloads
185 CallOverloads
186 };
186 };
187
187
188
188
189 //---------------------------------------------------------------------------
189 //---------------------------------------------------------------------------
190 //! \name Standard input handling
190 //! \name Standard input handling
191 //@{
191 //@{
192
192
193 //! Overwrite default handling of stdin using a custom callback. It internally backup
193 //! Overwrite default handling of stdin using a custom callback. It internally backup
194 //! the original 'sys.stdin' into 'sys.pythonqt_original_stdin'
194 //! the original 'sys.stdin' into 'sys.pythonqt_original_stdin'
195 void setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData = 0);
195 void setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData = 0);
196
196
197 //! Enable or disable stdin custom callback. It resets 'sys.stdin' using either 'sys.pythonqt_stdin'
197 //! Enable or disable stdin custom callback. It resets 'sys.stdin' using either 'sys.pythonqt_stdin'
198 //! or 'sys.pythonqt_original_stdin'
198 //! or 'sys.pythonqt_original_stdin'
199 void setRedirectStdInCallbackEnabled(bool enabled);
199 void setRedirectStdInCallbackEnabled(bool enabled);
200
200
201 //@}
201 //@}
202
202
203 //---------------------------------------------------------------------------
203 //---------------------------------------------------------------------------
204 //! \name Modules
204 //! \name Modules
205 //@{
205 //@{
206
206
207 //! get the __main__ module of python
207 //! get the __main__ module of python
208 PythonQtObjectPtr getMainModule();
208 PythonQtObjectPtr getMainModule();
209
209
210 //! import the given module and return a reference to it (useful to import e.g. "sys" and call something on it)
210 //! import the given module and return a reference to it (useful to import e.g. "sys" and call something on it)
211 //! If a module is already imported, this returns the already imported module.
211 //! If a module is already imported, this returns the already imported module.
212 PythonQtObjectPtr importModule(const QString& name);
212 PythonQtObjectPtr importModule(const QString& name);
213
213
214 //! creates the new module \c name and evaluates the given file in the context of that module
214 //! creates the new module \c name and evaluates the given file in the context of that module
215 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
215 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
216 //! to a module later on.
216 //! to a module later on.
217 //! The user needs to make sure that the \c name is unique in the python module dictionary.
217 //! The user needs to make sure that the \c name is unique in the python module dictionary.
218 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
218 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
219
219
220 //! creates the new module \c name and evaluates the given script in the context of that module.
220 //! creates the new module \c name and evaluates the given script in the context of that module.
221 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
221 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
222 //! to a module later on.
222 //! to a module later on.
223 //! The user needs to make sure that the \c name is unique in the python module dictionary.
223 //! The user needs to make sure that the \c name is unique in the python module dictionary.
224 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
224 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
225
225
226 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
226 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
227 //! script code
227 //! script code
228 PythonQtObjectPtr createUniqueModule();
228 PythonQtObjectPtr createUniqueModule();
229
229
230 //@}
230 //@}
231
231
232 //---------------------------------------------------------------------------
232 //---------------------------------------------------------------------------
233 //! \name Importing/Paths
233 //! \name Importing/Paths
234 //@{
234 //@{
235
235
236 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
236 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
237 void overwriteSysPath(const QStringList& paths);
237 void overwriteSysPath(const QStringList& paths);
238
238
239 //! prepend a path to sys.path to allow importing from it
239 //! prepend a path to sys.path to allow importing from it
240 void addSysPath(const QString& path);
240 void addSysPath(const QString& path);
241
241
242 //! sets the __path__ list of a module to the given list (important for local imports)
242 //! sets the __path__ list of a module to the given list (important for local imports)
243 void setModuleImportPath(PyObject* module, const QStringList& paths);
243 void setModuleImportPath(PyObject* module, const QStringList& paths);
244
244
245 //@}
245 //@}
246
246
247 //---------------------------------------------------------------------------
247 //---------------------------------------------------------------------------
248 //! \name Registering Classes
248 //! \name Registering Classes
249 //@{
249 //@{
250
250
251 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
251 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
252 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
252 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
253 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
253 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
254 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
254 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
255
255
256 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
256 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
257 //! (ownership of wrapper is passed to PythonQt)
257 //! (ownership of wrapper is passed to PythonQt)
258 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
258 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
259
259
260 This will add a wrapper object that is used to make calls to the given classname \c typeName.
260 This will add a wrapper object that is used to make calls to the given classname \c typeName.
261 All slots that take a pointer to typeName as the first argument will be callable from Python on
261 All slots that take a pointer to typeName as the first argument will be callable from Python on
262 a variant object that contains such a type.
262 a variant object that contains such a type.
263 */
263 */
264 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
264 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
265
265
266 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
266 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
267 //! and it will register the classes when it first sees a pointer to such a derived class
267 //! and it will register the classes when it first sees a pointer to such a derived class
268 void registerQObjectClassNames(const QStringList& names);
268 void registerQObjectClassNames(const QStringList& names);
269
269
270 //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance
270 //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance
271 //! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that
271 //! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that
272 //! type is really derived from parentType.
272 //! type is really derived from parentType.
273 //! Returns false if the typeName was not yet registered.
273 //! Returns false if the typeName was not yet registered.
274 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
274 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
275
275
276 //! add a handler for polymorphic downcasting
276 //! add a handler for polymorphic downcasting
277 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
277 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
278
278
279 //@}
279 //@}
280
280
281 //---------------------------------------------------------------------------
281 //---------------------------------------------------------------------------
282 //! \name Script Parsing and Evaluation
282 //! \name Script Parsing and Evaluation
283 //@{
283 //@{
284
284
285 //! parses the given file and returns the python code object, this can then be used to call evalCode()
285 //! parses the given file and returns the python code object, this can then be used to call evalCode()
286 PythonQtObjectPtr parseFile(const QString& filename);
286 PythonQtObjectPtr parseFile(const QString& filename);
287
287
288 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
288 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
289 //! If pycode is NULL, a python error is printed.
289 //! If pycode is NULL, a python error is printed.
290 QVariant evalCode(PyObject* object, PyObject* pycode);
290 QVariant evalCode(PyObject* object, PyObject* pycode);
291
291
292 //! evaluates the given script code and returns the result value
292 //! evaluates the given script code and returns the result value
293 QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input);
293 QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input);
294
294
295 //! evaluates the given script code from file
295 //! evaluates the given script code from file
296 void evalFile(PyObject* object, const QString& filename);
296 void evalFile(PyObject* object, const QString& filename);
297
297
298 //@}
298 //@}
299
299
300 //---------------------------------------------------------------------------
300 //---------------------------------------------------------------------------
301 //! \name Signal Handlers
301 //! \name Signal Handlers
302 //@{
302 //@{
303
303
304 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
304 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
305 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
305 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
306
306
307 //! remove a signal handler from the given \c signal of \c obj
307 //! remove a signal handler from the given \c signal of \c obj
308 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
308 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
309
309
310 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
310 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
311 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
311 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
312
312
313 //! remove a signal handler from the given \c signal of \c obj
313 //! remove a signal handler from the given \c signal of \c obj
314 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
314 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
315
315
316 //@}
316 //@}
317
317
318 //---------------------------------------------------------------------------
318 //---------------------------------------------------------------------------
319 //! \name Variable access
319 //! \name Variable access
320 //@{
320 //@{
321
321
322 //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable)
322 //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable)
323 void addObject(PyObject* object, const QString& name, QObject* qObject);
323 void addObject(PyObject* object, const QString& name, QObject* qObject);
324
324
325 //! add the given variable to the object
325 //! add the given variable to the object
326 void addVariable(PyObject* object, const QString& name, const QVariant& v);
326 void addVariable(PyObject* object, const QString& name, const QVariant& v);
327
327
328 //! remove the given variable
328 //! remove the given variable
329 void removeVariable(PyObject* module, const QString& name);
329 void removeVariable(PyObject* module, const QString& name);
330
330
331 //! get the variable with the \c name of the \c object, returns an invalid QVariant on error
331 //! get the variable with the \c name of the \c object, returns an invalid QVariant on error
332 QVariant getVariable(PyObject* object, const QString& name);
332 QVariant getVariable(PyObject* object, const QString& name);
333
333
334 //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname
334 //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname
335 QStringList introspection(PyObject* object, const QString& objectname, ObjectType type);
335 QStringList introspection(PyObject* object, const QString& objectname, ObjectType type);
336 //! read vars etc. in scope of the given \c object
336 //! read vars etc. in scope of the given \c object
337 QStringList introspectObject(PyObject* object, ObjectType type);
337 QStringList introspectObject(PyObject* object, ObjectType type);
338 //! read vars etc. in scope of the type object called \c typename. First the typename
338 //! read vars etc. in scope of the type object called \c typename. First the typename
339 //! of the form module.type is split into module and type. Then the module is looked up
339 //! of the form module.type is split into module and type. Then the module is looked up
340 //! in sys.modules. If the module or type is not found there, then the type is looked up in
340 //! in sys.modules. If the module or type is not found there, then the type is looked up in
341 //! the __builtin__ module.
341 //! the __builtin__ module.
342 QStringList introspectType(const QString& typeName, ObjectType type);
342 QStringList introspectType(const QString& typeName, ObjectType type);
343
343
344 //! returns the found callable object or NULL
344 //! returns the found callable object or NULL
345 //! @return new reference
345 //! @return new reference
346 PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
346 PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
347
347
348 //! returns the return type of the method of a wrapped c++ object referenced by \c objectname
348 //! returns the return type of the method of a wrapped c++ object referenced by \c objectname
349 QString getReturnTypeOfWrappedMethod(PyObject* module, const QString& objectname);
349 QString getReturnTypeOfWrappedMethod(PyObject* module, const QString& objectname);
350 //! returns the return type of the method \c methodName of a wrapped c++ type referenced by \c typeName
350 //! returns the return type of the method \c methodName of a wrapped c++ type referenced by \c typeName
351 QString getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName);
351 QString getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName);
352 //@}
352 //@}
353
353
354 //---------------------------------------------------------------------------
354 //---------------------------------------------------------------------------
355 //! \name Calling Python Objects
355 //! \name Calling Python Objects
356 //@{
356 //@{
357
357
358 //! call the given python \c callable in the scope of object, returns the result converted to a QVariant
358 //! call the given python \c callable in the scope of object, returns the result converted to a QVariant
359 QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList(), const QVariantMap& kwargs = QVariantMap());
359 QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList(), const QVariantMap& kwargs = QVariantMap());
360
360
361 //! call the given python object, returns the result converted to a QVariant
361 //! call the given python object, returns the result converted to a QVariant
362 QVariant call(PyObject* callable, const QVariantList& args = QVariantList(), const QVariantMap& kwargs = QVariantMap());
362 QVariant call(PyObject* callable, const QVariantList& args = QVariantList(), const QVariantMap& kwargs = QVariantMap());
363
363
364 //! call the given python object, returns the result as new PyObject
364 //! call the given python object, returns the result as new PyObject
365 PyObject* callAndReturnPyObject(PyObject* callable, const QVariantList& args = QVariantList(), const QVariantMap& kwargs = QVariantMap());
365 PyObject* callAndReturnPyObject(PyObject* callable, const QVariantList& args = QVariantList(), const QVariantMap& kwargs = QVariantMap());
366
366
367 //@}
367 //@}
368
368
369 //---------------------------------------------------------------------------
369 //---------------------------------------------------------------------------
370 //! \name Decorations, Constructors, Wrappers...
370 //! \name Decorations, Constructors, Wrappers...
371 //@{
371 //@{
372
372
373 //! add an object whose slots will be used as decorator slots for
373 //! add an object whose slots will be used as decorator slots for
374 //! other QObjects or CPP classes. The slots need to follow the
374 //! other QObjects or CPP classes. The slots need to follow the
375 //! convention that the first argument is a pointer to the wrapped object.
375 //! convention that the first argument is a pointer to the wrapped object.
376 //! (ownership is passed to PythonQt)
376 //! (ownership is passed to PythonQt)
377 /*!
377 /*!
378 Example:
378 Example:
379
379
380 A slot with the signature
380 A slot with the signature
381
381
382 \code
382 \code
383 bool doSomething(QWidget* w, int a)
383 bool doSomething(QWidget* w, int a)
384 \endcode
384 \endcode
385
385
386 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
386 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
387 that will be called with the concrete instance as first argument.
387 that will be called with the concrete instance as first argument.
388 So in Python you can now e.g. call
388 So in Python you can now e.g. call
389
389
390 \code
390 \code
391 someWidget.doSomething(12)
391 someWidget.doSomething(12)
392 \endcode
392 \endcode
393
393
394 without QWidget really having this method. This allows to easily make normal methods
394 without QWidget really having this method. This allows to easily make normal methods
395 of Qt classes callable by forwarding them with such decorator slots
395 of Qt classes callable by forwarding them with such decorator slots
396 or to make CPP classes (which are not derived from QObject) callable from Python.
396 or to make CPP classes (which are not derived from QObject) callable from Python.
397 */
397 */
398 void addInstanceDecorators(QObject* o);
398 void addInstanceDecorators(QObject* o);
399
399
400 //! add an object whose slots will be used as decorator slots for
400 //! add an object whose slots will be used as decorator slots for
401 //! class objects (ownership is passed to PythonQt)
401 //! class objects (ownership is passed to PythonQt)
402 /*!
402 /*!
403 The slots need to follow the following convention:
403 The slots need to follow the following convention:
404 - SomeClass* new_SomeClass(...)
404 - SomeClass* new_SomeClass(...)
405 - QVariant new_SomeClass(...)
405 - QVariant new_SomeClass(...)
406 - void delete_SomeClass(SomeClass*)
406 - void delete_SomeClass(SomeClass*)
407 - ... static_SomeClass_someName(...)
407 - ... static_SomeClass_someName(...)
408
408
409 This will add:
409 This will add:
410 - a constructor
410 - a constructor
411 - a constructor which generates a QVariant
411 - a constructor which generates a QVariant
412 - a destructor (only useful for CPP objects)
412 - a destructor (only useful for CPP objects)
413 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
413 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
414
414
415 */
415 */
416 void addClassDecorators(QObject* o);
416 void addClassDecorators(QObject* o);
417
417
418 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
418 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
419 void addDecorators(QObject* o);
419 void addDecorators(QObject* o);
420
420
421 //! add the given factory to PythonQt (ownership stays with caller)
421 //! add the given factory to PythonQt (ownership stays with caller)
422 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
422 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
423
423
424 //! add the given factory to PythonQt (ownership stays with caller)
424 //! add the given factory to PythonQt (ownership stays with caller)
425 void addWrapperFactory(PythonQtForeignWrapperFactory* factory);
425 void addWrapperFactory(PythonQtForeignWrapperFactory* factory);
426
426
427 //! remove the wrapper factory
427 //! remove the wrapper factory
428 void removeWrapperFactory(PythonQtCppWrapperFactory* factory);
428 void removeWrapperFactory(PythonQtCppWrapperFactory* factory);
429
429
430 //! remove the wrapper factory
430 //! remove the wrapper factory
431 void removeWrapperFactory(PythonQtForeignWrapperFactory* factory);
431 void removeWrapperFactory(PythonQtForeignWrapperFactory* factory);
432
432
433 //@}
433 //@}
434
434
435 //---------------------------------------------------------------------------
435 //---------------------------------------------------------------------------
436 //! \name Custom Importer
436 //! \name Custom Importer
437 //@{
437 //@{
438
438
439 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
439 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
440 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
440 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
441 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
441 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
442 //! This is not reversible, so even setting setImporter(NULL) afterwards will
442 //! This is not reversible, so even setting setImporter(NULL) afterwards will
443 //! keep the custom PythonQt importer with a QFile default import interface.
443 //! keep the custom PythonQt importer with a QFile default import interface.
444 //! Subsequent python import calls will make use of the passed importInterface
444 //! Subsequent python import calls will make use of the passed importInterface
445 //! which forwards all import calls to the given \c importInterface.
445 //! which forwards all import calls to the given \c importInterface.
446 //! Passing NULL will install a default QFile importer.
446 //! Passing NULL will install a default QFile importer.
447 //! (\c importInterface ownership stays with caller)
447 //! (\c importInterface ownership stays with caller)
448 void setImporter(PythonQtImportFileInterface* importInterface);
448 void setImporter(PythonQtImportFileInterface* importInterface);
449
449
450 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
450 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
451 //! (without calling setImporter or installDefaultImporter at least once, the default python import
451 //! (without calling setImporter or installDefaultImporter at least once, the default python import
452 //! mechanism is in place)
452 //! mechanism is in place)
453 //! the default importer allows to import files from anywhere QFile can read from,
453 //! the default importer allows to import files from anywhere QFile can read from,
454 //! including the Qt resource system using ":". Keep in mind that you need to extend
454 //! including the Qt resource system using ":". Keep in mind that you need to extend
455 //! "sys.path" with ":" to be able to import from the Qt resources.
455 //! "sys.path" with ":" to be able to import from the Qt resources.
456 void installDefaultImporter() { setImporter(NULL); }
456 void installDefaultImporter() { setImporter(NULL); }
457
457
458 //! set paths that the importer should ignore
458 //! set paths that the importer should ignore
459 void setImporterIgnorePaths(const QStringList& paths);
459 void setImporterIgnorePaths(const QStringList& paths);
460
460
461 //! get paths that the importer should ignore
461 //! get paths that the importer should ignore
462 const QStringList& getImporterIgnorePaths();
462 const QStringList& getImporterIgnorePaths();
463
463
464 //! get access to the file importer (if set)
464 //! get access to the file importer (if set)
465 static PythonQtImportFileInterface* importInterface();
465 static PythonQtImportFileInterface* importInterface();
466
466
467 //@}
467 //@}
468
468
469 //---------------------------------------------------------------------------
469 //---------------------------------------------------------------------------
470 //! \name Other Stuff
470 //! \name Other Stuff
471 //@{
471 //@{
472
472
473 //! get access to internal data (should not be used on the public API, but is used by some C functions)
473 //! get access to internal data (should not be used on the public API, but is used by some C functions)
474 static PythonQtPrivate* priv() { return _self->_p; }
474 static PythonQtPrivate* priv() { return _self->_p; }
475
475
476 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
476 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
477 //! The error is currently just output to the python stderr, future version might implement better trace printing
477 //! The error is currently just output to the python stderr, future version might implement better trace printing
478 bool handleError();
478 bool handleError();
479
479
480 //! clear all NotFound entries on all class infos, to ensure that
480 //! clear all NotFound entries on all class infos, to ensure that
481 //! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded
481 //! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded
482 void clearNotFoundCachedMembers();
482 void clearNotFoundCachedMembers();
483
483
484 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
484 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
485 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
485 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
486 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
486 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
487 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
487 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
488
488
489 //! call the callback if it is set
489 //! call the callback if it is set
490 static void qObjectNoLongerWrappedCB(QObject* o);
490 static void qObjectNoLongerWrappedCB(QObject* o);
491
491
492 //! called by internal help methods
492 //! called by internal help methods
493 PyObject* helpCalled(PythonQtClassInfo* info);
493 PyObject* helpCalled(PythonQtClassInfo* info);
494
494
495 //! returns the found object or NULL
495 //! returns the found object or NULL
496 //! @return new reference
496 //! @return new reference
497 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
497 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
498
498
499 //! sets a callback that is called before and after function calls for profiling
499 //! sets a callback that is called before and after function calls for profiling
500 void setProfilingCallback(ProfilingCB* cb);
500 void setProfilingCallback(ProfilingCB* cb);
501
501
502 //@}
502 //@}
503
503
504 signals:
504 signals:
505 //! emitted when python outputs something to stdout (and redirection is turned on)
505 //! emitted when python outputs something to stdout (and redirection is turned on)
506 void pythonStdOut(const QString& str);
506 void pythonStdOut(const QString& str);
507 //! emitted when python outputs something to stderr (and redirection is turned on)
507 //! emitted when python outputs something to stderr (and redirection is turned on)
508 void pythonStdErr(const QString& str);
508 void pythonStdErr(const QString& str);
509
509
510 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
510 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
511 void pythonHelpRequest(const QByteArray& cppClassName);
511 void pythonHelpRequest(const QByteArray& cppClassName);
512
512
513 private:
513 private:
514 void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName);
514 void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName);
515
515
516 QString getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context);
516 QString getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context);
517
517
518 PyObject* getObjectByType(const QString& typeName);
518 PyObject* getObjectByType(const QString& typeName);
519
519
520 //! callback for stdout redirection, emits pythonStdOut signal
520 //! callback for stdout redirection, emits pythonStdOut signal
521 static void stdOutRedirectCB(const QString& str);
521 static void stdOutRedirectCB(const QString& str);
522 //! callback for stderr redirection, emits pythonStdErr signal
522 //! callback for stderr redirection, emits pythonStdErr signal
523 static void stdErrRedirectCB(const QString& str);
523 static void stdErrRedirectCB(const QString& str);
524
524
525 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
525 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
526 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
526 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
527
527
528 PythonQt(int flags, const QByteArray& pythonQtModuleName);
528 PythonQt(int flags, const QByteArray& pythonQtModuleName);
529 ~PythonQt();
529 ~PythonQt();
530
530
531 static PythonQt* _self;
531 static PythonQt* _self;
532 static int _uniqueModuleCount;
532 static int _uniqueModuleCount;
533
533
534 PythonQtPrivate* _p;
534 PythonQtPrivate* _p;
535
535
536 };
536 };
537
537
538 //! internal PythonQt details
538 //! internal PythonQt details
539 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
539 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
540
540
541 Q_OBJECT
541 Q_OBJECT
542
542
543 public:
543 public:
544 PythonQtPrivate();
544 PythonQtPrivate();
545 ~PythonQtPrivate();
545 ~PythonQtPrivate();
546
546
547 enum DecoratorTypes {
547 enum DecoratorTypes {
548 StaticDecorator = 1,
548 StaticDecorator = 1,
549 ConstructorDecorator = 2,
549 ConstructorDecorator = 2,
550 DestructorDecorator = 4,
550 DestructorDecorator = 4,
551 InstanceDecorator = 8,
551 InstanceDecorator = 8,
552 AllDecorators = 0xffff
552 AllDecorators = 0xffff
553 };
553 };
554
554
555 //! get the suffixes that are used for shared libraries
555 //! get the suffixes that are used for shared libraries
556 const QStringList& sharedLibrarySuffixes() { return _sharedLibrarySuffixes; }
556 const QStringList& sharedLibrarySuffixes() { return _sharedLibrarySuffixes; }
557
557
558 //! returns if the id is the id for PythonQtObjectPtr
558 //! returns if the id is the id for PythonQtObjectPtr
559 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
559 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
560
560
561 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
561 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
562 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
562 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
563 //! remove the wrapper ptr again
563 //! remove the wrapper ptr again
564 void removeWrapperPointer(void* obj);
564 void removeWrapperPointer(void* obj);
565
565
566 //! called by destructor of shells to allow invalidation of the Python wrapper
566 //! called by destructor of shells to allow invalidation of the Python wrapper
567 void shellClassDeleted(void* shellClass);
567 void shellClassDeleted(void* shellClass);
568
568
569 //! try to unwrap the given object to a C++ pointer using the foreign wrapper factories
569 //! try to unwrap the given object to a C++ pointer using the foreign wrapper factories
570 void* unwrapForeignWrapper(const QByteArray& classname, PyObject* obj);
570 void* unwrapForeignWrapper(const QByteArray& classname, PyObject* obj);
571
571
572 //! add parent class relation
572 //! add parent class relation
573 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
573 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
574
574
575 //! add a handler for polymorphic downcasting
575 //! add a handler for polymorphic downcasting
576 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
576 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
577
577
578 //! lookup existing classinfo and return new if not yet present
578 //! lookup existing classinfo and return new if not yet present
579 PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
579 PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
580
580
581 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
581 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
582 void removeSignalEmitter(QObject* obj);
582 void removeSignalEmitter(QObject* obj);
583
583
584 //! wrap the given QObject into a Python object (or return existing wrapper!)
584 //! wrap the given QObject into a Python object (or return existing wrapper!)
585 PyObject* wrapQObject(QObject* obj);
585 PyObject* wrapQObject(QObject* obj);
586
586
587 //! wrap the given ptr into a Python object (or return existing wrapper!) if there is a known QObject of that name or a known wrapper in the factory
587 //! wrap the given ptr into a Python object (or return existing wrapper!) if there is a known QObject of that name or a known wrapper in the factory
588 PyObject* wrapPtr(void* ptr, const QByteArray& name);
588 PyObject* wrapPtr(void* ptr, const QByteArray& name);
589
589
590 //! create a read-only buffer object from the given memory
591 static PyObject* wrapMemoryAsBuffer(const void* data, Py_ssize_t size);
592
593 //! create a read-write buffer object from the given memory
594 static PyObject* wrapMemoryAsBuffer(void* data, Py_ssize_t size);
595
590 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
596 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
591 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
597 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
592 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
598 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
593 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
599 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
594
600
595 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
601 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
596 //! (ownership of wrapper is passed to PythonQt)
602 //! (ownership of wrapper is passed to PythonQt)
597 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
603 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
598
604
599 This will add a wrapper object that is used to make calls to the given classname \c typeName.
605 This will add a wrapper object that is used to make calls to the given classname \c typeName.
600 All slots that take a pointer to typeName as the first argument will be callable from Python on
606 All slots that take a pointer to typeName as the first argument will be callable from Python on
601 a variant object that contains such a type.
607 a variant object that contains such a type.
602 */
608 */
603 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
609 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
604
610
605 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
611 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
606 //! and it will register the classes when it first sees a pointer to such a derived class
612 //! and it will register the classes when it first sees a pointer to such a derived class
607 void registerQObjectClassNames(const QStringList& names);
613 void registerQObjectClassNames(const QStringList& names);
608
614
609 //! add a decorator object
615 //! add a decorator object
610 void addDecorators(QObject* o, int decoTypes);
616 void addDecorators(QObject* o, int decoTypes);
611
617
612 //! helper method that creates a PythonQtClassWrapper object (returns a new reference)
618 //! helper method that creates a PythonQtClassWrapper object (returns a new reference)
613 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* module);
619 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* module);
614
620
615 //! create a new instance of the given enum type with given value (returns a new reference)
621 //! create a new instance of the given enum type with given value (returns a new reference)
616 static PyObject* createEnumValueInstance(PyObject* enumType, unsigned int enumValue);
622 static PyObject* createEnumValueInstance(PyObject* enumType, unsigned int enumValue);
617
623
618 //! helper that creates a new int derived class that represents the enum of the given name (returns a new reference)
624 //! helper that creates a new int derived class that represents the enum of the given name (returns a new reference)
619 static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
625 static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
620
626
621 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
627 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
622 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
628 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
623
629
624 //! get the class info for a meta object (if available)
630 //! get the class info for a meta object (if available)
625 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
631 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
626
632
627 //! get the class info for a meta object (if available)
633 //! get the class info for a meta object (if available)
628 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
634 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
629
635
630 //! creates the new module from the given pycode
636 //! creates the new module from the given pycode
631 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
637 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
632
638
633 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
639 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
634 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
640 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
635
641
636 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
642 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
637 static PyObject* dummyTuple();
643 static PyObject* dummyTuple();
638
644
639 //! called by virtual overloads when a python return value can not be converted to the required Qt type
645 //! called by virtual overloads when a python return value can not be converted to the required Qt type
640 void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result);
646 void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result);
641
647
642 //! get access to the PythonQt module
648 //! get access to the PythonQt module
643 PythonQtObjectPtr pythonQtModule() const { return _pythonQtModule; }
649 PythonQtObjectPtr pythonQtModule() const { return _pythonQtModule; }
644
650
645 //! returns the profiling callback, which may be NULL
651 //! returns the profiling callback, which may be NULL
646 PythonQt::ProfilingCB* profilingCB() const { return _profilingCB; }
652 PythonQt::ProfilingCB* profilingCB() const { return _profilingCB; }
647
653
648 //! determines the signature of the given callable object (similar as pydoc)
654 //! determines the signature of the given callable object (similar as pydoc)
649 QString getSignature(PyObject* object);
655 QString getSignature(PyObject* object);
650
656
651 //! returns true if the object is a method descriptor (same as inspect.ismethoddescriptor() in inspect.py)
657 //! returns true if the object is a method descriptor (same as inspect.ismethoddescriptor() in inspect.py)
652 bool isMethodDescriptor(PyObject* object) const;
658 bool isMethodDescriptor(PyObject* object) const;
653
659
654 private:
660 private:
655 //! Setup the shared library suffixes by getting them from the "imp" module.
661 //! Setup the shared library suffixes by getting them from the "imp" module.
656 void setupSharedLibrarySuffixes();
662 void setupSharedLibrarySuffixes();
657
663
658 //! create a new pythonqt class wrapper and place it in the pythonqt module
664 //! create a new pythonqt class wrapper and place it in the pythonqt module
659 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module = NULL);
665 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module = NULL);
660
666
661 //! get/create new package module (the returned object is a borrowed reference)
667 //! get/create new package module (the returned object is a borrowed reference)
662 PyObject* packageByName(const char* name);
668 PyObject* packageByName(const char* name);
663
669
664 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
670 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
665 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
671 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
666
672
667 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
673 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
668 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
674 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
669
675
670 //! stores the meta info of known Qt classes
676 //! stores the meta info of known Qt classes
671 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
677 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
672
678
673 //! names of qobject derived classes that can be casted to qobject savely
679 //! names of qobject derived classes that can be casted to qobject savely
674 QHash<QByteArray, bool> _knownQObjectClassNames;
680 QHash<QByteArray, bool> _knownQObjectClassNames;
675
681
676 //! stores signal receivers for QObjects
682 //! stores signal receivers for QObjects
677 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
683 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
678
684
679 //! the PythonQt python module
685 //! the PythonQt python module
680 PythonQtObjectPtr _pythonQtModule;
686 PythonQtObjectPtr _pythonQtModule;
681
687
682 //! the name of the PythonQt python module
688 //! the name of the PythonQt python module
683 QByteArray _pythonQtModuleName;
689 QByteArray _pythonQtModuleName;
684
690
685 //! the importer interface (if set)
691 //! the importer interface (if set)
686 PythonQtImportFileInterface* _importInterface;
692 PythonQtImportFileInterface* _importInterface;
687
693
688 //! the default importer
694 //! the default importer
689 PythonQtQFileImporter* _defaultImporter;
695 PythonQtQFileImporter* _defaultImporter;
690
696
691 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
697 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
692 PythonQtQObjectWrappedCB* _wrappedCB;
698 PythonQtQObjectWrappedCB* _wrappedCB;
693
699
694 QStringList _importIgnorePaths;
700 QStringList _importIgnorePaths;
695 QStringList _sharedLibrarySuffixes;
701 QStringList _sharedLibrarySuffixes;
696
702
697 //! the cpp object wrapper factories
703 //! the cpp object wrapper factories
698 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
704 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
699
705
700 QList<PythonQtForeignWrapperFactory*> _foreignWrapperFactories;
706 QList<PythonQtForeignWrapperFactory*> _foreignWrapperFactories;
701
707
702 QHash<QByteArray, PyObject*> _packages;
708 QHash<QByteArray, PyObject*> _packages;
703
709
704 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
710 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
705
711
706 PythonQt::ProfilingCB* _profilingCB;
712 PythonQt::ProfilingCB* _profilingCB;
707
713
708 int _initFlags;
714 int _initFlags;
709 int _PythonQtObjectPtr_metaId;
715 int _PythonQtObjectPtr_metaId;
710
716
711 friend class PythonQt;
717 friend class PythonQt;
712 };
718 };
713
719
714 #endif
720 #endif
@@ -1,535 +1,532
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) 2010 MeVis Medical Solutions AG All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, 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 notitle
49 \mainpage notitle
50 \endif
50 \endif
51
51
52 \image html PythonQt.jpg
52 \image html PythonQt.jpg
53
53
54 \section Introduction
54 \section Introduction
55
55
56 \b PythonQt is a dynamic <a href="http://www.python.org" target="_blank">
56 \b PythonQt is a dynamic <a href="http://www.python.org" target="_blank">
57 Python</a> binding for the <a href="http://qt.nokia.com" target="_blank">
57 Python</a> binding for the <a href="http://qt.nokia.com" target="_blank">
58 Qt framework</a>.
58 Qt framework</a>.
59 It offers an easy way to embed the Python scripting language into
59 It offers an easy way to embed the Python scripting language into
60 your C++ Qt applications. It makes heavy use of the QMetaObject system and thus requires Qt 4.x.
60 your C++ Qt applications. It makes heavy use of the QMetaObject system and thus requires Qt 4.x.
61
61
62 The focus of PythonQt is on embedding Python into an existing C++ application, not on writing the whole
62 The focus of PythonQt is on embedding Python into an existing C++ application, not on writing the whole
63 application completely in Python. If you want to write your whole application in Python,
63 application completely in Python. If you want to write your whole application in Python,
64 you should use <a href="http://www.riverbankcomputing.co.uk/pyqt/" target="_blank">PyQt</a> or <a href="http://www.pyside.org" target="_blank">PySide</a> instead.
64 you should use <a href="http://www.riverbankcomputing.co.uk/pyqt/" target="_blank">PyQt</a> or <a href="http://www.pyside.org" target="_blank">PySide</a> instead.
65
65
66 If you are looking for a simple way to embed Python objects into your C++/Qt Application
66 If you are looking for a simple way to embed Python objects into your C++/Qt Application
67 and to script parts of your application via Python, PythonQt is the way to go!
67 and to script parts of your application via Python, PythonQt is the way to go!
68
68
69 PythonQt is a stable library that was developed to make the
69 PythonQt is a stable library that was developed to make the
70 Image Processing and Visualization platform <a href="http://www.mevislab.de" target="_blank">MeVisLab</a>
70 Image Processing and Visualization platform <a href="http://www.mevislab.de" target="_blank">MeVisLab</a>
71 scriptable from Python.
71 scriptable from Python.
72
72
73 - \ref Features
73 - \ref Features
74 - \ref Download
74 - \ref Download
75 - \ref License
75 - \ref License
76 - \ref Developer
76 - \ref Developer
77 - \ref Building
77 - \ref Building
78 - \ref Examples
78 - \ref Examples
79
79
80 \page Features Features
80 \page Features Features
81
81
82 \section Builtin Built-in Features
82 \section Builtin Built-in Features
83
83
84 The following are the built-in features of the PythonQt library:
84 The following are the built-in features of the PythonQt library:
85
85
86 - Access all \b slots, \b properties, children and registered enums of any QObject derived class from Python
86 - Access all \b slots, \b properties, children and registered enums of any QObject derived class from Python
87 - Connecting Qt Signals to Python functions (both from within Python and from C++)
87 - Connecting Qt Signals to Python functions (both from within Python and from C++)
88 - Easy wrapping of Python objects from C++ with smart, reference-counting PythonQtObjectPtr.
88 - Easy wrapping of Python objects from C++ with smart, reference-counting PythonQtObjectPtr.
89 - Convenient conversions to/from QVariant for PythonQtObjectPtr.
89 - Convenient conversions to/from QVariant for PythonQtObjectPtr.
90 - Wrapping of C++ objects (which are not derived from QObject) via PythonQtCppWrapperFactory
90 - Wrapping of C++ objects (which are not derived from QObject) via PythonQtCppWrapperFactory
91 - Extending C++ and QObject derived classes with additional slots, static methods and constructors (see Decorators)
91 - Extending C++ and QObject derived classes with additional slots, static methods and constructors (see Decorators)
92 - StdOut/Err redirection to Qt signals instead of cout
92 - StdOut/Err redirection to Qt signals instead of cout
93 - Interface for creating your own \c import replacement, so that Python scripts can be e.g. signed/verified before they are executed (PythonQtImportFileInterface)
93 - Interface for creating your own \c import replacement, so that Python scripts can be e.g. signed/verified before they are executed (PythonQtImportFileInterface)
94 - Mapping of plain-old-datatypes and ALL QVariant types to and from Python
94 - Mapping of plain-old-datatypes and ALL QVariant types to and from Python
95 - Support for wrapping of user QVariant types which are registerd via QMetaType
95 - Support for wrapping of user QVariant types which are registerd via QMetaType
96 - Support for Qt namespace (with all enumerators)
96 - Support for Qt namespace (with all enumerators)
97 - All PythonQt wrapped objects support the dir() statement, so that you can see easily which attributes a QObject, CPP object or QVariant has
97 - All PythonQt wrapped objects support the dir() statement, so that you can see easily which attributes a QObject, CPP object or QVariant has
98 - 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)
98 - 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)
99 - 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)
99 - 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)
100 - 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)
100 - 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)
101 - Deriving C++ objects from Python and overwriting virtual method with a Python implementation (requires usage of wrapper generator or manual work!)
101 - Deriving C++ objects from Python and overwriting virtual method with a Python implementation (requires usage of wrapper generator or manual work!)
102 - Extensible handler for Python/C++ conversion of complex types, e.g. mapping of QVector<SomeObject> to/from a Python array
102 - Extensible handler for Python/C++ conversion of complex types, e.g. mapping of QVector<SomeObject> to/from a Python array
103 - Setting of dynamic QObject properties via setProperty(), dynamic properties can be accessed for reading and writing like normal Python attributes (but creating a new property needs to be done with setProperty(), to distinguish from normal Python attributes)
103 - Setting of dynamic QObject properties via setProperty(), dynamic properties can be accessed for reading and writing like normal Python attributes (but creating a new property needs to be done with setProperty(), to distinguish from normal Python attributes)
104
104
105 \section FeaturesQtAll Features with wrapper generator
105 \section FeaturesQtAll Features with wrapper generator
106
106
107 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.
107 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.
108 This offers the following features:
108 This offers the following features:
109
109
110 - Complete Qt API wrapped and accessible
110 - Complete Qt API wrapped and accessible
111 - The following modules are available as submodules of the PythonQt module:
111 - The following modules are available as submodules of the PythonQt module:
112 - QtCore
112 - QtCore
113 - QtGui
113 - QtGui
114 - QtNetwork
114 - QtNetwork
115 - QtOpenGL
115 - QtOpenGL
116 - QtSql
116 - QtSql
117 - QtSvg
117 - QtSvg
118 - QtUiTools
118 - QtUiTools
119 - QtWebKit
119 - QtWebKit
120 - QtXml
120 - QtXml
121 - (QtXmlPatterns, QtScript, QtHelp, phonon, assistant, designer are currently not supported, this would require some additional effort on the code generator)
121 - (QtXmlPatterns, QtScript, QtHelp, phonon, assistant, designer are currently not supported, this would require some additional effort on the code generator)
122 - 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
122 - 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
123 - Any Qt class that has virtual methods can be easily derived from Python and the virtual methods can be reimplemented in Python (this feature is considered experimental!)
123 - Any Qt class that has virtual methods can be easily derived from Python and the virtual methods can be reimplemented in Python (this feature is considered experimental!)
124 - Polymorphic downcasting on QEvent, QGraphicsItem, QStyleOption, ...
124 - Polymorphic downcasting on QEvent, QGraphicsItem, QStyleOption, ...
125 - Multiple inheritance support (e.g., QGraphicsTextItem is a QObject AND a QGraphicsItem, PythonQt will handle this well)
125 - Multiple inheritance support (e.g., QGraphicsTextItem is a QObject AND a QGraphicsItem, PythonQt will handle this well)
126
126
127 \section Comparison Comparison with PyQt/PySide
127 \section Comparison Comparison with PyQt/PySide
128
128
129 - 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
129 - 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
130 - 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
130 - 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
131 - 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)
131 - 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)
132 - PythonQt currently does not support instanceof checks for Qt classes, except for the exact match and derived Python classes
132 - PythonQt currently does not support instanceof checks for Qt classes, except for the exact match and derived Python classes
133 - QObject.emit to emit Qt signals from Python is not yet implemented but PythonQt allows to just emit a signal by calling it like a normal slot
133 - QObject.emit to emit Qt signals from Python is not yet implemented but PythonQt allows to just emit a signal by calling it like a normal slot
134 - PythonQt does not (yet) offer to add new signals to Python/C++ objects and it does not yet support the newstyle PyQt signals (so you need to connect via C++ string signatures)
134 - PythonQt does not (yet) offer to add new signals to Python/C++ objects and it does not yet support the newstyle PyQt signals (so you need to connect via C++ string signatures)
135 - 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 in a future version)
135 - 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 in a future version)
136 - QStrings are always converted to unicode Python objects, QByteArray always stays a QByteArray and can be converted using str()
136 - QStrings are always converted to unicode Python objects, QByteArray always stays a QByteArray and can be converted using str()
137 - There are many details in the generated wrappers that could need some polishing, e.g., methods that use pointer arguments for additional return values could return a results tuple.
137 - There are many details in the generated wrappers that could need some polishing, e.g., methods that use pointer arguments for additional return values could return a results tuple.
138 - Not all types of QList/QVector/QHash templates are supported, some Qt methods use those as arguments/return values (but you can add your own handlers to handle them if you need them).
138 - Not all types of QList/QVector/QHash templates are supported, some Qt methods use those as arguments/return values (but you can add your own handlers to handle them if you need them).
139 - Probably there are lots of details that differ, I do not know PyQt that well to list them all.
139 - Probably there are lots of details that differ, I do not know PyQt that well to list them all.
140 - In the long run, PythonQt will consider using/extending PySide with the features of PythonQt to get rid of its own generator and typesystem files, alternatively the KDE Smoke generator might be used in the future (this has not yet been decided, the current PythonQt generator works well and there is no hurry to switch).
140 - In the long run, PythonQt will consider using/extending PySide with the features of PythonQt to get rid of its own generator and typesystem files, alternatively the KDE Smoke generator might be used in the future (this has not yet been decided, the current PythonQt generator works well and there is no hurry to switch).
141
141
142 \page Download Download
142 \page Download Download
143
143
144 PythonQt is hosted on <a href="http://sourceforge.net/projects/pythonqt/" target="_blank">SourceForge</a>.
144 PythonQt is hosted on <a href="http://sourceforge.net/projects/pythonqt/" target="_blank">SourceForge</a>.
145
145
146 You can download the source code as a tarball at http://sourceforge.net/projects/pythonqt/files/.
146 You can download the source code as a tarball at http://sourceforge.net/projects/pythonqt/files/.
147 Alternatively you can get the latest version from the svn repository.
147 Alternatively you can get the latest version from the svn repository.
148
148
149 You can also browse the source code online via ViewVC: http://pythonqt.svn.sourceforge.net/viewvc/pythonqt/trunk/
149 You can also browse the source code online via ViewVC: http://pythonqt.svn.sourceforge.net/viewvc/pythonqt/trunk/
150
150
151 \note We do not offer prebuilt binaries, since there are so many possible combinations of
151 \note We do not offer prebuilt binaries, since there are so many possible combinations of
152 platforms (Windows/Linux/MacOs), architectures (32/64 bit) and Python versions.
152 platforms (Windows/Linux/MacOs), architectures (32/64 bit) and Python versions.
153
153
154 \page License License
154 \page License License
155
155
156 PythonQt is distributed under the LGPL license, so it pairs well with the LGPL of the Qt 4.5 release and allows
156 PythonQt is distributed under the LGPL license, so it pairs well with the LGPL of the Qt 4.5 release and allows
157 to be used in commercial applications when following the LGPL 2.1 obligations.
157 to be used in commercial applications when following the LGPL 2.1 obligations.
158
158
159 The build system of PythonQt makes use of a modified version of the LGPL'ed QtScript generator,
159 The build system of PythonQt makes use of a modified version of the LGPL'ed QtScript generator,
160 located in the "generator" directory.
160 located in the "generator" directory.
161
161
162 See http://qt.gitorious.org/qt-labs/qtscriptgenerator for details on the original project.
162 See http://qt.gitorious.org/qt-labs/qtscriptgenerator for details on the original project.
163 Thanks a lot to the QtJambi guys and the QtScript Generator project for the C++ parser and
163 Thanks a lot to the QtJambi guys and the QtScript Generator project for the C++ parser and
164 Qt typesystem files!
164 Qt typesystem files!
165
165
166 The PythonQt wrappers generated by the generator located in the "generated_cpp" directory are free to be used without any licensing restrictions.
166 The PythonQt wrappers generated by the generator located in the "generated_cpp" directory are free to be used without any licensing restrictions.
167
167
168 The generated wrappers are pre-generated and checked-in for Qt 4.8, so you only need to build and run the
168 The generated wrappers are pre-generated and checked-in for Qt 4.6.1, so you only need to build and run the
169 generator when you want to build additional wrappers or you want to upgrade/downgrade to another Qt version.
169 generator when you want to build additional wrappers or you want to upgrade/downgrade to another Qt version.
170 You may use the generator to generate C++ bindings for your own C++ classes (e.g., to make them inheritable in Python),
170 You may use the generator to generate C++ bindings for your own C++ classes (e.g., to make them inheritable in Python),
171 but this is currently not documented and involves creating your own typesystem files (although the Qt Jambi examples might help you).
171 but this is currently not documented and involves creating your own typesystem files (although the Qt Jambi examples might help you).
172
172
173
173
174 \page Developer Developer
174 \page Developer Developer
175
175
176 \section Interface Interface
176 \section Interface Interface
177
177
178 The main interface to PythonQt is the PythonQt singleton.
178 The main interface to PythonQt is the PythonQt singleton.
179 PythonQt needs to be initialized via PythonQt::init() once.
179 PythonQt needs to be initialized via PythonQt::init() once.
180 Afterwards you communicate with the singleton via PythonQt::self().
180 Afterwards you communicate with the singleton via PythonQt::self().
181 PythonQt offers a complete Qt binding, which
181 PythonQt offers a complete Qt binding, which
182 needs to be enabled via PythonQt_QtAll::init().
182 needs to be enabled via PythonQt_QtAll::init().
183
183
184
184
185 \section Datatype Datatype Mapping
185 \section Datatype Datatype Mapping
186
186
187 The following table shows the mapping between Python and Qt objects:
187 The following table shows the mapping between Python and Qt objects:
188 <table>
188 <table>
189 <tr><th>Qt/C++</th><th>Python</th></tr>
189 <tr><th>Qt/C++</th><th>Python</th></tr>
190 <tr><td>bool</td><td>bool</td></tr>
190 <tr><td>bool</td><td>bool</td></tr>
191 <tr><td>double</td><td>float</td></tr>
191 <tr><td>double</td><td>float</td></tr>
192 <tr><td>float</td><td>float</td></tr>
192 <tr><td>float</td><td>float</td></tr>
193 <tr><td>char/uchar,int/uint,short,ushort,QChar</td><td>integer</td></tr>
193 <tr><td>char/uchar,int/uint,short,ushort,QChar</td><td>integer</td></tr>
194 <tr><td>long</td><td>integer</td></tr>
194 <tr><td>long</td><td>integer</td></tr>
195 <tr><td>ulong,longlong,ulonglong</td><td>long</td></tr>
195 <tr><td>ulong,longlong,ulonglong</td><td>long</td></tr>
196 <tr><td>QString</td><td>unicode string</td></tr>
196 <tr><td>QString</td><td>unicode string</td></tr>
197 <tr><td>QByteArray</td><td>QByteArray wrapper</td></tr>
197 <tr><td>QByteArray</td><td>QByteArray wrapper</td></tr>
198 <tr><td>char*</td><td>str</td></tr>
198 <tr><td>char*</td><td>str</td></tr>
199 <tr><td>QStringList</td><td>tuple of unicode strings</td></tr>
199 <tr><td>QStringList</td><td>tuple of unicode strings</td></tr>
200 <tr><td>QVariantList</td><td>tuple of objects</td></tr>
200 <tr><td>QVariantList</td><td>tuple of objects</td></tr>
201 <tr><td>QVariantMap</td><td>dict of objects</td></tr>
201 <tr><td>QVariantMap</td><td>dict of objects</td></tr>
202 <tr><td>QVariant</td><td>depends on type, see below</td></tr>
202 <tr><td>QVariant</td><td>depends on type, see below</td></tr>
203 <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>
203 <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>
204 <tr><td>OwnRegisteredMetaType</td><td>C++ wrapper, optionally with additional information/wrapping provided by registerCPPClass()</td></tr>
204 <tr><td>OwnRegisteredMetaType</td><td>C++ wrapper, optionally with additional information/wrapping provided by registerCPPClass()</td></tr>
205 <tr><td>QList<AnyObject*></td><td>converts to a list of CPP wrappers</td></tr>
205 <tr><td>QList<AnyObject*></td><td>converts to a list of CPP wrappers</td></tr>
206 <tr><td>QVector<AnyObject*></td><td>converts to a list of CPP wrappers</td></tr>
206 <tr><td>QVector<AnyObject*></td><td>converts to a list of CPP wrappers</td></tr>
207 <tr><td>EnumType</td><td>Enum wrapper derived from python integer</td></tr>
207 <tr><td>EnumType</td><td>Enum wrapper derived from python integer</td></tr>
208 <tr><td>QObject (and derived classes)</td><td>QObject wrapper</td></tr>
208 <tr><td>QObject (and derived classes)</td><td>QObject wrapper</td></tr>
209 <tr><td>C++ object</td><td>CPP wrapper, either wrapped via PythonQtCppWrapperFactory or just decorated with decorators</td></tr>
209 <tr><td>C++ object</td><td>CPP wrapper, either wrapped via PythonQtCppWrapperFactory or just decorated with decorators</td></tr>
210 <tr><td>PyObject</td><td>PyObject</td></tr>
210 <tr><td>PyObject</td><td>PyObject</td></tr>
211 </table>
211 </table>
212
212
213 PyObject is passed as direct pointer, which allows to pass/return any Python object directly to/from
213 PyObject is passed as direct pointer, which allows to pass/return any Python object directly to/from
214 a Qt slot that uses PyObject* as its argument/return value.
214 a Qt slot that uses PyObject* as its argument/return value.
215 QVariants are mapped recursively as given above, e.g. a dictionary can
215 QVariants are mapped recursively as given above, e.g. a dictionary can
216 contain lists of dictionaries of doubles.
216 contain lists of dictionaries of doubles.
217 All Qt QVariant types are implemented, PythonQt supports the complete Qt API for these object.
217 All Qt QVariant types are implemented, PythonQt supports the complete Qt API for these object.
218
218
219 \section QObject QObject Wrapping
219 \section QObject QObject Wrapping
220
220
221 All classes derived from QObject are automatically wrapped with a python wrapper class
221 All classes derived from QObject are automatically wrapped with a python wrapper class
222 when they become visible to the Python interpreter. This can happen via
222 when they become visible to the Python interpreter. This can happen via
223 - the PythonQt::addObject() method
223 - the PythonQt::addObject() method
224 - when a Qt \b slot returns a QObject derived object to python
224 - when a Qt \b slot returns a QObject derived object to python
225 - when a Qt \b signal contains a QObject and is connected to a python function
225 - when a Qt \b signal contains a QObject and is connected to a python function
226
226
227 It is important that you call PythonQt::registerClass() for any QObject derived class
227 It is important that you call PythonQt::registerClass() for any QObject derived class
228 that may become visible to Python, except when you add it via PythonQt::addObject().
228 that may become visible to Python, except when you add it via PythonQt::addObject().
229 This will register the complete parent hierachy of the registered class, so that
229 This will register the complete parent hierachy of the registered class, so that
230 when you register e.g. a QPushButton, QWidget will be registered as well (and all intermediate
230 when you register e.g. a QPushButton, QWidget will be registered as well (and all intermediate
231 parents).
231 parents).
232
232
233 From Python, you can talk to the returned QObjects in a natural way by calling
233 From Python, you can talk to the returned QObjects in a natural way by calling
234 their slots and receiving the return values. You can also read/write all
234 their slots and receiving the return values. You can also read/write all
235 properties of the objects as if they where normal python properties.
235 properties of the objects as if they where normal python properties.
236
236
237 In addition to this, the wrapped objects support
237 In addition to this, the wrapped objects support
238 - className() - returns a string that reprents the classname of the QObject
238 - className() - returns a string that reprents the classname of the QObject
239 - help() - shows all properties, slots, enums, decorator slots and constructors of the object, in a printable form
239 - help() - shows all properties, slots, enums, decorator slots and constructors of the object, in a printable form
240 - delete() - deletes the object (use with care, especially if you passed the ownership to C++)
240 - delete() - deletes the object (use with care, especially if you passed the ownership to C++)
241 - connect(signal, function) - connect the signal of the given object to a python function
241 - connect(signal, function) - connect the signal of the given object to a python function
242 - connect(signal, qobject, slot) - connect the signal of the given object to a slot of another QObject
242 - connect(signal, qobject, slot) - connect the signal of the given object to a slot of another QObject
243 - disconnect(signal, function) - disconnect the signal of the given object from a python function
243 - disconnect(signal, function) - disconnect the signal of the given object from a python function
244 - disconnect(signal, qobject, slot) - disconnect the signal of the given object from a slot of another QObject
244 - disconnect(signal, qobject, slot) - disconnect the signal of the given object from a slot of another QObject
245 - children() - returns the children of the object
245 - children() - returns the children of the object
246 - setParent(QObject) - set the parent
246 - setParent(QObject) - set the parent
247 - QObject* parent() - get the parent
247 - QObject* parent() - get the parent
248
248
249 The below example shows how to connect signals in Python:
249 The below example shows how to connect signals in Python:
250
250
251 \code
251 \code
252 # define a signal handler function
252 # define a signal handler function
253 def someFunction(flag):
253 def someFunction(flag):
254 print flag
254 print flag
255
255
256 # button1 is a QPushButton that has been added to Python via addObject()
256 # button1 is a QPushButton that has been added to Python via addObject()
257 # connect the clicked signal to a python function:
257 # connect the clicked signal to a python function:
258 button1.connect("clicked(bool)", someFunction)
258 button1.connect("clicked(bool)", someFunction)
259
259
260 \endcode
260 \endcode
261
261
262 \section CPP CPP Wrapping
262 \section CPP CPP Wrapping
263
263
264 You can create dedicated wrapper QObjects for any C++ class. This is done by deriving from PythonQtCppWrapperFactory
264 You can create dedicated wrapper QObjects for any C++ class. This is done by deriving from PythonQtCppWrapperFactory
265 and adding your factory via addWrapperFactory().
265 and adding your factory via addWrapperFactory().
266 Whenever PythonQt encounters a CPP pointer (e.g. on a slot or signal)
266 Whenever PythonQt encounters a CPP pointer (e.g. on a slot or signal)
267 and it does not known it as a QObject derived class, it will create a generic CPP wrapper. So even unknown C++ objects
267 and it does not known it as a QObject derived class, it will create a generic CPP wrapper. So even unknown C++ objects
268 can be passed through Python. If the wrapper factory supports the CPP class, a QObject wrapper will be created for each
268 can be passed through Python. If the wrapper factory supports the CPP class, a QObject wrapper will be created for each
269 instance that enters Python. An alternative to a complete wrapper via the wrapper factory are decorators, see \ref Decorators
269 instance that enters Python. An alternative to a complete wrapper via the wrapper factory are decorators, see \ref Decorators
270
270
271 \section MetaObject Meta Object/Class access
271 \section MetaObject Meta Object/Class access
272
272
273 For each known C++ class, PythonQt provides a Python class. These classes are visible
273 For each known C++ class, PythonQt provides a Python class. These classes are visible
274 inside of the "PythonQt" python module or in subpackages if a package is given when the class is registered.
274 inside of the "PythonQt" python module or in subpackages if a package is given when the class is registered.
275
275
276 A Meta class supports:
276 A Meta class supports:
277
277
278 - access to all declared enum values
278 - access to all declared enum values
279 - constructors
279 - constructors
280 - static methods
280 - static methods
281 - unbound non-static methods
281 - unbound non-static methods
282 - help() and className()
282 - help() and className()
283
283
284 From within Python, you can import the module "PythonQt" to access these classes and the Qt namespace.
284 From within Python, you can import the module "PythonQt" to access these classes and the Qt namespace.
285
285
286 \code
286 \code
287 from PythonQt import QtCore
287 from PythonQt import QtCore
288
288
289 # namespace access:
289 # namespace access:
290 print QtCore.Qt.AlignLeft
290 print QtCore.Qt.AlignLeft
291
291
292 # constructors
292 # constructors
293 a = QtCore.QSize(12,13)
293 a = QtCore.QSize(12,13)
294 b = QtCore.QFont()
294 b = QtCore.QFont()
295
295
296 # static method
296 # static method
297 QtCore.QDate.currentDate()
297 QtCore.QDate.currentDate()
298
298
299 # enum value
299 # enum value
300 QtCore.QFont.UltraCondensed
300 QtCore.QFont.UltraCondensed
301
301
302 \endcode
302 \endcode
303
303
304 \section Decorators Decorator slots
304 \section Decorators Decorator slots
305
305
306 PythonQt introduces a new generic approach to extend any wrapped QObject or CPP object with
306 PythonQt introduces a new generic approach to extend any wrapped QObject or CPP object with
307
307
308 - constructors
308 - constructors
309 - destructors (for CPP objects)
309 - destructors (for CPP objects)
310 - additional slots
310 - additional slots
311 - static slots (callable on both the Meta object and the instances)
311 - static slots (callable on both the Meta object and the instances)
312
312
313 The idea behind decorators is that we wanted to make it as easy as possible to extend
313 The idea behind decorators is that we wanted to make it as easy as possible to extend
314 wrapped objects. Since we already have an implementation for invoking any Qt Slot from
314 wrapped objects. Since we already have an implementation for invoking any Qt Slot from
315 Python, it looked promising to use this approach for the extension of wrapped objects as well.
315 Python, it looked promising to use this approach for the extension of wrapped objects as well.
316 This avoids that the PythonQt user needs to care about how Python arguments are mapped from/to
316 This avoids that the PythonQt user needs to care about how Python arguments are mapped from/to
317 Qt when he wants to create static methods, constructors and additional member functions.
317 Qt when he wants to create static methods, constructors and additional member functions.
318
318
319 The basic idea about decorators is to create a QObject derived class that implements slots
319 The basic idea about decorators is to create a QObject derived class that implements slots
320 which take one of the above roles (e.g. constructor, destructor etc.) via a naming convention.
320 which take one of the above roles (e.g. constructor, destructor etc.) via a naming convention.
321 These slots are then assigned to other classes via the naming convention.
321 These slots are then assigned to other classes via the naming convention.
322
322
323 - 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)
323 - 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)
324 - void delete_SomeClassName(SomeClassName* o) - defines a destructor, which should delete the passed in object o
324 - void delete_SomeClassName(SomeClassName* o) - defines a destructor, which should delete the passed in object o
325 - anything static_SomeClassName_someMethodName(...) - defines a static method that is callable on instances and the meta class
325 - anything static_SomeClassName_someMethodName(...) - defines a static method that is callable on instances and the meta class
326 - 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.
326 - 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.
327
327
328 The below example shows all kinds of decorators in action:
328 The below example shows all kinds of decorators in action:
329
329
330 \code
330 \code
331
331
332 // an example CPP object
332 // an example CPP object
333 class YourCPPObject {
333 class YourCPPObject {
334 public:
334 public:
335 YourCPPObject(int arg1, float arg2) { a = arg1; b = arg2; }
335 YourCPPObject(int arg1, float arg2) { a = arg1; b = arg2; }
336
336
337 float doSomething(int arg1) { return arg1*a*b; };
337 float doSomething(int arg1) { return arg1*a*b; };
338
338
339 private:
339 private:
340
340
341 int a;
341 int a;
342 float b;
342 float b;
343 };
343 };
344
344
345 // an example decorator
345 // an example decorator
346 class ExampleDecorator : public QObject
346 class ExampleDecorator : public QObject
347 {
347 {
348 Q_OBJECT
348 Q_OBJECT
349
349
350 public slots:
350 public slots:
351 // add a constructor to QSize that takes a QPoint
351 // add a constructor to QSize that takes a QPoint
352 QSize* new_QSize(const QPoint& p) { return new QSize(p.x(), p.y()); }
352 QSize* new_QSize(const QPoint& p) { return new QSize(p.x(), p.y()); }
353
353
354 // add a constructor for QPushButton that takes a text and a parent widget
354 // add a constructor for QPushButton that takes a text and a parent widget
355 QPushButton* new_QPushButton(const QString& text, QWidget* parent=NULL) { return new QPushButton(text, parent); }
355 QPushButton* new_QPushButton(const QString& text, QWidget* parent=NULL) { return new QPushButton(text, parent); }
356
356
357 // add a constructor for a CPP object
357 // add a constructor for a CPP object
358 YourCPPObject* new_YourCPPObject(int arg1, float arg2) { return new YourCPPObject(arg1, arg2); }
358 YourCPPObject* new_YourCPPObject(int arg1, float arg2) { return new YourCPPObject(arg1, arg2); }
359
359
360 // add a destructor for a CPP object
360 // add a destructor for a CPP object
361 void delete_YourCPPObject(YourCPPObject* obj) { delete obj; }
361 void delete_YourCPPObject(YourCPPObject* obj) { delete obj; }
362
362
363 // add a static method to QWidget
363 // add a static method to QWidget
364 QWidget* static_QWidget_mouseGrabber() { return QWidget::mouseGrabber(); }
364 QWidget* static_QWidget_mouseGrabber() { return QWidget::mouseGrabber(); }
365
365
366 // add an additional slot to QWidget (make move() callable, which is not declared as a slot in QWidget)
366 // add an additional slot to QWidget (make move() callable, which is not declared as a slot in QWidget)
367 void move(QWidget* w, const QPoint& p) { w->move(p); }
367 void move(QWidget* w, const QPoint& p) { w->move(p); }
368
368
369 // add an additional slot to QWidget, overloading the above move method
369 // add an additional slot to QWidget, overloading the above move method
370 void move(QWidget* w, int x, int y) { w->move(x,y); }
370 void move(QWidget* w, int x, int y) { w->move(x,y); }
371
371
372 // add a method to your own CPP object
372 // add a method to your own CPP object
373 int doSomething(YourCPPObject* obj, int arg1) { return obj->doSomething(arg1); }
373 int doSomething(YourCPPObject* obj, int arg1) { return obj->doSomething(arg1); }
374 };
374 };
375
375
376 ...
376 ...
377
377
378 PythonQt::self()->addDecorators(new ExampleDecorator());
378 PythonQt::self()->addDecorators(new ExampleDecorator());
379 PythonQt::self()->registerCPPClass("YourCPPObject");
379 PythonQt::self()->registerCPPClass("YourCPPObject");
380
380
381 \endcode
381 \endcode
382
382
383 After you have registered an instance of the above ExampleDecorator, you can do the following from Python
383 After you have registered an instance of the above ExampleDecorator, you can do the following from Python
384 (all these calls are mapped to the above decorator slots):
384 (all these calls are mapped to the above decorator slots):
385
385
386 \code
386 \code
387 from PythonQt import QtCore, QtGui, YourCPPObject
387 from PythonQt import QtCore, QtGui, YourCPPObject
388
388
389 # call our new constructor of QSize
389 # call our new constructor of QSize
390 size = QtCore.QSize(QPoint(1,2));
390 size = QtCore.QSize(QPoint(1,2));
391
391
392 # call our new QPushButton constructor
392 # call our new QPushButton constructor
393 button = QtGui.QPushButton("sometext");
393 button = QtGui.QPushButton("sometext");
394
394
395 # call the move slot (overload1)
395 # call the move slot (overload1)
396 button.move(QPoint(0,0))
396 button.move(QPoint(0,0))
397
397
398 # call the move slot (overload2)
398 # call the move slot (overload2)
399 button.move(0,0)
399 button.move(0,0)
400
400
401 # call the static method
401 # call the static method
402 grabber = QtGui.QWidget.mouseWrapper();
402 grabber = QtGui.QWidget.mouseWrapper();
403
403
404 # create a CPP object via constructor
404 # create a CPP object via constructor
405 yourCpp = YourCPPObject(1,11.5)
405 yourCpp = YourCPPObject(1,11.5)
406
406
407 # call the wrapped method on CPP object
407 # call the wrapped method on CPP object
408 print yourCpp.doSomething(1);
408 print yourCpp.doSomething(1);
409
409
410 # destructor will be called:
410 # destructor will be called:
411 yourCpp = None
411 yourCpp = None
412
412
413 \endcode
413 \endcode
414
414
415 \page Building Building
415 \page Building Building
416
416
417 PythonQt requires at least Qt 4.6.1 (for earlier Qt versions, you will need to run the pythonqt_gerenator, Qt 4.3 is the absolute minimum) and Python 2.5.x or 2.6.x on Windows, Linux and MacOS X. It has not yet been tested with Python 3.x, but it should only require minor changes.
417 PythonQt requires at least Qt 4.6.1 (for earlier Qt versions, you will need to run the pythonqt_gerenator, Qt 4.3 is the absolute minimum) and Python 2.5.x or 2.6.x on Windows, Linux and MacOS X. It has not yet been tested with Python 3.x, but it should only require minor changes.
418 To compile PythonQt, you will need a python developer installation which includes Python's header files and
418 To compile PythonQt, you will need a python developer installation which includes Python's header files and
419 the python2x.[lib | dll | so | dynlib].
419 the python2x.[lib | dll | so | dynlib].
420 The build scripts a currently set to use Python 2.6.
420 The build scripts a currently set to use Python 2.6.
421 You may need to tweak the \b build/python.prf file to set the correct Python includes and libs on your system.
421 You may need to tweak the \b build/python.prf file to set the correct Python includes and libs on your system.
422
422
423 \note In addition to the qmake profiles, PythonQt now offers building via Cmake. Just use the provided
423 \subsection Windows
424 CMakeLists.txt in the root directory of the project. This build option has not been well tested yet.
425
426 \section Windows
427
424
428 On Windows, the (non-source) Python Windows installer can be used.
425 On Windows, the (non-source) Python Windows installer can be used.
429 Make sure that you use the same compiler, the current Python distribution is built
426 Make sure that you use the same compiler, the current Python distribution is built
430 with Visual Studio 2003. If you want to use another compiler, you will need to build
427 with Visual Studio 2003. If you want to use another compiler, you will need to build
431 Python yourself, using your compiler.
428 Python yourself, using your compiler.
432
429
433 To build PythonQt, you need to set the environment variable \b PYTHON_PATH to point to the root
430 To build PythonQt, you need to set the environment variable \b PYTHON_PATH to point to the root
434 dir of the python installation and \b PYTHON_LIB to point to
431 dir of the python installation and \b PYTHON_LIB to point to
435 the directory where the python lib file is located.
432 the directory where the python lib file is located.
436
433
437 When using the prebuild Python installer, this will be:
434 When using the prebuild Python installer, this will be:
438
435
439 \code
436 \code
440 > set PYTHON_PATH = c:\Python26
437 > set PYTHON_PATH = c:\Python26
441 > set PYTHON_LIB = c:\Python26\libs
438 > set PYTHON_LIB = c:\Python26\libs
442 \endcode
439 \endcode
443
440
444 When using the python sources, this will be something like:
441 When using the python sources, this will be something like:
445
442
446 \code
443 \code
447 > set PYTHON_PATH = c:\yourDir\Python-2.6.1\
444 > set PYTHON_PATH = c:\yourDir\Python-2.6.1\
448 > set PYTHON_LIB = c:\yourDir\Python-2.6.1\PCbuild8\Win32
445 > set PYTHON_LIB = c:\yourDir\Python-2.6.1\PCbuild8\Win32
449 \endcode
446 \endcode
450
447
451 To build all, do the following (after setting the above variables):
448 To build all, do the following (after setting the above variables):
452
449
453 \code
450 \code
454 > cd PythonQtRoot
451 > cd PythonQtRoot
455 > vcvars32
452 > vcvars32
456 > qmake
453 > qmake
457 > nmake
454 > nmake
458 \endcode
455 \endcode
459
456
460 This should build everything. If Python can not be linked or include files can not be found,
457 This should build everything. If Python can not be linked or include files can not be found,
461 you probably need to tweak \b build/python.prf
458 you probably need to tweak \b build/python.prf
462
459
463 The tests and examples are located in PythonQt/lib.
460 The tests and examples are located in PythonQt/lib.
464
461
465 \section Linux
462 \subsection Linux
466
463
467 On Linux, you need to install a Python-dev package.
464 On Linux, you need to install a Python-dev package.
468 If Python can not be linked or include files can not be found,
465 If Python can not be linked or include files can not be found,
469 you probably need to tweak \b build/python.prf
466 you probably need to tweak \b build/python.prf
470
467
471 To build PythonQt, just do a:
468 To build PythonQt, just do a:
472
469
473 \code
470 \code
474 > cd PythonQtRoot
471 > cd PythonQtRoot
475 > qmake
472 > qmake
476 > make all
473 > make all
477 \endcode
474 \endcode
478
475
479 The tests and examples are located in PythonQt/lib.
476 The tests and examples are located in PythonQt/lib.
480 You should add PythonQt/lib to your LD_LIBRARY_PATH so that the runtime
477 You should add PythonQt/lib to your LD_LIBRARY_PATH so that the runtime
481 linker can find the *.so files.
478 linker can find the *.so files.
482
479
483 \section MacOSX
480 \subsection MacOsX
484
481
485 On Mac, Python is installed as a Framework, so you should not need to install it.
482 On Mac, Python is installed as a Framework, so you should not need to install it.
486 To build PythonQt, just do a:
483 To build PythonQt, just do a:
487
484
488 \code
485 \code
489 > cd PythonQtRoot
486 > cd PythonQtRoot
490 > qmake
487 > qmake
491 > make all
488 > make all
492 \endcode
489 \endcode
493
490
494 \section Tests
491 \section Tests
495
492
496 There is a unit test that tests most features of PythonQt, see the \b tests subdirectory for details.
493 There is a unit test that tests most features of PythonQt, see the \b tests subdirectory for details.
497
494
498 \page Examples Examples
495 \page Examples Examples
499
496
500 Examples are available in the \b examples directory. The PyScriptingConsole implements a simple
497 Examples are available in the \b examples directory. The PyScriptingConsole implements a simple
501 interactive scripting console that shows how to script a simple application. The PyLauncher application can be used to run arbitrary PythonQt scripts given on the commandline.
498 interactive scripting console that shows how to script a simple application. The PyLauncher application can be used to run arbitrary PythonQt scripts given on the commandline.
502
499
503 The following shows a simple example on how to integrate PythonQt into your Qt application:
500 The following shows a simple example on how to integrate PythonQt into your Qt application:
504
501
505 \code
502 \code
506 #include "PythonQt.h"
503 #include "PythonQt.h"
507 #include <QApplication>
504 #include <QApplication>
508 ...
505 ...
509
506
510 int main( int argc, char **argv )
507 int main( int argc, char **argv )
511 {
508 {
512
509
513 QApplication qapp(argc, argv);
510 QApplication qapp(argc, argv);
514
511
515 // init PythonQt and Python itself
512 // init PythonQt and Python itself
516 PythonQt::init();
513 PythonQt::init();
517
514
518 // get a smart pointer to the __main__ module of the Python interpreter
515 // get a smart pointer to the __main__ module of the Python interpreter
519 PythonQtObjectPtr context = PythonQt::self()->getMainModule();
516 PythonQtObjectPtr context = PythonQt::self()->getMainModule();
520
517
521 // add a QObject as variable of name "example" to the namespace of the __main__ module
518 // add a QObject as variable of name "example" to the namespace of the __main__ module
522 PyExampleObject example;
519 PyExampleObject example;
523 context.addObject("example", &example);
520 context.addObject("example", &example);
524
521
525 // do something
522 // do something
526 context.evalScript("print example");
523 context.evalScript("print example");
527 context.evalScript("def multiply(a,b):\n return a*b;\n");
524 context.evalScript("def multiply(a,b):\n return a*b;\n");
528 QVariantList args;
525 QVariantList args;
529 args << 42 << 47;
526 args << 42 << 47;
530 QVariant result = context.call("multiply", args);
527 QVariant result = context.call("multiply", args);
531 ...
528 ...
532 \endcode
529 \endcode
533
530
534
531
535 */
532 */
General Comments 0
You need to be logged in to leave comments. Login now