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