##// END OF EJS Templates
changed to support dicts for variable lookup and eval...
florianlink -
r25:60e7b3114ac6
parent child
Show More
@@ -1,1115 +1,1164
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 }
143 }
144
144
145 void PythonQt::cleanup()
145 void PythonQt::cleanup()
146 {
146 {
147 if (_self) {
147 if (_self) {
148 delete _self;
148 delete _self;
149 _self = NULL;
149 _self = NULL;
150 }
150 }
151 }
151 }
152
152
153 PythonQt::PythonQt(int flags)
153 PythonQt::PythonQt(int flags)
154 {
154 {
155 _p = new PythonQtPrivate;
155 _p = new PythonQtPrivate;
156 _p->_initFlags = flags;
156 _p->_initFlags = flags;
157
157
158 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
158 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
159
159
160 Py_SetProgramName("PythonQt");
160 Py_SetProgramName("PythonQt");
161 if (flags & IgnoreSiteModule) {
161 if (flags & IgnoreSiteModule) {
162 // this prevents the automatic importing of Python site files
162 // this prevents the automatic importing of Python site files
163 Py_NoSiteFlag = 1;
163 Py_NoSiteFlag = 1;
164 }
164 }
165 Py_Initialize();
165 Py_Initialize();
166
166
167 // add our own python object types for qt object slots
167 // add our own python object types for qt object slots
168 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
168 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
169 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
169 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
170 }
170 }
171 Py_INCREF(&PythonQtSlotFunction_Type);
171 Py_INCREF(&PythonQtSlotFunction_Type);
172
172
173 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
173 // 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;
174 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
175 // add our own python object types for classes
175 // add our own python object types for classes
176 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
176 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
177 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
177 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
178 }
178 }
179 Py_INCREF(&PythonQtClassWrapper_Type);
179 Py_INCREF(&PythonQtClassWrapper_Type);
180
180
181 // add our own python object types for CPP instances
181 // add our own python object types for CPP instances
182 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
182 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
183 PythonQt::handleError();
183 PythonQt::handleError();
184 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
184 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
185 }
185 }
186 Py_INCREF(&PythonQtInstanceWrapper_Type);
186 Py_INCREF(&PythonQtInstanceWrapper_Type);
187
187
188 // add our own python object types for redirection of stdout
188 // add our own python object types for redirection of stdout
189 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
189 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
190 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
190 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
191 }
191 }
192 Py_INCREF(&PythonQtStdOutRedirectType);
192 Py_INCREF(&PythonQtStdOutRedirectType);
193
193
194 initPythonQtModule(flags & RedirectStdOut);
194 initPythonQtModule(flags & RedirectStdOut);
195
195
196 }
196 }
197
197
198 PythonQt::~PythonQt() {
198 PythonQt::~PythonQt() {
199 delete _p;
199 delete _p;
200 _p = NULL;
200 _p = NULL;
201 }
201 }
202
202
203 PythonQtPrivate::~PythonQtPrivate() {
203 PythonQtPrivate::~PythonQtPrivate() {
204 delete _defaultImporter;
204 delete _defaultImporter;
205 _defaultImporter = NULL;
205 _defaultImporter = NULL;
206
206
207 {
207 {
208 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
208 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
209 while (i.hasNext()) {
209 while (i.hasNext()) {
210 delete i.next().value();
210 delete i.next().value();
211 }
211 }
212 }
212 }
213 PythonQtConv::global_valueStorage.clear();
213 PythonQtConv::global_valueStorage.clear();
214 PythonQtConv::global_ptrStorage.clear();
214 PythonQtConv::global_ptrStorage.clear();
215 PythonQtConv::global_variantStorage.clear();
215 PythonQtConv::global_variantStorage.clear();
216
216
217 PythonQtMethodInfo::cleanupCachedMethodInfos();
217 PythonQtMethodInfo::cleanupCachedMethodInfos();
218 }
218 }
219
219
220 PythonQtImportFileInterface* PythonQt::importInterface()
220 PythonQtImportFileInterface* PythonQt::importInterface()
221 {
221 {
222 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
222 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
223 }
223 }
224
224
225 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
225 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
226 {
226 {
227 if (_self->_p->_noLongerWrappedCB) {
227 if (_self->_p->_noLongerWrappedCB) {
228 (*_self->_p->_noLongerWrappedCB)(o);
228 (*_self->_p->_noLongerWrappedCB)(o);
229 };
229 };
230 }
230 }
231
231
232 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
232 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
233 {
233 {
234 _p->registerClass(metaobject, package, wrapperCreator, shell);
234 _p->registerClass(metaobject, package, wrapperCreator, shell);
235 }
235 }
236
236
237 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
237 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
238 {
238 {
239 // we register all classes in the hierarchy
239 // we register all classes in the hierarchy
240 const QMetaObject* m = metaobject;
240 const QMetaObject* m = metaobject;
241 bool first = true;
241 bool first = true;
242 while (m) {
242 while (m) {
243 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
243 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
244 if (!info->pythonQtClassWrapper()) {
244 if (!info->pythonQtClassWrapper()) {
245 info->setupQObject(m);
245 info->setupQObject(m);
246 createPythonQtClassWrapper(info, package);
246 createPythonQtClassWrapper(info, package);
247 if (m->superClass()) {
247 if (m->superClass()) {
248 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
248 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
249 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
249 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
250 }
250 }
251 }
251 }
252 if (first) {
252 if (first) {
253 first = false;
253 first = false;
254 if (wrapperCreator) {
254 if (wrapperCreator) {
255 info->setDecoratorProvider(wrapperCreator);
255 info->setDecoratorProvider(wrapperCreator);
256 }
256 }
257 if (shell) {
257 if (shell) {
258 info->setShellSetInstanceWrapperCB(shell);
258 info->setShellSetInstanceWrapperCB(shell);
259 }
259 }
260 }
260 }
261 m = m->superClass();
261 m = m->superClass();
262 }
262 }
263 }
263 }
264
264
265 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package)
265 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package)
266 {
266 {
267 PyObject* pack = packageByName(package);
267 PyObject* pack = packageByName(package);
268 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, package);
268 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, package);
269 PyModule_AddObject(pack, info->className(), pyobj);
269 PyModule_AddObject(pack, info->className(), pyobj);
270 if (package && strncmp(package,"Qt",2)==0) {
270 if (package && strncmp(package,"Qt",2)==0) {
271 // since PyModule_AddObject steals the reference, we need a incref once more...
271 // since PyModule_AddObject steals the reference, we need a incref once more...
272 Py_INCREF(pyobj);
272 Py_INCREF(pyobj);
273 // put all qt objects into Qt as well
273 // put all qt objects into Qt as well
274 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
274 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
275 }
275 }
276 info->setPythonQtClassWrapper(pyobj);
276 info->setPythonQtClassWrapper(pyobj);
277 }
277 }
278
278
279 bool PythonQtPrivate::isEnumType(const QMetaObject* meta, const QByteArray& name) {
279 bool PythonQtPrivate::isEnumType(const QMetaObject* meta, const QByteArray& name) {
280 int i = meta?meta->indexOfEnumerator(name.constData()):-1;
280 int i = meta?meta->indexOfEnumerator(name.constData()):-1;
281 if (i!=-1) {
281 if (i!=-1) {
282 return true;
282 return true;
283 } else {
283 } else {
284 // look for scope
284 // look for scope
285 int scopePos = name.indexOf("::");
285 int scopePos = name.indexOf("::");
286 if (scopePos != -1) {
286 if (scopePos != -1) {
287 // slit into scope and enum name
287 // slit into scope and enum name
288 QByteArray enumScope = name.mid(0,scopePos);
288 QByteArray enumScope = name.mid(0,scopePos);
289 QByteArray enumName = name.mid(scopePos+2);
289 QByteArray enumName = name.mid(scopePos+2);
290 if (enumScope == "Qt") {
290 if (enumScope == "Qt") {
291 // special qt namespace case
291 // special qt namespace case
292 return isEnumType(&staticQtMetaObject, enumName);
292 return isEnumType(&staticQtMetaObject, enumName);
293 } else {
293 } else {
294 // look for known classes as scope
294 // look for known classes as scope
295 // TODO: Q_GADGETS are not yet handled
295 // TODO: Q_GADGETS are not yet handled
296 PythonQtClassInfo* info = _knownClassInfos.value(enumScope);
296 PythonQtClassInfo* info = _knownClassInfos.value(enumScope);
297 if (info) {
297 if (info) {
298 return isEnumType(info->metaObject(), enumName);
298 return isEnumType(info->metaObject(), enumName);
299 }
299 }
300 }
300 }
301 }
301 }
302 }
302 }
303 return false;
303 return false;
304 }
304 }
305
305
306 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
306 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
307 {
307 {
308 if (!obj) {
308 if (!obj) {
309 Py_INCREF(Py_None);
309 Py_INCREF(Py_None);
310 return Py_None;
310 return Py_None;
311 }
311 }
312 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
312 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
313 if (!wrap) {
313 if (!wrap) {
314 // smuggling it in...
314 // smuggling it in...
315 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
315 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
316 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
316 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
317 registerClass(obj->metaObject());
317 registerClass(obj->metaObject());
318 classInfo = _knownClassInfos.value(obj->metaObject()->className());
318 classInfo = _knownClassInfos.value(obj->metaObject()->className());
319 }
319 }
320 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
320 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
321 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
321 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
322 } else {
322 } else {
323 Py_INCREF(wrap);
323 Py_INCREF(wrap);
324 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
324 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
325 }
325 }
326 return (PyObject*)wrap;
326 return (PyObject*)wrap;
327 }
327 }
328
328
329 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
329 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
330 {
330 {
331 if (!ptr) {
331 if (!ptr) {
332 Py_INCREF(Py_None);
332 Py_INCREF(Py_None);
333 return Py_None;
333 return Py_None;
334 }
334 }
335
335
336 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
336 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
337 if (!wrap) {
337 if (!wrap) {
338 PythonQtClassInfo* info = _knownClassInfos.value(name);
338 PythonQtClassInfo* info = _knownClassInfos.value(name);
339 if (!info) {
339 if (!info) {
340 // maybe it is a PyObject, which we can return directly
340 // maybe it is a PyObject, which we can return directly
341 if (name == "PyObject") {
341 if (name == "PyObject") {
342 PyObject* p = (PyObject*)ptr;
342 PyObject* p = (PyObject*)ptr;
343 Py_INCREF(p);
343 Py_INCREF(p);
344 return p;
344 return p;
345 }
345 }
346
346
347 // we do not know the metaobject yet, but we might know it by it's name:
347 // we do not know the metaobject yet, but we might know it by it's name:
348 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
348 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
349 // yes, we know it, so we can convert to QObject
349 // yes, we know it, so we can convert to QObject
350 QObject* qptr = (QObject*)ptr;
350 QObject* qptr = (QObject*)ptr;
351 registerClass(qptr->metaObject());
351 registerClass(qptr->metaObject());
352 info = _knownClassInfos.value(qptr->metaObject()->className());
352 info = _knownClassInfos.value(qptr->metaObject()->className());
353 }
353 }
354 }
354 }
355 if (info && info->isQObject()) {
355 if (info && info->isQObject()) {
356 QObject* qptr = (QObject*)ptr;
356 QObject* qptr = (QObject*)ptr;
357 // if the object is a derived object, we want to switch the class info to the one of the derived class:
357 // if the object is a derived object, we want to switch the class info to the one of the derived class:
358 if (name!=(qptr->metaObject()->className())) {
358 if (name!=(qptr->metaObject()->className())) {
359 registerClass(qptr->metaObject());
359 registerClass(qptr->metaObject());
360 info = _knownClassInfos.value(qptr->metaObject()->className());
360 info = _knownClassInfos.value(qptr->metaObject()->className());
361 }
361 }
362 wrap = createNewPythonQtInstanceWrapper(qptr, info);
362 wrap = createNewPythonQtInstanceWrapper(qptr, info);
363 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
363 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
364 return (PyObject*)wrap;
364 return (PyObject*)wrap;
365 }
365 }
366
366
367 // not a known QObject, so try our wrapper factory:
367 // not a known QObject, so try our wrapper factory:
368 QObject* wrapper = NULL;
368 QObject* wrapper = NULL;
369 for (int i=0; i<_cppWrapperFactories.size(); i++) {
369 for (int i=0; i<_cppWrapperFactories.size(); i++) {
370 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
370 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
371 if (wrapper) {
371 if (wrapper) {
372 break;
372 break;
373 }
373 }
374 }
374 }
375 if (!info || info->pythonQtClassWrapper()==NULL) {
375 if (!info || info->pythonQtClassWrapper()==NULL) {
376 // still unknown, register as CPP class
376 // still unknown, register as CPP class
377 registerCPPClass(name.constData());
377 registerCPPClass(name.constData());
378 info = _knownClassInfos.value(name);
378 info = _knownClassInfos.value(name);
379 }
379 }
380 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
380 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
381 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
381 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
382 info->setMetaObject(wrapper->metaObject());
382 info->setMetaObject(wrapper->metaObject());
383 }
383 }
384 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
384 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
385 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
385 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
386 } else {
386 } else {
387 Py_INCREF(wrap);
387 Py_INCREF(wrap);
388 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
388 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
389 }
389 }
390 return (PyObject*)wrap;
390 return (PyObject*)wrap;
391 }
391 }
392
392
393 PyObject* PythonQtPrivate::dummyTuple() {
393 PyObject* PythonQtPrivate::dummyTuple() {
394 static PyObject* dummyTuple = NULL;
394 static PyObject* dummyTuple = NULL;
395 if (dummyTuple==NULL) {
395 if (dummyTuple==NULL) {
396 dummyTuple = PyTuple_New(1);
396 dummyTuple = PyTuple_New(1);
397 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
397 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
398 }
398 }
399 return dummyTuple;
399 return dummyTuple;
400 }
400 }
401
401
402
402
403 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
403 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
404 // call the associated class type to create a new instance...
404 // call the associated class type to create a new instance...
405 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
405 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
406
406
407 result->setQObject(obj);
407 result->setQObject(obj);
408 result->_wrappedPtr = wrappedPtr;
408 result->_wrappedPtr = wrappedPtr;
409 result->_ownedByPythonQt = false;
409 result->_ownedByPythonQt = false;
410 result->_useQMetaTypeDestroy = false;
410 result->_useQMetaTypeDestroy = false;
411
411
412 if (wrappedPtr) {
412 if (wrappedPtr) {
413 _wrappedObjects.insert(wrappedPtr, result);
413 _wrappedObjects.insert(wrappedPtr, result);
414 } else {
414 } else {
415 _wrappedObjects.insert(obj, result);
415 _wrappedObjects.insert(obj, result);
416 if (obj->parent()== NULL && _wrappedCB) {
416 if (obj->parent()== NULL && _wrappedCB) {
417 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
417 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
418 (*_wrappedCB)(obj);
418 (*_wrappedCB)(obj);
419 }
419 }
420 }
420 }
421 return result;
421 return result;
422 }
422 }
423
423
424 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package) {
424 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package) {
425 PythonQtClassWrapper* result;
425 PythonQtClassWrapper* result;
426
426
427 PyObject* className = PyString_FromString(info->className());
427 PyObject* className = PyString_FromString(info->className());
428
428
429 PyObject* baseClasses = PyTuple_New(1);
429 PyObject* baseClasses = PyTuple_New(1);
430 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
430 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
431
431
432 PyObject* typeDict = PyDict_New();
432 PyObject* typeDict = PyDict_New();
433 QByteArray moduleName("PythonQt");
433 QByteArray moduleName("PythonQt");
434 if (package && strcmp(package, "")!=0) {
434 if (package && strcmp(package, "")!=0) {
435 moduleName += ".";
435 moduleName += ".";
436 moduleName += package;
436 moduleName += package;
437 }
437 }
438 PyDict_SetItemString(typeDict, "__module__", PyString_FromString(moduleName.constData()));
438 PyDict_SetItemString(typeDict, "__module__", PyString_FromString(moduleName.constData()));
439
439
440 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
440 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
441
441
442 // set the class info so that PythonQtClassWrapper_new can read it
442 // set the class info so that PythonQtClassWrapper_new can read it
443 _currentClassInfoForClassWrapperCreation = info;
443 _currentClassInfoForClassWrapperCreation = info;
444 // create the new type object by calling the type
444 // create the new type object by calling the type
445 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
445 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
446
446
447 Py_DECREF(baseClasses);
447 Py_DECREF(baseClasses);
448 Py_DECREF(typeDict);
448 Py_DECREF(typeDict);
449 Py_DECREF(args);
449 Py_DECREF(args);
450 Py_DECREF(className);
450 Py_DECREF(className);
451
451
452 return result;
452 return result;
453 }
453 }
454
454
455
455
456 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
456 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
457 {
457 {
458 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
458 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
459 if (!r) {
459 if (!r) {
460 r = new PythonQtSignalReceiver(obj);
460 r = new PythonQtSignalReceiver(obj);
461 _p->_signalReceivers.insert(obj, r);
461 _p->_signalReceivers.insert(obj, r);
462 }
462 }
463 return r;
463 return r;
464 }
464 }
465
465
466 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
466 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
467 {
467 {
468 bool flag = false;
468 bool flag = false;
469 PythonQtObjectPtr callable = lookupCallable(module, objectname);
469 PythonQtObjectPtr callable = lookupCallable(module, objectname);
470 if (callable) {
470 if (callable) {
471 PythonQtSignalReceiver* r = getSignalReceiver(obj);
471 PythonQtSignalReceiver* r = getSignalReceiver(obj);
472 flag = r->addSignalHandler(signal, callable);
472 flag = r->addSignalHandler(signal, callable);
473 if (!flag) {
473 if (!flag) {
474 // signal not found
474 // signal not found
475 }
475 }
476 } else {
476 } else {
477 // callable not found
477 // callable not found
478 }
478 }
479 return flag;
479 return flag;
480 }
480 }
481
481
482 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
482 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
483 {
483 {
484 bool flag = false;
484 bool flag = false;
485 PythonQtSignalReceiver* r = getSignalReceiver(obj);
485 PythonQtSignalReceiver* r = getSignalReceiver(obj);
486 if (r) {
486 if (r) {
487 flag = r->addSignalHandler(signal, receiver);
487 flag = r->addSignalHandler(signal, receiver);
488 }
488 }
489 return flag;
489 return flag;
490 }
490 }
491
491
492 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
492 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
493 {
493 {
494 bool flag = false;
494 bool flag = false;
495 PythonQtObjectPtr callable = lookupCallable(module, objectname);
495 PythonQtObjectPtr callable = lookupCallable(module, objectname);
496 if (callable) {
496 if (callable) {
497 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
497 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
498 if (r) {
498 if (r) {
499 flag = r->removeSignalHandler(signal, callable);
499 flag = r->removeSignalHandler(signal, callable);
500 }
500 }
501 } else {
501 } else {
502 // callable not found
502 // callable not found
503 }
503 }
504 return flag;
504 return flag;
505 }
505 }
506
506
507 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
507 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
508 {
508 {
509 bool flag = false;
509 bool flag = false;
510 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
510 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
511 if (r) {
511 if (r) {
512 flag = r->removeSignalHandler(signal, receiver);
512 flag = r->removeSignalHandler(signal, receiver);
513 }
513 }
514 return flag;
514 return flag;
515 }
515 }
516
516
517 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
517 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
518 {
518 {
519 PythonQtObjectPtr p = lookupObject(module, name);
519 PythonQtObjectPtr p = lookupObject(module, name);
520 if (p) {
520 if (p) {
521 if (PyCallable_Check(p)) {
521 if (PyCallable_Check(p)) {
522 return p;
522 return p;
523 }
523 }
524 }
524 }
525 PyErr_Clear();
525 PyErr_Clear();
526 return NULL;
526 return NULL;
527 }
527 }
528
528
529 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
529 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
530 {
530 {
531 QStringList l = name.split('.');
531 QStringList l = name.split('.');
532 PythonQtObjectPtr p = module;
532 PythonQtObjectPtr p = module;
533 PythonQtObjectPtr prev;
533 PythonQtObjectPtr prev;
534 QString s;
534 QString s;
535 QByteArray b;
535 QByteArray b;
536 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
536 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
537 prev = p;
537 prev = p;
538 b = (*i).toLatin1();
538 b = (*i).toLatin1();
539 if (PyDict_Check(p)) {
540 p = PyDict_GetItemString(p, b.data());
541 } else {
539 p.setNewRef(PyObject_GetAttrString(p, b.data()));
542 p.setNewRef(PyObject_GetAttrString(p, b.data()));
540 }
543 }
544 }
541 PyErr_Clear();
545 PyErr_Clear();
542 return p;
546 return p;
543 }
547 }
544
548
545 PythonQtObjectPtr PythonQt::getMainModule() {
549 PythonQtObjectPtr PythonQt::getMainModule() {
546 //both borrowed
550 //both borrowed
547 PythonQtObjectPtr dict = PyImport_GetModuleDict();
551 PythonQtObjectPtr dict = PyImport_GetModuleDict();
548 return PyDict_GetItemString(dict, "__main__");
552 return PyDict_GetItemString(dict, "__main__");
549 }
553 }
550
554
551 QVariant PythonQt::evalCode(PyObject* module, PyObject* pycode) {
555 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
552 QVariant result;
556 QVariant result;
553 if (pycode) {
557 if (pycode) {
554 PyObject* r = PyEval_EvalCode((PyCodeObject*)pycode, PyModule_GetDict((PyObject*)module) , PyModule_GetDict((PyObject*)module));
558 PyObject* dict = NULL;
559 if (PyModule_Check(object)) {
560 dict = PyModule_GetDict(object);
561 } else if (PyDict_Check(object)) {
562 dict = object;
563 }
564 PyObject* r = NULL;
565 if (dict) {
566 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
567 }
555 if (r) {
568 if (r) {
556 result = PythonQtConv::PyObjToQVariant(r);
569 result = PythonQtConv::PyObjToQVariant(r);
557 Py_DECREF(r);
570 Py_DECREF(r);
558 } else {
571 } else {
559 handleError();
572 handleError();
560 }
573 }
561 } else {
574 } else {
562 handleError();
575 handleError();
563 }
576 }
564 return result;
577 return result;
565 }
578 }
566
579
567 QVariant PythonQt::evalScript(PyObject* module, const QString& script, int start)
580 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
568 {
581 {
569 QVariant result;
582 QVariant result;
570 PythonQtObjectPtr p;
583 PythonQtObjectPtr p;
571 p.setNewRef(PyRun_String(script.toLatin1().data(), start, PyModule_GetDict(module), PyModule_GetDict(module)));
584 PyObject* dict = NULL;
585 if (PyModule_Check(object)) {
586 dict = PyModule_GetDict(object);
587 } else if (PyDict_Check(object)) {
588 dict = object;
589 }
590 if (dict) {
591 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
592 }
572 if (p) {
593 if (p) {
573 result = PythonQtConv::PyObjToQVariant(p);
594 result = PythonQtConv::PyObjToQVariant(p);
574 } else {
595 } else {
575 handleError();
596 handleError();
576 }
597 }
577 return result;
598 return result;
578 }
599 }
579
600
580 void PythonQt::evalFile(PyObject* module, const QString& filename)
601 void PythonQt::evalFile(PyObject* module, const QString& filename)
581 {
602 {
582 PythonQtObjectPtr code = parseFile(filename);
603 PythonQtObjectPtr code = parseFile(filename);
583 if (code) {
604 if (code) {
584 evalCode(module, code);
605 evalCode(module, code);
585 } else {
606 } else {
586 handleError();
607 handleError();
587 }
608 }
588 }
609 }
589
610
590 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
611 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
591 {
612 {
592 PythonQtObjectPtr p;
613 PythonQtObjectPtr p;
593 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
614 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
594 if (!p) {
615 if (!p) {
595 handleError();
616 handleError();
596 }
617 }
597 return p;
618 return p;
598 }
619 }
599
620
600 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
621 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
601 {
622 {
602 PythonQtObjectPtr code = parseFile(filename);
623 PythonQtObjectPtr code = parseFile(filename);
603 PythonQtObjectPtr module = _p->createModule(name, code);
624 PythonQtObjectPtr module = _p->createModule(name, code);
604 return module;
625 return module;
605 }
626 }
606
627
607 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
628 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
608 {
629 {
609 PyErr_Clear();
630 PyErr_Clear();
610 QString scriptCode = script;
631 QString scriptCode = script;
611 if (scriptCode.isEmpty()) {
632 if (scriptCode.isEmpty()) {
612 // we always need at least a linefeed
633 // we always need at least a linefeed
613 scriptCode = "\n";
634 scriptCode = "\n";
614 }
635 }
615 PythonQtObjectPtr pycode;
636 PythonQtObjectPtr pycode;
616 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
637 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
617 PythonQtObjectPtr module = _p->createModule(name, pycode);
638 PythonQtObjectPtr module = _p->createModule(name, pycode);
618 return module;
639 return module;
619 }
640 }
620
641
621 PythonQtObjectPtr PythonQt::createUniqueModule()
642 PythonQtObjectPtr PythonQt::createUniqueModule()
622 {
643 {
623 static QString pyQtStr("PythonQt_module");
644 static QString pyQtStr("PythonQt_module");
624 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
645 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
625 return createModuleFromScript(moduleName);
646 return createModuleFromScript(moduleName);
626 }
647 }
627
648
628 void PythonQt::addObject(PyObject* module, const QString& name, QObject* object)
649 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
629 {
650 {
630 PyModule_AddObject(module, name.toLatin1().data(), _p->wrapQObject(object));
651 if (PyModule_Check(object)) {
652 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
653 } else if (PyDict_Check(object)) {
654 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
655 } else {
656 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
657 }
631 }
658 }
632
659
633 void PythonQt::addVariable(PyObject* module, const QString& name, const QVariant& v)
660 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
634 {
661 {
635 PyModule_AddObject(module, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
662 if (PyModule_Check(object)) {
663 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
664 } else if (PyDict_Check(object)) {
665 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
666 } else {
667 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
668 }
636 }
669 }
637
670
638 void PythonQt::removeVariable(PyObject* module, const QString& name)
671 void PythonQt::removeVariable(PyObject* object, const QString& name)
639 {
672 {
640 PyObject_DelAttrString(module, name.toLatin1().data());
673 if (PyDict_Check(object)) {
674 PyDict_DelItemString(object, name.toLatin1().data());
675 } else {
676 PyObject_DelAttrString(object, name.toLatin1().data());
677 }
641 }
678 }
642
679
643 QVariant PythonQt::getVariable(PyObject* module, const QString& objectname)
680 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
644 {
681 {
645 QVariant result;
682 QVariant result;
646 PythonQtObjectPtr obj = lookupObject(module, objectname);
683 PythonQtObjectPtr obj = lookupObject(object, objectname);
647 if (obj) {
684 if (obj) {
648 result = PythonQtConv::PyObjToQVariant(obj);
685 result = PythonQtConv::PyObjToQVariant(obj);
649 }
686 }
650 return result;
687 return result;
651 }
688 }
652
689
653 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
690 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
654 {
691 {
655 QStringList results;
692 QStringList results;
656
693
657 PythonQtObjectPtr object;
694 PythonQtObjectPtr object;
658 if (objectname.isEmpty()) {
695 if (objectname.isEmpty()) {
659 object = module;
696 object = module;
660 } else {
697 } else {
661 object = lookupObject(module, objectname);
698 object = lookupObject(module, objectname);
662 if (!object && type == CallOverloads) {
699 if (!object && type == CallOverloads) {
663 PyObject* dict = lookupObject(module, "__builtins__");
700 PyObject* dict = lookupObject(module, "__builtins__");
664 if (dict) {
701 if (dict) {
665 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
702 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
666 }
703 }
667 }
704 }
668 }
705 }
669
706
670 if (object) {
707 if (object) {
671 if (type == CallOverloads) {
708 if (type == CallOverloads) {
672 if (PythonQtSlotFunction_Check(object)) {
709 if (PythonQtSlotFunction_Check(object)) {
673 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
710 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
674 PythonQtSlotInfo* info = o->m_ml;
711 PythonQtSlotInfo* info = o->m_ml;
675
712
676 while (info) {
713 while (info) {
677 results << info->fullSignature();
714 results << info->fullSignature();
678 info = info->nextInfo();
715 info = info->nextInfo();
679 }
716 }
680 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
717 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
681 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
718 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
682 PythonQtSlotInfo* info = o->classInfo()->constructors();
719 PythonQtSlotInfo* info = o->classInfo()->constructors();
683
720
684 while (info) {
721 while (info) {
685 results << info->fullSignature();
722 results << info->fullSignature();
686 info = info->nextInfo();
723 info = info->nextInfo();
687 }
724 }
688 } else {
725 } else {
689 //TODO: use pydoc!
726 //TODO: use pydoc!
690 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
727 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
691 if (doc) {
728 if (doc) {
692 results << PyString_AsString(doc);
729 results << PyString_AsString(doc);
693 Py_DECREF(doc);
730 Py_DECREF(doc);
694 }
731 }
695 }
732 }
696 } else {
733 } else {
697 PyObject* keys = PyObject_Dir(object);
734 PyObject* keys = NULL;
735 bool isDict = false;
736 if (PyDict_Check(object)) {
737 keys = PyDict_Keys(object);
738 isDict = true;
739 } else {
740 keys = PyObject_Dir(object);
741 }
698 if (keys) {
742 if (keys) {
699 int count = PyList_Size(keys);
743 int count = PyList_Size(keys);
700 PyObject* key;
744 PyObject* key;
701 PyObject* value;
745 PyObject* value;
702 QString keystr;
746 QString keystr;
703 for (int i = 0;i<count;i++) {
747 for (int i = 0;i<count;i++) {
704 key = PyList_GetItem(keys,i);
748 key = PyList_GetItem(keys,i);
749 if (isDict) {
750 value = PyDict_GetItem(object, key);
751 Py_INCREF(value);
752 } else {
705 value = PyObject_GetAttr(object, key);
753 value = PyObject_GetAttr(object, key);
754 }
706 if (!value) continue;
755 if (!value) continue;
707 keystr = PyString_AsString(key);
756 keystr = PyString_AsString(key);
708 static const QString underscoreStr("__tmp");
757 static const QString underscoreStr("__tmp");
709 if (!keystr.startsWith(underscoreStr)) {
758 if (!keystr.startsWith(underscoreStr)) {
710 switch (type) {
759 switch (type) {
711 case Anything:
760 case Anything:
712 results << keystr;
761 results << keystr;
713 break;
762 break;
714 case Class:
763 case Class:
715 if (value->ob_type == &PyClass_Type) {
764 if (value->ob_type == &PyClass_Type) {
716 results << keystr;
765 results << keystr;
717 }
766 }
718 break;
767 break;
719 case Variable:
768 case Variable:
720 if (value->ob_type != &PyClass_Type
769 if (value->ob_type != &PyClass_Type
721 && value->ob_type != &PyCFunction_Type
770 && value->ob_type != &PyCFunction_Type
722 && value->ob_type != &PyFunction_Type
771 && value->ob_type != &PyFunction_Type
723 && value->ob_type != &PyModule_Type
772 && value->ob_type != &PyModule_Type
724 ) {
773 ) {
725 results << keystr;
774 results << keystr;
726 }
775 }
727 break;
776 break;
728 case Function:
777 case Function:
729 if (value->ob_type == &PyFunction_Type ||
778 if (value->ob_type == &PyFunction_Type ||
730 value->ob_type == &PyMethod_Type
779 value->ob_type == &PyMethod_Type
731 ) {
780 ) {
732 results << keystr;
781 results << keystr;
733 }
782 }
734 break;
783 break;
735 case Module:
784 case Module:
736 if (value->ob_type == &PyModule_Type) {
785 if (value->ob_type == &PyModule_Type) {
737 results << keystr;
786 results << keystr;
738 }
787 }
739 break;
788 break;
740 default:
789 default:
741 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
790 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
742 }
791 }
743 }
792 }
744 Py_DECREF(value);
793 Py_DECREF(value);
745 }
794 }
746 Py_DECREF(keys);
795 Py_DECREF(keys);
747 }
796 }
748 }
797 }
749 }
798 }
750 return results;
799 return results;
751 }
800 }
752
801
753 QVariant PythonQt::call(PyObject* module, const QString& name, const QVariantList& args)
802 QVariant PythonQt::call(PyObject* module, const QString& name, const QVariantList& args)
754 {
803 {
755 QVariant r;
804 QVariant r;
756
805
757 PythonQtObjectPtr callable = lookupCallable(module, name);
806 PythonQtObjectPtr callable = lookupCallable(module, name);
758 if (callable) {
807 if (callable) {
759 PythonQtObjectPtr pargs;
808 PythonQtObjectPtr pargs;
760 int count = args.size();
809 int count = args.size();
761 if (count>0) {
810 if (count>0) {
762 pargs.setNewRef(PyTuple_New(count));
811 pargs.setNewRef(PyTuple_New(count));
763 }
812 }
764 bool err = false;
813 bool err = false;
765 // transform QVariants to Python
814 // transform QVariants to Python
766 for (int i = 0; i < count; i++) {
815 for (int i = 0; i < count; i++) {
767 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
816 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
768 if (arg) {
817 if (arg) {
769 // steals reference, no unref
818 // steals reference, no unref
770 PyTuple_SetItem(pargs, i,arg);
819 PyTuple_SetItem(pargs, i,arg);
771 } else {
820 } else {
772 err = true;
821 err = true;
773 break;
822 break;
774 }
823 }
775 }
824 }
776
825
777 if (!err) {
826 if (!err) {
778 PyErr_Clear();
827 PyErr_Clear();
779 PythonQtObjectPtr result;
828 PythonQtObjectPtr result;
780 result.setNewRef(PyObject_CallObject(callable, pargs));
829 result.setNewRef(PyObject_CallObject(callable, pargs));
781 if (result) {
830 if (result) {
782 // ok
831 // ok
783 r = PythonQtConv::PyObjToQVariant(result);
832 r = PythonQtConv::PyObjToQVariant(result);
784 } else {
833 } else {
785 PythonQt::self()->handleError();
834 PythonQt::self()->handleError();
786 }
835 }
787 }
836 }
788 }
837 }
789 return r;
838 return r;
790 }
839 }
791
840
792 void PythonQt::addInstanceDecorators(QObject* o)
841 void PythonQt::addInstanceDecorators(QObject* o)
793 {
842 {
794 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
843 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
795 }
844 }
796
845
797 void PythonQt::addClassDecorators(QObject* o)
846 void PythonQt::addClassDecorators(QObject* o)
798 {
847 {
799 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
848 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
800 }
849 }
801
850
802 void PythonQt::addDecorators(QObject* o)
851 void PythonQt::addDecorators(QObject* o)
803 {
852 {
804 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
853 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
805 }
854 }
806
855
807 void PythonQt::registerQObjectClassNames(const QStringList& names)
856 void PythonQt::registerQObjectClassNames(const QStringList& names)
808 {
857 {
809 _p->registerQObjectClassNames(names);
858 _p->registerQObjectClassNames(names);
810 }
859 }
811
860
812 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
861 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
813 {
862 {
814 PythonQtImport::init();
863 PythonQtImport::init();
815 _p->_importInterface = importInterface;
864 _p->_importInterface = importInterface;
816 }
865 }
817
866
818 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
867 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
819 {
868 {
820 _p->_importIgnorePaths = paths;
869 _p->_importIgnorePaths = paths;
821 }
870 }
822
871
823 const QStringList& PythonQt::getImporterIgnorePaths()
872 const QStringList& PythonQt::getImporterIgnorePaths()
824 {
873 {
825 return _p->_importIgnorePaths;
874 return _p->_importIgnorePaths;
826 }
875 }
827
876
828 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
877 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
829 {
878 {
830 _p->_cppWrapperFactories.append(factory);
879 _p->_cppWrapperFactories.append(factory);
831 }
880 }
832
881
833 //---------------------------------------------------------------------------------------------------
882 //---------------------------------------------------------------------------------------------------
834 PythonQtPrivate::PythonQtPrivate()
883 PythonQtPrivate::PythonQtPrivate()
835 {
884 {
836 _importInterface = NULL;
885 _importInterface = NULL;
837 _defaultImporter = new PythonQtQFileImporter;
886 _defaultImporter = new PythonQtQFileImporter;
838 _noLongerWrappedCB = NULL;
887 _noLongerWrappedCB = NULL;
839 _wrappedCB = NULL;
888 _wrappedCB = NULL;
840 _currentClassInfoForClassWrapperCreation = NULL;
889 _currentClassInfoForClassWrapperCreation = NULL;
841 }
890 }
842
891
843 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
892 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
844 {
893 {
845 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
894 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
846 _currentClassInfoForClassWrapperCreation = NULL;
895 _currentClassInfoForClassWrapperCreation = NULL;
847 return info;
896 return info;
848 }
897 }
849
898
850 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
899 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
851 {
900 {
852 o->setParent(this);
901 o->setParent(this);
853 int numMethods = o->metaObject()->methodCount();
902 int numMethods = o->metaObject()->methodCount();
854 for (int i = 0; i < numMethods; i++) {
903 for (int i = 0; i < numMethods; i++) {
855 QMetaMethod m = o->metaObject()->method(i);
904 QMetaMethod m = o->metaObject()->method(i);
856 if ((m.methodType() == QMetaMethod::Method ||
905 if ((m.methodType() == QMetaMethod::Method ||
857 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
906 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
858 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m);
907 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m);
859 if (qstrncmp(m.signature(), "new_", 4)==0) {
908 if (qstrncmp(m.signature(), "new_", 4)==0) {
860 if ((decoTypes & ConstructorDecorator) == 0) continue;
909 if ((decoTypes & ConstructorDecorator) == 0) continue;
861 // either it returns a * or a QVariant and the name starts with "new_"
910 // either it returns a * or a QVariant and the name starts with "new_"
862 bool isVariantReturn = info->parameters().at(0).typeId == PythonQtMethodInfo::Variant;
911 bool isVariantReturn = info->parameters().at(0).typeId == PythonQtMethodInfo::Variant;
863 if ((info->parameters().at(0).isPointer || isVariantReturn)) {
912 if ((info->parameters().at(0).isPointer || isVariantReturn)) {
864 QByteArray signature = m.signature();
913 QByteArray signature = m.signature();
865 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
914 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
866 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
915 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
867 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
916 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
868 classInfo->addConstructor(newSlot);
917 classInfo->addConstructor(newSlot);
869 }
918 }
870 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
919 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
871 if ((decoTypes & DestructorDecorator) == 0) continue;
920 if ((decoTypes & DestructorDecorator) == 0) continue;
872 QByteArray signature = m.signature();
921 QByteArray signature = m.signature();
873 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
922 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
874 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
923 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
875 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
924 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
876 classInfo->setDestructor(newSlot);
925 classInfo->setDestructor(newSlot);
877 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
926 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
878 if ((decoTypes & StaticDecorator) == 0) continue;
927 if ((decoTypes & StaticDecorator) == 0) continue;
879 QByteArray signature = m.signature();
928 QByteArray signature = m.signature();
880 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
929 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
881 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
930 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
882 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
931 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
883 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
932 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
884 classInfo->addDecoratorSlot(newSlot);
933 classInfo->addDecoratorSlot(newSlot);
885 } else {
934 } else {
886 if ((decoTypes & InstanceDecorator) == 0) continue;
935 if ((decoTypes & InstanceDecorator) == 0) continue;
887 if (info->parameters().count()>1) {
936 if (info->parameters().count()>1) {
888 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
937 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
889 if (p.isPointer) {
938 if (p.isPointer) {
890 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
939 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
891 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::InstanceDecorator);
940 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::InstanceDecorator);
892 classInfo->addDecoratorSlot(newSlot);
941 classInfo->addDecoratorSlot(newSlot);
893 }
942 }
894 }
943 }
895 }
944 }
896 }
945 }
897 }
946 }
898 }
947 }
899
948
900 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
949 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
901 {
950 {
902 foreach(QString name, names) {
951 foreach(QString name, names) {
903 _knownQObjectClassNames.insert(name.toLatin1(), true);
952 _knownQObjectClassNames.insert(name.toLatin1(), true);
904 }
953 }
905 }
954 }
906
955
907 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
956 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
908 {
957 {
909 _signalReceivers.remove(obj);
958 _signalReceivers.remove(obj);
910 }
959 }
911
960
912 bool PythonQt::handleError()
961 bool PythonQt::handleError()
913 {
962 {
914 bool flag = false;
963 bool flag = false;
915 if (PyErr_Occurred()) {
964 if (PyErr_Occurred()) {
916
965
917 // currently we just print the error and the stderr handler parses the errors
966 // currently we just print the error and the stderr handler parses the errors
918 PyErr_Print();
967 PyErr_Print();
919
968
920 /*
969 /*
921 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
970 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
922 PyObject *ptype;
971 PyObject *ptype;
923 PyObject *pvalue;
972 PyObject *pvalue;
924 PyObject *ptraceback;
973 PyObject *ptraceback;
925 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
974 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
926
975
927 Py_XDECREF(ptype);
976 Py_XDECREF(ptype);
928 Py_XDECREF(pvalue);
977 Py_XDECREF(pvalue);
929 Py_XDECREF(ptraceback);
978 Py_XDECREF(ptraceback);
930 */
979 */
931 PyErr_Clear();
980 PyErr_Clear();
932 flag = true;
981 flag = true;
933 }
982 }
934 return flag;
983 return flag;
935 }
984 }
936
985
937 void PythonQt::addSysPath(const QString& path)
986 void PythonQt::addSysPath(const QString& path)
938 {
987 {
939 PythonQtObjectPtr sys;
988 PythonQtObjectPtr sys;
940 sys.setNewRef(PyImport_ImportModule("sys"));
989 sys.setNewRef(PyImport_ImportModule("sys"));
941 PythonQtObjectPtr obj = lookupObject(sys, "path");
990 PythonQtObjectPtr obj = lookupObject(sys, "path");
942 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
991 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
943 }
992 }
944
993
945 void PythonQt::overwriteSysPath(const QStringList& paths)
994 void PythonQt::overwriteSysPath(const QStringList& paths)
946 {
995 {
947 PythonQtObjectPtr sys;
996 PythonQtObjectPtr sys;
948 sys.setNewRef(PyImport_ImportModule("sys"));
997 sys.setNewRef(PyImport_ImportModule("sys"));
949 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
998 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
950 }
999 }
951
1000
952 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1001 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
953 {
1002 {
954 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1003 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
955 }
1004 }
956
1005
957 void PythonQt::stdOutRedirectCB(const QString& str)
1006 void PythonQt::stdOutRedirectCB(const QString& str)
958 {
1007 {
959 emit PythonQt::self()->pythonStdOut(str);
1008 emit PythonQt::self()->pythonStdOut(str);
960 }
1009 }
961
1010
962 void PythonQt::stdErrRedirectCB(const QString& str)
1011 void PythonQt::stdErrRedirectCB(const QString& str)
963 {
1012 {
964 emit PythonQt::self()->pythonStdErr(str);
1013 emit PythonQt::self()->pythonStdErr(str);
965 }
1014 }
966
1015
967 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1016 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
968 {
1017 {
969 _p->_wrappedCB = cb;
1018 _p->_wrappedCB = cb;
970 }
1019 }
971
1020
972 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1021 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
973 {
1022 {
974 _p->_noLongerWrappedCB = cb;
1023 _p->_noLongerWrappedCB = cb;
975 }
1024 }
976
1025
977
1026
978
1027
979 static PyMethodDef PythonQtMethods[] = {
1028 static PyMethodDef PythonQtMethods[] = {
980 {NULL, NULL, 0, NULL}
1029 {NULL, NULL, 0, NULL}
981 };
1030 };
982
1031
983 void PythonQt::initPythonQtModule(bool redirectStdOut)
1032 void PythonQt::initPythonQtModule(bool redirectStdOut)
984 {
1033 {
985 _p->_pythonQtModule = Py_InitModule("PythonQt", PythonQtMethods);
1034 _p->_pythonQtModule = Py_InitModule("PythonQt", PythonQtMethods);
986
1035
987 if (redirectStdOut) {
1036 if (redirectStdOut) {
988 PythonQtObjectPtr sys;
1037 PythonQtObjectPtr sys;
989 PythonQtObjectPtr out;
1038 PythonQtObjectPtr out;
990 PythonQtObjectPtr err;
1039 PythonQtObjectPtr err;
991 sys.setNewRef(PyImport_ImportModule("sys"));
1040 sys.setNewRef(PyImport_ImportModule("sys"));
992 // create a redirection object for stdout and stderr
1041 // create a redirection object for stdout and stderr
993 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1042 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
994 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1043 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
995 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1044 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
996 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1045 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
997 // replace the built in file objects with our own objects
1046 // replace the built in file objects with our own objects
998 PyModule_AddObject(sys, "stdout", out);
1047 PyModule_AddObject(sys, "stdout", out);
999 PyModule_AddObject(sys, "stderr", err);
1048 PyModule_AddObject(sys, "stderr", err);
1000 }
1049 }
1001 }
1050 }
1002
1051
1003 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1052 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1004 {
1053 {
1005 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1054 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1006 }
1055 }
1007
1056
1008
1057
1009 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1058 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1010 {
1059 {
1011 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1060 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1012 if (!info) {
1061 if (!info) {
1013 info = new PythonQtClassInfo();
1062 info = new PythonQtClassInfo();
1014 info->setupCPPObject(typeName);
1063 info->setupCPPObject(typeName);
1015 _knownClassInfos.insert(typeName, info);
1064 _knownClassInfos.insert(typeName, info);
1016 }
1065 }
1017 return info;
1066 return info;
1018 }
1067 }
1019
1068
1020 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1069 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1021 {
1070 {
1022 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1071 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1023 }
1072 }
1024
1073
1025 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1074 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1026 {
1075 {
1027 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1076 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1028 if (info) {
1077 if (info) {
1029 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1078 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1030 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1079 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1031 return true;
1080 return true;
1032 } else {
1081 } else {
1033 return false;
1082 return false;
1034 }
1083 }
1035 }
1084 }
1036
1085
1037 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1086 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1038 {
1087 {
1039 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1088 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1040 if (!info->pythonQtClassWrapper()) {
1089 if (!info->pythonQtClassWrapper()) {
1041 info->setupCPPObject(typeName);
1090 info->setupCPPObject(typeName);
1042 createPythonQtClassWrapper(info, package);
1091 createPythonQtClassWrapper(info, package);
1043 }
1092 }
1044 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1093 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1045 addParentClass(typeName, parentTypeName, 0);
1094 addParentClass(typeName, parentTypeName, 0);
1046 }
1095 }
1047 if (wrapperCreator) {
1096 if (wrapperCreator) {
1048 info->setDecoratorProvider(wrapperCreator);
1097 info->setDecoratorProvider(wrapperCreator);
1049 }
1098 }
1050 if (shell) {
1099 if (shell) {
1051 info->setShellSetInstanceWrapperCB(shell);
1100 info->setShellSetInstanceWrapperCB(shell);
1052 }
1101 }
1053 }
1102 }
1054
1103
1055 PyObject* PythonQtPrivate::packageByName(const char* name)
1104 PyObject* PythonQtPrivate::packageByName(const char* name)
1056 {
1105 {
1057 if (name==NULL || name[0]==0) {
1106 if (name==NULL || name[0]==0) {
1058 return _pythonQtModule;
1107 return _pythonQtModule;
1059 }
1108 }
1060 PyObject* v = _packages.value(name);
1109 PyObject* v = _packages.value(name);
1061 if (!v) {
1110 if (!v) {
1062 v = PyImport_AddModule((QByteArray("PythonQt.") + name).constData());
1111 v = PyImport_AddModule((QByteArray("PythonQt.") + name).constData());
1063 _packages.insert(name, v);
1112 _packages.insert(name, v);
1064 // AddObject steals the reference, so increment it!
1113 // AddObject steals the reference, so increment it!
1065 Py_INCREF(v);
1114 Py_INCREF(v);
1066 PyModule_AddObject(_pythonQtModule, name, v);
1115 PyModule_AddObject(_pythonQtModule, name, v);
1067 }
1116 }
1068 return v;
1117 return v;
1069 }
1118 }
1070
1119
1071
1120
1072 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1121 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1073 {
1122 {
1074 if (_p->_initFlags & ExternalHelp) {
1123 if (_p->_initFlags & ExternalHelp) {
1075 emit pythonHelpRequest(QByteArray(info->className()));
1124 emit pythonHelpRequest(QByteArray(info->className()));
1076 return Py_BuildValue("");
1125 return Py_BuildValue("");
1077 } else {
1126 } else {
1078 return PyString_FromString(info->help().toLatin1().data());
1127 return PyString_FromString(info->help().toLatin1().data());
1079 }
1128 }
1080 }
1129 }
1081
1130
1082 void PythonQtPrivate::removeWrapperPointer(void* obj)
1131 void PythonQtPrivate::removeWrapperPointer(void* obj)
1083 {
1132 {
1084 _wrappedObjects.remove(obj);
1133 _wrappedObjects.remove(obj);
1085 }
1134 }
1086
1135
1087 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1136 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1088 {
1137 {
1089 _wrappedObjects.insert(obj, wrapper);
1138 _wrappedObjects.insert(obj, wrapper);
1090 }
1139 }
1091
1140
1092 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1141 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1093 {
1142 {
1094 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1143 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1095 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1144 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1096 // this is a wrapper whose QObject was already removed due to destruction
1145 // this is a wrapper whose QObject was already removed due to destruction
1097 // so the obj pointer has to be a new QObject with the same address...
1146 // so the obj pointer has to be a new QObject with the same address...
1098 // we remove the old one and set the copy to NULL
1147 // we remove the old one and set the copy to NULL
1099 wrap->_objPointerCopy = NULL;
1148 wrap->_objPointerCopy = NULL;
1100 removeWrapperPointer(obj);
1149 removeWrapperPointer(obj);
1101 wrap = NULL;
1150 wrap = NULL;
1102 }
1151 }
1103 return wrap;
1152 return wrap;
1104 }
1153 }
1105
1154
1106 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1155 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1107 {
1156 {
1108 PythonQtObjectPtr result;
1157 PythonQtObjectPtr result;
1109 if (pycode) {
1158 if (pycode) {
1110 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1159 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1111 } else {
1160 } else {
1112 PythonQt::self()->handleError();
1161 PythonQt::self()->handleError();
1113 }
1162 }
1114 return result;
1163 return result;
1115 }
1164 }
@@ -1,511 +1,511
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
70
71 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
71 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
72
72
73 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) { ((T*)object)->_wrapper = wrapper; };
73 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) { ((T*)object)->_wrapper = wrapper; };
74
74
75 //! returns the offset that needs to be added to upcast an object of type T1 to T2
75 //! returns the offset that needs to be added to upcast an object of type T1 to T2
76 template<class T1, class T2> int PythonQtUpcastingOffset() {
76 template<class T1, class T2> int PythonQtUpcastingOffset() {
77 return (((char*)(static_cast<T2*>(reinterpret_cast<T1*>(0x100)))) - ((char*)reinterpret_cast<T1*>(0x100)));
77 return (((char*)(static_cast<T2*>(reinterpret_cast<T1*>(0x100)))) - ((char*)reinterpret_cast<T1*>(0x100)));
78 }
78 }
79
79
80 //! callback to create a QObject lazily
80 //! callback to create a QObject lazily
81 typedef QObject* PythonQtQObjectCreatorFunctionCB();
81 typedef QObject* PythonQtQObjectCreatorFunctionCB();
82
82
83 //! helper template to create a derived QObject class
83 //! helper template to create a derived QObject class
84 template<class T> QObject* PythonQtCreateObject() { return new T(); };
84 template<class T> QObject* PythonQtCreateObject() { return new T(); };
85
85
86 //! the main interface to the Python Qt binding, realized as a singleton
86 //! the main interface to the Python Qt binding, realized as a singleton
87 class PYTHONQT_EXPORT PythonQt : public QObject {
87 class PYTHONQT_EXPORT PythonQt : public QObject {
88
88
89 Q_OBJECT
89 Q_OBJECT
90
90
91 public:
91 public:
92 enum InitFlags {
92 enum InitFlags {
93 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
93 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
94 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
94 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
95 ExternalHelp = 4 //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
95 ExternalHelp = 4 //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
96 };
96 };
97
97
98 //! initialize the python qt binding (flags are a or combination of InitFlags)
98 //! initialize the python qt binding (flags are a or combination of InitFlags)
99 static void init(int flags = IgnoreSiteModule | RedirectStdOut);
99 static void init(int flags = IgnoreSiteModule | RedirectStdOut);
100
100
101 //! cleanup
101 //! cleanup
102 static void cleanup();
102 static void cleanup();
103
103
104 //! get the singleton instance
104 //! get the singleton instance
105 static PythonQt* self() { return _self; }
105 static PythonQt* self() { return _self; }
106
106
107 //-----------------------------------------------------------------------------
107 //-----------------------------------------------------------------------------
108 // Public API:
108 // Public API:
109
109
110 //! defines the object types for introspection
110 //! defines the object types for introspection
111 enum ObjectType {
111 enum ObjectType {
112 Class,
112 Class,
113 Function,
113 Function,
114 Variable,
114 Variable,
115 Module,
115 Module,
116 Anything,
116 Anything,
117 CallOverloads
117 CallOverloads
118 };
118 };
119
119
120 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
120 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
121 void overwriteSysPath(const QStringList& paths);
121 void overwriteSysPath(const QStringList& paths);
122
122
123 //! prepend a path to sys.path to allow importing from it
123 //! prepend a path to sys.path to allow importing from it
124 void addSysPath(const QString& path);
124 void addSysPath(const QString& path);
125
125
126 //! sets the __path__ list of a module to the given list (important for local imports)
126 //! sets the __path__ list of a module to the given list (important for local imports)
127 void setModuleImportPath(PyObject* module, const QStringList& paths);
127 void setModuleImportPath(PyObject* module, const QStringList& paths);
128
128
129 //! get the __main__ module of python
129 //! get the __main__ module of python
130 PythonQtObjectPtr getMainModule();
130 PythonQtObjectPtr getMainModule();
131
131
132 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
132 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
133 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
133 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
134 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
134 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
135 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
135 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
136
136
137 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
137 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
138 //! (ownership of wrapper is passed to PythonQt)
138 //! (ownership of wrapper is passed to PythonQt)
139 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
139 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
140
140
141 This will add a wrapper object that is used to make calls to the given classname \c typeName.
141 This will add a wrapper object that is used to make calls to the given classname \c typeName.
142 All slots that take a pointer to typeName as the first argument will be callable from Python on
142 All slots that take a pointer to typeName as the first argument will be callable from Python on
143 a variant object that contains such a type.
143 a variant object that contains such a type.
144 */
144 */
145 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
145 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
146
146
147 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
147 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
148 //! and it will register the classes when it first sees a pointer to such a derived class
148 //! and it will register the classes when it first sees a pointer to such a derived class
149 void registerQObjectClassNames(const QStringList& names);
149 void registerQObjectClassNames(const QStringList& names);
150
150
151 //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance
151 //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance
152 //! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that
152 //! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that
153 //! type is really derived from parentType.
153 //! type is really derived from parentType.
154 //! Returns false if the typeName was not yet registered.
154 //! Returns false if the typeName was not yet registered.
155 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
155 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
156
156
157 //! parses the given file and returns the python code object, this can then be used to call evalCode()
157 //! parses the given file and returns the python code object, this can then be used to call evalCode()
158 PythonQtObjectPtr parseFile(const QString& filename);
158 PythonQtObjectPtr parseFile(const QString& filename);
159
159
160 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
160 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
161 //! If pycode is NULL, a python error is printed.
161 //! If pycode is NULL, a python error is printed.
162 QVariant evalCode(PyObject* module, PyObject* pycode);
162 QVariant evalCode(PyObject* object, PyObject* pycode);
163
163
164 //! evaluates the given script code and returns the result value
164 //! evaluates the given script code and returns the result value
165 QVariant evalScript(PyObject* module, const QString& script, int start = Py_file_input);
165 QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input);
166
166
167 //! evaluates the given script code from file
167 //! evaluates the given script code from file
168 void evalFile(PyObject* module, const QString& filename);
168 void evalFile(PyObject* object, const QString& filename);
169
169
170 //! creates the new module \c name and evaluates the given file in the context of that module
170 //! creates the new module \c name and evaluates the given file in the context of that module
171 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
171 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
172 //! to a module later on.
172 //! to a module later on.
173 //! The user needs to make sure that the \c name is unique in the python module dictionary.
173 //! The user needs to make sure that the \c name is unique in the python module dictionary.
174 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
174 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
175
175
176 //! creates the new module \c name and evaluates the given script in the context of that module.
176 //! creates the new module \c name and evaluates the given script in the context of that module.
177 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
177 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
178 //! to a module later on.
178 //! to a module later on.
179 //! The user needs to make sure that the \c name is unique in the python module dictionary.
179 //! The user needs to make sure that the \c name is unique in the python module dictionary.
180 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
180 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
181
181
182 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
182 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
183 //! script code
183 //! script code
184 PythonQtObjectPtr createUniqueModule();
184 PythonQtObjectPtr createUniqueModule();
185
185
186 //@{ Signal handlers
186 //@{ Signal handlers
187
187
188 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
188 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
189 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
189 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
190
190
191 //! remove a signal handler from the given \c signal of \c obj
191 //! remove a signal handler from the given \c signal of \c obj
192 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
192 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
193
193
194 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
194 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
195 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
195 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
196
196
197 //! remove a signal handler from the given \c signal of \c obj
197 //! remove a signal handler from the given \c signal of \c obj
198 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
198 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
199
199
200 //@}
200 //@}
201
201
202 //@{ Variable access
202 //@{ Variable access
203
203
204 //! add the given \c object to the \c module as a variable with \c name (it can be removed via clearVariable)
204 //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable)
205 void addObject(PyObject* module, const QString& name, QObject* object);
205 void addObject(PyObject* object, const QString& name, QObject* qObject);
206
206
207 //! add the given variable to the module
207 //! add the given variable to the object
208 void addVariable(PyObject* module, const QString& name, const QVariant& v);
208 void addVariable(PyObject* object, const QString& name, const QVariant& v);
209
209
210 //! remove the given variable
210 //! remove the given variable
211 void removeVariable(PyObject* module, const QString& name);
211 void removeVariable(PyObject* module, const QString& name);
212
212
213 //! get the variable with the \c name of the \c module, returns an invalid QVariant on error
213 //! get the variable with the \c name of the \c object, returns an invalid QVariant on error
214 QVariant getVariable(PyObject* module, const QString& name);
214 QVariant getVariable(PyObject* object, const QString& name);
215
215
216 //! read vars etc. in scope of a module, optional looking inside of an object \c objectname
216 //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname
217 QStringList introspection(PyObject* module, const QString& objectname, ObjectType type);
217 QStringList introspection(PyObject* object, const QString& objectname, ObjectType type);
218
218
219 //! returns the found callable object or NULL
219 //! returns the found callable object or NULL
220 //! @return new reference
220 //! @return new reference
221 PythonQtObjectPtr lookupCallable(PyObject* module, const QString& name);
221 PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
222
222
223 //@}
223 //@}
224
224
225 //@{ Calling of python callables
225 //@{ Calling of python callables
226
226
227 //! call the given python method, returns the result converted to a QVariant
227 //! call the given python method, returns the result converted to a QVariant
228 QVariant call(PyObject* module, const QString& callable, const QVariantList& args = QVariantList());
228 QVariant call(PyObject* module, const QString& callable, const QVariantList& args = QVariantList());
229
229
230 //@}
230 //@}
231
231
232 //@{ Decorations, constructors, wrappers...
232 //@{ Decorations, constructors, wrappers...
233
233
234
234
235 //! add an object whose slots will be used as decorator slots for
235 //! add an object whose slots will be used as decorator slots for
236 //! other QObjects or CPP classes. The slots need to follow the
236 //! other QObjects or CPP classes. The slots need to follow the
237 //! convention that the first argument is a pointer to the wrapped object.
237 //! convention that the first argument is a pointer to the wrapped object.
238 //! (ownership is passed to PythonQt)
238 //! (ownership is passed to PythonQt)
239 /*!
239 /*!
240 Example:
240 Example:
241
241
242 A slot with the signature
242 A slot with the signature
243
243
244 \code
244 \code
245 bool doSomething(QWidget* w, int a)
245 bool doSomething(QWidget* w, int a)
246 \endcode
246 \endcode
247
247
248 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
248 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
249 that will be called with the concrete instance as first argument.
249 that will be called with the concrete instance as first argument.
250 So in Python you can now e.g. call
250 So in Python you can now e.g. call
251
251
252 \code
252 \code
253 someWidget.doSomething(12)
253 someWidget.doSomething(12)
254 \endcode
254 \endcode
255
255
256 without QWidget really having this method. This allows to easily make normal methods
256 without QWidget really having this method. This allows to easily make normal methods
257 of Qt classes callable by forwarding them with such decorator slots
257 of Qt classes callable by forwarding them with such decorator slots
258 or to make CPP classes (which are not derived from QObject) callable from Python.
258 or to make CPP classes (which are not derived from QObject) callable from Python.
259 */
259 */
260 void addInstanceDecorators(QObject* o);
260 void addInstanceDecorators(QObject* o);
261
261
262 //! add an object whose slots will be used as decorator slots for
262 //! add an object whose slots will be used as decorator slots for
263 //! class objects (ownership is passed to PythonQt)
263 //! class objects (ownership is passed to PythonQt)
264 /*!
264 /*!
265 The slots need to follow the following convention:
265 The slots need to follow the following convention:
266 - SomeClass* new_SomeClass(...)
266 - SomeClass* new_SomeClass(...)
267 - QVariant new_SomeClass(...)
267 - QVariant new_SomeClass(...)
268 - void delete_SomeClass(SomeClass*)
268 - void delete_SomeClass(SomeClass*)
269 - ... static_SomeClass_someName(...)
269 - ... static_SomeClass_someName(...)
270
270
271 This will add:
271 This will add:
272 - a constructor
272 - a constructor
273 - a constructor which generates a QVariant
273 - a constructor which generates a QVariant
274 - a destructor (only useful for CPP objects)
274 - a destructor (only useful for CPP objects)
275 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
275 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
276
276
277 */
277 */
278 void addClassDecorators(QObject* o);
278 void addClassDecorators(QObject* o);
279
279
280 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
280 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
281 void addDecorators(QObject* o);
281 void addDecorators(QObject* o);
282
282
283 //! add the given factory to PythonQt (ownership stays with caller)
283 //! add the given factory to PythonQt (ownership stays with caller)
284 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
284 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
285
285
286 //@}
286 //@}
287
287
288 //@{ Custom importer (to replace internal import implementation of python)
288 //@{ Custom importer (to replace internal import implementation of python)
289
289
290 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
290 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
291 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
291 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
292 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
292 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
293 //! This is not reversible, so even setting setImporter(NULL) afterwards will
293 //! This is not reversible, so even setting setImporter(NULL) afterwards will
294 //! keep the custom PythonQt importer with a QFile default import interface.
294 //! keep the custom PythonQt importer with a QFile default import interface.
295 //! Subsequent python import calls will make use of the passed importInterface
295 //! Subsequent python import calls will make use of the passed importInterface
296 //! which forwards all import calls to the given \c importInterface.
296 //! which forwards all import calls to the given \c importInterface.
297 //! Passing NULL will install a default QFile importer.
297 //! Passing NULL will install a default QFile importer.
298 //! (\c importInterface ownership stays with caller)
298 //! (\c importInterface ownership stays with caller)
299 void setImporter(PythonQtImportFileInterface* importInterface);
299 void setImporter(PythonQtImportFileInterface* importInterface);
300
300
301 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
301 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
302 //! (without calling setImporter or installDefaultImporter at least once, the default python import
302 //! (without calling setImporter or installDefaultImporter at least once, the default python import
303 //! mechanism is in place)
303 //! mechanism is in place)
304 //! the default importer allows to import files from anywhere QFile can read from,
304 //! the default importer allows to import files from anywhere QFile can read from,
305 //! including the Qt resource system using ":". Keep in mind that you need to extend
305 //! including the Qt resource system using ":". Keep in mind that you need to extend
306 //! "sys.path" with ":" to be able to import from the Qt resources.
306 //! "sys.path" with ":" to be able to import from the Qt resources.
307 void installDefaultImporter() { setImporter(NULL); }
307 void installDefaultImporter() { setImporter(NULL); }
308
308
309 //! set paths that the importer should ignore
309 //! set paths that the importer should ignore
310 void setImporterIgnorePaths(const QStringList& paths);
310 void setImporterIgnorePaths(const QStringList& paths);
311
311
312 //! get paths that the importer should ignore
312 //! get paths that the importer should ignore
313 const QStringList& getImporterIgnorePaths();
313 const QStringList& getImporterIgnorePaths();
314
314
315 //@}
315 //@}
316
316
317 //! get access to internal data (should not be used on the public API, but is used by some C functions)
317 //! get access to internal data (should not be used on the public API, but is used by some C functions)
318 static PythonQtPrivate* priv() { return _self->_p; }
318 static PythonQtPrivate* priv() { return _self->_p; }
319
319
320 //! get access to the file importer (if set)
320 //! get access to the file importer (if set)
321 static PythonQtImportFileInterface* importInterface();
321 static PythonQtImportFileInterface* importInterface();
322
322
323 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
323 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
324 //! The error is currently just output to the python stderr, future version might implement better trace printing
324 //! The error is currently just output to the python stderr, future version might implement better trace printing
325 bool handleError();
325 bool handleError();
326
326
327 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
327 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
328 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
328 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
329 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
329 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
330 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
330 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
331
331
332 //! call the callback if it is set
332 //! call the callback if it is set
333 static void qObjectNoLongerWrappedCB(QObject* o);
333 static void qObjectNoLongerWrappedCB(QObject* o);
334
334
335 signals:
335 signals:
336 //! emitted when python outputs something to stdout (and redirection is turned on)
336 //! emitted when python outputs something to stdout (and redirection is turned on)
337 void pythonStdOut(const QString& str);
337 void pythonStdOut(const QString& str);
338 //! emitted when python outputs something to stderr (and redirection is turned on)
338 //! emitted when python outputs something to stderr (and redirection is turned on)
339 void pythonStdErr(const QString& str);
339 void pythonStdErr(const QString& str);
340
340
341 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
341 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
342 void pythonHelpRequest(const QByteArray& cppClassName);
342 void pythonHelpRequest(const QByteArray& cppClassName);
343
343
344
344
345 public:
345 public:
346 //! called by internal help methods
346 //! called by internal help methods
347 PyObject* helpCalled(PythonQtClassInfo* info);
347 PyObject* helpCalled(PythonQtClassInfo* info);
348
348
349 //! returns the found object or NULL
349 //! returns the found object or NULL
350 //! @return new reference
350 //! @return new reference
351 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
351 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
352
352
353 private:
353 private:
354 void initPythonQtModule(bool redirectStdOut);
354 void initPythonQtModule(bool redirectStdOut);
355
355
356 //! callback for stdout redirection, emits pythonStdOut signal
356 //! callback for stdout redirection, emits pythonStdOut signal
357 static void stdOutRedirectCB(const QString& str);
357 static void stdOutRedirectCB(const QString& str);
358 //! callback for stderr redirection, emits pythonStdErr signal
358 //! callback for stderr redirection, emits pythonStdErr signal
359 static void stdErrRedirectCB(const QString& str);
359 static void stdErrRedirectCB(const QString& str);
360
360
361 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
361 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
362 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
362 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
363
363
364 PythonQt(int flags);
364 PythonQt(int flags);
365 ~PythonQt();
365 ~PythonQt();
366
366
367 static PythonQt* _self;
367 static PythonQt* _self;
368 static int _uniqueModuleCount;
368 static int _uniqueModuleCount;
369
369
370 PythonQtPrivate* _p;
370 PythonQtPrivate* _p;
371
371
372 };
372 };
373
373
374 //! internal PythonQt details
374 //! internal PythonQt details
375 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
375 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
376
376
377 Q_OBJECT
377 Q_OBJECT
378
378
379 public:
379 public:
380 PythonQtPrivate();
380 PythonQtPrivate();
381 ~PythonQtPrivate();
381 ~PythonQtPrivate();
382
382
383 enum DecoratorTypes {
383 enum DecoratorTypes {
384 StaticDecorator = 1,
384 StaticDecorator = 1,
385 ConstructorDecorator = 2,
385 ConstructorDecorator = 2,
386 DestructorDecorator = 4,
386 DestructorDecorator = 4,
387 InstanceDecorator = 8,
387 InstanceDecorator = 8,
388 AllDecorators = 0xffff
388 AllDecorators = 0xffff
389 };
389 };
390
390
391 //! returns if the id is the id for PythonQtObjectPtr
391 //! returns if the id is the id for PythonQtObjectPtr
392 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
392 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
393
393
394 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
394 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
395 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
395 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
396 //! remove the wrapper ptr again
396 //! remove the wrapper ptr again
397 void removeWrapperPointer(void* obj);
397 void removeWrapperPointer(void* obj);
398
398
399 //! add parent class relation
399 //! add parent class relation
400 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
400 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
401
401
402 //! lookup existing classinfo and return new if not yet present
402 //! lookup existing classinfo and return new if not yet present
403 PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
403 PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
404
404
405 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
405 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
406 void removeSignalEmitter(QObject* obj);
406 void removeSignalEmitter(QObject* obj);
407
407
408 //! wrap the given QObject into a Python object (or return existing wrapper!)
408 //! wrap the given QObject into a Python object (or return existing wrapper!)
409 PyObject* wrapQObject(QObject* obj);
409 PyObject* wrapQObject(QObject* obj);
410
410
411 //! 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
411 //! 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
412 PyObject* wrapPtr(void* ptr, const QByteArray& name);
412 PyObject* wrapPtr(void* ptr, const QByteArray& name);
413
413
414 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
414 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
415 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
415 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
416 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
416 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
417 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
417 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
418
418
419 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
419 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
420 //! (ownership of wrapper is passed to PythonQt)
420 //! (ownership of wrapper is passed to PythonQt)
421 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
421 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
422
422
423 This will add a wrapper object that is used to make calls to the given classname \c typeName.
423 This will add a wrapper object that is used to make calls to the given classname \c typeName.
424 All slots that take a pointer to typeName as the first argument will be callable from Python on
424 All slots that take a pointer to typeName as the first argument will be callable from Python on
425 a variant object that contains such a type.
425 a variant object that contains such a type.
426 */
426 */
427 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
427 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
428
428
429 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
429 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
430 //! and it will register the classes when it first sees a pointer to such a derived class
430 //! and it will register the classes when it first sees a pointer to such a derived class
431 void registerQObjectClassNames(const QStringList& names);
431 void registerQObjectClassNames(const QStringList& names);
432
432
433 //! add a decorator object
433 //! add a decorator object
434 void addDecorators(QObject* o, int decoTypes);
434 void addDecorators(QObject* o, int decoTypes);
435
435
436 //! check if the enum is either part of the \c meta class or contains a scope and is
436 //! check if the enum is either part of the \c meta class or contains a scope and is
437 //! an enum of another known metaobject (and as last resort, of the Qt namespace)
437 //! an enum of another known metaobject (and as last resort, of the Qt namespace)
438 bool isEnumType(const QMetaObject* meta, const QByteArray& name);
438 bool isEnumType(const QMetaObject* meta, const QByteArray& name);
439
439
440 //! helper method that creates a PythonQtClassWrapper object
440 //! helper method that creates a PythonQtClassWrapper object
441 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package = NULL);
441 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package = NULL);
442
442
443 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
443 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
444 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
444 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
445
445
446 //! get the class info for a meta object (if available)
446 //! get the class info for a meta object (if available)
447 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
447 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
448
448
449 //! get the class info for a meta object (if available)
449 //! get the class info for a meta object (if available)
450 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
450 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
451
451
452 //! creates the new module from the given pycode
452 //! creates the new module from the given pycode
453 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
453 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
454
454
455 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
455 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
456 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
456 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
457
457
458 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
458 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
459 static PyObject* dummyTuple();
459 static PyObject* dummyTuple();
460
460
461 private:
461 private:
462
462
463 //! create a new pythonqt class wrapper and place it in the pythonqt module
463 //! create a new pythonqt class wrapper and place it in the pythonqt module
464 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package);
464 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package);
465
465
466 //! get/create new package module (the returned object is a borrowed reference)
466 //! get/create new package module (the returned object is a borrowed reference)
467 PyObject* packageByName(const char* name);
467 PyObject* packageByName(const char* name);
468
468
469 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
469 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
470 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
470 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
471
471
472 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
472 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
473 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
473 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
474
474
475 //! stores the meta info of known Qt classes
475 //! stores the meta info of known Qt classes
476 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
476 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
477
477
478 //! names of qobject derived classes that can be casted to qobject savely
478 //! names of qobject derived classes that can be casted to qobject savely
479 QHash<QByteArray, bool> _knownQObjectClassNames;
479 QHash<QByteArray, bool> _knownQObjectClassNames;
480
480
481 //! stores signal receivers for QObjects
481 //! stores signal receivers for QObjects
482 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
482 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
483
483
484 //! the PythonQt python module
484 //! the PythonQt python module
485 PythonQtObjectPtr _pythonQtModule;
485 PythonQtObjectPtr _pythonQtModule;
486
486
487 //! the importer interface (if set)
487 //! the importer interface (if set)
488 PythonQtImportFileInterface* _importInterface;
488 PythonQtImportFileInterface* _importInterface;
489
489
490 //! the default importer
490 //! the default importer
491 PythonQtQFileImporter* _defaultImporter;
491 PythonQtQFileImporter* _defaultImporter;
492
492
493 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
493 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
494 PythonQtQObjectWrappedCB* _wrappedCB;
494 PythonQtQObjectWrappedCB* _wrappedCB;
495
495
496 QStringList _importIgnorePaths;
496 QStringList _importIgnorePaths;
497
497
498 //! the cpp object wrapper factories
498 //! the cpp object wrapper factories
499 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
499 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
500
500
501 QHash<QByteArray, PyObject*> _packages;
501 QHash<QByteArray, PyObject*> _packages;
502
502
503 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
503 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
504
504
505 int _initFlags;
505 int _initFlags;
506 int _PythonQtObjectPtr_metaId;
506 int _PythonQtObjectPtr_metaId;
507
507
508 friend class PythonQt;
508 friend class PythonQt;
509 };
509 };
510
510
511 #endif
511 #endif
@@ -1,566 +1,575
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 PythonQtScriptingConsole.cpp
35 // \file PythonQtScriptingConsole.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-10
38 // \date 2006-10
39 */
39 */
40 //----------------------------------------------------------------------------------
40 //----------------------------------------------------------------------------------
41
41
42 #include "PythonQtScriptingConsole.h"
42 #include "PythonQtScriptingConsole.h"
43
43
44 #include <QMenu>
44 #include <QMenu>
45 #include <QMouseEvent>
45 #include <QMouseEvent>
46 #include <QKeyEvent>
46 #include <QKeyEvent>
47 #include <QApplication>
47 #include <QApplication>
48 #include <QTextDocumentFragment>
48 #include <QTextDocumentFragment>
49 #include <QTextBlock>
49 #include <QTextBlock>
50 #include <QTextCursor>
50 #include <QTextCursor>
51 #include <QDebug>
51 #include <QDebug>
52 #include <QCompleter>
52 #include <QCompleter>
53 #include <QStringListModel>
53 #include <QStringListModel>
54 #include <QScrollBar>
54 #include <QScrollBar>
55
55
56 //-----------------------------------------------------------------------------
56 //-----------------------------------------------------------------------------
57
57
58 PythonQtScriptingConsole::PythonQtScriptingConsole(QWidget* parent, const PythonQtObjectPtr& context, Qt::WindowFlags windowFlags)
58 PythonQtScriptingConsole::PythonQtScriptingConsole(QWidget* parent, const PythonQtObjectPtr& context, Qt::WindowFlags windowFlags)
59 : QTextEdit(parent) {
59 : QTextEdit(parent) {
60
60
61 setWindowFlags(windowFlags);
61 setWindowFlags(windowFlags);
62
62
63 _defaultTextCharacterFormat = currentCharFormat();
63 _defaultTextCharacterFormat = currentCharFormat();
64 _context = context;
64 _context = context;
65 _historyPosition = 0;
65 _historyPosition = 0;
66 _hadError = false;
66 _hadError = false;
67
67
68 _completer = new QCompleter(this);
68 _completer = new QCompleter(this);
69 _completer->setWidget(this);
69 _completer->setWidget(this);
70 QObject::connect(_completer, SIGNAL(activated(const QString&)),
70 QObject::connect(_completer, SIGNAL(activated(const QString&)),
71 this, SLOT(insertCompletion(const QString&)));
71 this, SLOT(insertCompletion(const QString&)));
72
72
73 clear();
73 clear();
74
74
75 connect(PythonQt::self(), SIGNAL(pythonStdOut(const QString&)), this, SLOT(stdOut(const QString&)));
75 connect(PythonQt::self(), SIGNAL(pythonStdOut(const QString&)), this, SLOT(stdOut(const QString&)));
76 connect(PythonQt::self(), SIGNAL(pythonStdErr(const QString&)), this, SLOT(stdErr(const QString&)));
76 connect(PythonQt::self(), SIGNAL(pythonStdErr(const QString&)), this, SLOT(stdErr(const QString&)));
77 }
77 }
78
78
79 //-----------------------------------------------------------------------------
79 //-----------------------------------------------------------------------------
80
80
81 void PythonQtScriptingConsole::stdOut(const QString& s)
81 void PythonQtScriptingConsole::stdOut(const QString& s)
82 {
82 {
83 _stdOut += s;
83 _stdOut += s;
84 int idx;
84 int idx;
85 while ((idx = _stdOut.indexOf('\n'))!=-1) {
85 while ((idx = _stdOut.indexOf('\n'))!=-1) {
86 consoleMessage(_stdOut.left(idx));
86 consoleMessage(_stdOut.left(idx));
87 std::cout << _stdOut.left(idx).toLatin1().data() << std::endl;
87 std::cout << _stdOut.left(idx).toLatin1().data() << std::endl;
88 _stdOut = _stdOut.mid(idx+1);
88 _stdOut = _stdOut.mid(idx+1);
89 }
89 }
90 }
90 }
91
91
92 void PythonQtScriptingConsole::stdErr(const QString& s)
92 void PythonQtScriptingConsole::stdErr(const QString& s)
93 {
93 {
94 _hadError = true;
94 _hadError = true;
95 _stdErr += s;
95 _stdErr += s;
96 int idx;
96 int idx;
97 while ((idx = _stdErr.indexOf('\n'))!=-1) {
97 while ((idx = _stdErr.indexOf('\n'))!=-1) {
98 consoleMessage(_stdErr.left(idx));
98 consoleMessage(_stdErr.left(idx));
99 std::cerr << _stdErr.left(idx).toLatin1().data() << std::endl;
99 std::cerr << _stdErr.left(idx).toLatin1().data() << std::endl;
100 _stdErr = _stdErr.mid(idx+1);
100 _stdErr = _stdErr.mid(idx+1);
101 }
101 }
102 }
102 }
103
103
104 void PythonQtScriptingConsole::flushStdOut()
104 void PythonQtScriptingConsole::flushStdOut()
105 {
105 {
106 if (!_stdOut.isEmpty()) {
106 if (!_stdOut.isEmpty()) {
107 stdOut("\n");
107 stdOut("\n");
108 }
108 }
109 if (!_stdErr.isEmpty()) {
109 if (!_stdErr.isEmpty()) {
110 stdErr("\n");
110 stdErr("\n");
111 }
111 }
112 }
112 }
113
113
114 //-----------------------------------------------------------------------------
114 //-----------------------------------------------------------------------------
115
115
116 PythonQtScriptingConsole::~PythonQtScriptingConsole() {
116 PythonQtScriptingConsole::~PythonQtScriptingConsole() {
117 }
117 }
118
118
119
119
120
120
121 //-----------------------------------------------------------------------------
121 //-----------------------------------------------------------------------------
122
122
123 void PythonQtScriptingConsole::clear() {
123 void PythonQtScriptingConsole::clear() {
124
124
125 QTextEdit::clear();
125 QTextEdit::clear();
126 appendCommandPrompt();
126 appendCommandPrompt();
127 }
127 }
128
128
129 //-----------------------------------------------------------------------------
129 //-----------------------------------------------------------------------------
130
130
131 void PythonQtScriptingConsole::executeLine(bool storeOnly)
131 void PythonQtScriptingConsole::executeLine(bool storeOnly)
132 {
132 {
133 QTextCursor textCursor = this->textCursor();
133 QTextCursor textCursor = this->textCursor();
134 textCursor.movePosition(QTextCursor::End);
134 textCursor.movePosition(QTextCursor::End);
135
135
136 // Select the text from the command prompt until the end of the block
136 // Select the text from the command prompt until the end of the block
137 // and get the selected text.
137 // and get the selected text.
138 textCursor.setPosition(commandPromptPosition());
138 textCursor.setPosition(commandPromptPosition());
139 textCursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
139 textCursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
140 QString code = textCursor.selectedText();
140 QString code = textCursor.selectedText();
141
141
142 // i don't know where this trailing space is coming from, blast it!
142 // i don't know where this trailing space is coming from, blast it!
143 if (code.endsWith(" ")) {
143 if (code.endsWith(" ")) {
144 code.truncate(code.length()-1);
144 code.truncate(code.length()-1);
145 }
145 }
146
146
147 if (!code.isEmpty()) {
147 if (!code.isEmpty()) {
148 // Update the history
148 // Update the history
149 _history << code;
149 _history << code;
150 _historyPosition = _history.count();
150 _historyPosition = _history.count();
151 _currentMultiLineCode += code + "\n";
151 _currentMultiLineCode += code + "\n";
152
152
153 if (!storeOnly) {
153 if (!storeOnly) {
154 executeCode(_currentMultiLineCode);
154 executeCode(_currentMultiLineCode);
155 _currentMultiLineCode = "";
155 _currentMultiLineCode = "";
156 }
156 }
157 }
157 }
158 // Insert a new command prompt
158 // Insert a new command prompt
159 appendCommandPrompt(storeOnly);
159 appendCommandPrompt(storeOnly);
160
160
161 }
161 }
162
162
163 void PythonQtScriptingConsole::executeCode(const QString& code)
163 void PythonQtScriptingConsole::executeCode(const QString& code)
164 {
164 {
165 // put visible cursor to the end of the line
165 // put visible cursor to the end of the line
166 QTextCursor cursor = QTextEdit::textCursor();
166 QTextCursor cursor = QTextEdit::textCursor();
167 cursor.movePosition(QTextCursor::End);
167 cursor.movePosition(QTextCursor::End);
168 setTextCursor(cursor);
168 setTextCursor(cursor);
169
169
170 int cursorPosition = this->textCursor().position();
170 int cursorPosition = this->textCursor().position();
171
171
172 // evaluate the code
172 // evaluate the code
173 _stdOut = "";
173 _stdOut = "";
174 _stdErr = "";
174 _stdErr = "";
175 PythonQtObjectPtr p;
175 PythonQtObjectPtr p;
176 p.setNewRef(PyRun_String(code.toLatin1().data(), Py_single_input, PyModule_GetDict(_context), PyModule_GetDict(_context)));
176 PyObject* dict = NULL;
177 if (PyModule_Check(_context)) {
178 dict = PyModule_GetDict(_context);
179 } else if (PyDict_Check(_context)) {
180 dict = _context;
181 }
182 if (dict) {
183 p.setNewRef(PyRun_String(code.toLatin1().data(), Py_single_input, dict, dict));
184 }
185
177 if (!p) {
186 if (!p) {
178 PythonQt::self()->handleError();
187 PythonQt::self()->handleError();
179 }
188 }
180
189
181 flushStdOut();
190 flushStdOut();
182
191
183 bool messageInserted = (this->textCursor().position() != cursorPosition);
192 bool messageInserted = (this->textCursor().position() != cursorPosition);
184
193
185 // If a message was inserted, then put another empty line before the command prompt
194 // If a message was inserted, then put another empty line before the command prompt
186 // to improve readability.
195 // to improve readability.
187 if (messageInserted) {
196 if (messageInserted) {
188 append(QString());
197 append(QString());
189 }
198 }
190 }
199 }
191
200
192
201
193 //-----------------------------------------------------------------------------
202 //-----------------------------------------------------------------------------
194
203
195 void PythonQtScriptingConsole::appendCommandPrompt(bool storeOnly) {
204 void PythonQtScriptingConsole::appendCommandPrompt(bool storeOnly) {
196 if (storeOnly) {
205 if (storeOnly) {
197 _commandPrompt = "...> ";
206 _commandPrompt = "...> ";
198 } else {
207 } else {
199 _commandPrompt = "py> ";
208 _commandPrompt = "py> ";
200 }
209 }
201 append(_commandPrompt);
210 append(_commandPrompt);
202
211
203 QTextCursor cursor = textCursor();
212 QTextCursor cursor = textCursor();
204 cursor.movePosition(QTextCursor::End);
213 cursor.movePosition(QTextCursor::End);
205 setTextCursor(cursor);
214 setTextCursor(cursor);
206 }
215 }
207
216
208
217
209
218
210 //-----------------------------------------------------------------------------
219 //-----------------------------------------------------------------------------
211
220
212 void PythonQtScriptingConsole::setCurrentFont(const QColor& color, bool bold) {
221 void PythonQtScriptingConsole::setCurrentFont(const QColor& color, bool bold) {
213
222
214 QTextCharFormat charFormat(_defaultTextCharacterFormat);
223 QTextCharFormat charFormat(_defaultTextCharacterFormat);
215
224
216 QFont font(charFormat.font());
225 QFont font(charFormat.font());
217 font.setBold(bold);
226 font.setBold(bold);
218 charFormat.setFont(font);
227 charFormat.setFont(font);
219
228
220 QBrush brush(charFormat.foreground());
229 QBrush brush(charFormat.foreground());
221 brush.setColor(color);
230 brush.setColor(color);
222 charFormat.setForeground(brush);
231 charFormat.setForeground(brush);
223
232
224 setCurrentCharFormat(charFormat);
233 setCurrentCharFormat(charFormat);
225 }
234 }
226
235
227
236
228
237
229 //-----------------------------------------------------------------------------
238 //-----------------------------------------------------------------------------
230
239
231 int PythonQtScriptingConsole::commandPromptPosition() {
240 int PythonQtScriptingConsole::commandPromptPosition() {
232
241
233 QTextCursor textCursor(this->textCursor());
242 QTextCursor textCursor(this->textCursor());
234 textCursor.movePosition(QTextCursor::End);
243 textCursor.movePosition(QTextCursor::End);
235
244
236 return textCursor.block().position() + _commandPrompt.length();
245 return textCursor.block().position() + _commandPrompt.length();
237 }
246 }
238
247
239
248
240
249
241 //-----------------------------------------------------------------------------
250 //-----------------------------------------------------------------------------
242
251
243 void PythonQtScriptingConsole::insertCompletion(const QString& completion)
252 void PythonQtScriptingConsole::insertCompletion(const QString& completion)
244 {
253 {
245 QTextCursor tc = textCursor();
254 QTextCursor tc = textCursor();
246 tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor);
255 tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor);
247 if (tc.selectedText()==".") {
256 if (tc.selectedText()==".") {
248 tc.insertText(QString(".") + completion);
257 tc.insertText(QString(".") + completion);
249 } else {
258 } else {
250 tc = textCursor();
259 tc = textCursor();
251 tc.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
260 tc.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
252 tc.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
261 tc.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
253 tc.insertText(completion);
262 tc.insertText(completion);
254 setTextCursor(tc);
263 setTextCursor(tc);
255 }
264 }
256 }
265 }
257
266
258 //-----------------------------------------------------------------------------
267 //-----------------------------------------------------------------------------
259 void PythonQtScriptingConsole::handleTabCompletion()
268 void PythonQtScriptingConsole::handleTabCompletion()
260 {
269 {
261 QTextCursor textCursor = this->textCursor();
270 QTextCursor textCursor = this->textCursor();
262 int pos = textCursor.position();
271 int pos = textCursor.position();
263 textCursor.setPosition(commandPromptPosition());
272 textCursor.setPosition(commandPromptPosition());
264 textCursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
273 textCursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
265 int startPos = textCursor.selectionStart();
274 int startPos = textCursor.selectionStart();
266
275
267 int offset = pos-startPos;
276 int offset = pos-startPos;
268 QString text = textCursor.selectedText();
277 QString text = textCursor.selectedText();
269
278
270 QString textToComplete;
279 QString textToComplete;
271 int cur = offset;
280 int cur = offset;
272 while (cur--) {
281 while (cur--) {
273 QChar c = text.at(cur);
282 QChar c = text.at(cur);
274 if (c.isLetterOrNumber() || c == '.' || c == '_') {
283 if (c.isLetterOrNumber() || c == '.' || c == '_') {
275 textToComplete.prepend(c);
284 textToComplete.prepend(c);
276 } else {
285 } else {
277 break;
286 break;
278 }
287 }
279 }
288 }
280
289
281
290
282 QString lookup;
291 QString lookup;
283 QString compareText = textToComplete;
292 QString compareText = textToComplete;
284 int dot = compareText.lastIndexOf('.');
293 int dot = compareText.lastIndexOf('.');
285 if (dot!=-1) {
294 if (dot!=-1) {
286 lookup = compareText.mid(0, dot);
295 lookup = compareText.mid(0, dot);
287 compareText = compareText.mid(dot+1, offset);
296 compareText = compareText.mid(dot+1, offset);
288 }
297 }
289 if (!lookup.isEmpty() || !compareText.isEmpty()) {
298 if (!lookup.isEmpty() || !compareText.isEmpty()) {
290 compareText = compareText.toLower();
299 compareText = compareText.toLower();
291 QStringList found;
300 QStringList found;
292 QStringList l = PythonQt::self()->introspection(_context, lookup, PythonQt::Anything);
301 QStringList l = PythonQt::self()->introspection(_context, lookup, PythonQt::Anything);
293 foreach (QString n, l) {
302 foreach (QString n, l) {
294 if (n.toLower().startsWith(compareText)) {
303 if (n.toLower().startsWith(compareText)) {
295 found << n;
304 found << n;
296 }
305 }
297 }
306 }
298
307
299 if (!found.isEmpty()) {
308 if (!found.isEmpty()) {
300 _completer->setCompletionPrefix(compareText);
309 _completer->setCompletionPrefix(compareText);
301 _completer->setCompletionMode(QCompleter::PopupCompletion);
310 _completer->setCompletionMode(QCompleter::PopupCompletion);
302 _completer->setModel(new QStringListModel(found, _completer));
311 _completer->setModel(new QStringListModel(found, _completer));
303 _completer->setCaseSensitivity(Qt::CaseInsensitive);
312 _completer->setCaseSensitivity(Qt::CaseInsensitive);
304 QTextCursor c = this->textCursor();
313 QTextCursor c = this->textCursor();
305 c.movePosition(QTextCursor::StartOfWord);
314 c.movePosition(QTextCursor::StartOfWord);
306 QRect cr = cursorRect(c);
315 QRect cr = cursorRect(c);
307 cr.setWidth(_completer->popup()->sizeHintForColumn(0)
316 cr.setWidth(_completer->popup()->sizeHintForColumn(0)
308 + _completer->popup()->verticalScrollBar()->sizeHint().width());
317 + _completer->popup()->verticalScrollBar()->sizeHint().width());
309 cr.translate(0,8);
318 cr.translate(0,8);
310 _completer->complete(cr);
319 _completer->complete(cr);
311 } else {
320 } else {
312 _completer->popup()->hide();
321 _completer->popup()->hide();
313 }
322 }
314 } else {
323 } else {
315 _completer->popup()->hide();
324 _completer->popup()->hide();
316 }
325 }
317 }
326 }
318
327
319 void PythonQtScriptingConsole::keyPressEvent(QKeyEvent* event) {
328 void PythonQtScriptingConsole::keyPressEvent(QKeyEvent* event) {
320
329
321 if (_completer && _completer->popup()->isVisible()) {
330 if (_completer && _completer->popup()->isVisible()) {
322 // The following keys are forwarded by the completer to the widget
331 // The following keys are forwarded by the completer to the widget
323 switch (event->key()) {
332 switch (event->key()) {
324 case Qt::Key_Return:
333 case Qt::Key_Return:
325 if (!_completer->popup()->currentIndex().isValid()) {
334 if (!_completer->popup()->currentIndex().isValid()) {
326 insertCompletion(_completer->currentCompletion());
335 insertCompletion(_completer->currentCompletion());
327 _completer->popup()->hide();
336 _completer->popup()->hide();
328 event->accept();
337 event->accept();
329 }
338 }
330 event->ignore();
339 event->ignore();
331 return;
340 return;
332 break;
341 break;
333 case Qt::Key_Enter:
342 case Qt::Key_Enter:
334 case Qt::Key_Escape:
343 case Qt::Key_Escape:
335 case Qt::Key_Tab:
344 case Qt::Key_Tab:
336 case Qt::Key_Backtab:
345 case Qt::Key_Backtab:
337
346
338 event->ignore();
347 event->ignore();
339 return; // let the completer do default behavior
348 return; // let the completer do default behavior
340 default:
349 default:
341 break;
350 break;
342 }
351 }
343 }
352 }
344 bool eventHandled = false;
353 bool eventHandled = false;
345 QTextCursor textCursor = this->textCursor();
354 QTextCursor textCursor = this->textCursor();
346
355
347 int key = event->key();
356 int key = event->key();
348 switch (key) {
357 switch (key) {
349
358
350 case Qt::Key_Left:
359 case Qt::Key_Left:
351
360
352 // Moving the cursor left is limited to the position
361 // Moving the cursor left is limited to the position
353 // of the command prompt.
362 // of the command prompt.
354
363
355 if (textCursor.position() <= commandPromptPosition()) {
364 if (textCursor.position() <= commandPromptPosition()) {
356
365
357 QApplication::beep();
366 QApplication::beep();
358 eventHandled = true;
367 eventHandled = true;
359 }
368 }
360 break;
369 break;
361
370
362 case Qt::Key_Up:
371 case Qt::Key_Up:
363
372
364 // Display the previous command in the history
373 // Display the previous command in the history
365 if (_historyPosition>0) {
374 if (_historyPosition>0) {
366 _historyPosition--;
375 _historyPosition--;
367 changeHistory();
376 changeHistory();
368 }
377 }
369
378
370 eventHandled = true;
379 eventHandled = true;
371 break;
380 break;
372
381
373 case Qt::Key_Down:
382 case Qt::Key_Down:
374
383
375 // Display the next command in the history
384 // Display the next command in the history
376 if (_historyPosition+1<_history.count()) {
385 if (_historyPosition+1<_history.count()) {
377 _historyPosition++;
386 _historyPosition++;
378 changeHistory();
387 changeHistory();
379 }
388 }
380
389
381 eventHandled = true;
390 eventHandled = true;
382 break;
391 break;
383
392
384 case Qt::Key_Return:
393 case Qt::Key_Return:
385
394
386 executeLine(event->modifiers() & Qt::ShiftModifier);
395 executeLine(event->modifiers() & Qt::ShiftModifier);
387 eventHandled = true;
396 eventHandled = true;
388 break;
397 break;
389
398
390 case Qt::Key_Backspace:
399 case Qt::Key_Backspace:
391
400
392 if (textCursor.hasSelection()) {
401 if (textCursor.hasSelection()) {
393
402
394 cut();
403 cut();
395 eventHandled = true;
404 eventHandled = true;
396
405
397 } else {
406 } else {
398
407
399 // Intercept backspace key event to check if
408 // Intercept backspace key event to check if
400 // deleting a character is allowed. It is not
409 // deleting a character is allowed. It is not
401 // allowed, if the user wants to delete the
410 // allowed, if the user wants to delete the
402 // command prompt.
411 // command prompt.
403
412
404 if (textCursor.position() <= commandPromptPosition()) {
413 if (textCursor.position() <= commandPromptPosition()) {
405
414
406 QApplication::beep();
415 QApplication::beep();
407 eventHandled = true;
416 eventHandled = true;
408 }
417 }
409 }
418 }
410 break;
419 break;
411
420
412 case Qt::Key_Delete:
421 case Qt::Key_Delete:
413
422
414 cut();
423 cut();
415 eventHandled = true;
424 eventHandled = true;
416 break;
425 break;
417
426
418 default:
427 default:
419
428
420 if (key >= Qt::Key_Space && key <= Qt::Key_division) {
429 if (key >= Qt::Key_Space && key <= Qt::Key_division) {
421
430
422 if (textCursor.hasSelection() && !verifySelectionBeforeDeletion()) {
431 if (textCursor.hasSelection() && !verifySelectionBeforeDeletion()) {
423
432
424 // The selection must not be deleted.
433 // The selection must not be deleted.
425 eventHandled = true;
434 eventHandled = true;
426
435
427 } else {
436 } else {
428
437
429 // The key is an input character, check if the cursor is
438 // The key is an input character, check if the cursor is
430 // behind the last command prompt, else inserting the
439 // behind the last command prompt, else inserting the
431 // character is not allowed.
440 // character is not allowed.
432
441
433 int commandPromptPosition = this->commandPromptPosition();
442 int commandPromptPosition = this->commandPromptPosition();
434 if (textCursor.position() < commandPromptPosition) {
443 if (textCursor.position() < commandPromptPosition) {
435
444
436 textCursor.setPosition(commandPromptPosition);
445 textCursor.setPosition(commandPromptPosition);
437 setTextCursor(textCursor);
446 setTextCursor(textCursor);
438 }
447 }
439 }
448 }
440 }
449 }
441 }
450 }
442
451
443 if (eventHandled) {
452 if (eventHandled) {
444
453
445 _completer->popup()->hide();
454 _completer->popup()->hide();
446 event->accept();
455 event->accept();
447
456
448 } else {
457 } else {
449
458
450 QTextEdit::keyPressEvent(event);
459 QTextEdit::keyPressEvent(event);
451 QString text = event->text();
460 QString text = event->text();
452 if (!text.isEmpty()) {
461 if (!text.isEmpty()) {
453 handleTabCompletion();
462 handleTabCompletion();
454 } else {
463 } else {
455 _completer->popup()->hide();
464 _completer->popup()->hide();
456 }
465 }
457 eventHandled = true;
466 eventHandled = true;
458 }
467 }
459 }
468 }
460
469
461
470
462
471
463 //-----------------------------------------------------------------------------
472 //-----------------------------------------------------------------------------
464
473
465 void PythonQtScriptingConsole::cut() {
474 void PythonQtScriptingConsole::cut() {
466
475
467 bool deletionAllowed = verifySelectionBeforeDeletion();
476 bool deletionAllowed = verifySelectionBeforeDeletion();
468 if (deletionAllowed) {
477 if (deletionAllowed) {
469 QTextEdit::cut();
478 QTextEdit::cut();
470 }
479 }
471 }
480 }
472
481
473
482
474
483
475 //-----------------------------------------------------------------------------
484 //-----------------------------------------------------------------------------
476
485
477 bool PythonQtScriptingConsole::verifySelectionBeforeDeletion() {
486 bool PythonQtScriptingConsole::verifySelectionBeforeDeletion() {
478
487
479 bool deletionAllowed = true;
488 bool deletionAllowed = true;
480
489
481
490
482 QTextCursor textCursor = this->textCursor();
491 QTextCursor textCursor = this->textCursor();
483
492
484 int commandPromptPosition = this->commandPromptPosition();
493 int commandPromptPosition = this->commandPromptPosition();
485 int selectionStart = textCursor.selectionStart();
494 int selectionStart = textCursor.selectionStart();
486 int selectionEnd = textCursor.selectionEnd();
495 int selectionEnd = textCursor.selectionEnd();
487
496
488 if (textCursor.hasSelection()) {
497 if (textCursor.hasSelection()) {
489
498
490 // Selected text may only be deleted after the last command prompt.
499 // Selected text may only be deleted after the last command prompt.
491 // If the selection is partly after the command prompt set the selection
500 // If the selection is partly after the command prompt set the selection
492 // to the part and deletion is allowed. If the selection occurs before the
501 // to the part and deletion is allowed. If the selection occurs before the
493 // last command prompt, then deletion is not allowed.
502 // last command prompt, then deletion is not allowed.
494
503
495 if (selectionStart < commandPromptPosition ||
504 if (selectionStart < commandPromptPosition ||
496 selectionEnd < commandPromptPosition) {
505 selectionEnd < commandPromptPosition) {
497
506
498 // Assure selectionEnd is bigger than selection start
507 // Assure selectionEnd is bigger than selection start
499 if (selectionStart > selectionEnd) {
508 if (selectionStart > selectionEnd) {
500 int tmp = selectionEnd;
509 int tmp = selectionEnd;
501 selectionEnd = selectionStart;
510 selectionEnd = selectionStart;
502 selectionStart = tmp;
511 selectionStart = tmp;
503 }
512 }
504
513
505 if (selectionEnd < commandPromptPosition) {
514 if (selectionEnd < commandPromptPosition) {
506
515
507 // Selection is completely before command prompt,
516 // Selection is completely before command prompt,
508 // so deletion is not allowed.
517 // so deletion is not allowed.
509 QApplication::beep();
518 QApplication::beep();
510 deletionAllowed = false;
519 deletionAllowed = false;
511
520
512 } else {
521 } else {
513
522
514 // The selectionEnd is after the command prompt, so set
523 // The selectionEnd is after the command prompt, so set
515 // the selection start to the commandPromptPosition.
524 // the selection start to the commandPromptPosition.
516 selectionStart = commandPromptPosition;
525 selectionStart = commandPromptPosition;
517 textCursor.setPosition(selectionStart);
526 textCursor.setPosition(selectionStart);
518 textCursor.setPosition(selectionStart, QTextCursor::KeepAnchor);
527 textCursor.setPosition(selectionStart, QTextCursor::KeepAnchor);
519 setTextCursor(textCursor);
528 setTextCursor(textCursor);
520 }
529 }
521 }
530 }
522
531
523 } else { // if (hasSelectedText())
532 } else { // if (hasSelectedText())
524
533
525 // When there is no selected text, deletion is not allowed before the
534 // When there is no selected text, deletion is not allowed before the
526 // command prompt.
535 // command prompt.
527 if (textCursor.position() < commandPromptPosition) {
536 if (textCursor.position() < commandPromptPosition) {
528
537
529 QApplication::beep();
538 QApplication::beep();
530 deletionAllowed = false;
539 deletionAllowed = false;
531 }
540 }
532 }
541 }
533
542
534 return deletionAllowed;
543 return deletionAllowed;
535 }
544 }
536
545
537
546
538
547
539 //-----------------------------------------------------------------------------
548 //-----------------------------------------------------------------------------
540
549
541 void PythonQtScriptingConsole::changeHistory() {
550 void PythonQtScriptingConsole::changeHistory() {
542
551
543 // Select the text after the last command prompt ...
552 // Select the text after the last command prompt ...
544 QTextCursor textCursor = this->textCursor();
553 QTextCursor textCursor = this->textCursor();
545 textCursor.movePosition(QTextCursor::End);
554 textCursor.movePosition(QTextCursor::End);
546 textCursor.setPosition(commandPromptPosition(), QTextCursor::KeepAnchor);
555 textCursor.setPosition(commandPromptPosition(), QTextCursor::KeepAnchor);
547
556
548 // ... and replace it with the history text.
557 // ... and replace it with the history text.
549 textCursor.insertText(_history.value(_historyPosition));
558 textCursor.insertText(_history.value(_historyPosition));
550
559
551 textCursor.movePosition(QTextCursor::End);
560 textCursor.movePosition(QTextCursor::End);
552 setTextCursor(textCursor);
561 setTextCursor(textCursor);
553 }
562 }
554
563
555
564
556
565
557 //-----------------------------------------------------------------------------
566 //-----------------------------------------------------------------------------
558
567
559 void PythonQtScriptingConsole::consoleMessage(const QString & message) {
568 void PythonQtScriptingConsole::consoleMessage(const QString & message) {
560
569
561 append(QString());
570 append(QString());
562 insertPlainText(message);
571 insertPlainText(message);
563
572
564 // Reset all font modifications done by the html string
573 // Reset all font modifications done by the html string
565 setCurrentCharFormat(_defaultTextCharacterFormat);
574 setCurrentCharFormat(_defaultTextCharacterFormat);
566 }
575 }
General Comments 0
You need to be logged in to leave comments. Login now