@@ -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 |
|
|
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 |
|
|
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 |
|
|
|
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 |
|
|
|
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 |
|
|
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 |
|
|
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. |
|
|
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. |
|
|
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 = |
|
|
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 |
|
|
643 | 635 |
|
|
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 ( |
|
|
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 |
|
|
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} |
|
|
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