##// END OF EJS Templates
florianlink -
r163:349fb638ffe0
parent child
Show More
@@ -0,0 +1,55
1 /*
2 *
3 * Copyright (C) 2011 MeVis Medical Solutions AG 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 Medical Solutions AG, Universitaetsallee 29,
27 * 28359 Bremen, Germany or:
28 *
29 * http://www.mevis.de
30 *
31 */
32
33 #ifndef __PythonQtPythonInclude_h
34 #define __PythonQtPythonInclude_h
35
36 // Undefine macros that Python.h defines to avoid redefinition warning.
37 #undef _POSIX_C_SOURCE
38 #undef _POSIX_THREADS
39 #undef _XOPEN_SOURCE
40
41 // If PYTHONQT_USE_RELEASE_PYTHON_FALLBACK is enabled, try to link
42 // release Python DLL if it is available by undefining _DEBUG while
43 // including Python.h
44 #if defined(PYTHONQT_USE_RELEASE_PYTHON_FALLBACK) && defined(_DEBUG)
45 #undef _DEBUG
46 #if defined(_MSC_VER) && _MSC_VER >= 1400
47 #define _CRT_NOFORCE_MANIFEST 1
48 #endif
49 #include <Python.h>
50 #define _DEBUG
51 #else
52 #include <Python.h>
53 #endif
54
55 #endif
@@ -0,0 +1,114
1 /*
2 *
3 * Copyright (C) 2011 MeVis Medical Solutions AG 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 Medical Solutions AG, Universitaetsallee 29,
27 * 28359 Bremen, Germany or:
28 *
29 * http://www.mevis.de
30 *
31 */
32
33 //----------------------------------------------------------------------------------
34 /*!
35 // \file PythonQtStdIn.cpp
36 // \author Jean-Christophe Fillion-Robin
37 // \author Last changed by $Author: jcfr $
38 // \date 2011
39 */
40 //----------------------------------------------------------------------------------
41
42 #include "PythonQtStdIn.h"
43
44 static PyObject *PythonQtStdInRedirect_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
45 {
46 PythonQtStdInRedirect *self;
47 self = (PythonQtStdInRedirect *)type->tp_alloc(type, 0);
48 self->_cb = NULL;
49 self->_callData = NULL;
50
51 return (PyObject *)self;
52 }
53
54 static PyObject *PythonQtStdInRedirect_readline(PyObject * self, PyObject * args)
55 {
56 PythonQtStdInRedirect* s = (PythonQtStdInRedirect*)self;
57 QString string;
58 if (s->_cb) {
59 string = (*s->_cb)(s->_callData);
60 }
61 return Py_BuildValue(const_cast<char*>("s"), const_cast<char*>(string.toAscii().data()));
62 }
63
64 static PyMethodDef PythonQtStdInRedirect_methods[] = {
65 {"readline", (PyCFunction)PythonQtStdInRedirect_readline, METH_VARARGS,
66 "read input line"},
67 {NULL, NULL, 0 , NULL} /* sentinel */
68 };
69
70 static PyMemberDef PythonQtStdInRedirect_members[] = {
71 {NULL} /* Sentinel */
72 };
73
74 PyTypeObject PythonQtStdInRedirectType = {
75 PyObject_HEAD_INIT(NULL)
76 0, /*ob_size*/
77 "PythonQtStdInRedirect", /*tp_name*/
78 sizeof(PythonQtStdInRedirect), /*tp_basicsize*/
79 0, /*tp_itemsize*/
80 0, /*tp_dealloc*/
81 0, /*tp_print*/
82 0, /*tp_getattr*/
83 0, /*tp_setattr*/
84 0, /*tp_compare*/
85 0, /*tp_repr*/
86 0, /*tp_as_number*/
87 0, /*tp_as_sequence*/
88 0, /*tp_as_mapping*/
89 0, /*tp_hash */
90 0, /*tp_call*/
91 0, /*tp_str*/
92 0, /*tp_getattro*/
93 0, /*tp_setattro*/
94 0, /*tp_as_buffer*/
95 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
96 "PythonQtStdInRedirect", /* tp_doc */
97 0, /* tp_traverse */
98 0, /* tp_clear */
99 0, /* tp_richcompare */
100 0, /* tp_weaklistoffset */
101 0, /* tp_iter */
102 0, /* tp_iternext */
103 PythonQtStdInRedirect_methods, /* tp_methods */
104 PythonQtStdInRedirect_members, /* tp_members */
105 0, /* tp_getset */
106 0, /* tp_base */
107 0, /* tp_dict */
108 0, /* tp_descr_get */
109 0, /* tp_descr_set */
110 0, /* tp_dictoffset */
111 0, /* tp_init */
112 0, /* tp_alloc */
113 PythonQtStdInRedirect_new, /* tp_new */
114 };
@@ -0,0 +1,63
1 #ifndef _PYTHONQTSTDIN_H
2 #define _PYTHONQTSTDIN_H
3
4 /*
5 *
6 * Copyright (C) 2011 MeVis Medical Solutions AG 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 Medical Solutions AG, Universitaetsallee 29,
30 * 28359 Bremen, Germany or:
31 *
32 * http://www.mevis.de
33 *
34 */
35
36 //----------------------------------------------------------------------------------
37 /*!
38 // \file PythonQtStdIn.h
39 // \author Jean-Christophe Fillion-Robin
40 // \author Last changed by $Author: jcfr $
41 // \date 2011
42 */
43 //----------------------------------------------------------------------------------
44
45
46 #include "PythonQtPythonInclude.h"
47 #include "structmember.h"
48 #include <QString>
49
50 //! declares the type of the stdout redirection class
51 extern PyTypeObject PythonQtStdInRedirectType;
52
53 //! declares the callback that is called from the write() function
54 typedef QString PythonQtInputChangedCB(void* callData);
55
56 //! declares the stdin redirection class
57 typedef struct {
58 PyObject_HEAD
59 PythonQtInputChangedCB* _cb;
60 void * _callData;
61 } PythonQtStdInRedirect;
62
63 #endif
@@ -1,675 +1,675
1 1 #ifndef _PYTHONQT_H
2 2 #define _PYTHONQT_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, 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 "PythonQtInstanceWrapper.h"
47 47 #include "PythonQtClassWrapper.h"
48 48 #include "PythonQtSlot.h"
49 49 #include "PythonQtObjectPtr.h"
50 50 #include "PythonQtStdIn.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 PythonQtQFileImporter;
68 68
69 69 typedef void PythonQtQObjectWrappedCB(QObject* object);
70 70 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
71 typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, char **class_name);
71 typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, const char **class_name);
72 72
73 73 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
74 74
75 75 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) {
76 76 (reinterpret_cast<T*>(object))->_wrapper = wrapper;
77 77 }
78 78
79 79 //! returns the offset that needs to be added to upcast an object of type T1 to T2
80 80 template<class T1, class T2> int PythonQtUpcastingOffset() {
81 81 return ((reinterpret_cast<char*>(static_cast<T2*>(reinterpret_cast<T1*>(0x100))))
82 82 - (reinterpret_cast<char*>(reinterpret_cast<T1*>(0x100))));
83 83 }
84 84
85 85 //! callback to create a QObject lazily
86 86 typedef QObject* PythonQtQObjectCreatorFunctionCB();
87 87
88 88 //! helper template to create a derived QObject class
89 89 template<class T> QObject* PythonQtCreateObject() { return new T(); };
90 90
91 91 //! The main interface to the Python Qt binding, realized as a singleton
92 92 /*!
93 93 Use PythonQt::init() to initialize the singleton and PythonQt::self() to access it.
94 94 While there can be only one PythonQt instance, you can have any number of Python context to do scripting in.
95 95 One possibility is to use createModuleFromFile(), createModuleFromScript() or createUniqueModule() to get a context
96 96 that is separated from the other contexts. Alternatively you can use Python dicts as contexts for script evaluation,
97 97 but you will need to populate the dict with the __builtins__ instance to have all Pythons available when running
98 98 code in the scope of a dict.
99 99 */
100 100 class PYTHONQT_EXPORT PythonQt : public QObject {
101 101
102 102 Q_OBJECT
103 103
104 104 public:
105 105
106 106 //! flags that can be passed to PythonQt::init()
107 107 enum InitFlags {
108 108 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
109 109 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
110 110 ExternalHelp = 4, //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
111 111 PythonAlreadyInitialized = 8 //!<< sets that PythonQt should not can PyInitialize, since it is already done
112 112 };
113 113
114 114 //! flags that tell PythonQt which operators to expect on the registered type
115 115 enum TypeSlots {
116 116 Type_Add = 1,
117 117 Type_Subtract = 1 << 1,
118 118 Type_Multiply = 1 << 2,
119 119 Type_Divide = 1 << 3,
120 120 Type_Mod = 1 << 4,
121 121 Type_And = 1 << 5,
122 122 Type_Or = 1 << 6,
123 123 Type_Xor = 1 << 7,
124 124 Type_LShift = 1 << 8,
125 125 Type_RShift = 1 << 9,
126 126
127 127 Type_InplaceAdd = 1 << 10,
128 128 Type_InplaceSubtract = 1 << 11,
129 129 Type_InplaceMultiply = 1 << 12,
130 130 Type_InplaceDivide = 1 << 13,
131 131 Type_InplaceMod = 1 << 14,
132 132 Type_InplaceAnd = 1 << 15,
133 133 Type_InplaceOr = 1 << 16,
134 134 Type_InplaceXor = 1 << 17,
135 135 Type_InplaceLShift = 1 << 18,
136 136 Type_InplaceRShift = 1 << 19,
137 137
138 138 // Not yet needed/nicely mappable/generated...
139 139 //Type_Positive = 1 << 29,
140 140 //Type_Negative = 1 << 29,
141 141 //Type_Abs = 1 << 29,
142 142 //Type_Hash = 1 << 29,
143 143
144 144 Type_Invert = 1 << 29,
145 145 Type_RichCompare = 1 << 30,
146 146 Type_NonZero = 1 << 31,
147 147
148 148 };
149 149
150 150 //! enum for profiling callback
151 151 enum ProfilingCallbackState {
152 152 Enter = 1,
153 153 Leave = 2
154 154 };
155 155
156 156 //! callback for profiling. className and methodName are only passed when state == Enter, otherwise
157 157 //! they are NULL.
158 158 typedef void ProfilingCB(ProfilingCallbackState state, const char* className, const char* methodName);
159 159
160 160 //---------------------------------------------------------------------------
161 161 //! \name Singleton Initialization
162 162 //@{
163 163
164 164 //! initialize the python qt binding (flags are a or combination of PythonQt::InitFlags), if \c pythonQtModuleName is given
165 165 //! it defines the name of the python module that PythonQt will add, otherwise "PythonQt" is used.
166 166 //! This can be used to e.g. pass in PySide or PyQt4 to make it more compatible.
167 167 static void init(int flags = IgnoreSiteModule | RedirectStdOut, const QByteArray& pythonQtModuleName = QByteArray());
168 168
169 169 //! cleanup of the singleton
170 170 static void cleanup();
171 171
172 172 //! get the singleton instance
173 173 static PythonQt* self();
174 174
175 175 //@}
176 176
177 177 //! defines the object types for introspection
178 178 enum ObjectType {
179 179 Class,
180 180 Function,
181 181 Variable,
182 182 Module,
183 183 Anything,
184 184 CallOverloads
185 185 };
186 186
187 187
188 188 //---------------------------------------------------------------------------
189 189 //! \name Standard input handling
190 190 //@{
191 191
192 192 //! Overwrite default handling of stdin using a custom callback. It internally backup
193 193 //! the original 'sys.stdin' into 'sys.pythonqt_original_stdin'
194 194 void setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData = 0);
195 195
196 196 //! Enable or disable stdin custom callback. It resets 'sys.stdin' using either 'sys.pythonqt_stdin'
197 197 //! or 'sys.pythonqt_original_stdin'
198 198 void setRedirectStdInCallbackEnabled(bool enabled);
199 199
200 200 //@}
201 201
202 202 //---------------------------------------------------------------------------
203 203 //! \name Modules
204 204 //@{
205 205
206 206 //! get the __main__ module of python
207 207 PythonQtObjectPtr getMainModule();
208 208
209 209 //! import the given module and return a reference to it (useful to import e.g. "sys" and call something on it)
210 210 //! If a module is already imported, this returns the already imported module.
211 211 PythonQtObjectPtr importModule(const QString& name);
212 212
213 213 //! creates the new module \c name and evaluates the given file in the context of that module
214 214 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
215 215 //! to a module later on.
216 216 //! The user needs to make sure that the \c name is unique in the python module dictionary.
217 217 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
218 218
219 219 //! creates the new module \c name and evaluates the given script in the context of that module.
220 220 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
221 221 //! to a module later on.
222 222 //! The user needs to make sure that the \c name is unique in the python module dictionary.
223 223 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
224 224
225 225 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
226 226 //! script code
227 227 PythonQtObjectPtr createUniqueModule();
228 228
229 229 //@}
230 230
231 231 //---------------------------------------------------------------------------
232 232 //! \name Importing/Paths
233 233 //@{
234 234
235 235 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
236 236 void overwriteSysPath(const QStringList& paths);
237 237
238 238 //! prepend a path to sys.path to allow importing from it
239 239 void addSysPath(const QString& path);
240 240
241 241 //! sets the __path__ list of a module to the given list (important for local imports)
242 242 void setModuleImportPath(PyObject* module, const QStringList& paths);
243 243
244 244 //@}
245 245
246 246 //---------------------------------------------------------------------------
247 247 //! \name Registering Classes
248 248 //@{
249 249
250 250 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
251 251 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
252 252 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
253 253 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
254 254
255 255 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
256 256 //! (ownership of wrapper is passed to PythonQt)
257 257 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
258 258
259 259 This will add a wrapper object that is used to make calls to the given classname \c typeName.
260 260 All slots that take a pointer to typeName as the first argument will be callable from Python on
261 261 a variant object that contains such a type.
262 262 */
263 263 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
264 264
265 265 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
266 266 //! and it will register the classes when it first sees a pointer to such a derived class
267 267 void registerQObjectClassNames(const QStringList& names);
268 268
269 269 //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance
270 270 //! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that
271 271 //! type is really derived from parentType.
272 272 //! Returns false if the typeName was not yet registered.
273 273 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
274 274
275 275 //! add a handler for polymorphic downcasting
276 276 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
277 277
278 278 //@}
279 279
280 280 //---------------------------------------------------------------------------
281 281 //! \name Script Parsing and Evaluation
282 282 //@{
283 283
284 284 //! parses the given file and returns the python code object, this can then be used to call evalCode()
285 285 PythonQtObjectPtr parseFile(const QString& filename);
286 286
287 287 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
288 288 //! If pycode is NULL, a python error is printed.
289 289 QVariant evalCode(PyObject* object, PyObject* pycode);
290 290
291 291 //! evaluates the given script code and returns the result value
292 292 QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input);
293 293
294 294 //! evaluates the given script code from file
295 295 void evalFile(PyObject* object, const QString& filename);
296 296
297 297 //@}
298 298
299 299 //---------------------------------------------------------------------------
300 300 //! \name Signal Handlers
301 301 //@{
302 302
303 303 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
304 304 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
305 305
306 306 //! remove a signal handler from the given \c signal of \c obj
307 307 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
308 308
309 309 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
310 310 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
311 311
312 312 //! remove a signal handler from the given \c signal of \c obj
313 313 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
314 314
315 315 //@}
316 316
317 317 //---------------------------------------------------------------------------
318 318 //! \name Variable access
319 319 //@{
320 320
321 321 //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable)
322 322 void addObject(PyObject* object, const QString& name, QObject* qObject);
323 323
324 324 //! add the given variable to the object
325 325 void addVariable(PyObject* object, const QString& name, const QVariant& v);
326 326
327 327 //! remove the given variable
328 328 void removeVariable(PyObject* module, const QString& name);
329 329
330 330 //! get the variable with the \c name of the \c object, returns an invalid QVariant on error
331 331 QVariant getVariable(PyObject* object, const QString& name);
332 332
333 333 //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname
334 334 QStringList introspection(PyObject* object, const QString& objectname, ObjectType type);
335 335
336 336 //! returns the found callable object or NULL
337 337 //! @return new reference
338 338 PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
339 339
340 340 //@}
341 341
342 342 //---------------------------------------------------------------------------
343 343 //! \name Calling Python Objects
344 344 //@{
345 345
346 346 //! call the given python \c callable in the scope of object, returns the result converted to a QVariant
347 347 QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList());
348 348
349 349 //! call the given python object, returns the result converted to a QVariant
350 350 QVariant call(PyObject* callable, const QVariantList& args = QVariantList());
351 351
352 352 //! call the given python object, returns the result as new PyObject
353 353 PyObject* callAndReturnPyObject(PyObject* callable, const QVariantList& args = QVariantList());
354 354
355 355 //@}
356 356
357 357 //---------------------------------------------------------------------------
358 358 //! \name Decorations, Constructors, Wrappers...
359 359 //@{
360 360
361 361 //! add an object whose slots will be used as decorator slots for
362 362 //! other QObjects or CPP classes. The slots need to follow the
363 363 //! convention that the first argument is a pointer to the wrapped object.
364 364 //! (ownership is passed to PythonQt)
365 365 /*!
366 366 Example:
367 367
368 368 A slot with the signature
369 369
370 370 \code
371 371 bool doSomething(QWidget* w, int a)
372 372 \endcode
373 373
374 374 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
375 375 that will be called with the concrete instance as first argument.
376 376 So in Python you can now e.g. call
377 377
378 378 \code
379 379 someWidget.doSomething(12)
380 380 \endcode
381 381
382 382 without QWidget really having this method. This allows to easily make normal methods
383 383 of Qt classes callable by forwarding them with such decorator slots
384 384 or to make CPP classes (which are not derived from QObject) callable from Python.
385 385 */
386 386 void addInstanceDecorators(QObject* o);
387 387
388 388 //! add an object whose slots will be used as decorator slots for
389 389 //! class objects (ownership is passed to PythonQt)
390 390 /*!
391 391 The slots need to follow the following convention:
392 392 - SomeClass* new_SomeClass(...)
393 393 - QVariant new_SomeClass(...)
394 394 - void delete_SomeClass(SomeClass*)
395 395 - ... static_SomeClass_someName(...)
396 396
397 397 This will add:
398 398 - a constructor
399 399 - a constructor which generates a QVariant
400 400 - a destructor (only useful for CPP objects)
401 401 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
402 402
403 403 */
404 404 void addClassDecorators(QObject* o);
405 405
406 406 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
407 407 void addDecorators(QObject* o);
408 408
409 409 //! add the given factory to PythonQt (ownership stays with caller)
410 410 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
411 411
412 412 //@}
413 413
414 414 //---------------------------------------------------------------------------
415 415 //! \name Custom Importer
416 416 //@{
417 417
418 418 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
419 419 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
420 420 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
421 421 //! This is not reversible, so even setting setImporter(NULL) afterwards will
422 422 //! keep the custom PythonQt importer with a QFile default import interface.
423 423 //! Subsequent python import calls will make use of the passed importInterface
424 424 //! which forwards all import calls to the given \c importInterface.
425 425 //! Passing NULL will install a default QFile importer.
426 426 //! (\c importInterface ownership stays with caller)
427 427 void setImporter(PythonQtImportFileInterface* importInterface);
428 428
429 429 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
430 430 //! (without calling setImporter or installDefaultImporter at least once, the default python import
431 431 //! mechanism is in place)
432 432 //! the default importer allows to import files from anywhere QFile can read from,
433 433 //! including the Qt resource system using ":". Keep in mind that you need to extend
434 434 //! "sys.path" with ":" to be able to import from the Qt resources.
435 435 void installDefaultImporter() { setImporter(NULL); }
436 436
437 437 //! set paths that the importer should ignore
438 438 void setImporterIgnorePaths(const QStringList& paths);
439 439
440 440 //! get paths that the importer should ignore
441 441 const QStringList& getImporterIgnorePaths();
442 442
443 443 //! get access to the file importer (if set)
444 444 static PythonQtImportFileInterface* importInterface();
445 445
446 446 //@}
447 447
448 448 //---------------------------------------------------------------------------
449 449 //! \name Other Stuff
450 450 //@{
451 451
452 452 //! get access to internal data (should not be used on the public API, but is used by some C functions)
453 453 static PythonQtPrivate* priv() { return _self->_p; }
454 454
455 455 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
456 456 //! The error is currently just output to the python stderr, future version might implement better trace printing
457 457 bool handleError();
458 458
459 459 //! clear all NotFound entries on all class infos, to ensure that
460 460 //! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded
461 461 void clearNotFoundCachedMembers();
462 462
463 463 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
464 464 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
465 465 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
466 466 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
467 467
468 468 //! call the callback if it is set
469 469 static void qObjectNoLongerWrappedCB(QObject* o);
470 470
471 471 //! called by internal help methods
472 472 PyObject* helpCalled(PythonQtClassInfo* info);
473 473
474 474 //! returns the found object or NULL
475 475 //! @return new reference
476 476 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
477 477
478 478 //! sets a callback that is called before and after function calls for profiling
479 479 void setProfilingCallback(ProfilingCB* cb);
480 480
481 481 //@}
482 482
483 483 signals:
484 484 //! emitted when python outputs something to stdout (and redirection is turned on)
485 485 void pythonStdOut(const QString& str);
486 486 //! emitted when python outputs something to stderr (and redirection is turned on)
487 487 void pythonStdErr(const QString& str);
488 488
489 489 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
490 490 void pythonHelpRequest(const QByteArray& cppClassName);
491 491
492 492 private:
493 493 void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName);
494 494
495 495 //! callback for stdout redirection, emits pythonStdOut signal
496 496 static void stdOutRedirectCB(const QString& str);
497 497 //! callback for stderr redirection, emits pythonStdErr signal
498 498 static void stdErrRedirectCB(const QString& str);
499 499
500 500 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
501 501 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
502 502
503 503 PythonQt(int flags, const QByteArray& pythonQtModuleName);
504 504 ~PythonQt();
505 505
506 506 static PythonQt* _self;
507 507 static int _uniqueModuleCount;
508 508
509 509 PythonQtPrivate* _p;
510 510
511 511 };
512 512
513 513 //! internal PythonQt details
514 514 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
515 515
516 516 Q_OBJECT
517 517
518 518 public:
519 519 PythonQtPrivate();
520 520 ~PythonQtPrivate();
521 521
522 522 enum DecoratorTypes {
523 523 StaticDecorator = 1,
524 524 ConstructorDecorator = 2,
525 525 DestructorDecorator = 4,
526 526 InstanceDecorator = 8,
527 527 AllDecorators = 0xffff
528 528 };
529 529
530 530 //! get the suffixes that are used for shared libraries
531 531 const QStringList& sharedLibrarySuffixes() { return _sharedLibrarySuffixes; }
532 532
533 533 //! returns if the id is the id for PythonQtObjectPtr
534 534 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
535 535
536 536 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
537 537 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
538 538 //! remove the wrapper ptr again
539 539 void removeWrapperPointer(void* obj);
540 540
541 541 //! add parent class relation
542 542 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
543 543
544 544 //! add a handler for polymorphic downcasting
545 545 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
546 546
547 547 //! lookup existing classinfo and return new if not yet present
548 548 PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
549 549
550 550 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
551 551 void removeSignalEmitter(QObject* obj);
552 552
553 553 //! wrap the given QObject into a Python object (or return existing wrapper!)
554 554 PyObject* wrapQObject(QObject* obj);
555 555
556 556 //! 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
557 557 PyObject* wrapPtr(void* ptr, const QByteArray& name);
558 558
559 559 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
560 560 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
561 561 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
562 562 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
563 563
564 564 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
565 565 //! (ownership of wrapper is passed to PythonQt)
566 566 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
567 567
568 568 This will add a wrapper object that is used to make calls to the given classname \c typeName.
569 569 All slots that take a pointer to typeName as the first argument will be callable from Python on
570 570 a variant object that contains such a type.
571 571 */
572 572 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
573 573
574 574 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
575 575 //! and it will register the classes when it first sees a pointer to such a derived class
576 576 void registerQObjectClassNames(const QStringList& names);
577 577
578 578 //! add a decorator object
579 579 void addDecorators(QObject* o, int decoTypes);
580 580
581 581 //! helper method that creates a PythonQtClassWrapper object (returns a new reference)
582 582 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* module);
583 583
584 584 //! create a new instance of the given enum type with given value (returns a new reference)
585 585 static PyObject* createEnumValueInstance(PyObject* enumType, unsigned int enumValue);
586 586
587 587 //! helper that creates a new int derived class that represents the enum of the given name (returns a new reference)
588 588 static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
589 589
590 590 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
591 591 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
592 592
593 593 //! get the class info for a meta object (if available)
594 594 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
595 595
596 596 //! get the class info for a meta object (if available)
597 597 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
598 598
599 599 //! creates the new module from the given pycode
600 600 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
601 601
602 602 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
603 603 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
604 604
605 605 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
606 606 static PyObject* dummyTuple();
607 607
608 608 //! called by virtual overloads when a python return value can not be converted to the required Qt type
609 609 void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result);
610 610
611 611 //! get access to the PythonQt module
612 612 PythonQtObjectPtr pythonQtModule() const { return _pythonQtModule; }
613 613
614 614 //! returns the profiling callback, which may be NULL
615 615 PythonQt::ProfilingCB* profilingCB() const { return _profilingCB; }
616 616
617 617 private:
618 618 //! Setup the shared library suffixes by getting them from the "imp" module.
619 619 void setupSharedLibrarySuffixes();
620 620
621 621 //! create a new pythonqt class wrapper and place it in the pythonqt module
622 622 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module = NULL);
623 623
624 624 //! get/create new package module (the returned object is a borrowed reference)
625 625 PyObject* packageByName(const char* name);
626 626
627 627 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
628 628 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
629 629
630 630 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
631 631 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
632 632
633 633 //! stores the meta info of known Qt classes
634 634 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
635 635
636 636 //! names of qobject derived classes that can be casted to qobject savely
637 637 QHash<QByteArray, bool> _knownQObjectClassNames;
638 638
639 639 //! stores signal receivers for QObjects
640 640 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
641 641
642 642 //! the PythonQt python module
643 643 PythonQtObjectPtr _pythonQtModule;
644 644
645 645 //! the name of the PythonQt python module
646 646 QByteArray _pythonQtModuleName;
647 647
648 648 //! the importer interface (if set)
649 649 PythonQtImportFileInterface* _importInterface;
650 650
651 651 //! the default importer
652 652 PythonQtQFileImporter* _defaultImporter;
653 653
654 654 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
655 655 PythonQtQObjectWrappedCB* _wrappedCB;
656 656
657 657 QStringList _importIgnorePaths;
658 658 QStringList _sharedLibrarySuffixes;
659 659
660 660 //! the cpp object wrapper factories
661 661 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
662 662
663 663 QHash<QByteArray, PyObject*> _packages;
664 664
665 665 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
666 666
667 667 PythonQt::ProfilingCB* _profilingCB;
668 668
669 669 int _initFlags;
670 670 int _PythonQtObjectPtr_metaId;
671 671
672 672 friend class PythonQt;
673 673 };
674 674
675 675 #endif
@@ -1,868 +1,868
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, 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 "PythonQtClassInfo.h"
43 43 #include "PythonQtMethodInfo.h"
44 44 #include "PythonQt.h"
45 45 #include <QMetaMethod>
46 46 #include <QMetaObject>
47 47 #include <QMetaEnum>
48 48
49 49 QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;
50 50
51 51 PythonQtClassInfo::PythonQtClassInfo() {
52 52 _meta = NULL;
53 53 _constructors = NULL;
54 54 _destructor = NULL;
55 55 _decoratorProvider = NULL;
56 56 _decoratorProviderCB = NULL;
57 57 _pythonQtClassWrapper = NULL;
58 58 _shellSetInstanceWrapperCB = NULL;
59 59 _metaTypeId = -1;
60 60 _typeSlots = 0;
61 61 _isQObject = false;
62 62 _enumsCreated = false;
63 63 }
64 64
65 65 PythonQtClassInfo::~PythonQtClassInfo()
66 66 {
67 67 clearCachedMembers();
68 68
69 69 if (_constructors) {
70 70 _constructors->deleteOverloadsAndThis();
71 71 }
72 72 if (_destructor) {
73 73 _destructor->deleteOverloadsAndThis();
74 74 }
75 75 foreach(PythonQtSlotInfo* info, _decoratorSlots) {
76 76 info->deleteOverloadsAndThis();
77 77 }
78 78 }
79 79
80 80 void PythonQtClassInfo::setupQObject(const QMetaObject* meta)
81 81 {
82 82 // _wrappedClassName is already set earlier in the class setup
83 83 _isQObject = true;
84 84 _meta = meta;
85 85 }
86 86
87 87 void PythonQtClassInfo::setupCPPObject(const QByteArray& classname)
88 88 {
89 89 _isQObject = false;
90 90 _wrappedClassName = classname;
91 91 _metaTypeId = QMetaType::type(classname);
92 92 }
93 93
94 94 void PythonQtClassInfo::clearCachedMembers()
95 95 {
96 96 QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers);
97 97 while (i.hasNext()) {
98 98 PythonQtMemberInfo member = i.next().value();
99 99 if (member._type== PythonQtMemberInfo::Slot) {
100 100 PythonQtSlotInfo* info = member._slot;
101 101 while (info) {
102 102 PythonQtSlotInfo* next = info->nextInfo();
103 103 delete info;
104 104 info = next;
105 105 }
106 106 }
107 107 }
108 108 }
109 109
110 110 int PythonQtClassInfo::findCharOffset(const char* sigStart, char someChar)
111 111 {
112 112 const char* sigEnd = sigStart;
113 113 char c;
114 114 do {
115 115 c = *sigEnd++;
116 116 } while (c!=someChar && c!=0);
117 117 return sigEnd-sigStart-1;
118 118 }
119 119
120 120 bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName)
121 121 {
122 122 if (!_meta) return false;
123 123
124 124 bool found = false;
125 125 bool nameMapped = false;
126 126 const char* attributeName = memberName;
127 127 // look for properties
128 128 int i = _meta->indexOfProperty(attributeName);
129 129 if (i==-1) {
130 130 // try to map name to objectName
131 131 if (qstrcmp(attributeName, "name")==0) {
132 132 attributeName = "objectName";
133 133 nameMapped = true;
134 134 i = _meta->indexOfProperty(attributeName);
135 135 }
136 136 }
137 137 if (i!=-1) {
138 138 PythonQtMemberInfo newInfo(_meta->property(i));
139 139 _cachedMembers.insert(attributeName, newInfo);
140 140 if (nameMapped) {
141 141 _cachedMembers.insert(memberName, newInfo);
142 142 }
143 143 #ifdef PYTHONQT_DEBUG
144 144 std::cout << "caching property " << memberName << " on " << _meta->className() << std::endl;
145 145 #endif
146 146 found = true;
147 147 }
148 148 return found;
149 149 }
150 150
151 151 PythonQtSlotInfo* PythonQtClassInfo::recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
152 152 {
153 153 inputInfo = findDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset);
154 154 foreach(const ParentClassInfo& info, _parentClasses) {
155 155 inputInfo = info._parent->recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset+info._upcastingOffset);
156 156 }
157 157 return inputInfo;
158 158 }
159 159
160 160 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset) {
161 161 QObject* decoratorProvider = decorator();
162 int memberNameLen = strlen(memberName);
162 int memberNameLen = static_cast<int>(strlen(memberName));
163 163 if (decoratorProvider) {
164 164 //qDebug()<< "looking " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
165 165 const QMetaObject* meta = decoratorProvider->metaObject();
166 166 int numMethods = meta->methodCount();
167 167 int startFrom = QObject::staticMetaObject.methodCount();
168 168 for (int i = startFrom; i < numMethods; i++) {
169 169 QMetaMethod m = meta->method(i);
170 170 if ((m.methodType() == QMetaMethod::Method ||
171 171 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
172 172
173 173 const char* sigStart = m.signature();
174 174 bool isClassDeco = false;
175 175 if (qstrncmp(sigStart, "static_", 7)==0) {
176 176 // skip the static_classname_ part of the string
177 177 sigStart += 7 + 1 + strlen(className());
178 178 isClassDeco = true;
179 179 } else if (qstrncmp(sigStart, "new_", 4)==0) {
180 180 isClassDeco = true;
181 181 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
182 182 isClassDeco = true;
183 183 }
184 184 // find the first '('
185 185 int offset = findCharOffset(sigStart, '(');
186 186
187 187 // XXX no checking is currently done if the slots have correct first argument or not...
188 188
189 189 // check if same length and same name
190 190 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
191 191 found = true;
192 192 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i, decoratorProvider, isClassDeco?PythonQtSlotInfo::ClassDecorator:PythonQtSlotInfo::InstanceDecorator);
193 193 info->setUpcastingOffset(upcastingOffset);
194 194 //qDebug()<< "adding " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
195 195 if (tail) {
196 196 tail->setNextInfo(info);
197 197 } else {
198 198 PythonQtMemberInfo newInfo(info);
199 199 memberCache.insert(memberName, newInfo);
200 200 }
201 201 tail = info;
202 202 }
203 203 }
204 204 }
205 205 }
206 206
207 207 tail = findDecoratorSlots(memberName, memberNameLen, tail, found, memberCache, upcastingOffset);
208 208
209 209 return tail;
210 210 }
211 211
212 212 bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName)
213 213 {
214 214 bool found = false;
215 int memberNameLen = strlen(memberName);
215 int memberNameLen = static_cast<int>(strlen(memberName));
216 216 PythonQtSlotInfo* tail = NULL;
217 217 if (_meta) {
218 218 int numMethods = _meta->methodCount();
219 219 for (int i = 0; i < numMethods; i++) {
220 220 QMetaMethod m = _meta->method(i);
221 221 if (((m.methodType() == QMetaMethod::Method ||
222 222 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public)
223 223 || m.methodType()==QMetaMethod::Signal) {
224 224
225 225 const char* sigStart = m.signature();
226 226 // find the first '('
227 227 int offset = findCharOffset(sigStart, '(');
228 228
229 229 // check if same length and same name
230 230 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
231 231 found = true;
232 232 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i);
233 233 if (tail) {
234 234 tail->setNextInfo(info);
235 235 } else {
236 236 PythonQtMemberInfo newInfo(info);
237 237 _cachedMembers.insert(memberName, newInfo);
238 238 }
239 239 tail = info;
240 240 }
241 241 }
242 242 }
243 243 }
244 244
245 245 // look for dynamic decorators in this class and in derived classes
246 246 tail = recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, tail, found, _cachedMembers, 0);
247 247
248 248 return found;
249 249 }
250 250
251 251 bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* memberName)
252 252 {
253 253 bool found = false;
254 254 // look for enum values
255 255 int enumCount = meta->enumeratorCount();
256 256 for (int i=0;i<enumCount; i++) {
257 257 QMetaEnum e = meta->enumerator(i);
258 258 // we do not want flags, they will cause our values to appear two times
259 259 if (e.isFlag()) continue;
260 260
261 261 for (int j=0; j < e.keyCount(); j++) {
262 262 if (qstrcmp(e.key(j), memberName)==0) {
263 263 PyObject* enumType = findEnumWrapper(e.name());
264 264 if (enumType) {
265 265 PythonQtObjectPtr enumValuePtr;
266 266 enumValuePtr.setNewRef(PythonQtPrivate::createEnumValueInstance(enumType, e.value(j)));
267 267 PythonQtMemberInfo newInfo(enumValuePtr);
268 268 _cachedMembers.insert(memberName, newInfo);
269 269 #ifdef PYTHONQT_DEBUG
270 270 std::cout << "caching enum " << memberName << " on " << meta->className() << std::endl;
271 271 #endif
272 272 found = true;
273 273 break;
274 274 } else {
275 275 std::cout << "enum " << e.name() << " not found on " << className() << std::endl;
276 276 }
277 277 }
278 278 }
279 279 }
280 280 return found;
281 281 }
282 282
283 283 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
284 284 {
285 285 PythonQtMemberInfo info = _cachedMembers.value(memberName);
286 286 if (info._type != PythonQtMemberInfo::Invalid) {
287 287 return info;
288 288 } else {
289 289 bool found = false;
290 290
291 291 found = lookForPropertyAndCache(memberName);
292 292 if (!found) {
293 293 found = lookForMethodAndCache(memberName);
294 294 }
295 295 if (!found) {
296 296 if (_meta) {
297 297 // check enums in our meta object directly
298 298 found = lookForEnumAndCache(_meta, memberName);
299 299 }
300 300 if (!found) {
301 301 // check enums in the class hierachy of CPP classes
302 302 // look for dynamic decorators in this class and in derived classes
303 303 QList<QObject*> decoObjects;
304 304 recursiveCollectDecoratorObjects(decoObjects);
305 305 foreach(QObject* deco, decoObjects) {
306 306 // call on ourself for caching, but with different metaObject():
307 307 found = lookForEnumAndCache(deco->metaObject(), memberName);
308 308 if (found) {
309 309 break;
310 310 }
311 311 }
312 312 }
313 313 }
314 314 if (!found) {
315 315 // maybe it is an enum wrapper?
316 316 PyObject* p = findEnumWrapper(memberName);
317 317 if (p) {
318 318 info._type = PythonQtMemberInfo::EnumWrapper;
319 319 info._enumWrapper = p;
320 320 _cachedMembers.insert(memberName, info);
321 321 found = true;
322 322 }
323 323 }
324 324 if (!found) {
325 325 // since python keywords can not be looked up, we check if the name contains a single trailing _
326 326 // and remove that and look again, so that we e.g. find exec on an exec_ lookup
327 327 QByteArray mbrName(memberName);
328 328 if ((mbrName.length()>2) &&
329 329 (mbrName.at(mbrName.length()-1) == '_') &&
330 330 (mbrName.at(mbrName.length()-2) != '_')) {
331 331 mbrName = mbrName.mid(0,mbrName.length()-1);
332 332 found = lookForMethodAndCache(mbrName.constData());
333 333 if (found) {
334 334 return _cachedMembers.value(mbrName);
335 335 }
336 336 }
337 337 }
338 338 if (!found) {
339 339 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
340 340 info._type = PythonQtMemberInfo::NotFound;
341 341 _cachedMembers.insert(memberName, info);
342 342 }
343 343 }
344 344
345 345 return _cachedMembers.value(memberName);
346 346 }
347 347
348 348 void PythonQtClassInfo::recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects) {
349 349 QObject* deco = decorator();
350 350 if (deco) {
351 351 decoratorObjects.append(deco);
352 352 }
353 353 foreach(const ParentClassInfo& info, _parentClasses) {
354 354 info._parent->recursiveCollectDecoratorObjects(decoratorObjects);
355 355 }
356 356 }
357 357
358 358 void PythonQtClassInfo::recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects) {
359 359 classInfoObjects.append(this);
360 360 foreach(const ParentClassInfo& info, _parentClasses) {
361 361 info._parent->recursiveCollectClassInfos(classInfoObjects);
362 362 }
363 363 }
364 364
365 365 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
366 366 {
367 367 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
368 368 while (it.hasNext()) {
369 369
370 370 PythonQtSlotInfo* infoOrig = it.next();
371 371
372 372 const char* sigStart = infoOrig->metaMethod()->signature();
373 373 if (qstrncmp("static_", sigStart, 7)==0) {
374 374 sigStart += 7;
375 375 sigStart += findCharOffset(sigStart, '_')+1;
376 376 }
377 377 int offset = findCharOffset(sigStart, '(');
378 378 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
379 379 //make a copy, otherwise we will have trouble on overloads!
380 380 PythonQtSlotInfo* info = new PythonQtSlotInfo(*infoOrig);
381 381 info->setUpcastingOffset(upcastingOffset);
382 382 found = true;
383 383 if (tail) {
384 384 tail->setNextInfo(info);
385 385 } else {
386 386 PythonQtMemberInfo newInfo(info);
387 387 memberCache.insert(memberName, newInfo);
388 388 }
389 389 tail = info;
390 390 }
391 391 }
392 392 return tail;
393 393 }
394 394
395 395 void PythonQtClassInfo::listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly) {
396 396 QObject* decoratorProvider = decorator();
397 397 if (decoratorProvider) {
398 398 const QMetaObject* meta = decoratorProvider->metaObject();
399 399 int numMethods = meta->methodCount();
400 400 int startFrom = QObject::staticMetaObject.methodCount();
401 401 for (int i = startFrom; i < numMethods; i++) {
402 402 QMetaMethod m = meta->method(i);
403 403 if ((m.methodType() == QMetaMethod::Method ||
404 404 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
405 405
406 406 const char* sigStart = m.signature();
407 407 bool isClassDeco = false;
408 408 if (qstrncmp(sigStart, "static_", 7)==0) {
409 409 // skip the static_classname_ part of the string
410 410 sigStart += 7 + 1 + strlen(className());
411 411 isClassDeco = true;
412 412 } else if (qstrncmp(sigStart, "new_", 4)==0) {
413 413 continue;
414 414 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
415 415 continue;
416 416 } else if (qstrncmp(sigStart, "py_", 3)==0) {
417 417 // hide everything that starts with py_
418 418 continue;
419 419 }
420 420 // find the first '('
421 421 int offset = findCharOffset(sigStart, '(');
422 422
423 423 // XXX no checking is currently done if the slots have correct first argument or not...
424 424 if (!metaOnly || isClassDeco) {
425 425 list << QString::fromLatin1(sigStart, offset);
426 426 }
427 427 }
428 428 }
429 429 }
430 430
431 431 // look for global decorator slots
432 432 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
433 433 while (it.hasNext()) {
434 434 PythonQtSlotInfo* slot = it.next();
435 435 if (metaOnly) {
436 436 if (slot->isClassDecorator()) {
437 437 QByteArray first = slot->slotName();
438 438 if (first.startsWith("static_")) {
439 439 int idx = first.indexOf('_');
440 440 idx = first.indexOf('_', idx+1);
441 441 first = first.mid(idx+1);
442 442 }
443 443 list << first;
444 444 }
445 445 } else {
446 446 list << slot->slotName();
447 447 }
448 448 }
449 449 }
450 450
451 451 QStringList PythonQtClassInfo::propertyList()
452 452 {
453 453 QStringList l;
454 454 if (_isQObject && _meta) {
455 455 int i;
456 456 int numProperties = _meta->propertyCount();
457 457 for (i = 0; i < numProperties; i++) {
458 458 QMetaProperty p = _meta->property(i);
459 459 l << QString(p.name());
460 460 }
461 461 }
462 462 return l;
463 463 }
464 464
465 465 QStringList PythonQtClassInfo::memberList(bool metaOnly)
466 466 {
467 467 decorator();
468 468
469 469 QStringList l;
470 470 QString h;
471 471 if (_isQObject && _meta && !metaOnly) {
472 472 l = propertyList();
473 473 }
474 474
475 475 // normal slots of QObject (or wrapper QObject)
476 476 if (!metaOnly && _meta) {
477 477 int numMethods = _meta->methodCount();
478 478 bool skipQObj = !_isQObject;
479 479 for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) {
480 480 QMetaMethod m = _meta->method(i);
481 481 if (((m.methodType() == QMetaMethod::Method ||
482 482 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public)
483 483 || m.methodType()==QMetaMethod::Signal) {
484 484 QByteArray signa(m.signature());
485 485 signa = signa.left(signa.indexOf('('));
486 486 l << signa;
487 487 }
488 488 }
489 489 }
490 490
491 491 {
492 492 // look for dynamic decorators in this class and in derived classes
493 493 QList<PythonQtClassInfo*> infos;
494 494 recursiveCollectClassInfos(infos);
495 495 foreach(PythonQtClassInfo* info, infos) {
496 496 info->listDecoratorSlotsFromDecoratorProvider(l, metaOnly);
497 497 }
498 498 }
499 499
500 500 // List enumerator keys...
501 501 QList<const QMetaObject*> enumMetaObjects;
502 502 if (_meta) {
503 503 enumMetaObjects << _meta;
504 504 }
505 505 // check enums in the class hierachy of CPP classes
506 506 QList<QObject*> decoObjects;
507 507 recursiveCollectDecoratorObjects(decoObjects);
508 508 foreach(QObject* deco, decoObjects) {
509 509 enumMetaObjects << deco->metaObject();
510 510 }
511 511
512 512 foreach(const QMetaObject* meta, enumMetaObjects) {
513 513 for (int i = 0; i<meta->enumeratorCount(); i++) {
514 514 QMetaEnum e = meta->enumerator(i);
515 515 l << e.name();
516 516 // we do not want flags, they will cause our values to appear two times
517 517 if (e.isFlag()) continue;
518 518
519 519 for (int j=0; j < e.keyCount(); j++) {
520 520 l << QString(e.key(j));
521 521 }
522 522 }
523 523 }
524 524
525 525 return QSet<QString>::fromList(l).toList();
526 526 }
527 527
528 528 const char* PythonQtClassInfo::className()
529 529 {
530 530 return _wrappedClassName.constData();
531 531 }
532 532
533 533 void* PythonQtClassInfo::castTo(void* ptr, const char* classname)
534 534 {
535 535 if (ptr==NULL) {
536 536 return NULL;
537 537 }
538 538 if (_wrappedClassName == classname) {
539 539 return ptr;
540 540 }
541 541 foreach(const ParentClassInfo& info, _parentClasses) {
542 542 void* result = info._parent->castTo((char*)ptr + info._upcastingOffset, classname);
543 543 if (result) {
544 544 return result;
545 545 }
546 546 }
547 547 return NULL;
548 548 }
549 549
550 550 bool PythonQtClassInfo::inherits(const char* name)
551 551 {
552 552 if (_wrappedClassName == name) {
553 553 return true;
554 554 }
555 555 foreach(const ParentClassInfo& info, _parentClasses) {
556 556 if (info._parent->inherits(name)) {
557 557 return true;
558 558 }
559 559 }
560 560 return false;
561 561 }
562 562
563 563 bool PythonQtClassInfo::inherits(PythonQtClassInfo* classInfo)
564 564 {
565 565 if (classInfo == this) {
566 566 return true;
567 567 }
568 568 foreach(const ParentClassInfo& info, _parentClasses) {
569 569 if (info._parent->inherits(classInfo)) {
570 570 return true;
571 571 }
572 572 }
573 573 return false;
574 574 }
575 575
576 576 QString PythonQtClassInfo::help()
577 577 {
578 578 decorator();
579 579 QString h;
580 580 h += QString("--- ") + QString(className()) + QString(" ---\n");
581 581
582 582 if (_isQObject) {
583 583 h += "Properties:\n";
584 584
585 585 int i;
586 586 int numProperties = _meta->propertyCount();
587 587 for (i = 0; i < numProperties; i++) {
588 588 QMetaProperty p = _meta->property(i);
589 589 h += QString(p.name()) + " (" + QString(p.typeName()) + " )\n";
590 590 }
591 591 }
592 592
593 593 if (constructors()) {
594 594 h += "Constructors:\n";
595 595 PythonQtSlotInfo* constr = constructors();
596 596 while (constr) {
597 597 h += constr->fullSignature() + "\n";
598 598 constr = constr->nextInfo();
599 599 }
600 600 }
601 601
602 602 h += "Slots:\n";
603 603 h += "QString help()\n";
604 604 h += "QString className()\n";
605 605
606 606 if (_meta) {
607 607 int numMethods = _meta->methodCount();
608 608 for (int i = 0; i < numMethods; i++) {
609 609 QMetaMethod m = _meta->method(i);
610 610 if ((m.methodType() == QMetaMethod::Method ||
611 611 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
612 612 PythonQtSlotInfo slot(this, m, i);
613 613 h += slot.fullSignature()+ "\n";
614 614 }
615 615 }
616 616 }
617 617
618 618 // TODO xxx : decorators and enums from decorator() are missing...
619 619 // maybe we can reuse memberlist()?
620 620
621 621 if (_meta && _meta->enumeratorCount()) {
622 622 h += "Enums:\n";
623 623 for (int i = 0; i<_meta->enumeratorCount(); i++) {
624 624 QMetaEnum e = _meta->enumerator(i);
625 625 h += QString(e.name()) + " {";
626 626 for (int j=0; j < e.keyCount(); j++) {
627 627 if (j) { h+= ", "; }
628 628 h += e.key(j);
629 629 }
630 630 h += " }\n";
631 631 }
632 632 }
633 633
634 634 if (_isQObject && _meta) {
635 635 int numMethods = _meta->methodCount();
636 636 if (numMethods>0) {
637 637 h += "Signals:\n";
638 638 for (int i = 0; i < numMethods; i++) {
639 639 QMetaMethod m = _meta->method(i);
640 640 if (m.methodType() == QMetaMethod::Signal) {
641 641 h += QString(m.signature()) + "\n";
642 642 }
643 643 }
644 644 }
645 645 }
646 646 return h;
647 647 }
648 648
649 649 PythonQtSlotInfo* PythonQtClassInfo::constructors()
650 650 {
651 651 if (!_constructors) {
652 652 // force creation of lazy decorator, which will register the decorators
653 653 decorator();
654 654 }
655 655 return _constructors;
656 656 }
657 657
658 658 PythonQtSlotInfo* PythonQtClassInfo::destructor()
659 659 {
660 660 if (!_destructor) {
661 661 // force creation of lazy decorator, which will register the decorators
662 662 decorator();
663 663 }
664 664 return _destructor;
665 665 }
666 666
667 667 void PythonQtClassInfo::addConstructor(PythonQtSlotInfo* info)
668 668 {
669 669 PythonQtSlotInfo* prev = constructors();
670 670 if (prev) {
671 671 info->setNextInfo(prev->nextInfo());
672 672 prev->setNextInfo(info);
673 673 } else {
674 674 _constructors = info;
675 675 }
676 676 }
677 677
678 678 void PythonQtClassInfo::addDecoratorSlot(PythonQtSlotInfo* info)
679 679 {
680 680 _decoratorSlots.append(info);
681 681 }
682 682
683 683 void PythonQtClassInfo::setDestructor(PythonQtSlotInfo* info)
684 684 {
685 685 if (_destructor) {
686 686 _destructor->deleteOverloadsAndThis();
687 687 }
688 688 _destructor = info;
689 689 }
690 690
691 691 void PythonQtClassInfo::setMetaObject(const QMetaObject* meta)
692 692 {
693 693 _meta = meta;
694 694 clearCachedMembers();
695 695 }
696 696
697 697 QObject* PythonQtClassInfo::decorator()
698 698 {
699 699 if (!_decoratorProvider && _decoratorProviderCB) {
700 700 _decoratorProvider = (*_decoratorProviderCB)();
701 701 if (_decoratorProvider) {
702 702 _decoratorProvider->setParent(PythonQt::priv());
703 703 // setup enums early, since they might be needed by the constructor decorators:
704 704 if (!_enumsCreated) {
705 705 createEnumWrappers();
706 706 }
707 707 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
708 708 }
709 709 }
710 710 // check if enums need to be created and create them if they are not yet created
711 711 if (!_enumsCreated) {
712 712 createEnumWrappers();
713 713 }
714 714 return _decoratorProvider;
715 715 }
716 716
717 717 bool PythonQtClassInfo::hasOwnerMethodButNoOwner(void* object)
718 718 {
719 719 PythonQtMemberInfo info = member("py_hasOwner");
720 720 if (info._type == PythonQtMemberInfo::Slot) {
721 721 void* obj = object;
722 722 bool result = false;
723 723 void* args[2];
724 724 args[0] = &result;
725 725 args[1] = &obj;
726 726 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
727 727 return !result;
728 728 } else {
729 729 return false;
730 730 }
731 731 }
732 732
733 void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, char** resultClassName)
733 void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, const char** resultClassName)
734 734 {
735 735 if (!_polymorphicHandlers.isEmpty()) {
736 736 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
737 737 void* resultPtr = (*cb)(ptr, resultClassName);
738 738 if (resultPtr) {
739 739 return resultPtr;
740 740 }
741 741 }
742 742 }
743 743 foreach(const ParentClassInfo& info, _parentClasses) {
744 744 if (!info._parent->isQObject()) {
745 745 void* resultPtr = info._parent->recursiveCastDownIfPossible((char*)ptr + info._upcastingOffset, resultClassName);
746 746 if (resultPtr) {
747 747 return resultPtr;
748 748 }
749 749 }
750 750 }
751 751 return NULL;
752 752 }
753 753
754 754 void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo)
755 755 {
756 char* className;
756 const char* className;
757 757 // this would do downcasting recursively...
758 758 // void* resultPtr = recursiveCastDownIfPossible(ptr, &className);
759 759
760 760 // we only do downcasting on the base object, not on the whole inheritance tree...
761 761 void* resultPtr = NULL;
762 762 if (!_polymorphicHandlers.isEmpty()) {
763 763 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
764 764 resultPtr = (*cb)(ptr, &className);
765 765 if (resultPtr) {
766 766 break;
767 767 }
768 768 }
769 769 }
770 770 if (resultPtr) {
771 771 *resultClassInfo = PythonQt::priv()->getClassInfo(className);
772 772 } else {
773 773 *resultClassInfo = this;
774 774 resultPtr = ptr;
775 775 }
776 776 return resultPtr;
777 777 }
778 778
779 779 PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum)
780 780 {
781 781 if (isLocalEnum) {
782 782 *isLocalEnum = true;
783 783 }
784 784 int scopePos = name.lastIndexOf("::");
785 785 if (scopePos != -1) {
786 786 if (isLocalEnum) {
787 787 *isLocalEnum = false;
788 788 }
789 789 // split into scope and enum name
790 790 QByteArray enumScope = name.mid(0,scopePos);
791 791 QByteArray enumName = name.mid(scopePos+2);
792 792 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(enumScope);
793 793 if (info) {
794 794 return info->findEnumWrapper(enumName);
795 795 } else{
796 796 return NULL;
797 797 }
798 798 }
799 799 if (localScope) {
800 800 return localScope->findEnumWrapper(name);
801 801 } else {
802 802 return NULL;
803 803 }
804 804 }
805 805
806 806 void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta)
807 807 {
808 808 for (int i = meta->enumeratorOffset();i<meta->enumeratorCount();i++) {
809 809 QMetaEnum e = meta->enumerator(i);
810 810 PythonQtObjectPtr p;
811 811 p.setNewRef(PythonQtPrivate::createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper));
812 812 _enumWrappers.append(p);
813 813 }
814 814 }
815 815
816 816 void PythonQtClassInfo::createEnumWrappers()
817 817 {
818 818 if (!_enumsCreated) {
819 819 _enumsCreated = true;
820 820 if (_meta) {
821 821 createEnumWrappers(_meta);
822 822 }
823 823 if (decorator()) {
824 824 createEnumWrappers(decorator()->metaObject());
825 825 }
826 826 foreach(const ParentClassInfo& info, _parentClasses) {
827 827 info._parent->createEnumWrappers();
828 828 }
829 829 }
830 830 }
831 831
832 832 PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) {
833 833 // force enum creation
834 834 if (!_enumsCreated) {
835 835 createEnumWrappers();
836 836 }
837 837 foreach(const PythonQtObjectPtr& p, _enumWrappers) {
838 838 const char* className = ((PyTypeObject*)p.object())->tp_name;
839 839 if (qstrcmp(className, name)==0) {
840 840 return p.object();
841 841 }
842 842 }
843 843 foreach(const ParentClassInfo& info, _parentClasses) {
844 844 PyObject* p = info._parent->findEnumWrapper(name);
845 845 if (p) return p;
846 846 }
847 847 return NULL;
848 848 }
849 849
850 850 void PythonQtClassInfo::setDecoratorProvider( PythonQtQObjectCreatorFunctionCB* cb )
851 851 {
852 852 _decoratorProviderCB = cb;
853 853 _decoratorProvider = NULL;
854 854 _enumsCreated = false;
855 855 }
856 856
857 857 void PythonQtClassInfo::clearNotFoundCachedMembers()
858 858 {
859 859 // remove all not found entries, since a new decorator means new slots,
860 860 // which might have been cached as "NotFound" already.
861 861 QMutableHashIterator<QByteArray, PythonQtMemberInfo> it(_cachedMembers);
862 862 while (it.hasNext()) {
863 863 it.next();
864 864 if (it.value()._type == PythonQtMemberInfo::NotFound) {
865 865 it.remove();
866 866 }
867 867 }
868 868 }
@@ -1,265 +1,265
1 1 #ifndef _PYTHONQTCLASSINFO_H
2 2 #define _PYTHONQTCLASSINFO_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 #include <QMetaObject>
37 37 #include <QMetaMethod>
38 38 #include <QHash>
39 39 #include <QByteArray>
40 40 #include <QList>
41 41 #include "PythonQt.h"
42 42
43 43 class PythonQtSlotInfo;
44 44
45 45 struct PythonQtMemberInfo {
46 46 enum Type {
47 47 Invalid, Slot, EnumValue, EnumWrapper, Property, NotFound
48 48 };
49 49
50 50 PythonQtMemberInfo():_type(Invalid),_slot(NULL),_enumWrapper(NULL),_enumValue(0) { }
51 51
52 52 PythonQtMemberInfo(PythonQtSlotInfo* info) {
53 53 _type = Slot;
54 54 _slot = info;
55 55 _enumValue = NULL;
56 56 }
57 57
58 58 PythonQtMemberInfo(const PythonQtObjectPtr& enumValue) {
59 59 _type = EnumValue;
60 60 _slot = NULL;
61 61 _enumValue = enumValue;
62 62 _enumWrapper = NULL;
63 63 }
64 64
65 65 PythonQtMemberInfo(const QMetaProperty& prop) {
66 66 _type = Property;
67 67 _slot = NULL;
68 68 _enumValue = NULL;
69 69 _property = prop;
70 70 _enumWrapper = NULL;
71 71 }
72 72
73 73 Type _type;
74 74
75 75 // TODO: this could be a union...
76 76 PythonQtSlotInfo* _slot;
77 77 PyObject* _enumWrapper;
78 78 PythonQtObjectPtr _enumValue;
79 79 QMetaProperty _property;
80 80 };
81 81
82 82 //! a class that stores all required information about a Qt object (and an optional associated C++ class name)
83 83 /*! for fast lookup of slots when calling the object from Python
84 84 */
85 85 class PYTHONQT_EXPORT PythonQtClassInfo {
86 86
87 87 public:
88 88 PythonQtClassInfo();
89 89 ~PythonQtClassInfo();
90 90
91 91 //! store information about parent classes
92 92 struct ParentClassInfo {
93 93 ParentClassInfo(PythonQtClassInfo* parent, int upcastingOffset=0):_parent(parent),_upcastingOffset(upcastingOffset)
94 94 {};
95 95
96 96 PythonQtClassInfo* _parent;
97 97 int _upcastingOffset;
98 98 };
99 99
100 100
101 101 //! setup as a QObject, taking the meta object as meta information about the QObject
102 102 void setupQObject(const QMetaObject* meta);
103 103
104 104 //! setup as a CPP (non-QObject), taking the classname
105 105 void setupCPPObject(const QByteArray& classname);
106 106
107 107 //! set the type capabilities
108 108 void setTypeSlots(int typeSlots) { _typeSlots = typeSlots; }
109 109 //! get the type capabilities
110 110 int typeSlots() const { return _typeSlots; }
111 111
112 112 //! get the Python method definition for a given slot name (without return type and signature)
113 113 PythonQtMemberInfo member(const char* member);
114 114
115 115 //! get access to the constructor slot (which may be overloaded if there are multiple constructors)
116 116 PythonQtSlotInfo* constructors();
117 117
118 118 //! get access to the destructor slot
119 119 PythonQtSlotInfo* destructor();
120 120
121 121 //! add a constructor, ownership is passed to classinfo
122 122 void addConstructor(PythonQtSlotInfo* info);
123 123
124 124 //! set a destructor, ownership is passed to classinfo
125 125 void setDestructor(PythonQtSlotInfo* info);
126 126
127 127 //! add a decorator slot, ownership is passed to classinfo
128 128 void addDecoratorSlot(PythonQtSlotInfo* info);
129 129
130 130 //! get the classname (either of the QObject or of the wrapped CPP object)
131 131 const char* className();
132 132
133 133 //! returns if the QObject
134 134 bool isQObject() { return _isQObject; }
135 135
136 136 //! returns if the class is a CPP wrapper
137 137 bool isCPPWrapper() { return !_isQObject; }
138 138
139 139 //! get the meta object
140 140 const QMetaObject* metaObject() { return _meta; }
141 141
142 142 //! set the meta object, this will reset the caching
143 143 void setMetaObject(const QMetaObject* meta);
144 144
145 145 //! returns if this class inherits from the given classname
146 146 bool inherits(const char* classname);
147 147
148 148 //! returns if this class inherits from the given classinfo
149 149 bool inherits(PythonQtClassInfo* info);
150 150
151 151 //! casts the given \c ptr to an object of type \c classname, returns the new pointer
152 152 //! which might be different to \c ptr due to C++ multiple inheritance
153 153 //! (if the cast is not possible or if ptr is NULL, NULL is returned)
154 154 void* castTo(void* ptr, const char* classname);
155 155
156 156 //! get help string for the metaobject
157 157 QString help();
158 158
159 159 //! get list of all properties (on QObjects only, otherwise the list is empty)
160 160 QStringList propertyList();
161 161
162 162 //! get list of all members
163 163 QStringList memberList(bool metaOnly = false);
164 164
165 165 //! get the meta type id of this class (only valid for isCPPWrapper() == true)
166 166 int metaTypeId() { return _metaTypeId; }
167 167
168 168 //! set an additional decorator provider that offers additional decorator slots for this class
169 169 void setDecoratorProvider(PythonQtQObjectCreatorFunctionCB* cb);
170 170
171 171 //! get the decorator qobject instance
172 172 QObject* decorator();
173 173
174 174 //! add the parent class info of a CPP object
175 175 void addParentClass(const ParentClassInfo& info) { _parentClasses.append(info); }
176 176
177 177 //! check if the special method "py_hasOwner" is implemented and if it returns false, which means that the object may be destroyed
178 178 bool hasOwnerMethodButNoOwner(void* object);
179 179
180 180 //! set the associated PythonQtClassWrapper (which handles instance creation of this type)
181 181 void setPythonQtClassWrapper(PyObject* obj) { _pythonQtClassWrapper = obj; }
182 182
183 183 //! get the associated PythonQtClassWrapper (which handles instance creation of this type)
184 184 PyObject* pythonQtClassWrapper() { return _pythonQtClassWrapper; }
185 185
186 186 //! set the shell set instance wrapper cb
187 187 void setShellSetInstanceWrapperCB(PythonQtShellSetInstanceWrapperCB* cb) {
188 188 _shellSetInstanceWrapperCB = cb;
189 189 }
190 190
191 191 //! get the shell set instance wrapper cb
192 192 PythonQtShellSetInstanceWrapperCB* shellSetInstanceWrapperCB() {
193 193 return _shellSetInstanceWrapperCB;
194 194 }
195 195
196 196 //! add a handler for polymorphic downcasting
197 197 void addPolymorphicHandler(PythonQtPolymorphicHandlerCB* cb) { _polymorphicHandlers.append(cb); }
198 198
199 199 //! cast the pointer down in the class hierarchy if a polymorphic handler allows to do that
200 200 void* castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo);
201 201
202 202 //! returns if the localScope has an enum of that type name or if the enum contains a :: scope, if that class contails the enum
203 203 static PyObject* findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum = NULL);
204 204
205 205 //! clear all members that where cached as "NotFound"
206 206 void clearNotFoundCachedMembers();
207 207
208 208 private:
209 209 void createEnumWrappers();
210 210 void createEnumWrappers(const QMetaObject* meta);
211 211 PyObject* findEnumWrapper(const char* name);
212 212
213 213 //! clear all cached members
214 214 void clearCachedMembers();
215 215
216 void* recursiveCastDownIfPossible(void* ptr, char** resultClassName);
216 void* recursiveCastDownIfPossible(void* ptr, const char** resultClassName);
217 217
218 218 PythonQtSlotInfo* findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
219 219 void listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly);
220 220 PythonQtSlotInfo* recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
221 221
222 222 void recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects);
223 223 void recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects);
224 224
225 225 bool lookForPropertyAndCache(const char* memberName);
226 226 bool lookForMethodAndCache(const char* memberName);
227 227 bool lookForEnumAndCache(const QMetaObject* m, const char* memberName);
228 228
229 229 PythonQtSlotInfo* findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
230 230 int findCharOffset(const char* sigStart, char someChar);
231 231
232 232 QHash<QByteArray, PythonQtMemberInfo> _cachedMembers;
233 233
234 234 PythonQtSlotInfo* _constructors;
235 235 PythonQtSlotInfo* _destructor;
236 236 QList<PythonQtSlotInfo*> _decoratorSlots;
237 237
238 238 QList<PythonQtObjectPtr> _enumWrappers;
239 239
240 240 const QMetaObject* _meta;
241 241
242 242 QByteArray _wrappedClassName;
243 243 QList<ParentClassInfo> _parentClasses;
244 244
245 245 QList<PythonQtPolymorphicHandlerCB*> _polymorphicHandlers;
246 246
247 247 QObject* _decoratorProvider;
248 248 PythonQtQObjectCreatorFunctionCB* _decoratorProviderCB;
249 249
250 250 PyObject* _pythonQtClassWrapper;
251 251
252 252 PythonQtShellSetInstanceWrapperCB* _shellSetInstanceWrapperCB;
253 253
254 254 int _metaTypeId;
255 255 int _typeSlots;
256 256
257 257 bool _isQObject;
258 258 bool _enumsCreated;
259 259
260 260 };
261 261
262 262 //---------------------------------------------------------------
263 263
264 264
265 265 #endif
@@ -1,61 +1,62
1 1 #ifndef _PYTHONQTCPPWRAPPERFACTORY_H
2 2 #define _PYTHONQTCPPWRAPPERFACTORY_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, 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 PythonQtCppWrapperFactory.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-06
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 //! Factory interface for C++ classes that can be wrapped by QObject objects
46 46 /*! To create your own factory, derive PythonQtCppWrapperFactory and implement
47 47 the create() method.
48 48 A factory can be added to PythonQt by PythonQt::addCppWrapperFactory().
49 49 */
50 50 class PYTHONQT_EXPORT PythonQtCppWrapperFactory
51 51 {
52 52 public:
53 53 PythonQtCppWrapperFactory() {};
54 54 virtual ~PythonQtCppWrapperFactory() {};
55 55
56 56 //! create a wrapper for the given object
57 57 virtual QObject* create(const QByteArray& name, void *ptr) = 0;
58 58
59 59 };
60 60
61 61 #endif
62
@@ -1,75 +1,76
1 1 #ifndef _PYTHONQTIMPORTFILEINTERFACE_H
2 2 #define _PYTHONQTIMPORTFILEINTERFACE_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, 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 54 // get rid of warnings
55 55 virtual ~PythonQtImportFileInterface() {}
56 56
57 57 //! read the given file as byte array, without doing any linefeed translations
58 58 virtual QByteArray readFileAsBytes(const QString& filename) = 0;
59 59
60 60 //! read a source file, expects a readable Python text file with translated line feeds.
61 61 //! If the file can not be load OR it can not be verified, ok is set to false
62 62 virtual QByteArray readSourceFile(const QString& filename, bool& ok) = 0;
63 63
64 64 //! returns if the file exists
65 65 virtual bool exists(const QString& filename) = 0;
66 66
67 67 //! get the last modified data of a file
68 68 virtual QDateTime lastModifiedDate(const QString& filename) = 0;
69 69
70 70 //! indicates that *.py files which are newer than their corresponding *.pyc files
71 71 //! are ignored
72 72 virtual bool ignoreUpdatedPythonSourceFiles() { return false; }
73 73 };
74 74
75 75 #endif
76
@@ -1,350 +1,350
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, 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 PythonQtMethodInfo.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 "PythonQtMethodInfo.h"
43 43 #include "PythonQtClassInfo.h"
44 44 #include <iostream>
45 45
46 46 QHash<QByteArray, PythonQtMethodInfo*> PythonQtMethodInfo::_cachedSignatures;
47 47 QHash<QByteArray, QByteArray> PythonQtMethodInfo::_parameterNameAliases;
48 48
49 49 PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo)
50 50 {
51 51 #ifdef PYTHONQT_DEBUG
52 52 QByteArray sig(meta.signature());
53 53 sig = sig.mid(sig.indexOf('('));
54 54 QByteArray fullSig = QByteArray(meta.typeName()) + " " + sig;
55 55 std::cout << "caching " << fullSig.data() << std::endl;
56 56 #endif
57 57
58 58 ParameterInfo type;
59 59 fillParameterInfo(type, QByteArray(meta.typeName()), classInfo);
60 60 _parameters.append(type);
61 61 QList<QByteArray> names = meta.parameterTypes();
62 62 foreach (const QByteArray& name, names) {
63 63 fillParameterInfo(type, name, classInfo);
64 64 _parameters.append(type);
65 65 }
66 66 }
67 67
68 68 PythonQtMethodInfo::PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args)
69 69 {
70 70 ParameterInfo type;
71 71 fillParameterInfo(type, typeName, NULL);
72 72 _parameters.append(type);
73 73 foreach (const QByteArray& name, args) {
74 74 fillParameterInfo(type, name, NULL);
75 75 _parameters.append(type);
76 76 }
77 77 }
78 78
79 79 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo)
80 80 {
81 81 QByteArray sig(signal.signature());
82 82 sig = sig.mid(sig.indexOf('('));
83 83 QByteArray fullSig = QByteArray(signal.typeName()) + " " + sig;
84 84 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
85 85 if (!result) {
86 86 result = new PythonQtMethodInfo(signal, classInfo);
87 87 _cachedSignatures.insert(fullSig, result);
88 88 }
89 89 return result;
90 90 }
91 91
92 92 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(int numArgs, const char** args)
93 93 {
94 94 QByteArray typeName = args[0];
95 95 QList<QByteArray> arguments;
96 96 QByteArray fullSig = typeName;
97 97 fullSig += "(";
98 98 for (int i =1;i<numArgs; i++) {
99 99 if (i>1) {
100 100 fullSig += ",";
101 101 }
102 102 arguments << QByteArray(args[i]);
103 103 }
104 104 fullSig += ")";
105 105 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
106 106 if (!result) {
107 107 result = new PythonQtMethodInfo(typeName, arguments);
108 108 _cachedSignatures.insert(fullSig, result);
109 109 }
110 110 return result;
111 111 }
112 112
113 113 void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo)
114 114 {
115 115 QByteArray name = orgName;
116 116
117 117 type.enumWrapper = NULL;
118 118
119 119 int len = name.length();
120 120 if (len>0) {
121 121 if (strncmp(name.constData(), "const ", 6)==0) {
122 122 name = name.mid(6);
123 123 len -= 6;
124 124 type.isConst = true;
125 125 } else {
126 126 type.isConst = false;
127 127 }
128 128 char pointerCount = 0;
129 129 bool hadReference = false;
130 130 // remove * and & from the end of the string, handle & and * the same way
131 131 while (name.at(len-1) == '*') {
132 132 len--;
133 133 pointerCount++;
134 134 }
135 135 while (name.at(len-1) == '&') {
136 136 len--;
137 137 hadReference = true;
138 138 }
139 139 if (len!=name.length()) {
140 140 name = name.left(len);
141 141 }
142 142 type.pointerCount = pointerCount;
143 143
144 144 QByteArray alias = _parameterNameAliases.value(name);
145 145 if (!alias.isEmpty()) {
146 146 name = alias;
147 147 }
148 148
149 149 type.typeId = nameToType(name);
150 150 if ((type.pointerCount == 0) && type.typeId == Unknown) {
151 151 type.typeId = QMetaType::type(name.constData());
152 152 if (type.typeId == QMetaType::Void) {
153 153 type.typeId = Unknown;
154 154 }
155 155 }
156 156 type.name = name;
157 157
158 158 if (type.typeId == PythonQtMethodInfo::Unknown || type.typeId >= QMetaType::User) {
159 159 bool isLocalEnum;
160 160 // TODOXXX: make use of this flag!
161 161 type.enumWrapper = PythonQtClassInfo::findEnumWrapper(type.name, classInfo, &isLocalEnum);
162 162 }
163 163 } else {
164 164 type.typeId = QMetaType::Void;
165 165 type.pointerCount = 0;
166 166 type.isConst = false;
167 167 }
168 168 }
169 169
170 170 int PythonQtMethodInfo::nameToType(const char* name)
171 171 {
172 172 if (_parameterTypeDict.isEmpty()) {
173 173 // we could also use QMetaType::nameToType, but that does a string compare search
174 174 // and does not support QVariant
175 175
176 176 // QMetaType names
177 177 _parameterTypeDict.insert("long", QMetaType::Long);
178 178 _parameterTypeDict.insert("int", QMetaType::Int);
179 179 _parameterTypeDict.insert("short", QMetaType::Short);
180 180 _parameterTypeDict.insert("char", QMetaType::Char);
181 181 _parameterTypeDict.insert("ulong", QMetaType::ULong);
182 182 _parameterTypeDict.insert("unsigned long", QMetaType::ULong);
183 183 _parameterTypeDict.insert("uint", QMetaType::UInt);
184 184 _parameterTypeDict.insert("unsigned int", QMetaType::UInt);
185 185 _parameterTypeDict.insert("ushort", QMetaType::UShort);
186 186 _parameterTypeDict.insert("unsigned short", QMetaType::UShort);
187 187 _parameterTypeDict.insert("uchar", QMetaType::UChar);
188 188 _parameterTypeDict.insert("unsigned char", QMetaType::UChar);
189 189 _parameterTypeDict.insert("bool", QMetaType::Bool);
190 190 _parameterTypeDict.insert("float", QMetaType::Float);
191 191 _parameterTypeDict.insert("double", QMetaType::Double);
192 192 _parameterTypeDict.insert("qreal", QMetaType::Double);
193 193 _parameterTypeDict.insert("QChar", QMetaType::QChar);
194 194 _parameterTypeDict.insert("QByteArray", QMetaType::QByteArray);
195 195 _parameterTypeDict.insert("QString", QMetaType::QString);
196 196 _parameterTypeDict.insert("", QMetaType::Void);
197 197 _parameterTypeDict.insert("void", QMetaType::Void);
198 198 // QVariant names
199 199 _parameterTypeDict.insert("Q_LLONG", QMetaType::LongLong);
200 200 _parameterTypeDict.insert("Q_ULLONG", QMetaType::ULongLong);
201 201 _parameterTypeDict.insert("qlonglong", QMetaType::LongLong);
202 202 _parameterTypeDict.insert("qulonglong", QMetaType::ULongLong);
203 203 _parameterTypeDict.insert("qint64", QMetaType::LongLong);
204 204 _parameterTypeDict.insert("quint64", QMetaType::ULongLong);
205 205 _parameterTypeDict.insert("QVariantMap", QMetaType::QVariantMap);
206 206 _parameterTypeDict.insert("QVariantList", QMetaType::QVariantList);
207 207 _parameterTypeDict.insert("QMap<QString,QVariant>", QMetaType::QVariantMap);
208 208 _parameterTypeDict.insert("QList<QVariant>", QMetaType::QVariantList);
209 209 _parameterTypeDict.insert("QStringList", QMetaType::QStringList);
210 210 _parameterTypeDict.insert("QBitArray", QMetaType::QBitArray);
211 211 _parameterTypeDict.insert("QDate", QMetaType::QDate);
212 212 _parameterTypeDict.insert("QTime", QMetaType::QTime);
213 213 _parameterTypeDict.insert("QDateTime", QMetaType::QDateTime);
214 214 _parameterTypeDict.insert("QUrl", QMetaType::QUrl);
215 215 _parameterTypeDict.insert("QLocale", QMetaType::QLocale);
216 216 _parameterTypeDict.insert("QRect", QMetaType::QRect);
217 217 _parameterTypeDict.insert("QRectF", QMetaType::QRectF);
218 218 _parameterTypeDict.insert("QSize", QMetaType::QSize);
219 219 _parameterTypeDict.insert("QSizeF", QMetaType::QSizeF);
220 220 _parameterTypeDict.insert("QLine", QMetaType::QLine);
221 221 _parameterTypeDict.insert("QLineF", QMetaType::QLineF);
222 222 _parameterTypeDict.insert("QPoint", QMetaType::QPoint);
223 223 _parameterTypeDict.insert("QPointF", QMetaType::QPointF);
224 224 _parameterTypeDict.insert("QRegExp", QMetaType::QRegExp);
225 225 _parameterTypeDict.insert("QFont", QMetaType::QFont);
226 226 _parameterTypeDict.insert("QPixmap", QMetaType::QPixmap);
227 227 _parameterTypeDict.insert("QBrush", QMetaType::QBrush);
228 228 _parameterTypeDict.insert("QColor", QMetaType::QColor);
229 229 _parameterTypeDict.insert("QCursor", QMetaType::QCursor);
230 230 _parameterTypeDict.insert("QPalette", QMetaType::QPalette);
231 231 _parameterTypeDict.insert("QIcon", QMetaType::QIcon);
232 232 _parameterTypeDict.insert("QImage", QMetaType::QImage);
233 233 _parameterTypeDict.insert("QRegion", QMetaType::QRegion);
234 234 _parameterTypeDict.insert("QBitmap", QMetaType::QBitmap);
235 235 _parameterTypeDict.insert("QSizePolicy", QMetaType::QSizePolicy);
236 236 _parameterTypeDict.insert("QKeySequence", QMetaType::QKeySequence);
237 237 _parameterTypeDict.insert("QPen", QMetaType::QPen);
238 238 _parameterTypeDict.insert("QTextLength", QMetaType::QTextLength);
239 239 _parameterTypeDict.insert("QTextFormat", QMetaType::QTextFormat);
240 240 _parameterTypeDict.insert("QMatrix", QMetaType::QMatrix);
241 241 _parameterTypeDict.insert("QVariant", PythonQtMethodInfo::Variant);
242 242 // own special types... (none so far, could be e.g. ObjectList
243 243 }
244 244 QHash<QByteArray, int>::const_iterator it = _parameterTypeDict.find(name);
245 245 if (it!=_parameterTypeDict.end()) {
246 246 return it.value();
247 247 } else {
248 248 return PythonQtMethodInfo::Unknown;
249 249 }
250 250 }
251 251
252 252 void PythonQtMethodInfo::cleanupCachedMethodInfos()
253 253 {
254 254 QHashIterator<QByteArray, PythonQtMethodInfo *> i(_cachedSignatures);
255 255 while (i.hasNext()) {
256 256 delete i.next().value();
257 257 }
258 258 }
259 259
260 260 void PythonQtMethodInfo::addParameterTypeAlias(const QByteArray& alias, const QByteArray& name)
261 261 {
262 262 _parameterNameAliases.insert(alias, name);
263 263 }
264 264
265 265 //-------------------------------------------------------------------------------------------------
266 266
267 267 void PythonQtSlotInfo::deleteOverloadsAndThis()
268 268 {
269 269 PythonQtSlotInfo* cur = this;
270 270 while(cur->nextInfo()) {
271 271 PythonQtSlotInfo* next = cur->nextInfo();
272 272 delete cur;
273 273 cur = next;
274 274 }
275 275 }
276 276
277 277
278 278 QString PythonQtSlotInfo::fullSignature()
279 279 {
280 280 bool skipFirstArg = isInstanceDecorator();
281 281 QString result = _meta.typeName();
282 282 QByteArray sig = slotName();
283 283 QList<QByteArray> names = _meta.parameterNames();
284 284
285 285 bool isStatic = false;
286 286 bool isConstructor = false;
287 287 bool isDestructor = false;
288 288
289 289 if (_type == ClassDecorator) {
290 290 if (sig.startsWith("new_")) {
291 sig = sig.mid(strlen("new_"));
291 sig = sig.mid(4);
292 292 isConstructor = true;
293 293 } else if (sig.startsWith("delete_")) {
294 sig = sig.mid(strlen("delete_"));
294 sig = sig.mid(7);
295 295 isDestructor = true;
296 296 } else if(sig.startsWith("static_")) {
297 297 isStatic = true;
298 sig = sig.mid(strlen("static_"));
298 sig = sig.mid(7);
299 299 int idx = sig.indexOf("_");
300 300 if (idx>=0) {
301 301 sig = sig.mid(idx+1);
302 302 }
303 303 }
304 304 }
305 305
306 306 result += QByteArray(" ") + sig;
307 307 result += "(";
308 308
309 309 int lastEntry = _parameters.count()-1;
310 310 for (int i = skipFirstArg?2:1; i<_parameters.count(); i++) {
311 311 if (_parameters.at(i).isConst) {
312 312 result += "const ";
313 313 }
314 314 result += _parameters.at(i).name;
315 315 if (_parameters.at(i).pointerCount) {
316 316 QByteArray stars;
317 317 stars.fill('*', _parameters.at(i).pointerCount);
318 318 result += stars;
319 319 }
320 320 if (!names.at(i-1).isEmpty()) {
321 321 result += " ";
322 322 result += names.at(i-1);
323 323 }
324 324 if (i!=lastEntry) {
325 325 result += ", ";
326 326 }
327 327 }
328 328 result += ")";
329 329
330 330 if (isStatic) {
331 331 result = QString("static ") + result;
332 332 }
333 333 if (isConstructor) {
334 334 // result = QString("constructor ") + result;
335 335 }
336 336 if (isDestructor) {
337 337 result = QString("~") + result;
338 338 }
339 339 return result;
340 340 }
341 341
342 342
343 343 QByteArray PythonQtSlotInfo::slotName()
344 344 {
345 345 QByteArray sig(_meta.signature());
346 346 int idx = sig.indexOf('(');
347 347 sig = sig.left(idx);
348 348 return sig;
349 349 }
350 350
@@ -1,43 +1,45
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 $$PWD/PythonQtStdIn.h \
10 11 $$PWD/PythonQtStdOut.h \
11 12 $$PWD/PythonQtMisc.h \
12 13 $$PWD/PythonQtMethodInfo.h \
13 14 $$PWD/PythonQtImportFileInterface.h \
14 15 $$PWD/PythonQtConversion.h \
15 16 $$PWD/PythonQtSignalReceiver.h \
16 17 $$PWD/PythonQtInstanceWrapper.h \
17 18 $$PWD/PythonQtClassWrapper.h \
18 19 $$PWD/PythonQtCppWrapperFactory.h \
19 20 $$PWD/PythonQtQFileImporter.h \
20 21 $$PWD/PythonQtQFileImporter.h \
21 22 $$PWD/PythonQtVariants.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 \
32 $$PWD/PythonQtStdIn.cpp \
31 33 $$PWD/PythonQtStdOut.cpp \
32 34 $$PWD/PythonQtSlot.cpp \
33 35 $$PWD/PythonQtMisc.cpp \
34 36 $$PWD/PythonQtMethodInfo.cpp \
35 37 $$PWD/PythonQtConversion.cpp \
36 38 $$PWD/PythonQtSignalReceiver.cpp \
37 39 $$PWD/PythonQtInstanceWrapper.cpp \
38 40 $$PWD/PythonQtQFileImporter.cpp \
39 41 $$PWD/PythonQtClassWrapper.cpp \
40 42 $$PWD/gui/PythonQtScriptingConsole.cpp \
41 43
42 44 include($$PWD/../generated_cpp/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin.pri)
43 45 include($$PWD/../generated_cpp/com_trolltech_qt_gui_builtin/com_trolltech_qt_gui_builtin.pri)
General Comments 0
You need to be logged in to leave comments. Login now