##// END OF EJS Templates
- removed warnings...
florianlink -
r8:f65f3e118cc5
parent child
Show More
@@ -0,0 +1,80
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 PythonQtQFileImporter.h
36 // \author Florian Link
37 // \author Last changed by $Author: florian $
38 // \date 2009-03
39 */
40 //----------------------------------------------------------------------------------
41
42 #include <QFile>
43 #include <QFileInfo>
44
45 #include "PythonQtQFileImporter.h"
46
47 PythonQtQFileImporter::PythonQtQFileImporter() {
48 }
49
50 PythonQtQFileImporter::~PythonQtQFileImporter() {
51 }
52
53 QByteArray PythonQtQFileImporter::readFileAsBytes (const QString &filename) {
54 QFile f(filename);
55 if (f.open(QIODevice::ReadOnly)) {
56 return f.readAll();
57 } else {
58 return QByteArray();
59 }
60 }
61
62 QByteArray PythonQtQFileImporter::readSourceFile (const QString &filename, bool &ok) {
63 QFile f(filename);
64 if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
65 ok = true;
66 return f.readAll();
67 } else {
68 ok = false;
69 return QByteArray();
70 }
71 }
72
73 bool PythonQtQFileImporter::exists (const QString &filename) {
74 return QFile::exists(filename);
75 }
76
77 QDateTime PythonQtQFileImporter::lastModifiedDate (const QString &filename) {
78 QFileInfo fi(filename);
79 return fi.lastModified();
80 }
@@ -0,0 +1,63
1 #ifndef _PYTHONQTQFILEIMPORTER_H
2 #define _PYTHONQTQFILEIMPORTER_H
3
4 /*
5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * Further, this software is distributed without any warranty that it is
19 * free of the rightful claim of any third person regarding infringement
20 * or the like. Any license provided herein, whether implied or
21 * otherwise, applies only to this software file. Patent licenses, if
22 * any, provided herein do not apply to combinations of this program with
23 * other software, or any other product whatsoever.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
30 * 28359 Bremen, Germany or:
31 *
32 * http://www.mevis.de
33 *
34 */
35
36 //----------------------------------------------------------------------------------
37 /*!
38 // \file PythonQtQFileImporter.h
39 // \author Florian Link
40 // \author Last changed by $Author: florian $
41 // \date 2009-03
42 */
43 //----------------------------------------------------------------------------------
44
45 #include <PythonQtImportFileInterface.h>
46
47 //! default importer implementation using QFile to load python code
48 class PythonQtQFileImporter : public PythonQtImportFileInterface {
49 public:
50 PythonQtQFileImporter();
51 ~PythonQtQFileImporter();
52
53 QByteArray readFileAsBytes (const QString &filename);
54
55 QByteArray readSourceFile (const QString &filename, bool &ok);
56
57 bool exists (const QString &filename);
58
59 QDateTime lastModifiedDate (const QString &filename);
60
61 };
62
63 #endif
@@ -1,49 +1,46
1 1 #include <PythonQt.h>
2 2 #include <QtGui>
3 #include "QFileImportInterface.h"
4 3
5 4 int main (int argc, char* argv[]) {
6 5 QApplication app(argc, argv);
7 6 PythonQt::init();
8 7 PythonQtObjectPtr mainModule = PythonQt::self()->getMainModule();
9 8 mainModule.evalScript(QString("import sys\n"));
10 9 Q_ASSERT(!mainModule.isNull());
11 10 {
12 11 // evaluate a python file embedded in executable as resource:
13 12 mainModule.evalFile(":eyed3tagger.py");
14 13 // create an object, hold onto its reference
15 14 PythonQtObjectPtr tag = mainModule.evalScript("EyeD3Tagger()\n", Py_eval_input);
16 15 Q_ASSERT(!tag.isNull());
17 16 tag.call("setFileName", QVariantList() << "t.mp3");
18 17 QVariant fn = tag.call("fileName", QVariantList());
19 18 Q_ASSERT(fn.toString() == QString("t.mp3"));
20 19 // tag goes out of scope, reference count decremented.
21 20 }
22 qDebug() << "test1";
23 /*
24 21 {
25 22 // Allow the python system path to recognize QFile paths in the sys.path
26 QFileImportInterface qfii;
23 //QFileImportInterface qfii;
24 PythonQt::self()->setImporter(NULL);
27 25 // append the Qt resource root directory to the sys.path
28 26 mainModule.evalScript("sys.path.append(':')\n");
29 27 mainModule.evalScript("import eyed3tagger\n");
30 28 PythonQtObjectPtr tag = mainModule.evalScript("eyed3tagger.EyeD3Tagger()\n", Py_eval_input);
31 29 Q_ASSERT(!tag.isNull());
32 30 tag.call("setFileName", QVariantList() << "t.mp3");
33 31 QVariant fn = tag.call("fileName", QVariantList());
34 32 Q_ASSERT(fn.toString() == QString("t.mp3"));
35 33 }
36 qDebug() << "test2"; */
37 34 { // alternative using import and loading it as a real module from sys.path
38 35 // import sys first
39 36 mainModule.evalScript(QString("sys.path.append('%1')\n").arg(QDir::currentPath()));
40 37 mainModule.evalScript("import eyed3tagger\n");
41 38 PythonQtObjectPtr tag = mainModule.evalScript("eyed3tagger.EyeD3Tagger()\n", Py_eval_input);
42 39 Q_ASSERT(!tag.isNull());
43 40 tag.call("setFileName", QVariantList() << "t.mp3");
44 41 QVariant fn = tag.call("fileName", QVariantList());
45 42 Q_ASSERT(fn.toString() == QString("t.mp3"));
46 43 }
47 44 qDebug() << "finished";
48 45 return 0;
49 46 }
@@ -1,11 +1,11
1 1 CONFIG += debug
2 2 VPATH +=
3 3 INCLUDEPATH += . $$(PYTHONQT_ROOT)/src /usr/include/python2.5
4 4
5 SOURCES += CPPPyWrapperExample.cpp QFileImportInterface.cpp
6 HEADERS += QFileImportInterface.h
5 SOURCES += CPPPyWrapperExample.cpp
7 6
7 mac { CONFIG -= app_bundle }
8 8
9 LIBS += -L$$(PYTHONQT_ROOT)/lib -lPythonQt -lutil
9 LIBS += -L$$(PYTHONQT_ROOT)/lib -lPythonQt_d -lutil
10 10
11 11 RESOURCES += CPPPyWrapperExample.qrc
@@ -1,1011 +1,1029
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 #include "PythonQtQFileImporter.h"
52 53 #include <pydebug.h>
53 54
54 55 PythonQt* PythonQt::_self = NULL;
55 56 int PythonQt::_uniqueModuleCount = 0;
56 57
57 58
58 59 void PythonQt::init(int flags)
59 60 {
60 61 if (!_self) {
61 62 _self = new PythonQt(flags);
62 63 }
63 64
64 65 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
65 66 qRegisterMetaType<QList<QObject*> >("QList<void*>");
66 67
67 68 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
68 69
69 70 PythonQt::priv()->addVariantWrapper("QBitArray", new PythonQtQBitArrayWrapper);
70 71 PythonQt::priv()->addVariantWrapper("QDate", new PythonQtQDateWrapper);
71 72 PythonQt::priv()->addVariantWrapper("QTime", new PythonQtQTimeWrapper);
72 73 PythonQt::priv()->addVariantWrapper("QDateTime", new PythonQtQDateTimeWrapper);
73 74 PythonQt::priv()->addVariantWrapper("QUrl", new PythonQtQUrlWrapper);
74 75 PythonQt::priv()->addVariantWrapper("QLocale", new PythonQtQLocaleWrapper);
75 76 PythonQt::priv()->addVariantWrapper("QRect", new PythonQtQRectWrapper);
76 77 PythonQt::priv()->addVariantWrapper("QRectF", new PythonQtQRectFWrapper);
77 78 PythonQt::priv()->addVariantWrapper("QSize", new PythonQtQSizeWrapper);
78 79 PythonQt::priv()->addVariantWrapper("QSizeF", new PythonQtQSizeFWrapper);
79 80 PythonQt::priv()->addVariantWrapper("QLine", new PythonQtQLineWrapper);
80 81 PythonQt::priv()->addVariantWrapper("QLineF", new PythonQtQLineFWrapper);
81 82 PythonQt::priv()->addVariantWrapper("QPoint", new PythonQtQPointWrapper);
82 83 PythonQt::priv()->addVariantWrapper("QPointF", new PythonQtQPointFWrapper);
83 84 PythonQt::priv()->addVariantWrapper("QRegExp", new PythonQtQRegExpWrapper);
84 85 PythonQt::priv()->addVariantWrapper("QFont", new PythonQtQFontWrapper);
85 86 PythonQt::priv()->addVariantWrapper("QPixmap", new PythonQtQPixmapWrapper);
86 87 PythonQt::priv()->addVariantWrapper("QBrush", new PythonQtQBrushWrapper);
87 88 PythonQt::priv()->addVariantWrapper("QColor", new PythonQtQColorWrapper);
88 89 PythonQt::priv()->addVariantWrapper("QPalette", new PythonQtQPaletteWrapper);
89 90 PythonQt::priv()->addVariantWrapper("QIcon", new PythonQtQIconWrapper);
90 91 PythonQt::priv()->addVariantWrapper("QImage", new PythonQtQImageWrapper);
91 92 PythonQt::priv()->addVariantWrapper("QPolygon", new PythonQtQPolygonWrapper);
92 93 PythonQt::priv()->addVariantWrapper("QRegion", new PythonQtQRegionWrapper);
93 94 PythonQt::priv()->addVariantWrapper("QBitmap", new PythonQtQBitmapWrapper);
94 95 PythonQt::priv()->addVariantWrapper("QCursor", new PythonQtQCursorWrapper);
95 96 PythonQt::priv()->addVariantWrapper("QSizePolicy", new PythonQtQSizePolicyWrapper);
96 97 PythonQt::priv()->addVariantWrapper("QKeySequence", new PythonQtQKeySequenceWrapper);
97 98 PythonQt::priv()->addVariantWrapper("QPen", new PythonQtQPenWrapper);
98 99 PythonQt::priv()->addVariantWrapper("QTextLength", new PythonQtQTextLengthWrapper);
99 100 PythonQt::priv()->addVariantWrapper("QTextFormat", new PythonQtQTextFormatWrapper);
100 101 PythonQt::priv()->addVariantWrapper("QMatrix", new PythonQtQMatrixWrapper);
101 102
102 103 }
103 104
104 105 void PythonQt::cleanup()
105 106 {
106 107 if (_self) {
107 108 delete _self;
108 109 _self = NULL;
109 110 }
110 111 }
111 112
112 113 PythonQt::PythonQt(int flags)
113 114 {
114 115 _p = new PythonQtPrivate;
115 116 _p->_initFlags = flags;
116 117
117 118 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
118 119
119 120 Py_SetProgramName("PythonQt");
120 121 if (flags & IgnoreSiteModule) {
121 122 // this prevents the automatic importing of Python site files
122 123 Py_NoSiteFlag = 1;
123 124 }
124 125 Py_Initialize();
125 126
126 127 // add our own python object types for qt object slots
127 128 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
128 129 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
129 130 }
130 131 Py_INCREF(&PythonQtSlotFunction_Type);
131 132
132 133 // add our own python object types for qt objects
133 134 if (PyType_Ready(&PythonQtWrapper_Type) < 0) {
134 135 std::cerr << "could not initialize PythonQtWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
135 136 }
136 137 Py_INCREF(&PythonQtWrapper_Type);
137 138
138 139 // add our own python object types for qt objects
139 140 if (PyType_Ready(&PythonQtVariantWrapper_Type) < 0) {
140 141 std::cerr << "could not initialize PythonQtVariantWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
141 142 }
142 143 Py_INCREF(&PythonQtVariantWrapper_Type);
143 144
144 145 // add our own python object types for qt objects
145 146 if (PyType_Ready(&PythonQtMetaObjectWrapper_Type) < 0) {
146 147 std::cerr << "could not initialize PythonQtMetaObjectWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
147 148 }
148 149 Py_INCREF(&PythonQtMetaObjectWrapper_Type);
149 150
150 151 // add our own python object types for redirection of stdout
151 152 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
152 153 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
153 154 }
154 155 Py_INCREF(&PythonQtStdOutRedirectType);
155 156
156 157 initPythonQtModule(flags & RedirectStdOut);
157 158
158 159 }
159 160
160 161 PythonQt::~PythonQt() {
161 162 delete _p;
162 163 _p = NULL;
163 164 }
164 165
165 166 PythonQtPrivate::~PythonQtPrivate() {
167 delete _defaultImporter;
168 _defaultImporter = NULL;
169 {
170 QHashIterator<QByteArray, PythonQtSlotInfo *> i(_knownQtDecoratorSlots);
171 while (i.hasNext()) {
172 delete i.next().value();
173 }
174 }
166 175 {
167 176 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownQtClasses);
168 177 while (i.hasNext()) {
169 178 delete i.next().value();
170 179 }
171 180 }
172 181 {
173 182 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownQtWrapperClasses);
174 183 while (i.hasNext()) {
175 184 delete i.next().value();
176 185 }
177 186 }
178 187 {
179 188 QHashIterator<int , QPair<PythonQtClassInfo*, QObject*> > i(_knownVariantWrappers);
180 189 while (i.hasNext()) {
181 190 delete i.next().value().first;
182 191 }
183 192 }
184 193 {
185 194 QHashIterator<QByteArray, PythonQtSlotInfo *> i(_constructorSlots);
186 195 while (i.hasNext()) {
187 delete i.next().value();
196 PythonQtSlotInfo* cur = i.next().value();
197 while(cur->nextInfo()) {
198 PythonQtSlotInfo* next = cur->nextInfo();
199 delete cur;
200 cur = next;
201 }
202 delete cur;
188 203 }
189 204 }
190 205 {
191 206 QHashIterator<QByteArray, PythonQtSlotInfo *> i(_destructorSlots);
192 207 while (i.hasNext()) {
193 delete i.next().value();
208 PythonQtSlotInfo* cur = i.next().value();
209 while(cur->nextInfo()) {
210 PythonQtSlotInfo* next = cur->nextInfo();
211 delete cur;
212 cur = next;
213 }
214 delete cur;
194 215 }
195 216 }
196 217 PythonQtConv::global_valueStorage.clear();
197 218 PythonQtConv::global_ptrStorage.clear();
198 219 PythonQtConv::global_variantStorage.clear();
199 220
200 221 PythonQtMethodInfo::cleanupCachedMethodInfos();
201 222
202 223 delete _qtNamespace;
203 224 }
204 225
205 226 PythonQtImportFileInterface* PythonQt::importInterface()
206 227 {
207 return _self->_p->_importInterface;
228 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
208 229 }
209 230
210 231 void PythonQt::registerClass(const QMetaObject* metaobject)
211 232 {
212 233 _p->registerClass(metaobject);
213 234 }
214 235
215 236 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
216 237 {
217 238 if (_self->_p->_noLongerWrappedCB) {
218 239 (*_self->_p->_noLongerWrappedCB)(o);
219 240 };
220 241 }
221 242
222 243 void PythonQtPrivate::registerClass(const QMetaObject* metaobject)
223 244 {
224 245 // we register all classes in the hierarchy
225 246 const QMetaObject* m = metaobject;
226 247 while (m) {
227 248 PythonQtClassInfo* info = _knownQtClasses.value(m->className());
228 249 if (!info) {
229 250 info = new PythonQtClassInfo(m);
230 251 _knownQtClasses.insert(m->className(), info);
231 252 PyModule_AddObject(_pythonQtModule, m->className(), (PyObject*)createNewPythonQtMetaObjectWrapper(info));
232 253 }
233 254 m = m->superClass();
234 255 }
235 256 }
236 257
237 258 bool PythonQtPrivate::isEnumType(const QMetaObject* meta, const QByteArray& name) {
238 259 int i = meta?meta->indexOfEnumerator(name.constData()):-1;
239 260 if (i!=-1) {
240 261 return true;
241 262 } else {
242 263 // look for scope
243 264 int scopePos = name.indexOf("::");
244 265 if (scopePos != -1) {
245 266 // slit into scope and enum name
246 267 QByteArray enumScope = name.mid(0,scopePos);
247 268 QByteArray enumName = name.mid(scopePos+2);
248 269 if (enumScope == "Qt") {
249 270 // special qt namespace case
250 271 return isEnumType(&staticQtMetaObject, enumName);
251 272 } else {
252 273 // look for known classes as scope
253 274 // TODO: Q_GADGETS are not yet handled
254 275 PythonQtClassInfo* info = _knownQtClasses.value(enumScope);
255 276 if (info) {
256 277 return isEnumType(info->metaObject(), enumName);
257 278 }
258 279 }
259 280 }
260 281 }
261 282 return false;
262 283 }
263 284
264 285 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
265 286 {
266 287 if (!obj) {
267 288 Py_INCREF(Py_None);
268 289 return Py_None;
269 290 }
270 291 PythonQtWrapper* wrap = findWrapperAndRemoveUnused(obj);
271 292 if (!wrap) {
272 293 // smuggling it in...
273 294 PythonQtClassInfo* classInfo = _knownQtClasses.value(obj->metaObject()->className());
274 295 if (!classInfo) {
275 296 registerClass(obj->metaObject());
276 297 classInfo = _knownQtClasses.value(obj->metaObject()->className());
277 298 }
278 299 wrap = createNewPythonQtWrapper(obj, classInfo);
279 300 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
280 301 } else {
281 302 Py_INCREF(wrap);
282 303 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
283 304 }
284 305 return (PyObject*)wrap;
285 306 }
286 307
287 308 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
288 309 {
289 310 if (!ptr) {
290 311 Py_INCREF(Py_None);
291 312 return Py_None;
292 313 }
293 314 PythonQtWrapper* wrap = findWrapperAndRemoveUnused(ptr);
294 315 if (!wrap) {
295 316 PythonQtClassInfo* info = _knownQtClasses.value(name);
296 317 if (!info) {
297 318 // we do not know the metaobject yet, but we might know it by it's name:
298 319 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
299 320 // yes, we know it, so we can convert to QObject
300 321 QObject* qptr = (QObject*)ptr;
301 322 registerClass(qptr->metaObject());
302 323 info = _knownQtClasses.value(qptr->metaObject()->className());
303 324 }
304 325 }
305 326 if (info) {
306 327 QObject* qptr = (QObject*)ptr;
307 328 // if the object is a derived object, we want to switch the class info to the one of the derived class:
308 329 if (name!=(qptr->metaObject()->className())) {
309 330 registerClass(qptr->metaObject());
310 331 info = _knownQtClasses.value(qptr->metaObject()->className());
311 332 }
312 333 wrap = createNewPythonQtWrapper(qptr, info);
313 334 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
314 335 } else {
315 336 // maybe it is a PyObject, which we can return directly
316 337 if (name == "PyObject") {
317 338 PyObject* p = (PyObject*)ptr;
318 339 Py_INCREF(p);
319 340 return p;
320 341 }
321 342 // not a known QObject, so try our wrapper factory:
322 343 QObject* wrapper = NULL;
323 344 for (int i=0; i<_cppWrapperFactories.size(); i++) {
324 345 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
325 346 if (wrapper) {
326 347 break;
327 348 }
328 349 }
329 350 PythonQtClassInfo* info = _knownQtWrapperClasses.value(name);
330 351 if (!info) {
331 352 info = new PythonQtClassInfo(wrapper?wrapper->metaObject():&QObject::staticQtMetaObject, name);
332 353 _knownQtWrapperClasses.insert(name, info);
333 354 PyModule_AddObject(_pythonQtModule, name, (PyObject*)createNewPythonQtMetaObjectWrapper(info));
334 355 } else {
335 356 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
336 357 info->setMetaObject(wrapper->metaObject());
337 358 }
338 359 }
339 360 wrap = createNewPythonQtWrapper(wrapper, info, ptr);
340 361 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
341 362 }
342 363 } else {
343 364 Py_INCREF(wrap);
344 365 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
345 366 }
346 367 return (PyObject*)wrap;
347 368 }
348 369
349 370 void PythonQt::registerCPPClassNames(const QStringList& names)
350 371 {
351 372 foreach ( QString n, names) {
352 373 QByteArray name = n.toLatin1();
353 374 PythonQtClassInfo* info = _p->_knownQtWrapperClasses.value(name);
354 375 if (!info) {
355 376 info = new PythonQtClassInfo(&QObject::staticMetaObject, name);
356 377 _p->_knownQtWrapperClasses.insert(name, info);
357 378 PyModule_AddObject(_p->_pythonQtModule, name.data(), (PyObject*)_p->createNewPythonQtMetaObjectWrapper(info));
358 379 }
359 380 }
360 381 }
361 382
362 383 PythonQtWrapper* PythonQtPrivate::createNewPythonQtWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
363 384 PythonQtWrapper* result;
364 385 result = (PythonQtWrapper *)PythonQtWrapper_Type.tp_new(&PythonQtWrapper_Type,
365 386 NULL, NULL);
366 387
367 388 result->setQObject(obj);
368 389 result->_info = info;
369 390 result->_wrappedPtr = wrappedPtr;
370 391 result->_ownedByPythonQt = false;
371 392
372 393 if (wrappedPtr) {
373 394 _wrappedObjects.insert(wrappedPtr, result);
374 395 } else {
375 396 _wrappedObjects.insert(obj, result);
376 397 if (obj->parent()== NULL && _wrappedCB) {
377 398 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
378 399 (*_wrappedCB)(obj);
379 400 }
380 401 }
381 402 return result;
382 403 }
383 404
384 405 PythonQtVariantWrapper* PythonQtPrivate::createNewPythonQtVariantWrapper(const QVariant& variant) {
385 406 PythonQtVariantWrapper* result;
386 407 result = (PythonQtVariantWrapper *)PythonQtVariantWrapper_Type.tp_new(&PythonQtVariantWrapper_Type,
387 408 NULL, NULL);
388 409
389 410 *result->_variant = variant;
390 411 QPair<PythonQtClassInfo*, QObject*> pair = _knownVariantWrappers.value(variant.userType());
391 412 result->_wrapper = pair.second;
392 413 result->_info = pair.first;
393 414 return result;
394 415 }
395 416
396 417 PythonQtMetaObjectWrapper* PythonQtPrivate::createNewPythonQtMetaObjectWrapper(PythonQtClassInfo* info) {
397 418 PythonQtMetaObjectWrapper* result;
398 419 result = (PythonQtMetaObjectWrapper *)PythonQtMetaObjectWrapper_Type.tp_new(&PythonQtMetaObjectWrapper_Type,
399 420 NULL, NULL);
400 421 result->_info = info;
401 422 return result;
402 423 }
403 424
404 425
405 426 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
406 427 {
407 428 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
408 429 if (!r) {
409 430 r = new PythonQtSignalReceiver(obj);
410 431 _p->_signalReceivers.insert(obj, r);
411 432 }
412 433 return r;
413 434 }
414 435
415 436 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
416 437 {
417 438 bool flag = false;
418 439 PythonQtObjectPtr callable = lookupCallable(module, objectname);
419 440 if (callable) {
420 441 PythonQtSignalReceiver* r = getSignalReceiver(obj);
421 442 flag = r->addSignalHandler(signal, callable);
422 443 if (!flag) {
423 444 // signal not found
424 445 }
425 446 } else {
426 447 // callable not found
427 448 }
428 449 return flag;
429 450 }
430 451
431 452 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
432 453 {
433 454 bool flag = false;
434 455 PythonQtSignalReceiver* r = getSignalReceiver(obj);
435 456 if (r) {
436 457 flag = r->addSignalHandler(signal, receiver);
437 458 }
438 459 return flag;
439 460 }
440 461
441 462 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
442 463 {
443 464 bool flag = false;
444 465 PythonQtObjectPtr callable = lookupCallable(module, objectname);
445 466 if (callable) {
446 467 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
447 468 if (r) {
448 469 flag = r->removeSignalHandler(signal, callable);
449 470 }
450 471 } else {
451 472 // callable not found
452 473 }
453 474 return flag;
454 475 }
455 476
456 477 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
457 478 {
458 479 bool flag = false;
459 480 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
460 481 if (r) {
461 482 flag = r->removeSignalHandler(signal, receiver);
462 483 }
463 484 return flag;
464 485 }
465 486
466 487 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
467 488 {
468 489 PythonQtObjectPtr p = lookupObject(module, name);
469 490 if (p) {
470 491 if (PyCallable_Check(p)) {
471 492 return p;
472 493 }
473 494 }
474 495 PyErr_Clear();
475 496 return NULL;
476 497 }
477 498
478 499 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
479 500 {
480 501 QStringList l = name.split('.');
481 502 PythonQtObjectPtr p = module;
482 503 PythonQtObjectPtr prev;
483 504 QString s;
484 505 QByteArray b;
485 506 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
486 507 prev = p;
487 508 b = (*i).toLatin1();
488 509 p.setNewRef(PyObject_GetAttrString(p, b.data()));
489 510 }
490 511 PyErr_Clear();
491 512 return p;
492 513 }
493 514
494 515 PythonQtObjectPtr PythonQt::getMainModule() {
495 516 //both borrowed
496 517 PythonQtObjectPtr dict = PyImport_GetModuleDict();
497 518 return PyDict_GetItemString(dict, "__main__");
498 519 }
499 520
500 521 QVariant PythonQt::evalCode(PyObject* module, PyObject* pycode) {
501 522 QVariant result;
502 523 if (pycode) {
503 524 PyObject* r = PyEval_EvalCode((PyCodeObject*)pycode, PyModule_GetDict((PyObject*)module) , PyModule_GetDict((PyObject*)module));
504 525 if (r) {
505 526 result = PythonQtConv::PyObjToQVariant(r);
506 527 Py_DECREF(r);
507 528 } else {
508 529 handleError();
509 530 }
510 531 } else {
511 532 handleError();
512 533 }
513 534 return result;
514 535 }
515 536
516 537 QVariant PythonQt::evalScript(PyObject* module, const QString& script, int start)
517 538 {
518 539 QVariant result;
519 540 PythonQtObjectPtr p;
520 541 p.setNewRef(PyRun_String(script.toLatin1().data(), start, PyModule_GetDict(module), PyModule_GetDict(module)));
521 542 if (p) {
522 543 result = PythonQtConv::PyObjToQVariant(p);
523 544 } else {
524 545 handleError();
525 546 }
526 547 return result;
527 548 }
528 549
529 550 void PythonQt::evalFile(PyObject* module, const QString& filename)
530 551 {
531 552 PythonQtObjectPtr code = parseFile(filename);
532 553 if (code) {
533 554 evalCode(module, code);
534 555 } else {
535 556 handleError();
536 557 }
537 558 }
538 559
539 560 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
540 561 {
541 562 PythonQtObjectPtr p;
542 563 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
543 564 if (!p) {
544 565 handleError();
545 566 }
546 567 return p;
547 568 }
548 569
549 570 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
550 571 {
551 572 PythonQtObjectPtr code = parseFile(filename);
552 573 PythonQtObjectPtr module = _p->createModule(name, code);
553 574 return module;
554 575 }
555 576
556 577 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
557 578 {
558 579 PyErr_Clear();
559 580 QString scriptCode = script;
560 581 if (scriptCode.isEmpty()) {
561 582 // we always need at least a linefeed
562 583 scriptCode = "\n";
563 584 }
564 585 PythonQtObjectPtr pycode;
565 586 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
566 587 PythonQtObjectPtr module = _p->createModule(name, pycode);
567 588 return module;
568 589 }
569 590
570 591 PythonQtObjectPtr PythonQt::createUniqueModule()
571 592 {
572 593 static QString pyQtStr("PythonQt_module");
573 594 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
574 595 return createModuleFromScript(moduleName);
575 596 }
576 597
577 598 void PythonQt::addObject(PyObject* module, const QString& name, QObject* object)
578 599 {
579 600 PyModule_AddObject(module, name.toLatin1().data(), _p->wrapQObject(object));
580 601 }
581 602
582 603 void PythonQt::addVariable(PyObject* module, const QString& name, const QVariant& v)
583 604 {
584 605 PyModule_AddObject(module, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
585 606 }
586 607
587 608 void PythonQt::removeVariable(PyObject* module, const QString& name)
588 609 {
589 610 PyObject_DelAttrString(module, name.toLatin1().data());
590 611 }
591 612
592 613 QVariant PythonQt::getVariable(PyObject* module, const QString& objectname)
593 614 {
594 615 QVariant result;
595 616 PythonQtObjectPtr obj = lookupObject(module, objectname);
596 617 if (obj) {
597 618 result = PythonQtConv::PyObjToQVariant(obj);
598 619 }
599 620 return result;
600 621 }
601 622
602 623 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
603 624 {
604 625 QStringList results;
605 626
606 627 PythonQtObjectPtr object;
607 628 if (objectname.isEmpty()) {
608 629 object = module;
609 630 } else {
610 631 object = lookupObject(module, objectname);
611 632 if (!object && type == CallOverloads) {
612 633 PyObject* dict = lookupObject(module, "__builtins__");
613 634 if (dict) {
614 635 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
615 636 }
616 637 }
617 638 }
618 639
619 640 if (object) {
620 641 if (type == CallOverloads) {
621 642 if (PythonQtSlotFunction_Check(object)) {
622 643 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
623 644 PythonQtSlotInfo* info = o->m_ml;
624 645
625 646 while (info) {
626 647 results << info->fullSignature(info->isInstanceDecorator() || o->m_self->ob_type == &PythonQtVariantWrapper_Type);
627 648 info = info->nextInfo();
628 649 }
629 650 } else if (object->ob_type == &PythonQtMetaObjectWrapper_Type) {
630 651 PythonQtMetaObjectWrapper* o = (PythonQtMetaObjectWrapper*)object.object();
631 652 PythonQtSlotInfo* info = o->_info->constructors();
632 653
633 654 while (info) {
634 655 results << info->fullSignature(false);
635 656 info = info->nextInfo();
636 657 }
637 658 } else {
638 659 //TODO: use pydoc!
639 660 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
640 661 if (doc) {
641 662 results << PyString_AsString(doc);
642 663 Py_DECREF(doc);
643 664 }
644 665 }
645 666 } else {
646 667 PyObject* keys = PyObject_Dir(object);
647 668 if (keys) {
648 669 int count = PyList_Size(keys);
649 670 PyObject* key;
650 671 PyObject* value;
651 672 QString keystr;
652 673 for (int i = 0;i<count;i++) {
653 674 key = PyList_GetItem(keys,i);
654 675 value = PyObject_GetAttr(object, key);
655 676 if (!value) continue;
656 677 keystr = PyString_AsString(key);
657 678 static const QString underscoreStr("__tmp");
658 679 if (!keystr.startsWith(underscoreStr)) {
659 680 switch (type) {
660 681 case Anything:
661 682 results << keystr;
662 683 break;
663 684 case Class:
664 685 if (value->ob_type == &PyClass_Type) {
665 686 results << keystr;
666 687 }
667 688 break;
668 689 case Variable:
669 690 if (value->ob_type != &PyClass_Type
670 691 && value->ob_type != &PyCFunction_Type
671 692 && value->ob_type != &PyFunction_Type
672 693 && value->ob_type != &PyModule_Type
673 694 ) {
674 695 results << keystr;
675 696 }
676 697 break;
677 698 case Function:
678 699 if (value->ob_type == &PyFunction_Type ||
679 700 value->ob_type == &PyMethod_Type
680 701 ) {
681 702 results << keystr;
682 703 }
683 704 break;
684 705 case Module:
685 706 if (value->ob_type == &PyModule_Type) {
686 707 results << keystr;
687 708 }
688 709 break;
689 710 default:
690 711 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
691 712 }
692 713 }
693 714 Py_DECREF(value);
694 715 }
695 716 Py_DECREF(keys);
696 717 }
697 718 }
698 719 }
699 720 return results;
700 721 }
701 722
702 723 QVariant PythonQt::call(PyObject* module, const QString& name, const QVariantList& args)
703 724 {
704 725 QVariant r;
705 726
706 727 PythonQtObjectPtr callable = lookupCallable(module, name);
707 728 if (callable) {
708 729 PythonQtObjectPtr pargs;
709 730 int count = args.size();
710 731 if (count>0) {
711 732 pargs.setNewRef(PyTuple_New(count));
712 733 }
713 734 bool err = false;
714 735 // transform QVariants to Python
715 736 for (int i = 0; i < count; i++) {
716 737 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
717 738 if (arg) {
718 739 // steals reference, no unref
719 740 PyTuple_SetItem(pargs, i,arg);
720 741 } else {
721 742 err = true;
722 743 break;
723 744 }
724 745 }
725 746
726 747 if (!err) {
727 748 PyErr_Clear();
728 749 PythonQtObjectPtr result;
729 750 result.setNewRef(PyObject_CallObject(callable, pargs));
730 751 if (result) {
731 752 // ok
732 753 r = PythonQtConv::PyObjToQVariant(result);
733 754 } else {
734 755 PythonQt::self()->handleError();
735 756 }
736 757 }
737 758 }
738 759 return r;
739 760 }
740 761
741 762 void PythonQt::addInstanceDecorators(QObject* o)
742 763 {
743 764 _p->addDecorators(o, true, false);
744 765 }
745 766
746 767 void PythonQt::addClassDecorators(QObject* o)
747 768 {
748 769 _p->addDecorators(o, false, true);
749 770 }
750 771
751 772 void PythonQt::addDecorators(QObject* o)
752 773 {
753 774 _p->addDecorators(o, true, true);
754 775 }
755 776
756 777 void PythonQt::registerQObjectClassNames(const QStringList& names)
757 778 {
758 779 _p->registerQObjectClassNames(names);
759 780 }
760 781
761 782 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
762 783 {
763 static bool first = true;
764 if (first) {
765 first = false;
766 _p->_importInterface = importInterface;
767 784 PythonQtImport::init();
768 }
785 _p->_importInterface = importInterface;
769 786 }
770 787
771 788 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
772 789 {
773 790 _p->_importIgnorePaths = paths;
774 791 }
775 792
776 793 const QStringList& PythonQt::getImporterIgnorePaths()
777 794 {
778 795 return _p->_importIgnorePaths;
779 796 }
780 797
781 798 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
782 799 {
783 800 _p->_cppWrapperFactories.append(factory);
784 801 }
785 802
786 803 void PythonQt::addConstructorHandler(PythonQtConstructorHandler* factory)
787 804 {
788 805 _p->_constructorHandlers.append(factory);
789 806 }
790 807
791 808 const QList<PythonQtConstructorHandler*>& PythonQt::constructorHandlers()
792 809 {
793 810 return _p->_constructorHandlers;
794 811 };
795 812
796 813 //---------------------------------------------------------------------------------------------------
797 814 PythonQtPrivate::PythonQtPrivate()
798 815 {
799 816 _importInterface = NULL;
817 _defaultImporter = new PythonQtQFileImporter;
800 818 _noLongerWrappedCB = NULL;
801 819 _wrappedCB = NULL;
802 820 }
803 821
804 822 void PythonQtPrivate::addDecorators(QObject* o, bool instanceDeco, bool classDeco)
805 823 {
806 824 o->setParent(this);
807 825 int numMethods = o->metaObject()->methodCount();
808 826 for (int i = 0; i < numMethods; i++) {
809 827 QMetaMethod m = o->metaObject()->method(i);
810 828 if ((m.methodType() == QMetaMethod::Method ||
811 829 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
812 830 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m);
813 831 if (qstrncmp(m.signature(), "new_", 4)==0) {
814 832 if (!classDeco) continue;
815 833 // either it returns a * or a QVariant and the name starts with "new_"
816 834 bool isVariantReturn = info->parameters().at(0).typeId == PythonQtMethodInfo::Variant;
817 835 if ((info->parameters().at(0).isPointer || isVariantReturn)) {
818 836 QByteArray signature = m.signature();
819 837 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
820 838 PythonQtSlotInfo* prev = _constructorSlots.value(nameOfClass);
821 839 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
822 840 if (prev) {
823 841 newSlot->setNextInfo(prev->nextInfo());
824 842 prev->setNextInfo(newSlot);
825 843 } else {
826 844 _constructorSlots.insert(nameOfClass, newSlot);
827 845 }
828 846 }
829 847 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
830 848 if (!classDeco) continue;
831 849 QByteArray signature = m.signature();
832 850 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
833 851 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
834 852 _destructorSlots.insert(nameOfClass, newSlot);
835 853 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
836 854 if (!classDeco) continue;
837 855 QByteArray signature = m.signature();
838 856 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
839 857 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
840 858 PythonQtSlotInfo* slotCopy = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::ClassDecorator);
841 859 _knownQtDecoratorSlots.insert(nameOfClass, slotCopy);
842 860 } else {
843 861 if (!instanceDeco) continue;
844 862 if (info->parameters().count()>1) {
845 863 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
846 864 if (p.isPointer) {
847 865 PythonQtSlotInfo* slotCopy = new PythonQtSlotInfo(m, i, o, PythonQtSlotInfo::InstanceDecorator);
848 866 _knownQtDecoratorSlots.insert(p.name, slotCopy);
849 867 }
850 868 }
851 869 }
852 870 }
853 871 }
854 872 }
855 873
856 874 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
857 875 {
858 876 foreach(QString name, names) {
859 877 _knownQObjectClassNames.insert(name.toLatin1(), true);
860 878 }
861 879 }
862 880
863 881 QList<PythonQtSlotInfo*> PythonQtPrivate::getDecoratorSlots(const QByteArray& className)
864 882 {
865 883 return _knownQtDecoratorSlots.values(className);
866 884 }
867 885
868 886 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
869 887 {
870 888 _signalReceivers.remove(obj);
871 889 }
872 890
873 891 bool PythonQt::handleError()
874 892 {
875 893 bool flag = false;
876 894 if (PyErr_Occurred()) {
877 895
878 896 // currently we just print the error and the stderr handler parses the errors
879 897 PyErr_Print();
880 898
881 899 /*
882 900 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
883 901 PyObject *ptype;
884 902 PyObject *pvalue;
885 903 PyObject *ptraceback;
886 904 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
887 905
888 906 Py_XDECREF(ptype);
889 907 Py_XDECREF(pvalue);
890 908 Py_XDECREF(ptraceback);
891 909 */
892 910 PyErr_Clear();
893 911 flag = true;
894 912 }
895 913 return flag;
896 914 }
897 915
898 916 void PythonQt::overwriteSysPath(const QStringList& paths)
899 917 {
900 918 PythonQtObjectPtr sys;
901 919 sys.setNewRef(PyImport_ImportModule("sys"));
902 920 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
903 921 }
904 922
905 923 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
906 924 {
907 925 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
908 926 }
909 927
910 928 void PythonQt::stdOutRedirectCB(const QString& str)
911 929 {
912 930 emit PythonQt::self()->pythonStdOut(str);
913 931 }
914 932
915 933 void PythonQt::stdErrRedirectCB(const QString& str)
916 934 {
917 935 emit PythonQt::self()->pythonStdErr(str);
918 936 }
919 937
920 938 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
921 939 {
922 940 _p->_wrappedCB = cb;
923 941 }
924 942
925 943 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
926 944 {
927 945 _p->_noLongerWrappedCB = cb;
928 946 }
929 947
930 948
931 949
932 950 static PyMethodDef PythonQtMethods[] = {
933 951 {NULL, NULL, 0, NULL}
934 952 };
935 953
936 954 void PythonQt::initPythonQtModule(bool redirectStdOut)
937 955 {
938 956 _p->_pythonQtModule.setNewRef(Py_InitModule("PythonQt", PythonQtMethods));
939 957 _p->_qtNamespace = new PythonQtClassInfo(&staticQtMetaObject);
940 958 PyModule_AddObject(_p->_pythonQtModule, "Qt", (PyObject*)_p->createNewPythonQtMetaObjectWrapper(_p->_qtNamespace));
941 959
942 960 if (redirectStdOut) {
943 961 PythonQtObjectPtr sys;
944 962 PythonQtObjectPtr out;
945 963 PythonQtObjectPtr err;
946 964 sys.setNewRef(PyImport_ImportModule("sys"));
947 965 // create a redirection object for stdout and stderr
948 966 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
949 967 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
950 968 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
951 969 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
952 970 // replace the built in file objects with our own objects
953 971 PyModule_AddObject(sys, "stdout", out);
954 972 PyModule_AddObject(sys, "stderr", err);
955 973 }
956 974 }
957 975
958 976 void PythonQt::addVariantWrapper(const char* typeName, QObject* wrapper)
959 977 {
960 978 _p->addVariantWrapper(typeName, wrapper);
961 979 }
962 980
963 981
964 982 void PythonQtPrivate::addVariantWrapper(const char* typeName, QObject* wrapper)
965 983 {
966 984 int type = QMetaType::type(typeName);
967 985 PythonQtClassInfo* info = new PythonQtClassInfo(wrapper->metaObject(), typeName);
968 986 _knownVariantWrappers.insert(type, qMakePair(info, wrapper));
969 987 addDecorators(wrapper, false, true);
970 988 PyModule_AddObject(_pythonQtModule, typeName, (PyObject*)createNewPythonQtMetaObjectWrapper(info));
971 989 }
972 990
973 991 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
974 992 {
975 993 if (_p->_initFlags & ExternalHelp) {
976 994 emit pythonHelpRequest(QByteArray(info->className()));
977 995 return Py_BuildValue("");
978 996 } else {
979 997 return PyString_FromString(info->help().toLatin1().data());
980 998 }
981 999 }
982 1000
983 1001 void PythonQtPrivate::removeWrapperPointer(void* obj)
984 1002 {
985 1003 _wrappedObjects.remove(obj);
986 1004 }
987 1005
988 1006 PythonQtWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
989 1007 {
990 1008 PythonQtWrapper* wrap = _wrappedObjects.value(obj);
991 1009 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
992 1010 // this is a wrapper whose QObject was already removed due to destruction
993 1011 // so the obj pointer has to be a new QObject with the same address...
994 1012 // we remove the old one and set the copy to NULL
995 1013 wrap->_objPointerCopy = NULL;
996 1014 removeWrapperPointer(obj);
997 1015 wrap = NULL;
998 1016 }
999 1017 return wrap;
1000 1018 }
1001 1019
1002 1020 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1003 1021 {
1004 1022 PythonQtObjectPtr result;
1005 1023 if (pycode) {
1006 1024 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1007 1025 } else {
1008 1026 PythonQt::self()->handleError();
1009 1027 }
1010 1028 return result;
1011 1029 }
@@ -1,469 +1,487
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 "PythonQtVariantWrapper.h"
48 48 #include "PythonQtMetaObjectWrapper.h"
49 49 #include "PythonQtSlot.h"
50 50 #include "PythonQtObjectPtr.h"
51 51 #include <QObject>
52 52 #include <QVariant>
53 53 #include <QList>
54 54 #include <QHash>
55 55 #include <QByteArray>
56 56 #include <QStringList>
57 57 #include <QtDebug>
58 58 #include <iostream>
59 59
60 60
61 61 class PythonQtClassInfo;
62 62 class PythonQtPrivate;
63 63 class PythonQtMethodInfo;
64 64 class PythonQtSignalReceiver;
65 65 class PythonQtImportFileInterface;
66 66 class PythonQtCppWrapperFactory;
67 67 class PythonQtConstructorHandler;
68 class PythonQtQFileImporter;
68 69
69 70 typedef void PythonQtQObjectWrappedCB(QObject* object);
70 71 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
71 72
72 73 //! the main interface to the Python Qt binding, realized as a singleton
73 74 class PYTHONQT_EXPORT PythonQt : public QObject {
74 75
75 76 Q_OBJECT
76 77
77 78 public:
78 79 enum InitFlags {
79 80 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
80 81 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
81 82 ExternalHelp = 4 //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
82 83 };
83 84
84 85 //! initialize the python qt binding (flags are a or combination of InitFlags)
85 86 static void init(int flags = IgnoreSiteModule | RedirectStdOut);
86 87
87 88 //! cleanup
88 89 static void cleanup();
89 90
90 91 //! get the singleton instance
91 92 static PythonQt* self() { return _self; }
92 93
93 94 //-----------------------------------------------------------------------------
94 95 // Public API:
95 96
96 97 //! defines the object types for introspection
97 98 enum ObjectType {
98 99 Class,
99 100 Function,
100 101 Variable,
101 102 Module,
102 103 Anything,
103 104 CallOverloads
104 105 };
105 106
106 107 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
107 108 void overwriteSysPath(const QStringList& paths);
108 109
109 110 //! sets the __path__ list of a module to the given list (important for local imports)
110 111 void setModuleImportPath(PyObject* module, const QStringList& paths);
111 112
112 113 //! get the __main__ module of python
113 114 PythonQtObjectPtr getMainModule();
114 115
115 116 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
116 117 //! All added metaobjects will be visible under the className in the PythonQt module as MetaObjectWrappers and the enums
117 118 //! and constructors (added by addConstructors) will be available.
118 119 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
119 120 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
120 121 void registerClass(const QMetaObject* metaobject);
121 122
122 123 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
123 124 //! and it will register the classes when it first sees a pointer to such a derived class
124 125 void registerQObjectClassNames(const QStringList& names);
125 126
126 127 //! this will register CPP classnames as known CPP classes (NOT QObjects) and make their MetaObjectWrapper available in
127 128 //! the PythonQt module. In combination with addConstuctors(), this can be used to create CPP objects from PythonQt
128 129 void registerCPPClassNames(const QStringList& names);
129 130
130 131 //! parses the given file and returns the python code object, this can then be used to call evalCode()
131 132 PythonQtObjectPtr parseFile(const QString& filename);
132 133
133 134 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
134 135 //! If pycode is NULL, a python error is printed.
135 136 QVariant evalCode(PyObject* module, PyObject* pycode);
136 137
137 138 //! evaluates the given script code and returns the result value
138 139 QVariant evalScript(PyObject* module, const QString& script, int start = Py_file_input);
139 140
140 141 //! evaluates the given script code from file
141 142 void evalFile(PyObject* module, const QString& filename);
142 143
143 144 //! creates the new module \c name and evaluates the given file in the context of that module
144 145 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
145 146 //! to a module later on.
146 147 //! The user needs to make sure that the \c name is unique in the python module dictionary.
147 148 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
148 149
149 150 //! creates the new module \c name and evaluates the given script in the context of that module.
150 151 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
151 152 //! to a module later on.
152 153 //! The user needs to make sure that the \c name is unique in the python module dictionary.
153 154 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
154 155
155 156 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
156 157 //! script code
157 158 PythonQtObjectPtr createUniqueModule();
158 159
159 160 //@{ Signal handlers
160 161
161 162 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
162 163 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
163 164
164 165 //! remove a signal handler from the given \c signal of \c obj
165 166 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
166 167
167 168 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
168 169 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
169 170
170 171 //! remove a signal handler from the given \c signal of \c obj
171 172 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
172 173
173 174 //@}
174 175
175 176 //@{ Variable access
176 177
177 178 //! add the given \c object to the \c module as a variable with \c name (it can be removed via clearVariable)
178 179 void addObject(PyObject* module, const QString& name, QObject* object);
179 180
180 181 //! add the given variable to the module
181 182 void addVariable(PyObject* module, const QString& name, const QVariant& v);
182 183
183 184 //! remove the given variable
184 185 void removeVariable(PyObject* module, const QString& name);
185 186
186 187 //! get the variable with the \c name of the \c module, returns an invalid QVariant on error
187 188 QVariant getVariable(PyObject* module, const QString& name);
188 189
189 190 //! read vars etc. in scope of a module, optional looking inside of an object \c objectname
190 191 QStringList introspection(PyObject* module, const QString& objectname, ObjectType type);
191 192
192 193 //! returns the found callable object or NULL
193 194 //! @return new reference
194 195 PythonQtObjectPtr lookupCallable(PyObject* module, const QString& name);
195 196
196 197 //@}
197 198
198 199 //@{ Calling of python callables
199 200
200 201 //! call the given python method, returns the result converted to a QVariant
201 202 QVariant call(PyObject* module, const QString& callable, const QVariantList& args);
202 203
203 204 //@}
204 205
205 206 //@{ Decorations, constructors, wrappers...
206 207
207 208
208 209 //! add an object whose slots will be used as decorator slots for
209 210 //! other QObjects or CPP classes. The slots need to follow the
210 211 //! convention that the first argument is a pointer to the wrapped object.
211 212 //! (ownership is passed to PythonQt)
212 213 /*!
213 214 Example:
214 215
215 216 A slot with the signature
216 217
217 218 \code
218 219 bool doSomething(QWidget* w, int a)
219 220 \endcode
220 221
221 222 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
222 223 that will be called with the concrete instance as first argument.
223 224 So in Python you can now e.g. call
224 225
225 226 \code
226 227 someWidget.doSomething(12)
227 228 \endcode
228 229
229 230 without QWidget really having this method. This allows to easily make normal methods
230 231 of Qt classes callable by forwarding them with such decorator slots
231 232 or to make CPP classes (which are not derived from QObject) callable from Python.
232 233 */
233 234 void addInstanceDecorators(QObject* o);
234 235
235 236 //! add an object whose slots will be used as decorator slots for
236 237 //! class objects (ownership is passed to PythonQt)
237 238 /*!
238 239 The slots need to follow the following convention:
239 240 - SomeClass* new_SomeClass(...)
240 241 - QVariant new_SomeClass(...)
241 242 - void delete_SomeClass(SomeClass*)
242 243 - ... static_SomeClass_someName(...)
243 244
244 245 This will add:
245 246 - a constructor
246 247 - a constructor which generates a QVariant
247 248 - a destructor (only useful for CPP objects)
248 249 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
249 250
250 251 */
251 252 void addClassDecorators(QObject* o);
252 253
253 254 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
254 255 void addDecorators(QObject* o);
255 256
256 257 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
257 258 //! (ownership of wrapper is passed to PythonQt)
258 259 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
259 260
260 261 This will add a wrapper object that is used to make calls to the given classname \c typeName.
261 262 All slots that take a pointer to typeName as the first argument will be callable from Python on
262 263 a variant object that contains such a type.
263 264 */
264 265 void addVariantWrapper(const char* typeName, QObject* wrapper);
265 266
266 267 //! add the given factory to PythonQt (ownership stays with caller)
267 268 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
268 269
269 270 //! add the given constructor handler to PythonQt (ownership stays with caller)
270 271 void addConstructorHandler(PythonQtConstructorHandler* handler);
271 272
272 273 //! get list of constructor handlers
273 274 const QList<PythonQtConstructorHandler*>& constructorHandlers();
274 275
275 276 //@}
276 277
277 278 //@{ Custom importer (to replace internal import implementation of python)
278 279
279 280 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
280 281 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
281 //! It can only be called once, further calls will be ignored silently. (ownership stays with caller)
282 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
283 //! This is not reversible, so even setting setImporter(NULL) afterwards will
284 //! keep the custom PythonQt importer with a QFile default import interface.
285 //! Subsequent python import calls will make use of the passed importInterface
286 //! which forwards all import calls to the given \c importInterface.
287 //! Passing NULL will install a default QFile importer.
288 //! (\c importInterface ownership stays with caller)
282 289 void setImporter(PythonQtImportFileInterface* importInterface);
283 290
291 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
292 //! (without calling setImporter or installDefaultImporter at least once, the default python import
293 //! mechanism is in place)
294 //! the default importer allows to import files from anywhere QFile can read from,
295 //! including the Qt resource system using ":". Keep in mind that you need to extend
296 //! "sys.path" with ":" to be able to import from the Qt resources.
297 void installDefaultImporter() { setImporter(NULL); }
298
284 299 //! set paths that the importer should ignore
285 300 void setImporterIgnorePaths(const QStringList& paths);
286 301
287 302 //! get paths that the importer should ignore
288 303 const QStringList& getImporterIgnorePaths();
289 304
290 305 //@}
291 306
292 307 //! get access to internal data (should not be used on the public API, but is used by some C functions)
293 308 static PythonQtPrivate* priv() { return _self->_p; }
294 309
295 310 //! get access to the file importer (if set)
296 311 static PythonQtImportFileInterface* importInterface();
297 312
298 313 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
299 314 //! The error is currently just output to the python stderr, future version might implement better trace printing
300 315 bool handleError();
301 316
302 317 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
303 318 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
304 319 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
305 320 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
306 321
307 322 //! call the callback if it is set
308 323 static void qObjectNoLongerWrappedCB(QObject* o);
309 324
310 325 signals:
311 326 //! emitted when python outputs something to stdout (and redirection is turned on)
312 327 void pythonStdOut(const QString& str);
313 328 //! emitted when python outputs something to stderr (and redirection is turned on)
314 329 void pythonStdErr(const QString& str);
315 330
316 331 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
317 332 void pythonHelpRequest(const QByteArray& cppClassName);
318 333
319 334
320 335 public:
321 336 //! called by internal help methods
322 337 PyObject* helpCalled(PythonQtClassInfo* info);
323 338
324 339 //! returns the found object or NULL
325 340 //! @return new reference
326 341 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
327 342
328 343 private:
329 344 void initPythonQtModule(bool redirectStdOut);
330 345
331 346 //! callback for stdout redirection, emits pythonStdOut signal
332 347 static void stdOutRedirectCB(const QString& str);
333 348 //! callback for stderr redirection, emits pythonStdErr signal
334 349 static void stdErrRedirectCB(const QString& str);
335 350
336 351 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
337 352 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
338 353
339 354 PythonQt(int flags);
340 355 ~PythonQt();
341 356
342 357 static PythonQt* _self;
343 358 static int _uniqueModuleCount;
344 359
345 360 PythonQtPrivate* _p;
346 361
347 362 };
348 363
349 364 //! internal PythonQt details
350 365 class PythonQtPrivate : public QObject {
351 366
352 367 Q_OBJECT
353 368
354 369 public:
355 370 PythonQtPrivate();
356 371 ~PythonQtPrivate();
357 372
358 373 //! returns if the id is the id for PythonQtObjectPtr
359 374 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
360 375
361 376 //! remove the wrapper ptr again
362 377 void removeWrapperPointer(void* obj);
363 378
364 379 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
365 380 void removeSignalEmitter(QObject* obj);
366 381
367 382 //! wrap the given QObject into a Python object (or return existing wrapper!)
368 383 PyObject* wrapQObject(QObject* obj);
369 384
370 385 //! 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
371 386 PyObject* wrapPtr(void* ptr, const QByteArray& name);
372 387
373 388 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
374 389 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
375 390 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
376 391 void registerClass(const QMetaObject* metaobject);
377 392
378 393 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
379 394 //! and it will register the classes when it first sees a pointer to such a derived class
380 395 void registerQObjectClassNames(const QStringList& names);
381 396
382 397 //! add a decorator object
383 398 void addDecorators(QObject* o, bool instanceDeco, bool classDeco);
384 399
385 400 //! add a wrapper object for the given qvariant, also does an addConstructors() to add constructors for variants
386 401 void addVariantWrapper(const char* typeName, QObject* wrapper);
387 402
388 403 //! get list of all slots that are available as decorator slots
389 404 QList<PythonQtSlotInfo*> getDecoratorSlots(const QByteArray& className);
390 405
391 406 //! check if the enum is either part of the \c meta class or contains a scope and is
392 407 //! an enum of another known metaobject (and as last resort, of the Qt namespace)
393 408 bool isEnumType(const QMetaObject* meta, const QByteArray& name);
394 409
395 410 //! helper method that creates a PythonQtMetaObjectWrapper object
396 411 PythonQtMetaObjectWrapper* createNewPythonQtMetaObjectWrapper(PythonQtClassInfo* info);
397 412
398 413 //! helper method that creates a PythonQtWrapper object and registers it in the object map
399 414 PythonQtWrapper* createNewPythonQtWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
400 415
401 416 //! helper method that creates a PythonQtVariantWrapper object
402 417 PythonQtVariantWrapper* createNewPythonQtVariantWrapper(const QVariant& variant);
403 418
404 419 //! get the class info for a meta object (if available)
405 420 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownQtClasses.value(meta->className()); }
406 421
407 422 //! get the constructor slot for the given classname
408 423 PythonQtSlotInfo* getConstructorSlot(const QByteArray& className) { return _constructorSlots.value(className); }
409 424
410 425 //! get the destructor slot for the given classname
411 426 PythonQtSlotInfo* getDestructorSlot(const QByteArray& className) { return _destructorSlots.value(className); }
412 427
413 428 //! creates the new module from the given pycode
414 429 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
415 430
416 431 private:
417 432
418 433 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
419 434 PythonQtWrapper* findWrapperAndRemoveUnused(void* obj);
420 435
421 436 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
422 437 QHash<void* , PythonQtWrapper *> _wrappedObjects;
423 438
424 439 //! stores the meta info of known Qt classes
425 440 QHash<QByteArray, PythonQtClassInfo *> _knownQtClasses;
426 441
427 442 //! stores the meta info of known Qt classes
428 443 QHash<QByteArray, PythonQtClassInfo *> _knownQtWrapperClasses;
429 444
430 445 //! stores the meta info of known Qt C++ wrapper classes
431 446 QMultiHash<QByteArray, PythonQtSlotInfo *> _knownQtDecoratorSlots;
432 447
433 448 //! names of qobject derived classes that can be casted to qobject savely
434 449 QHash<QByteArray, bool> _knownQObjectClassNames;
435 450
436 451 //! stores signal receivers for QObjects
437 452 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
438 453
439 454 //! the PythonQt python module
440 455 PythonQtObjectPtr _pythonQtModule;
441 456
442 457 //! the importer interface (if set)
443 458 PythonQtImportFileInterface* _importInterface;
444 459
460 //! the default importer
461 PythonQtQFileImporter* _defaultImporter;
462
445 463 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
446 464 PythonQtQObjectWrappedCB* _wrappedCB;
447 465
448 466 QStringList _importIgnorePaths;
449 467
450 468 //! the cpp object wrapper factories
451 469 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
452 470
453 471 //! the cpp object wrapper factories
454 472 QList<PythonQtConstructorHandler*> _constructorHandlers;
455 473
456 474 QHash<QByteArray , PythonQtSlotInfo *> _constructorSlots;
457 475 QHash<QByteArray , PythonQtSlotInfo *> _destructorSlots;
458 476
459 477 QHash<int , QPair<PythonQtClassInfo*, QObject*> > _knownVariantWrappers;
460 478
461 479 PythonQtClassInfo* _qtNamespace;
462 480
463 481 int _initFlags;
464 482 int _PythonQtObjectPtr_metaId;
465 483
466 484 friend class PythonQt;
467 485 };
468 486
469 487 #endif
@@ -1,1017 +1,1017
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 PythonQtConversion.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 "PythonQtConversion.h"
43 43 #include "PythonQtVariants.h"
44 44 #include "PythonQtVariantWrapper.h"
45 45 #include <QDateTime>
46 46 #include <QTime>
47 47 #include <QDate>
48 48
49 49 PythonQtValueStorage<qint64, 128> PythonQtConv::global_valueStorage;
50 50 PythonQtValueStorage<void*, 128> PythonQtConv::global_ptrStorage;
51 51 PythonQtValueStorage<QVariant, 32> PythonQtConv::global_variantStorage;
52 52
53 53
54 54 PyObject* PythonQtConv::GetPyBool(bool val)
55 55 {
56 56 PyObject* r = val?Py_True:Py_False;
57 57 Py_INCREF(r);
58 58 return r;
59 59 }
60 60
61 61 PyObject* PythonQtConv::ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, void* data) {
62 62 if (info.typeId == QMetaType::Void) {
63 63 Py_INCREF(Py_None);
64 64 return Py_None;
65 65 } else {
66 66 if (info.isPointer && (info.typeId == PythonQtMethodInfo::Unknown)) {
67 67 // try to convert the pointer to a Python Object
68 68 PyObject* pyObj = PythonQt::priv()->wrapPtr(*((void**)data), info.name);
69 69 if (pyObj) {
70 70 return pyObj;
71 71 } else {
72 72 std::cerr << "unknown pointer type " << info.name.data() << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
73 73 Py_INCREF(Py_None);
74 74 return Py_None;
75 75 }
76 76 } else if (info.isPointer && (info.typeId == QMetaType::Char)) {
77 77 // a char ptr will probably be a null terminated string, so we support that:
78 78 return PyString_FromString(*((char**)data));
79 79 } else {
80 80 if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
81 81 if (info.name.startsWith("QList<")) {
82 82 QByteArray innerType = info.name.mid(6,info.name.length()-7);
83 83 if (innerType.endsWith("*")) {
84 84 innerType.truncate(innerType.length()-1);
85 85 return ConvertQListWithPointersToPython((QList<void*>*)data, innerType);
86 86 }
87 87 }
88 88 }
89 89 // handle values that are not yet handled and not pointers
90 90 return ConvertQtValueToPythonInternal(info.typeId, data);
91 91 }
92 92 }
93 93 }
94 94
95 95 PyObject* PythonQtConv::ConvertQtValueToPythonInternal(int type, void* data) {
96 96 switch (type) {
97 97 case QMetaType::Void:
98 98 Py_INCREF(Py_None);
99 99 return Py_None;
100 100 case QMetaType::Char:
101 101 return PyInt_FromLong(*((char*)data));
102 102 case QMetaType::UChar:
103 103 return PyInt_FromLong(*((unsigned char*)data));
104 104 case QMetaType::Short:
105 105 return PyInt_FromLong(*((short*)data));
106 106 case QMetaType::UShort:
107 107 return PyInt_FromLong(*((unsigned short*)data));
108 108 case QMetaType::Long:
109 109 return PyInt_FromLong(*((long*)data));
110 110 case QMetaType::ULong:
111 111 // does not fit into simple int of python
112 112 return PyLong_FromUnsignedLong(*((unsigned long*)data));
113 113 case QMetaType::Bool:
114 114 return PythonQtConv::GetPyBool(*((bool*)data));
115 115 case QMetaType::Int:
116 116 return PyInt_FromLong(*((int*)data));
117 117 case QMetaType::UInt:
118 118 return PyInt_FromLong(*((unsigned int*)data));
119 119 case QMetaType::QChar:
120 120 return PyInt_FromLong(*((short*)data));
121 121 case QMetaType::Float:
122 122 return PyFloat_FromDouble(*((float*)data));
123 123 case QMetaType::Double:
124 124 return PyFloat_FromDouble(*((double*)data));
125 125 case QMetaType::LongLong:
126 126 return PyLong_FromLongLong(*((qint64*)data));
127 127 case QMetaType::ULongLong:
128 128 return PyLong_FromUnsignedLongLong(*((quint64*)data));
129 129 case QMetaType::QByteArray: {
130 130 QByteArray* v = (QByteArray*) data;
131 131 return PyString_FromStringAndSize(*v, v->size());
132 132 }
133 133 case QMetaType::QVariantMap:
134 134 return PythonQtConv::QVariantMapToPyObject(*((QVariantMap*)data));
135 135 case QMetaType::QVariantList:
136 136 return PythonQtConv::QVariantListToPyObject(*((QVariantList*)data));
137 137 case QMetaType::QString:
138 138 return PythonQtConv::QStringToPyObject(*((QString*)data));
139 139 case QMetaType::QStringList:
140 140 return PythonQtConv::QStringListToPyObject(*((QStringList*)data));
141 141
142 142 case PythonQtMethodInfo::Variant:
143 143 return PythonQtConv::QVariantToPyObject(*((QVariant*)data));
144 144 case QMetaType::QObjectStar:
145 145 case QMetaType::QWidgetStar:
146 146 return PythonQt::priv()->wrapQObject(*((QObject**)data));
147 147
148 148 // the following cases could be handled by the default case, but it is faster to do it with
149 149 // direct casts:
150 150 case QMetaType::QDate:
151 151 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QDate*)data)));
152 152 case QMetaType::QTime:
153 153 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QTime*)data)));
154 154 case QMetaType::QDateTime:
155 155 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QDateTime*)data)));
156 156 case QMetaType::QRect:
157 157 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QRect*)data)));
158 158 case QMetaType::QSize:
159 159 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QSize*)data)));
160 160 case QMetaType::QPoint:
161 161 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QPoint*)data)));
162 162 case QMetaType::QColor:
163 163 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QColor*)data)));
164 164 case QMetaType::QPixmap:
165 165 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QPixmap*)data)));
166 166 case QMetaType::QUrl:
167 167 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QUrl*)data)));
168 168 case QMetaType::QRectF:
169 169 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QRectF*)data)));
170 170 case QMetaType::QSizeF:
171 171 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QSizeF*)data)));
172 172 case QMetaType::QLine:
173 173 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QLine*)data)));
174 174 case QMetaType::QLineF:
175 175 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QLineF*)data)));
176 176 case QMetaType::QPointF:
177 177 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QPointF*)data)));
178 178 case QMetaType::QRegExp:
179 179 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QRegExp*)data)));
180 180 case QMetaType::QBitArray:
181 181 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QBitArray*)data)));
182 182 case QMetaType::QLocale:
183 183 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QLocale*)data)));
184 184 case QMetaType::QFont:
185 185 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QFont*)data)));
186 186 case QMetaType::QBrush:
187 187 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QBrush*)data)));
188 188 case QMetaType::QPalette:
189 189 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QPalette*)data)));
190 190 case QMetaType::QIcon:
191 191 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(qVariantFromValue(*((QIcon*)data)));
192 192 case QMetaType::QImage:
193 193 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QImage*)data)));
194 194 case QMetaType::QPolygon:
195 195 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QPolygon*)data)));
196 196 case QMetaType::QRegion:
197 197 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QRegion*)data)));
198 198 case QMetaType::QBitmap:
199 199 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(qVariantFromValue(*((QBitmap*)data)));
200 200 case QMetaType::QCursor:
201 201 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QCursor*)data)));
202 202 case QMetaType::QSizePolicy:
203 203 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(QVariant(*((QSizePolicy*)data)));
204 204 case QMetaType::QKeySequence:
205 205 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(qVariantFromValue(*((QKeySequence*)data)));
206 206 case QMetaType::QPen:
207 207 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(qVariantFromValue(*((QPen*)data)));
208 208 case QMetaType::QTextLength:
209 209 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(qVariantFromValue(*((QTextLength*)data)));
210 210 case QMetaType::QTextFormat:
211 211 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(qVariantFromValue(*((QTextFormat*)data)));
212 212 case QMetaType::QMatrix:
213 213 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(qVariantFromValue(*((QMatrix*)data)));
214 214 default:
215 215 if (PythonQt::priv()->isPythonQtObjectPtrMetaId(type)) {
216 216 PyObject* o = ((PythonQtObjectPtr*)data)->object();
217 217 Py_INCREF(o);
218 218 return o;
219 219 } else {
220 220 if (type != PythonQtMethodInfo::Unknown) {
221 221 QVariant v(type, data);
222 222 if (v.isValid()) {
223 223 return (PyObject*)PythonQt::priv()->createNewPythonQtVariantWrapper(v);
224 224 }
225 225 }
226 226 std::cerr << "Unknown type that can not be converted to Python: " << type << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
227 227 }
228 228 }
229 229 Py_INCREF(Py_None);
230 230 return Py_None;
231 231 }
232 232
233 233 void* PythonQtConv::CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info) {
234 234 void* ptr = NULL;
235 235 if (info.isPointer) {
236 236 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
237 237 } else {
238 238 switch (info.typeId) {
239 239 case QMetaType::Char:
240 240 case QMetaType::UChar:
241 241 case QMetaType::Short:
242 242 case QMetaType::UShort:
243 243 case QMetaType::Long:
244 244 case QMetaType::ULong:
245 245 case QMetaType::Bool:
246 246 case QMetaType::Int:
247 247 case QMetaType::UInt:
248 248 case QMetaType::QChar:
249 249 case QMetaType::Float:
250 250 case QMetaType::Double:
251 251 PythonQtValueStorage_ADD_VALUE(global_valueStorage, long, 0, ptr);
252 252 break;
253 253 case PythonQtMethodInfo::Variant:
254 254 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, 0, ptr);
255 255 // return the ptr to the variant
256 256 break;
257 257 default:
258 258 if (info.typeId == PythonQtMethodInfo::Unknown) {
259 259 // check if we have a QList of pointers, which we can circumvent with a QList<void*>
260 260 if (info.name.startsWith("QList<")) {
261 261 QByteArray innerType = info.name.mid(6,info.name.length()-7);
262 262 if (innerType.endsWith("*")) {
263 263 static int id = QMetaType::type("QList<void*>");
264 264 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr);
265 265 // return the constData pointer that will be filled with the result value later on
266 266 ptr = (void*)((QVariant*)ptr)->constData();
267 267 }
268 268 }
269 269 }
270 270
271 271 if (!ptr) {
272 272 // everything else is stored in a QVariant...
273 273 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
274 274 // return the constData pointer that will be filled with the result value later on
275 275 ptr = (void*)((QVariant*)ptr)->constData();
276 276 }
277 277 }
278 278 }
279 279 return ptr;
280 280 }
281 281
282 282 void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, const QMetaObject* meta)
283 283 {
284 284 bool ok;
285 285 void* ptr = NULL;
286 286 if (info.isPointer) {
287 287 if (obj->ob_type == &PythonQtWrapper_Type) {
288 288 PythonQtWrapper* wrap = (PythonQtWrapper*)obj;
289 289 // c++ wrapper, check if the class names of the c++ objects match
290 290 if (wrap->_info->isCPPWrapper()) {
291 291 //TODO: we could support inheritance on cpp wrappers as well
292 292 if (wrap->_info->wrappedCPPClassName() == info.name) {
293 293 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, wrap->_wrappedPtr, ptr);
294 294 } else {
295 295 // not matching
296 296 }
297 297 } else {
298 298 if (wrap->_info->inherits(info.name)) {
299 299 QObject* myObject = wrap->_obj;
300 300 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, myObject, ptr);
301 301 } else {
302 302 // not matching
303 303 }
304 304 }
305 305 } else
306 306 if (info.typeId == QMetaType::Char || info.typeId == QMetaType::UChar) {
307 307 QString str = PyObjGetString(obj, strict, ok);
308 308 if (ok) {
309 309 void* ptr2 = NULL;
310 310 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant(str.toUtf8()), ptr2);
311 311 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr);
312 312 }
313 313 } else if (info.name == "PyObject") {
314 314 // handle low level PyObject directly
315 315 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, obj, ptr);
316 316 } else if (obj == Py_None) {
317 317 // None is treated as a NULL ptr
318 318 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
319 319 } else {
320 320 // if we are not strict, we try if we are passed a 0 integer
321 321 if (!strict) {
322 322 bool ok;
323 323 int value = PyObjGetInt(obj, true, ok);
324 324 if (ok && value==0) {
325 325 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
326 326 }
327 327 }
328 328 // EXTRA: we could support pointers to other simple types, but this would not make sense in most situations
329 329 }
330 330
331 331 } else {
332 332 // not a pointer
333 333 switch (info.typeId) {
334 334 case QMetaType::Char:
335 335 {
336 336 int val = PyObjGetInt(obj, strict, ok);
337 337 if (ok) {
338 338 PythonQtValueStorage_ADD_VALUE(global_valueStorage, char, val, ptr);
339 339 }
340 340 }
341 341 break;
342 342 case QMetaType::UChar:
343 343 {
344 344 int val = PyObjGetInt(obj, strict, ok);
345 345 if (ok) {
346 346 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned char, val, ptr);
347 347 }
348 348 }
349 349 break;
350 350 case QMetaType::Short:
351 351 {
352 352 int val = PyObjGetInt(obj, strict, ok);
353 353 if (ok) {
354 354 PythonQtValueStorage_ADD_VALUE(global_valueStorage, short, val, ptr);
355 355 }
356 356 }
357 357 break;
358 358 case QMetaType::UShort:
359 359 {
360 360 int val = PyObjGetInt(obj, strict, ok);
361 361 if (ok) {
362 362 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned short, val, ptr);
363 363 }
364 364 }
365 365 break;
366 366 case QMetaType::Long:
367 367 {
368 368 long val = (long)PyObjGetLongLong(obj, strict, ok);
369 369 if (ok) {
370 370 PythonQtValueStorage_ADD_VALUE(global_valueStorage, long, val, ptr);
371 371 }
372 372 }
373 373 break;
374 374 case QMetaType::ULong:
375 375 {
376 376 unsigned long val = (unsigned long)PyObjGetLongLong(obj, strict, ok);
377 377 if (ok) {
378 378 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned long, val, ptr);
379 379 }
380 380 }
381 381 break;
382 382 case QMetaType::Bool:
383 383 {
384 384 bool val = PyObjGetBool(obj, strict, ok);
385 385 if (ok) {
386 386 PythonQtValueStorage_ADD_VALUE(global_valueStorage, bool, val, ptr);
387 387 }
388 388 }
389 389 break;
390 390 case QMetaType::Int:
391 391 {
392 392 int val = PyObjGetInt(obj, strict, ok);
393 393 if (ok) {
394 394 PythonQtValueStorage_ADD_VALUE(global_valueStorage, int, val, ptr);
395 395 }
396 396 }
397 397 break;
398 398 case QMetaType::UInt:
399 399 {
400 400 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
401 401 if (ok) {
402 402 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned int, val, ptr);
403 403 }
404 404 }
405 405 break;
406 406 case QMetaType::QChar:
407 407 {
408 408 int val = PyObjGetInt(obj, strict, ok);
409 409 if (ok) {
410 410 PythonQtValueStorage_ADD_VALUE(global_valueStorage, short, val, ptr);
411 411 }
412 412 }
413 413 break;
414 414 case QMetaType::Float:
415 415 {
416 416 float val = (float)PyObjGetDouble(obj, strict, ok);
417 417 if (ok) {
418 418 PythonQtValueStorage_ADD_VALUE(global_valueStorage, float, val, ptr);
419 419 }
420 420 }
421 421 break;
422 422 case QMetaType::Double:
423 423 {
424 424 double val = (double)PyObjGetDouble(obj, strict, ok);
425 425 if (ok) {
426 426 PythonQtValueStorage_ADD_VALUE(global_valueStorage, double, val, ptr);
427 427 }
428 428 }
429 429 break;
430 430 case QMetaType::LongLong:
431 431 {
432 432 qint64 val = PyObjGetLongLong(obj, strict, ok);
433 433 if (ok) {
434 434 PythonQtValueStorage_ADD_VALUE(global_valueStorage, qint64, val, ptr);
435 435 }
436 436 }
437 437 break;
438 438 case QMetaType::ULongLong:
439 439 {
440 440 quint64 val = PyObjGetULongLong(obj, strict, ok);
441 441 if (ok) {
442 442 PythonQtValueStorage_ADD_VALUE(global_valueStorage, quint64, val, ptr);
443 443 }
444 444 }
445 445 break;
446 446 case QMetaType::QByteArray:
447 447 {
448 448 QByteArray bytes = PyObjGetBytes(obj, strict, ok);
449 449 if (ok) {
450 450 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant(bytes), ptr);
451 451 ptr = (void*)((QVariant*)ptr)->constData();
452 452 }
453 453 }
454 454 break;
455 455 case QMetaType::QString:
456 456 {
457 457 QString str = PyObjGetString(obj, strict, ok);
458 458 if (ok) {
459 459 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant(str), ptr);
460 460 ptr = (void*)((QVariant*)ptr)->constData();
461 461 }
462 462 }
463 463 break;
464 464 case QMetaType::QStringList:
465 465 {
466 466 QStringList l = PyObjToStringList(obj, strict, ok);
467 467 if (ok) {
468 468 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant(l), ptr);
469 469 ptr = (void*)((QVariant*)ptr)->constData();
470 470 }
471 471 }
472 472 break;
473 473
474 474 case PythonQtMethodInfo::Variant:
475 475 {
476 476 QVariant v = PyObjToQVariant(obj);
477 477 if (v.isValid()) {
478 478 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, v, ptr);
479 479 }
480 480 }
481 481 break;
482 482 default:
483 483 {
484 484 if (info.typeId == PythonQtMethodInfo::Unknown) {
485 485 // check for enum case
486 486 if (PythonQt::priv()->isEnumType(meta, info.name)) {
487 487 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
488 488 if (ok) {
489 489 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned int, val, ptr);
490 490 return ptr;
491 491 } else {
492 492 return NULL;
493 493 }
494 494 }
495 495 }
496 496 if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
497 497 // check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant
498 498 if (info.name.startsWith("QList<")) {
499 499 QByteArray innerType = info.name.mid(6,info.name.length()-7);
500 500 if (innerType.endsWith("*")) {
501 501 innerType.truncate(innerType.length()-1);
502 502 static int id = QMetaType::type("QList<void*>");
503 503 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr);
504 504 ptr = (void*)((QVariant*)ptr)->constData();
505 505 ok = ConvertPythonListToQListOfType(obj, (QList<void*>*)ptr, innerType, strict);
506 506 if (ok) {
507 507 return ptr;
508 508 } else {
509 509 return NULL;
510 510 }
511 511 }
512 512 }
513 513 }
514 514
515 515 // for all other types, we use the same qvariant conversion and pass out the constData of the variant:
516 516 QVariant v = PyObjToQVariant(obj, info.typeId);
517 517 if (v.isValid()) {
518 518 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, v, ptr);
519 519 ptr = (void*)((QVariant*)ptr)->constData();
520 520 }
521 521 }
522 522 }
523 523 }
524 524 return ptr;
525 525 }
526 526
527 527
528 528 QStringList PythonQtConv::PyObjToStringList(PyObject* val, bool strict, bool& ok) {
529 529 QStringList v;
530 530 ok = false;
531 531 // if we are strict, we do not want to convert a string to a stringlist
532 532 // (strings in python are detected to be sequences)
533 533 if (strict &&
534 534 (val->ob_type == &PyString_Type ||
535 535 PyUnicode_Check(val))) {
536 536 ok = false;
537 537 return v;
538 538 }
539 539 if (PySequence_Check(val)) {
540 540 int count = PySequence_Size(val);
541 541 for (int i = 0;i<count;i++) {
542 542 PyObject* value = PySequence_GetItem(val,i);
543 543 v.append(PyObjGetString(value,false,ok));
544 544 }
545 545 ok = true;
546 546 }
547 547 return v;
548 548 }
549 549
550 550 QString PythonQtConv::PyObjGetRepresentation(PyObject* val)
551 551 {
552 552 QString r;
553 553 PyObject* str = PyObject_Repr(val);
554 554 if (str) {
555 555 r = QString(PyString_AS_STRING(str));
556 556 Py_DECREF(str);
557 557 }
558 558 return r;
559 559 }
560 560
561 561 QString PythonQtConv::PyObjGetString(PyObject* val, bool strict, bool& ok) {
562 562 QString r;
563 563 ok = true;
564 564 if (val->ob_type == &PyString_Type) {
565 565 r = QString(PyString_AS_STRING(val));
566 566 } else if (PyUnicode_Check(val)) {
567 567 #ifdef WIN32
568 568 r = QString::fromUtf16(PyUnicode_AS_UNICODE(val));
569 569 #else
570 570 PyObject *ptmp = PyUnicode_AsUTF8String(val);
571 571 if(ptmp) {
572 572 r = QString::fromUtf8(PyString_AS_STRING(ptmp));
573 573 Py_DECREF(ptmp);
574 574 }
575 575 #endif
576 576 } else if (!strict) {
577 577 // EXTRA: could also use _Unicode, but why should we?
578 578 PyObject* str = PyObject_Str(val);
579 579 if (str) {
580 580 r = QString(PyString_AS_STRING(str));
581 581 Py_DECREF(str);
582 582 } else {
583 583 ok = false;
584 584 }
585 585 } else {
586 586 ok = false;
587 587 }
588 588 return r;
589 589 }
590 590
591 QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool strict, bool& ok) {
591 QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) {
592 592 QByteArray r;
593 593 ok = true;
594 594 if (val->ob_type == &PyString_Type) {
595 595 long size = PyString_GET_SIZE(val);
596 596 r = QByteArray(PyString_AS_STRING(val), size);
597 597 } else {
598 598 ok = false;
599 599 }
600 600 return r;
601 601 }
602 602
603 603 bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) {
604 604 bool d = false;
605 605 ok = false;
606 606 if (val == Py_False) {
607 607 d = false;
608 608 ok = true;
609 609 } else if (val == Py_True) {
610 610 d = true;
611 611 ok = true;
612 612 } else if (!strict) {
613 613 d = PyObjGetInt(val, false, ok)!=0;
614 614 ok = true;
615 615 }
616 616 return d;
617 617 }
618 618
619 619 int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) {
620 620 int d = 0;
621 621 ok = true;
622 622 if (val->ob_type == &PyInt_Type) {
623 623 d = PyInt_AS_LONG(val);
624 624 } else if (!strict) {
625 625 if (val->ob_type == &PyFloat_Type) {
626 626 d = floor(PyFloat_AS_DOUBLE(val));
627 627 } else if (val->ob_type == &PyLong_Type) {
628 628 // handle error on overflow!
629 629 d = PyLong_AsLong(val);
630 630 } else if (val == Py_False) {
631 631 d = 0;
632 632 } else if (val == Py_True) {
633 633 d = 1;
634 634 } else {
635 635 ok = false;
636 636 }
637 637 } else {
638 638 ok = false;
639 639 }
640 640 return d;
641 641 }
642 642
643 643 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
644 644 qint64 d = 0;
645 645 ok = true;
646 646 if (val->ob_type == &PyInt_Type) {
647 647 d = PyInt_AS_LONG(val);
648 648 } else if (val->ob_type == &PyLong_Type) {
649 649 d = PyLong_AsLongLong(val);
650 650 } else if (!strict) {
651 651 if (val->ob_type == &PyFloat_Type) {
652 652 d = floor(PyFloat_AS_DOUBLE(val));
653 653 } else if (val == Py_False) {
654 654 d = 0;
655 655 } else if (val == Py_True) {
656 656 d = 1;
657 657 } else {
658 658 ok = false;
659 659 }
660 660 } else {
661 661 ok = false;
662 662 }
663 663 return d;
664 664 }
665 665
666 666 quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) {
667 667 quint64 d = 0;
668 668 ok = true;
669 669 if (val->ob_type == &PyInt_Type) {
670 670 d = PyInt_AS_LONG(val);
671 671 } else if (val->ob_type == &PyLong_Type) {
672 672 d = PyLong_AsLongLong(val);
673 673 } else if (!strict) {
674 674 if (val->ob_type == &PyFloat_Type) {
675 675 d = floor(PyFloat_AS_DOUBLE(val));
676 676 } else if (val == Py_False) {
677 677 d = 0;
678 678 } else if (val == Py_True) {
679 679 d = 1;
680 680 } else {
681 681 ok = false;
682 682 }
683 683 } else {
684 684 ok = false;
685 685 }
686 686 return d;
687 687 }
688 688
689 689 double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) {
690 690 double d = 0;
691 691 ok = true;
692 692 if (val->ob_type == &PyFloat_Type) {
693 693 d = PyFloat_AS_DOUBLE(val);
694 694 } else if (!strict) {
695 695 if (val->ob_type == &PyInt_Type) {
696 696 d = PyInt_AS_LONG(val);
697 697 } else if (val->ob_type == &PyLong_Type) {
698 698 d = PyLong_AsLong(val);
699 699 } else if (val == Py_False) {
700 700 d = 0;
701 701 } else if (val == Py_True) {
702 702 d = 1;
703 703 } else {
704 704 ok = false;
705 705 }
706 706 } else {
707 707 ok = false;
708 708 }
709 709 return d;
710 710 }
711 711
712 712 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
713 713 {
714 714 QVariant v;
715 715 bool ok = true;
716 716
717 717 if (type==-1) {
718 718 // no special type requested
719 719 if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) {
720 720 type = QVariant::String;
721 721 } else if (val->ob_type==&PyInt_Type) {
722 722 type = QVariant::Int;
723 723 } else if (val->ob_type==&PyLong_Type) {
724 724 type = QVariant::LongLong;
725 725 } else if (val->ob_type==&PyFloat_Type) {
726 726 type = QVariant::Double;
727 727 } else if (val == Py_False || val == Py_True) {
728 728 type = QVariant::Bool;
729 729 } else if (val->ob_type == &PythonQtWrapper_Type) {
730 730 PythonQtWrapper* wrap = (PythonQtWrapper*)val;
731 731 // c++ wrapper, check if the class names of the c++ objects match
732 732 if (wrap->_info->isCPPWrapper()) {
733 733 // is this worth anything? we loose the knowledge of the cpp object type
734 734 v = qVariantFromValue(wrap->_wrappedPtr);
735 735 } else {
736 736 QObject* myObject = wrap->_obj;
737 737 v = qVariantFromValue(myObject);
738 738 }
739 739 return v;
740 740 } else if (val->ob_type==&PyDict_Type) {
741 741 type = QVariant::Map;
742 742 } else if (val->ob_type==&PyList_Type || val->ob_type==&PyTuple_Type || PySequence_Check(val)) {
743 743 type = QVariant::List;
744 744 } else if (val == Py_None) {
745 745 // none is invalid
746 746 type = QVariant::Invalid;
747 747 } else if (val->ob_type == &PythonQtVariantWrapper_Type) {
748 748 PythonQtVariantWrapper* varWrap = (PythonQtVariantWrapper*)val;
749 749 if (varWrap->_variant->userType() == type) {
750 750 v = *varWrap->_variant;
751 751 return v;
752 752 }
753 753 } else {
754 754 // this used to be:
755 755 // type = QVariant::String;
756 756 // but now we want to transport the Python Objects directly:
757 757 PythonQtObjectPtr o(val);
758 758 v = qVariantFromValue(o);
759 759 return v;
760 760 }
761 761 }
762 762 // special type request:
763 763 switch (type) {
764 764 case QVariant::Invalid:
765 765 return v;
766 766 break;
767 767 case QVariant::Int:
768 768 {
769 769 int d = PyObjGetInt(val, false, ok);
770 770 if (ok) return QVariant(d);
771 771 }
772 772 break;
773 773 case QVariant::UInt:
774 774 {
775 775 int d = PyObjGetInt(val, false,ok);
776 776 if (ok) v = QVariant((unsigned int)d);
777 777 }
778 778 break;
779 779 case QVariant::Bool:
780 780 {
781 781 int d = PyObjGetBool(val,false,ok);
782 782 if (ok) v = QVariant((bool)(d!=0));
783 783 }
784 784 break;
785 785 case QVariant::Double:
786 786 {
787 787 double d = PyObjGetDouble(val,false,ok);
788 788 if (ok) v = QVariant(d);
789 789 break;
790 790 }
791 791 case QMetaType::Float:
792 792 {
793 793 float d = (float) PyObjGetDouble(val,false,ok);
794 794 if (ok) v = qVariantFromValue(d);
795 795 break;
796 796 }
797 797 case QMetaType::Long:
798 798 {
799 799 long d = (long) PyObjGetLongLong(val,false,ok);
800 800 if (ok) v = qVariantFromValue(d);
801 801 break;
802 802 }
803 803 case QMetaType::ULong:
804 804 {
805 805 unsigned long d = (unsigned long) PyObjGetLongLong(val,false,ok);
806 806 if (ok) v = qVariantFromValue(d);
807 807 break;
808 808 }
809 809 case QMetaType::Short:
810 810 {
811 811 short d = (short) PyObjGetInt(val,false,ok);
812 812 if (ok) v = qVariantFromValue(d);
813 813 break;
814 814 }
815 815 case QMetaType::UShort:
816 816 {
817 817 unsigned short d = (unsigned short) PyObjGetInt(val,false,ok);
818 818 if (ok) v = qVariantFromValue(d);
819 819 break;
820 820 }
821 821 case QMetaType::Char:
822 822 {
823 823 char d = (char) PyObjGetInt(val,false,ok);
824 824 if (ok) v = qVariantFromValue(d);
825 825 break;
826 826 }
827 827 case QMetaType::UChar:
828 828 {
829 829 unsigned char d = (unsigned char) PyObjGetInt(val,false,ok);
830 830 if (ok) v = qVariantFromValue(d);
831 831 break;
832 832 }
833 833
834 834 case QVariant::ByteArray:
835 835 case QVariant::String:
836 836 {
837 837 bool ok;
838 838 v = QVariant(PyObjGetString(val, false, ok));
839 839 }
840 840 break;
841 841
842 842 // these are important for MeVisLab
843 843 case QVariant::Map:
844 844 {
845 845 if (PyMapping_Check(val)) {
846 846 QMap<QString,QVariant> map;
847 847 PyObject* items = PyMapping_Items(val);
848 848 if (items) {
849 849 int count = PyList_Size(items);
850 850 PyObject* value;
851 851 PyObject* key;
852 852 PyObject* tuple;
853 853 for (int i = 0;i<count;i++) {
854 854 tuple = PyList_GetItem(items,i);
855 855 key = PyTuple_GetItem(tuple, 0);
856 856 value = PyTuple_GetItem(tuple, 1);
857 857 map.insert(PyObjGetString(key), PyObjToQVariant(value,-1));
858 858 }
859 859 Py_DECREF(items);
860 860 v = map;
861 861 }
862 862 }
863 863 }
864 864 break;
865 865 case QVariant::List:
866 866 if (PySequence_Check(val)) {
867 867 QVariantList list;
868 868 int count = PySequence_Size(val);
869 869 PyObject* value;
870 870 for (int i = 0;i<count;i++) {
871 871 value = PySequence_GetItem(val,i);
872 872 list.append(PyObjToQVariant(value, -1));
873 873 }
874 874 v = list;
875 875 }
876 876 break;
877 877 case QVariant::StringList:
878 878 {
879 879 bool ok;
880 880 QStringList l = PyObjToStringList(val, false, ok);
881 881 if (ok) {
882 882 v = l;
883 883 }
884 884 }
885 885 break;
886 886
887 887 default:
888 888 if (val->ob_type == &PythonQtVariantWrapper_Type) {
889 889 PythonQtVariantWrapper* varWrap = (PythonQtVariantWrapper*)val;
890 890 if (varWrap->_variant->userType() == type) {
891 891 v = *varWrap->_variant;
892 892 }
893 893 } else {
894 894 v = QVariant();
895 895 }
896 896 }
897 897 return v;
898 898 }
899 899
900 900 PyObject* PythonQtConv::QStringToPyObject(const QString& str)
901 901 {
902 902 if (str.isNull()) {
903 903 return PyString_FromString("");
904 904 } else {
905 905 #ifdef WIN32
906 906 // return PyString_FromString(str.toLatin1().data());
907 907 return PyUnicode_FromUnicode(str.utf16(), str.length());
908 908 #else
909 909 return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, NULL, NULL);
910 910 #endif
911 911 }
912 912 }
913 913
914 914 PyObject* PythonQtConv::QStringListToPyObject(const QStringList& list)
915 915 {
916 916 PyObject* result = PyTuple_New(list.count());
917 917 int i = 0;
918 918 QString str;
919 919 foreach (str, list) {
920 920 PyTuple_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(str));
921 921 i++;
922 922 }
923 923 // why is the error state bad after this?
924 924 PyErr_Clear();
925 925 return result;
926 926 }
927 927
928 928 PyObject* PythonQtConv::QStringListToPyList(const QStringList& list)
929 929 {
930 930 PyObject* result = PyList_New(list.count());
931 931 int i = 0;
932 932 for (QStringList::ConstIterator it = list.begin(); it!=list.end(); ++it) {
933 933 PyList_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(*it));
934 934 i++;
935 935 }
936 936 return result;
937 937 }
938 938
939 939 PyObject* PythonQtConv::QVariantToPyObject(const QVariant& v)
940 940 {
941 941 return ConvertQtValueToPythonInternal(v.userType(), (void*)v.constData());
942 942 }
943 943
944 944 PyObject* PythonQtConv::QVariantMapToPyObject(const QVariantMap& m) {
945 945 PyObject* result = PyDict_New();
946 946 QVariantMap::const_iterator t = m.constBegin();
947 947 PyObject* key;
948 948 PyObject* val;
949 949 for (;t!=m.end();t++) {
950 950 key = QStringToPyObject(t.key());
951 951 val = QVariantToPyObject(t.value());
952 952 PyDict_SetItem(result, key, val);
953 953 Py_DECREF(key);
954 954 Py_DECREF(val);
955 955 }
956 956 return result;
957 957 }
958 958
959 959 PyObject* PythonQtConv::QVariantListToPyObject(const QVariantList& l) {
960 960 PyObject* result = PyTuple_New(l.count());
961 961 int i = 0;
962 962 QVariant v;
963 963 foreach (v, l) {
964 964 PyTuple_SET_ITEM(result, i, PythonQtConv::QVariantToPyObject(v));
965 965 i++;
966 966 }
967 967 // why is the error state bad after this?
968 968 PyErr_Clear();
969 969 return result;
970 970 }
971 971
972 972 PyObject* PythonQtConv::ConvertQListWithPointersToPython(QList<void*>* list, const QByteArray& type)
973 973 {
974 974 PyObject* result = PyTuple_New(list->count());
975 975 int i = 0;
976 976 foreach (void* value, *list) {
977 977 PyTuple_SET_ITEM(result, i, PythonQt::priv()->wrapPtr(value, type));
978 978 i++;
979 979 }
980 980 return result;
981 981 }
982 982
983 bool PythonQtConv::ConvertPythonListToQListOfType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool strict)
983 bool PythonQtConv::ConvertPythonListToQListOfType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool /*strict*/)
984 984 {
985 985 bool result = false;
986 986 if (PySequence_Check(obj)) {
987 987 result = true;
988 988 int count = PySequence_Size(obj);
989 989 PyObject* value;
990 990 for (int i = 0;i<count;i++) {
991 991 value = PySequence_GetItem(obj,i);
992 992 if (value->ob_type == &PythonQtWrapper_Type) {
993 993 PythonQtWrapper* wrap = (PythonQtWrapper*)value;
994 994 // c++ wrapper, check if the class names of the c++ objects match
995 995 if (wrap->_info->isCPPWrapper()) {
996 996 //TODO: we could support inheritance on cpp wrappers as well
997 997 if (wrap->_info->wrappedCPPClassName() == type) {
998 998 list->append(wrap->_wrappedPtr);
999 999 } else {
1000 1000 result = false;
1001 1001 break;
1002 1002 }
1003 1003 } else {
1004 1004 if (wrap->_info->inherits(type)) {
1005 1005 QObject* myObject = wrap->_obj;
1006 1006 list->append((void*)myObject);
1007 1007 } else {
1008 1008 result = false;
1009 1009 break;
1010 1010 }
1011 1011 }
1012 1012 }
1013 1013 }
1014 1014 }
1015 1015 return result;
1016 1016 }
1017 1017
@@ -1,466 +1,462
1 1 #ifndef _PYTHONQTDOC_H
2 2 #define _PYTHONQTDOC_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 PythonQtDoc.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 /*!
46 46 \if USE_GLOBAL_DOXYGEN_DOC
47 47 \page PythonQtPage PythonQt Overview
48 48 \else
49 49 \mainpage PythonQt Overview
50 50 \endif
51 51
52 52 \section Introduction
53 53
54 \b PythonQt is a dynamic Python (http://www.python.org) binding for Qt (http://www.trolltech.com).
54 \b PythonQt is a dynamic Python (http://www.python.org) binding for Qt (http://www.qtsoftware.com).
55 55 It offers an easy way to embed the Python scripting language into
56 56 your Qt applications. It makes heavy use of the QMetaObject system and thus requires Qt4.x.
57 57
58 58 In contrast to <a href="http://www.riverbankcomputing.co.uk/pyqt/">PyQt</a> , PythonQt is \b not a complete
59 59 Python wrapper around the complete Qt functionality. So if you are looking for a way to
60 60 write complete applications in Python using the Qt GUI, you should use PyQt.
61 61
62 62 If you are looking for a simple way to embed Python objects into your C++/Qt Application
63 63 and to script parts of your application via Python, PythonQt is the way to go!
64 64
65 65 PythonQt is a stable library that was developed to make the
66 66 Image Processing and Visualization platform MeVisLab (http://www.mevislab.de)
67 67 scriptable from Python.
68 68
69 69 \section Licensing
70 70
71 71 PythonQt is distributed under the LGPL license.
72 72
73 73 \section Download
74 74
75 75 PythonQt is hosted on SourceForge at http://sourceforge.net/projects/pythonqt , you can access it via SVN
76 76 or download a tarball.
77 77
78 78 \section Features
79 79
80 80 - Easy wrapping of Python objects from C++ with smart, reference-counting PythonQtObjectPtr.
81 81 - Convenient conversions to/from QVariant for PythonQtObjectPtr.
82 82 - Access all \b slots, \b properties, children and registered enums of any QObject derived class from Python
83 83 - Connecting Qt Signals to Python functions (both from within Python and from C++)
84 84 - Wrapping of C++ objects (which are not derived from QObject) via PythonQtCppWrapperFactory
85 85 - Extending C++ and QObject derived classes with additional slots, static methods and constructors (see Decorators)
86 86 - StdOut/Err redirection to Qt signals instead of cout
87 87 - Interface for creating your own \c import replacement, so that Python scripts can be e.g. signed/verified before they are executed (PythonQtImportFileInterface)
88 88 - Mapping of plain-old-datatypes and ALL QVariant types to and from Python
89 89 - Support for wrapping of user QVariant types which are registerd via QMetaType
90 90 - Support for Qt namespace (with all enumerators)
91 91 - All PythonQt wrapped objects support the dir() statement, so that you can see easily which attributes a QObject, CPP object or QVariant has
92 92 - No preprocessing/wrapping tool needs to be started, PythonQt can script any QObject without prior knowledge about it (except for the MetaObject information from the \b moc)
93 93
94 94 \section Non-Features
95 95
96 96 Features that PythonQt does NOT support (and will not support):
97 97
98 98 - you can not derive from QObjects inside of Python, this would require wrapper generation like PyQt does
99 99 - you can only script QObject derived classes, for normal C++ classes you need to create a PythonQtCppWrapperFactory and adequate wrapper classes or add decorator slots
100 100 - you can not access normal member functions of QObjects, only slots and properties, because the \b moc does not store normal member functions in the MetaObject system
101 101
102 102 \section Interface
103 103
104 104 The main interface to PythonQt is the PythonQt singleton.
105 105 PythonQt needs to be initialized via PythonQt::init() once.
106 106 Afterwards you communicate with the singleton via PythonQt::self().
107 107 PythonQt offers a default binding for the complete QWidget set, which
108 108 needs to be enabled via PythonQtGui::init().
109 109
110 110
111 111 \section Datatype Datatype Mapping
112 112
113 113 The following table shows the mapping between Python and Qt objects:
114 114 <table>
115 115 <tr><th>Qt/C++</th><th>Python</th></tr>
116 116 <tr><td>bool</td><td>bool</td></tr>
117 117 <tr><td>double</td><td>float</td></tr>
118 118 <tr><td>float</td><td>float</td></tr>
119 119 <tr><td>char/uchar,int/uint,short,ushort,QChar</td><td>integer</td></tr>
120 120 <tr><td>long</td><td>integer</td></tr>
121 121 <tr><td>ulong,longlong,ulonglong</td><td>long</td></tr>
122 122 <tr><td>QString</td><td>unicode string</td></tr>
123 123 <tr><td>QByteArray</td><td>str</td></tr>
124 124 <tr><td>char*</td><td>str</td></tr>
125 125 <tr><td>QStringList</td><td>tuple of unicode strings</td></tr>
126 126 <tr><td>QVariantList</td><td>tuple of objects</td></tr>
127 127 <tr><td>QVariantMap</td><td>dict of objects</td></tr>
128 128 <tr><td>QVariant</td><td>depends on type, see below</td></tr>
129 129 <tr><td>QSize, QRect and all other standard Qt QVariants</td><td>variant wrapper that supports complete API of the respective Qt classes</td></tr>
130 130 <tr><td>OwnRegisteredMetaType</td><td>variant wrapper, optionally with a wrapper provided by addVariantWrapper()</td></tr>
131 131 <tr><td>EnumType</td><td>integer (all enums that are known via the moc and the Qt namespace are supported)</td></tr>
132 132 <tr><td>QObject (and derived classes)</td><td>QObject wrapper</td></tr>
133 133 <tr><td>C++ object</td><td>CPP wrapper, either wrapped via PythonQtCppWrapperFactory or just decorated with decorators</td></tr>
134 134 <tr><td>PyObject</td><td>PyObject</td></tr>
135 135 </table>
136 136
137 137 PyObject is passed as simple pointer, which allows to pass/return any Python Object directly to/from
138 138 a Qt slot.
139 139 QVariants are mapped recursively as given above, e.g. a dictionary can
140 140 contain lists of dictionaries of doubles.
141 141 For example a QVariant of type "String" is mapped to a python unicode string.
142 142 All Qt QVariant types are implemented, PythonQt supports the complete Qt API for these object.
143 143
144 144 \section QObject QObject Wrapping
145 145
146 146 All classes derived from QObject are automatically wrapped with a python wrapper class
147 147 when they become visible to the Python interpreter. This can happen via
148 148 - the PythonQt::addObject() method
149 149 - when a Qt \b slot returns a QObject derived object to python
150 150 - when a Qt \b signal contains a QObject and is connected to a python function
151 151
152 152 It is important that you call PythonQt::registerClass() for any QObject derived class
153 153 that may become visible to Python, except when you add it via PythonQt::addObject().
154 154 This will register the complete parent hierachy of the registered class, so that
155 155 when you register e.g. a QPushButton, QWidget will be registered as well (and all intermediate
156 156 parents).
157 157
158 158 From Python, you can talk to the returned QObjects in a natural way by calling
159 159 their slots and receiving the return values. You can also read/write all
160 160 properties of the objects as if they where normal python properties.
161 161
162 162 In addition to this, the wrapped objects support
163 163 - className() - returns a string that reprents the classname of the QObject
164 164 - help() - shows all properties, slots, enums, decorator slots and constructors of the object, in a printable form
165 165 - connect(signal, function) - connect the signal of the given object to a python function
166 166 - connect(signal, qobject, slot) - connect the signal of the given object to a slot of another QObject
167 167 - disconnect(signal, function) - disconnect the signal of the given object from a python function
168 168 - disconnect(signal, qobject, slot) - disconnect the signal of the given object from a slot of another QObject
169 169 - children() - returns the children of the object
170 170 - setParent(QObject) - set the parent
171 171 - QObject* parent() - get the parent
172 172
173 173 The below example shows how to connect signals in Python:
174 174
175 175 \code
176 176 # define a signal handler function
177 177 def someFunction(flag):
178 178 print flag
179 179
180 180 # button1 is a QPushButton that has been added to Python via addObject()
181 181 # connect the clicked signal to a python function:
182 182 button1.connect("clicked(bool)", someFunction)
183 183
184 184 \endcode
185 185
186 186 \section CPP CPP Wrapping
187 187
188 188 You can create dedicated wrapper QObject for any C++ class. This is done by deriving from PythonQtCppWrapperFactory
189 189 and adding your factory via addWrapperFactory().
190 190 Whenever PythonQt encounters a CPP pointer (e.g. on a slot or signal)
191 191 and it does not known it as a QObject derived class, it will create a generic CPP wrapper. So even unknown C++ objects
192 192 can be passed through Python. If the wrapper factory supports the CPP class, a QObject wrapper will be created for each
193 193 instance that enters Python. An alternative to a complete wrapper via the wrapper factory are decorators, see \ref Decorators
194 194
195 195 \section MetaObject Meta Object/Class access
196 196
197 197 For each known CPP class, QObject derived class and QVariant type, PythonQt provides a Meta class. These meta classes are visible
198 198 inside of the "PythonQt" python module.
199 199
200 200 A Meta class supports:
201 201
202 202 - access to all declared enum values
203 203 - constructors
204 204 - static decorator slots
205 205 - help() and className()
206 206
207 207 From within Python, you can import the module "PythonQt" to access these meta objects and the Qt namespace.
208 208
209 209 \code
210 210 from PythonQt import *
211 211
212 212 # namespace access:
213 213 print Qt.AlignLeft
214 214
215 215 # constructors
216 216 a = QSize(12,13)
217 217 b = QFont()
218 218
219 219 # static method
220 220 QDate.currentDate()
221 221
222 222 # enum value
223 223 QFont.UltraCondensed
224 224
225 225 \endcode
226 226
227 227 \section Decorators Decorator slots
228 228
229 229 PythonQt introduces a new generic approach to extend any wrapped QObject or CPP object with
230 230
231 231 - constructors
232 232 - destructors (for CPP objects)
233 233 - additional slots
234 234 - static slots (callable on both the Meta object and the instances)
235 235
236 236 The idea behind decorators is that we wanted to make it as easy as possible to extend
237 237 wrapped objects. Since we already have an implementation for invoking any Qt Slot from
238 238 Python, it looked promising to use this approach for the extension of wrapped objects as well.
239 239 This avoids that the PythonQt user needs to care about how Python arguments are mapped from/to
240 240 Qt when he wants to create static methods, constructors and additional member functions.
241 241
242 242 The basic idea about decorators is to create a QObject derived class that implements slots
243 243 which take one of the above roles (e.g. constructor, destructor etc.) via a naming convention.
244 244 These slots are then assigned to other classes via the naming convention.
245 245
246 246 - QVariant new_SomeClassName(...) - defines a constructor for "SomeClassName" that returns a QVariant
247 247 - SomeClassName* new_SomeClassName(...) - defines a constructor for "SomeClassName" that returns a new object of type SomeClassName (where SomeClassName can be any CPP class, not just QObject classes)
248 248 - void delete_SomeClassName(SomeClassName* o) - defines a destructor, which should delete the passed in object o
249 249 - anything static_SomeClassName_someMethodName(...) - defines a static method that is callable on instances and the meta class
250 250 - anything someMethodName(SomeClassName* o, ...) - defines a slot that will be available on SomeClassName instances (and derived instances). When such a slot is called the first argument is the pointer to the instance and the rest of the arguments can be used to make a call on the instance.
251 251
252 252 The below example shows all kinds of decorators in action:
253 253
254 254 \code
255 255
256 256 // an example CPP object
257 257 class YourCPPObject {
258 258 public:
259 259 YourCPPObject(int arg1, float arg2) { a = arg1; b = arg2; }
260 260
261 261 float doSomething(int arg1) { return arg1*a*b; };
262 262
263 263 private:
264 264
265 265 int a;
266 266 float b;
267 267 };
268 268
269 269 // an example decorator
270 270 class ExampleDecorator : public QObject
271 271 {
272 272 Q_OBJECT
273 273
274 274 public slots:
275 275 // add a constructor to QSize variant that takes a QPoint
276 276 QVariant new_QSize(const QPoint& p) { return QSize(p.x(), p.y()); }
277 277
278 278 // add a constructor for QPushButton that takes a text and a parent widget
279 279 QPushButton* new_QPushButton(const QString& text, QWidget* parent=NULL) { return new QPushButton(text, parent); }
280 280
281 281 // add a constructor for a CPP object
282 282 YourCPPObject* new_YourCPPObject(int arg1, float arg2) { return new YourCPPObject(arg1, arg2); }
283 283
284 284 // add a destructor for a CPP object
285 285 void delete_YourCPPObject(YourCPPObject* obj) { delete obj; }
286 286
287 287 // add a static method to QWidget
288 288 QWidget* static_QWidget_mouseGrabber() { return QWidget::mouseGrabber(); }
289 289
290 290 // add an additional slot to QWidget (make move() callable, which is not declared as a slot in QWidget)
291 291 void move(QWidget* w, const QPoint& p) { w->move(p); }
292 292
293 293 // add an additional slot to QWidget, overloading the above move method
294 294 void move(QWidget* w, int x, int y) { w->move(x,y); }
295 295
296 296 // add a method to your own CPP object
297 297 int doSomething(YourCPPObject* obj, int arg1) { return obj->doSomething(arg1); }
298 298 };
299 299
300 300 ...
301 301
302 302 PythonQt::self()->addDecorators(new ExampleDecorator());
303 303 PythonQt::self()->registerClass(&QPushButton::staticMetaObject);
304 304 PythonQt::self()->registerCPPClassNames(QStringList() << "YourCPPObject");
305 305
306 306 \endcode
307 307
308 308 After you have registered an instance of the above ExampleDecorator, you can do the following from Python
309 309 (all these calls are mapped to the above decorator slots):
310 310
311 311 \code
312 312 from PythonQt import *
313 313
314 314 # call our new constructor of QSize
315 315 size = QSize(QPoint(1,2));
316 316
317 317 # call our new QPushButton constructor
318 318 button = QPushButton("sometext");
319 319
320 320 # call the move slot (overload1)
321 321 button.move(QPoint(0,0))
322 322
323 323 # call the move slot (overload2)
324 324 button.move(0,0)
325 325
326 326 # call the static method
327 327 grabber = QWidget.mouseWrapper();
328 328
329 329 # create a CPP object via constructor
330 330 yourCpp = YourCPPObject(1,11.5)
331 331
332 332 # call the wrapped method on CPP object
333 333 print yourCpp.doSomething(1);
334 334
335 335 # destructor will be called:
336 336 yourCpp = None
337 337
338 338 \endcode
339 339
340 340 \section Building
341 341
342 PythonQt requires at least Qt 4.2.2 (or higher) and Python 2.3, 2.4 or 2.5 on Windows, Linux and MacOS X.
342 PythonQt requires at least Qt 4.2.2 (or higher) and Python 2.3, 2.4, 2.5 or 2.6 on Windows, Linux and MacOS X. It has not yet been tested with Python 3.x, but it should only require minor changes.
343 343 To compile PythonQt, you will need a python developer installation which includes Python's header files and
344 344 the python2x.[lib | dll | so | dynlib].
345 345 The build scripts a currently set to use Python 2.5.
346 346 You may need to tweak the \b build/python.prf file to set the correct Python includes and libs on your system.
347 347
348 348 \subsection Windows
349 349
350 350 On Windows, the (non-source) Python Windows installer can be used.
351 351 Make sure that you use the same compiler, the current Python distribution is built
352 352 with Visual Studio 2003. If you want to use another compiler, you will need to build
353 353 Python yourself, using your compiler.
354 354
355 355 To build PythonQt, you need to set the environment variable \b PYTHON_PATH to point to the root
356 356 dir of the python installation and \b PYTHON_LIB to point to
357 357 the directory where the python lib file is located.
358 358
359 359 When using the prebuild Python installer, this will be:
360 360
361 361 \code
362 362 > set PYTHON_PATH = c:\Python25
363 363 > set PYTHON_LIB = c:\Python25\libs
364 364 \endcode
365 365
366 366 When using the python sources, this will be something like:
367 367
368 368 \code
369 369 > set PYTHON_PATH = c:\yourDir\Python-2.5.1\
370 370 > set PYTHON_LIB = c:\yourDir\Python-2.5.1\PCbuild8\Win32
371 371 \endcode
372 372
373 373 To build all, do the following (after setting the above variables):
374 374
375 375 \code
376 376 > cd PythonQtRoot
377 377 > vcvars32
378 378 > qmake
379 379 > nmake
380 380 \endcode
381 381
382 382 This should build everything. If Python can not be linked or include files can not be found,
383 383 you probably need to tweak \b build/python.prf
384 384
385 385 The tests and examples are located in PythonQt/lib.
386 386
387 387 \subsection Linux
388 388
389 389 On Linux, you need to install a Python-dev package.
390 390 If Python can not be linked or include files can not be found,
391 391 you probably need to tweak \b build/python.prf
392 392
393 393 To build PythonQt, just do a:
394 394
395 395 \code
396 396 > cd PythonQtRoot
397 397 > qmake
398 398 > make all
399 399 \endcode
400 400
401 401 The tests and examples are located in PythonQt/lib.
402 402 You should add PythonQt/lib to your LD_LIBRARY_PATH so that the runtime
403 403 linker can find the *.so files.
404 404
405 405 \subsection MacOsX
406 406
407 407 On Mac, Python is installed as a Framework, so you should not need to install it.
408 408 To build PythonQt, just do a:
409 409
410 410 \code
411 411 > cd PythonQtRoot
412 412 > qmake
413 413 > make all
414 414 \endcode
415 415
416 416 \section Tests
417 417
418 418 There is a unit test that tests most features of PythonQt, see the \b tests subdirectory for details.
419 419
420 420 \section Examples
421 421
422 422 Examples are available in the \b examples directory. The PyScriptingConsole implements a simple
423 423 interactive scripting console that shows how to script a simple application.
424 424
425 425 The following shows how to integrate PythonQt into you Qt application:
426 426
427 427 \code
428 428 #include "PythonQt.h"
429 429 #include <QApplication>
430 430 ...
431 431
432 432 int main( int argc, char **argv )
433 433 {
434 434
435 435 QApplication qapp(argc, argv);
436 436
437 437 // init PythonQt and Python itself
438 438 PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
439 439
440 440 // get a smart pointer to the __main__ module of the Python interpreter
441 441 PythonQtObjectPtr mainContext = PythonQt::self()->getMainModule();
442 442
443 443 // add a QObject as variable of name "example" to the namespace of the __main__ module
444 444 PyExampleObject example;
445 445 PythonQt::self()->addObject(mainContext, "example", &example);
446 446
447 447 // register all other QObjects that you want to script and that are returned by your API
448 448 PythonQt::self()->registerClass(&QMainWindow::staticMetaObject);
449 449 PythonQt::self()->registerClass(&QPushButton::staticMetaObject);
450 450 ...
451 451
452 452 // do something
453 453 PythonQt::self()->runScript(mainContext, "print example\n");
454 454 PythonQt::self()->runScript(mainContext, "def multiply(a,b):\n return a*b;\n");
455 455 QVariantList args;
456 456 args << 42 << 47;
457 457 QVariant result = PythonQt::self()->call(mainContext,"multiply", args);
458 458 ...
459 459 \endcode
460 460
461 461
462 \section TODOs
463
464 - add more information on how to distribute an application that uses PythonQt, including the Python distribution
465
466 462 */
@@ -1,69 +1,72
1 1 #ifndef _PYTHONQTIMPORTFILEINTERFACE_H
2 2 #define _PYTHONQTIMPORTFILEINTERFACE_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 PythonQtImportFileInterface.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 <QDateTime>
46 46 #include <QString>
47 47 #include <QByteArray>
48 48
49 49 //! Defines an abstract interface to file access for the Python import statement.
50 50 //! see PythonQt::setImporter()
51 51 class PythonQtImportFileInterface {
52 52
53 53 public:
54 // get rid of warnings
55 virtual ~PythonQtImportFileInterface() {}
56
54 57 //! read the given file as byte array, without doing any linefeed translations
55 58 virtual QByteArray readFileAsBytes(const QString& filename) = 0;
56 59
57 60 //! read a source file, expects a readable Python text file with translated line feeds.
58 61 //! If the file can not be load OR it can not be verified, ok is set to false
59 62 virtual QByteArray readSourceFile(const QString& filename, bool& ok) = 0;
60 63
61 64 //! returns if the file exists
62 65 virtual bool exists(const QString& filename) = 0;
63 66
64 67 //! get the last modified data of a file
65 68 virtual QDateTime lastModifiedDate(const QString& filename) = 0;
66 69
67 70 };
68 71
69 72 #endif No newline at end of file
@@ -1,790 +1,781
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 PythonQtImporter.h
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 // This module was inspired by the zipimport.c module of the original
41 41 // Python distribution. Most of the functions are identical or slightly
42 42 // modified to do all the loading of Python files via an external file interface.
43 43 // In contrast to zipimport.c, this module also writes *.pyc files
44 44 // automatically if it has write access/is not inside of a zip file.
45 45 //----------------------------------------------------------------------------------
46 46
47 47 #include "PythonQtImporter.h"
48 48 #include "PythonQtImportFileInterface.h"
49 49 #include "PythonQt.h"
50 50 #include <QFile>
51 51 #include <QFileInfo>
52 52
53 53 #define IS_SOURCE 0x0
54 54 #define IS_BYTECODE 0x1
55 55 #define IS_PACKAGE 0x2
56 56
57 57 struct st_mlab_searchorder {
58 58 char suffix[14];
59 59 int type;
60 60 };
61 61
62 62 /* mlab_searchorder defines how we search for a module in the Zip
63 63 archive: we first search for a package __init__, then for
64 64 non-package .pyc, .pyo and .py entries. The .pyc and .pyo entries
65 65 are swapped by initmlabimport() if we run in optimized mode. Also,
66 66 '/' is replaced by SEP there. */
67 67 struct st_mlab_searchorder mlab_searchorder[] = {
68 68 {"/__init__.pyc", IS_PACKAGE | IS_BYTECODE},
69 69 {"/__init__.pyo", IS_PACKAGE | IS_BYTECODE},
70 70 {"/__init__.py", IS_PACKAGE | IS_SOURCE},
71 71 {".pyc", IS_BYTECODE},
72 72 {".pyo", IS_BYTECODE},
73 73 {".py", IS_SOURCE},
74 74 {"", 0}
75 75 };
76 76
77 77 extern PyTypeObject PythonQtImporter_Type;
78 78 PyObject *PythonQtImportError;
79 79
80 80 QString PythonQtImport::getSubName(const QString& str)
81 81 {
82 82 int idx = str.lastIndexOf('.');
83 83 if (idx!=-1) {
84 84 return str.mid(idx+1);
85 85 } else {
86 86 return str;
87 87 }
88 88 }
89 89
90 90 PythonQtImport::module_info PythonQtImport::getModuleInfo(PythonQtImporter* self, const QString& fullname)
91 91 {
92 92 QString subname;
93 93 struct st_mlab_searchorder *zso;
94 94
95 95 subname = getSubName(fullname);
96 96 QString path = *self->_path + "/" + subname;
97 97
98 98 QString test;
99 99 for (zso = mlab_searchorder; *zso->suffix; zso++) {
100 100 test = path + zso->suffix;
101 101 if (PythonQt::importInterface()->exists(test)) {
102 102 if (zso->type & IS_PACKAGE)
103 103 return MI_PACKAGE;
104 104 else
105 105 return MI_MODULE;
106 106 }
107 107 }
108 108 return MI_NOT_FOUND;
109 109 }
110 110
111 111
112 112 /* PythonQtImporter.__init__
113 113 Just store the path argument
114 114 */
115 int PythonQtImporter_init(PythonQtImporter *self, PyObject *args, PyObject *kwds)
115 int PythonQtImporter_init(PythonQtImporter *self, PyObject *args, PyObject * /*kwds*/)
116 116 {
117 117 self->_path = NULL;
118 118
119 119 const char* path;
120 120 if (!PyArg_ParseTuple(args, "s",
121 121 &path))
122 122 return -1;
123 123
124 124 if (PythonQt::importInterface()->exists(path)) {
125 125 //qDebug("path %s", path);
126 126 QString p(path);
127 127 const QStringList& ignorePaths = PythonQt::self()->getImporterIgnorePaths();
128 128 foreach(QString a, ignorePaths) {
129 129 if (a==p) {
130 130 PyErr_SetString(PythonQtImportError,
131 131 "path ignored");
132 132 return -1;
133 133 }
134 134 }
135 135
136 136 self->_path = new QString(p);
137 137
138 138 //mlabDebugConst("MLABPython", "PythonQtImporter init: " << *self->_path);
139 139
140 140 return 0;
141 141 } else {
142 142 PyErr_SetString(PythonQtImportError,
143 143 "path does not exist error");
144 144 return -1;
145 145 }
146 146 }
147 147
148 148 void
149 149 PythonQtImporter_dealloc(PythonQtImporter *self)
150 150 {
151 151 // free the stored path
152 152 if (self->_path) delete self->_path;
153 153 // free ourself
154 154 self->ob_type->tp_free((PyObject *)self);
155 155 }
156 156
157 157
158 158 /* Check whether we can satisfy the import of the module named by
159 159 'fullname'. Return self if we can, None if we can't. */
160 160 PyObject *
161 161 PythonQtImporter_find_module(PyObject *obj, PyObject *args)
162 162 {
163 163 PythonQtImporter *self = (PythonQtImporter *)obj;
164 164 PyObject *path = NULL;
165 165 char *fullname;
166 166
167 167 if (!PyArg_ParseTuple(args, "s|O:PythonQtImporter.find_module",
168 168 &fullname, &path))
169 169 return NULL;
170 170
171 171 // mlabDebugConst("MLABPython", "FindModule " << fullname << " in " << *self->_path);
172 172
173 173 PythonQtImport::module_info info = PythonQtImport::getModuleInfo(self, fullname);
174 174 if (info == PythonQtImport::MI_MODULE || info == PythonQtImport::MI_PACKAGE) {
175 175 Py_INCREF(self);
176 176 return (PyObject *)self;
177 177 } else {
178 178 Py_INCREF(Py_None);
179 179 return Py_None;
180 180 }
181 181 }
182 182
183 183 /* Load and return the module named by 'fullname'. */
184 184 PyObject *
185 185 PythonQtImporter_load_module(PyObject *obj, PyObject *args)
186 186 {
187 187 PythonQtImporter *self = (PythonQtImporter *)obj;
188 188 PyObject *code, *mod, *dict;
189 189 char *fullname;
190 190 QString modpath;
191 191 int ispackage;
192 192
193 193 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.load_module",
194 194 &fullname))
195 195 return NULL;
196 196
197 197 code = PythonQtImport::getModuleCode(self, fullname, &ispackage, modpath);
198 198 if (code == NULL)
199 199 return NULL;
200 200
201 201 mod = PyImport_AddModule(fullname);
202 202 if (mod == NULL) {
203 203 Py_DECREF(code);
204 204 return NULL;
205 205 }
206 206 dict = PyModule_GetDict(mod);
207 207
208 if (PyDict_SetItemString(dict, "__loader__", (PyObject *)self) != 0)
209 goto error;
208 if (PyDict_SetItemString(dict, "__loader__", (PyObject *)self) != 0) {
209 Py_DECREF(code);
210 Py_DECREF(mod);
211 return NULL;
212 }
210 213
211 214 if (ispackage) {
212 215 PyObject *pkgpath, *fullpath;
213 216 QString subname = PythonQtImport::getSubName(fullname);
214 217 int err;
215 218
216 219 fullpath = PyString_FromFormat("%s%c%s",
217 220 self->_path->toLatin1().constData(),
218 221 SEP,
219 222 subname.toLatin1().constData());
220 if (fullpath == NULL)
221 goto error;
223 if (fullpath == NULL) {
224 Py_DECREF(code);
225 Py_DECREF(mod);
226 return NULL;
227 }
222 228
223 229 pkgpath = Py_BuildValue("[O]", fullpath);
224 230 Py_DECREF(fullpath);
225 if (pkgpath == NULL)
226 goto error;
231 if (pkgpath == NULL) {
232 Py_DECREF(code);
233 Py_DECREF(mod);
234 return NULL;
235 }
227 236 err = PyDict_SetItemString(dict, "__path__", pkgpath);
228 237 Py_DECREF(pkgpath);
229 if (err != 0)
230 goto error;
238 if (err != 0) {
239 Py_DECREF(code);
240 Py_DECREF(mod);
241 return NULL;
242 }
231 243 }
232 244 mod = PyImport_ExecCodeModuleEx(fullname, code, (char*)modpath.toLatin1().data());
233 245 Py_DECREF(code);
234 246 if (Py_VerboseFlag)
235 247 PySys_WriteStderr("import %s # loaded from %s\n",
236 fullname, modpath);
248 fullname, modpath.toLatin1().constData());
237 249 return mod;
238 error:
239 Py_DECREF(code);
240 Py_DECREF(mod);
241 return NULL;
242 250 }
243 251
244 252
245 253 PyObject *
246 PythonQtImporter_get_data(PyObject *obj, PyObject *args)
254 PythonQtImporter_get_data(PyObject* /*obj*/, PyObject* /*args*/)
247 255 {
248 256 // EXTRA, NOT YET IMPLEMENTED
249 257 return NULL;
250 258 }
251 259
252 260 PyObject *
253 261 PythonQtImporter_get_code(PyObject *obj, PyObject *args)
254 262 {
255 263 PythonQtImporter *self = (PythonQtImporter *)obj;
256 264 char *fullname;
257 265
258 266 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.get_code", &fullname))
259 267 return NULL;
260 268
261 269 QString notused;
262 270 return PythonQtImport::getModuleCode(self, fullname, NULL, notused);
263 271 }
264 272
265 273 PyObject *
266 PythonQtImporter_get_source(PyObject *obj, PyObject *args)
274 PythonQtImporter_get_source(PyObject * /*obj*/, PyObject * /*args*/)
267 275 {
268 276 // EXTRA, NOT YET IMPLEMENTED
269 277 /*
270 278 PythonQtImporter *self = (PythonQtImporter *)obj;
271 279 PyObject *toc_entry;
272 280 char *fullname, *subname, path[MAXPATHLEN+1];
273 281 int len;
274 282 enum module_info mi;
275 283
276 284 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.get_source", &fullname))
277 285 return NULL;
278 286
279 287 mi = get_module_info(self, fullname);
280 288 if (mi == MI_ERROR)
281 289 return NULL;
282 290 if (mi == MI_NOT_FOUND) {
283 291 PyErr_Format(PythonQtImportError, "can't find module '%.200s'",
284 292 fullname);
285 293 return NULL;
286 294 }
287 295 subname = get_subname(fullname);
288 296
289 297 len = make_filename(PyString_AsString(self->prefix), subname, path);
290 298 if (len < 0)
291 299 return NULL;
292 300
293 301 if (mi == MI_PACKAGE) {
294 302 path[len] = SEP;
295 303 strcpy(path + len + 1, "__init__.py");
296 304 }
297 305 else
298 306 strcpy(path + len, ".py");
299 307
300 308 toc_entry = PyDict_GetItemString(self->files, path);
301 309 if (toc_entry != NULL)
302 310 return get_data(PyString_AsString(self->archive), toc_entry);
303 311
304 312 Py_INCREF(Py_None);
305 313 return Py_None;
306 314 */
307 315 return NULL;
308 316 }
309 317
310 318 PyDoc_STRVAR(doc_find_module,
311 319 "find_module(fullname, path=None) -> self or None.\n\
312 320 \n\
313 321 Search for a module specified by 'fullname'. 'fullname' must be the\n\
314 322 fully qualified (dotted) module name. It returns the PythonQtImporter\n\
315 323 instance itself if the module was found, or None if it wasn't.\n\
316 324 The optional 'path' argument is ignored -- it's there for compatibility\n\
317 325 with the importer protocol.");
318 326
319 327 PyDoc_STRVAR(doc_load_module,
320 328 "load_module(fullname) -> module.\n\
321 329 \n\
322 330 Load the module specified by 'fullname'. 'fullname' must be the\n\
323 331 fully qualified (dotted) module name. It returns the imported\n\
324 332 module, or raises PythonQtImportError if it wasn't found.");
325 333
326 334 PyDoc_STRVAR(doc_get_data,
327 335 "get_data(pathname) -> string with file data.\n\
328 336 \n\
329 337 Return the data associated with 'pathname'. Raise IOError if\n\
330 338 the file wasn't found.");
331 339
332 340 PyDoc_STRVAR(doc_get_code,
333 341 "get_code(fullname) -> code object.\n\
334 342 \n\
335 343 Return the code object for the specified module. Raise PythonQtImportError\n\
336 344 is the module couldn't be found.");
337 345
338 346 PyDoc_STRVAR(doc_get_source,
339 347 "get_source(fullname) -> source string.\n\
340 348 \n\
341 349 Return the source code for the specified module. Raise PythonQtImportError\n\
342 350 is the module couldn't be found, return None if the archive does\n\
343 351 contain the module, but has no source for it.");
344 352
345 353 PyMethodDef PythonQtImporter_methods[] = {
346 354 {"find_module", PythonQtImporter_find_module, METH_VARARGS,
347 355 doc_find_module},
348 356 {"load_module", PythonQtImporter_load_module, METH_VARARGS,
349 357 doc_load_module},
350 358 {"get_data", PythonQtImporter_get_data, METH_VARARGS,
351 359 doc_get_data},
352 360 {"get_code", PythonQtImporter_get_code, METH_VARARGS,
353 361 doc_get_code},
354 362 {"get_source", PythonQtImporter_get_source, METH_VARARGS,
355 363 doc_get_source},
356 {NULL, NULL} /* sentinel */
364 {NULL, NULL, 0 , NULL} /* sentinel */
357 365 };
358 366
359 367
360 368 PyDoc_STRVAR(PythonQtImporter_doc,
361 369 "PythonQtImporter(path) -> PythonQtImporter object\n\
362 370 \n\
363 371 Create a new PythonQtImporter instance. 'path' must be a valid path on disk/or inside of a zip file known to MeVisLab\n\
364 372 . Every path is accepted.");
365 373
366 374 #define DEFERRED_ADDRESS(ADDR) 0
367 375
368 376 PyTypeObject PythonQtImporter_Type = {
369 377 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
370 378 0,
371 379 "PythonQtImport.PythonQtImporter",
372 380 sizeof(PythonQtImporter),
373 381 0, /* tp_itemsize */
374 382 (destructor)PythonQtImporter_dealloc, /* tp_dealloc */
375 383 0, /* tp_print */
376 384 0, /* tp_getattr */
377 385 0, /* tp_setattr */
378 386 0, /* tp_compare */
379 387 0, /* tp_repr */
380 388 0, /* tp_as_number */
381 389 0, /* tp_as_sequence */
382 390 0, /* tp_as_mapping */
383 391 0, /* tp_hash */
384 392 0, /* tp_call */
385 393 0, /* tp_str */
386 394 PyObject_GenericGetAttr, /* tp_getattro */
387 395 0, /* tp_setattro */
388 396 0, /* tp_as_buffer */
389 397 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE , /* tp_flags */
390 398 PythonQtImporter_doc, /* tp_doc */
391 399 0, /* tp_traverse */
392 400 0, /* tp_clear */
393 401 0, /* tp_richcompare */
394 402 0, /* tp_weaklistoffset */
395 403 0, /* tp_iter */
396 404 0, /* tp_iternext */
397 405 PythonQtImporter_methods, /* tp_methods */
398 406 0, /* tp_members */
399 407 0, /* tp_getset */
400 408 0, /* tp_base */
401 409 0, /* tp_dict */
402 410 0, /* tp_descr_get */
403 411 0, /* tp_descr_set */
404 412 0, /* tp_dictoffset */
405 413 (initproc)PythonQtImporter_init, /* tp_init */
406 414 PyType_GenericAlloc, /* tp_alloc */
407 415 PyType_GenericNew, /* tp_new */
408 416 PyObject_Del, /* tp_free */
409 417 };
410 418
411 419
412 420 /* Given a buffer, return the long that is represented by the first
413 421 4 bytes, encoded as little endian. This partially reimplements
414 422 marshal.c:r_long() */
415 423 long
416 424 PythonQtImport::getLong(unsigned char *buf)
417 425 {
418 426 long x;
419 427 x = buf[0];
420 428 x |= (long)buf[1] << 8;
421 429 x |= (long)buf[2] << 16;
422 430 x |= (long)buf[3] << 24;
423 431 #if SIZEOF_LONG > 4
424 432 /* Sign extension for 64-bit machines */
425 433 x |= -(x & 0x80000000L);
426 434 #endif
427 435 return x;
428 436 }
429 437
430 438 FILE *
431 439 open_exclusive(const QString& filename)
432 440 {
433 441 #if defined(O_EXCL)&&defined(O_CREAT)&&defined(O_WRONLY)&&defined(O_TRUNC)
434 442 /* Use O_EXCL to avoid a race condition when another process tries to
435 443 write the same file. When that happens, our open() call fails,
436 444 which is just fine (since it's only a cache).
437 445 XXX If the file exists and is writable but the directory is not
438 446 writable, the file will never be written. Oh well.
439 447 */
440 448 QFile::remove(filename);
441 449
442 450 int fd;
443 451 int flags = O_EXCL|O_CREAT|O_WRONLY|O_TRUNC;
444 452 #ifdef O_BINARY
445 453 flags |= O_BINARY; /* necessary for Windows */
446 454 #endif
447 455 #ifdef WIN32
448 456 fd = _wopen(filename.ucs2(), flags, 0666);
449 457 #else
450 458 fd = open(filename.local8Bit(), flags, 0666);
451 459 #endif
452 460 if (fd < 0)
453 461 return NULL;
454 462 return fdopen(fd, "wb");
455 463 #else
456 464 /* Best we can do -- on Windows this can't happen anyway */
457 465 return fopen(filename.toLocal8Bit().constData(), "wb");
458 466 #endif
459 467 }
460 468
461 469
462 470 void PythonQtImport::writeCompiledModule(PyCodeObject *co, const QString& filename, long mtime)
463 471 {
464 472 FILE *fp;
465 473
466 474 fp = open_exclusive(filename);
467 475 if (fp == NULL) {
468 476 if (Py_VerboseFlag)
469 477 PySys_WriteStderr(
470 478 "# can't create %s\n", filename.toLatin1().constData());
471 479 return;
472 480 }
473 481 #if PY_VERSION_HEX < 0x02040000
474 482 PyMarshal_WriteLongToFile(PyImport_GetMagicNumber(), fp);
475 483 #else
476 484 PyMarshal_WriteLongToFile(PyImport_GetMagicNumber(), fp, Py_MARSHAL_VERSION);
477 485 #endif
478 486 /* First write a 0 for mtime */
479 487 #if PY_VERSION_HEX < 0x02040000
480 488 PyMarshal_WriteLongToFile(0L, fp);
481 489 #else
482 490 PyMarshal_WriteLongToFile(0L, fp, Py_MARSHAL_VERSION);
483 491 #endif
484 492 #if PY_VERSION_HEX < 0x02040000
485 493 PyMarshal_WriteObjectToFile((PyObject *)co, fp);
486 494 #else
487 495 PyMarshal_WriteObjectToFile((PyObject *)co, fp, Py_MARSHAL_VERSION);
488 496 #endif
489 497 if (ferror(fp)) {
490 498 if (Py_VerboseFlag)
491 499 PySys_WriteStderr("# can't write %s\n", filename.toLatin1().constData());
492 500 /* Don't keep partial file */
493 501 fclose(fp);
494 502 QFile::remove(filename);
495 503 return;
496 504 }
497 505 /* Now write the true mtime */
498 506 fseek(fp, 4L, 0);
499 507 #if PY_VERSION_HEX < 0x02040000
500 508 PyMarshal_WriteLongToFile(mtime, fp);
501 509 #else
502 510 PyMarshal_WriteLongToFile(mtime, fp, Py_MARSHAL_VERSION);
503 511 #endif
504 512 fflush(fp);
505 513 fclose(fp);
506 514 if (Py_VerboseFlag)
507 515 PySys_WriteStderr("# wrote %s\n", filename.toLatin1().constData());
508 516 //#ifdef macintosh
509 517 // PyMac_setfiletype(cpathname, 'Pyth', 'PYC ');
510 518 //#endif
511 519 }
512 520
513 521 /* Given the contents of a .py[co] file in a buffer, unmarshal the data
514 522 and return the code object. Return None if it the magic word doesn't
515 523 match (we do this instead of raising an exception as we fall back
516 524 to .py if available and we don't want to mask other errors).
517 525 Returns a new reference. */
518 526 PyObject *
519 527 PythonQtImport::unmarshalCode(const QString& path, const QByteArray& data, time_t mtime)
520 528 {
521 529 PyObject *code;
522 530 // ugly cast, but Python API is not const safe
523 531 char *buf = (char*) data.constData();
524 532 int size = data.size();
525 533
526 534 if (size <= 9) {
527 535 PySys_WriteStderr("# %s has bad pyc data\n",
528 536 path.toLatin1().constData());
529 537 Py_INCREF(Py_None);
530 538 return Py_None;
531 539 }
532 540
533 541 if (getLong((unsigned char *)buf) != PyImport_GetMagicNumber()) {
534 542 if (Py_VerboseFlag)
535 543 PySys_WriteStderr("# %s has bad magic\n",
536 544 path.toLatin1().constData());
537 545 Py_INCREF(Py_None);
538 546 return Py_None;
539 547 }
540 548
541 549 if (mtime != 0 && !(getLong((unsigned char *)buf + 4) == mtime)) {
542 550 if (Py_VerboseFlag)
543 551 PySys_WriteStderr("# %s has bad mtime\n",
544 552 path.toLatin1().constData());
545 553 Py_INCREF(Py_None);
546 554 return Py_None;
547 555 }
548 556
549 557 code = PyMarshal_ReadObjectFromString(buf + 8, size - 8);
550 558 if (code == NULL)
551 559 return NULL;
552 560 if (!PyCode_Check(code)) {
553 561 Py_DECREF(code);
554 562 PyErr_Format(PyExc_TypeError,
555 563 "compiled module %.200s is not a code object",
556 564 path.toLatin1().constData());
557 565 return NULL;
558 566 }
559 567 return code;
560 568 }
561 569
562 570
563 571 /* Given a string buffer containing Python source code, compile it
564 572 return and return a code object as a new reference. */
565 573 PyObject *
566 574 PythonQtImport::compileSource(const QString& path, const QByteArray& data)
567 575 {
568 576 PyObject *code;
569 577 QByteArray data1 = data;
570 578 // in qt4, data is null terminated
571 579 // data1.resize(data.size()+1);
572 580 // data1.data()[data.size()-1] = 0;
573 581 code = Py_CompileString(data.data(), path.toLatin1().constData(),
574 582 Py_file_input);
575 583 return code;
576 584 }
577 585
578 586
579 587 /* Return the code object for the module named by 'fullname' from the
580 588 Zip archive as a new reference. */
581 589 PyObject *
582 PythonQtImport::getCodeFromData(const QString& path, int isbytecode,int ispackage, time_t mtime)
590 PythonQtImport::getCodeFromData(const QString& path, int isbytecode,int /*ispackage*/, time_t mtime)
583 591 {
584 bool hasImporter = PythonQt::importInterface()!=NULL;
585
586 592 PyObject *code;
587 593
588 594 QByteArray qdata;
589 if (!hasImporter) {
590 QFile file(path);
591 QIODevice::OpenMode flags = QIODevice::ReadOnly;
592 if (!isbytecode) {
593 flags |= QIODevice::Text;
594 }
595 if (!file.open(flags)) {
596 return NULL;
597 }
598 qdata = file.readAll();
599 } else {
600 595 if (!isbytecode) {
601 596 // mlabDebugConst("MLABPython", "reading source " << path);
602 597 bool ok;
603 598 qdata = PythonQt::importInterface()->readSourceFile(path, ok);
604 599 if (!ok) {
605 600 // mlabErrorConst("PythonQtImporter","File could not be verified" << path);
606 601 return NULL;
607 602 }
608 603 if (qdata == " ") {
609 604 qdata.clear();
610 605 }
611 606 } else {
612 607 qdata = PythonQt::importInterface()->readFileAsBytes(path);
613 608 }
614 }
615 609
616 610 if (isbytecode) {
617 611 // mlabDebugConst("MLABPython", "reading bytecode " << path);
618 612 code = unmarshalCode(path, qdata, mtime);
619 613 }
620 614 else {
621 615 // mlabDebugConst("MLABPython", "compiling source " << path);
622 616 code = compileSource(path, qdata);
623 617 if (code) {
624 618 // save a pyc file if possible
625 619 QDateTime time;
626 time = hasImporter?PythonQt::importInterface()->lastModifiedDate(path):QFileInfo(path).lastModified();
620 time = PythonQt::importInterface()->lastModifiedDate(path);
627 621 writeCompiledModule((PyCodeObject*)code, path+"c", time.toTime_t());
628 622 }
629 623 }
630 624 return code;
631 625 }
632 626
633 627 time_t
634 628 PythonQtImport::getMTimeOfSource(const QString& path)
635 629 {
636 630 time_t mtime = 0;
637 631 QString path2 = path;
638 632 path2.truncate(path.length()-1);
639 633
640 bool hasImporter = PythonQt::importInterface()!=NULL;
641 if (hasImporter) {
642 634 if (PythonQt::importInterface()->exists(path2)) {
643 635 mtime = PythonQt::importInterface()->lastModifiedDate(path2).toTime_t();
644 636 }
645 } else {
646 if (QFile::exists(path2)) {
647 mtime = QFileInfo(path2).lastModified().toTime_t();
648 }
649 }
637
650 638 return mtime;
651 639 }
652 640
653 641 /* Get the code object associated with the module specified by
654 642 'fullname'. */
655 643 PyObject *
656 644 PythonQtImport::getModuleCode(PythonQtImporter *self, char *fullname,
657 645 int *p_ispackage, QString& modpath)
658 646 {
659 647 QString subname;
660 648 struct st_mlab_searchorder *zso;
661 649
662 650 subname = getSubName(fullname);
663 651 QString path = *self->_path + "/" + subname;
664 652
665 653 QString test;
666 654 for (zso = mlab_searchorder; *zso->suffix; zso++) {
667 655 PyObject *code = NULL;
668 656 test = path + zso->suffix;
669 657
670 658 if (Py_VerboseFlag > 1)
671 659 PySys_WriteStderr("# trying %s\n",
672 660 test.toLatin1().constData());
673 661 if (PythonQt::importInterface()->exists(test)) {
674 662 time_t mtime = 0;
675 663 int ispackage = zso->type & IS_PACKAGE;
676 664 int isbytecode = zso->type & IS_BYTECODE;
677 665
678 666 if (isbytecode)
679 667 mtime = getMTimeOfSource(test);
680 668 if (p_ispackage != NULL)
681 669 *p_ispackage = ispackage;
682 670 code = getCodeFromData(test, isbytecode, ispackage, mtime);
683 671 if (code == Py_None) {
684 672 Py_DECREF(code);
685 673 continue;
686 674 }
687 675 if (code != NULL)
688 676 modpath = test;
689 677 return code;
690 678 }
691 679 }
692 680 PyErr_Format(PythonQtImportError, "can't find module '%.200s'", fullname);
693 681
694 682 return NULL;
695 683 }
696 684
697 685 QString PythonQtImport::replaceExtension(const QString& str, const QString& ext)
698 686 {
699 687 QString r;
700 688 int i = str.lastIndexOf('.');
701 689 if (i!=-1) {
702 690 r = str.mid(0,i) + "." + ext;
703 691 } else {
704 692 r = str + "." + ext;
705 693 }
706 694 return r;
707 695 }
708 696
709 697 PyObject* PythonQtImport::getCodeFromPyc(const QString& file)
710 698 {
711 bool hasImporter = PythonQt::importInterface()!=NULL;
712
713 699 PyObject* code;
714 700 const static QString pycStr("pyc");
715 701 QString pyc = replaceExtension(file, pycStr);
716 if ((hasImporter && PythonQt::importInterface()->exists(pyc)) ||
717 (!hasImporter && QFile::exists(pyc))) {
702 if (PythonQt::importInterface()->exists(pyc)) {
718 703 time_t mtime = 0;
719 704 mtime = getMTimeOfSource(pyc);
720 705 code = getCodeFromData(pyc, true, false, mtime);
721 706 if (code != Py_None && code != NULL) {
722 707 return code;
723 708 }
724 709 if (code) {
725 710 Py_DECREF(code);
726 711 }
727 712 }
728 713 code = getCodeFromData(file,false,false,0);
729 714 return code;
730 715 }
731 716
732 717 /* Module init */
733 718
734 719 PyDoc_STRVAR(mlabimport_doc,
735 "Imports python files into MeVisLab, completely replaces internal python import");
720 "Imports python files into PythonQt, completely replaces internal python import");
736 721
737 722 void PythonQtImport::init()
738 723 {
724 static bool first = true;
725 if (!first) {
726 return;
727 }
728 first = false;
729
739 730 PyObject *mod;
740 731
741 732 if (PyType_Ready(&PythonQtImporter_Type) < 0)
742 733 return;
743 734
744 735 /* Correct directory separator */
745 736 mlab_searchorder[0].suffix[0] = SEP;
746 737 mlab_searchorder[1].suffix[0] = SEP;
747 738 mlab_searchorder[2].suffix[0] = SEP;
748 739 if (Py_OptimizeFlag) {
749 740 /* Reverse *.pyc and *.pyo */
750 741 struct st_mlab_searchorder tmp;
751 742 tmp = mlab_searchorder[0];
752 743 mlab_searchorder[0] = mlab_searchorder[1];
753 744 mlab_searchorder[1] = tmp;
754 745 tmp = mlab_searchorder[3];
755 746 mlab_searchorder[3] = mlab_searchorder[4];
756 747 mlab_searchorder[4] = tmp;
757 748 }
758 749
759 750 mod = Py_InitModule4("PythonQtImport", NULL, mlabimport_doc,
760 751 NULL, PYTHON_API_VERSION);
761 752
762 753 PythonQtImportError = PyErr_NewException("PythonQtImport.PythonQtImportError",
763 754 PyExc_ImportError, NULL);
764 755 if (PythonQtImportError == NULL)
765 756 return;
766 757
767 758 Py_INCREF(PythonQtImportError);
768 759 if (PyModule_AddObject(mod, "PythonQtImportError",
769 760 PythonQtImportError) < 0)
770 761 return;
771 762
772 763 Py_INCREF(&PythonQtImporter_Type);
773 764 if (PyModule_AddObject(mod, "PythonQtImporter",
774 765 (PyObject *)&PythonQtImporter_Type) < 0)
775 766 return;
776 767
777 768 // set our importer into the path_hooks to handle all path on sys.path
778 769 PyObject* classobj = PyDict_GetItemString(PyModule_GetDict(mod), "PythonQtImporter");
779 770 PyObject* path_hooks = PySys_GetObject("path_hooks");
780 771 PyList_Append(path_hooks, classobj);
781 772
782 773 #ifndef WIN32
783 774 // reload the encodings module, because it might fail to custom import requirements (e.g. encryption).
784 775 PyObject* modules = PyImport_GetModuleDict();
785 776 PyObject* encodingsModule = PyDict_GetItemString(modules, "encodings");
786 777 if (encodingsModule != NULL) {
787 778 PyImport_ReloadModule(encodingsModule);
788 779 }
789 780 #endif
790 781 }
@@ -1,245 +1,245
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 PythonQtMetaObjectWrapper.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 "PythonQtMetaObjectWrapper.h"
43 43 #include <QObject>
44 44
45 45 #include "PythonQt.h"
46 46 #include "PythonQtSlot.h"
47 47 #include "PythonQtClassInfo.h"
48 48 #include "PythonQtConversion.h"
49 49
50 50 static void PythonQtMetaObjectWrapper_dealloc(PythonQtMetaObjectWrapper* self)
51 51 {
52 52 self->ob_type->tp_free((PyObject*)self);
53 53 }
54 54
55 static PyObject* PythonQtMetaObjectWrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
55 static PyObject* PythonQtMetaObjectWrapper_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
56 56 {
57 57 PythonQtMetaObjectWrapper *self;
58 58
59 59 self = (PythonQtMetaObjectWrapper *)type->tp_alloc(type, 0);
60 60 if (self != NULL) {
61 61 self->_info = NULL;
62 62 }
63 63 return (PyObject *)self;
64 64 }
65 65
66 static int PythonQtMetaObjectWrapper_init(PythonQtMetaObjectWrapper *self, PyObject *args, PyObject *kwds)
66 static int PythonQtMetaObjectWrapper_init(PythonQtMetaObjectWrapper * /*self*/, PyObject * /*args*/, PyObject * /*kwds*/)
67 67 {
68 68 return 0;
69 69 }
70 70
71 71 PyObject *PythonQtMetaObjectWrapper_call(PyObject *func, PyObject *args, PyObject *kw) {
72 72 PythonQtMetaObjectWrapper* wrapper = (PythonQtMetaObjectWrapper*)func;
73 73 PyObject* result = NULL;
74 74 QString error;
75 75 PyObject* err = NULL;
76 76 if (wrapper->_info->constructors()) {
77 77 result = PythonQtSlotFunction_CallImpl(NULL, wrapper->_info->constructors(), args, kw);
78 78 err = PyErr_Occurred();
79 79 }
80 80 if (!result) {
81 81 QObject* v = NULL;
82 82 QListIterator<PythonQtConstructorHandler*> it(PythonQt::self()->constructorHandlers());
83 83 while (!v && it.hasNext()) {
84 84 v = it.next()->create(wrapper->_info->metaObject(), args, kw, error);
85 85 }
86 86 if (v) {
87 87 result = PythonQt::priv()->wrapQObject(v);
88 88 }
89 89 }
90 90 if (result) {
91 91 // change ownershipflag to be owned by PythonQt
92 92 if (result->ob_type == &PythonQtWrapper_Type) {
93 93 ((PythonQtWrapper*)result)->_ownedByPythonQt = true;
94 94 }
95 95 } else {
96 96 if (!wrapper->_info->constructors()) {
97 97 if (!err) {
98 98 if (error.isEmpty()) {
99 99 error = QString("No constructors available for ") + wrapper->_info->className();
100 100 }
101 101 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
102 102 }
103 103 }
104 104 }
105 105 return result;
106 106 }
107 107
108 108 static PyObject *PythonQtMetaObjectWrapper_classname(PythonQtMetaObjectWrapper* type)
109 109 {
110 110 return PyString_FromString((QString("Meta_") + type->_info->className()).toLatin1().data());
111 111 }
112 112
113 113 static PyObject *PythonQtMetaObjectWrapper_help(PythonQtMetaObjectWrapper* type)
114 114 {
115 115 return PythonQt::self()->helpCalled(type->_info);
116 116 }
117 117
118 118
119 119 static PyMethodDef PythonQtMetaObjectWrapper_methods[] = {
120 120 {"className", (PyCFunction)PythonQtMetaObjectWrapper_classname, METH_NOARGS,
121 121 "Return the classname of the object"
122 122 },
123 123 {"help", (PyCFunction)PythonQtMetaObjectWrapper_help, METH_NOARGS,
124 124 "Shows the help of available methods for this class"
125 125 },
126 {NULL} /* Sentinel */
126 {NULL, NULL, 0 , NULL} /* Sentinel */
127 127 };
128 128
129 129
130 130 static PyObject *PythonQtMetaObjectWrapper_getattro(PyObject *obj,PyObject *name)
131 131 {
132 132 const char *attributeName;
133 133 PythonQtMetaObjectWrapper *wt = (PythonQtMetaObjectWrapper *)obj;
134 134
135 135 if ((attributeName = PyString_AsString(name)) == NULL) {
136 136 return NULL;
137 137 }
138 138
139 139 PythonQtMemberInfo member = wt->_info->member(attributeName);
140 140 if (member._type == PythonQtMemberInfo::EnumValue) {
141 141 return PyInt_FromLong(member._enumValue);
142 142 }
143 143 if (member._type == PythonQtMemberInfo::Slot && member._slot->isClassDecorator()) {
144 144 return PythonQtSlotFunction_New(member._slot, obj, NULL);
145 145 }
146 146
147 147 // look for the interal methods (className(), help())
148 148 PyObject* internalMethod = Py_FindMethod( PythonQtMetaObjectWrapper_methods, obj, (char*)attributeName);
149 149 if (internalMethod) {
150 150 return internalMethod;
151 151 }
152 152 PyErr_Clear();
153 153
154 154 if (qstrcmp(attributeName, "__dict__")==0) {
155 155 QStringList l = wt->_info->memberList(true);
156 156 PyObject* dict = PyDict_New();
157 157 foreach (QString name, l) {
158 158 //PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
159 159 PyDict_SetItemString(dict, name.toLatin1().data(), Py_None);
160 160 //Py_DECREF(o);
161 161 }
162 162 return dict;
163 163 }
164 164
165 165 QString error = QString(wt->_info->className()) + " has no attribute named '" + QString(attributeName) + "'";
166 166 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
167 167 return NULL;
168 168 }
169 169
170 170 static PyObject * PythonQtMetaObjectWrapper_repr(PyObject * obj)
171 171 {
172 172 PythonQtMetaObjectWrapper* wt = (PythonQtMetaObjectWrapper*)obj;
173 173 if (wt->_info->isCPPWrapper()) {
174 174 return PyString_FromFormat("%s Class (C++ wrapped by %s)", wt->_info->className(), wt->_info->metaObject()->className());
175 175 } else {
176 176 return PyString_FromFormat("%s Class", wt->_info->className());
177 177 }
178 178 }
179 179
180 180 static int PythonQtMetaObjectWrapper_compare(PyObject * obj1, PyObject * obj2)
181 181 {
182 182 if (obj1->ob_type == &PythonQtMetaObjectWrapper_Type &&
183 183 obj2->ob_type == &PythonQtMetaObjectWrapper_Type) {
184 184
185 185 PythonQtMetaObjectWrapper* w1 = (PythonQtMetaObjectWrapper*)obj1;
186 186 PythonQtMetaObjectWrapper* w2 = (PythonQtMetaObjectWrapper*)obj2;
187 187 if (w1->_info == w2->_info) {
188 188 return 0;
189 189 } else {
190 190 return -1;
191 191 }
192 192 } else {
193 193 return -1;
194 194 }
195 195 }
196 196
197 197 static long PythonQtMetaObjectWrapper_hash(PythonQtMetaObjectWrapper *obj)
198 198 {
199 199 return reinterpret_cast<long>(obj->_info);
200 200 }
201 201
202 202 PyTypeObject PythonQtMetaObjectWrapper_Type = {
203 203 PyObject_HEAD_INIT(NULL)
204 204 0, /*ob_size*/
205 205 "PythonQt.PythonQtMetaObjectWrapper", /*tp_name*/
206 206 sizeof(PythonQtMetaObjectWrapper), /*tp_basicsize*/
207 207 0, /*tp_itemsize*/
208 208 (destructor)PythonQtMetaObjectWrapper_dealloc, /*tp_dealloc*/
209 209 0, /*tp_print*/
210 210 0, /*tp_getattr*/
211 211 0, /*tp_setattr*/
212 212 PythonQtMetaObjectWrapper_compare, /*tp_compare*/
213 213 PythonQtMetaObjectWrapper_repr, /*tp_repr*/
214 214 0, /*tp_as_number*/
215 215 0, /*tp_as_sequence*/
216 216 0, /*tp_as_mapping*/
217 217 (hashfunc)PythonQtMetaObjectWrapper_hash, /*tp_hash */
218 218 PythonQtMetaObjectWrapper_call, /*tp_call*/
219 219 0, /*tp_str*/
220 220 PythonQtMetaObjectWrapper_getattro, /*tp_getattro*/
221 221 0, /*tp_setattro*/
222 222 0, /*tp_as_buffer*/
223 223 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
224 224 "PythonQtMetaObjectWrapper object", /* tp_doc */
225 225 0, /* tp_traverse */
226 226 0, /* tp_clear */
227 227 0, /* tp_richcompare */
228 228 0, /* tp_weaklistoffset */
229 229 0, /* tp_iter */
230 230 0, /* tp_iternext */
231 231 0, /* tp_methods */
232 232 0, /* tp_members */
233 233 0, /* tp_getset */
234 234 0, /* tp_base */
235 235 0, /* tp_dict */
236 236 0, /* tp_descr_get */
237 237 0, /* tp_descr_set */
238 238 0, /* tp_dictoffset */
239 239 (initproc)PythonQtMetaObjectWrapper_init, /* tp_init */
240 240 0, /* tp_alloc */
241 241 PythonQtMetaObjectWrapper_new, /* tp_new */
242 242 };
243 243
244 244 //-------------------------------------------------------
245 245
@@ -1,76 +1,79
1 1 #ifndef _PYTHONQTMETAOBJECTWRAPPER_H
2 2 #define _PYTHONQTMETAOBJECTWRAPPER_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 PythonQtMetaObjectWrapper.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 <Python.h>
46 46
47 47 #include "structmember.h"
48 48 #include "methodobject.h"
49 49 #include "compile.h"
50 50 #include "eval.h"
51 51 #include <QString>
52 52
53 53 class PythonQtClassInfo;
54 54 class QObject;
55 55 struct QMetaObject;
56 56
57 57 extern PyTypeObject PythonQtMetaObjectWrapper_Type;
58 58
59 59 //---------------------------------------------------------------
60 60 //! a Python wrapper object for Qt meta objects
61 61 typedef struct {
62 62 PyObject_HEAD
63 63
64 64 //! the class information (which contains the meta object as well)
65 65 PythonQtClassInfo* _info;
66 66
67 67 } PythonQtMetaObjectWrapper;
68 68
69 69 //---------------------------------------------------------------
70 70 // an abstact class for handling construction of objects
71 71 class PythonQtConstructorHandler {
72 72 public:
73 //! get rid of warnings
74 virtual ~PythonQtConstructorHandler() {}
75
73 76 virtual QObject* create(const QMetaObject* meta, PyObject *args, PyObject *kw, QString& error) = 0;
74 77 };
75 78
76 79 #endif No newline at end of file
@@ -1,134 +1,135
1 1 #ifndef _PYTHONQTMISC_H
2 2 #define _PYTHONQTMISC_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 PythonQtMisc.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
46 46 #include <QList>
47 47
48 48 #define PythonQtValueStorage_ADD_VALUE(store, type, value, ptr) \
49 49 { type* item = (type*)store.nextValuePtr(); \
50 50 *item = value; \
51 51 ptr = (void*)item; \
52 52 }
53 53
54 54 //! stores a position in the PythonQtValueStorage
55 55 class PythonQtValueStoragePosition {
56 56
57 57 public:
58 58 PythonQtValueStoragePosition() { chunkIdx = 0; chunkOffset = 0; }
59 59
60 60 int chunkIdx;
61 61 int chunkOffset;
62 62
63 63 };
64 64
65 65 //! a helper class that stores basic C++ value types in chunks
66 66 template <typename T, int chunkEntries> class PythonQtValueStorage
67 67 {
68 68 public:
69 69 PythonQtValueStorage() {
70 70 _chunkIdx = 0;
71 71 _chunkOffset = 0;
72 72 _currentChunk = new T[chunkEntries];
73 73 _chunks.append(_currentChunk);
74 74 };
75 75
76 76 //! clear all memory
77 77 void clear() {
78 78 T* chunk;
79 79 foreach(chunk, _chunks) {
80 80 delete[]chunk;
81 81 }
82 _chunks.clear();
82 83 }
83 84
84 85 //! reset the storage to 0 (without freeing memory, thus caching old entries for reuse)
85 86 void reset() {
86 87 _chunkIdx = 0;
87 88 _chunkOffset = 0;
88 89 _currentChunk = _chunks.at(0);
89 90 }
90 91
91 92 //! get the current position to be restored with setPos
92 93 void getPos(PythonQtValueStoragePosition & pos) {
93 94 pos.chunkIdx = _chunkIdx;
94 95 pos.chunkOffset = _chunkOffset;
95 96 }
96 97
97 98 //! set the current position (without freeing memory, thus caching old entries for reuse)
98 99 void setPos(const PythonQtValueStoragePosition& pos) {
99 100 _chunkOffset = pos.chunkOffset;
100 101 if (_chunkIdx != pos.chunkIdx) {
101 102 _chunkIdx = pos.chunkIdx;
102 103 _currentChunk = _chunks.at(_chunkIdx);
103 104 }
104 105 }
105 106
106 107 //! add one default constructed value and return the pointer to it
107 108 T* nextValuePtr() {
108 109 if (_chunkOffset>=chunkEntries) {
109 110 _chunkIdx++;
110 111 if (_chunkIdx >= _chunks.size()) {
111 112 T* newChunk = new T[chunkEntries];
112 113 _chunks.append(newChunk);
113 114 _currentChunk = newChunk;
114 115 } else {
115 116 _currentChunk = _chunks.at(_chunkIdx);
116 117 }
117 118 _chunkOffset = 0;
118 119 }
119 120 T* newEntry = _currentChunk + _chunkOffset;
120 121 _chunkOffset++;
121 122 return newEntry;
122 123 };
123 124
124 125 private:
125 126 QList<T*> _chunks;
126 127
127 128 int _chunkIdx;
128 129 int _chunkOffset;
129 130 T* _currentChunk;
130 131
131 132 };
132 133
133 134
134 135 #endif
@@ -1,450 +1,454
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 PythonQtSlot.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 "PythonQtSlot.h"
44 44 #include "PythonQtWrapper.h"
45 45 #include "PythonQtClassInfo.h"
46 46 #include "PythonQtMisc.h"
47 47 #include "PythonQtConversion.h"
48 48 #include <iostream>
49 49
50 50 #define PYTHONQT_MAX_ARGS 32
51 51
52 52
53 53 PyObject* PythonQtCallSlot(QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, bool isVariantCall, void* firstArgument)
54 54 {
55 55 if (isVariantCall && info->isInstanceDecorator()) return NULL;
56 56
57 57 static unsigned int recursiveEntry = 0;
58 58
59 59 // store the current storage position, so that we can get back to this state after a slot is called
60 60 // (do this locally, so that we have all positions on the stack
61 61 PythonQtValueStoragePosition globalValueStoragePos;
62 62 PythonQtValueStoragePosition globalPtrStoragePos;
63 63 PythonQtValueStoragePosition globalVariantStoragePos;
64 64 PythonQtConv::global_valueStorage.getPos(globalValueStoragePos);
65 65 PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos);
66 66 PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos);
67 67
68 68 recursiveEntry++;
69 69
70 70 // the arguments that are passed to qt_metacall
71 71 void* argList[PYTHONQT_MAX_ARGS];
72 72 PyObject* result = NULL;
73 73 int argc = info->parameterCount();
74 74 const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters();
75 75
76 76 bool returnValueIsEnum = false;
77 77 const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);
78 78 // set return argument to NULL
79 79 argList[0] = NULL;
80 80
81 81 if (returnValueParam.typeId != QMetaType::Void) {
82 82 // extra handling of enum return value
83 83 if (!returnValueParam.isPointer && returnValueParam.typeId == PythonQtMethodInfo::Unknown) {
84 84 returnValueIsEnum = PythonQt::priv()->isEnumType(objectToCall->metaObject(), returnValueParam.name);
85 85 if (returnValueIsEnum) {
86 86 // create enum return value
87 87 PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, argList[0]);
88 88 }
89 89 }
90 90 if (argList[0]==NULL) {
91 91 // create empty default value for the return value
92 92 argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);
93 93 }
94 94 }
95 95
96 96 const QMetaObject* meta = objectToCall?objectToCall->metaObject():NULL;
97 97 bool ok = true;
98 98 bool skipFirst = false;
99 99 if (info->isInstanceDecorator() || isVariantCall) {
100 100 skipFirst = true;
101 101 if (!firstArgument) {
102 102 argList[1] = &objectToCall;
103 103 } else {
104 104 // for the variant call we take the ptr to the variant data, for decorators on CPP objects, we take the cpp ptr
105 105 argList[1] = &firstArgument;
106 106 }
107 107 if (ok) {
108 108 for (int i = 2; i<argc && ok; i++) {
109 109 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
110 110 //std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
111 111 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, meta);
112 112 if (argList[i]==NULL) {
113 113 ok = false;
114 114 break;
115 115 }
116 116 }
117 117 }
118 118 } else {
119 119 for (int i = 1; i<argc && ok; i++) {
120 120 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
121 121 //std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
122 122 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, meta);
123 123 if (argList[i]==NULL) {
124 124 ok = false;
125 125 break;
126 126 }
127 127 }
128 128 }
129 129
130 130 if (ok) {
131 131 (info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
132 132
133 133 if (argList[0] || returnValueParam.typeId == QMetaType::Void) {
134 134 if (!returnValueIsEnum) {
135 135 result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]);
136 136 } else {
137 137 result = PyInt_FromLong(*((unsigned int*)argList[0]));
138 138 }
139 139 } else {
140 140 QString e = QString("Called ") + info->fullSignature(skipFirst) + ", return type is ignored because it is unknown to PythonQt.";
141 141 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
142 142 result = NULL;
143 143 }
144 144 }
145 145 recursiveEntry--;
146 146
147 147 // reset the parameter storage position to the stored pos to "pop" the parameter stack
148 148 PythonQtConv::global_valueStorage.setPos(globalValueStoragePos);
149 149 PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos);
150 150 PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos);
151 151
152 152 // NOTE: it is important to only return here, otherwise the stack will not be popped!!!
153 153 return result;
154 154 }
155 155
156 156 //-----------------------------------------------------------------------------------
157 157
158 158 static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL;
159 159
160 160 PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw)
161 161 {
162 162 PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func;
163 163 PythonQtSlotInfo* info = f->m_ml;
164 164 if (f->m_self->ob_type == &PythonQtWrapper_Type) {
165 165 PythonQtWrapper* self = (PythonQtWrapper*) f->m_self;
166 166 return PythonQtSlotFunction_CallImpl(self->_obj, info, args, kw, false, self->_wrappedPtr);
167 167 } else if (f->m_self->ob_type == &PythonQtVariantWrapper_Type) {
168 168 PythonQtVariantWrapper* self = (PythonQtVariantWrapper*) f->m_self;
169 169 if (!info->isClassDecorator()) {
170 170 return PythonQtSlotFunction_CallImpl(self->_wrapper, info, args, kw, true, (void*)self->_variant->constData());
171 171 } else {
172 172 return PythonQtSlotFunction_CallImpl(NULL, info, args, kw);
173 173 }
174 174 } else if (f->m_self->ob_type == &PythonQtMetaObjectWrapper_Type) {
175 175 return PythonQtSlotFunction_CallImpl(NULL, info, args, kw);
176 176 } else {
177 177 return NULL;
178 178 }
179 179 }
180 180
181 PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject *kw, bool isVariantCall, void* firstArg)
181 PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, bool isVariantCall, void* firstArg)
182 182 {
183 183 int argc = PyTuple_Size(args);
184 184
185 185 #ifdef PYTHONQT_DEBUG
186 186 std::cout << "called " << info->metaMethod()->typeName() << " " << info->metaMethod()->signature() << std::endl;
187 187 #endif
188 188
189 189 PyObject* r = NULL;
190 190
191 191 if (info->nextInfo()) {
192 192 // overloaded slot call, try on all slots with strict conversion first
193 193 PythonQtSlotInfo* i = info;
194 194 while (i && r==NULL) {
195 195 bool skipFirst = (i->isInstanceDecorator() || isVariantCall);
196 196 if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
197 197 PyErr_Clear();
198 198 r = PythonQtCallSlot(objectToCall, args, true, i, isVariantCall, firstArg);
199 199 if (PyErr_Occurred()) break;
200 200 }
201 201 i = i->nextInfo();
202 202 }
203 203 if (!r) {
204 204 // try on all slots with non-strict conversion
205 205 i = info;
206 206 while (i && r==NULL) {
207 207 bool skipFirst = (i->isInstanceDecorator() || isVariantCall);
208 208 if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
209 209 PyErr_Clear();
210 210 r = PythonQtCallSlot(objectToCall, args, false, i, isVariantCall, firstArg);
211 211 if (PyErr_Occurred()) break;
212 212 }
213 213 i = i->nextInfo();
214 214 }
215 215 }
216 216 if (r==NULL && !PyErr_Occurred()) {
217 217 QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n");
218 218 PythonQtSlotInfo* i = info;
219 219 while (i) {
220 220 bool skipFirst = (i->isInstanceDecorator() || isVariantCall);
221 221 e += QString(i->fullSignature(skipFirst)) + "\n";
222 222 i = i->nextInfo();
223 223 }
224 224 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
225 225 }
226 226 } else {
227 227 // simple (non-overloaded) slot call
228 228 bool skipFirst = (info->isInstanceDecorator() || isVariantCall);
229 229 if (info->parameterCount()-1-(skipFirst?1:0) == argc) {
230 230 PyErr_Clear();
231 231 r = PythonQtCallSlot(objectToCall, args, false, info, isVariantCall, firstArg);
232 232 if (r==NULL && !PyErr_Occurred()) {
233 233 QString e = QString("Called ") + info->fullSignature(skipFirst) + " with wrong arguments: " + PythonQtConv::PyObjGetString(args);
234 234 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
235 235 }
236 236 } else {
237 237 QString e = QString("Called ") + info->fullSignature(skipFirst) + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args);
238 238 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
239 239 }
240 240 }
241 241
242 242 return r;
243 243 }
244 244
245 245 PyObject *
246 246 PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module)
247 247 {
248 248 PythonQtSlotFunctionObject *op;
249 249 op = pythonqtslot_free_list;
250 250 if (op != NULL) {
251 251 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self);
252 252 PyObject_INIT(op, &PythonQtSlotFunction_Type);
253 253 }
254 254 else {
255 255 op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type);
256 256 if (op == NULL)
257 257 return NULL;
258 258 }
259 259 op->m_ml = ml;
260 260 Py_XINCREF(self);
261 261 op->m_self = self;
262 262 Py_XINCREF(module);
263 263 op->m_module = module;
264 264 PyObject_GC_Track(op);
265 265 return (PyObject *)op;
266 266 }
267 267
268 268 PythonQtSlotInfo*
269 269 PythonQtSlotFunction_GetSlotInfo(PyObject *op)
270 270 {
271 271 if (!PythonQtSlotFunction_Check(op)) {
272 272 PyErr_BadInternalCall();
273 273 return NULL;
274 274 }
275 275 return ((PythonQtSlotFunctionObject *)op) -> m_ml;
276 276 }
277 277
278 278 PyObject *
279 279 PythonQtSlotFunction_GetSelf(PyObject *op)
280 280 {
281 281 if (!PythonQtSlotFunction_Check(op)) {
282 282 PyErr_BadInternalCall();
283 283 return NULL;
284 284 }
285 285 return ((PythonQtSlotFunctionObject *)op) -> m_self;
286 286 }
287 287
288 288 /* Methods (the standard built-in methods, that is) */
289 289
290 290 static void
291 291 meth_dealloc(PythonQtSlotFunctionObject *m)
292 292 {
293 293 PyObject_GC_UnTrack(m);
294 294 Py_XDECREF(m->m_self);
295 295 Py_XDECREF(m->m_module);
296 296 m->m_self = (PyObject *)pythonqtslot_free_list;
297 297 pythonqtslot_free_list = m;
298 298 }
299 299
300 300 static PyObject *
301 meth_get__doc__(PythonQtSlotFunctionObject *m, void *closure)
301 meth_get__doc__(PythonQtSlotFunctionObject * /*m*/, void * /*closure*/)
302 302 {
303 303 Py_INCREF(Py_None);
304 304 return Py_None;
305 305 }
306 306
307 307 static PyObject *
308 meth_get__name__(PythonQtSlotFunctionObject *m, void *closure)
308 meth_get__name__(PythonQtSlotFunctionObject *m, void * /*closure*/)
309 309 {
310 310 return PyString_FromString(m->m_ml->metaMethod()->signature());
311 311 }
312 312
313 313 static int
314 314 meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg)
315 315 {
316 316 int err;
317 317 if (m->m_self != NULL) {
318 318 err = visit(m->m_self, arg);
319 319 if (err)
320 320 return err;
321 321 }
322 322 if (m->m_module != NULL) {
323 323 err = visit(m->m_module, arg);
324 324 if (err)
325 325 return err;
326 326 }
327 327 return 0;
328 328 }
329 329
330 330 static PyObject *
331 meth_get__self__(PythonQtSlotFunctionObject *m, void *closure)
331 meth_get__self__(PythonQtSlotFunctionObject *m, void * /*closure*/)
332 332 {
333 333 PyObject *self;
334 334 if (PyEval_GetRestricted()) {
335 335 PyErr_SetString(PyExc_RuntimeError,
336 336 "method.__self__ not accessible in restricted mode");
337 337 return NULL;
338 338 }
339 339 self = m->m_self;
340 340 if (self == NULL)
341 341 self = Py_None;
342 342 Py_INCREF(self);
343 343 return self;
344 344 }
345 345
346 346 static PyGetSetDef meth_getsets [] = {
347 347 {"__doc__", (getter)meth_get__doc__, NULL, NULL},
348 348 {"__name__", (getter)meth_get__name__, NULL, NULL},
349 349 {"__self__", (getter)meth_get__self__, NULL, NULL},
350 {0}
350 {NULL, NULL, NULL,NULL},
351 351 };
352 352
353 #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6
354 #define PY_WRITE_RESTRICTED WRITE_RESTRICTED
355 #endif
356
353 357 #define OFF(x) offsetof(PythonQtSlotFunctionObject, x)
354 358
355 359 static PyMemberDef meth_members[] = {
356 {"__module__", T_OBJECT, OFF(m_module), WRITE_RESTRICTED},
360 {"__module__", T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED},
357 361 {NULL}
358 362 };
359 363
360 364 static PyObject *
361 365 meth_repr(PythonQtSlotFunctionObject *m)
362 366 {
363 367 return PyString_FromFormat("<built-in qt slot %s of %s object at %p>",
364 368 m->m_ml->metaMethod()->signature(),
365 369 m->m_self->ob_type->tp_name,
366 370 m->m_self);
367 371 }
368 372
369 373 static int
370 374 meth_compare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b)
371 375 {
372 376 if (a->m_self != b->m_self)
373 377 return (a->m_self < b->m_self) ? -1 : 1;
374 378 if (a->m_ml == b->m_ml)
375 379 return 0;
376 380 if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0)
377 381 return -1;
378 382 else
379 383 return 1;
380 384 }
381 385
382 386 static long
383 387 meth_hash(PythonQtSlotFunctionObject *a)
384 388 {
385 389 long x,y;
386 390 if (a->m_self == NULL)
387 391 x = 0;
388 392 else {
389 393 x = PyObject_Hash(a->m_self);
390 394 if (x == -1)
391 395 return -1;
392 396 }
393 397 y = _Py_HashPointer((void*)(a->m_ml));
394 398 if (y == -1)
395 399 return -1;
396 400 x ^= y;
397 401 if (x == -1)
398 402 x = -2;
399 403 return x;
400 404 }
401 405
402 406
403 407 PyTypeObject PythonQtSlotFunction_Type = {
404 408 PyObject_HEAD_INIT(&PyType_Type)
405 409 0,
406 410 "builtin_qt_slot",
407 411 sizeof(PythonQtSlotFunctionObject),
408 412 0,
409 413 (destructor)meth_dealloc, /* tp_dealloc */
410 414 0, /* tp_print */
411 415 0, /* tp_getattr */
412 416 0, /* tp_setattr */
413 417 (cmpfunc)meth_compare, /* tp_compare */
414 418 (reprfunc)meth_repr, /* tp_repr */
415 419 0, /* tp_as_number */
416 420 0, /* tp_as_sequence */
417 421 0, /* tp_as_mapping */
418 422 (hashfunc)meth_hash, /* tp_hash */
419 423 PythonQtSlotFunction_Call, /* tp_call */
420 424 0, /* tp_str */
421 425 PyObject_GenericGetAttr, /* tp_getattro */
422 426 0, /* tp_setattro */
423 427 0, /* tp_as_buffer */
424 428 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
425 429 0, /* tp_doc */
426 430 (traverseproc)meth_traverse, /* tp_traverse */
427 431 0, /* tp_clear */
428 432 0, /* tp_richcompare */
429 433 0, /* tp_weaklistoffset */
430 434 0, /* tp_iter */
431 435 0, /* tp_iternext */
432 436 0, /* tp_methods */
433 437 meth_members, /* tp_members */
434 438 meth_getsets, /* tp_getset */
435 439 0, /* tp_base */
436 440 0, /* tp_dict */
437 441 };
438 442
439 443 /* Clear out the free list */
440 444
441 445 void
442 446 PythonQtSlotFunction_Fini(void)
443 447 {
444 448 while (pythonqtslot_free_list) {
445 449 PythonQtSlotFunctionObject *v = pythonqtslot_free_list;
446 450 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(v->m_self);
447 451 PyObject_GC_Del(v);
448 452 }
449 453 }
450 454
@@ -1,136 +1,136
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 PythonQtStdOut.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 "PythonQtStdOut.h"
43 43
44 static PyObject *PythonQtStdOutRedirect_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
44 static PyObject *PythonQtStdOutRedirect_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
45 45 {
46 46 PythonQtStdOutRedirect *self;
47 47 self = (PythonQtStdOutRedirect *)type->tp_alloc(type, 0);
48 48
49 49 self->softspace = 0;
50 50 self->_cb = NULL;
51 51
52 52 return (PyObject *)self;
53 53 }
54 54
55 55 static PyObject *PythonQtStdOutRedirect_write(PyObject *self, PyObject *args)
56 56 {
57 57 PythonQtStdOutRedirect* s = (PythonQtStdOutRedirect*)self;
58 58 if (s->_cb) {
59 59 char *string;
60 60 if (!PyArg_ParseTuple(args, "s", &string))
61 61 return NULL;
62 62
63 63 if (s->softspace > 0) {
64 64 (*s->_cb)(QString(""));
65 65 s->softspace = 0;
66 66 }
67 67
68 68 (*s->_cb)(QString(string));
69 69 }
70 70 return Py_BuildValue("");
71 71 }
72 72
73 static PyObject *PythonQtStdOutRedirect_flush(PyObject *self, PyObject *args)
73 static PyObject *PythonQtStdOutRedirect_flush(PyObject * /*self*/, PyObject * /*args*/)
74 74 {
75 75 return Py_BuildValue("");
76 76 }
77 77
78 78
79 79
80 80 static PyMethodDef PythonQtStdOutRedirect_methods[] = {
81 81 {"write", (PyCFunction)PythonQtStdOutRedirect_write, METH_VARARGS,
82 82 "redirect the writing to a callback"},
83 83 {"flush", (PyCFunction)PythonQtStdOutRedirect_flush, METH_VARARGS,
84 84 "flush the output, currently not implemented but needed for logging framework"
85 85 },
86 {NULL} /* Sentinel */
86 {NULL, NULL, 0 , NULL} /* sentinel */
87 87 };
88 88
89 89 static PyMemberDef PythonQtStdOutRedirect_members[] = {
90 90 {"softspace", T_INT, offsetof(PythonQtStdOutRedirect, softspace), 0,
91 91 "soft space flag"
92 92 },
93 93 {NULL} /* Sentinel */
94 94 };
95 95
96 96 PyTypeObject PythonQtStdOutRedirectType = {
97 97 PyObject_HEAD_INIT(NULL)
98 98 0, /*ob_size*/
99 99 "PythonQtStdOutRedirect", /*tp_name*/
100 100 sizeof(PythonQtStdOutRedirect), /*tp_basicsize*/
101 101 0, /*tp_itemsize*/
102 102 0, /*tp_dealloc*/
103 103 0, /*tp_print*/
104 104 0, /*tp_getattr*/
105 105 0, /*tp_setattr*/
106 106 0, /*tp_compare*/
107 107 0, /*tp_repr*/
108 108 0, /*tp_as_number*/
109 109 0, /*tp_as_sequence*/
110 110 0, /*tp_as_mapping*/
111 111 0, /*tp_hash */
112 112 0, /*tp_call*/
113 113 0, /*tp_str*/
114 114 0, /*tp_getattro*/
115 115 0, /*tp_setattro*/
116 116 0, /*tp_as_buffer*/
117 117 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
118 118 "PythonQtStdOutRedirect", /* tp_doc */
119 119 0, /* tp_traverse */
120 120 0, /* tp_clear */
121 121 0, /* tp_richcompare */
122 122 0, /* tp_weaklistoffset */
123 123 0, /* tp_iter */
124 124 0, /* tp_iternext */
125 125 PythonQtStdOutRedirect_methods, /* tp_methods */
126 126 PythonQtStdOutRedirect_members, /* tp_members */
127 127 0, /* tp_getset */
128 128 0, /* tp_base */
129 129 0, /* tp_dict */
130 130 0, /* tp_descr_get */
131 131 0, /* tp_descr_set */
132 132 0, /* tp_dictoffset */
133 133 0, /* tp_init */
134 134 0, /* tp_alloc */
135 135 PythonQtStdOutRedirect_new, /* tp_new */
136 136 };
@@ -1,271 +1,271
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 PythonQtVariantWrapper.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 "PythonQtVariantWrapper.h"
43 43 #include <QObject>
44 44 #include <QDate>
45 45 #include <QDateTime>
46 46 #include <QTime>
47 47 #include "PythonQt.h"
48 48 #include "PythonQtSlot.h"
49 49 #include "PythonQtClassInfo.h"
50 50 #include "PythonQtConversion.h"
51 51
52 52 static void PythonQtVariantWrapper_dealloc(PythonQtVariantWrapper* self)
53 53 {
54 54 if (self->_variant) {
55 55 delete self->_variant;
56 56 self->_variant = NULL;
57 57 }
58 58 self->ob_type->tp_free((PyObject*)self);
59 59 }
60 60
61 static PyObject* PythonQtVariantWrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
61 static PyObject* PythonQtVariantWrapper_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
62 62 {
63 63 PythonQtVariantWrapper *self;
64 64
65 65 self = (PythonQtVariantWrapper *)type->tp_alloc(type, 0);
66 66 if (self != NULL) {
67 67 self->_variant = new QVariant();
68 68 self->_info = NULL;
69 69 }
70 70 return (PyObject *)self;
71 71 }
72 72
73 static int PythonQtVariantWrapper_init(PythonQtVariantWrapper *self, PyObject *args, PyObject *kwds)
73 static int PythonQtVariantWrapper_init(PythonQtVariantWrapper * /*self*/, PyObject * /*args*/, PyObject * /*kwds*/)
74 74 {
75 75 return 0;
76 76 }
77 77
78 78 static PyObject *PythonQtVariantWrapper_classname(PythonQtVariantWrapper* type)
79 79 {
80 80 return PyString_FromString(type->_info->className());
81 81 }
82 82
83 83 static PyObject *PythonQtVariantWrapper_help(PythonQtVariantWrapper* type)
84 84 {
85 85 return PythonQt::self()->helpCalled(type->_info);
86 86 }
87 87
88 88
89 89 static PyMethodDef PythonQtVariantWrapper_methods[] = {
90 90 {"className", (PyCFunction)PythonQtVariantWrapper_classname, METH_NOARGS,
91 91 "Return the classname of the object"
92 92 },
93 93 {"help", (PyCFunction)PythonQtVariantWrapper_help, METH_NOARGS,
94 94 "Shows the help of available methods for this class"
95 95 },
96 {NULL} /* Sentinel */
96 {NULL,NULL,0,NULL} /* Sentinel */
97 97 };
98 98
99 99
100 100 static PyObject *PythonQtVariantWrapper_getattro(PyObject *obj,PyObject *name)
101 101 {
102 102 const char *attributeName;
103 103 PythonQtVariantWrapper *wt = (PythonQtVariantWrapper *)obj;
104 104
105 105 if ((attributeName = PyString_AsString(name)) == NULL) {
106 106 return NULL;
107 107 }
108 108
109 109 if (wt->_wrapper && wt->_info) {
110 110 PythonQtMemberInfo member = wt->_info->member(attributeName);
111 111 if (member._type == PythonQtMemberInfo::Slot) {
112 112 return PythonQtSlotFunction_New(member._slot, obj, NULL);
113 113 } else if (member._type == PythonQtMemberInfo::EnumValue) {
114 114 return PyInt_FromLong(member._enumValue);
115 115 }
116 116 }
117 117
118 118 // look for the interal methods (className(), help())
119 119 PyObject* internalMethod = Py_FindMethod( PythonQtVariantWrapper_methods, obj, (char*)attributeName);
120 120 if (internalMethod) {
121 121 return internalMethod;
122 122 }
123 123 PyErr_Clear();
124 124
125 125 if (qstrcmp(attributeName, "__dict__")==0) {
126 126 QStringList l = wt->_info->memberList(false);
127 127 PyObject* dict = PyDict_New();
128 128 foreach (QString name, l) {
129 129 //PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
130 130 PyDict_SetItemString(dict, name.toLatin1().data(), Py_None);
131 131 //Py_DECREF(o);
132 132 }
133 133 return dict;
134 134 }
135 135
136 136 QString error = QString(wt->_variant->typeName()) + " has no attribute named '" + QString(attributeName) + "'";
137 137 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
138 138
139 139 return NULL;
140 140 }
141 141
142 142 QString qVariantToString(const QVariant& v) {
143 143 QString r;
144 144 switch (v.type()) {
145 145 case QVariant::Size:
146 146 r = QString::number(v.toSize().width()) + ", " + QString::number(v.toSize().height());
147 147 break;
148 148 case QVariant::SizeF:
149 149 r = QString::number(v.toSizeF().width()) + ", " + QString::number(v.toSizeF().height());
150 150 break;
151 151 case QVariant::Point:
152 152 r = QString::number(v.toPoint().x()) + ", " + QString::number(v.toPoint().y());
153 153 break;
154 154 case QVariant::PointF:
155 155 r = QString::number(v.toPointF().x()) + ", " + QString::number(v.toPointF().y());
156 156 break;
157 157 case QVariant::Rect:
158 158 r = QString::number(v.toRect().x()) + ", " + QString::number(v.toRect().y());
159 159 r += ", " + QString::number(v.toRect().width()) + ", " + QString::number(v.toRect().height());
160 160 break;
161 161 case QVariant::RectF:
162 162 r = QString::number(v.toRectF().x()) + ", " + QString::number(v.toRectF().y());
163 163 r += ", " + QString::number(v.toRectF().width()) + ", " + QString::number(v.toRectF().height());
164 164 break;
165 165 case QVariant::Date:
166 166 r = v.toDate().toString(Qt::ISODate);
167 167 break;
168 168 case QVariant::DateTime:
169 169 r = v.toDateTime().toString(Qt::ISODate);
170 170 break;
171 171 case QVariant::Time:
172 172 r = v.toTime().toString(Qt::ISODate);
173 173 break;
174 174 case QVariant::Pixmap:
175 175 {
176 176 QPixmap p = qvariant_cast<QPixmap>(v);
177 177 r = QString("Pixmap ") + QString::number(p.width()) + ", " + QString::number(p.height());
178 178 }
179 179 break;
180 180 case QVariant::Image:
181 181 {
182 182 QImage img = qvariant_cast<QImage>(v);
183 183 r = QString("Image ") + QString::number(img.width()) + ", " + QString::number(img.height());
184 184 }
185 185 break;
186 186 //TODO: add more printing for other variant types
187 187 default:
188 188 r = v.toString();
189 189 }
190 190 return r;
191 191 }
192 192
193 193 static PyObject * PythonQtVariantWrapper_str(PyObject * obj)
194 194 {
195 195 PythonQtVariantWrapper* wt = (PythonQtVariantWrapper*)obj;
196 196 QString val = qVariantToString(*wt->_variant);
197 197 if (val.isEmpty()) {
198 198 val = wt->_variant->typeName();
199 199 }
200 200 return PyString_FromFormat("%s", val.toLatin1().constData());
201 201 }
202 202
203 203 static PyObject * PythonQtVariantWrapper_repr(PyObject * obj)
204 204 {
205 205 PythonQtVariantWrapper* wt = (PythonQtVariantWrapper*)obj;
206 206 QString val = qVariantToString(*wt->_variant);
207 207 return PyString_FromFormat("%s(%s)", wt->_variant->typeName(), val.toLatin1().constData());
208 208 }
209 209
210 210 static int PythonQtVariantWrapper_compare(PyObject * obj1, PyObject * obj2)
211 211 {
212 212 if (obj1->ob_type == &PythonQtVariantWrapper_Type &&
213 213 obj2->ob_type == &PythonQtVariantWrapper_Type) {
214 214
215 215 PythonQtVariantWrapper* w1 = (PythonQtVariantWrapper*)obj1;
216 216 PythonQtVariantWrapper* w2 = (PythonQtVariantWrapper*)obj2;
217 217 if (*w1->_variant == *w2->_variant) {
218 218 return 0;
219 219 } else {
220 220 return -1;
221 221 }
222 222 } else {
223 223 return -1;
224 224 }
225 225 }
226 226
227 227
228 228 PyTypeObject PythonQtVariantWrapper_Type = {
229 229 PyObject_HEAD_INIT(NULL)
230 230 0, /*ob_size*/
231 231 "PythonQt.PythonQtVariantWrapper", /*tp_name*/
232 232 sizeof(PythonQtVariantWrapper), /*tp_basicsize*/
233 233 0, /*tp_itemsize*/
234 234 (destructor)PythonQtVariantWrapper_dealloc, /*tp_dealloc*/
235 235 0, /*tp_print*/
236 236 0, /*tp_getattr*/
237 237 0, /*tp_setattr*/
238 238 PythonQtVariantWrapper_compare, /*tp_compare*/
239 239 PythonQtVariantWrapper_repr, /*tp_repr*/
240 240 0, /*tp_as_number*/
241 241 0, /*tp_as_sequence*/
242 242 0, /*tp_as_mapping*/
243 243 0, /*tp_hash */
244 244 0, /*tp_call*/
245 245 PythonQtVariantWrapper_str, /*tp_str*/
246 246 PythonQtVariantWrapper_getattro, /*tp_getattro*/
247 247 0, /*tp_setattro*/
248 248 0, /*tp_as_buffer*/
249 249 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
250 250 "PythonQtVariantWrapper object", /* tp_doc */
251 251 0, /* tp_traverse */
252 252 0, /* tp_clear */
253 253 0, /* tp_richcompare */
254 254 0, /* tp_weaklistoffset */
255 255 0, /* tp_iter */
256 256 0, /* tp_iternext */
257 257 0, /* tp_methods */
258 258 0, /* tp_members */
259 259 0, /* tp_getset */
260 260 0, /* tp_base */
261 261 0, /* tp_dict */
262 262 0, /* tp_descr_get */
263 263 0, /* tp_descr_set */
264 264 0, /* tp_dictoffset */
265 265 (initproc)PythonQtVariantWrapper_init, /* tp_init */
266 266 0, /* tp_alloc */
267 267 PythonQtVariantWrapper_new, /* tp_new */
268 268 };
269 269
270 270 //-------------------------------------------------------
271 271
@@ -1,400 +1,403
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 PythonQtWrapper.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 "PythonQtWrapper.h"
43 43 #include <QObject>
44 44 #include "PythonQt.h"
45 45 #include "PythonQtSlot.h"
46 46 #include "PythonQtClassInfo.h"
47 47 #include "PythonQtConversion.h"
48 48
49 49 static void PythonQtWrapper_dealloc(PythonQtWrapper* self)
50 50 {
51 51 if (self->_wrappedPtr) {
52 52
53 53 //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->_info->wrappedClassName().latin1());
54 54
55 55 PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr);
56 56 // we own our qobject, so we delete it now:
57 57 delete self->_obj;
58 58 self->_obj = NULL;
59 59 if (self->_ownedByPythonQt) {
60 60 PythonQtSlotInfo* slot = PythonQt::priv()->getDestructorSlot(self->_info->wrappedCPPClassName());
61 61 if (slot) {
62 62 void* args[2];
63 63 args[0] = NULL;
64 64 args[1] = &self->_wrappedPtr;
65 65 slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, slot->slotIndex(), args);
66 66 self->_wrappedPtr = NULL;
67 67 } else {
68 68 // TODO: print a warning? we can not destroy that object
69 69 }
70 70 }
71 71 } else {
72 72 //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->_info->wrappedClassName().latin1());
73 73 if (self->_objPointerCopy) {
74 74 PythonQt::priv()->removeWrapperPointer(self->_objPointerCopy);
75 75 }
76 76 if (self->_obj) {
77 77 if (self->_ownedByPythonQt) {
78 78 if (!self->_obj->parent()) {
79 79 delete self->_obj;
80 80 }
81 81 } else {
82 82 if (self->_obj->parent()==NULL) {
83 83 // tell someone who is interested that the qobject is no longer wrapped, if it has no parent
84 84 PythonQt::qObjectNoLongerWrappedCB(self->_obj);
85 85 }
86 86 }
87 87 }
88 88 }
89 89 self->_obj = NULL;
90 90 self->_obj.~QPointer<QObject>();
91 91 self->ob_type->tp_free((PyObject*)self);
92 92 }
93 93
94 static PyObject* PythonQtWrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
94 static PyObject* PythonQtWrapper_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
95 95 {
96 96 PythonQtWrapper *self;
97 97
98 98 self = (PythonQtWrapper *)type->tp_alloc(type, 0);
99 99 if (self != NULL) {
100 100 self->_info = NULL;
101 101 new (&self->_obj) QPointer<QObject>();
102 102 self->_wrappedPtr = NULL;
103 103 self->_ownedByPythonQt = false;
104 104 }
105 105 return (PyObject *)self;
106 106 }
107 107
108 static int PythonQtWrapper_init(PythonQtWrapper *self, PyObject *args, PyObject *kwds)
108 static int PythonQtWrapper_init(PythonQtWrapper * /*self*/, PyObject * /*args*/, PyObject * /*kwds*/)
109 109 {
110 110 return 0;
111 111 }
112 112
113 113 static PyObject *PythonQtWrapper_classname(PythonQtWrapper* type)
114 114 {
115 115 return PyString_FromString(type->_info->className());
116 116 }
117 117
118 118 static PyObject *PythonQtWrapper_help(PythonQtWrapper* type)
119 119 {
120 120 return PythonQt::self()->helpCalled(type->_info);
121 121 }
122 122
123 123
124 124 static PyMethodDef PythonQtWrapper_methods[] = {
125 125 {"className", (PyCFunction)PythonQtWrapper_classname, METH_NOARGS,
126 126 "Return the classname of the object"
127 127 },
128 128 {"help", (PyCFunction)PythonQtWrapper_help, METH_NOARGS,
129 129 "Shows the help of available methods for this class"
130 130 },
131 {NULL} /* Sentinel */
131 {NULL, NULL, 0, NULL} /* Sentinel */
132 132 };
133 133
134 134
135 135 static PyObject *PythonQtWrapper_getattro(PyObject *obj,PyObject *name)
136 136 {
137 137 const char *attributeName;
138 138 PythonQtWrapper *wt = (PythonQtWrapper *)obj;
139 139
140 140 if ((attributeName = PyString_AsString(name)) == NULL) {
141 141 return NULL;
142 142 }
143 143
144 144 if (!wt->_obj && !wt->_wrappedPtr) {
145 145 QString error = QString("Trying to read attribute '") + attributeName + "' from a destroyed " + wt->_info->className() + " object";
146 146 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
147 147 return NULL;
148 148 }
149 149
150 150 // mlabDebugConst("Python","get " << attributeName);
151 151
152 152 // TODO: dynamic properties are missing
153 153
154 154 PythonQtMemberInfo member = wt->_info->member(attributeName);
155 155 switch (member._type) {
156 156 case PythonQtMemberInfo::Property:
157 157 if (wt->_obj) {
158 158 return PythonQtConv::QVariantToPyObject(member._property.read(wt->_obj));
159 159 }
160 160 break;
161 161 case PythonQtMemberInfo::Slot:
162 162 return PythonQtSlotFunction_New(member._slot, obj, NULL);
163 163 break;
164 164 case PythonQtMemberInfo::EnumValue:
165 165 return PyInt_FromLong(member._enumValue);
166 166 break;
167 default:
168 // is an invalid type, go on
169 break;
167 170 }
168 171
169 172 // look for the interal methods (className(), help())
170 173 PyObject* internalMethod = Py_FindMethod( PythonQtWrapper_methods, obj, (char*)attributeName);
171 174 if (internalMethod) {
172 175 return internalMethod;
173 176 }
174 177 PyErr_Clear();
175 178
176 179 if (wt->_obj) {
177 180 // look for a child
178 181 QObjectList children = wt->_obj->children();
179 182 for (int i = 0; i < children.count(); i++) {
180 183 QObject *child = children.at(i);
181 184 if (child->objectName() == attributeName) {
182 185 return PythonQt::self()->priv()->wrapQObject(child);
183 186 }
184 187 }
185 188 }
186 189
187 190 if (qstrcmp(attributeName, "__dict__")==0) {
188 191 QStringList l = wt->_info->memberList(false);
189 192 PyObject* dict = PyDict_New();
190 193 foreach (QString name, l) {
191 194 //PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
192 195 PyDict_SetItemString(dict, name.toLatin1().data(), Py_None);
193 196 //Py_DECREF(o);
194 197 }
195 198 // Note: we do not put children into the dict, is would look confusing?!
196 199 return dict;
197 200 }
198 201
199 202
200 203 QString error = QString(wt->_info->className()) + " has no attribute named '" + QString(attributeName) + "'";
201 204 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
202 205 return NULL;
203 206 }
204 207
205 208 static int PythonQtWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
206 209 {
207 210 QString error;
208 211 char *attributeName;
209 212 PythonQtWrapper *wt = (PythonQtWrapper *)obj;
210 213
211 214 if ((attributeName = PyString_AsString(name)) == NULL)
212 215 return -1;
213 216
214 217 if (!wt->_obj) {
215 218 error = QString("Trying to set attribute '") + attributeName + "' on a destroyed " + wt->_info->className() + " object";
216 219 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
217 220 return -1;
218 221 }
219 222
220 223 PythonQtMemberInfo member = wt->_info->member(attributeName);
221 224 if (member._type == PythonQtMemberInfo::Property) {
222 225 QMetaProperty prop = member._property;
223 226 if (prop.isWritable()) {
224 227 QVariant v;
225 228 if (prop.isEnumType()) {
226 229 // this will give us either a string or an int, everything else will probably be an error
227 230 v = PythonQtConv::PyObjToQVariant(value);
228 231 } else {
229 232 int t = prop.userType();
230 233 v = PythonQtConv::PyObjToQVariant(value, t);
231 234 }
232 235 bool success = false;
233 236 if (v.isValid()) {
234 237 success = prop.write(wt->_obj, v);
235 238 }
236 239 if (success) {
237 240 return 0;
238 241 } else {
239 242 error = QString("Property '") + attributeName + "' of type '" +
240 243 prop.typeName() + "' does not accept an object of type "
241 244 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
242 245 }
243 246 } else {
244 247 error = QString("Property '") + attributeName + "' of " + wt->_info->className() + " object is not writable";
245 248 }
246 249 } else {
247 250 if (member._type == PythonQtMemberInfo::Slot) {
248 251 error = QString("Slot '") + attributeName + "' can not be overwritten on " + wt->_info->className() + " object";
249 252 } else if (member._type == PythonQtMemberInfo::EnumValue) {
250 253 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + wt->_info->className() + " object";
251 254 }
252 255 }
253 256
254 257 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
255 258 return -1;
256 259 }
257 260
258 261 static PyObject * PythonQtWrapper_repr(PyObject * obj)
259 262 {
260 263 PythonQtWrapper* wt = (PythonQtWrapper*)obj;
261 264 QObject *qobj = wt->_obj;
262 265 if (wt->_wrappedPtr) {
263 266 if (wt->_obj) {
264 267 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", wt->_info->className(), wt->_wrappedPtr, wt->_obj->metaObject()->className(), qobj);
265 268 } else {
266 269 return PyString_FromFormat("%s (C++ Object %p unwrapped)", wt->_info->className(), wt->_wrappedPtr);
267 270 }
268 271 } else {
269 272 return PyString_FromFormat("%s (QObject %p)", wt->_info->className(), qobj);
270 273 }
271 274 }
272 275
273 276 static int PythonQtWrapper_compare(PyObject * obj1, PyObject * obj2)
274 277 {
275 278 if (obj1->ob_type == &PythonQtWrapper_Type &&
276 279 obj2->ob_type == &PythonQtWrapper_Type) {
277 280
278 281 PythonQtWrapper* w1 = (PythonQtWrapper*)obj1;
279 282 PythonQtWrapper* w2 = (PythonQtWrapper*)obj2;
280 283 if (w1->_wrappedPtr != NULL) {
281 284 if (w1->_wrappedPtr == w1->_wrappedPtr) {
282 285 return 0;
283 286 } else {
284 287 return -1;
285 288 }
286 289 } else if (w1->_obj == w2->_obj) {
287 290 return 0;
288 291 } else {
289 292 return -1;
290 293 }
291 294 } else {
292 295 return -1;
293 296 }
294 297 }
295 298
296 299 static int PythonQtWrapper_nonzero(PyObject *obj)
297 300 {
298 301 PythonQtWrapper* wt = (PythonQtWrapper*)obj;
299 302 return (wt->_wrappedPtr == NULL && wt->_obj == NULL)?0:1;
300 303 }
301 304
302 305
303 306 static long PythonQtWrapper_hash(PythonQtWrapper *obj)
304 307 {
305 308 if (obj->_wrappedPtr != NULL) {
306 309 return reinterpret_cast<long>(obj->_wrappedPtr);
307 310 } else {
308 311 QObject* qobj = obj->_obj; // get pointer from QPointer wrapper
309 312 return reinterpret_cast<long>(qobj);
310 313 }
311 314 }
312 315
313 316
314 317
315 318 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
316 319 static PyNumberMethods PythonQtWrapper_as_number = {
317 320 0, /* nb_add */
318 321 0, /* nb_subtract */
319 322 0, /* nb_multiply */
320 323 0, /* nb_divide */
321 324 0, /* nb_remainder */
322 325 0, /* nb_divmod */
323 326 0, /* nb_power */
324 327 0, /* nb_negative */
325 328 0, /* nb_positive */
326 329 0, /* nb_absolute */
327 330 PythonQtWrapper_nonzero, /* nb_nonzero */
328 331 0, /* nb_invert */
329 332 0, /* nb_lshift */
330 333 0, /* nb_rshift */
331 334 0, /* nb_and */
332 335 0, /* nb_xor */
333 336 0, /* nb_or */
334 337 0, /* nb_coerce */
335 338 0, /* nb_int */
336 339 0, /* nb_long */
337 340 0, /* nb_float */
338 341 0, /* nb_oct */
339 342 0, /* nb_hex */
340 343 0, /* nb_inplace_add */
341 344 0, /* nb_inplace_subtract */
342 345 0, /* nb_inplace_multiply */
343 346 0, /* nb_inplace_divide */
344 347 0, /* nb_inplace_remainder */
345 348 0, /* nb_inplace_power */
346 349 0, /* nb_inplace_lshift */
347 350 0, /* nb_inplace_rshift */
348 351 0, /* nb_inplace_and */
349 352 0, /* nb_inplace_xor */
350 353 0, /* nb_inplace_or */
351 354 0, /* nb_floor_divide */
352 355 0, /* nb_true_divide */
353 356 0, /* nb_inplace_floor_divide */
354 357 0, /* nb_inplace_true_divide */
355 358 };
356 359
357 360 PyTypeObject PythonQtWrapper_Type = {
358 361 PyObject_HEAD_INIT(NULL)
359 362 0, /*ob_size*/
360 363 "PythonQt.PythonQtWrapper", /*tp_name*/
361 364 sizeof(PythonQtWrapper), /*tp_basicsize*/
362 365 0, /*tp_itemsize*/
363 366 (destructor)PythonQtWrapper_dealloc, /*tp_dealloc*/
364 367 0, /*tp_print*/
365 368 0, /*tp_getattr*/
366 369 0, /*tp_setattr*/
367 370 PythonQtWrapper_compare, /*tp_compare*/
368 371 PythonQtWrapper_repr, /*tp_repr*/
369 372 &PythonQtWrapper_as_number, /*tp_as_number*/
370 373 0, /*tp_as_sequence*/
371 374 0, /*tp_as_mapping*/
372 375 (hashfunc)PythonQtWrapper_hash, /*tp_hash */
373 376 0, /*tp_call*/
374 377 0, /*tp_str*/
375 378 PythonQtWrapper_getattro, /*tp_getattro*/
376 379 PythonQtWrapper_setattro, /*tp_setattro*/
377 380 0, /*tp_as_buffer*/
378 381 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
379 382 "PythonQtWrapper object", /* tp_doc */
380 383 0, /* tp_traverse */
381 384 0, /* tp_clear */
382 385 0, /* tp_richcompare */
383 386 0, /* tp_weaklistoffset */
384 387 0, /* tp_iter */
385 388 0, /* tp_iternext */
386 389 0, /* tp_methods */
387 390 0, /* tp_members */
388 391 0, /* tp_getset */
389 392 0, /* tp_base */
390 393 0, /* tp_dict */
391 394 0, /* tp_descr_get */
392 395 0, /* tp_descr_set */
393 396 0, /* tp_dictoffset */
394 397 (initproc)PythonQtWrapper_init, /* tp_init */
395 398 0, /* tp_alloc */
396 399 PythonQtWrapper_new, /* tp_new */
397 400 };
398 401
399 402 //-------------------------------------------------------
400 403
@@ -1,42 +1,44
1 1 DEFINES += PYTHONQT_EXPORTS
2 2
3 3 HEADERS += \
4 4 $$PWD/PythonQt.h \
5 5 $$PWD/PythonQtStdDecorators.h \
6 6 $$PWD/PythonQtClassInfo.h \
7 7 $$PWD/PythonQtImporter.h \
8 8 $$PWD/PythonQtObjectPtr.h \
9 9 $$PWD/PythonQtSlot.h \
10 10 $$PWD/PythonQtStdOut.h \
11 11 $$PWD/PythonQtMisc.h \
12 12 $$PWD/PythonQtMethodInfo.h \
13 13 $$PWD/PythonQtImportFileInterface.h \
14 14 $$PWD/PythonQtConversion.h \
15 15 $$PWD/PythonQtSignalReceiver.h \
16 16 $$PWD/PythonQtWrapper.h \
17 17 $$PWD/PythonQtMetaObjectWrapper.h \
18 18 $$PWD/PythonQtCppWrapperFactory.h \
19 19 $$PWD/PythonQtVariants.h \
20 20 $$PWD/PythonQtVariantWrapper.h \
21 $$PWD/PythonQtQFileImporter.h \
21 22 $$PWD/wrapper/PythonQtWrappedVariants.h \
22 23 $$PWD/gui/PythonQtScriptingConsole.h \
23 24 $$PWD/PythonQtSystem.h
24 25
25 26 SOURCES += \
26 27 $$PWD/PythonQtStdDecorators.cpp \
27 28 $$PWD/PythonQt.cpp \
28 29 $$PWD/PythonQtClassInfo.cpp \
29 30 $$PWD/PythonQtImporter.cpp \
30 31 $$PWD/PythonQtObjectPtr.cpp \
31 32 $$PWD/PythonQtStdOut.cpp \
32 33 $$PWD/PythonQtSlot.cpp \
33 34 $$PWD/PythonQtMisc.cpp \
34 35 $$PWD/PythonQtMethodInfo.cpp \
35 36 $$PWD/PythonQtConversion.cpp \
36 37 $$PWD/PythonQtSignalReceiver.cpp \
37 38 $$PWD/PythonQtVariants.cpp \
38 39 $$PWD/PythonQtVariantWrapper.cpp \
39 40 $$PWD/PythonQtWrapper.cpp \
41 $$PWD/PythonQtQFileImporter.cpp \
40 42 $$PWD/PythonQtMetaObjectWrapper.cpp \
41 43 $$PWD/gui/PythonQtScriptingConsole.cpp
42 44
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now