##// END OF EJS Templates
added error handling for virtual method overloads, added more global functions (qsrand etc.), added support for exec_ etc (python keyword overlap resolution), change virtual method handling, this will require code regeneration (I will do that tomorrow)...
florianlink -
r67:57d78f859ef3
parent child
Show More
@@ -1,1227 +1,1215
1 /*
1 /*
2 *
2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 *
4 *
5 * This library is free software; you can redistribute it and/or
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
8 * version 2.1 of the License, or (at your option) any later version.
9 *
9 *
10 * This library is distributed in the hope that it will be useful,
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
13 * Lesser General Public License for more details.
14 *
14 *
15 * Further, this software is distributed without any warranty that it is
15 * Further, this software is distributed without any warranty that it is
16 * free of the rightful claim of any third person regarding infringement
16 * free of the rightful claim of any third person regarding infringement
17 * or the like. Any license provided herein, whether implied or
17 * or the like. Any license provided herein, whether implied or
18 * otherwise, applies only to this software file. Patent licenses, if
18 * otherwise, applies only to this software file. Patent licenses, if
19 * any, provided herein do not apply to combinations of this program with
19 * any, provided herein do not apply to combinations of this program with
20 * other software, or any other product whatsoever.
20 * other software, or any other product whatsoever.
21 *
21 *
22 * You should have received a copy of the GNU Lesser General Public
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 * 28359 Bremen, Germany or:
27 * 28359 Bremen, Germany or:
28 *
28 *
29 * http://www.mevis.de
29 * http://www.mevis.de
30 *
30 *
31 */
31 */
32
32
33 //----------------------------------------------------------------------------------
33 //----------------------------------------------------------------------------------
34 /*!
34 /*!
35 // \file PythonQt.cpp
35 // \file PythonQt.cpp
36 // \author Florian Link
36 // \author Florian Link
37 // \author Last changed by $Author: florian $
37 // \author Last changed by $Author: florian $
38 // \date 2006-05
38 // \date 2006-05
39 */
39 */
40 //----------------------------------------------------------------------------------
40 //----------------------------------------------------------------------------------
41
41
42 #include "PythonQt.h"
42 #include "PythonQt.h"
43 #include "PythonQtImporter.h"
43 #include "PythonQtImporter.h"
44 #include "PythonQtClassInfo.h"
44 #include "PythonQtClassInfo.h"
45 #include "PythonQtMethodInfo.h"
45 #include "PythonQtMethodInfo.h"
46 #include "PythonQtSignalReceiver.h"
46 #include "PythonQtSignalReceiver.h"
47 #include "PythonQtConversion.h"
47 #include "PythonQtConversion.h"
48 #include "PythonQtStdOut.h"
48 #include "PythonQtStdOut.h"
49 #include "PythonQtCppWrapperFactory.h"
49 #include "PythonQtCppWrapperFactory.h"
50 #include "PythonQtVariants.h"
50 #include "PythonQtVariants.h"
51 #include "PythonQtStdDecorators.h"
51 #include "PythonQtStdDecorators.h"
52 #include "PythonQtQFileImporter.h"
52 #include "PythonQtQFileImporter.h"
53 #include <pydebug.h>
53 #include <pydebug.h>
54 #include <vector>
54 #include <vector>
55
55
56 PythonQt* PythonQt::_self = NULL;
56 PythonQt* PythonQt::_self = NULL;
57 int PythonQt::_uniqueModuleCount = 0;
57 int PythonQt::_uniqueModuleCount = 0;
58
58
59 void PythonQt::init(int flags)
59 void PythonQt::init(int flags)
60 {
60 {
61 if (!_self) {
61 if (!_self) {
62 _self = new PythonQt(flags);
62 _self = new PythonQt(flags);
63 }
63 }
64
64
65 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
65 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
66 qRegisterMetaType<QList<QObject*> >("QList<void*>");
66 qRegisterMetaType<QList<QObject*> >("QList<void*>");
67
67
68 PythonQtRegisterToolClassesTemplateConverter(int);
68 PythonQtRegisterToolClassesTemplateConverter(int);
69 PythonQtRegisterToolClassesTemplateConverter(float);
69 PythonQtRegisterToolClassesTemplateConverter(float);
70 PythonQtRegisterToolClassesTemplateConverter(double);
70 PythonQtRegisterToolClassesTemplateConverter(double);
71 // TODO: which other POD types should be available for QList etc.
71 // TODO: which other POD types should be available for QList etc.
72
72
73 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
73 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
74
74
75 PythonQt::self()->registerCPPClass("Qt", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_Qt>);
75 PythonQt::self()->registerCPPClass("Qt", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_Qt>);
76 PythonQt::self()->registerCPPClass("QBitArray", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QBitArray>);
76 PythonQt::self()->registerCPPClass("QBitArray", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QBitArray>);
77 PythonQt::self()->registerCPPClass("QDate", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QDate>);
77 PythonQt::self()->registerCPPClass("QDate", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QDate>);
78 PythonQt::self()->registerCPPClass("QTime", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QTime>);
78 PythonQt::self()->registerCPPClass("QTime", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QTime>);
79 PythonQt::self()->registerCPPClass("QDateTime", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QDateTime>);
79 PythonQt::self()->registerCPPClass("QDateTime", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QDateTime>);
80 PythonQt::self()->registerCPPClass("QUrl", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QUrl>);
80 PythonQt::self()->registerCPPClass("QUrl", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QUrl>);
81 PythonQt::self()->registerCPPClass("QLocale", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLocale>);
81 PythonQt::self()->registerCPPClass("QLocale", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLocale>);
82 PythonQt::self()->registerCPPClass("QRect", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRect>);
82 PythonQt::self()->registerCPPClass("QRect", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRect>);
83 PythonQt::self()->registerCPPClass("QRectF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRectF>);
83 PythonQt::self()->registerCPPClass("QRectF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRectF>);
84 PythonQt::self()->registerCPPClass("QSize", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QSize>);
84 PythonQt::self()->registerCPPClass("QSize", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QSize>);
85 PythonQt::self()->registerCPPClass("QSizeF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QSizeF>);
85 PythonQt::self()->registerCPPClass("QSizeF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QSizeF>);
86 PythonQt::self()->registerCPPClass("QLine", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLine>);
86 PythonQt::self()->registerCPPClass("QLine", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLine>);
87 PythonQt::self()->registerCPPClass("QLineF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLineF>);
87 PythonQt::self()->registerCPPClass("QLineF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLineF>);
88 PythonQt::self()->registerCPPClass("QPoint", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QPoint>);
88 PythonQt::self()->registerCPPClass("QPoint", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QPoint>);
89 PythonQt::self()->registerCPPClass("QPointF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QPointF>);
89 PythonQt::self()->registerCPPClass("QPointF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QPointF>);
90 PythonQt::self()->registerCPPClass("QRegExp", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRegExp>);
90 PythonQt::self()->registerCPPClass("QRegExp", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRegExp>);
91
91
92 PythonQtRegisterToolClassesTemplateConverter(QDate);
92 PythonQtRegisterToolClassesTemplateConverter(QDate);
93 PythonQtRegisterToolClassesTemplateConverter(QTime);
93 PythonQtRegisterToolClassesTemplateConverter(QTime);
94 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
94 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
95 PythonQtRegisterToolClassesTemplateConverter(QUrl);
95 PythonQtRegisterToolClassesTemplateConverter(QUrl);
96 PythonQtRegisterToolClassesTemplateConverter(QLocale);
96 PythonQtRegisterToolClassesTemplateConverter(QLocale);
97 PythonQtRegisterToolClassesTemplateConverter(QRect);
97 PythonQtRegisterToolClassesTemplateConverter(QRect);
98 PythonQtRegisterToolClassesTemplateConverter(QRectF);
98 PythonQtRegisterToolClassesTemplateConverter(QRectF);
99 PythonQtRegisterToolClassesTemplateConverter(QSize);
99 PythonQtRegisterToolClassesTemplateConverter(QSize);
100 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
100 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
101 PythonQtRegisterToolClassesTemplateConverter(QLine);
101 PythonQtRegisterToolClassesTemplateConverter(QLine);
102 PythonQtRegisterToolClassesTemplateConverter(QLineF);
102 PythonQtRegisterToolClassesTemplateConverter(QLineF);
103 PythonQtRegisterToolClassesTemplateConverter(QPoint);
103 PythonQtRegisterToolClassesTemplateConverter(QPoint);
104 PythonQtRegisterToolClassesTemplateConverter(QPointF);
104 PythonQtRegisterToolClassesTemplateConverter(QPointF);
105 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
105 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
106
106
107 PythonQt::self()->registerCPPClass("QFont", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QFont>);
107 PythonQt::self()->registerCPPClass("QFont", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QFont>);
108 PythonQt::self()->registerCPPClass("QPixmap", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPixmap>);
108 PythonQt::self()->registerCPPClass("QPixmap", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPixmap>);
109 PythonQt::self()->registerCPPClass("QBrush", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QBrush>);
109 PythonQt::self()->registerCPPClass("QBrush", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QBrush>);
110 PythonQt::self()->registerCPPClass("QColor", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QColor>);
110 PythonQt::self()->registerCPPClass("QColor", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QColor>);
111 PythonQt::self()->registerCPPClass("QPalette", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPalette>);
111 PythonQt::self()->registerCPPClass("QPalette", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPalette>);
112 PythonQt::self()->registerCPPClass("QIcon", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QIcon>);
112 PythonQt::self()->registerCPPClass("QIcon", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QIcon>);
113 PythonQt::self()->registerCPPClass("QImage", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QImage>);
113 PythonQt::self()->registerCPPClass("QImage", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QImage>);
114 PythonQt::self()->registerCPPClass("QPolygon", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPolygon>);
114 PythonQt::self()->registerCPPClass("QPolygon", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPolygon>);
115 PythonQt::self()->registerCPPClass("QRegion", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QRegion>);
115 PythonQt::self()->registerCPPClass("QRegion", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QRegion>);
116 PythonQt::self()->registerCPPClass("QBitmap", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QBitmap>);
116 PythonQt::self()->registerCPPClass("QBitmap", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QBitmap>);
117 PythonQt::self()->registerCPPClass("QCursor", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QCursor>);
117 PythonQt::self()->registerCPPClass("QCursor", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QCursor>);
118 PythonQt::self()->registerCPPClass("QSizePolicy", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QSizePolicy>);
118 PythonQt::self()->registerCPPClass("QSizePolicy", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QSizePolicy>);
119 PythonQt::self()->registerCPPClass("QKeySequence", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QKeySequence>);
119 PythonQt::self()->registerCPPClass("QKeySequence", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QKeySequence>);
120 PythonQt::self()->registerCPPClass("QPen", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPen>);
120 PythonQt::self()->registerCPPClass("QPen", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPen>);
121 PythonQt::self()->registerCPPClass("QTextLength", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QTextLength>);
121 PythonQt::self()->registerCPPClass("QTextLength", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QTextLength>);
122 PythonQt::self()->registerCPPClass("QTextFormat", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QTextFormat>);
122 PythonQt::self()->registerCPPClass("QTextFormat", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QTextFormat>);
123 PythonQt::self()->registerCPPClass("QMatrix", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QMatrix>);
123 PythonQt::self()->registerCPPClass("QMatrix", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QMatrix>);
124
124
125 PythonQtRegisterToolClassesTemplateConverter(QFont);
125 PythonQtRegisterToolClassesTemplateConverter(QFont);
126 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
126 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
127 PythonQtRegisterToolClassesTemplateConverter(QBrush);
127 PythonQtRegisterToolClassesTemplateConverter(QBrush);
128 PythonQtRegisterToolClassesTemplateConverter(QColor);
128 PythonQtRegisterToolClassesTemplateConverter(QColor);
129 PythonQtRegisterToolClassesTemplateConverter(QPalette);
129 PythonQtRegisterToolClassesTemplateConverter(QPalette);
130 PythonQtRegisterToolClassesTemplateConverter(QIcon);
130 PythonQtRegisterToolClassesTemplateConverter(QIcon);
131 PythonQtRegisterToolClassesTemplateConverter(QImage);
131 PythonQtRegisterToolClassesTemplateConverter(QImage);
132 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
132 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
133 PythonQtRegisterToolClassesTemplateConverter(QRegion);
133 PythonQtRegisterToolClassesTemplateConverter(QRegion);
134 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
134 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
135 PythonQtRegisterToolClassesTemplateConverter(QCursor);
135 PythonQtRegisterToolClassesTemplateConverter(QCursor);
136 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
136 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
137 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
137 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
138 PythonQtRegisterToolClassesTemplateConverter(QPen);
138 PythonQtRegisterToolClassesTemplateConverter(QPen);
139 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
139 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
140 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
140 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
141 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
141 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
142
142
143
144 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
145 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
146 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
147 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
148 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
149 for (unsigned int i = 0;i<16; i++) {
150 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
151 if (obj) {
152 PyModule_AddObject(pack, names[i], obj);
153 Py_INCREF(obj);
154 PyModule_AddObject(pack2, names[i], obj);
155 } else {
156 std::cerr << "method not found " << names[i];
157 }
158 }
143 }
159 }
144
160
145 void PythonQt::cleanup()
161 void PythonQt::cleanup()
146 {
162 {
147 if (_self) {
163 if (_self) {
148 delete _self;
164 delete _self;
149 _self = NULL;
165 _self = NULL;
150 }
166 }
151 }
167 }
152
168
153 PythonQt::PythonQt(int flags)
169 PythonQt::PythonQt(int flags)
154 {
170 {
155 _p = new PythonQtPrivate;
171 _p = new PythonQtPrivate;
156 _p->_initFlags = flags;
172 _p->_initFlags = flags;
157
173
158 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
174 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
159
175
160 Py_SetProgramName("PythonQt");
176 Py_SetProgramName("PythonQt");
161 if (flags & IgnoreSiteModule) {
177 if (flags & IgnoreSiteModule) {
162 // this prevents the automatic importing of Python site files
178 // this prevents the automatic importing of Python site files
163 Py_NoSiteFlag = 1;
179 Py_NoSiteFlag = 1;
164 }
180 }
165 Py_Initialize();
181 Py_Initialize();
166
182
167 // add our own python object types for qt object slots
183 // add our own python object types for qt object slots
168 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
184 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
169 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
185 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
170 }
186 }
171 Py_INCREF(&PythonQtSlotFunction_Type);
187 Py_INCREF(&PythonQtSlotFunction_Type);
172
188
173 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
189 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
174 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
190 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
175 // add our own python object types for classes
191 // add our own python object types for classes
176 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
192 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
177 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
193 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
178 }
194 }
179 Py_INCREF(&PythonQtClassWrapper_Type);
195 Py_INCREF(&PythonQtClassWrapper_Type);
180
196
181 // add our own python object types for CPP instances
197 // add our own python object types for CPP instances
182 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
198 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
183 PythonQt::handleError();
199 PythonQt::handleError();
184 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
200 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
185 }
201 }
186 Py_INCREF(&PythonQtInstanceWrapper_Type);
202 Py_INCREF(&PythonQtInstanceWrapper_Type);
187
203
188 // add our own python object types for redirection of stdout
204 // add our own python object types for redirection of stdout
189 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
205 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
190 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
206 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
191 }
207 }
192 Py_INCREF(&PythonQtStdOutRedirectType);
208 Py_INCREF(&PythonQtStdOutRedirectType);
193
209
194 initPythonQtModule(flags & RedirectStdOut);
210 initPythonQtModule(flags & RedirectStdOut);
195
211
196 }
212 }
197
213
198 PythonQt::~PythonQt() {
214 PythonQt::~PythonQt() {
199 delete _p;
215 delete _p;
200 _p = NULL;
216 _p = NULL;
201 }
217 }
202
218
203 PythonQtPrivate::~PythonQtPrivate() {
219 PythonQtPrivate::~PythonQtPrivate() {
204 delete _defaultImporter;
220 delete _defaultImporter;
205 _defaultImporter = NULL;
221 _defaultImporter = NULL;
206
222
207 {
223 {
208 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
224 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
209 while (i.hasNext()) {
225 while (i.hasNext()) {
210 delete i.next().value();
226 delete i.next().value();
211 }
227 }
212 }
228 }
213 PythonQtConv::global_valueStorage.clear();
229 PythonQtConv::global_valueStorage.clear();
214 PythonQtConv::global_ptrStorage.clear();
230 PythonQtConv::global_ptrStorage.clear();
215 PythonQtConv::global_variantStorage.clear();
231 PythonQtConv::global_variantStorage.clear();
216
232
217 PythonQtMethodInfo::cleanupCachedMethodInfos();
233 PythonQtMethodInfo::cleanupCachedMethodInfos();
218 }
234 }
219
235
220 PythonQtImportFileInterface* PythonQt::importInterface()
236 PythonQtImportFileInterface* PythonQt::importInterface()
221 {
237 {
222 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
238 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
223 }
239 }
224
240
225 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
241 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
226 {
242 {
227 if (_self->_p->_noLongerWrappedCB) {
243 if (_self->_p->_noLongerWrappedCB) {
228 (*_self->_p->_noLongerWrappedCB)(o);
244 (*_self->_p->_noLongerWrappedCB)(o);
229 };
245 };
230 }
246 }
231
247
232 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
248 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
233 {
249 {
234 _p->registerClass(metaobject, package, wrapperCreator, shell);
250 _p->registerClass(metaobject, package, wrapperCreator, shell);
235 }
251 }
236
252
237 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
253 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
238 {
254 {
239 // we register all classes in the hierarchy
255 // we register all classes in the hierarchy
240 const QMetaObject* m = metaobject;
256 const QMetaObject* m = metaobject;
241 bool first = true;
257 bool first = true;
242 while (m) {
258 while (m) {
243 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
259 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
244 if (!info->pythonQtClassWrapper()) {
260 if (!info->pythonQtClassWrapper()) {
245 info->setupQObject(m);
261 info->setupQObject(m);
246 createPythonQtClassWrapper(info, package);
262 createPythonQtClassWrapper(info, package);
247 if (m->superClass()) {
263 if (m->superClass()) {
248 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
264 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
249 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
265 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
250 }
266 }
251 }
267 }
252 if (first) {
268 if (first) {
253 first = false;
269 first = false;
254 if (wrapperCreator) {
270 if (wrapperCreator) {
255 info->setDecoratorProvider(wrapperCreator);
271 info->setDecoratorProvider(wrapperCreator);
256 }
272 }
257 if (shell) {
273 if (shell) {
258 info->setShellSetInstanceWrapperCB(shell);
274 info->setShellSetInstanceWrapperCB(shell);
259 }
275 }
260 }
276 }
261 m = m->superClass();
277 m = m->superClass();
262 }
278 }
263 }
279 }
264
280
265 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package)
281 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package)
266 {
282 {
267 PyObject* pack = packageByName(package);
283 PyObject* pack = packageByName(package);
268 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, package);
284 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, package);
269 PyModule_AddObject(pack, info->className(), pyobj);
285 PyModule_AddObject(pack, info->className(), pyobj);
270 if (package && strncmp(package,"Qt",2)==0) {
286 if (package && strncmp(package,"Qt",2)==0) {
271 // since PyModule_AddObject steals the reference, we need a incref once more...
287 // since PyModule_AddObject steals the reference, we need a incref once more...
272 Py_INCREF(pyobj);
288 Py_INCREF(pyobj);
273 // put all qt objects into Qt as well
289 // put all qt objects into Qt as well
274 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
290 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
275 }
291 }
276 info->setPythonQtClassWrapper(pyobj);
292 info->setPythonQtClassWrapper(pyobj);
277 }
293 }
278
294
279 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
295 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
280 {
296 {
281 if (!obj) {
297 if (!obj) {
282 Py_INCREF(Py_None);
298 Py_INCREF(Py_None);
283 return Py_None;
299 return Py_None;
284 }
300 }
285 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
301 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
286 if (!wrap) {
302 if (!wrap) {
287 // smuggling it in...
303 // smuggling it in...
288 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
304 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
289 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
305 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
290 registerClass(obj->metaObject());
306 registerClass(obj->metaObject());
291 classInfo = _knownClassInfos.value(obj->metaObject()->className());
307 classInfo = _knownClassInfos.value(obj->metaObject()->className());
292 }
308 }
293 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
309 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
294 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
310 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
295 } else {
311 } else {
296 Py_INCREF(wrap);
312 Py_INCREF(wrap);
297 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
313 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
298 }
314 }
299 return (PyObject*)wrap;
315 return (PyObject*)wrap;
300 }
316 }
301
317
302 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
318 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
303 {
319 {
304 if (!ptr) {
320 if (!ptr) {
305 Py_INCREF(Py_None);
321 Py_INCREF(Py_None);
306 return Py_None;
322 return Py_None;
307 }
323 }
308
324
309 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
325 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
310 if (!wrap) {
326 if (!wrap) {
311 PythonQtClassInfo* info = _knownClassInfos.value(name);
327 PythonQtClassInfo* info = _knownClassInfos.value(name);
312 if (!info) {
328 if (!info) {
313 // maybe it is a PyObject, which we can return directly
329 // maybe it is a PyObject, which we can return directly
314 if (name == "PyObject") {
330 if (name == "PyObject") {
315 PyObject* p = (PyObject*)ptr;
331 PyObject* p = (PyObject*)ptr;
316 Py_INCREF(p);
332 Py_INCREF(p);
317 return p;
333 return p;
318 }
334 }
319
335
320 // we do not know the metaobject yet, but we might know it by it's name:
336 // we do not know the metaobject yet, but we might know it by it's name:
321 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
337 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
322 // yes, we know it, so we can convert to QObject
338 // yes, we know it, so we can convert to QObject
323 QObject* qptr = (QObject*)ptr;
339 QObject* qptr = (QObject*)ptr;
324 registerClass(qptr->metaObject());
340 registerClass(qptr->metaObject());
325 info = _knownClassInfos.value(qptr->metaObject()->className());
341 info = _knownClassInfos.value(qptr->metaObject()->className());
326 }
342 }
327 }
343 }
328 if (info && info->isQObject()) {
344 if (info && info->isQObject()) {
329 QObject* qptr = (QObject*)ptr;
345 QObject* qptr = (QObject*)ptr;
330 // if the object is a derived object, we want to switch the class info to the one of the derived class:
346 // if the object is a derived object, we want to switch the class info to the one of the derived class:
331 if (name!=(qptr->metaObject()->className())) {
347 if (name!=(qptr->metaObject()->className())) {
332 registerClass(qptr->metaObject());
348 registerClass(qptr->metaObject());
333 info = _knownClassInfos.value(qptr->metaObject()->className());
349 info = _knownClassInfos.value(qptr->metaObject()->className());
334 }
350 }
335 wrap = createNewPythonQtInstanceWrapper(qptr, info);
351 wrap = createNewPythonQtInstanceWrapper(qptr, info);
336 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
352 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
337 return (PyObject*)wrap;
353 return (PyObject*)wrap;
338 }
354 }
339
355
340 // not a known QObject, so try our wrapper factory:
356 // not a known QObject, so try our wrapper factory:
341 QObject* wrapper = NULL;
357 QObject* wrapper = NULL;
342 for (int i=0; i<_cppWrapperFactories.size(); i++) {
358 for (int i=0; i<_cppWrapperFactories.size(); i++) {
343 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
359 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
344 if (wrapper) {
360 if (wrapper) {
345 break;
361 break;
346 }
362 }
347 }
363 }
348
364
349 if (info) {
365 if (info) {
350 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
366 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
351 ptr = info->castDownIfPossible(ptr, &info);
367 ptr = info->castDownIfPossible(ptr, &info);
352 }
368 }
353
369
354 if (!info || info->pythonQtClassWrapper()==NULL) {
370 if (!info || info->pythonQtClassWrapper()==NULL) {
355 // still unknown, register as CPP class
371 // still unknown, register as CPP class
356 registerCPPClass(name.constData());
372 registerCPPClass(name.constData());
357 info = _knownClassInfos.value(name);
373 info = _knownClassInfos.value(name);
358 }
374 }
359 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
375 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
360 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
376 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
361 info->setMetaObject(wrapper->metaObject());
377 info->setMetaObject(wrapper->metaObject());
362 }
378 }
363 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
379 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
364 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
380 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
365 } else {
381 } else {
366 Py_INCREF(wrap);
382 Py_INCREF(wrap);
367 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
383 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
368 }
384 }
369 return (PyObject*)wrap;
385 return (PyObject*)wrap;
370 }
386 }
371
387
372 PyObject* PythonQtPrivate::dummyTuple() {
388 PyObject* PythonQtPrivate::dummyTuple() {
373 static PyObject* dummyTuple = NULL;
389 static PyObject* dummyTuple = NULL;
374 if (dummyTuple==NULL) {
390 if (dummyTuple==NULL) {
375 dummyTuple = PyTuple_New(1);
391 dummyTuple = PyTuple_New(1);
376 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
392 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
377 }
393 }
378 return dummyTuple;
394 return dummyTuple;
379 }
395 }
380
396
381
397
382 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
398 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
383 // call the associated class type to create a new instance...
399 // call the associated class type to create a new instance...
384 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
400 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
385
401
386 result->setQObject(obj);
402 result->setQObject(obj);
387 result->_wrappedPtr = wrappedPtr;
403 result->_wrappedPtr = wrappedPtr;
388 result->_ownedByPythonQt = false;
404 result->_ownedByPythonQt = false;
389 result->_useQMetaTypeDestroy = false;
405 result->_useQMetaTypeDestroy = false;
390
406
391 if (wrappedPtr) {
407 if (wrappedPtr) {
392 _wrappedObjects.insert(wrappedPtr, result);
408 _wrappedObjects.insert(wrappedPtr, result);
393 } else {
409 } else {
394 _wrappedObjects.insert(obj, result);
410 _wrappedObjects.insert(obj, result);
395 if (obj->parent()== NULL && _wrappedCB) {
411 if (obj->parent()== NULL && _wrappedCB) {
396 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
412 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
397 (*_wrappedCB)(obj);
413 (*_wrappedCB)(obj);
398 }
414 }
399 }
415 }
400 return result;
416 return result;
401 }
417 }
402
418
403 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package) {
419 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package) {
404 PythonQtClassWrapper* result;
420 PythonQtClassWrapper* result;
405
421
406 PyObject* className = PyString_FromString(info->className());
422 PyObject* className = PyString_FromString(info->className());
407
423
408 PyObject* baseClasses = PyTuple_New(1);
424 PyObject* baseClasses = PyTuple_New(1);
409 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
425 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
410
426
411 PyObject* typeDict = PyDict_New();
427 PyObject* typeDict = PyDict_New();
412 QByteArray moduleName("PythonQt");
428 QByteArray moduleName("PythonQt");
413 if (package && strcmp(package, "")!=0) {
429 if (package && strcmp(package, "")!=0) {
414 moduleName += ".";
430 moduleName += ".";
415 moduleName += package;
431 moduleName += package;
416 }
432 }
417 PyDict_SetItemString(typeDict, "__module__", PyString_FromString(moduleName.constData()));
433 PyDict_SetItemString(typeDict, "__module__", PyString_FromString(moduleName.constData()));
418
434
419 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
435 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
420
436
421 // set the class info so that PythonQtClassWrapper_new can read it
437 // set the class info so that PythonQtClassWrapper_new can read it
422 _currentClassInfoForClassWrapperCreation = info;
438 _currentClassInfoForClassWrapperCreation = info;
423 // create the new type object by calling the type
439 // create the new type object by calling the type
424 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
440 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
425
441
426 Py_DECREF(baseClasses);
442 Py_DECREF(baseClasses);
427 Py_DECREF(typeDict);
443 Py_DECREF(typeDict);
428 Py_DECREF(args);
444 Py_DECREF(args);
429 Py_DECREF(className);
445 Py_DECREF(className);
430
446
431 return result;
447 return result;
432 }
448 }
433
449
434 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
450 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
435 {
451 {
436 PyObject* args = Py_BuildValue("(i)", enumValue);
452 PyObject* args = Py_BuildValue("(i)", enumValue);
437 PyObject* result = PyObject_Call(enumType, args, NULL);
453 PyObject* result = PyObject_Call(enumType, args, NULL);
438 Py_DECREF(args);
454 Py_DECREF(args);
439 return result;
455 return result;
440 }
456 }
441
457
442 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
458 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
443 PyObject* result;
459 PyObject* result;
444
460
445 PyObject* className = PyString_FromString(enumName);
461 PyObject* className = PyString_FromString(enumName);
446
462
447 PyObject* baseClasses = PyTuple_New(1);
463 PyObject* baseClasses = PyTuple_New(1);
448 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
464 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
449
465
450 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
466 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
451 PyObject* typeDict = PyDict_New();
467 PyObject* typeDict = PyDict_New();
452 PyDict_SetItemString(typeDict, "__module__", module);
468 PyDict_SetItemString(typeDict, "__module__", module);
453
469
454 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
470 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
455
471
456 // create the new int derived type object by calling the core type
472 // create the new int derived type object by calling the core type
457 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
473 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
458
474
459 Py_DECREF(baseClasses);
475 Py_DECREF(baseClasses);
460 Py_DECREF(typeDict);
476 Py_DECREF(typeDict);
461 Py_DECREF(args);
477 Py_DECREF(args);
462 Py_DECREF(className);
478 Py_DECREF(className);
463
479
464 return result;
480 return result;
465 }
481 }
466
482
467 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
483 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
468 {
484 {
469 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
485 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
470 if (!r) {
486 if (!r) {
471 r = new PythonQtSignalReceiver(obj);
487 r = new PythonQtSignalReceiver(obj);
472 _p->_signalReceivers.insert(obj, r);
488 _p->_signalReceivers.insert(obj, r);
473 }
489 }
474 return r;
490 return r;
475 }
491 }
476
492
477 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
493 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
478 {
494 {
479 bool flag = false;
495 bool flag = false;
480 PythonQtObjectPtr callable = lookupCallable(module, objectname);
496 PythonQtObjectPtr callable = lookupCallable(module, objectname);
481 if (callable) {
497 if (callable) {
482 PythonQtSignalReceiver* r = getSignalReceiver(obj);
498 PythonQtSignalReceiver* r = getSignalReceiver(obj);
483 flag = r->addSignalHandler(signal, callable);
499 flag = r->addSignalHandler(signal, callable);
484 if (!flag) {
500 if (!flag) {
485 // signal not found
501 // signal not found
486 }
502 }
487 } else {
503 } else {
488 // callable not found
504 // callable not found
489 }
505 }
490 return flag;
506 return flag;
491 }
507 }
492
508
493 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
509 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
494 {
510 {
495 bool flag = false;
511 bool flag = false;
496 PythonQtSignalReceiver* r = getSignalReceiver(obj);
512 PythonQtSignalReceiver* r = getSignalReceiver(obj);
497 if (r) {
513 if (r) {
498 flag = r->addSignalHandler(signal, receiver);
514 flag = r->addSignalHandler(signal, receiver);
499 }
515 }
500 return flag;
516 return flag;
501 }
517 }
502
518
503 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
519 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
504 {
520 {
505 bool flag = false;
521 bool flag = false;
506 PythonQtObjectPtr callable = lookupCallable(module, objectname);
522 PythonQtObjectPtr callable = lookupCallable(module, objectname);
507 if (callable) {
523 if (callable) {
508 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
524 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
509 if (r) {
525 if (r) {
510 flag = r->removeSignalHandler(signal, callable);
526 flag = r->removeSignalHandler(signal, callable);
511 }
527 }
512 } else {
528 } else {
513 // callable not found
529 // callable not found
514 }
530 }
515 return flag;
531 return flag;
516 }
532 }
517
533
518 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
534 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
519 {
535 {
520 bool flag = false;
536 bool flag = false;
521 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
537 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
522 if (r) {
538 if (r) {
523 flag = r->removeSignalHandler(signal, receiver);
539 flag = r->removeSignalHandler(signal, receiver);
524 }
540 }
525 return flag;
541 return flag;
526 }
542 }
527
543
528 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
544 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
529 {
545 {
530 PythonQtObjectPtr p = lookupObject(module, name);
546 PythonQtObjectPtr p = lookupObject(module, name);
531 if (p) {
547 if (p) {
532 if (PyCallable_Check(p)) {
548 if (PyCallable_Check(p)) {
533 return p;
549 return p;
534 }
550 }
535 }
551 }
536 PyErr_Clear();
552 PyErr_Clear();
537 return NULL;
553 return NULL;
538 }
554 }
539
555
540 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
556 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
541 {
557 {
542 QStringList l = name.split('.');
558 QStringList l = name.split('.');
543 PythonQtObjectPtr p = module;
559 PythonQtObjectPtr p = module;
544 PythonQtObjectPtr prev;
560 PythonQtObjectPtr prev;
545 QString s;
561 QString s;
546 QByteArray b;
562 QByteArray b;
547 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
563 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
548 prev = p;
564 prev = p;
549 b = (*i).toLatin1();
565 b = (*i).toLatin1();
550 if (PyDict_Check(p)) {
566 if (PyDict_Check(p)) {
551 p = PyDict_GetItemString(p, b.data());
567 p = PyDict_GetItemString(p, b.data());
552 } else {
568 } else {
553 p.setNewRef(PyObject_GetAttrString(p, b.data()));
569 p.setNewRef(PyObject_GetAttrString(p, b.data()));
554 }
570 }
555 }
571 }
556 PyErr_Clear();
572 PyErr_Clear();
557 return p;
573 return p;
558 }
574 }
559
575
560 PythonQtObjectPtr PythonQt::getMainModule() {
576 PythonQtObjectPtr PythonQt::getMainModule() {
561 //both borrowed
577 //both borrowed
562 PythonQtObjectPtr dict = PyImport_GetModuleDict();
578 PythonQtObjectPtr dict = PyImport_GetModuleDict();
563 return PyDict_GetItemString(dict, "__main__");
579 return PyDict_GetItemString(dict, "__main__");
564 }
580 }
565
581
566 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
582 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
567 QVariant result;
583 QVariant result;
568 if (pycode) {
584 if (pycode) {
569 PyObject* dict = NULL;
585 PyObject* dict = NULL;
570 if (PyModule_Check(object)) {
586 if (PyModule_Check(object)) {
571 dict = PyModule_GetDict(object);
587 dict = PyModule_GetDict(object);
572 } else if (PyDict_Check(object)) {
588 } else if (PyDict_Check(object)) {
573 dict = object;
589 dict = object;
574 }
590 }
575 PyObject* r = NULL;
591 PyObject* r = NULL;
576 if (dict) {
592 if (dict) {
577 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
593 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
578 }
594 }
579 if (r) {
595 if (r) {
580 result = PythonQtConv::PyObjToQVariant(r);
596 result = PythonQtConv::PyObjToQVariant(r);
581 Py_DECREF(r);
597 Py_DECREF(r);
582 } else {
598 } else {
583 handleError();
599 handleError();
584 }
600 }
585 } else {
601 } else {
586 handleError();
602 handleError();
587 }
603 }
588 return result;
604 return result;
589 }
605 }
590
606
591 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
607 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
592 {
608 {
593 QVariant result;
609 QVariant result;
594 PythonQtObjectPtr p;
610 PythonQtObjectPtr p;
595 PyObject* dict = NULL;
611 PyObject* dict = NULL;
596 if (PyModule_Check(object)) {
612 if (PyModule_Check(object)) {
597 dict = PyModule_GetDict(object);
613 dict = PyModule_GetDict(object);
598 } else if (PyDict_Check(object)) {
614 } else if (PyDict_Check(object)) {
599 dict = object;
615 dict = object;
600 }
616 }
601 if (dict) {
617 if (dict) {
602 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
618 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
603 }
619 }
604 if (p) {
620 if (p) {
605 result = PythonQtConv::PyObjToQVariant(p);
621 result = PythonQtConv::PyObjToQVariant(p);
606 } else {
622 } else {
607 handleError();
623 handleError();
608 }
624 }
609 return result;
625 return result;
610 }
626 }
611
627
612 void PythonQt::evalFile(PyObject* module, const QString& filename)
628 void PythonQt::evalFile(PyObject* module, const QString& filename)
613 {
629 {
614 PythonQtObjectPtr code = parseFile(filename);
630 PythonQtObjectPtr code = parseFile(filename);
615 if (code) {
631 if (code) {
616 evalCode(module, code);
632 evalCode(module, code);
617 } else {
633 } else {
618 handleError();
634 handleError();
619 }
635 }
620 }
636 }
621
637
622 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
638 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
623 {
639 {
624 PythonQtObjectPtr p;
640 PythonQtObjectPtr p;
625 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
641 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
626 if (!p) {
642 if (!p) {
627 handleError();
643 handleError();
628 }
644 }
629 return p;
645 return p;
630 }
646 }
631
647
632 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
648 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
633 {
649 {
634 PythonQtObjectPtr code = parseFile(filename);
650 PythonQtObjectPtr code = parseFile(filename);
635 PythonQtObjectPtr module = _p->createModule(name, code);
651 PythonQtObjectPtr module = _p->createModule(name, code);
636 return module;
652 return module;
637 }
653 }
638
654
639 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
655 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
640 {
656 {
641 PyErr_Clear();
657 PyErr_Clear();
642 QString scriptCode = script;
658 QString scriptCode = script;
643 if (scriptCode.isEmpty()) {
659 if (scriptCode.isEmpty()) {
644 // we always need at least a linefeed
660 // we always need at least a linefeed
645 scriptCode = "\n";
661 scriptCode = "\n";
646 }
662 }
647 PythonQtObjectPtr pycode;
663 PythonQtObjectPtr pycode;
648 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
664 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
649 PythonQtObjectPtr module = _p->createModule(name, pycode);
665 PythonQtObjectPtr module = _p->createModule(name, pycode);
650 return module;
666 return module;
651 }
667 }
652
668
653 PythonQtObjectPtr PythonQt::createUniqueModule()
669 PythonQtObjectPtr PythonQt::createUniqueModule()
654 {
670 {
655 static QString pyQtStr("PythonQt_module");
671 static QString pyQtStr("PythonQt_module");
656 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
672 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
657 return createModuleFromScript(moduleName);
673 return createModuleFromScript(moduleName);
658 }
674 }
659
675
660 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
676 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
661 {
677 {
662 if (PyModule_Check(object)) {
678 if (PyModule_Check(object)) {
663 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
679 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
664 } else if (PyDict_Check(object)) {
680 } else if (PyDict_Check(object)) {
665 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
681 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
666 } else {
682 } else {
667 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
683 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
668 }
684 }
669 }
685 }
670
686
671 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
687 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
672 {
688 {
673 if (PyModule_Check(object)) {
689 if (PyModule_Check(object)) {
674 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
690 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
675 } else if (PyDict_Check(object)) {
691 } else if (PyDict_Check(object)) {
676 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
692 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
677 } else {
693 } else {
678 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
694 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
679 }
695 }
680 }
696 }
681
697
682 void PythonQt::removeVariable(PyObject* object, const QString& name)
698 void PythonQt::removeVariable(PyObject* object, const QString& name)
683 {
699 {
684 if (PyDict_Check(object)) {
700 if (PyDict_Check(object)) {
685 PyDict_DelItemString(object, name.toLatin1().data());
701 PyDict_DelItemString(object, name.toLatin1().data());
686 } else {
702 } else {
687 PyObject_DelAttrString(object, name.toLatin1().data());
703 PyObject_DelAttrString(object, name.toLatin1().data());
688 }
704 }
689 }
705 }
690
706
691 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
707 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
692 {
708 {
693 QVariant result;
709 QVariant result;
694 PythonQtObjectPtr obj = lookupObject(object, objectname);
710 PythonQtObjectPtr obj = lookupObject(object, objectname);
695 if (obj) {
711 if (obj) {
696 result = PythonQtConv::PyObjToQVariant(obj);
712 result = PythonQtConv::PyObjToQVariant(obj);
697 }
713 }
698 return result;
714 return result;
699 }
715 }
700
716
701 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
717 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
702 {
718 {
703 QStringList results;
719 QStringList results;
704
720
705 PythonQtObjectPtr object;
721 PythonQtObjectPtr object;
706 if (objectname.isEmpty()) {
722 if (objectname.isEmpty()) {
707 object = module;
723 object = module;
708 } else {
724 } else {
709 object = lookupObject(module, objectname);
725 object = lookupObject(module, objectname);
710 if (!object && type == CallOverloads) {
726 if (!object && type == CallOverloads) {
711 PyObject* dict = lookupObject(module, "__builtins__");
727 PyObject* dict = lookupObject(module, "__builtins__");
712 if (dict) {
728 if (dict) {
713 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
729 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
714 }
730 }
715 }
731 }
716 }
732 }
717
733
718 if (object) {
734 if (object) {
719 if (type == CallOverloads) {
735 if (type == CallOverloads) {
720 if (PythonQtSlotFunction_Check(object)) {
736 if (PythonQtSlotFunction_Check(object)) {
721 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
737 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
722 PythonQtSlotInfo* info = o->m_ml;
738 PythonQtSlotInfo* info = o->m_ml;
723
739
724 while (info) {
740 while (info) {
725 results << info->fullSignature();
741 results << info->fullSignature();
726 info = info->nextInfo();
742 info = info->nextInfo();
727 }
743 }
728 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
744 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
729 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
745 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
730 PythonQtSlotInfo* info = o->classInfo()->constructors();
746 PythonQtSlotInfo* info = o->classInfo()->constructors();
731
747
732 while (info) {
748 while (info) {
733 results << info->fullSignature();
749 results << info->fullSignature();
734 info = info->nextInfo();
750 info = info->nextInfo();
735 }
751 }
736 } else {
752 } else {
737 //TODO: use pydoc!
753 //TODO: use pydoc!
738 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
754 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
739 if (doc) {
755 if (doc) {
740 results << PyString_AsString(doc);
756 results << PyString_AsString(doc);
741 Py_DECREF(doc);
757 Py_DECREF(doc);
742 }
758 }
743 }
759 }
744 } else {
760 } else {
745 PyObject* keys = NULL;
761 PyObject* keys = NULL;
746 bool isDict = false;
762 bool isDict = false;
747 if (PyDict_Check(object)) {
763 if (PyDict_Check(object)) {
748 keys = PyDict_Keys(object);
764 keys = PyDict_Keys(object);
749 isDict = true;
765 isDict = true;
750 } else {
766 } else {
751 keys = PyObject_Dir(object);
767 keys = PyObject_Dir(object);
752 }
768 }
753 if (keys) {
769 if (keys) {
754 int count = PyList_Size(keys);
770 int count = PyList_Size(keys);
755 PyObject* key;
771 PyObject* key;
756 PyObject* value;
772 PyObject* value;
757 QString keystr;
773 QString keystr;
758 for (int i = 0;i<count;i++) {
774 for (int i = 0;i<count;i++) {
759 key = PyList_GetItem(keys,i);
775 key = PyList_GetItem(keys,i);
760 if (isDict) {
776 if (isDict) {
761 value = PyDict_GetItem(object, key);
777 value = PyDict_GetItem(object, key);
762 Py_INCREF(value);
778 Py_INCREF(value);
763 } else {
779 } else {
764 value = PyObject_GetAttr(object, key);
780 value = PyObject_GetAttr(object, key);
765 }
781 }
766 if (!value) continue;
782 if (!value) continue;
767 keystr = PyString_AsString(key);
783 keystr = PyString_AsString(key);
768 static const QString underscoreStr("__tmp");
784 static const QString underscoreStr("__tmp");
769 if (!keystr.startsWith(underscoreStr)) {
785 if (!keystr.startsWith(underscoreStr)) {
770 switch (type) {
786 switch (type) {
771 case Anything:
787 case Anything:
772 results << keystr;
788 results << keystr;
773 break;
789 break;
774 case Class:
790 case Class:
775 if (value->ob_type == &PyClass_Type) {
791 if (value->ob_type == &PyClass_Type) {
776 results << keystr;
792 results << keystr;
777 }
793 }
778 break;
794 break;
779 case Variable:
795 case Variable:
780 if (value->ob_type != &PyClass_Type
796 if (value->ob_type != &PyClass_Type
781 && value->ob_type != &PyCFunction_Type
797 && value->ob_type != &PyCFunction_Type
782 && value->ob_type != &PyFunction_Type
798 && value->ob_type != &PyFunction_Type
783 && value->ob_type != &PyModule_Type
799 && value->ob_type != &PyModule_Type
784 ) {
800 ) {
785 results << keystr;
801 results << keystr;
786 }
802 }
787 break;
803 break;
788 case Function:
804 case Function:
789 if (value->ob_type == &PyFunction_Type ||
805 if (value->ob_type == &PyFunction_Type ||
790 value->ob_type == &PyMethod_Type
806 value->ob_type == &PyMethod_Type
791 ) {
807 ) {
792 results << keystr;
808 results << keystr;
793 }
809 }
794 break;
810 break;
795 case Module:
811 case Module:
796 if (value->ob_type == &PyModule_Type) {
812 if (value->ob_type == &PyModule_Type) {
797 results << keystr;
813 results << keystr;
798 }
814 }
799 break;
815 break;
800 default:
816 default:
801 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
817 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
802 }
818 }
803 }
819 }
804 Py_DECREF(value);
820 Py_DECREF(value);
805 }
821 }
806 Py_DECREF(keys);
822 Py_DECREF(keys);
807 }
823 }
808 }
824 }
809 }
825 }
810 return results;
826 return results;
811 }
827 }
812
828
813 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
829 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
814 {
830 {
815 PythonQtObjectPtr callable = lookupCallable(object, name);
831 PythonQtObjectPtr callable = lookupCallable(object, name);
816 if (callable) {
832 if (callable) {
817 return call(callable, args);
833 return call(callable, args);
818 } else {
834 } else {
819 return QVariant();
835 return QVariant();
820 }
836 }
821 }
837 }
822
838
823 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
839 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
824 {
840 {
825 QVariant r;
841 QVariant r;
826 if (callable) {
842 if (callable) {
827 PythonQtObjectPtr pargs;
843 PythonQtObjectPtr pargs;
828 int count = args.size();
844 int count = args.size();
829 if (count>0) {
845 if (count>0) {
830 pargs.setNewRef(PyTuple_New(count));
846 pargs.setNewRef(PyTuple_New(count));
831 }
847 }
832 bool err = false;
848 bool err = false;
833 // transform QVariants to Python
849 // transform QVariants to Python
834 for (int i = 0; i < count; i++) {
850 for (int i = 0; i < count; i++) {
835 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
851 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
836 if (arg) {
852 if (arg) {
837 // steals reference, no unref
853 // steals reference, no unref
838 PyTuple_SetItem(pargs, i,arg);
854 PyTuple_SetItem(pargs, i,arg);
839 } else {
855 } else {
840 err = true;
856 err = true;
841 break;
857 break;
842 }
858 }
843 }
859 }
844
860
845 if (!err) {
861 if (!err) {
846 PyErr_Clear();
862 PyErr_Clear();
847 PythonQtObjectPtr result;
863 PythonQtObjectPtr result;
848 result.setNewRef(PyObject_CallObject(callable, pargs));
864 result.setNewRef(PyObject_CallObject(callable, pargs));
849 if (result) {
865 if (result) {
850 // ok
866 // ok
851 r = PythonQtConv::PyObjToQVariant(result);
867 r = PythonQtConv::PyObjToQVariant(result);
852 } else {
868 } else {
853 PythonQt::self()->handleError();
869 PythonQt::self()->handleError();
854 }
870 }
855 }
871 }
856 }
872 }
857 return r;
873 return r;
858 }
874 }
859
875
860 void PythonQt::addInstanceDecorators(QObject* o)
876 void PythonQt::addInstanceDecorators(QObject* o)
861 {
877 {
862 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
878 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
863 }
879 }
864
880
865 void PythonQt::addClassDecorators(QObject* o)
881 void PythonQt::addClassDecorators(QObject* o)
866 {
882 {
867 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
883 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
868 }
884 }
869
885
870 void PythonQt::addDecorators(QObject* o)
886 void PythonQt::addDecorators(QObject* o)
871 {
887 {
872 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
888 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
873 }
889 }
874
890
875 void PythonQt::registerQObjectClassNames(const QStringList& names)
891 void PythonQt::registerQObjectClassNames(const QStringList& names)
876 {
892 {
877 _p->registerQObjectClassNames(names);
893 _p->registerQObjectClassNames(names);
878 }
894 }
879
895
880 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
896 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
881 {
897 {
882 PythonQtImport::init();
898 PythonQtImport::init();
883 _p->_importInterface = importInterface;
899 _p->_importInterface = importInterface;
884 }
900 }
885
901
886 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
902 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
887 {
903 {
888 _p->_importIgnorePaths = paths;
904 _p->_importIgnorePaths = paths;
889 }
905 }
890
906
891 const QStringList& PythonQt::getImporterIgnorePaths()
907 const QStringList& PythonQt::getImporterIgnorePaths()
892 {
908 {
893 return _p->_importIgnorePaths;
909 return _p->_importIgnorePaths;
894 }
910 }
895
911
896 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
912 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
897 {
913 {
898 _p->_cppWrapperFactories.append(factory);
914 _p->_cppWrapperFactories.append(factory);
899 }
915 }
900
916
901 //---------------------------------------------------------------------------------------------------
917 //---------------------------------------------------------------------------------------------------
902 PythonQtPrivate::PythonQtPrivate()
918 PythonQtPrivate::PythonQtPrivate()
903 {
919 {
904 _importInterface = NULL;
920 _importInterface = NULL;
905 _defaultImporter = new PythonQtQFileImporter;
921 _defaultImporter = new PythonQtQFileImporter;
906 _noLongerWrappedCB = NULL;
922 _noLongerWrappedCB = NULL;
907 _wrappedCB = NULL;
923 _wrappedCB = NULL;
908 _currentClassInfoForClassWrapperCreation = NULL;
924 _currentClassInfoForClassWrapperCreation = NULL;
909 }
925 }
910
926
911 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
927 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
912 {
928 {
913 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
929 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
914 _currentClassInfoForClassWrapperCreation = NULL;
930 _currentClassInfoForClassWrapperCreation = NULL;
915 return info;
931 return info;
916 }
932 }
917
933
918 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
934 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
919 {
935 {
920 o->setParent(this);
936 o->setParent(this);
921 int numMethods = o->metaObject()->methodCount();
937 int numMethods = o->metaObject()->methodCount();
922 for (int i = 0; i < numMethods; i++) {
938 for (int i = 0; i < numMethods; i++) {
923 QMetaMethod m = o->metaObject()->method(i);
939 QMetaMethod m = o->metaObject()->method(i);
924 if ((m.methodType() == QMetaMethod::Method ||
940 if ((m.methodType() == QMetaMethod::Method ||
925 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
941 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
926 if (qstrncmp(m.signature(), "new_", 4)==0) {
942 if (qstrncmp(m.signature(), "new_", 4)==0) {
927 if ((decoTypes & ConstructorDecorator) == 0) continue;
943 if ((decoTypes & ConstructorDecorator) == 0) continue;
928 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
944 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
929 if (info->parameters().at(0).isPointer) {
945 if (info->parameters().at(0).isPointer) {
930 QByteArray signature = m.signature();
946 QByteArray signature = m.signature();
931 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
947 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
932 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
948 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
933 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
949 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
934 classInfo->addConstructor(newSlot);
950 classInfo->addConstructor(newSlot);
935 }
951 }
936 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
952 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
937 if ((decoTypes & DestructorDecorator) == 0) continue;
953 if ((decoTypes & DestructorDecorator) == 0) continue;
938 QByteArray signature = m.signature();
954 QByteArray signature = m.signature();
939 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
955 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
940 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
956 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
941 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
957 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
942 classInfo->setDestructor(newSlot);
958 classInfo->setDestructor(newSlot);
943 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
959 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
944 if ((decoTypes & StaticDecorator) == 0) continue;
960 if ((decoTypes & StaticDecorator) == 0) continue;
945 QByteArray signature = m.signature();
961 QByteArray signature = m.signature();
946 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
962 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
947 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
963 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
948 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
964 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
949 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
965 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
950 classInfo->addDecoratorSlot(newSlot);
966 classInfo->addDecoratorSlot(newSlot);
951 } else {
967 } else {
952 if ((decoTypes & InstanceDecorator) == 0) continue;
968 if ((decoTypes & InstanceDecorator) == 0) continue;
953 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
969 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
954 if (info->parameters().count()>1) {
970 if (info->parameters().count()>1) {
955 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
971 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
956 if (p.isPointer) {
972 if (p.isPointer) {
957 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
973 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
958 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
974 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
959 classInfo->addDecoratorSlot(newSlot);
975 classInfo->addDecoratorSlot(newSlot);
960 }
976 }
961 }
977 }
962 }
978 }
963 }
979 }
964 }
980 }
965 }
981 }
966
982
967 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
983 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
968 {
984 {
969 foreach(QString name, names) {
985 foreach(QString name, names) {
970 _knownQObjectClassNames.insert(name.toLatin1(), true);
986 _knownQObjectClassNames.insert(name.toLatin1(), true);
971 }
987 }
972 }
988 }
973
989
974 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
990 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
975 {
991 {
976 _signalReceivers.remove(obj);
992 _signalReceivers.remove(obj);
977 }
993 }
978
994
979 bool PythonQt::handleError()
995 bool PythonQt::handleError()
980 {
996 {
981 bool flag = false;
997 bool flag = false;
982 if (PyErr_Occurred()) {
998 if (PyErr_Occurred()) {
983
999
984 // currently we just print the error and the stderr handler parses the errors
1000 // currently we just print the error and the stderr handler parses the errors
985 PyErr_Print();
1001 PyErr_Print();
986
1002
987 /*
1003 /*
988 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1004 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
989 PyObject *ptype;
1005 PyObject *ptype;
990 PyObject *pvalue;
1006 PyObject *pvalue;
991 PyObject *ptraceback;
1007 PyObject *ptraceback;
992 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1008 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
993
1009
994 Py_XDECREF(ptype);
1010 Py_XDECREF(ptype);
995 Py_XDECREF(pvalue);
1011 Py_XDECREF(pvalue);
996 Py_XDECREF(ptraceback);
1012 Py_XDECREF(ptraceback);
997 */
1013 */
998 PyErr_Clear();
1014 PyErr_Clear();
999 flag = true;
1015 flag = true;
1000 }
1016 }
1001 return flag;
1017 return flag;
1002 }
1018 }
1003
1019
1004 void PythonQt::addSysPath(const QString& path)
1020 void PythonQt::addSysPath(const QString& path)
1005 {
1021 {
1006 PythonQtObjectPtr sys;
1022 PythonQtObjectPtr sys;
1007 sys.setNewRef(PyImport_ImportModule("sys"));
1023 sys.setNewRef(PyImport_ImportModule("sys"));
1008 PythonQtObjectPtr obj = lookupObject(sys, "path");
1024 PythonQtObjectPtr obj = lookupObject(sys, "path");
1009 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1025 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1010 }
1026 }
1011
1027
1012 void PythonQt::overwriteSysPath(const QStringList& paths)
1028 void PythonQt::overwriteSysPath(const QStringList& paths)
1013 {
1029 {
1014 PythonQtObjectPtr sys;
1030 PythonQtObjectPtr sys;
1015 sys.setNewRef(PyImport_ImportModule("sys"));
1031 sys.setNewRef(PyImport_ImportModule("sys"));
1016 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1032 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1017 }
1033 }
1018
1034
1019 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1035 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1020 {
1036 {
1021 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1037 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1022 }
1038 }
1023
1039
1024 void PythonQt::stdOutRedirectCB(const QString& str)
1040 void PythonQt::stdOutRedirectCB(const QString& str)
1025 {
1041 {
1026 emit PythonQt::self()->pythonStdOut(str);
1042 emit PythonQt::self()->pythonStdOut(str);
1027 }
1043 }
1028
1044
1029 void PythonQt::stdErrRedirectCB(const QString& str)
1045 void PythonQt::stdErrRedirectCB(const QString& str)
1030 {
1046 {
1031 emit PythonQt::self()->pythonStdErr(str);
1047 emit PythonQt::self()->pythonStdErr(str);
1032 }
1048 }
1033
1049
1034 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1050 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1035 {
1051 {
1036 _p->_wrappedCB = cb;
1052 _p->_wrappedCB = cb;
1037 }
1053 }
1038
1054
1039 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1055 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1040 {
1056 {
1041 _p->_noLongerWrappedCB = cb;
1057 _p->_noLongerWrappedCB = cb;
1042 }
1058 }
1043
1059
1044
1060
1045
1061
1046 static PyMethodDef PythonQtMethods[] = {
1062 static PyMethodDef PythonQtMethods[] = {
1047 {NULL, NULL, 0, NULL}
1063 {NULL, NULL, 0, NULL}
1048 };
1064 };
1049
1065
1050 void PythonQt::initPythonQtModule(bool redirectStdOut)
1066 void PythonQt::initPythonQtModule(bool redirectStdOut)
1051 {
1067 {
1052 _p->_pythonQtModule = Py_InitModule("PythonQt", PythonQtMethods);
1068 _p->_pythonQtModule = Py_InitModule("PythonQt", PythonQtMethods);
1053
1069
1054 if (redirectStdOut) {
1070 if (redirectStdOut) {
1055 PythonQtObjectPtr sys;
1071 PythonQtObjectPtr sys;
1056 PythonQtObjectPtr out;
1072 PythonQtObjectPtr out;
1057 PythonQtObjectPtr err;
1073 PythonQtObjectPtr err;
1058 sys.setNewRef(PyImport_ImportModule("sys"));
1074 sys.setNewRef(PyImport_ImportModule("sys"));
1059 // create a redirection object for stdout and stderr
1075 // create a redirection object for stdout and stderr
1060 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1076 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1061 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1077 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1062 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1078 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1063 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1079 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1064 // replace the built in file objects with our own objects
1080 // replace the built in file objects with our own objects
1065 PyModule_AddObject(sys, "stdout", out);
1081 PyModule_AddObject(sys, "stdout", out);
1066 PyModule_AddObject(sys, "stderr", err);
1082 PyModule_AddObject(sys, "stderr", err);
1067 }
1083 }
1068 }
1084 }
1069
1085
1070 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1086 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1071 {
1087 {
1072 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1088 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1073 }
1089 }
1074
1090
1075
1091
1076 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1092 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1077 {
1093 {
1078 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1094 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1079 if (!info) {
1095 if (!info) {
1080 info = new PythonQtClassInfo();
1096 info = new PythonQtClassInfo();
1081 info->setupCPPObject(typeName);
1097 info->setupCPPObject(typeName);
1082 _knownClassInfos.insert(typeName, info);
1098 _knownClassInfos.insert(typeName, info);
1083 }
1099 }
1084 return info;
1100 return info;
1085 }
1101 }
1086
1102
1087 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1103 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1088 {
1104 {
1089 _p->addPolymorphicHandler(typeName, cb);
1105 _p->addPolymorphicHandler(typeName, cb);
1090 }
1106 }
1091
1107
1092 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1108 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1093 {
1109 {
1094 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1110 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1095 info->addPolymorphicHandler(cb);
1111 info->addPolymorphicHandler(cb);
1096 }
1112 }
1097
1113
1098 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1114 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1099 {
1115 {
1100 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1116 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1101 }
1117 }
1102
1118
1103 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1119 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1104 {
1120 {
1105 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1121 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1106 if (info) {
1122 if (info) {
1107 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1123 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1108 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1124 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1109 return true;
1125 return true;
1110 } else {
1126 } else {
1111 return false;
1127 return false;
1112 }
1128 }
1113 }
1129 }
1114
1130
1115 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1131 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1116 {
1132 {
1117 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1133 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1118 if (!info->pythonQtClassWrapper()) {
1134 if (!info->pythonQtClassWrapper()) {
1119 info->setupCPPObject(typeName);
1135 info->setupCPPObject(typeName);
1120 createPythonQtClassWrapper(info, package);
1136 createPythonQtClassWrapper(info, package);
1121 }
1137 }
1122 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1138 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1123 addParentClass(typeName, parentTypeName, 0);
1139 addParentClass(typeName, parentTypeName, 0);
1124 }
1140 }
1125 if (wrapperCreator) {
1141 if (wrapperCreator) {
1126 info->setDecoratorProvider(wrapperCreator);
1142 info->setDecoratorProvider(wrapperCreator);
1127 }
1143 }
1128 if (shell) {
1144 if (shell) {
1129 info->setShellSetInstanceWrapperCB(shell);
1145 info->setShellSetInstanceWrapperCB(shell);
1130 }
1146 }
1131 }
1147 }
1132
1148
1133 static PyObject *PythonQt_SIGNAL(PyObject * /*type*/, PyObject *args)
1134 {
1135 const char* value;
1136 if (!PyArg_ParseTuple(args, "s", &value)) {
1137 return NULL;
1138 }
1139 // we do not prepend 0,1 or 2, why should we?
1140 return PyString_FromString(QByteArray("2") + value);
1141 }
1142
1143 static PyObject *PythonQt_SLOT(PyObject * /*type*/, PyObject *args)
1144 {
1145 const char* value;
1146 if (!PyArg_ParseTuple(args, "s", &value)) {
1147 return NULL;
1148 }
1149 // we do not prepend 0,1 or 2, why should we?
1150 return PyString_FromString(QByteArray("1") + value);
1151 }
1152
1153 static PyMethodDef PythonQt_Qt_methods[] = {
1154 {"SIGNAL", (PyCFunction)PythonQt_SIGNAL, METH_VARARGS,
1155 "Returns a signal string"
1156 },
1157 {"SLOT", (PyCFunction)PythonQt_SLOT, METH_VARARGS,
1158 "Returns a slot string"
1159 }
1160 };
1161
1162 PyObject* PythonQtPrivate::packageByName(const char* name)
1149 PyObject* PythonQtPrivate::packageByName(const char* name)
1163 {
1150 {
1164 if (name==NULL || name[0]==0) {
1151 if (name==NULL || name[0]==0) {
1165 return _pythonQtModule;
1152 return _pythonQtModule;
1166 }
1153 }
1167 PyObject* v = _packages.value(name);
1154 PyObject* v = _packages.value(name);
1168 if (!v) {
1155 if (!v) {
1169 v = PyImport_AddModule((QByteArray("PythonQt.") + name).constData());
1156 v = PyImport_AddModule((QByteArray("PythonQt.") + name).constData());
1170 if (strcmp(name,"Qt")==0 || strcmp(name,"QtCore")==0) {
1171 // add SIGNAL and SLOT functions
1172 PyModule_AddObject(v, "SIGNAL", PyCFunction_New(PythonQt_Qt_methods, v));
1173 PyModule_AddObject(v, "SLOT", PyCFunction_New(PythonQt_Qt_methods+1, v));
1174 }
1175 _packages.insert(name, v);
1157 _packages.insert(name, v);
1176 // AddObject steals the reference, so increment it!
1158 // AddObject steals the reference, so increment it!
1177 Py_INCREF(v);
1159 Py_INCREF(v);
1178 PyModule_AddObject(_pythonQtModule, name, v);
1160 PyModule_AddObject(_pythonQtModule, name, v);
1179 }
1161 }
1180 return v;
1162 return v;
1181 }
1163 }
1182
1164
1165 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1166 {
1167 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;
1168 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1169 PythonQt::self()->handleError();
1170 }
1183
1171
1184 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1172 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1185 {
1173 {
1186 if (_p->_initFlags & ExternalHelp) {
1174 if (_p->_initFlags & ExternalHelp) {
1187 emit pythonHelpRequest(QByteArray(info->className()));
1175 emit pythonHelpRequest(QByteArray(info->className()));
1188 return Py_BuildValue("");
1176 return Py_BuildValue("");
1189 } else {
1177 } else {
1190 return PyString_FromString(info->help().toLatin1().data());
1178 return PyString_FromString(info->help().toLatin1().data());
1191 }
1179 }
1192 }
1180 }
1193
1181
1194 void PythonQtPrivate::removeWrapperPointer(void* obj)
1182 void PythonQtPrivate::removeWrapperPointer(void* obj)
1195 {
1183 {
1196 _wrappedObjects.remove(obj);
1184 _wrappedObjects.remove(obj);
1197 }
1185 }
1198
1186
1199 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1187 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1200 {
1188 {
1201 _wrappedObjects.insert(obj, wrapper);
1189 _wrappedObjects.insert(obj, wrapper);
1202 }
1190 }
1203
1191
1204 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1192 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1205 {
1193 {
1206 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1194 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1207 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1195 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1208 // this is a wrapper whose QObject was already removed due to destruction
1196 // this is a wrapper whose QObject was already removed due to destruction
1209 // so the obj pointer has to be a new QObject with the same address...
1197 // so the obj pointer has to be a new QObject with the same address...
1210 // we remove the old one and set the copy to NULL
1198 // we remove the old one and set the copy to NULL
1211 wrap->_objPointerCopy = NULL;
1199 wrap->_objPointerCopy = NULL;
1212 removeWrapperPointer(obj);
1200 removeWrapperPointer(obj);
1213 wrap = NULL;
1201 wrap = NULL;
1214 }
1202 }
1215 return wrap;
1203 return wrap;
1216 }
1204 }
1217
1205
1218 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1206 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1219 {
1207 {
1220 PythonQtObjectPtr result;
1208 PythonQtObjectPtr result;
1221 if (pycode) {
1209 if (pycode) {
1222 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1210 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1223 } else {
1211 } else {
1224 PythonQt::self()->handleError();
1212 PythonQt::self()->handleError();
1225 }
1213 }
1226 return result;
1214 return result;
1227 }
1215 }
@@ -1,523 +1,526
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) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
7 *
7 *
8 * This library is free software; you can redistribute it and/or
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
11 * version 2.1 of the License, or (at your option) any later version.
12 *
12 *
13 * This library is distributed in the hope that it will be useful,
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
16 * Lesser General Public License for more details.
17 *
17 *
18 * Further, this software is distributed without any warranty that it is
18 * Further, this software is distributed without any warranty that it is
19 * free of the rightful claim of any third person regarding infringement
19 * free of the rightful claim of any third person regarding infringement
20 * or the like. Any license provided herein, whether implied or
20 * or the like. Any license provided herein, whether implied or
21 * otherwise, applies only to this software file. Patent licenses, if
21 * otherwise, applies only to this software file. Patent licenses, if
22 * any, provided herein do not apply to combinations of this program with
22 * any, provided herein do not apply to combinations of this program with
23 * other software, or any other product whatsoever.
23 * other software, or any other product whatsoever.
24 *
24 *
25 * You should have received a copy of the GNU Lesser General Public
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
30 * 28359 Bremen, Germany or:
30 * 28359 Bremen, Germany or:
31 *
31 *
32 * http://www.mevis.de
32 * http://www.mevis.de
33 *
33 *
34 */
34 */
35
35
36 //----------------------------------------------------------------------------------
36 //----------------------------------------------------------------------------------
37 /*!
37 /*!
38 // \file 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 <QObject>
50 #include <QObject>
51 #include <QVariant>
51 #include <QVariant>
52 #include <QList>
52 #include <QList>
53 #include <QHash>
53 #include <QHash>
54 #include <QByteArray>
54 #include <QByteArray>
55 #include <QStringList>
55 #include <QStringList>
56 #include <QtDebug>
56 #include <QtDebug>
57 #include <iostream>
57 #include <iostream>
58
58
59
59
60 class PythonQtClassInfo;
60 class PythonQtClassInfo;
61 class PythonQtPrivate;
61 class PythonQtPrivate;
62 class PythonQtMethodInfo;
62 class PythonQtMethodInfo;
63 class PythonQtSignalReceiver;
63 class PythonQtSignalReceiver;
64 class PythonQtImportFileInterface;
64 class PythonQtImportFileInterface;
65 class PythonQtCppWrapperFactory;
65 class PythonQtCppWrapperFactory;
66 class PythonQtQFileImporter;
66 class PythonQtQFileImporter;
67
67
68 typedef void PythonQtQObjectWrappedCB(QObject* object);
68 typedef void PythonQtQObjectWrappedCB(QObject* object);
69 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
69 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
70 typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, char **class_name);
70 typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, char **class_name);
71
71
72 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
72 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
73
73
74 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) { ((T*)object)->_wrapper = wrapper; };
74 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) { ((T*)object)->_wrapper = wrapper; };
75
75
76 //! returns the offset that needs to be added to upcast an object of type T1 to T2
76 //! returns the offset that needs to be added to upcast an object of type T1 to T2
77 template<class T1, class T2> int PythonQtUpcastingOffset() {
77 template<class T1, class T2> int PythonQtUpcastingOffset() {
78 return (((char*)(static_cast<T2*>(reinterpret_cast<T1*>(0x100)))) - ((char*)reinterpret_cast<T1*>(0x100)));
78 return (((char*)(static_cast<T2*>(reinterpret_cast<T1*>(0x100)))) - ((char*)reinterpret_cast<T1*>(0x100)));
79 }
79 }
80
80
81 //! callback to create a QObject lazily
81 //! callback to create a QObject lazily
82 typedef QObject* PythonQtQObjectCreatorFunctionCB();
82 typedef QObject* PythonQtQObjectCreatorFunctionCB();
83
83
84 //! helper template to create a derived QObject class
84 //! helper template to create a derived QObject class
85 template<class T> QObject* PythonQtCreateObject() { return new T(); };
85 template<class T> QObject* PythonQtCreateObject() { return new T(); };
86
86
87 //! the main interface to the Python Qt binding, realized as a singleton
87 //! the main interface to the Python Qt binding, realized as a singleton
88 class PYTHONQT_EXPORT PythonQt : public QObject {
88 class PYTHONQT_EXPORT PythonQt : public QObject {
89
89
90 Q_OBJECT
90 Q_OBJECT
91
91
92 public:
92 public:
93 enum InitFlags {
93 enum InitFlags {
94 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
94 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
95 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
95 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
96 ExternalHelp = 4 //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
96 ExternalHelp = 4 //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
97 };
97 };
98
98
99 //! initialize the python qt binding (flags are a or combination of InitFlags)
99 //! initialize the python qt binding (flags are a or combination of InitFlags)
100 static void init(int flags = IgnoreSiteModule | RedirectStdOut);
100 static void init(int flags = IgnoreSiteModule | RedirectStdOut);
101
101
102 //! cleanup
102 //! cleanup
103 static void cleanup();
103 static void cleanup();
104
104
105 //! get the singleton instance
105 //! get the singleton instance
106 static PythonQt* self() { return _self; }
106 static PythonQt* self() { return _self; }
107
107
108 //-----------------------------------------------------------------------------
108 //-----------------------------------------------------------------------------
109 // Public API:
109 // Public API:
110
110
111 //! defines the object types for introspection
111 //! defines the object types for introspection
112 enum ObjectType {
112 enum ObjectType {
113 Class,
113 Class,
114 Function,
114 Function,
115 Variable,
115 Variable,
116 Module,
116 Module,
117 Anything,
117 Anything,
118 CallOverloads
118 CallOverloads
119 };
119 };
120
120
121 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
121 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
122 void overwriteSysPath(const QStringList& paths);
122 void overwriteSysPath(const QStringList& paths);
123
123
124 //! prepend a path to sys.path to allow importing from it
124 //! prepend a path to sys.path to allow importing from it
125 void addSysPath(const QString& path);
125 void addSysPath(const QString& path);
126
126
127 //! sets the __path__ list of a module to the given list (important for local imports)
127 //! sets the __path__ list of a module to the given list (important for local imports)
128 void setModuleImportPath(PyObject* module, const QStringList& paths);
128 void setModuleImportPath(PyObject* module, const QStringList& paths);
129
129
130 //! get the __main__ module of python
130 //! get the __main__ module of python
131 PythonQtObjectPtr getMainModule();
131 PythonQtObjectPtr getMainModule();
132
132
133 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
133 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
134 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
134 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
135 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
135 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
136 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
136 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
137
137
138 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
138 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
139 //! (ownership of wrapper is passed to PythonQt)
139 //! (ownership of wrapper is passed to PythonQt)
140 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
140 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
141
141
142 This will add a wrapper object that is used to make calls to the given classname \c typeName.
142 This will add a wrapper object that is used to make calls to the given classname \c typeName.
143 All slots that take a pointer to typeName as the first argument will be callable from Python on
143 All slots that take a pointer to typeName as the first argument will be callable from Python on
144 a variant object that contains such a type.
144 a variant object that contains such a type.
145 */
145 */
146 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
146 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
147
147
148 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
148 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
149 //! and it will register the classes when it first sees a pointer to such a derived class
149 //! and it will register the classes when it first sees a pointer to such a derived class
150 void registerQObjectClassNames(const QStringList& names);
150 void registerQObjectClassNames(const QStringList& names);
151
151
152 //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance
152 //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance
153 //! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that
153 //! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that
154 //! type is really derived from parentType.
154 //! type is really derived from parentType.
155 //! Returns false if the typeName was not yet registered.
155 //! Returns false if the typeName was not yet registered.
156 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
156 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
157
157
158 //! add a handler for polymorphic downcasting
158 //! add a handler for polymorphic downcasting
159 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
159 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
160
160
161 //! parses the given file and returns the python code object, this can then be used to call evalCode()
161 //! parses the given file and returns the python code object, this can then be used to call evalCode()
162 PythonQtObjectPtr parseFile(const QString& filename);
162 PythonQtObjectPtr parseFile(const QString& filename);
163
163
164 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
164 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
165 //! If pycode is NULL, a python error is printed.
165 //! If pycode is NULL, a python error is printed.
166 QVariant evalCode(PyObject* object, PyObject* pycode);
166 QVariant evalCode(PyObject* object, PyObject* pycode);
167
167
168 //! evaluates the given script code and returns the result value
168 //! evaluates the given script code and returns the result value
169 QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input);
169 QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input);
170
170
171 //! evaluates the given script code from file
171 //! evaluates the given script code from file
172 void evalFile(PyObject* object, const QString& filename);
172 void evalFile(PyObject* object, const QString& filename);
173
173
174 //! creates the new module \c name and evaluates the given file in the context of that module
174 //! creates the new module \c name and evaluates the given file in the context of that module
175 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
175 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
176 //! to a module later on.
176 //! to a module later on.
177 //! The user needs to make sure that the \c name is unique in the python module dictionary.
177 //! The user needs to make sure that the \c name is unique in the python module dictionary.
178 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
178 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
179
179
180 //! creates the new module \c name and evaluates the given script in the context of that module.
180 //! creates the new module \c name and evaluates the given script in the context of that module.
181 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
181 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
182 //! to a module later on.
182 //! to a module later on.
183 //! The user needs to make sure that the \c name is unique in the python module dictionary.
183 //! The user needs to make sure that the \c name is unique in the python module dictionary.
184 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
184 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
185
185
186 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
186 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
187 //! script code
187 //! script code
188 PythonQtObjectPtr createUniqueModule();
188 PythonQtObjectPtr createUniqueModule();
189
189
190 //@{ Signal handlers
190 //@{ Signal handlers
191
191
192 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
192 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
193 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
193 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
194
194
195 //! remove a signal handler from the given \c signal of \c obj
195 //! remove a signal handler from the given \c signal of \c obj
196 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
196 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
197
197
198 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
198 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
199 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
199 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
200
200
201 //! remove a signal handler from the given \c signal of \c obj
201 //! remove a signal handler from the given \c signal of \c obj
202 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
202 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
203
203
204 //@}
204 //@}
205
205
206 //@{ Variable access
206 //@{ Variable access
207
207
208 //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable)
208 //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable)
209 void addObject(PyObject* object, const QString& name, QObject* qObject);
209 void addObject(PyObject* object, const QString& name, QObject* qObject);
210
210
211 //! add the given variable to the object
211 //! add the given variable to the object
212 void addVariable(PyObject* object, const QString& name, const QVariant& v);
212 void addVariable(PyObject* object, const QString& name, const QVariant& v);
213
213
214 //! remove the given variable
214 //! remove the given variable
215 void removeVariable(PyObject* module, const QString& name);
215 void removeVariable(PyObject* module, const QString& name);
216
216
217 //! get the variable with the \c name of the \c object, returns an invalid QVariant on error
217 //! get the variable with the \c name of the \c object, returns an invalid QVariant on error
218 QVariant getVariable(PyObject* object, const QString& name);
218 QVariant getVariable(PyObject* object, const QString& name);
219
219
220 //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname
220 //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname
221 QStringList introspection(PyObject* object, const QString& objectname, ObjectType type);
221 QStringList introspection(PyObject* object, const QString& objectname, ObjectType type);
222
222
223 //! returns the found callable object or NULL
223 //! returns the found callable object or NULL
224 //! @return new reference
224 //! @return new reference
225 PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
225 PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
226
226
227 //@}
227 //@}
228
228
229 //@{ Calling of python callables
229 //@{ Calling of python callables
230
230
231 //! call the given python \c callable in the scope of object, returns the result converted to a QVariant
231 //! call the given python \c callable in the scope of object, returns the result converted to a QVariant
232 QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList());
232 QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList());
233
233
234 //! call the given python object, returns the result converted to a QVariant
234 //! call the given python object, returns the result converted to a QVariant
235 QVariant call(PyObject* callable, const QVariantList& args = QVariantList());
235 QVariant call(PyObject* callable, const QVariantList& args = QVariantList());
236
236
237 //@}
237 //@}
238
238
239 //@{ Decorations, constructors, wrappers...
239 //@{ Decorations, constructors, wrappers...
240
240
241
241
242 //! add an object whose slots will be used as decorator slots for
242 //! add an object whose slots will be used as decorator slots for
243 //! other QObjects or CPP classes. The slots need to follow the
243 //! other QObjects or CPP classes. The slots need to follow the
244 //! convention that the first argument is a pointer to the wrapped object.
244 //! convention that the first argument is a pointer to the wrapped object.
245 //! (ownership is passed to PythonQt)
245 //! (ownership is passed to PythonQt)
246 /*!
246 /*!
247 Example:
247 Example:
248
248
249 A slot with the signature
249 A slot with the signature
250
250
251 \code
251 \code
252 bool doSomething(QWidget* w, int a)
252 bool doSomething(QWidget* w, int a)
253 \endcode
253 \endcode
254
254
255 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
255 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
256 that will be called with the concrete instance as first argument.
256 that will be called with the concrete instance as first argument.
257 So in Python you can now e.g. call
257 So in Python you can now e.g. call
258
258
259 \code
259 \code
260 someWidget.doSomething(12)
260 someWidget.doSomething(12)
261 \endcode
261 \endcode
262
262
263 without QWidget really having this method. This allows to easily make normal methods
263 without QWidget really having this method. This allows to easily make normal methods
264 of Qt classes callable by forwarding them with such decorator slots
264 of Qt classes callable by forwarding them with such decorator slots
265 or to make CPP classes (which are not derived from QObject) callable from Python.
265 or to make CPP classes (which are not derived from QObject) callable from Python.
266 */
266 */
267 void addInstanceDecorators(QObject* o);
267 void addInstanceDecorators(QObject* o);
268
268
269 //! add an object whose slots will be used as decorator slots for
269 //! add an object whose slots will be used as decorator slots for
270 //! class objects (ownership is passed to PythonQt)
270 //! class objects (ownership is passed to PythonQt)
271 /*!
271 /*!
272 The slots need to follow the following convention:
272 The slots need to follow the following convention:
273 - SomeClass* new_SomeClass(...)
273 - SomeClass* new_SomeClass(...)
274 - QVariant new_SomeClass(...)
274 - QVariant new_SomeClass(...)
275 - void delete_SomeClass(SomeClass*)
275 - void delete_SomeClass(SomeClass*)
276 - ... static_SomeClass_someName(...)
276 - ... static_SomeClass_someName(...)
277
277
278 This will add:
278 This will add:
279 - a constructor
279 - a constructor
280 - a constructor which generates a QVariant
280 - a constructor which generates a QVariant
281 - a destructor (only useful for CPP objects)
281 - a destructor (only useful for CPP objects)
282 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
282 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
283
283
284 */
284 */
285 void addClassDecorators(QObject* o);
285 void addClassDecorators(QObject* o);
286
286
287 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
287 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
288 void addDecorators(QObject* o);
288 void addDecorators(QObject* o);
289
289
290 //! add the given factory to PythonQt (ownership stays with caller)
290 //! add the given factory to PythonQt (ownership stays with caller)
291 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
291 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
292
292
293 //@}
293 //@}
294
294
295 //@{ Custom importer (to replace internal import implementation of python)
295 //@{ Custom importer (to replace internal import implementation of python)
296
296
297 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
297 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
298 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
298 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
299 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
299 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
300 //! This is not reversible, so even setting setImporter(NULL) afterwards will
300 //! This is not reversible, so even setting setImporter(NULL) afterwards will
301 //! keep the custom PythonQt importer with a QFile default import interface.
301 //! keep the custom PythonQt importer with a QFile default import interface.
302 //! Subsequent python import calls will make use of the passed importInterface
302 //! Subsequent python import calls will make use of the passed importInterface
303 //! which forwards all import calls to the given \c importInterface.
303 //! which forwards all import calls to the given \c importInterface.
304 //! Passing NULL will install a default QFile importer.
304 //! Passing NULL will install a default QFile importer.
305 //! (\c importInterface ownership stays with caller)
305 //! (\c importInterface ownership stays with caller)
306 void setImporter(PythonQtImportFileInterface* importInterface);
306 void setImporter(PythonQtImportFileInterface* importInterface);
307
307
308 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
308 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
309 //! (without calling setImporter or installDefaultImporter at least once, the default python import
309 //! (without calling setImporter or installDefaultImporter at least once, the default python import
310 //! mechanism is in place)
310 //! mechanism is in place)
311 //! the default importer allows to import files from anywhere QFile can read from,
311 //! the default importer allows to import files from anywhere QFile can read from,
312 //! including the Qt resource system using ":". Keep in mind that you need to extend
312 //! including the Qt resource system using ":". Keep in mind that you need to extend
313 //! "sys.path" with ":" to be able to import from the Qt resources.
313 //! "sys.path" with ":" to be able to import from the Qt resources.
314 void installDefaultImporter() { setImporter(NULL); }
314 void installDefaultImporter() { setImporter(NULL); }
315
315
316 //! set paths that the importer should ignore
316 //! set paths that the importer should ignore
317 void setImporterIgnorePaths(const QStringList& paths);
317 void setImporterIgnorePaths(const QStringList& paths);
318
318
319 //! get paths that the importer should ignore
319 //! get paths that the importer should ignore
320 const QStringList& getImporterIgnorePaths();
320 const QStringList& getImporterIgnorePaths();
321
321
322 //@}
322 //@}
323
323
324 //! get access to internal data (should not be used on the public API, but is used by some C functions)
324 //! get access to internal data (should not be used on the public API, but is used by some C functions)
325 static PythonQtPrivate* priv() { return _self->_p; }
325 static PythonQtPrivate* priv() { return _self->_p; }
326
326
327 //! get access to the file importer (if set)
327 //! get access to the file importer (if set)
328 static PythonQtImportFileInterface* importInterface();
328 static PythonQtImportFileInterface* importInterface();
329
329
330 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
330 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
331 //! The error is currently just output to the python stderr, future version might implement better trace printing
331 //! The error is currently just output to the python stderr, future version might implement better trace printing
332 bool handleError();
332 bool handleError();
333
333
334 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
334 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
335 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
335 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
336 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
336 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
337 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
337 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
338
338
339 //! call the callback if it is set
339 //! call the callback if it is set
340 static void qObjectNoLongerWrappedCB(QObject* o);
340 static void qObjectNoLongerWrappedCB(QObject* o);
341
341
342 signals:
342 signals:
343 //! emitted when python outputs something to stdout (and redirection is turned on)
343 //! emitted when python outputs something to stdout (and redirection is turned on)
344 void pythonStdOut(const QString& str);
344 void pythonStdOut(const QString& str);
345 //! emitted when python outputs something to stderr (and redirection is turned on)
345 //! emitted when python outputs something to stderr (and redirection is turned on)
346 void pythonStdErr(const QString& str);
346 void pythonStdErr(const QString& str);
347
347
348 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
348 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
349 void pythonHelpRequest(const QByteArray& cppClassName);
349 void pythonHelpRequest(const QByteArray& cppClassName);
350
350
351
351
352 public:
352 public:
353 //! called by internal help methods
353 //! called by internal help methods
354 PyObject* helpCalled(PythonQtClassInfo* info);
354 PyObject* helpCalled(PythonQtClassInfo* info);
355
355
356 //! returns the found object or NULL
356 //! returns the found object or NULL
357 //! @return new reference
357 //! @return new reference
358 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
358 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
359
359
360 private:
360 private:
361 void initPythonQtModule(bool redirectStdOut);
361 void initPythonQtModule(bool redirectStdOut);
362
362
363 //! callback for stdout redirection, emits pythonStdOut signal
363 //! callback for stdout redirection, emits pythonStdOut signal
364 static void stdOutRedirectCB(const QString& str);
364 static void stdOutRedirectCB(const QString& str);
365 //! callback for stderr redirection, emits pythonStdErr signal
365 //! callback for stderr redirection, emits pythonStdErr signal
366 static void stdErrRedirectCB(const QString& str);
366 static void stdErrRedirectCB(const QString& str);
367
367
368 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
368 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
369 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
369 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
370
370
371 PythonQt(int flags);
371 PythonQt(int flags);
372 ~PythonQt();
372 ~PythonQt();
373
373
374 static PythonQt* _self;
374 static PythonQt* _self;
375 static int _uniqueModuleCount;
375 static int _uniqueModuleCount;
376
376
377 PythonQtPrivate* _p;
377 PythonQtPrivate* _p;
378
378
379 };
379 };
380
380
381 //! internal PythonQt details
381 //! internal PythonQt details
382 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
382 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
383
383
384 Q_OBJECT
384 Q_OBJECT
385
385
386 public:
386 public:
387 PythonQtPrivate();
387 PythonQtPrivate();
388 ~PythonQtPrivate();
388 ~PythonQtPrivate();
389
389
390 enum DecoratorTypes {
390 enum DecoratorTypes {
391 StaticDecorator = 1,
391 StaticDecorator = 1,
392 ConstructorDecorator = 2,
392 ConstructorDecorator = 2,
393 DestructorDecorator = 4,
393 DestructorDecorator = 4,
394 InstanceDecorator = 8,
394 InstanceDecorator = 8,
395 AllDecorators = 0xffff
395 AllDecorators = 0xffff
396 };
396 };
397
397
398 //! returns if the id is the id for PythonQtObjectPtr
398 //! returns if the id is the id for PythonQtObjectPtr
399 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
399 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
400
400
401 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
401 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
402 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
402 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
403 //! remove the wrapper ptr again
403 //! remove the wrapper ptr again
404 void removeWrapperPointer(void* obj);
404 void removeWrapperPointer(void* obj);
405
405
406 //! add parent class relation
406 //! add parent class relation
407 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
407 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
408
408
409 //! add a handler for polymorphic downcasting
409 //! add a handler for polymorphic downcasting
410 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
410 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
411
411
412 //! lookup existing classinfo and return new if not yet present
412 //! lookup existing classinfo and return new if not yet present
413 PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
413 PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
414
414
415 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
415 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
416 void removeSignalEmitter(QObject* obj);
416 void removeSignalEmitter(QObject* obj);
417
417
418 //! wrap the given QObject into a Python object (or return existing wrapper!)
418 //! wrap the given QObject into a Python object (or return existing wrapper!)
419 PyObject* wrapQObject(QObject* obj);
419 PyObject* wrapQObject(QObject* obj);
420
420
421 //! 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
421 //! 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
422 PyObject* wrapPtr(void* ptr, const QByteArray& name);
422 PyObject* wrapPtr(void* ptr, const QByteArray& name);
423
423
424 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
424 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
425 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
425 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
426 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
426 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
427 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
427 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
428
428
429 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
429 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
430 //! (ownership of wrapper is passed to PythonQt)
430 //! (ownership of wrapper is passed to PythonQt)
431 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
431 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
432
432
433 This will add a wrapper object that is used to make calls to the given classname \c typeName.
433 This will add a wrapper object that is used to make calls to the given classname \c typeName.
434 All slots that take a pointer to typeName as the first argument will be callable from Python on
434 All slots that take a pointer to typeName as the first argument will be callable from Python on
435 a variant object that contains such a type.
435 a variant object that contains such a type.
436 */
436 */
437 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
437 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
438
438
439 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
439 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
440 //! and it will register the classes when it first sees a pointer to such a derived class
440 //! and it will register the classes when it first sees a pointer to such a derived class
441 void registerQObjectClassNames(const QStringList& names);
441 void registerQObjectClassNames(const QStringList& names);
442
442
443 //! add a decorator object
443 //! add a decorator object
444 void addDecorators(QObject* o, int decoTypes);
444 void addDecorators(QObject* o, int decoTypes);
445
445
446 //! helper method that creates a PythonQtClassWrapper object (returns a new reference)
446 //! helper method that creates a PythonQtClassWrapper object (returns a new reference)
447 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package = NULL);
447 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package = NULL);
448
448
449 //! create a new instance of the given enum type with given value (returns a new reference)
449 //! create a new instance of the given enum type with given value (returns a new reference)
450 static PyObject* createEnumValueInstance(PyObject* enumType, unsigned int enumValue);
450 static PyObject* createEnumValueInstance(PyObject* enumType, unsigned int enumValue);
451
451
452 //! helper that creates a new int derived class that represents the enum of the given name (returns a new reference)
452 //! helper that creates a new int derived class that represents the enum of the given name (returns a new reference)
453 static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
453 static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
454
454
455 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
455 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
456 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
456 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
457
457
458 //! get the class info for a meta object (if available)
458 //! get the class info for a meta object (if available)
459 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
459 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
460
460
461 //! get the class info for a meta object (if available)
461 //! get the class info for a meta object (if available)
462 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
462 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
463
463
464 //! creates the new module from the given pycode
464 //! creates the new module from the given pycode
465 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
465 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
466
466
467 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
467 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
468 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
468 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
469
469
470 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
470 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
471 static PyObject* dummyTuple();
471 static PyObject* dummyTuple();
472
472
473 //! called by virtual overloads when a python return value can not be converted to the required Qt type
474 void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result);
475
473 private:
476 private:
474
477
475 //! create a new pythonqt class wrapper and place it in the pythonqt module
478 //! create a new pythonqt class wrapper and place it in the pythonqt module
476 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package);
479 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package);
477
480
478 //! get/create new package module (the returned object is a borrowed reference)
481 //! get/create new package module (the returned object is a borrowed reference)
479 PyObject* packageByName(const char* name);
482 PyObject* packageByName(const char* name);
480
483
481 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
484 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
482 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
485 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
483
486
484 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
487 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
485 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
488 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
486
489
487 //! stores the meta info of known Qt classes
490 //! stores the meta info of known Qt classes
488 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
491 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
489
492
490 //! names of qobject derived classes that can be casted to qobject savely
493 //! names of qobject derived classes that can be casted to qobject savely
491 QHash<QByteArray, bool> _knownQObjectClassNames;
494 QHash<QByteArray, bool> _knownQObjectClassNames;
492
495
493 //! stores signal receivers for QObjects
496 //! stores signal receivers for QObjects
494 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
497 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
495
498
496 //! the PythonQt python module
499 //! the PythonQt python module
497 PythonQtObjectPtr _pythonQtModule;
500 PythonQtObjectPtr _pythonQtModule;
498
501
499 //! the importer interface (if set)
502 //! the importer interface (if set)
500 PythonQtImportFileInterface* _importInterface;
503 PythonQtImportFileInterface* _importInterface;
501
504
502 //! the default importer
505 //! the default importer
503 PythonQtQFileImporter* _defaultImporter;
506 PythonQtQFileImporter* _defaultImporter;
504
507
505 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
508 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
506 PythonQtQObjectWrappedCB* _wrappedCB;
509 PythonQtQObjectWrappedCB* _wrappedCB;
507
510
508 QStringList _importIgnorePaths;
511 QStringList _importIgnorePaths;
509
512
510 //! the cpp object wrapper factories
513 //! the cpp object wrapper factories
511 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
514 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
512
515
513 QHash<QByteArray, PyObject*> _packages;
516 QHash<QByteArray, PyObject*> _packages;
514
517
515 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
518 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
516
519
517 int _initFlags;
520 int _initFlags;
518 int _PythonQtObjectPtr_metaId;
521 int _PythonQtObjectPtr_metaId;
519
522
520 friend class PythonQt;
523 friend class PythonQt;
521 };
524 };
522
525
523 #endif
526 #endif
@@ -1,826 +1,841
1 /*
1 /*
2 *
2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 *
4 *
5 * This library is free software; you can redistribute it and/or
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
8 * version 2.1 of the License, or (at your option) any later version.
9 *
9 *
10 * This library is distributed in the hope that it will be useful,
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
13 * Lesser General Public License for more details.
14 *
14 *
15 * Further, this software is distributed without any warranty that it is
15 * Further, this software is distributed without any warranty that it is
16 * free of the rightful claim of any third person regarding infringement
16 * free of the rightful claim of any third person regarding infringement
17 * or the like. Any license provided herein, whether implied or
17 * or the like. Any license provided herein, whether implied or
18 * otherwise, applies only to this software file. Patent licenses, if
18 * otherwise, applies only to this software file. Patent licenses, if
19 * any, provided herein do not apply to combinations of this program with
19 * any, provided herein do not apply to combinations of this program with
20 * other software, or any other product whatsoever.
20 * other software, or any other product whatsoever.
21 *
21 *
22 * You should have received a copy of the GNU Lesser General Public
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 * 28359 Bremen, Germany or:
27 * 28359 Bremen, Germany or:
28 *
28 *
29 * http://www.mevis.de
29 * http://www.mevis.de
30 *
30 *
31 */
31 */
32
32
33 //----------------------------------------------------------------------------------
33 //----------------------------------------------------------------------------------
34 /*!
34 /*!
35 // \file PythonQt.cpp
35 // \file PythonQt.cpp
36 // \author Florian Link
36 // \author Florian Link
37 // \author Last changed by $Author: florian $
37 // \author Last changed by $Author: florian $
38 // \date 2006-05
38 // \date 2006-05
39 */
39 */
40 //----------------------------------------------------------------------------------
40 //----------------------------------------------------------------------------------
41
41
42 #include "PythonQtClassInfo.h"
42 #include "PythonQtClassInfo.h"
43 #include "PythonQtMethodInfo.h"
43 #include "PythonQtMethodInfo.h"
44 #include "PythonQt.h"
44 #include "PythonQt.h"
45 #include <QMetaMethod>
45 #include <QMetaMethod>
46 #include <QMetaObject>
46 #include <QMetaObject>
47 #include <QMetaEnum>
47 #include <QMetaEnum>
48
48
49 QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;
49 QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;
50
50
51 PythonQtClassInfo::PythonQtClassInfo() {
51 PythonQtClassInfo::PythonQtClassInfo() {
52 _meta = NULL;
52 _meta = NULL;
53 _constructors = NULL;
53 _constructors = NULL;
54 _destructor = NULL;
54 _destructor = NULL;
55 _decoratorProvider = NULL;
55 _decoratorProvider = NULL;
56 _decoratorProviderCB = NULL;
56 _decoratorProviderCB = NULL;
57 _pythonQtClassWrapper = NULL;
57 _pythonQtClassWrapper = NULL;
58 _shellSetInstanceWrapperCB = NULL;
58 _shellSetInstanceWrapperCB = NULL;
59 _metaTypeId = -1;
59 _metaTypeId = -1;
60 _isQObject = false;
60 _isQObject = false;
61 _enumsCreated = false;
61 _enumsCreated = false;
62 }
62 }
63
63
64 PythonQtClassInfo::~PythonQtClassInfo()
64 PythonQtClassInfo::~PythonQtClassInfo()
65 {
65 {
66 clearCachedMembers();
66 clearCachedMembers();
67
67
68 if (_constructors) {
68 if (_constructors) {
69 _constructors->deleteOverloadsAndThis();
69 _constructors->deleteOverloadsAndThis();
70 }
70 }
71 if (_destructor) {
71 if (_destructor) {
72 _destructor->deleteOverloadsAndThis();
72 _destructor->deleteOverloadsAndThis();
73 }
73 }
74 foreach(PythonQtSlotInfo* info, _decoratorSlots) {
74 foreach(PythonQtSlotInfo* info, _decoratorSlots) {
75 info->deleteOverloadsAndThis();
75 info->deleteOverloadsAndThis();
76 }
76 }
77 }
77 }
78
78
79 void PythonQtClassInfo::setupQObject(const QMetaObject* meta)
79 void PythonQtClassInfo::setupQObject(const QMetaObject* meta)
80 {
80 {
81 // _wrappedClassName is already set earlier in the class setup
81 // _wrappedClassName is already set earlier in the class setup
82 _isQObject = true;
82 _isQObject = true;
83 _meta = meta;
83 _meta = meta;
84 }
84 }
85
85
86 void PythonQtClassInfo::setupCPPObject(const QByteArray& classname)
86 void PythonQtClassInfo::setupCPPObject(const QByteArray& classname)
87 {
87 {
88 _isQObject = false;
88 _isQObject = false;
89 _wrappedClassName = classname;
89 _wrappedClassName = classname;
90 _metaTypeId = QMetaType::type(classname);
90 _metaTypeId = QMetaType::type(classname);
91 }
91 }
92
92
93 void PythonQtClassInfo::clearCachedMembers()
93 void PythonQtClassInfo::clearCachedMembers()
94 {
94 {
95 QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers);
95 QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers);
96 while (i.hasNext()) {
96 while (i.hasNext()) {
97 PythonQtMemberInfo member = i.next().value();
97 PythonQtMemberInfo member = i.next().value();
98 if (member._type== PythonQtMemberInfo::Slot) {
98 if (member._type== PythonQtMemberInfo::Slot) {
99 PythonQtSlotInfo* info = member._slot;
99 PythonQtSlotInfo* info = member._slot;
100 while (info) {
100 while (info) {
101 PythonQtSlotInfo* next = info->nextInfo();
101 PythonQtSlotInfo* next = info->nextInfo();
102 delete info;
102 delete info;
103 info = next;
103 info = next;
104 }
104 }
105 }
105 }
106 }
106 }
107 }
107 }
108
108
109 int PythonQtClassInfo::findCharOffset(const char* sigStart, char someChar)
109 int PythonQtClassInfo::findCharOffset(const char* sigStart, char someChar)
110 {
110 {
111 const char* sigEnd = sigStart;
111 const char* sigEnd = sigStart;
112 char c;
112 char c;
113 do {
113 do {
114 c = *sigEnd++;
114 c = *sigEnd++;
115 } while (c!=someChar && c!=0);
115 } while (c!=someChar && c!=0);
116 return sigEnd-sigStart-1;
116 return sigEnd-sigStart-1;
117 }
117 }
118
118
119 bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName)
119 bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName)
120 {
120 {
121 bool found = false;
121 bool found = false;
122 bool nameMapped = false;
122 bool nameMapped = false;
123 const char* attributeName = memberName;
123 const char* attributeName = memberName;
124 // look for properties
124 // look for properties
125 int i = _meta->indexOfProperty(attributeName);
125 int i = _meta->indexOfProperty(attributeName);
126 if (i==-1) {
126 if (i==-1) {
127 // try to map name to objectName
127 // try to map name to objectName
128 if (qstrcmp(attributeName, "name")==0) {
128 if (qstrcmp(attributeName, "name")==0) {
129 attributeName = "objectName";
129 attributeName = "objectName";
130 nameMapped = true;
130 nameMapped = true;
131 i = _meta->indexOfProperty(attributeName);
131 i = _meta->indexOfProperty(attributeName);
132 }
132 }
133 }
133 }
134 if (i!=-1) {
134 if (i!=-1) {
135 PythonQtMemberInfo newInfo(_meta->property(i));
135 PythonQtMemberInfo newInfo(_meta->property(i));
136 _cachedMembers.insert(attributeName, newInfo);
136 _cachedMembers.insert(attributeName, newInfo);
137 if (nameMapped) {
137 if (nameMapped) {
138 _cachedMembers.insert(memberName, newInfo);
138 _cachedMembers.insert(memberName, newInfo);
139 }
139 }
140 #ifdef PYTHONQT_DEBUG
140 #ifdef PYTHONQT_DEBUG
141 std::cout << "caching property " << memberName << " on " << _meta->className() << std::endl;
141 std::cout << "caching property " << memberName << " on " << _meta->className() << std::endl;
142 #endif
142 #endif
143 found = true;
143 found = true;
144 }
144 }
145 return found;
145 return found;
146 }
146 }
147
147
148 PythonQtSlotInfo* PythonQtClassInfo::recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
148 PythonQtSlotInfo* PythonQtClassInfo::recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
149 {
149 {
150 inputInfo = findDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset);
150 inputInfo = findDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset);
151 foreach(const ParentClassInfo& info, _parentClasses) {
151 foreach(const ParentClassInfo& info, _parentClasses) {
152 inputInfo = info._parent->recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset+info._upcastingOffset);
152 inputInfo = info._parent->recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset+info._upcastingOffset);
153 }
153 }
154 return inputInfo;
154 return inputInfo;
155 }
155 }
156
156
157 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset) {
157 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset) {
158 QObject* decoratorProvider = decorator();
158 QObject* decoratorProvider = decorator();
159 int memberNameLen = strlen(memberName);
159 int memberNameLen = strlen(memberName);
160 if (decoratorProvider) {
160 if (decoratorProvider) {
161 //qDebug()<< "looking " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
161 //qDebug()<< "looking " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
162 const QMetaObject* meta = decoratorProvider->metaObject();
162 const QMetaObject* meta = decoratorProvider->metaObject();
163 int numMethods = meta->methodCount();
163 int numMethods = meta->methodCount();
164 int startFrom = QObject::staticMetaObject.methodCount();
164 int startFrom = QObject::staticMetaObject.methodCount();
165 for (int i = startFrom; i < numMethods; i++) {
165 for (int i = startFrom; i < numMethods; i++) {
166 QMetaMethod m = meta->method(i);
166 QMetaMethod m = meta->method(i);
167 if ((m.methodType() == QMetaMethod::Method ||
167 if ((m.methodType() == QMetaMethod::Method ||
168 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
168 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
169
169
170 const char* sigStart = m.signature();
170 const char* sigStart = m.signature();
171 bool isClassDeco = false;
171 bool isClassDeco = false;
172 if (qstrncmp(sigStart, "static_", 7)==0) {
172 if (qstrncmp(sigStart, "static_", 7)==0) {
173 // skip the static_classname_ part of the string
173 // skip the static_classname_ part of the string
174 sigStart += 7 + 1 + strlen(className());
174 sigStart += 7 + 1 + strlen(className());
175 isClassDeco = true;
175 isClassDeco = true;
176 } else if (qstrncmp(sigStart, "new_", 4)==0) {
176 } else if (qstrncmp(sigStart, "new_", 4)==0) {
177 isClassDeco = true;
177 isClassDeco = true;
178 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
178 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
179 isClassDeco = true;
179 isClassDeco = true;
180 }
180 }
181 // find the first '('
181 // find the first '('
182 int offset = findCharOffset(sigStart, '(');
182 int offset = findCharOffset(sigStart, '(');
183
183
184 // XXX no checking is currently done if the slots have correct first argument or not...
184 // XXX no checking is currently done if the slots have correct first argument or not...
185
185
186 // check if same length and same name
186 // check if same length and same name
187 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
187 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
188 found = true;
188 found = true;
189 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i, decoratorProvider, isClassDeco?PythonQtSlotInfo::ClassDecorator:PythonQtSlotInfo::InstanceDecorator);
189 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i, decoratorProvider, isClassDeco?PythonQtSlotInfo::ClassDecorator:PythonQtSlotInfo::InstanceDecorator);
190 info->setUpcastingOffset(upcastingOffset);
190 info->setUpcastingOffset(upcastingOffset);
191 //qDebug()<< "adding " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
191 //qDebug()<< "adding " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
192 if (tail) {
192 if (tail) {
193 tail->setNextInfo(info);
193 tail->setNextInfo(info);
194 } else {
194 } else {
195 PythonQtMemberInfo newInfo(info);
195 PythonQtMemberInfo newInfo(info);
196 memberCache.insert(memberName, newInfo);
196 memberCache.insert(memberName, newInfo);
197 }
197 }
198 tail = info;
198 tail = info;
199 }
199 }
200 }
200 }
201 }
201 }
202 }
202 }
203
203
204 tail = findDecoratorSlots(memberName, memberNameLen, tail, found, memberCache, upcastingOffset);
204 tail = findDecoratorSlots(memberName, memberNameLen, tail, found, memberCache, upcastingOffset);
205
205
206 return tail;
206 return tail;
207 }
207 }
208
208
209 bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName)
209 bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName)
210 {
210 {
211 bool found = false;
211 bool found = false;
212 int memberNameLen = strlen(memberName);
212 int memberNameLen = strlen(memberName);
213 PythonQtSlotInfo* tail = NULL;
213 PythonQtSlotInfo* tail = NULL;
214 if (_meta) {
214 if (_meta) {
215 int numMethods = _meta->methodCount();
215 int numMethods = _meta->methodCount();
216 for (int i = 0; i < numMethods; i++) {
216 for (int i = 0; i < numMethods; i++) {
217 QMetaMethod m = _meta->method(i);
217 QMetaMethod m = _meta->method(i);
218 if ((m.methodType() == QMetaMethod::Method ||
218 if ((m.methodType() == QMetaMethod::Method ||
219 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
219 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
220
220
221 const char* sigStart = m.signature();
221 const char* sigStart = m.signature();
222 // find the first '('
222 // find the first '('
223 int offset = findCharOffset(sigStart, '(');
223 int offset = findCharOffset(sigStart, '(');
224
224
225 // check if same length and same name
225 // check if same length and same name
226 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
226 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
227 found = true;
227 found = true;
228 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i);
228 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i);
229 if (tail) {
229 if (tail) {
230 tail->setNextInfo(info);
230 tail->setNextInfo(info);
231 } else {
231 } else {
232 PythonQtMemberInfo newInfo(info);
232 PythonQtMemberInfo newInfo(info);
233 _cachedMembers.insert(memberName, newInfo);
233 _cachedMembers.insert(memberName, newInfo);
234 }
234 }
235 tail = info;
235 tail = info;
236 }
236 }
237 }
237 }
238 }
238 }
239 }
239 }
240
240
241 // look for dynamic decorators in this class and in derived classes
241 // look for dynamic decorators in this class and in derived classes
242 tail = recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, tail, found, _cachedMembers, 0);
242 tail = recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, tail, found, _cachedMembers, 0);
243
243
244 return found;
244 return found;
245 }
245 }
246
246
247 bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* memberName)
247 bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* memberName)
248 {
248 {
249 bool found = false;
249 bool found = false;
250 // look for enum values
250 // look for enum values
251 int enumCount = meta->enumeratorCount();
251 int enumCount = meta->enumeratorCount();
252 for (int i=0;i<enumCount; i++) {
252 for (int i=0;i<enumCount; i++) {
253 QMetaEnum e = meta->enumerator(i);
253 QMetaEnum e = meta->enumerator(i);
254 // we do not want flags, they will cause our values to appear two times
254 // we do not want flags, they will cause our values to appear two times
255 if (e.isFlag()) continue;
255 if (e.isFlag()) continue;
256
256
257 for (int j=0; j < e.keyCount(); j++) {
257 for (int j=0; j < e.keyCount(); j++) {
258 if (qstrcmp(e.key(j), memberName)==0) {
258 if (qstrcmp(e.key(j), memberName)==0) {
259 PyObject* enumType = findEnumWrapper(e.name());
259 PyObject* enumType = findEnumWrapper(e.name());
260 if (enumType) {
260 if (enumType) {
261 PythonQtObjectPtr enumValuePtr;
261 PythonQtObjectPtr enumValuePtr;
262 enumValuePtr.setNewRef(PythonQtPrivate::createEnumValueInstance(enumType, e.value(j)));
262 enumValuePtr.setNewRef(PythonQtPrivate::createEnumValueInstance(enumType, e.value(j)));
263 PythonQtMemberInfo newInfo(enumValuePtr);
263 PythonQtMemberInfo newInfo(enumValuePtr);
264 _cachedMembers.insert(memberName, newInfo);
264 _cachedMembers.insert(memberName, newInfo);
265 #ifdef PYTHONQT_DEBUG
265 #ifdef PYTHONQT_DEBUG
266 std::cout << "caching enum " << memberName << " on " << meta->className() << std::endl;
266 std::cout << "caching enum " << memberName << " on " << meta->className() << std::endl;
267 #endif
267 #endif
268 found = true;
268 found = true;
269 break;
269 break;
270 } else {
270 } else {
271 std::cout << "enum " << e.name() << " not found on " << className() << std::endl;
271 std::cout << "enum " << e.name() << " not found on " << className() << std::endl;
272 }
272 }
273 }
273 }
274 }
274 }
275 }
275 }
276 return found;
276 return found;
277 }
277 }
278
278
279 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
279 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
280 {
280 {
281 PythonQtMemberInfo info = _cachedMembers.value(memberName);
281 PythonQtMemberInfo info = _cachedMembers.value(memberName);
282 if (info._type != PythonQtMemberInfo::Invalid) {
282 if (info._type != PythonQtMemberInfo::Invalid) {
283 return info;
283 return info;
284 } else {
284 } else {
285 bool found = false;
285 bool found = false;
286
286
287 found = lookForPropertyAndCache(memberName);
287 found = lookForPropertyAndCache(memberName);
288 if (!found) {
288 if (!found) {
289 found = lookForMethodAndCache(memberName);
289 found = lookForMethodAndCache(memberName);
290 }
290 }
291 if (!found) {
291 if (!found) {
292 if (_meta) {
292 if (_meta) {
293 // check enums in our meta object directly
293 // check enums in our meta object directly
294 found = lookForEnumAndCache(_meta, memberName);
294 found = lookForEnumAndCache(_meta, memberName);
295 }
295 }
296 if (!found) {
296 if (!found) {
297 // check enums in the class hierachy of CPP classes
297 // check enums in the class hierachy of CPP classes
298 // look for dynamic decorators in this class and in derived classes
298 // look for dynamic decorators in this class and in derived classes
299 QList<QObject*> decoObjects;
299 QList<QObject*> decoObjects;
300 recursiveCollectDecoratorObjects(decoObjects);
300 recursiveCollectDecoratorObjects(decoObjects);
301 foreach(QObject* deco, decoObjects) {
301 foreach(QObject* deco, decoObjects) {
302 // call on ourself for caching, but with different metaObject():
302 // call on ourself for caching, but with different metaObject():
303 found = lookForEnumAndCache(deco->metaObject(), memberName);
303 found = lookForEnumAndCache(deco->metaObject(), memberName);
304 if (found) {
304 if (found) {
305 break;
305 break;
306 }
306 }
307 }
307 }
308 }
308 }
309 }
309 }
310 if (!found) {
310 if (!found) {
311 // maybe it is an enum wrapper?
311 PyObject* p = findEnumWrapper(memberName);
312 PyObject* p = findEnumWrapper(memberName);
312 if (p) {
313 if (p) {
313 info._type = PythonQtMemberInfo::EnumWrapper;
314 info._type = PythonQtMemberInfo::EnumWrapper;
314 info._enumWrapper = p;
315 info._enumWrapper = p;
315 _cachedMembers.insert(memberName, info);
316 _cachedMembers.insert(memberName, info);
316 found = true;
317 found = true;
317 }
318 }
318 }
319 }
319 if (!found) {
320 if (!found) {
321 // since python keywords can not be looked up, we check if the name contains a single trailing _
322 // and remove that and look again, so that we e.g. find exec on an exec_ lookup
323 QByteArray mbrName(memberName);
324 if ((mbrName.length()>2) &&
325 (mbrName.at(mbrName.length()-1) == '_') &&
326 (mbrName.at(mbrName.length()-2) != '_')) {
327 mbrName = mbrName.mid(0,mbrName.length()-1);
328 found = lookForMethodAndCache(mbrName.constData());
329 if (found) {
330 return _cachedMembers.value(mbrName);
331 }
332 }
333 }
334 if (!found) {
320 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
335 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
321 info._type = PythonQtMemberInfo::NotFound;
336 info._type = PythonQtMemberInfo::NotFound;
322 _cachedMembers.insert(memberName, info);
337 _cachedMembers.insert(memberName, info);
323 }
338 }
324 }
339 }
325
340
326 return _cachedMembers.value(memberName);
341 return _cachedMembers.value(memberName);
327 }
342 }
328
343
329 void PythonQtClassInfo::recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects) {
344 void PythonQtClassInfo::recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects) {
330 QObject* deco = decorator();
345 QObject* deco = decorator();
331 if (deco) {
346 if (deco) {
332 decoratorObjects.append(deco);
347 decoratorObjects.append(deco);
333 }
348 }
334 foreach(const ParentClassInfo& info, _parentClasses) {
349 foreach(const ParentClassInfo& info, _parentClasses) {
335 info._parent->recursiveCollectDecoratorObjects(decoratorObjects);
350 info._parent->recursiveCollectDecoratorObjects(decoratorObjects);
336 }
351 }
337 }
352 }
338
353
339 void PythonQtClassInfo::recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects) {
354 void PythonQtClassInfo::recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects) {
340 classInfoObjects.append(this);
355 classInfoObjects.append(this);
341 foreach(const ParentClassInfo& info, _parentClasses) {
356 foreach(const ParentClassInfo& info, _parentClasses) {
342 info._parent->recursiveCollectClassInfos(classInfoObjects);
357 info._parent->recursiveCollectClassInfos(classInfoObjects);
343 }
358 }
344 }
359 }
345
360
346 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
361 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
347 {
362 {
348 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
363 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
349 while (it.hasNext()) {
364 while (it.hasNext()) {
350
365
351 PythonQtSlotInfo* infoOrig = it.next();
366 PythonQtSlotInfo* infoOrig = it.next();
352
367
353 const char* sigStart = infoOrig->metaMethod()->signature();
368 const char* sigStart = infoOrig->metaMethod()->signature();
354 if (qstrncmp("static_", sigStart, 7)==0) {
369 if (qstrncmp("static_", sigStart, 7)==0) {
355 sigStart += 7;
370 sigStart += 7;
356 sigStart += findCharOffset(sigStart, '_')+1;
371 sigStart += findCharOffset(sigStart, '_')+1;
357 }
372 }
358 int offset = findCharOffset(sigStart, '(');
373 int offset = findCharOffset(sigStart, '(');
359 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
374 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
360 //make a copy, otherwise we will have trouble on overloads!
375 //make a copy, otherwise we will have trouble on overloads!
361 PythonQtSlotInfo* info = new PythonQtSlotInfo(*infoOrig);
376 PythonQtSlotInfo* info = new PythonQtSlotInfo(*infoOrig);
362 info->setUpcastingOffset(upcastingOffset);
377 info->setUpcastingOffset(upcastingOffset);
363 found = true;
378 found = true;
364 if (tail) {
379 if (tail) {
365 tail->setNextInfo(info);
380 tail->setNextInfo(info);
366 } else {
381 } else {
367 PythonQtMemberInfo newInfo(info);
382 PythonQtMemberInfo newInfo(info);
368 memberCache.insert(memberName, newInfo);
383 memberCache.insert(memberName, newInfo);
369 }
384 }
370 tail = info;
385 tail = info;
371 }
386 }
372 }
387 }
373 return tail;
388 return tail;
374 }
389 }
375
390
376 void PythonQtClassInfo::listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly) {
391 void PythonQtClassInfo::listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly) {
377 QObject* decoratorProvider = decorator();
392 QObject* decoratorProvider = decorator();
378 if (decoratorProvider) {
393 if (decoratorProvider) {
379 const QMetaObject* meta = decoratorProvider->metaObject();
394 const QMetaObject* meta = decoratorProvider->metaObject();
380 int numMethods = meta->methodCount();
395 int numMethods = meta->methodCount();
381 int startFrom = QObject::staticMetaObject.methodCount();
396 int startFrom = QObject::staticMetaObject.methodCount();
382 for (int i = startFrom; i < numMethods; i++) {
397 for (int i = startFrom; i < numMethods; i++) {
383 QMetaMethod m = meta->method(i);
398 QMetaMethod m = meta->method(i);
384 if ((m.methodType() == QMetaMethod::Method ||
399 if ((m.methodType() == QMetaMethod::Method ||
385 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
400 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
386
401
387 const char* sigStart = m.signature();
402 const char* sigStart = m.signature();
388 bool isClassDeco = false;
403 bool isClassDeco = false;
389 if (qstrncmp(sigStart, "static_", 7)==0) {
404 if (qstrncmp(sigStart, "static_", 7)==0) {
390 // skip the static_classname_ part of the string
405 // skip the static_classname_ part of the string
391 sigStart += 7 + 1 + strlen(className());
406 sigStart += 7 + 1 + strlen(className());
392 isClassDeco = true;
407 isClassDeco = true;
393 } else if (qstrncmp(sigStart, "new_", 4)==0) {
408 } else if (qstrncmp(sigStart, "new_", 4)==0) {
394 continue;
409 continue;
395 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
410 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
396 continue;
411 continue;
397 }
412 }
398 // find the first '('
413 // find the first '('
399 int offset = findCharOffset(sigStart, '(');
414 int offset = findCharOffset(sigStart, '(');
400
415
401 // XXX no checking is currently done if the slots have correct first argument or not...
416 // XXX no checking is currently done if the slots have correct first argument or not...
402 if (!metaOnly || isClassDeco) {
417 if (!metaOnly || isClassDeco) {
403 list << QString::fromLatin1(sigStart, offset);
418 list << QString::fromLatin1(sigStart, offset);
404 }
419 }
405 }
420 }
406 }
421 }
407 }
422 }
408
423
409 // look for global decorator slots
424 // look for global decorator slots
410 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
425 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
411 while (it.hasNext()) {
426 while (it.hasNext()) {
412 PythonQtSlotInfo* slot = it.next();
427 PythonQtSlotInfo* slot = it.next();
413 if (metaOnly) {
428 if (metaOnly) {
414 if (slot->isClassDecorator()) {
429 if (slot->isClassDecorator()) {
415 QByteArray first = slot->slotName();
430 QByteArray first = slot->slotName();
416 if (first.startsWith("static_")) {
431 if (first.startsWith("static_")) {
417 int idx = first.indexOf('_');
432 int idx = first.indexOf('_');
418 idx = first.indexOf('_', idx+1);
433 idx = first.indexOf('_', idx+1);
419 first = first.mid(idx+1);
434 first = first.mid(idx+1);
420 }
435 }
421 list << first;
436 list << first;
422 }
437 }
423 } else {
438 } else {
424 list << slot->slotName();
439 list << slot->slotName();
425 }
440 }
426 }
441 }
427 }
442 }
428
443
429 QStringList PythonQtClassInfo::propertyList()
444 QStringList PythonQtClassInfo::propertyList()
430 {
445 {
431 QStringList l;
446 QStringList l;
432 if (_isQObject && _meta) {
447 if (_isQObject && _meta) {
433 int i;
448 int i;
434 int numProperties = _meta->propertyCount();
449 int numProperties = _meta->propertyCount();
435 for (i = 0; i < numProperties; i++) {
450 for (i = 0; i < numProperties; i++) {
436 QMetaProperty p = _meta->property(i);
451 QMetaProperty p = _meta->property(i);
437 l << QString(p.name());
452 l << QString(p.name());
438 }
453 }
439 }
454 }
440 return l;
455 return l;
441 }
456 }
442
457
443 QStringList PythonQtClassInfo::memberList(bool metaOnly)
458 QStringList PythonQtClassInfo::memberList(bool metaOnly)
444 {
459 {
445 decorator();
460 decorator();
446
461
447 QStringList l;
462 QStringList l;
448 QString h;
463 QString h;
449 if (_isQObject && _meta && !metaOnly) {
464 if (_isQObject && _meta && !metaOnly) {
450 l = propertyList();
465 l = propertyList();
451 }
466 }
452
467
453 // normal slots of QObject (or wrapper QObject)
468 // normal slots of QObject (or wrapper QObject)
454 if (!metaOnly && _meta) {
469 if (!metaOnly && _meta) {
455 int numMethods = _meta->methodCount();
470 int numMethods = _meta->methodCount();
456 bool skipQObj = !_isQObject;
471 bool skipQObj = !_isQObject;
457 for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) {
472 for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) {
458 QMetaMethod m = _meta->method(i);
473 QMetaMethod m = _meta->method(i);
459 if ((m.methodType() == QMetaMethod::Method ||
474 if ((m.methodType() == QMetaMethod::Method ||
460 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
475 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
461 QByteArray signa(m.signature());
476 QByteArray signa(m.signature());
462 signa = signa.left(signa.indexOf('('));
477 signa = signa.left(signa.indexOf('('));
463 l << signa;
478 l << signa;
464 }
479 }
465 }
480 }
466 }
481 }
467
482
468 {
483 {
469 // look for dynamic decorators in this class and in derived classes
484 // look for dynamic decorators in this class and in derived classes
470 QList<PythonQtClassInfo*> infos;
485 QList<PythonQtClassInfo*> infos;
471 recursiveCollectClassInfos(infos);
486 recursiveCollectClassInfos(infos);
472 foreach(PythonQtClassInfo* info, infos) {
487 foreach(PythonQtClassInfo* info, infos) {
473 info->listDecoratorSlotsFromDecoratorProvider(l, metaOnly);
488 info->listDecoratorSlotsFromDecoratorProvider(l, metaOnly);
474 }
489 }
475 }
490 }
476
491
477 // List enumerator keys...
492 // List enumerator keys...
478 QList<const QMetaObject*> enumMetaObjects;
493 QList<const QMetaObject*> enumMetaObjects;
479 if (_meta) {
494 if (_meta) {
480 enumMetaObjects << _meta;
495 enumMetaObjects << _meta;
481 }
496 }
482 // check enums in the class hierachy of CPP classes
497 // check enums in the class hierachy of CPP classes
483 QList<QObject*> decoObjects;
498 QList<QObject*> decoObjects;
484 recursiveCollectDecoratorObjects(decoObjects);
499 recursiveCollectDecoratorObjects(decoObjects);
485 foreach(QObject* deco, decoObjects) {
500 foreach(QObject* deco, decoObjects) {
486 enumMetaObjects << deco->metaObject();
501 enumMetaObjects << deco->metaObject();
487 }
502 }
488
503
489 foreach(const QMetaObject* meta, enumMetaObjects) {
504 foreach(const QMetaObject* meta, enumMetaObjects) {
490 for (int i = 0; i<meta->enumeratorCount(); i++) {
505 for (int i = 0; i<meta->enumeratorCount(); i++) {
491 QMetaEnum e = meta->enumerator(i);
506 QMetaEnum e = meta->enumerator(i);
492 l << e.name();
507 l << e.name();
493 // we do not want flags, they will cause our values to appear two times
508 // we do not want flags, they will cause our values to appear two times
494 if (e.isFlag()) continue;
509 if (e.isFlag()) continue;
495
510
496 for (int j=0; j < e.keyCount(); j++) {
511 for (int j=0; j < e.keyCount(); j++) {
497 l << QString(e.key(j));
512 l << QString(e.key(j));
498 }
513 }
499 }
514 }
500 }
515 }
501
516
502 return QSet<QString>::fromList(l).toList();
517 return QSet<QString>::fromList(l).toList();
503 }
518 }
504
519
505 const char* PythonQtClassInfo::className()
520 const char* PythonQtClassInfo::className()
506 {
521 {
507 return _wrappedClassName.constData();
522 return _wrappedClassName.constData();
508 }
523 }
509
524
510 void* PythonQtClassInfo::castTo(void* ptr, const char* classname)
525 void* PythonQtClassInfo::castTo(void* ptr, const char* classname)
511 {
526 {
512 if (ptr==NULL) {
527 if (ptr==NULL) {
513 return NULL;
528 return NULL;
514 }
529 }
515 if (_wrappedClassName == classname) {
530 if (_wrappedClassName == classname) {
516 return ptr;
531 return ptr;
517 }
532 }
518 foreach(const ParentClassInfo& info, _parentClasses) {
533 foreach(const ParentClassInfo& info, _parentClasses) {
519 void* result = info._parent->castTo((char*)ptr + info._upcastingOffset, classname);
534 void* result = info._parent->castTo((char*)ptr + info._upcastingOffset, classname);
520 if (result) {
535 if (result) {
521 return result;
536 return result;
522 }
537 }
523 }
538 }
524 return NULL;
539 return NULL;
525 }
540 }
526
541
527 bool PythonQtClassInfo::inherits(const char* name)
542 bool PythonQtClassInfo::inherits(const char* name)
528 {
543 {
529 if (_wrappedClassName == name) {
544 if (_wrappedClassName == name) {
530 return true;
545 return true;
531 }
546 }
532 foreach(const ParentClassInfo& info, _parentClasses) {
547 foreach(const ParentClassInfo& info, _parentClasses) {
533 if (info._parent->inherits(name)) {
548 if (info._parent->inherits(name)) {
534 return true;
549 return true;
535 }
550 }
536 }
551 }
537 return false;
552 return false;
538 }
553 }
539
554
540 bool PythonQtClassInfo::inherits(PythonQtClassInfo* classInfo)
555 bool PythonQtClassInfo::inherits(PythonQtClassInfo* classInfo)
541 {
556 {
542 if (classInfo == this) {
557 if (classInfo == this) {
543 return true;
558 return true;
544 }
559 }
545 foreach(const ParentClassInfo& info, _parentClasses) {
560 foreach(const ParentClassInfo& info, _parentClasses) {
546 if (info._parent->inherits(classInfo)) {
561 if (info._parent->inherits(classInfo)) {
547 return true;
562 return true;
548 }
563 }
549 }
564 }
550 return false;
565 return false;
551 }
566 }
552
567
553 QString PythonQtClassInfo::help()
568 QString PythonQtClassInfo::help()
554 {
569 {
555 decorator();
570 decorator();
556 QString h;
571 QString h;
557 h += QString("--- ") + QString(className()) + QString(" ---\n");
572 h += QString("--- ") + QString(className()) + QString(" ---\n");
558
573
559 if (_isQObject) {
574 if (_isQObject) {
560 h += "Properties:\n";
575 h += "Properties:\n";
561
576
562 int i;
577 int i;
563 int numProperties = _meta->propertyCount();
578 int numProperties = _meta->propertyCount();
564 for (i = 0; i < numProperties; i++) {
579 for (i = 0; i < numProperties; i++) {
565 QMetaProperty p = _meta->property(i);
580 QMetaProperty p = _meta->property(i);
566 h += QString(p.name()) + " (" + QString(p.typeName()) + " )\n";
581 h += QString(p.name()) + " (" + QString(p.typeName()) + " )\n";
567 }
582 }
568 }
583 }
569
584
570 if (constructors()) {
585 if (constructors()) {
571 h += "Constructors:\n";
586 h += "Constructors:\n";
572 PythonQtSlotInfo* constr = constructors();
587 PythonQtSlotInfo* constr = constructors();
573 while (constr) {
588 while (constr) {
574 h += constr->fullSignature() + "\n";
589 h += constr->fullSignature() + "\n";
575 constr = constr->nextInfo();
590 constr = constr->nextInfo();
576 }
591 }
577 }
592 }
578
593
579 h += "Slots:\n";
594 h += "Slots:\n";
580 h += "QString help()\n";
595 h += "QString help()\n";
581 h += "QString className()\n";
596 h += "QString className()\n";
582
597
583 if (_meta) {
598 if (_meta) {
584 int numMethods = _meta->methodCount();
599 int numMethods = _meta->methodCount();
585 for (int i = 0; i < numMethods; i++) {
600 for (int i = 0; i < numMethods; i++) {
586 QMetaMethod m = _meta->method(i);
601 QMetaMethod m = _meta->method(i);
587 if ((m.methodType() == QMetaMethod::Method ||
602 if ((m.methodType() == QMetaMethod::Method ||
588 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
603 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
589 PythonQtSlotInfo slot(this, m, i);
604 PythonQtSlotInfo slot(this, m, i);
590 h += slot.fullSignature()+ "\n";
605 h += slot.fullSignature()+ "\n";
591 }
606 }
592 }
607 }
593 }
608 }
594
609
595 // TODO xxx : decorators and enums from decorator() are missing...
610 // TODO xxx : decorators and enums from decorator() are missing...
596 // maybe we can reuse memberlist()?
611 // maybe we can reuse memberlist()?
597
612
598 if (_meta && _meta->enumeratorCount()) {
613 if (_meta && _meta->enumeratorCount()) {
599 h += "Enums:\n";
614 h += "Enums:\n";
600 for (int i = 0; i<_meta->enumeratorCount(); i++) {
615 for (int i = 0; i<_meta->enumeratorCount(); i++) {
601 QMetaEnum e = _meta->enumerator(i);
616 QMetaEnum e = _meta->enumerator(i);
602 h += QString(e.name()) + " {";
617 h += QString(e.name()) + " {";
603 for (int j=0; j < e.keyCount(); j++) {
618 for (int j=0; j < e.keyCount(); j++) {
604 if (j) { h+= ", "; }
619 if (j) { h+= ", "; }
605 h += e.key(j);
620 h += e.key(j);
606 }
621 }
607 h += " }\n";
622 h += " }\n";
608 }
623 }
609 }
624 }
610
625
611 if (_isQObject && _meta) {
626 if (_isQObject && _meta) {
612 int numMethods = _meta->methodCount();
627 int numMethods = _meta->methodCount();
613 if (numMethods>0) {
628 if (numMethods>0) {
614 h += "Signals:\n";
629 h += "Signals:\n";
615 for (int i = 0; i < numMethods; i++) {
630 for (int i = 0; i < numMethods; i++) {
616 QMetaMethod m = _meta->method(i);
631 QMetaMethod m = _meta->method(i);
617 if (m.methodType() == QMetaMethod::Signal) {
632 if (m.methodType() == QMetaMethod::Signal) {
618 h += QString(m.signature()) + "\n";
633 h += QString(m.signature()) + "\n";
619 }
634 }
620 }
635 }
621 }
636 }
622 }
637 }
623 return h;
638 return h;
624 }
639 }
625
640
626 PythonQtSlotInfo* PythonQtClassInfo::constructors()
641 PythonQtSlotInfo* PythonQtClassInfo::constructors()
627 {
642 {
628 if (!_constructors) {
643 if (!_constructors) {
629 // force creation of lazy decorator, which will register the decorators
644 // force creation of lazy decorator, which will register the decorators
630 decorator();
645 decorator();
631 }
646 }
632 return _constructors;
647 return _constructors;
633 }
648 }
634
649
635 PythonQtSlotInfo* PythonQtClassInfo::destructor()
650 PythonQtSlotInfo* PythonQtClassInfo::destructor()
636 {
651 {
637 if (!_destructor) {
652 if (!_destructor) {
638 // force creation of lazy decorator, which will register the decorators
653 // force creation of lazy decorator, which will register the decorators
639 decorator();
654 decorator();
640 }
655 }
641 return _destructor;
656 return _destructor;
642 }
657 }
643
658
644 void PythonQtClassInfo::addConstructor(PythonQtSlotInfo* info)
659 void PythonQtClassInfo::addConstructor(PythonQtSlotInfo* info)
645 {
660 {
646 PythonQtSlotInfo* prev = constructors();
661 PythonQtSlotInfo* prev = constructors();
647 if (prev) {
662 if (prev) {
648 info->setNextInfo(prev->nextInfo());
663 info->setNextInfo(prev->nextInfo());
649 prev->setNextInfo(info);
664 prev->setNextInfo(info);
650 } else {
665 } else {
651 _constructors = info;
666 _constructors = info;
652 }
667 }
653 }
668 }
654
669
655 void PythonQtClassInfo::addDecoratorSlot(PythonQtSlotInfo* info)
670 void PythonQtClassInfo::addDecoratorSlot(PythonQtSlotInfo* info)
656 {
671 {
657 _decoratorSlots.append(info);
672 _decoratorSlots.append(info);
658 }
673 }
659
674
660 void PythonQtClassInfo::setDestructor(PythonQtSlotInfo* info)
675 void PythonQtClassInfo::setDestructor(PythonQtSlotInfo* info)
661 {
676 {
662 if (_destructor) {
677 if (_destructor) {
663 _destructor->deleteOverloadsAndThis();
678 _destructor->deleteOverloadsAndThis();
664 }
679 }
665 _destructor = info;
680 _destructor = info;
666 }
681 }
667
682
668 void PythonQtClassInfo::setMetaObject(const QMetaObject* meta)
683 void PythonQtClassInfo::setMetaObject(const QMetaObject* meta)
669 {
684 {
670 _meta = meta;
685 _meta = meta;
671 clearCachedMembers();
686 clearCachedMembers();
672 }
687 }
673
688
674 QObject* PythonQtClassInfo::decorator()
689 QObject* PythonQtClassInfo::decorator()
675 {
690 {
676 if (!_decoratorProvider && _decoratorProviderCB) {
691 if (!_decoratorProvider && _decoratorProviderCB) {
677 _decoratorProvider = (*_decoratorProviderCB)();
692 _decoratorProvider = (*_decoratorProviderCB)();
678 if (_decoratorProvider) {
693 if (_decoratorProvider) {
679 _decoratorProvider->setParent(PythonQt::priv());
694 _decoratorProvider->setParent(PythonQt::priv());
680 // setup enums early, since they might be needed by the constructor decorators:
695 // setup enums early, since they might be needed by the constructor decorators:
681 if (!_enumsCreated) {
696 if (!_enumsCreated) {
682 createEnumWrappers();
697 createEnumWrappers();
683 }
698 }
684 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
699 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
685 }
700 }
686 }
701 }
687 // check if enums need to be created and create them if they are not yet created
702 // check if enums need to be created and create them if they are not yet created
688 if (!_enumsCreated) {
703 if (!_enumsCreated) {
689 createEnumWrappers();
704 createEnumWrappers();
690 }
705 }
691 return _decoratorProvider;
706 return _decoratorProvider;
692 }
707 }
693
708
694 bool PythonQtClassInfo::hasOwnerMethodButNoOwner(void* object)
709 bool PythonQtClassInfo::hasOwnerMethodButNoOwner(void* object)
695 {
710 {
696 PythonQtMemberInfo info = member("hasOwner");
711 PythonQtMemberInfo info = member("hasOwner");
697 if (info._type == PythonQtMemberInfo::Slot) {
712 if (info._type == PythonQtMemberInfo::Slot) {
698 void* obj = object;
713 void* obj = object;
699 bool result = false;
714 bool result = false;
700 void* args[2];
715 void* args[2];
701 args[0] = &result;
716 args[0] = &result;
702 args[1] = &obj;
717 args[1] = &obj;
703 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
718 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
704 return !result;
719 return !result;
705 } else {
720 } else {
706 return false;
721 return false;
707 }
722 }
708 }
723 }
709
724
710 void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, char** resultClassName)
725 void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, char** resultClassName)
711 {
726 {
712 if (!_polymorphicHandlers.isEmpty()) {
727 if (!_polymorphicHandlers.isEmpty()) {
713 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
728 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
714 void* resultPtr = (*cb)(ptr, resultClassName);
729 void* resultPtr = (*cb)(ptr, resultClassName);
715 if (resultPtr) {
730 if (resultPtr) {
716 return resultPtr;
731 return resultPtr;
717 }
732 }
718 }
733 }
719 }
734 }
720 foreach(const ParentClassInfo& info, _parentClasses) {
735 foreach(const ParentClassInfo& info, _parentClasses) {
721 if (!info._parent->isQObject()) {
736 if (!info._parent->isQObject()) {
722 void* resultPtr = info._parent->recursiveCastDownIfPossible((char*)ptr + info._upcastingOffset, resultClassName);
737 void* resultPtr = info._parent->recursiveCastDownIfPossible((char*)ptr + info._upcastingOffset, resultClassName);
723 if (resultPtr) {
738 if (resultPtr) {
724 return resultPtr;
739 return resultPtr;
725 }
740 }
726 }
741 }
727 }
742 }
728 return NULL;
743 return NULL;
729 }
744 }
730
745
731 void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo)
746 void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo)
732 {
747 {
733 char* className;
748 char* className;
734 // this would do downcasting recursively...
749 // this would do downcasting recursively...
735 // void* resultPtr = recursiveCastDownIfPossible(ptr, &className);
750 // void* resultPtr = recursiveCastDownIfPossible(ptr, &className);
736
751
737 // we only do downcasting on the base object, not on the whole inheritance tree...
752 // we only do downcasting on the base object, not on the whole inheritance tree...
738 void* resultPtr = NULL;
753 void* resultPtr = NULL;
739 if (!_polymorphicHandlers.isEmpty()) {
754 if (!_polymorphicHandlers.isEmpty()) {
740 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
755 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
741 resultPtr = (*cb)(ptr, &className);
756 resultPtr = (*cb)(ptr, &className);
742 if (resultPtr) {
757 if (resultPtr) {
743 break;
758 break;
744 }
759 }
745 }
760 }
746 }
761 }
747 if (resultPtr) {
762 if (resultPtr) {
748 *resultClassInfo = PythonQt::priv()->getClassInfo(className);
763 *resultClassInfo = PythonQt::priv()->getClassInfo(className);
749 } else {
764 } else {
750 *resultClassInfo = this;
765 *resultClassInfo = this;
751 resultPtr = ptr;
766 resultPtr = ptr;
752 }
767 }
753 return resultPtr;
768 return resultPtr;
754 }
769 }
755
770
756 PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum)
771 PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum)
757 {
772 {
758 if (isLocalEnum) {
773 if (isLocalEnum) {
759 *isLocalEnum = true;
774 *isLocalEnum = true;
760 }
775 }
761 int scopePos = name.lastIndexOf("::");
776 int scopePos = name.lastIndexOf("::");
762 if (scopePos != -1) {
777 if (scopePos != -1) {
763 if (isLocalEnum) {
778 if (isLocalEnum) {
764 *isLocalEnum = false;
779 *isLocalEnum = false;
765 }
780 }
766 // split into scope and enum name
781 // split into scope and enum name
767 QByteArray enumScope = name.mid(0,scopePos);
782 QByteArray enumScope = name.mid(0,scopePos);
768 QByteArray enumName = name.mid(scopePos+2);
783 QByteArray enumName = name.mid(scopePos+2);
769 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(enumScope);
784 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(enumScope);
770 if (info) {
785 if (info) {
771 return info->findEnumWrapper(enumName);
786 return info->findEnumWrapper(enumName);
772 } else{
787 } else{
773 return NULL;
788 return NULL;
774 }
789 }
775 }
790 }
776 if (localScope) {
791 if (localScope) {
777 return localScope->findEnumWrapper(name);
792 return localScope->findEnumWrapper(name);
778 } else {
793 } else {
779 return NULL;
794 return NULL;
780 }
795 }
781 }
796 }
782
797
783 void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta)
798 void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta)
784 {
799 {
785 for (int i = meta->enumeratorOffset();i<meta->enumeratorCount();i++) {
800 for (int i = meta->enumeratorOffset();i<meta->enumeratorCount();i++) {
786 QMetaEnum e = meta->enumerator(i);
801 QMetaEnum e = meta->enumerator(i);
787 PythonQtObjectPtr p;
802 PythonQtObjectPtr p;
788 p.setNewRef(PythonQtPrivate::createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper));
803 p.setNewRef(PythonQtPrivate::createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper));
789 _enumWrappers.append(p);
804 _enumWrappers.append(p);
790 }
805 }
791 }
806 }
792
807
793 void PythonQtClassInfo::createEnumWrappers()
808 void PythonQtClassInfo::createEnumWrappers()
794 {
809 {
795 if (!_enumsCreated) {
810 if (!_enumsCreated) {
796 _enumsCreated = true;
811 _enumsCreated = true;
797 if (_meta) {
812 if (_meta) {
798 createEnumWrappers(_meta);
813 createEnumWrappers(_meta);
799 }
814 }
800 if (decorator()) {
815 if (decorator()) {
801 createEnumWrappers(decorator()->metaObject());
816 createEnumWrappers(decorator()->metaObject());
802 }
817 }
803 foreach(const ParentClassInfo& info, _parentClasses) {
818 foreach(const ParentClassInfo& info, _parentClasses) {
804 info._parent->createEnumWrappers();
819 info._parent->createEnumWrappers();
805 }
820 }
806 }
821 }
807 }
822 }
808
823
809 PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) {
824 PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) {
810 // force enum creation
825 // force enum creation
811 if (!_enumsCreated) {
826 if (!_enumsCreated) {
812 createEnumWrappers();
827 createEnumWrappers();
813 }
828 }
814 foreach(const PythonQtObjectPtr& p, _enumWrappers) {
829 foreach(const PythonQtObjectPtr& p, _enumWrappers) {
815 const char* className = ((PyTypeObject*)p.object())->tp_name;
830 const char* className = ((PyTypeObject*)p.object())->tp_name;
816 if (qstrcmp(className, name)==0) {
831 if (qstrcmp(className, name)==0) {
817 return p.object();
832 return p.object();
818 }
833 }
819 }
834 }
820 foreach(const ParentClassInfo& info, _parentClasses) {
835 foreach(const ParentClassInfo& info, _parentClasses) {
821 PyObject* p = info._parent->findEnumWrapper(name);
836 PyObject* p = info._parent->findEnumWrapper(name);
822 if (p) return p;
837 if (p) return p;
823 }
838 }
824 return NULL;
839 return NULL;
825 }
840 }
826
841
@@ -1,510 +1,510
1 #ifndef _PYTHONQTDOC_H
1 #ifndef _PYTHONQTDOC_H
2 #define _PYTHONQTDOC_H
2 #define _PYTHONQTDOC_H
3
3
4 /*
4 /*
5 *
5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
7 *
7 *
8 * This library is free software; you can redistribute it and/or
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
11 * version 2.1 of the License, or (at your option) any later version.
12 *
12 *
13 * This library is distributed in the hope that it will be useful,
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
16 * Lesser General Public License for more details.
17 *
17 *
18 * Further, this software is distributed without any warranty that it is
18 * Further, this software is distributed without any warranty that it is
19 * free of the rightful claim of any third person regarding infringement
19 * free of the rightful claim of any third person regarding infringement
20 * or the like. Any license provided herein, whether implied or
20 * or the like. Any license provided herein, whether implied or
21 * otherwise, applies only to this software file. Patent licenses, if
21 * otherwise, applies only to this software file. Patent licenses, if
22 * any, provided herein do not apply to combinations of this program with
22 * any, provided herein do not apply to combinations of this program with
23 * other software, or any other product whatsoever.
23 * other software, or any other product whatsoever.
24 *
24 *
25 * You should have received a copy of the GNU Lesser General Public
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
30 * 28359 Bremen, Germany or:
30 * 28359 Bremen, Germany or:
31 *
31 *
32 * http://www.mevis.de
32 * http://www.mevis.de
33 *
33 *
34 */
34 */
35
35
36 //----------------------------------------------------------------------------------
36 //----------------------------------------------------------------------------------
37 /*!
37 /*!
38 // \file PythonQtDoc.h
38 // \file PythonQtDoc.h
39 // \author Florian Link
39 // \author Florian Link
40 // \author Last changed by $Author: florian $
40 // \author Last changed by $Author: florian $
41 // \date 2006-10
41 // \date 2006-10
42 */
42 */
43 //----------------------------------------------------------------------------------
43 //----------------------------------------------------------------------------------
44
44
45 /*!
45 /*!
46 \if USE_GLOBAL_DOXYGEN_DOC
46 \if USE_GLOBAL_DOXYGEN_DOC
47 \page PythonQtPage PythonQt Overview
47 \page PythonQtPage PythonQt Overview
48 \else
48 \else
49 \mainpage PythonQt Overview
49 \mainpage PythonQt Overview
50 \endif
50 \endif
51
51
52 \section Introduction
52 \section Introduction
53
53
54 \b PythonQt is a dynamic Python (http://www.python.org) binding for Qt (http://www.qtsoftware.com).
54 \b PythonQt is a dynamic Python (http://www.python.org) binding for Qt (http://www.qtsoftware.com).
55 It offers an easy way to embed the Python scripting language into
55 It offers an easy way to embed the Python scripting language into
56 your Qt applications. It makes heavy use of the QMetaObject system and thus requires Qt4.x.
56 your Qt applications. It makes heavy use of the QMetaObject system and thus requires Qt4.x.
57
57
58 The focus of PythonQt is on embedding Python into an existing C++ application, not on writing the whole
58 The focus of PythonQt is on embedding Python into an existing C++ application, not on writing the whole
59 application completely in Python. If you want to write your whole application in Python,
59 application completely in Python. If you want to write your whole application in Python,
60 you should use <a href="http://www.riverbankcomputing.co.uk/pyqt/">PyQt</a> instead.
60 you should use <a href="http://www.riverbankcomputing.co.uk/pyqt/">PyQt</a> instead.
61
61
62 If you are looking for a simple way to embed Python objects into your C++/Qt Application
62 If you are looking for a simple way to embed Python objects into your C++/Qt Application
63 and to script parts of your application via Python, PythonQt is the way to go!
63 and to script parts of your application via Python, PythonQt is the way to go!
64
64
65 PythonQt is a stable library that was developed to make the
65 PythonQt is a stable library that was developed to make the
66 Image Processing and Visualization platform MeVisLab (http://www.mevislab.de)
66 Image Processing and Visualization platform MeVisLab (http://www.mevislab.de)
67 scriptable from Python.
67 scriptable from Python.
68
68
69 \section Download
69 \section Download
70
70
71 PythonQt is hosted on SourceForge at http://sourceforge.net/projects/pythonqt , you can access it via SVN
71 PythonQt is hosted on SourceForge at http://sourceforge.net/projects/pythonqt , you can access it via SVN
72 or download a tarball.
72 or download a tarball.
73
73
74 \section Licensing
74 \section Licensing
75
75
76 PythonQt is distributed under the LGPL license, so it pairs well with the LGPL of the Qt 4.5 release and allows
76 PythonQt is distributed under the LGPL license, so it pairs well with the LGPL of the Qt 4.5 release and allows
77 to be used in commercial applications when following the LGPL 2.1 obligations.
77 to be used in commercial applications when following the LGPL 2.1 obligations.
78
78
79 \section LicensingWrapper Licensing of Wrapper Generator
79 \section LicensingWrapper Licensing of Wrapper Generator
80
80
81 The build system of PythonQt makes use of a modified version of the GPL'ed QtScript generator,
81 The build system of PythonQt makes use of a modified version of the GPL'ed QtScript generator,
82 located in the "generator" directory.
82 located in the "generator" directory.
83
83
84 See http://labs.trolltech.com/page/Projects/QtScript/Generator for details on the original project.
84 See http://labs.trolltech.com/page/Projects/QtScript/Generator for details on the original project.
85 Thanks a lot to the QtJambi guys and the QtScript Generator project for the C++ parser and
85 Thanks a lot to the QtJambi guys and the QtScript Generator project for the C++ parser and
86 Qt typesystem files!
86 Qt typesystem files!
87
87
88 The PythonQt wrappers generated by the generator located in the "generated_cpp" directory are distributed under the LGPL,
88 The PythonQt wrappers generated by the generator located in the "generated_cpp" directory are distributed under the LGPL,
89 they are not restriced by the GPL.
89 they are not restriced by the GPL.
90
90
91 The generated wrappers are pre-generated and checked-in for Qt 4.4.3, so you only need to build and run the
91 The generated wrappers are pre-generated and checked-in for Qt 4.4.3, so you only need to build and run the
92 generator when you want to build additional wrappers or you want to upgrade/downgrade to an newer Qt version.
92 generator when you want to build additional wrappers or you want to upgrade/downgrade to an newer Qt version.
93 You may use the generator to generate C++ bindings for your own C++ classes (e.g. to make them deriveable in Python),
93 You may use the generator to generate C++ bindings for your own C++ classes (e.g. to make them deriveable in Python),
94 , but this is currently not documented and involves creating your own typesystem files.
94 , but this is currently not documented and involves creating your own typesystem files.
95
95
96 \section Features
96 \section Features
97
97
98 The following are the built-in features of the PythonQt library:
98 The following are the built-in features of the PythonQt library:
99
99
100 - Access all \b slots, \b properties, children and registered enums of any QObject derived class from Python
100 - Access all \b slots, \b properties, children and registered enums of any QObject derived class from Python
101 - Connecting Qt Signals to Python functions (both from within Python and from C++)
101 - Connecting Qt Signals to Python functions (both from within Python and from C++)
102 - Easy wrapping of Python objects from C++ with smart, reference-counting PythonQtObjectPtr.
102 - Easy wrapping of Python objects from C++ with smart, reference-counting PythonQtObjectPtr.
103 - Convenient conversions to/from QVariant for PythonQtObjectPtr.
103 - Convenient conversions to/from QVariant for PythonQtObjectPtr.
104 - Wrapping of C++ objects (which are not derived from QObject) via PythonQtCppWrapperFactory
104 - Wrapping of C++ objects (which are not derived from QObject) via PythonQtCppWrapperFactory
105 - Extending C++ and QObject derived classes with additional slots, static methods and constructors (see Decorators)
105 - Extending C++ and QObject derived classes with additional slots, static methods and constructors (see Decorators)
106 - StdOut/Err redirection to Qt signals instead of cout
106 - StdOut/Err redirection to Qt signals instead of cout
107 - Interface for creating your own \c import replacement, so that Python scripts can be e.g. signed/verified before they are executed (PythonQtImportFileInterface)
107 - Interface for creating your own \c import replacement, so that Python scripts can be e.g. signed/verified before they are executed (PythonQtImportFileInterface)
108 - Mapping of plain-old-datatypes and ALL QVariant types to and from Python
108 - Mapping of plain-old-datatypes and ALL QVariant types to and from Python
109 - Support for wrapping of user QVariant types which are registerd via QMetaType
109 - Support for wrapping of user QVariant types which are registerd via QMetaType
110 - Support for Qt namespace (with all enumerators)
110 - Support for Qt namespace (with all enumerators)
111 - All PythonQt wrapped objects support the dir() statement, so that you can see easily which attributes a QObject, CPP object or QVariant has
111 - All PythonQt wrapped objects support the dir() statement, so that you can see easily which attributes a QObject, CPP object or QVariant has
112 - No preprocessing/wrapping tool needs to be started, PythonQt can script any QObject without prior knowledge about it (except for the MetaObject information from the \b moc)
112 - 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)
113 - Multiple inheritance for C++ objects (e.g. a QWidget is derived from QObject and QPaintDevice, PythonQt will automatically cast a QWidget to a QPaintDevice when needed)
113 - 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)
114 - Polymorphic downcasting (if e.g. PythonQt sees a QEvent, it can downcast it depending on the type(), so the Python e.g. sees a QPaintEvent instead of a plain QEvent)
114 - 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)
115 - Deriving C++ objects from Python and overwriting virtual method with a Python implementation (requires usage of wrapper generator or manual work!)
115 - Deriving C++ objects from Python and overwriting virtual method with a Python implementation (requires usage of wrapper generator or manual work!)
116 - Extensible handler for Python/C++ conversion of complex types, e.g. mapping of QVector<SomeObject> to/from a Python array
116 - Extensible handler for Python/C++ conversion of complex types, e.g. mapping of QVector<SomeObject> to/from a Python array
117
117
118 \section FeaturesQtAll Features (with PythonQt_QtAll linked in)
118 \section FeaturesQtAll Features (with PythonQt_QtAll linked in)
119
119
120 Thanks to the new wrapper generator, PythonQt now offers the additional PythonQt_QtAll library which wraps the complete Qt API, including all C++ classes and all non-slots on QObject derived classes.
120 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.
121 This offers the following features:
121 This offers the following features:
122
122
123 - Complete Qt API wrapped and accessible
123 - Complete Qt API wrapped and accessible
124 - The following modules are available as submodule of the PythonQt module:
124 - The following modules are available as submodule of the PythonQt module:
125 - QtCore
125 - QtCore
126 - QtGui
126 - QtGui
127 - QtNetwork
127 - QtNetwork
128 - QtOpenGL
128 - QtOpenGL
129 - QtSql
129 - QtSql
130 - QtSvg
130 - QtSvg
131 - QtUiTools
131 - QtUiTools
132 - QtWebKit
132 - QtWebKit
133 - QtXml
133 - QtXml
134 - QtXmlPatterns
134 - QtXmlPatterns
135 - (phonon, QtHelp, assistant, designer are currently not supported, this would require some additional effort on the code generator)
135 - (phonon, QtHelp, assistant, designer are currently not supported, this would require some additional effort on the code generator)
136 - For convenience, all classes are also available in the PythonQt.Qt module, for people who do not care in which module a class is located
136 - 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
137 - Any Qt class that has virtual methods can be easily derived from Python and the virtual methods can be reimplemented in Python
137 - Any Qt class that has virtual methods can be easily derived from Python and the virtual methods can be reimplemented in Python
138 - Polymorphic downcasting on QEvent, QGraphicsItem, QStyleOption, ...
138 - Polymorphic downcasting on QEvent, QGraphicsItem, QStyleOption, ...
139 - Multiple inheritance support (e.g. QGraphicsTextItem is a QObject AND a QGraphicsItem, PythonQt will handle this well)
139 - Multiple inheritance support (e.g. QGraphicsTextItem is a QObject AND a QGraphicsItem, PythonQt will handle this well)
140
140
141 \section Comparision Comparision with PyQt
141 \section Comparision Comparision with PyQt
142
142
143 - PythonQt is not as Pythonic as PyQt in many details (e.g. operator mapping, pickling, translation support, ...) and it is mainly thought for embedding and intercommunication between Qt/Cpp and Python
143 - PythonQt is not as Pythonic as PyQt in many details (e.g. operator mapping, pickling, translation support, ...) and it is mainly thought for embedding and intercommunication between Qt/Cpp and Python
144 - PythonQt allows to communicate in both directions, e.g. calling a Python object from C++ AND calling a C++ method from Python, while PyQt only handles the Python->C++ direction
144 - PythonQt 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
145 - PythonQt offers properties as Python attributes, while PyQt offers them as setter/getter methods (e.g. QWidget.width is a property in PythonQt and a method in PyQt)
145 - PythonQt 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)
146 - PythonQt does not support instanceof checks for Qt classes, except for the exact match and derived Python classes
146 - PythonQt does not support instanceof checks for Qt classes, except for the exact match and derived Python classes
147 - QObject.emit to emit Qt signals from Python is not yet implemented
147 - QObject.emit to emit Qt signals from Python is not yet implemented but PythonQt allows to just emit a signal by calling it
148 - PythonQt does not offer to add new signals to Python/C++ objects
148 - PythonQt does not offer to add new signals to Python/C++ objects
149 - Ownership of objects is a bit different in PythonQt, currently Python classes derived from a C++ class need to be manually references in PythonQt to not get deleted too early (this will be fixed)
149 - Ownership of objects is a bit different in PythonQt, currently Python classes derived from a C++ class need to be manually references in PythonQt to not get deleted too early (this will be fixed)
150 - Probably there are lots of details that differ, I do not know PyQt that well to list them all.
150 - Probably there are lots of details that differ, I do not know PyQt that well to list them all.
151
151
152
152
153 \section Interface
153 \section Interface
154
154
155 The main interface to PythonQt is the PythonQt singleton.
155 The main interface to PythonQt is the PythonQt singleton.
156 PythonQt needs to be initialized via PythonQt::init() once.
156 PythonQt needs to be initialized via PythonQt::init() once.
157 Afterwards you communicate with the singleton via PythonQt::self().
157 Afterwards you communicate with the singleton via PythonQt::self().
158 PythonQt offers a complete Qt binding, which
158 PythonQt offers a complete Qt binding, which
159 needs to be enabled via PythonQt_QtAll::init().
159 needs to be enabled via PythonQt_QtAll::init().
160
160
161
161
162 \section Datatype Datatype Mapping
162 \section Datatype Datatype Mapping
163
163
164 The following table shows the mapping between Python and Qt objects:
164 The following table shows the mapping between Python and Qt objects:
165 <table>
165 <table>
166 <tr><th>Qt/C++</th><th>Python</th></tr>
166 <tr><th>Qt/C++</th><th>Python</th></tr>
167 <tr><td>bool</td><td>bool</td></tr>
167 <tr><td>bool</td><td>bool</td></tr>
168 <tr><td>double</td><td>float</td></tr>
168 <tr><td>double</td><td>float</td></tr>
169 <tr><td>float</td><td>float</td></tr>
169 <tr><td>float</td><td>float</td></tr>
170 <tr><td>char/uchar,int/uint,short,ushort,QChar</td><td>integer</td></tr>
170 <tr><td>char/uchar,int/uint,short,ushort,QChar</td><td>integer</td></tr>
171 <tr><td>long</td><td>integer</td></tr>
171 <tr><td>long</td><td>integer</td></tr>
172 <tr><td>ulong,longlong,ulonglong</td><td>long</td></tr>
172 <tr><td>ulong,longlong,ulonglong</td><td>long</td></tr>
173 <tr><td>QString</td><td>unicode string</td></tr>
173 <tr><td>QString</td><td>unicode string</td></tr>
174 <tr><td>QByteArray</td><td>str</td></tr>
174 <tr><td>QByteArray</td><td>str</td></tr>
175 <tr><td>char*</td><td>str</td></tr>
175 <tr><td>char*</td><td>str</td></tr>
176 <tr><td>QStringList</td><td>tuple of unicode strings</td></tr>
176 <tr><td>QStringList</td><td>tuple of unicode strings</td></tr>
177 <tr><td>QVariantList</td><td>tuple of objects</td></tr>
177 <tr><td>QVariantList</td><td>tuple of objects</td></tr>
178 <tr><td>QVariantMap</td><td>dict of objects</td></tr>
178 <tr><td>QVariantMap</td><td>dict of objects</td></tr>
179 <tr><td>QVariant</td><td>depends on type, see below</td></tr>
179 <tr><td>QVariant</td><td>depends on type, see below</td></tr>
180 <tr><td>QSize, QRect and all other standard Qt QVariants</td><td>variant wrapper that supports complete API of the respective Qt classes</td></tr>
180 <tr><td>QSize, QRect and all other standard Qt QVariants</td><td>variant wrapper that supports complete API of the respective Qt classes</td></tr>
181 <tr><td>OwnRegisteredMetaType</td><td>C++ wrapper, optionally with additional information/wrapping provided by registerCPPClass()</td></tr>
181 <tr><td>OwnRegisteredMetaType</td><td>C++ wrapper, optionally with additional information/wrapping provided by registerCPPClass()</td></tr>
182 <tr><td>QList<AnyObject*></td><td>converts to a list of CPP wrappers</td></tr>
182 <tr><td>QList<AnyObject*></td><td>converts to a list of CPP wrappers</td></tr>
183 <tr><td>EnumType</td><td>integer (all enums that are known via the moc and the Qt namespace are supported)</td></tr>
183 <tr><td>EnumType</td><td>integer (all enums that are known via the moc and the Qt namespace are supported)</td></tr>
184 <tr><td>QObject (and derived classes)</td><td>QObject wrapper</td></tr>
184 <tr><td>QObject (and derived classes)</td><td>QObject wrapper</td></tr>
185 <tr><td>C++ object</td><td>CPP wrapper, either wrapped via PythonQtCppWrapperFactory or just decorated with decorators</td></tr>
185 <tr><td>C++ object</td><td>CPP wrapper, either wrapped via PythonQtCppWrapperFactory or just decorated with decorators</td></tr>
186 <tr><td>PyObject</td><td>PyObject</td></tr>
186 <tr><td>PyObject</td><td>PyObject</td></tr>
187 </table>
187 </table>
188
188
189 PyObject is passed as simple pointer, which allows to pass/return any Python Object directly to/from
189 PyObject is passed as simple pointer, which allows to pass/return any Python Object directly to/from
190 a Qt slot.
190 a Qt slot.
191 QVariants are mapped recursively as given above, e.g. a dictionary can
191 QVariants are mapped recursively as given above, e.g. a dictionary can
192 contain lists of dictionaries of doubles.
192 contain lists of dictionaries of doubles.
193 For example a QVariant of type "String" is mapped to a python unicode string.
193 For example a QVariant of type "String" is mapped to a python unicode string.
194 All Qt QVariant types are implemented, PythonQt supports the complete Qt API for these object.
194 All Qt QVariant types are implemented, PythonQt supports the complete Qt API for these object.
195
195
196 \section QObject QObject Wrapping
196 \section QObject QObject Wrapping
197
197
198 All classes derived from QObject are automatically wrapped with a python wrapper class
198 All classes derived from QObject are automatically wrapped with a python wrapper class
199 when they become visible to the Python interpreter. This can happen via
199 when they become visible to the Python interpreter. This can happen via
200 - the PythonQt::addObject() method
200 - the PythonQt::addObject() method
201 - when a Qt \b slot returns a QObject derived object to python
201 - when a Qt \b slot returns a QObject derived object to python
202 - when a Qt \b signal contains a QObject and is connected to a python function
202 - when a Qt \b signal contains a QObject and is connected to a python function
203
203
204 It is important that you call PythonQt::registerClass() for any QObject derived class
204 It is important that you call PythonQt::registerClass() for any QObject derived class
205 that may become visible to Python, except when you add it via PythonQt::addObject().
205 that may become visible to Python, except when you add it via PythonQt::addObject().
206 This will register the complete parent hierachy of the registered class, so that
206 This will register the complete parent hierachy of the registered class, so that
207 when you register e.g. a QPushButton, QWidget will be registered as well (and all intermediate
207 when you register e.g. a QPushButton, QWidget will be registered as well (and all intermediate
208 parents).
208 parents).
209
209
210 From Python, you can talk to the returned QObjects in a natural way by calling
210 From Python, you can talk to the returned QObjects in a natural way by calling
211 their slots and receiving the return values. You can also read/write all
211 their slots and receiving the return values. You can also read/write all
212 properties of the objects as if they where normal python properties.
212 properties of the objects as if they where normal python properties.
213
213
214 In addition to this, the wrapped objects support
214 In addition to this, the wrapped objects support
215 - className() - returns a string that reprents the classname of the QObject
215 - className() - returns a string that reprents the classname of the QObject
216 - help() - shows all properties, slots, enums, decorator slots and constructors of the object, in a printable form
216 - help() - shows all properties, slots, enums, decorator slots and constructors of the object, in a printable form
217 - delete() - deletes the object (use with care, especially if you passed the ownership to C++)
217 - delete() - deletes the object (use with care, especially if you passed the ownership to C++)
218 - connect(signal, function) - connect the signal of the given object to a python function
218 - connect(signal, function) - connect the signal of the given object to a python function
219 - connect(signal, qobject, slot) - connect the signal of the given object to a slot of another QObject
219 - connect(signal, qobject, slot) - connect the signal of the given object to a slot of another QObject
220 - disconnect(signal, function) - disconnect the signal of the given object from a python function
220 - disconnect(signal, function) - disconnect the signal of the given object from a python function
221 - disconnect(signal, qobject, slot) - disconnect the signal of the given object from a slot of another QObject
221 - disconnect(signal, qobject, slot) - disconnect the signal of the given object from a slot of another QObject
222 - children() - returns the children of the object
222 - children() - returns the children of the object
223 - setParent(QObject) - set the parent
223 - setParent(QObject) - set the parent
224 - QObject* parent() - get the parent
224 - QObject* parent() - get the parent
225
225
226 The below example shows how to connect signals in Python:
226 The below example shows how to connect signals in Python:
227
227
228 \code
228 \code
229 # define a signal handler function
229 # define a signal handler function
230 def someFunction(flag):
230 def someFunction(flag):
231 print flag
231 print flag
232
232
233 # button1 is a QPushButton that has been added to Python via addObject()
233 # button1 is a QPushButton that has been added to Python via addObject()
234 # connect the clicked signal to a python function:
234 # connect the clicked signal to a python function:
235 button1.connect("clicked(bool)", someFunction)
235 button1.connect("clicked(bool)", someFunction)
236
236
237 \endcode
237 \endcode
238
238
239 \section CPP CPP Wrapping
239 \section CPP CPP Wrapping
240
240
241 You can create dedicated wrapper QObjects for any C++ class. This is done by deriving from PythonQtCppWrapperFactory
241 You can create dedicated wrapper QObjects for any C++ class. This is done by deriving from PythonQtCppWrapperFactory
242 and adding your factory via addWrapperFactory().
242 and adding your factory via addWrapperFactory().
243 Whenever PythonQt encounters a CPP pointer (e.g. on a slot or signal)
243 Whenever PythonQt encounters a CPP pointer (e.g. on a slot or signal)
244 and it does not known it as a QObject derived class, it will create a generic CPP wrapper. So even unknown C++ objects
244 and it does not known it as a QObject derived class, it will create a generic CPP wrapper. So even unknown C++ objects
245 can be passed through Python. If the wrapper factory supports the CPP class, a QObject wrapper will be created for each
245 can be passed through Python. If the wrapper factory supports the CPP class, a QObject wrapper will be created for each
246 instance that enters Python. An alternative to a complete wrapper via the wrapper factory are decorators, see \ref Decorators
246 instance that enters Python. An alternative to a complete wrapper via the wrapper factory are decorators, see \ref Decorators
247
247
248 \section MetaObject Meta Object/Class access
248 \section MetaObject Meta Object/Class access
249
249
250 For each known C++ class, PythonQt provides a Python class. These classes are visible
250 For each known C++ class, PythonQt provides a Python class. These classes are visible
251 inside of the "PythonQt" python module or in subpackages if a package is given when the class is registered.
251 inside of the "PythonQt" python module or in subpackages if a package is given when the class is registered.
252
252
253 A Meta class supports:
253 A Meta class supports:
254
254
255 - access to all declared enum values
255 - access to all declared enum values
256 - constructors
256 - constructors
257 - static methods
257 - static methods
258 - unbound non-static methods
258 - unbound non-static methods
259 - help() and className()
259 - help() and className()
260
260
261 From within Python, you can import the module "PythonQt" to access these classes and the Qt namespace.
261 From within Python, you can import the module "PythonQt" to access these classes and the Qt namespace.
262
262
263 \code
263 \code
264 from PythonQt import QtCore
264 from PythonQt import QtCore
265
265
266 # namespace access:
266 # namespace access:
267 print QtCore.Qt.AlignLeft
267 print QtCore.Qt.AlignLeft
268
268
269 # constructors
269 # constructors
270 a = QtCore.QSize(12,13)
270 a = QtCore.QSize(12,13)
271 b = QtCore.QFont()
271 b = QtCore.QFont()
272
272
273 # static method
273 # static method
274 QtCore.QDate.currentDate()
274 QtCore.QDate.currentDate()
275
275
276 # enum value
276 # enum value
277 QtCore.QFont.UltraCondensed
277 QtCore.QFont.UltraCondensed
278
278
279 \endcode
279 \endcode
280
280
281 \section Decorators Decorator slots
281 \section Decorators Decorator slots
282
282
283 PythonQt introduces a new generic approach to extend any wrapped QObject or CPP object with
283 PythonQt introduces a new generic approach to extend any wrapped QObject or CPP object with
284
284
285 - constructors
285 - constructors
286 - destructors (for CPP objects)
286 - destructors (for CPP objects)
287 - additional slots
287 - additional slots
288 - static slots (callable on both the Meta object and the instances)
288 - static slots (callable on both the Meta object and the instances)
289
289
290 The idea behind decorators is that we wanted to make it as easy as possible to extend
290 The idea behind decorators is that we wanted to make it as easy as possible to extend
291 wrapped objects. Since we already have an implementation for invoking any Qt Slot from
291 wrapped objects. Since we already have an implementation for invoking any Qt Slot from
292 Python, it looked promising to use this approach for the extension of wrapped objects as well.
292 Python, it looked promising to use this approach for the extension of wrapped objects as well.
293 This avoids that the PythonQt user needs to care about how Python arguments are mapped from/to
293 This avoids that the PythonQt user needs to care about how Python arguments are mapped from/to
294 Qt when he wants to create static methods, constructors and additional member functions.
294 Qt when he wants to create static methods, constructors and additional member functions.
295
295
296 The basic idea about decorators is to create a QObject derived class that implements slots
296 The basic idea about decorators is to create a QObject derived class that implements slots
297 which take one of the above roles (e.g. constructor, destructor etc.) via a naming convention.
297 which take one of the above roles (e.g. constructor, destructor etc.) via a naming convention.
298 These slots are then assigned to other classes via the naming convention.
298 These slots are then assigned to other classes via the naming convention.
299
299
300 - SomeClassName* new_SomeClassName(...) - defines a constructor for "SomeClassName" that returns a new object of type SomeClassName (where SomeClassName can be any CPP class, not just QObject classes)
300 - 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)
301 - void delete_SomeClassName(SomeClassName* o) - defines a destructor, which should delete the passed in object o
301 - void delete_SomeClassName(SomeClassName* o) - defines a destructor, which should delete the passed in object o
302 - anything static_SomeClassName_someMethodName(...) - defines a static method that is callable on instances and the meta class
302 - anything static_SomeClassName_someMethodName(...) - defines a static method that is callable on instances and the meta class
303 - anything someMethodName(SomeClassName* o, ...) - defines a slot that will be available on SomeClassName instances (and derived instances). When such a slot is called the first argument is the pointer to the instance and the rest of the arguments can be used to make a call on the instance.
303 - 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.
304
304
305 The below example shows all kinds of decorators in action:
305 The below example shows all kinds of decorators in action:
306
306
307 \code
307 \code
308
308
309 // an example CPP object
309 // an example CPP object
310 class YourCPPObject {
310 class YourCPPObject {
311 public:
311 public:
312 YourCPPObject(int arg1, float arg2) { a = arg1; b = arg2; }
312 YourCPPObject(int arg1, float arg2) { a = arg1; b = arg2; }
313
313
314 float doSomething(int arg1) { return arg1*a*b; };
314 float doSomething(int arg1) { return arg1*a*b; };
315
315
316 private:
316 private:
317
317
318 int a;
318 int a;
319 float b;
319 float b;
320 };
320 };
321
321
322 // an example decorator
322 // an example decorator
323 class ExampleDecorator : public QObject
323 class ExampleDecorator : public QObject
324 {
324 {
325 Q_OBJECT
325 Q_OBJECT
326
326
327 public slots:
327 public slots:
328 // add a constructor to QSize that takes a QPoint
328 // add a constructor to QSize that takes a QPoint
329 QSize* new_QSize(const QPoint& p) { return new QSize(p.x(), p.y()); }
329 QSize* new_QSize(const QPoint& p) { return new QSize(p.x(), p.y()); }
330
330
331 // add a constructor for QPushButton that takes a text and a parent widget
331 // add a constructor for QPushButton that takes a text and a parent widget
332 QPushButton* new_QPushButton(const QString& text, QWidget* parent=NULL) { return new QPushButton(text, parent); }
332 QPushButton* new_QPushButton(const QString& text, QWidget* parent=NULL) { return new QPushButton(text, parent); }
333
333
334 // add a constructor for a CPP object
334 // add a constructor for a CPP object
335 YourCPPObject* new_YourCPPObject(int arg1, float arg2) { return new YourCPPObject(arg1, arg2); }
335 YourCPPObject* new_YourCPPObject(int arg1, float arg2) { return new YourCPPObject(arg1, arg2); }
336
336
337 // add a destructor for a CPP object
337 // add a destructor for a CPP object
338 void delete_YourCPPObject(YourCPPObject* obj) { delete obj; }
338 void delete_YourCPPObject(YourCPPObject* obj) { delete obj; }
339
339
340 // add a static method to QWidget
340 // add a static method to QWidget
341 QWidget* static_QWidget_mouseGrabber() { return QWidget::mouseGrabber(); }
341 QWidget* static_QWidget_mouseGrabber() { return QWidget::mouseGrabber(); }
342
342
343 // add an additional slot to QWidget (make move() callable, which is not declared as a slot in QWidget)
343 // add an additional slot to QWidget (make move() callable, which is not declared as a slot in QWidget)
344 void move(QWidget* w, const QPoint& p) { w->move(p); }
344 void move(QWidget* w, const QPoint& p) { w->move(p); }
345
345
346 // add an additional slot to QWidget, overloading the above move method
346 // add an additional slot to QWidget, overloading the above move method
347 void move(QWidget* w, int x, int y) { w->move(x,y); }
347 void move(QWidget* w, int x, int y) { w->move(x,y); }
348
348
349 // add a method to your own CPP object
349 // add a method to your own CPP object
350 int doSomething(YourCPPObject* obj, int arg1) { return obj->doSomething(arg1); }
350 int doSomething(YourCPPObject* obj, int arg1) { return obj->doSomething(arg1); }
351 };
351 };
352
352
353 ...
353 ...
354
354
355 PythonQt::self()->addDecorators(new ExampleDecorator());
355 PythonQt::self()->addDecorators(new ExampleDecorator());
356 PythonQt::self()->registerCPPClass("YourCPPObject");
356 PythonQt::self()->registerCPPClass("YourCPPObject");
357
357
358 \endcode
358 \endcode
359
359
360 After you have registered an instance of the above ExampleDecorator, you can do the following from Python
360 After you have registered an instance of the above ExampleDecorator, you can do the following from Python
361 (all these calls are mapped to the above decorator slots):
361 (all these calls are mapped to the above decorator slots):
362
362
363 \code
363 \code
364 from PythonQt import QtCore, QtGui, YourCPPObject
364 from PythonQt import QtCore, QtGui, YourCPPObject
365
365
366 # call our new constructor of QSize
366 # call our new constructor of QSize
367 size = QtCore.QSize(QPoint(1,2));
367 size = QtCore.QSize(QPoint(1,2));
368
368
369 # call our new QPushButton constructor
369 # call our new QPushButton constructor
370 button = QtGui.QPushButton("sometext");
370 button = QtGui.QPushButton("sometext");
371
371
372 # call the move slot (overload1)
372 # call the move slot (overload1)
373 button.move(QPoint(0,0))
373 button.move(QPoint(0,0))
374
374
375 # call the move slot (overload2)
375 # call the move slot (overload2)
376 button.move(0,0)
376 button.move(0,0)
377
377
378 # call the static method
378 # call the static method
379 grabber = QtGui.QWidget.mouseWrapper();
379 grabber = QtGui.QWidget.mouseWrapper();
380
380
381 # create a CPP object via constructor
381 # create a CPP object via constructor
382 yourCpp = YourCPPObject(1,11.5)
382 yourCpp = YourCPPObject(1,11.5)
383
383
384 # call the wrapped method on CPP object
384 # call the wrapped method on CPP object
385 print yourCpp.doSomething(1);
385 print yourCpp.doSomething(1);
386
386
387 # destructor will be called:
387 # destructor will be called:
388 yourCpp = None
388 yourCpp = None
389
389
390 \endcode
390 \endcode
391
391
392 \section Building
392 \section Building
393
393
394 PythonQt requires at least Qt 4.2.2 (or higher) and Python 2.3, 2.4, 2.5 or 2.6 on Windows, Linux and MacOS X. It has not yet been tested with Python 3.x, but it should only require minor changes.
394 PythonQt requires at least Qt 4.2.2 (or higher) and Python 2.3, 2.4, 2.5 or 2.6 on Windows, Linux and MacOS X. It has not yet been tested with Python 3.x, but it should only require minor changes.
395 To compile PythonQt, you will need a python developer installation which includes Python's header files and
395 To compile PythonQt, you will need a python developer installation which includes Python's header files and
396 the python2x.[lib | dll | so | dynlib].
396 the python2x.[lib | dll | so | dynlib].
397 The build scripts a currently set to use Python 2.5.
397 The build scripts a currently set to use Python 2.5.
398 You may need to tweak the \b build/python.prf file to set the correct Python includes and libs on your system.
398 You may need to tweak the \b build/python.prf file to set the correct Python includes and libs on your system.
399
399
400 \subsection Windows
400 \subsection Windows
401
401
402 On Windows, the (non-source) Python Windows installer can be used.
402 On Windows, the (non-source) Python Windows installer can be used.
403 Make sure that you use the same compiler, the current Python distribution is built
403 Make sure that you use the same compiler, the current Python distribution is built
404 with Visual Studio 2003. If you want to use another compiler, you will need to build
404 with Visual Studio 2003. If you want to use another compiler, you will need to build
405 Python yourself, using your compiler.
405 Python yourself, using your compiler.
406
406
407 To build PythonQt, you need to set the environment variable \b PYTHON_PATH to point to the root
407 To build PythonQt, you need to set the environment variable \b PYTHON_PATH to point to the root
408 dir of the python installation and \b PYTHON_LIB to point to
408 dir of the python installation and \b PYTHON_LIB to point to
409 the directory where the python lib file is located.
409 the directory where the python lib file is located.
410
410
411 When using the prebuild Python installer, this will be:
411 When using the prebuild Python installer, this will be:
412
412
413 \code
413 \code
414 > set PYTHON_PATH = c:\Python25
414 > set PYTHON_PATH = c:\Python25
415 > set PYTHON_LIB = c:\Python25\libs
415 > set PYTHON_LIB = c:\Python25\libs
416 \endcode
416 \endcode
417
417
418 When using the python sources, this will be something like:
418 When using the python sources, this will be something like:
419
419
420 \code
420 \code
421 > set PYTHON_PATH = c:\yourDir\Python-2.5.1\
421 > set PYTHON_PATH = c:\yourDir\Python-2.5.1\
422 > set PYTHON_LIB = c:\yourDir\Python-2.5.1\PCbuild8\Win32
422 > set PYTHON_LIB = c:\yourDir\Python-2.5.1\PCbuild8\Win32
423 \endcode
423 \endcode
424
424
425 To build all, do the following (after setting the above variables):
425 To build all, do the following (after setting the above variables):
426
426
427 \code
427 \code
428 > cd PythonQtRoot
428 > cd PythonQtRoot
429 > vcvars32
429 > vcvars32
430 > qmake
430 > qmake
431 > nmake
431 > nmake
432 \endcode
432 \endcode
433
433
434 This should build everything. If Python can not be linked or include files can not be found,
434 This should build everything. If Python can not be linked or include files can not be found,
435 you probably need to tweak \b build/python.prf
435 you probably need to tweak \b build/python.prf
436
436
437 The tests and examples are located in PythonQt/lib.
437 The tests and examples are located in PythonQt/lib.
438
438
439 \subsection Linux
439 \subsection Linux
440
440
441 On Linux, you need to install a Python-dev package.
441 On Linux, you need to install a Python-dev package.
442 If Python can not be linked or include files can not be found,
442 If Python can not be linked or include files can not be found,
443 you probably need to tweak \b build/python.prf
443 you probably need to tweak \b build/python.prf
444
444
445 To build PythonQt, just do a:
445 To build PythonQt, just do a:
446
446
447 \code
447 \code
448 > cd PythonQtRoot
448 > cd PythonQtRoot
449 > qmake
449 > qmake
450 > make all
450 > make all
451 \endcode
451 \endcode
452
452
453 The tests and examples are located in PythonQt/lib.
453 The tests and examples are located in PythonQt/lib.
454 You should add PythonQt/lib to your LD_LIBRARY_PATH so that the runtime
454 You should add PythonQt/lib to your LD_LIBRARY_PATH so that the runtime
455 linker can find the *.so files.
455 linker can find the *.so files.
456
456
457 \subsection MacOsX
457 \subsection MacOsX
458
458
459 On Mac, Python is installed as a Framework, so you should not need to install it.
459 On Mac, Python is installed as a Framework, so you should not need to install it.
460 To build PythonQt, just do a:
460 To build PythonQt, just do a:
461
461
462 \code
462 \code
463 > cd PythonQtRoot
463 > cd PythonQtRoot
464 > qmake
464 > qmake
465 > make all
465 > make all
466 \endcode
466 \endcode
467
467
468 \section Tests
468 \section Tests
469
469
470 There is a unit test that tests most features of PythonQt, see the \b tests subdirectory for details.
470 There is a unit test that tests most features of PythonQt, see the \b tests subdirectory for details.
471
471
472 \section Examples
472 \section Examples
473
473
474 Examples are available in the \b examples directory. The PyScriptingConsole implements a simple
474 Examples are available in the \b examples directory. The PyScriptingConsole implements a simple
475 interactive scripting console that shows how to script a simple application.
475 interactive scripting console that shows how to script a simple application.
476
476
477 The following shows how to integrate PythonQt into you Qt application:
477 The following shows how to integrate PythonQt into you Qt application:
478
478
479 \code
479 \code
480 #include "PythonQt.h"
480 #include "PythonQt.h"
481 #include <QApplication>
481 #include <QApplication>
482 ...
482 ...
483
483
484 int main( int argc, char **argv )
484 int main( int argc, char **argv )
485 {
485 {
486
486
487 QApplication qapp(argc, argv);
487 QApplication qapp(argc, argv);
488
488
489 // init PythonQt and Python itself
489 // init PythonQt and Python itself
490 PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
490 PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
491
491
492
492
493 // get a smart pointer to the __main__ module of the Python interpreter
493 // get a smart pointer to the __main__ module of the Python interpreter
494 PythonQtObjectPtr mainContext = PythonQt::self()->getMainModule();
494 PythonQtObjectPtr mainContext = PythonQt::self()->getMainModule();
495
495
496 // add a QObject as variable of name "example" to the namespace of the __main__ module
496 // add a QObject as variable of name "example" to the namespace of the __main__ module
497 PyExampleObject example;
497 PyExampleObject example;
498 PythonQt::self()->addObject(mainContext, "example", &example);
498 PythonQt::self()->addObject(mainContext, "example", &example);
499
499
500 // do something
500 // do something
501 PythonQt::self()->runScript(mainContext, "print example\n");
501 PythonQt::self()->runScript(mainContext, "print example\n");
502 PythonQt::self()->runScript(mainContext, "def multiply(a,b):\n return a*b;\n");
502 PythonQt::self()->runScript(mainContext, "def multiply(a,b):\n return a*b;\n");
503 QVariantList args;
503 QVariantList args;
504 args << 42 << 47;
504 args << 42 << 47;
505 QVariant result = PythonQt::self()->call(mainContext,"multiply", args);
505 QVariant result = PythonQt::self()->call(mainContext,"multiply", args);
506 ...
506 ...
507 \endcode
507 \endcode
508
508
509
509
510 */
510 */
@@ -1,328 +1,351
1 /*
1 /*
2 *
2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 *
4 *
5 * This library is free software; you can redistribute it and/or
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
8 * version 2.1 of the License, or (at your option) any later version.
9 *
9 *
10 * This library is distributed in the hope that it will be useful,
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
13 * Lesser General Public License for more details.
14 *
14 *
15 * Further, this software is distributed without any warranty that it is
15 * Further, this software is distributed without any warranty that it is
16 * free of the rightful claim of any third person regarding infringement
16 * free of the rightful claim of any third person regarding infringement
17 * or the like. Any license provided herein, whether implied or
17 * or the like. Any license provided herein, whether implied or
18 * otherwise, applies only to this software file. Patent licenses, if
18 * otherwise, applies only to this software file. Patent licenses, if
19 * any, provided herein do not apply to combinations of this program with
19 * any, provided herein do not apply to combinations of this program with
20 * other software, or any other product whatsoever.
20 * other software, or any other product whatsoever.
21 *
21 *
22 * You should have received a copy of the GNU Lesser General Public
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 * 28359 Bremen, Germany or:
27 * 28359 Bremen, Germany or:
28 *
28 *
29 * http://www.mevis.de
29 * http://www.mevis.de
30 *
30 *
31 */
31 */
32
32
33 //----------------------------------------------------------------------------------
33 //----------------------------------------------------------------------------------
34 /*!
34 /*!
35 // \file PythonQtMethodInfo.cpp
35 // \file PythonQtMethodInfo.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 "PythonQtMethodInfo.h"
42 #include "PythonQtMethodInfo.h"
43 #include "PythonQtClassInfo.h"
43 #include "PythonQtClassInfo.h"
44 #include <iostream>
44 #include <iostream>
45
45
46 QHash<QByteArray, PythonQtMethodInfo*> PythonQtMethodInfo::_cachedSignatures;
46 QHash<QByteArray, PythonQtMethodInfo*> PythonQtMethodInfo::_cachedSignatures;
47 QHash<QByteArray, QByteArray> PythonQtMethodInfo::_parameterNameAliases;
47 QHash<QByteArray, QByteArray> PythonQtMethodInfo::_parameterNameAliases;
48
48
49 PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo)
49 PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo)
50 {
50 {
51 #ifdef PYTHONQT_DEBUG
51 #ifdef PYTHONQT_DEBUG
52 QByteArray sig(meta.signature());
52 QByteArray sig(meta.signature());
53 sig = sig.mid(sig.indexOf('('));
53 sig = sig.mid(sig.indexOf('('));
54 QByteArray fullSig = QByteArray(meta.typeName()) + " " + sig;
54 QByteArray fullSig = QByteArray(meta.typeName()) + " " + sig;
55 std::cout << "caching " << fullSig.data() << std::endl;
55 std::cout << "caching " << fullSig.data() << std::endl;
56 #endif
56 #endif
57
57
58 ParameterInfo type;
58 ParameterInfo type;
59 fillParameterInfo(type, QByteArray(meta.typeName()), classInfo);
59 fillParameterInfo(type, QByteArray(meta.typeName()), classInfo);
60 _parameters.append(type);
60 _parameters.append(type);
61 QByteArray name;
62 QList<QByteArray> names = meta.parameterTypes();
61 QList<QByteArray> names = meta.parameterTypes();
63 foreach (name, names) {
62 foreach (const QByteArray& name, names) {
64 fillParameterInfo(type, name, classInfo);
63 fillParameterInfo(type, name, classInfo);
65 _parameters.append(type);
64 _parameters.append(type);
66 }
65 }
67 }
66 }
68
67
68 PythonQtMethodInfo::PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args)
69 {
70 ParameterInfo type;
71 fillParameterInfo(type, typeName, NULL);
72 _parameters.append(type);
73 foreach (const QByteArray& name, args) {
74 fillParameterInfo(type, name, NULL);
75 _parameters.append(type);
76 }
77 }
78
69 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo)
79 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo)
70 {
80 {
71 QByteArray sig(signal.signature());
81 QByteArray sig(signal.signature());
72 sig = sig.mid(sig.indexOf('('));
82 sig = sig.mid(sig.indexOf('('));
73 QByteArray fullSig = QByteArray(signal.typeName()) + " " + sig;
83 QByteArray fullSig = QByteArray(signal.typeName()) + " " + sig;
74 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
84 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
75 if (!result) {
85 if (!result) {
76 result = new PythonQtMethodInfo(signal, classInfo);
86 result = new PythonQtMethodInfo(signal, classInfo);
77 _cachedSignatures.insert(fullSig, result);
87 _cachedSignatures.insert(fullSig, result);
78 }
88 }
79 return result;
89 return result;
80 }
90 }
81
91
82 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromMetaObjectAndSignature(const QMetaObject* metaObject, const char* signature)
92 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(int numArgs, const char** args)
83 {
93 {
84 QByteArray sig = QMetaObject::normalizedSignature(signature);
94 QByteArray typeName = args[0];
85 int idx = metaObject->indexOfMethod(sig);
95 QList<QByteArray> arguments;
86 QMetaMethod meta = metaObject->method(idx);
96 QByteArray fullSig = typeName;
87 return PythonQtMethodInfo::getCachedMethodInfo(meta, NULL);
97 fullSig += "(";
98 for (int i =1;i<numArgs; i++) {
99 if (i>1) {
100 fullSig += ",";
101 }
102 arguments << QByteArray(args[i]);
103 }
104 fullSig += ")";
105 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
106 if (!result) {
107 result = new PythonQtMethodInfo(typeName, arguments);
108 _cachedSignatures.insert(fullSig, result);
109 }
110 return result;
88 }
111 }
89
112
90 void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo)
113 void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo)
91 {
114 {
92 QByteArray name = orgName;
115 QByteArray name = orgName;
93
116
94 type.enumWrapper = NULL;
117 type.enumWrapper = NULL;
95
118
96 int len = name.length();
119 int len = name.length();
97 if (len>0) {
120 if (len>0) {
98 if (strncmp(name.constData(), "const ", 6)==0) {
121 if (strncmp(name.constData(), "const ", 6)==0) {
99 name = name.mid(6);
122 name = name.mid(6);
100 len -= 6;
123 len -= 6;
101 type.isConst = true;
124 type.isConst = true;
102 } else {
125 } else {
103 type.isConst = false;
126 type.isConst = false;
104 }
127 }
105 bool hadPointer = false;
128 bool hadPointer = false;
106 bool hadReference = false;
129 bool hadReference = false;
107 // remove * and & from the end of the string, handle & and * the same way
130 // remove * and & from the end of the string, handle & and * the same way
108 while (name.at(len-1) == '*') {
131 while (name.at(len-1) == '*') {
109 len--;
132 len--;
110 hadPointer = true;
133 hadPointer = true;
111 }
134 }
112 while (name.at(len-1) == '&') {
135 while (name.at(len-1) == '&') {
113 len--;
136 len--;
114 hadReference = true;
137 hadReference = true;
115 }
138 }
116 if (len!=name.length()) {
139 if (len!=name.length()) {
117 name = name.left(len);
140 name = name.left(len);
118 }
141 }
119 type.isPointer = hadPointer;
142 type.isPointer = hadPointer;
120
143
121 QByteArray alias = _parameterNameAliases.value(name);
144 QByteArray alias = _parameterNameAliases.value(name);
122 if (!alias.isEmpty()) {
145 if (!alias.isEmpty()) {
123 name = alias;
146 name = alias;
124 }
147 }
125
148
126 type.typeId = nameToType(name);
149 type.typeId = nameToType(name);
127 if (!type.isPointer && type.typeId == Unknown) {
150 if (!type.isPointer && type.typeId == Unknown) {
128 type.typeId = QMetaType::type(name.constData());
151 type.typeId = QMetaType::type(name.constData());
129 if (type.typeId == QMetaType::Void) {
152 if (type.typeId == QMetaType::Void) {
130 type.typeId = Unknown;
153 type.typeId = Unknown;
131 }
154 }
132 }
155 }
133 type.name = name;
156 type.name = name;
134
157
135 if (type.typeId == PythonQtMethodInfo::Unknown || type.typeId >= QMetaType::User) {
158 if (type.typeId == PythonQtMethodInfo::Unknown || type.typeId >= QMetaType::User) {
136 bool isLocalEnum;
159 bool isLocalEnum;
137 // TODOXXX: make use of this flag!
160 // TODOXXX: make use of this flag!
138 type.enumWrapper = PythonQtClassInfo::findEnumWrapper(type.name, classInfo, &isLocalEnum);
161 type.enumWrapper = PythonQtClassInfo::findEnumWrapper(type.name, classInfo, &isLocalEnum);
139 }
162 }
140 } else {
163 } else {
141 type.typeId = QMetaType::Void;
164 type.typeId = QMetaType::Void;
142 type.isPointer = false;
165 type.isPointer = false;
143 type.isConst = false;
166 type.isConst = false;
144 }
167 }
145 }
168 }
146
169
147 int PythonQtMethodInfo::nameToType(const char* name)
170 int PythonQtMethodInfo::nameToType(const char* name)
148 {
171 {
149 if (_parameterTypeDict.isEmpty()) {
172 if (_parameterTypeDict.isEmpty()) {
150 // we could also use QMetaType::nameToType, but that does a string compare search
173 // we could also use QMetaType::nameToType, but that does a string compare search
151 // and does not support QVariant
174 // and does not support QVariant
152
175
153 // QMetaType names
176 // QMetaType names
154 _parameterTypeDict.insert("long", QMetaType::Long);
177 _parameterTypeDict.insert("long", QMetaType::Long);
155 _parameterTypeDict.insert("int", QMetaType::Int);
178 _parameterTypeDict.insert("int", QMetaType::Int);
156 _parameterTypeDict.insert("short", QMetaType::Short);
179 _parameterTypeDict.insert("short", QMetaType::Short);
157 _parameterTypeDict.insert("char", QMetaType::Char);
180 _parameterTypeDict.insert("char", QMetaType::Char);
158 _parameterTypeDict.insert("ulong", QMetaType::ULong);
181 _parameterTypeDict.insert("ulong", QMetaType::ULong);
159 _parameterTypeDict.insert("unsigned long", QMetaType::ULong);
182 _parameterTypeDict.insert("unsigned long", QMetaType::ULong);
160 _parameterTypeDict.insert("uint", QMetaType::UInt);
183 _parameterTypeDict.insert("uint", QMetaType::UInt);
161 _parameterTypeDict.insert("unsigned int", QMetaType::UInt);
184 _parameterTypeDict.insert("unsigned int", QMetaType::UInt);
162 _parameterTypeDict.insert("ushort", QMetaType::UShort);
185 _parameterTypeDict.insert("ushort", QMetaType::UShort);
163 _parameterTypeDict.insert("unsigned short", QMetaType::UShort);
186 _parameterTypeDict.insert("unsigned short", QMetaType::UShort);
164 _parameterTypeDict.insert("uchar", QMetaType::UChar);
187 _parameterTypeDict.insert("uchar", QMetaType::UChar);
165 _parameterTypeDict.insert("unsigned char", QMetaType::UChar);
188 _parameterTypeDict.insert("unsigned char", QMetaType::UChar);
166 _parameterTypeDict.insert("bool", QMetaType::Bool);
189 _parameterTypeDict.insert("bool", QMetaType::Bool);
167 _parameterTypeDict.insert("float", QMetaType::Float);
190 _parameterTypeDict.insert("float", QMetaType::Float);
168 _parameterTypeDict.insert("double", QMetaType::Double);
191 _parameterTypeDict.insert("double", QMetaType::Double);
169 _parameterTypeDict.insert("qreal", QMetaType::Double);
192 _parameterTypeDict.insert("qreal", QMetaType::Double);
170 _parameterTypeDict.insert("QChar", QMetaType::QChar);
193 _parameterTypeDict.insert("QChar", QMetaType::QChar);
171 _parameterTypeDict.insert("QByteArray", QMetaType::QByteArray);
194 _parameterTypeDict.insert("QByteArray", QMetaType::QByteArray);
172 _parameterTypeDict.insert("Q3CString", QMetaType::QByteArray);
195 _parameterTypeDict.insert("Q3CString", QMetaType::QByteArray);
173 _parameterTypeDict.insert("QString", QMetaType::QString);
196 _parameterTypeDict.insert("QString", QMetaType::QString);
174 _parameterTypeDict.insert("", QMetaType::Void);
197 _parameterTypeDict.insert("", QMetaType::Void);
175 _parameterTypeDict.insert("void", QMetaType::Void);
198 _parameterTypeDict.insert("void", QMetaType::Void);
176 // QVariant names
199 // QVariant names
177 _parameterTypeDict.insert("Q_LLONG", QMetaType::LongLong);
200 _parameterTypeDict.insert("Q_LLONG", QMetaType::LongLong);
178 _parameterTypeDict.insert("Q_ULLONG", QMetaType::ULongLong);
201 _parameterTypeDict.insert("Q_ULLONG", QMetaType::ULongLong);
179 _parameterTypeDict.insert("qlonglong", QMetaType::LongLong);
202 _parameterTypeDict.insert("qlonglong", QMetaType::LongLong);
180 _parameterTypeDict.insert("qulonglong", QMetaType::ULongLong);
203 _parameterTypeDict.insert("qulonglong", QMetaType::ULongLong);
181 _parameterTypeDict.insert("qint64", QMetaType::LongLong);
204 _parameterTypeDict.insert("qint64", QMetaType::LongLong);
182 _parameterTypeDict.insert("quint64", QMetaType::ULongLong);
205 _parameterTypeDict.insert("quint64", QMetaType::ULongLong);
183 _parameterTypeDict.insert("QIconSet", QMetaType::QIcon);
206 _parameterTypeDict.insert("QIconSet", QMetaType::QIcon);
184 _parameterTypeDict.insert("QVariantMap", QMetaType::QVariantMap);
207 _parameterTypeDict.insert("QVariantMap", QMetaType::QVariantMap);
185 _parameterTypeDict.insert("QVariantList", QMetaType::QVariantList);
208 _parameterTypeDict.insert("QVariantList", QMetaType::QVariantList);
186 _parameterTypeDict.insert("QMap<QString,QVariant>", QMetaType::QVariantMap);
209 _parameterTypeDict.insert("QMap<QString,QVariant>", QMetaType::QVariantMap);
187 _parameterTypeDict.insert("QList<QVariant>", QMetaType::QVariantList);
210 _parameterTypeDict.insert("QList<QVariant>", QMetaType::QVariantList);
188 _parameterTypeDict.insert("QStringList", QMetaType::QStringList);
211 _parameterTypeDict.insert("QStringList", QMetaType::QStringList);
189 _parameterTypeDict.insert("QBitArray", QMetaType::QBitArray);
212 _parameterTypeDict.insert("QBitArray", QMetaType::QBitArray);
190 _parameterTypeDict.insert("QDate", QMetaType::QDate);
213 _parameterTypeDict.insert("QDate", QMetaType::QDate);
191 _parameterTypeDict.insert("QTime", QMetaType::QTime);
214 _parameterTypeDict.insert("QTime", QMetaType::QTime);
192 _parameterTypeDict.insert("QDateTime", QMetaType::QDateTime);
215 _parameterTypeDict.insert("QDateTime", QMetaType::QDateTime);
193 _parameterTypeDict.insert("QUrl", QMetaType::QUrl);
216 _parameterTypeDict.insert("QUrl", QMetaType::QUrl);
194 _parameterTypeDict.insert("QLocale", QMetaType::QLocale);
217 _parameterTypeDict.insert("QLocale", QMetaType::QLocale);
195 _parameterTypeDict.insert("QRect", QMetaType::QRect);
218 _parameterTypeDict.insert("QRect", QMetaType::QRect);
196 _parameterTypeDict.insert("QRectf", QMetaType::QRectF);
219 _parameterTypeDict.insert("QRectf", QMetaType::QRectF);
197 _parameterTypeDict.insert("QSize", QMetaType::QSize);
220 _parameterTypeDict.insert("QSize", QMetaType::QSize);
198 _parameterTypeDict.insert("QSizef", QMetaType::QSizeF);
221 _parameterTypeDict.insert("QSizef", QMetaType::QSizeF);
199 _parameterTypeDict.insert("QLine", QMetaType::QLine);
222 _parameterTypeDict.insert("QLine", QMetaType::QLine);
200 _parameterTypeDict.insert("QLinef", QMetaType::QLineF);
223 _parameterTypeDict.insert("QLinef", QMetaType::QLineF);
201 _parameterTypeDict.insert("QPoint", QMetaType::QPoint);
224 _parameterTypeDict.insert("QPoint", QMetaType::QPoint);
202 _parameterTypeDict.insert("QPointf", QMetaType::QPointF);
225 _parameterTypeDict.insert("QPointf", QMetaType::QPointF);
203 _parameterTypeDict.insert("QRegExp", QMetaType::QRegExp);
226 _parameterTypeDict.insert("QRegExp", QMetaType::QRegExp);
204 // _parameterTypeDict.insert("QColorGroup", QMetaType::QColorGroup);
227 // _parameterTypeDict.insert("QColorGroup", QMetaType::QColorGroup);
205 _parameterTypeDict.insert("QFont", QMetaType::QFont);
228 _parameterTypeDict.insert("QFont", QMetaType::QFont);
206 _parameterTypeDict.insert("QPixmap", QMetaType::QPixmap);
229 _parameterTypeDict.insert("QPixmap", QMetaType::QPixmap);
207 _parameterTypeDict.insert("QBrush", QMetaType::QBrush);
230 _parameterTypeDict.insert("QBrush", QMetaType::QBrush);
208 _parameterTypeDict.insert("QColor", QMetaType::QColor);
231 _parameterTypeDict.insert("QColor", QMetaType::QColor);
209 _parameterTypeDict.insert("QCursor", QMetaType::QCursor);
232 _parameterTypeDict.insert("QCursor", QMetaType::QCursor);
210 _parameterTypeDict.insert("QPalette", QMetaType::QPalette);
233 _parameterTypeDict.insert("QPalette", QMetaType::QPalette);
211 _parameterTypeDict.insert("QIcon", QMetaType::QIcon);
234 _parameterTypeDict.insert("QIcon", QMetaType::QIcon);
212 _parameterTypeDict.insert("QImage", QMetaType::QPolygon);
235 _parameterTypeDict.insert("QImage", QMetaType::QPolygon);
213 _parameterTypeDict.insert("QRegion", QMetaType::QRegion);
236 _parameterTypeDict.insert("QRegion", QMetaType::QRegion);
214 _parameterTypeDict.insert("QBitmap", QMetaType::QBitmap);
237 _parameterTypeDict.insert("QBitmap", QMetaType::QBitmap);
215 _parameterTypeDict.insert("QSizePolicy", QMetaType::QSizePolicy);
238 _parameterTypeDict.insert("QSizePolicy", QMetaType::QSizePolicy);
216 _parameterTypeDict.insert("QKeySequence", QMetaType::QKeySequence);
239 _parameterTypeDict.insert("QKeySequence", QMetaType::QKeySequence);
217 _parameterTypeDict.insert("QPen", QMetaType::QPen);
240 _parameterTypeDict.insert("QPen", QMetaType::QPen);
218 _parameterTypeDict.insert("QTextLength", QMetaType::QTextLength);
241 _parameterTypeDict.insert("QTextLength", QMetaType::QTextLength);
219 _parameterTypeDict.insert("QTextFormat", QMetaType::QTextFormat);
242 _parameterTypeDict.insert("QTextFormat", QMetaType::QTextFormat);
220 _parameterTypeDict.insert("QMatrix", QMetaType::QMatrix);
243 _parameterTypeDict.insert("QMatrix", QMetaType::QMatrix);
221 _parameterTypeDict.insert("QVariant", PythonQtMethodInfo::Variant);
244 _parameterTypeDict.insert("QVariant", PythonQtMethodInfo::Variant);
222 // own special types... (none so far, could be e.g. ObjectList
245 // own special types... (none so far, could be e.g. ObjectList
223 }
246 }
224 QHash<QByteArray, int>::const_iterator it = _parameterTypeDict.find(name);
247 QHash<QByteArray, int>::const_iterator it = _parameterTypeDict.find(name);
225 if (it!=_parameterTypeDict.end()) {
248 if (it!=_parameterTypeDict.end()) {
226 return it.value();
249 return it.value();
227 } else {
250 } else {
228 return PythonQtMethodInfo::Unknown;
251 return PythonQtMethodInfo::Unknown;
229 }
252 }
230 }
253 }
231
254
232 void PythonQtMethodInfo::cleanupCachedMethodInfos()
255 void PythonQtMethodInfo::cleanupCachedMethodInfos()
233 {
256 {
234 QHashIterator<QByteArray, PythonQtMethodInfo *> i(_cachedSignatures);
257 QHashIterator<QByteArray, PythonQtMethodInfo *> i(_cachedSignatures);
235 while (i.hasNext()) {
258 while (i.hasNext()) {
236 delete i.next().value();
259 delete i.next().value();
237 }
260 }
238 }
261 }
239
262
240 void PythonQtMethodInfo::addParameterTypeAlias(const QByteArray& alias, const QByteArray& name)
263 void PythonQtMethodInfo::addParameterTypeAlias(const QByteArray& alias, const QByteArray& name)
241 {
264 {
242 _parameterNameAliases.insert(alias, name);
265 _parameterNameAliases.insert(alias, name);
243 }
266 }
244
267
245 //-------------------------------------------------------------------------------------------------
268 //-------------------------------------------------------------------------------------------------
246
269
247 void PythonQtSlotInfo::deleteOverloadsAndThis()
270 void PythonQtSlotInfo::deleteOverloadsAndThis()
248 {
271 {
249 PythonQtSlotInfo* cur = this;
272 PythonQtSlotInfo* cur = this;
250 while(cur->nextInfo()) {
273 while(cur->nextInfo()) {
251 PythonQtSlotInfo* next = cur->nextInfo();
274 PythonQtSlotInfo* next = cur->nextInfo();
252 delete cur;
275 delete cur;
253 cur = next;
276 cur = next;
254 }
277 }
255 }
278 }
256
279
257
280
258 QString PythonQtSlotInfo::fullSignature()
281 QString PythonQtSlotInfo::fullSignature()
259 {
282 {
260 bool skipFirstArg = isInstanceDecorator();
283 bool skipFirstArg = isInstanceDecorator();
261 QString result = _meta.typeName();
284 QString result = _meta.typeName();
262 QByteArray sig = slotName();
285 QByteArray sig = slotName();
263 QList<QByteArray> names = _meta.parameterNames();
286 QList<QByteArray> names = _meta.parameterNames();
264
287
265 bool isStatic = false;
288 bool isStatic = false;
266 bool isConstructor = false;
289 bool isConstructor = false;
267 bool isDestructor = false;
290 bool isDestructor = false;
268
291
269 if (_type == ClassDecorator) {
292 if (_type == ClassDecorator) {
270 if (sig.startsWith("new_")) {
293 if (sig.startsWith("new_")) {
271 sig = sig.mid(strlen("new_"));
294 sig = sig.mid(strlen("new_"));
272 isConstructor = true;
295 isConstructor = true;
273 } else if (sig.startsWith("delete_")) {
296 } else if (sig.startsWith("delete_")) {
274 sig = sig.mid(strlen("delete_"));
297 sig = sig.mid(strlen("delete_"));
275 isDestructor = true;
298 isDestructor = true;
276 } else if(sig.startsWith("static_")) {
299 } else if(sig.startsWith("static_")) {
277 isStatic = true;
300 isStatic = true;
278 sig = sig.mid(strlen("static_"));
301 sig = sig.mid(strlen("static_"));
279 int idx = sig.indexOf("_");
302 int idx = sig.indexOf("_");
280 if (idx>=0) {
303 if (idx>=0) {
281 sig = sig.mid(idx+1);
304 sig = sig.mid(idx+1);
282 }
305 }
283 }
306 }
284 }
307 }
285
308
286 result += QByteArray(" ") + sig;
309 result += QByteArray(" ") + sig;
287 result += "(";
310 result += "(";
288
311
289 int lastEntry = _parameters.count()-1;
312 int lastEntry = _parameters.count()-1;
290 for (int i = skipFirstArg?2:1; i<_parameters.count(); i++) {
313 for (int i = skipFirstArg?2:1; i<_parameters.count(); i++) {
291 if (_parameters.at(i).isConst) {
314 if (_parameters.at(i).isConst) {
292 result += "const ";
315 result += "const ";
293 }
316 }
294 result += _parameters.at(i).name;
317 result += _parameters.at(i).name;
295 if (_parameters.at(i).isPointer) {
318 if (_parameters.at(i).isPointer) {
296 result += "*";
319 result += "*";
297 }
320 }
298 if (!names.at(i-1).isEmpty()) {
321 if (!names.at(i-1).isEmpty()) {
299 result += " ";
322 result += " ";
300 result += names.at(i-1);
323 result += names.at(i-1);
301 }
324 }
302 if (i!=lastEntry) {
325 if (i!=lastEntry) {
303 result += ", ";
326 result += ", ";
304 }
327 }
305 }
328 }
306 result += ")";
329 result += ")";
307
330
308 if (isStatic) {
331 if (isStatic) {
309 result = QString("static ") + result;
332 result = QString("static ") + result;
310 }
333 }
311 if (isConstructor) {
334 if (isConstructor) {
312 // result = QString("constructor ") + result;
335 // result = QString("constructor ") + result;
313 }
336 }
314 if (isDestructor) {
337 if (isDestructor) {
315 result = QString("~") + result;
338 result = QString("~") + result;
316 }
339 }
317 return result;
340 return result;
318 }
341 }
319
342
320
343
321 QByteArray PythonQtSlotInfo::slotName()
344 QByteArray PythonQtSlotInfo::slotName()
322 {
345 {
323 QByteArray sig(_meta.signature());
346 QByteArray sig(_meta.signature());
324 int idx = sig.indexOf('(');
347 int idx = sig.indexOf('(');
325 sig = sig.left(idx);
348 sig = sig.left(idx);
326 return sig;
349 return sig;
327 }
350 }
328
351
@@ -1,189 +1,190
1 #ifndef _PYTHONQTMETHODINFO_H
1 #ifndef _PYTHONQTMETHODINFO_H
2 #define _PYTHONQTMETHODINFO_H
2 #define _PYTHONQTMETHODINFO_H
3
3
4 /*
4 /*
5 *
5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
7 *
7 *
8 * This library is free software; you can redistribute it and/or
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
11 * version 2.1 of the License, or (at your option) any later version.
12 *
12 *
13 * This library is distributed in the hope that it will be useful,
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
16 * Lesser General Public License for more details.
17 *
17 *
18 * Further, this software is distributed without any warranty that it is
18 * Further, this software is distributed without any warranty that it is
19 * free of the rightful claim of any third person regarding infringement
19 * free of the rightful claim of any third person regarding infringement
20 * or the like. Any license provided herein, whether implied or
20 * or the like. Any license provided herein, whether implied or
21 * otherwise, applies only to this software file. Patent licenses, if
21 * otherwise, applies only to this software file. Patent licenses, if
22 * any, provided herein do not apply to combinations of this program with
22 * any, provided herein do not apply to combinations of this program with
23 * other software, or any other product whatsoever.
23 * other software, or any other product whatsoever.
24 *
24 *
25 * You should have received a copy of the GNU Lesser General Public
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
30 * 28359 Bremen, Germany or:
30 * 28359 Bremen, Germany or:
31 *
31 *
32 * http://www.mevis.de
32 * http://www.mevis.de
33 *
33 *
34 */
34 */
35
35
36 //----------------------------------------------------------------------------------
36 //----------------------------------------------------------------------------------
37 /*!
37 /*!
38 // \file PythonQtMethodInfo.h
38 // \file PythonQtMethodInfo.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
46
47 #include <QByteArray>
47 #include <QByteArray>
48 #include <QHash>
48 #include <QHash>
49 #include <QList>
49 #include <QList>
50 #include <QMetaMethod>
50 #include <QMetaMethod>
51
51
52 class PythonQtClassInfo;
52 class PythonQtClassInfo;
53 struct _object;
53 struct _object;
54 typedef struct _object PyObject;
54 typedef struct _object PyObject;
55
55
56 //! stores information about a specific signal/slot/method
56 //! stores information about a specific signal/slot/method
57 class PYTHONQT_EXPORT PythonQtMethodInfo
57 class PYTHONQT_EXPORT PythonQtMethodInfo
58 {
58 {
59 public:
59 public:
60 enum ParameterType {
60 enum ParameterType {
61 Unknown = -1,
61 Unknown = -1,
62 Variant = -2
62 Variant = -2
63 };
63 };
64
64
65 //! stores the QVariant id (if available) and the name of the type
65 //! stores the QVariant id (if available) and the name of the type
66 struct ParameterInfo {
66 struct ParameterInfo {
67 QByteArray name;
67 QByteArray name;
68 PyObject* enumWrapper; // if it is an enum, a pointer to the enum wrapper
68 PyObject* enumWrapper; // if it is an enum, a pointer to the enum wrapper
69 int typeId; // a mixture from QMetaType and ParameterType
69 int typeId; // a mixture from QMetaType and ParameterType
70 bool isPointer;
70 bool isPointer;
71 bool isConst;
71 bool isConst;
72 };
72 };
73
73
74 PythonQtMethodInfo() {};
74 PythonQtMethodInfo() {};
75 ~PythonQtMethodInfo() {};
75 ~PythonQtMethodInfo() {};
76 PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo);
76 PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo);
77 PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args);
77 PythonQtMethodInfo(const PythonQtMethodInfo& other) {
78 PythonQtMethodInfo(const PythonQtMethodInfo& other) {
78 _parameters = other._parameters;
79 _parameters = other._parameters;
79 }
80 }
80
81
81 //! returns the method info of the signature, uses a cache internally to speed up
82 //! returns the method info of the signature, uses a cache internally to speed up
82 //! multiple requests for the same method, classInfo is passed to allow local enum resolution (if NULL is passed, no local enums are recognized)
83 //! multiple requests for the same method, classInfo is passed to allow local enum resolution (if NULL is passed, no local enums are recognized)
83 static const PythonQtMethodInfo* getCachedMethodInfo(const QMetaMethod& method, PythonQtClassInfo* classInfo);
84 static const PythonQtMethodInfo* getCachedMethodInfo(const QMetaMethod& method, PythonQtClassInfo* classInfo);
84
85
85 //! get the cached method info by finding the meta method on the meta object via its signature, enums are only supported with leading namespace::
86 //! get the cached method info using the passed in list of return value and arguments, return value needs to be passed as first arg
86 static const PythonQtMethodInfo* getCachedMethodInfoFromMetaObjectAndSignature(const QMetaObject* metaObject, const char* signature);
87 static const PythonQtMethodInfo* getCachedMethodInfoFromArgumentList(int numArgs, const char** args);
87
88
88 //! cleanup the cache
89 //! cleanup the cache
89 static void cleanupCachedMethodInfos();
90 static void cleanupCachedMethodInfos();
90
91
91 //! returns the number of parameters including the return value
92 //! returns the number of parameters including the return value
92 int parameterCount() const { return _parameters.size(); };
93 int parameterCount() const { return _parameters.size(); };
93
94
94 //! returns the id for the given type (using an internal dictionary)
95 //! returns the id for the given type (using an internal dictionary)
95 static int nameToType(const char* name);
96 static int nameToType(const char* name);
96
97
97 //! get the parameter infos
98 //! get the parameter infos
98 const QList<ParameterInfo>& parameters() const { return _parameters; }
99 const QList<ParameterInfo>& parameters() const { return _parameters; }
99
100
100 //! add an alias for a typename, e.g. QObjectList and QList<QObject*>.
101 //! add an alias for a typename, e.g. QObjectList and QList<QObject*>.
101 static void addParameterTypeAlias(const QByteArray& alias, const QByteArray& name);
102 static void addParameterTypeAlias(const QByteArray& alias, const QByteArray& name);
102
103
103 protected:
104 protected:
104 static void fillParameterInfo(ParameterInfo& type, const QByteArray& name, PythonQtClassInfo* classInfo);
105 static void fillParameterInfo(ParameterInfo& type, const QByteArray& name, PythonQtClassInfo* classInfo);
105
106
106 static QHash<QByteArray, int> _parameterTypeDict;
107 static QHash<QByteArray, int> _parameterTypeDict;
107 static QHash<QByteArray, QByteArray> _parameterNameAliases;
108 static QHash<QByteArray, QByteArray> _parameterNameAliases;
108
109
109 //! stores the cached signatures of methods to speedup mapping from Qt to Python types
110 //! stores the cached signatures of methods to speedup mapping from Qt to Python types
110 static QHash<QByteArray, PythonQtMethodInfo*> _cachedSignatures;
111 static QHash<QByteArray, PythonQtMethodInfo*> _cachedSignatures;
111
112
112 QList<ParameterInfo> _parameters;
113 QList<ParameterInfo> _parameters;
113 };
114 };
114
115
115 //! stores information about a slot, including a next pointer to overloaded slots
116 //! stores information about a slot, including a next pointer to overloaded slots
116 class PythonQtSlotInfo : public PythonQtMethodInfo
117 class PythonQtSlotInfo : public PythonQtMethodInfo
117 {
118 {
118 public:
119 public:
119 enum Type {
120 enum Type {
120 MemberSlot, InstanceDecorator, ClassDecorator
121 MemberSlot, InstanceDecorator, ClassDecorator
121 };
122 };
122
123
123 PythonQtSlotInfo(const PythonQtSlotInfo& info):PythonQtMethodInfo() {
124 PythonQtSlotInfo(const PythonQtSlotInfo& info):PythonQtMethodInfo() {
124 _meta = info._meta;
125 _meta = info._meta;
125 _parameters = info._parameters;
126 _parameters = info._parameters;
126 _slotIndex = info._slotIndex;
127 _slotIndex = info._slotIndex;
127 _next = NULL;
128 _next = NULL;
128 _decorator = info._decorator;
129 _decorator = info._decorator;
129 _type = info._type;
130 _type = info._type;
130 _upcastingOffset = 0;
131 _upcastingOffset = 0;
131 }
132 }
132
133
133 PythonQtSlotInfo(PythonQtClassInfo* classInfo, const QMetaMethod& meta, int slotIndex, QObject* decorator = NULL, Type type = MemberSlot ):PythonQtMethodInfo()
134 PythonQtSlotInfo(PythonQtClassInfo* classInfo, const QMetaMethod& meta, int slotIndex, QObject* decorator = NULL, Type type = MemberSlot ):PythonQtMethodInfo()
134 {
135 {
135 const PythonQtMethodInfo* info = getCachedMethodInfo(meta, classInfo);
136 const PythonQtMethodInfo* info = getCachedMethodInfo(meta, classInfo);
136 _meta = meta;
137 _meta = meta;
137 _parameters = info->parameters();
138 _parameters = info->parameters();
138 _slotIndex = slotIndex;
139 _slotIndex = slotIndex;
139 _next = NULL;
140 _next = NULL;
140 _decorator = decorator;
141 _decorator = decorator;
141 _type = type;
142 _type = type;
142 _upcastingOffset = 0;
143 _upcastingOffset = 0;
143 }
144 }
144
145
145
146
146 public:
147 public:
147
148
148 void deleteOverloadsAndThis();
149 void deleteOverloadsAndThis();
149
150
150 const QMetaMethod* metaMethod() const { return &_meta; }
151 const QMetaMethod* metaMethod() const { return &_meta; }
151
152
152 void setUpcastingOffset(int upcastingOffset) { _upcastingOffset = upcastingOffset; }
153 void setUpcastingOffset(int upcastingOffset) { _upcastingOffset = upcastingOffset; }
153
154
154 int upcastingOffset() const { return _upcastingOffset; }
155 int upcastingOffset() const { return _upcastingOffset; }
155
156
156 //! get the index of the slot (needed for qt_metacall)
157 //! get the index of the slot (needed for qt_metacall)
157 int slotIndex() const { return _slotIndex; }
158 int slotIndex() const { return _slotIndex; }
158
159
159 //! get next overloaded slot (which has the same name)
160 //! get next overloaded slot (which has the same name)
160 PythonQtSlotInfo* nextInfo() const { return _next; }
161 PythonQtSlotInfo* nextInfo() const { return _next; }
161
162
162 //! set the next overloaded slot
163 //! set the next overloaded slot
163 void setNextInfo(PythonQtSlotInfo* next) { _next = next; }
164 void setNextInfo(PythonQtSlotInfo* next) { _next = next; }
164
165
165 //! returns if the slot is a decorator slot
166 //! returns if the slot is a decorator slot
166 bool isInstanceDecorator() { return _decorator!=NULL && _type == InstanceDecorator; }
167 bool isInstanceDecorator() { return _decorator!=NULL && _type == InstanceDecorator; }
167
168
168 //! returns if the slot is a constructor slot
169 //! returns if the slot is a constructor slot
169 bool isClassDecorator() { return _decorator!=NULL && _type == ClassDecorator; }
170 bool isClassDecorator() { return _decorator!=NULL && _type == ClassDecorator; }
170
171
171 QObject* decorator() { return _decorator; }
172 QObject* decorator() { return _decorator; }
172
173
173 //! get the full signature including return type
174 //! get the full signature including return type
174 QString fullSignature();
175 QString fullSignature();
175
176
176 //! get the short slot name
177 //! get the short slot name
177 QByteArray slotName();
178 QByteArray slotName();
178
179
179 private:
180 private:
180 int _slotIndex;
181 int _slotIndex;
181 PythonQtSlotInfo* _next;
182 PythonQtSlotInfo* _next;
182 QObject* _decorator;
183 QObject* _decorator;
183 Type _type;
184 Type _type;
184 QMetaMethod _meta;
185 QMetaMethod _meta;
185 int _upcastingOffset;
186 int _upcastingOffset;
186 };
187 };
187
188
188
189
189 #endif
190 #endif
@@ -1,233 +1,226
1 /*
1 /*
2 *
2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 *
4 *
5 * This library is free software; you can redistribute it and/or
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
8 * version 2.1 of the License, or (at your option) any later version.
9 *
9 *
10 * This library is distributed in the hope that it will be useful,
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
13 * Lesser General Public License for more details.
14 *
14 *
15 * Further, this software is distributed without any warranty that it is
15 * Further, this software is distributed without any warranty that it is
16 * free of the rightful claim of any third person regarding infringement
16 * free of the rightful claim of any third person regarding infringement
17 * or the like. Any license provided herein, whether implied or
17 * or the like. Any license provided herein, whether implied or
18 * otherwise, applies only to this software file. Patent licenses, if
18 * otherwise, applies only to this software file. Patent licenses, if
19 * any, provided herein do not apply to combinations of this program with
19 * any, provided herein do not apply to combinations of this program with
20 * other software, or any other product whatsoever.
20 * other software, or any other product whatsoever.
21 *
21 *
22 * You should have received a copy of the GNU Lesser General Public
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 * 28359 Bremen, Germany or:
27 * 28359 Bremen, Germany or:
28 *
28 *
29 * http://www.mevis.de
29 * http://www.mevis.de
30 *
30 *
31 */
31 */
32
32
33 //----------------------------------------------------------------------------------
33 //----------------------------------------------------------------------------------
34 /*!
34 /*!
35 // \file PythonQtSignalReceiver.cpp
35 // \file PythonQtSignalReceiver.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 "PythonQtSignalReceiver.h"
42 #include "PythonQtSignalReceiver.h"
43 #include "PythonQtClassInfo.h"
43 #include "PythonQtClassInfo.h"
44 #include "PythonQtMethodInfo.h"
44 #include "PythonQtMethodInfo.h"
45 #include "PythonQtConversion.h"
45 #include "PythonQtConversion.h"
46 #include <QMetaObject>
46 #include <QMetaObject>
47 #include <QMetaMethod>
47 #include <QMetaMethod>
48 #include "funcobject.h"
48 #include "funcobject.h"
49
49
50 void PythonQtSignalTarget::call(void **arguments) const {
50 void PythonQtSignalTarget::call(void **arguments) const {
51 PyObject* result = call(_callable, methodInfo(), arguments, false);
51 PyObject* result = call(_callable, methodInfo(), arguments);
52 if (result) {
52 if (result) {
53 Py_DECREF(result);
53 Py_DECREF(result);
54 }
54 }
55 }
55 }
56
56
57 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInfo* methodInfos, void **arguments, bool skipFirstArgumentOfMethodInfo)
57 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInfo* methodInfos, void **arguments, bool skipFirstArgumentOfMethodInfo)
58 {
58 {
59 // Note: we check if the callable is a PyFunctionObject and has a fixed number of arguments
59 // Note: we check if the callable is a PyFunctionObject and has a fixed number of arguments
60 // if that is the case, we only pass these arguments to python and skip the additional arguments from the signal
60 // if that is the case, we only pass these arguments to python and skip the additional arguments from the signal
61
61
62 int numPythonArgs = -1;
62 int numPythonArgs = -1;
63 if (PyFunction_Check(callable)) {
63 if (PyFunction_Check(callable)) {
64 PyObject* o = callable;
64 PyObject* o = callable;
65 PyFunctionObject* func = (PyFunctionObject*)o;
65 PyFunctionObject* func = (PyFunctionObject*)o;
66 PyCodeObject* code = (PyCodeObject*)func->func_code;
66 PyCodeObject* code = (PyCodeObject*)func->func_code;
67 if (!(code->co_flags & 0x04)) {
67 if (!(code->co_flags & 0x04)) {
68 numPythonArgs = code->co_argcount;
68 numPythonArgs = code->co_argcount;
69 } else {
69 } else {
70 // variable numbers of arguments allowed
70 // variable numbers of arguments allowed
71 }
71 }
72 } else if (PyMethod_Check(callable)) {
72 } else if (PyMethod_Check(callable)) {
73 PyObject* o = callable;
73 PyObject* o = callable;
74 PyMethodObject* method = (PyMethodObject*)o;
74 PyMethodObject* method = (PyMethodObject*)o;
75 if (PyFunction_Check(method->im_func)) {
75 if (PyFunction_Check(method->im_func)) {
76 PyFunctionObject* func = (PyFunctionObject*)method->im_func;
76 PyFunctionObject* func = (PyFunctionObject*)method->im_func;
77 PyCodeObject* code = (PyCodeObject*)func->func_code;
77 PyCodeObject* code = (PyCodeObject*)func->func_code;
78 if (!(code->co_flags & 0x04)) {
78 if (!(code->co_flags & 0x04)) {
79 numPythonArgs = code->co_argcount - 1; // we subtract one because the first is "self"
79 numPythonArgs = code->co_argcount - 1; // we subtract one because the first is "self"
80 } else {
80 } else {
81 // variable numbers of arguments allowed
81 // variable numbers of arguments allowed
82 }
82 }
83 }
83 }
84 }
84 }
85
85
86 const PythonQtMethodInfo* m = methodInfos;
86 const PythonQtMethodInfo* m = methodInfos;
87 // parameterCount includes return value:
87 // parameterCount includes return value:
88 int count = m->parameterCount();
88 int count = m->parameterCount();
89 if (skipFirstArgumentOfMethodInfo) {
90 count--;
91 }
92 if (numPythonArgs!=-1) {
89 if (numPythonArgs!=-1) {
93 if (count>numPythonArgs+1) {
90 if (count>numPythonArgs+1) {
94 // take less arguments
91 // take less arguments
95 count = numPythonArgs+1;
92 count = numPythonArgs+1;
96 }
93 }
97 }
94 }
98
95
99 PyObject* pargs = NULL;
96 PyObject* pargs = NULL;
100 if (count>1) {
97 if (count>1) {
101 pargs = PyTuple_New(count-1);
98 pargs = PyTuple_New(count-1);
102 }
99 }
103 bool err = false;
100 bool err = false;
104 // transform Qt values to Python
101 // transform Qt values to Python
105 const QList<PythonQtMethodInfo::ParameterInfo>& params = m->parameters();
102 const QList<PythonQtMethodInfo::ParameterInfo>& params = m->parameters();
106 int skipFirstOffset = 0;
107 if (skipFirstArgumentOfMethodInfo) {
108 skipFirstOffset = 1;
109 }
110 for (int i = 1; i < count; i++) {
103 for (int i = 1; i < count; i++) {
111 const PythonQtMethodInfo::ParameterInfo& param = params.at(i + skipFirstOffset);
104 const PythonQtMethodInfo::ParameterInfo& param = params.at(i);
112 PyObject* arg = PythonQtConv::ConvertQtValueToPython(param, arguments[i]);
105 PyObject* arg = PythonQtConv::ConvertQtValueToPython(param, arguments[i]);
113 if (arg) {
106 if (arg) {
114 // steals reference, no unref
107 // steals reference, no unref
115 PyTuple_SetItem(pargs, i-1,arg);
108 PyTuple_SetItem(pargs, i-1,arg);
116 } else {
109 } else {
117 err = true;
110 err = true;
118 break;
111 break;
119 }
112 }
120 }
113 }
121
114
122 PyObject* result = NULL;
115 PyObject* result = NULL;
123 if (!err) {
116 if (!err) {
124 PyErr_Clear();
117 PyErr_Clear();
125 result = PyObject_CallObject(callable, pargs);
118 result = PyObject_CallObject(callable, pargs);
126 if (result) {
119 if (result) {
127 // ok
120 // ok
128 } else {
121 } else {
129 PythonQt::self()->handleError();
122 PythonQt::self()->handleError();
130 }
123 }
131 }
124 }
132 if (pargs) {
125 if (pargs) {
133 // free the arguments again
126 // free the arguments again
134 Py_DECREF(pargs);
127 Py_DECREF(pargs);
135 }
128 }
136
129
137 return result;
130 return result;
138 }
131 }
139
132
140 //------------------------------------------------------------------------------
133 //------------------------------------------------------------------------------
141
134
142 PythonQtSignalReceiver::PythonQtSignalReceiver(QObject* obj):PythonQtSignalReceiverBase(obj)
135 PythonQtSignalReceiver::PythonQtSignalReceiver(QObject* obj):PythonQtSignalReceiverBase(obj)
143 {
136 {
144 _obj = obj;
137 _obj = obj;
145
138
146 // fetch the class info for object, since we will need to for correct enum resolution in
139 // fetch the class info for object, since we will need to for correct enum resolution in
147 // signals
140 // signals
148 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
141 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
149 if (!_objClassInfo || !_objClassInfo->isQObject()) {
142 if (!_objClassInfo || !_objClassInfo->isQObject()) {
150 PythonQt::self()->registerClass(obj->metaObject());
143 PythonQt::self()->registerClass(obj->metaObject());
151 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
144 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
152 }
145 }
153 // force decorator/enum creation
146 // force decorator/enum creation
154 _objClassInfo->decorator();
147 _objClassInfo->decorator();
155
148
156 _slotCount = staticMetaObject.methodOffset();
149 _slotCount = staticMetaObject.methodOffset();
157 }
150 }
158
151
159 PythonQtSignalReceiver::~PythonQtSignalReceiver()
152 PythonQtSignalReceiver::~PythonQtSignalReceiver()
160 {
153 {
161 PythonQt::priv()->removeSignalEmitter(_obj);
154 PythonQt::priv()->removeSignalEmitter(_obj);
162 }
155 }
163
156
164
157
165 bool PythonQtSignalReceiver::addSignalHandler(const char* signal, PyObject* callable)
158 bool PythonQtSignalReceiver::addSignalHandler(const char* signal, PyObject* callable)
166 {
159 {
167 bool flag = false;
160 bool flag = false;
168 int sigId = getSignalIndex(signal);
161 int sigId = getSignalIndex(signal);
169 if (sigId>=0) {
162 if (sigId>=0) {
170 // create PythonQtMethodInfo from signal
163 // create PythonQtMethodInfo from signal
171 QMetaMethod meta = _obj->metaObject()->method(sigId);
164 QMetaMethod meta = _obj->metaObject()->method(sigId);
172 const PythonQtMethodInfo* signalInfo = PythonQtMethodInfo::getCachedMethodInfo(meta, _objClassInfo);
165 const PythonQtMethodInfo* signalInfo = PythonQtMethodInfo::getCachedMethodInfo(meta, _objClassInfo);
173 PythonQtSignalTarget t(sigId, signalInfo, _slotCount, callable);
166 PythonQtSignalTarget t(sigId, signalInfo, _slotCount, callable);
174 _targets.append(t);
167 _targets.append(t);
175 // now connect to ourselves with the new slot id
168 // now connect to ourselves with the new slot id
176 QMetaObject::connect(_obj, sigId, this, _slotCount, Qt::AutoConnection, 0);
169 QMetaObject::connect(_obj, sigId, this, _slotCount, Qt::AutoConnection, 0);
177
170
178 _slotCount++;
171 _slotCount++;
179 flag = true;
172 flag = true;
180 }
173 }
181 return flag;
174 return flag;
182 }
175 }
183
176
184 bool PythonQtSignalReceiver::removeSignalHandler(const char* signal, PyObject* callable)
177 bool PythonQtSignalReceiver::removeSignalHandler(const char* signal, PyObject* callable)
185 {
178 {
186 bool found = false;
179 bool found = false;
187 int sigId = getSignalIndex(signal);
180 int sigId = getSignalIndex(signal);
188 if (sigId>=0) {
181 if (sigId>=0) {
189 QMutableListIterator<PythonQtSignalTarget> i(_targets);
182 QMutableListIterator<PythonQtSignalTarget> i(_targets);
190 while (i.hasNext()) {
183 while (i.hasNext()) {
191 if (i.next().isSame(sigId, callable)) {
184 if (i.next().isSame(sigId, callable)) {
192 i.remove();
185 i.remove();
193 found = true;
186 found = true;
194 break;
187 break;
195 }
188 }
196 }
189 }
197 }
190 }
198 return found;
191 return found;
199 }
192 }
200
193
201 void PythonQtSignalReceiver::removeSignalHandlers()
194 void PythonQtSignalReceiver::removeSignalHandlers()
202 {
195 {
203 _targets.clear();
196 _targets.clear();
204 }
197 }
205
198
206 int PythonQtSignalReceiver::getSignalIndex(const char* signal)
199 int PythonQtSignalReceiver::getSignalIndex(const char* signal)
207 {
200 {
208 int sigId = _obj->metaObject()->indexOfSignal(signal+1);
201 int sigId = _obj->metaObject()->indexOfSignal(signal+1);
209 if (sigId<0) {
202 if (sigId<0) {
210 QByteArray tmpSig = QMetaObject::normalizedSignature(signal+1);
203 QByteArray tmpSig = QMetaObject::normalizedSignature(signal+1);
211 sigId = _obj->metaObject()->indexOfSignal(tmpSig);
204 sigId = _obj->metaObject()->indexOfSignal(tmpSig);
212 }
205 }
213 return sigId;
206 return sigId;
214 }
207 }
215
208
216 int PythonQtSignalReceiver::qt_metacall(QMetaObject::Call c, int id, void **arguments)
209 int PythonQtSignalReceiver::qt_metacall(QMetaObject::Call c, int id, void **arguments)
217 {
210 {
218 // mlabDebugConst("PythonQt", "PythonQtSignalReceiver invoke " << _obj->className() << " " << _obj->name() << " " << id);
211 // mlabDebugConst("PythonQt", "PythonQtSignalReceiver invoke " << _obj->className() << " " << _obj->name() << " " << id);
219 if (c != QMetaObject::InvokeMetaMethod) {
212 if (c != QMetaObject::InvokeMetaMethod) {
220 QObject::qt_metacall(c, id, arguments);
213 QObject::qt_metacall(c, id, arguments);
221 }
214 }
222
215
223 bool found = false;
216 bool found = false;
224 foreach(const PythonQtSignalTarget& t, _targets) {
217 foreach(const PythonQtSignalTarget& t, _targets) {
225 if (t.slotId() == id) {
218 if (t.slotId() == id) {
226 found = true;
219 found = true;
227 t.call(arguments);
220 t.call(arguments);
228 break;
221 break;
229 }
222 }
230 }
223 }
231 return 0;
224 return 0;
232 }
225 }
233
226
@@ -1,79 +1,101
1 #ifndef _PYTHONQTSTDDECORATORS_H
1 #ifndef _PYTHONQTSTDDECORATORS_H
2 #define _PYTHONQTSTDDECORATORS_H
2 #define _PYTHONQTSTDDECORATORS_H
3
3
4 /*
4 /*
5 *
5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
7 *
7 *
8 * This library is free software; you can redistribute it and/or
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
11 * version 2.1 of the License, or (at your option) any later version.
12 *
12 *
13 * This library is distributed in the hope that it will be useful,
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
16 * Lesser General Public License for more details.
17 *
17 *
18 * Further, this software is distributed without any warranty that it is
18 * Further, this software is distributed without any warranty that it is
19 * free of the rightful claim of any third person regarding infringement
19 * free of the rightful claim of any third person regarding infringement
20 * or the like. Any license provided herein, whether implied or
20 * or the like. Any license provided herein, whether implied or
21 * otherwise, applies only to this software file. Patent licenses, if
21 * otherwise, applies only to this software file. Patent licenses, if
22 * any, provided herein do not apply to combinations of this program with
22 * any, provided herein do not apply to combinations of this program with
23 * other software, or any other product whatsoever.
23 * other software, or any other product whatsoever.
24 *
24 *
25 * You should have received a copy of the GNU Lesser General Public
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
30 * 28359 Bremen, Germany or:
30 * 28359 Bremen, Germany or:
31 *
31 *
32 * http://www.mevis.de
32 * http://www.mevis.de
33 *
33 *
34 */
34 */
35
35
36 //----------------------------------------------------------------------------------
36 //----------------------------------------------------------------------------------
37 /*!
37 /*!
38 // \file PythonQtStdDecorators.h
38 // \file PythonQtStdDecorators.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 2007-04
41 // \date 2007-04
42 */
42 */
43 //----------------------------------------------------------------------------------
43 //----------------------------------------------------------------------------------
44
44
45 #include "PythonQtSystem.h"
45 #include "PythonQtSystem.h"
46 #include <Python.h>
46 #include <Python.h>
47 #include <QObject>
47 #include <QObject>
48 #include <QVariantList>
48 #include <QVariantList>
49 #include <QTextDocument>
49 #include <QTextDocument>
50 #include <QColor>
50 #include <QColor>
51 #include <QDateTime>
51 #include <QDateTime>
52 #include <QDate>
52 #include <QDate>
53 #include <QTime>
53 #include <QTime>
54
54
55 class PYTHONQT_EXPORT PythonQtStdDecorators : public QObject
55 class PYTHONQT_EXPORT PythonQtStdDecorators : public QObject
56 {
56 {
57 Q_OBJECT
57 Q_OBJECT
58
58
59 public slots:
59 public slots:
60 bool connect(QObject* sender, const QByteArray& signal, PyObject* callable);
60 bool connect(QObject* sender, const QByteArray& signal, PyObject* callable);
61 bool connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot);
61 bool connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot);
62 bool disconnect(QObject* sender, const QByteArray& signal, PyObject* callable);
62 bool disconnect(QObject* sender, const QByteArray& signal, PyObject* callable);
63 bool disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot);
63 bool disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot);
64
64
65 #undef emit
65 #undef emit
66 void emit(QObject* sender, const QByteArray& signal, PyObject* arg1 = NULL,PyObject* arg2 = NULL,
66 void emit(QObject* sender, const QByteArray& signal, PyObject* arg1 = NULL,PyObject* arg2 = NULL,
67 PyObject* arg3 = NULL,PyObject* arg4 = NULL,PyObject* arg5 = NULL,PyObject* arg6 = NULL,PyObject* arg7 = NULL);
67 PyObject* arg3 = NULL,PyObject* arg4 = NULL,PyObject* arg5 = NULL,PyObject* arg6 = NULL,PyObject* arg7 = NULL);
68 #define emit
68 #define emit
69
69
70 QObject* parent(QObject* o);
70 QObject* parent(QObject* o);
71 void setParent(QObject* o, QObject* parent);
71 void setParent(QObject* o, QObject* parent);
72
72
73 QVariantList children(QObject* o);
73 QVariantList children(QObject* o);
74
74
75 double static_Qt_qAbs(double a) { return qAbs(a); }
76 double static_Qt_qBound(double a,double b,double c) { return qBound(a,b,c); }
77 void static_Qt_qDebug(const QByteArray& msg) { qDebug(msg.constData()); }
78 // TODO: multi arg qDebug...
79 void static_Qt_qWarning(const QByteArray& msg) { qWarning(msg.constData()); }
80 // TODO: multi arg qWarning...
81 void static_Qt_qCritical(const QByteArray& msg) { qCritical(msg.constData()); }
82 // TODO: multi arg qCritical...
83 void static_Qt_qFatal(const QByteArray& msg) { qFatal(msg.constData()); }
84 // TODO: multi arg qFatal...
85 bool static_Qt_qFuzzyCompare(double a, double b) { return qFuzzyCompare(a, b); }
86 double static_Qt_qMax(double a, double b) { return qMax(a, b); }
87 double static_Qt_qMin(double a, double b) { return qMin(a, b); }
88 int static_Qt_qRound(double a) { return qRound(a); }
89 qint64 static_Qt_qRound64(double a) { return qRound64(a); }
90 const char* static_Qt_qVersion() { return qVersion(); }
91 int static_Qt_qrand() { return qrand(); }
92 void static_Qt_qsrand(uint a) { qsrand(a); }
93
94 QByteArray static_Qt_SIGNAL(const QByteArray& s) { return QByteArray("2") + s; }
95 QByteArray static_Qt_SLOT(const QByteArray& s) { return QByteArray("1") + s; }
96
75 //TODO: add findChild/findChildren/children/...
97 //TODO: add findChild/findChildren/children/...
76 };
98 };
77
99
78
100
79 #endif
101 #endif
General Comments 0
You need to be logged in to leave comments. Login now