##// END OF EJS Templates
Fix __getattr__ problems.
Orochimarufan -
r207:99eb8a233276
parent child
Show More
@@ -1,138 +1,142
1 1 project(PythonQt)
2 2 cmake_minimum_required(VERSION 2.8.10)
3 3
4 4 include(CTestUseLaunchers OPTIONAL)
5 5
6 6 set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
7 7
8 8 #-----------------------------------------------------------------------------
9 9 # Debug
10 10 option(PythonQt_DEBUG "Enable/Disable PythonQt debug output" OFF)
11 11 if(PythonQt_DEBUG)
12 12 add_definitions(-DPYTHONQT_DEBUG)
13 13 else()
14 14 remove_definitions(-DPYTHONQT_DEBUG)
15 15 endif()
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Qt
19 19 option(PythonQt_Qt5 "Use Qt 5.x (5.1+)" OFF)
20 20 if(PythonQt_Qt5)
21 21 include(PythonQt_Qt_5x)
22 22 else(PythonQt_Qt5)
23 23 include(PythonQt_Qt_4x)
24 24 endif(PythonQt_Qt5)
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # The variable "generated_cpp_suffix" allows to conditionnally compile the generated wrappers
28 28 # associated with the Qt version being used.
29 29 if(PythonQt_Qt5)
30 30 set(generated_cpp_suffix "_${Qt5Core_VERSION_MAJOR}${Qt5Core_VERSION_MINOR}")
31 31 else()
32 32 set(generated_cpp_suffix "_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}")
33 33 endif()
34 34
35 35 if("${generated_cpp_suffix}" STREQUAL "_48")
36 36 set(generated_cpp_suffix "")
37 37 endif()
38 38 if("${generated_cpp_suffix}" STREQUAL "_46")
39 39 set(generated_cpp_suffix "_47") # Also use 4.7 wrappers for 4.6.x version
40 40 endif()
41 41 if("${generated_cpp_suffix}" STREQUAL "_51")
42 42 set(generated_cpp_suffix "_50")
43 43 endif()
44 44
45 45 #-----------------------------------------------------------------------------
46 46 # Generator
47 47 if(PythonQt_Qt5)
48 48 add_subdirectory(generator_50 EXCLUDE_FROM_ALL)
49 49 add_custom_target(generator)
50 50 add_dependencies(generator pythonqt_generator)
51 51 endif()
52 52
53 53 # TODO
54 54
55 55 #-----------------------------------------------------------------------------
56 56 # Build options
57 57
58 58 #option(PythonQt_Wrap_QtAll "Make all Qt components available in python" OFF)
59 59 #
60 60 #set(qtlibs core gui network opengl sql svg uitools webkit xml xmlpatterns)
61 61 #foreach(qtlib ${qtlibs})
62 62 # OPTION(PythonQt_Wrap_Qt${qtlib} "Make all of Qt${qtlib} available in python" OFF)
63 63 #endforeach()
64 64
65 65 # Force option if it applies
66 66 #if(PythonQt_Wrap_QtAll)
67 67 # list(REMOVE_ITEM qtlibs xmlpatterns) # xmlpatterns wrapper does *NOT* build at all :(
68 68 # foreach(qtlib ${qtlibs})
69 69 # if(NOT ${PythonQt_Wrap_Qt${qtlib}})
70 70 # set(PythonQt_Wrap_Qt${qtlib} ON CACHE BOOL "Make all of Qt${qtlib} available in python" FORCE)
71 71 # message(STATUS "Enabling [PythonQt_Wrap_Qt${qtlib}] because of [PythonQt_Wrap_QtAll] evaluates to True")
72 72 # endif()
73 73 # endforeach()
74 74 #endif()
75 75
76 76 #-----------------------------------------------------------------------------
77 77 # Add extra sources
78 78 #foreach(qtlib core gui network opengl sql svg uitools webkit xml xmlpatterns)
79 79 #
80 80 # if (${PythonQt_Wrap_Qt${qtlib}})
81 81 #
82 82 # ADD_DEFINITIONS(-DPYTHONQT_WRAP_Qt${qtlib})
83 83 #
84 84 # set(file_prefix generated_cpp${generated_cpp_suffix}/com_trolltech_qt_${qtlib}/com_trolltech_qt_${qtlib})
85 85 #
86 86 # foreach(index RANGE 0 11)
87 87 #
88 88 # # Source files
89 89 # if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file_prefix}${index}.cpp)
90 90 # list(APPEND sources ${file_prefix}${index}.cpp)
91 91 # endif()
92 92 #
93 93 # # Headers that should run through moc
94 94 # if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file_prefix}${index}.h)
95 95 # list(APPEND moc_sources ${file_prefix}${index}.h)
96 96 # endif()
97 97 #
98 98 # endforeach()
99 99 #
100 100 # list(APPEND sources ${file_prefix}_init.cpp)
101 101 #
102 102 # endif()
103 103 #endforeach()
104 104
105 105 #-----------------------------------------------------------------------------
106 106 # Find Python
107 107 option(PythonQt_Python3 "Use Python 3.x (3.3+)" OFF)
108 if(PythonQt_Python3)
109 set(PythonQt_PythonMin 3.3)
110 else(PythonQt_Python3)
111 set(PythonQt_PythonMin 2.6)
108 option(PythonQt_Python "Use specific Python Version" OFF)
109 if(PythonQt_Python)
110 find_package(Python ${PythonQt_Python} REQUIRED EXACT)
111 elseif(PythonQt_Python3)
112 find_package(Python 3.3 REQUIRED)
113 else()
114 find_package(Python 2.6 REQUIRED)
112 115 endif()
113 116
114 find_package(Python ${PythonQt_PythonMin} REQUIRED)
115 117 include_directories(${PYTHON_INCLUDE_DIRS})
116 118 add_definitions(-DPYTHONQT_USE_RELEASE_PYTHON_FALLBACK)
117 119
120 #-----------------------------------------------------------------------------
121 # Core
118 122 add_subdirectory(src)
119 123
120 124 #-----------------------------------------------------------------------------
121 125 # Tests
122 126 add_subdirectory(tests EXCLUDE_FROM_ALL)
123 127 # test alias
124 128 add_custom_target(test COMMAND tests/PythonQtTest WORKING_DIRECTORY ${CURRENT_BINARY_DIR})
125 129 add_dependencies(test PythonQtTest)
126 130
127 131 #-----------------------------------------------------------------------------
128 132 # Extenseions (QtAll)
129 133 add_subdirectory(extensions EXCLUDE_FROM_ALL)
130 134 # QtAll alias
131 135 add_custom_target(QtAll)
132 136 add_dependencies(QtAll PythonQt_QtAll)
133 137
134 138 #-----------------------------------------------------------------------------
135 139 # Examples
136 140 include_directories(src)
137 141 include_directories(extensions/PythonQt_QtAll)
138 142 add_subdirectory(examples EXCLUDE_FROM_ALL)
@@ -1,2064 +1,2067
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 "PythonQt.h"
43 43 #include "PythonQtImporter.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include "PythonQtMethodInfo.h"
46 46 #include "PythonQtSignal.h"
47 47 #include "PythonQtSignalReceiver.h"
48 48 #include "PythonQtConversion.h"
49 49 #include "PythonQtStdIn.h"
50 50 #include "PythonQtStdOut.h"
51 51 #include "PythonQtCppWrapperFactory.h"
52 52 #include "PythonQtVariants.h"
53 53 #include "PythonQtStdDecorators.h"
54 54 #include "PythonQtQFileImporter.h"
55 55 #include <pydebug.h>
56 56 #include <vector>
57 57
58 58 PythonQt* PythonQt::_self = NULL;
59 59 int PythonQt::_uniqueModuleCount = 0;
60 60
61 61 void PythonQt_init_QtGuiBuiltin(PyObject*);
62 62 void PythonQt_init_QtCoreBuiltin(PyObject*);
63 63
64 64
65 65 PyObject* PythonQtConvertFromStringRef(const void* inObject, int /*metaTypeId*/)
66 66 {
67 67 return PythonQtConv::QStringToPyObject(((QStringRef*)inObject)->toString());
68 68 }
69 69
70 70 void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
71 71 {
72 72 if (!_self) {
73 73 _self = new PythonQt(flags, pythonQtModuleName);
74 74
75 75 PythonQt::priv()->setupSharedLibrarySuffixes();
76 76
77 77 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
78 78 qRegisterMetaType<QList<QObject*> >("QList<void*>");
79 79
80 80 int stringRefId = qRegisterMetaType<QStringRef>("QStringRef");
81 81 PythonQtConv::registerMetaTypeToPythonConverter(stringRefId, PythonQtConvertFromStringRef);
82 82
83 83 PythonQtRegisterToolClassesTemplateConverter(int);
84 84 PythonQtRegisterToolClassesTemplateConverter(float);
85 85 PythonQtRegisterToolClassesTemplateConverter(double);
86 86 PythonQtRegisterToolClassesTemplateConverter(qint32);
87 87 PythonQtRegisterToolClassesTemplateConverter(quint32);
88 88 PythonQtRegisterToolClassesTemplateConverter(qint64);
89 89 PythonQtRegisterToolClassesTemplateConverter(quint64);
90 90 // TODO: which other POD types should be available for QList etc.
91 91
92 92 PythonQt_init_QtCoreBuiltin(NULL);
93 93 PythonQt_init_QtGuiBuiltin(NULL);
94 94
95 95 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
96 96 PythonQt::self()->registerCPPClass("QMetaObject",0, "QtCore", PythonQtCreateObject<PythonQtWrapper_QMetaObject>);
97 97
98 98 PythonQtRegisterToolClassesTemplateConverter(QByteArray);
99 99 PythonQtRegisterToolClassesTemplateConverter(QDate);
100 100 PythonQtRegisterToolClassesTemplateConverter(QTime);
101 101 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
102 102 PythonQtRegisterToolClassesTemplateConverter(QUrl);
103 103 PythonQtRegisterToolClassesTemplateConverter(QLocale);
104 104 PythonQtRegisterToolClassesTemplateConverter(QRect);
105 105 PythonQtRegisterToolClassesTemplateConverter(QRectF);
106 106 PythonQtRegisterToolClassesTemplateConverter(QSize);
107 107 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
108 108 PythonQtRegisterToolClassesTemplateConverter(QLine);
109 109 PythonQtRegisterToolClassesTemplateConverter(QLineF);
110 110 PythonQtRegisterToolClassesTemplateConverter(QPoint);
111 111 PythonQtRegisterToolClassesTemplateConverter(QPointF);
112 112 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
113 113
114 114 PythonQtRegisterToolClassesTemplateConverter(QFont);
115 115 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
116 116 PythonQtRegisterToolClassesTemplateConverter(QBrush);
117 117 PythonQtRegisterToolClassesTemplateConverter(QColor);
118 118 PythonQtRegisterToolClassesTemplateConverter(QPalette);
119 119 PythonQtRegisterToolClassesTemplateConverter(QIcon);
120 120 PythonQtRegisterToolClassesTemplateConverter(QImage);
121 121 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
122 122 PythonQtRegisterToolClassesTemplateConverter(QRegion);
123 123 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
124 124 PythonQtRegisterToolClassesTemplateConverter(QCursor);
125 125 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
126 126 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
127 127 PythonQtRegisterToolClassesTemplateConverter(QPen);
128 128 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
129 129 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
130 130 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
131 131
132 132
133 133 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
134 134 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
135 135 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
136 136 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
137 137 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
138 138 for (unsigned int i = 0;i<16; i++) {
139 139 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
140 140 if (obj) {
141 141 PyModule_AddObject(pack, names[i], obj);
142 142 Py_INCREF(obj);
143 143 PyModule_AddObject(pack2, names[i], obj);
144 144 } else {
145 std::cerr << "method not found " << names[i];
145 std::cerr << "method not found " << names[i] << std::endl;
146 146 }
147 147 }
148 148 }
149 149 }
150 150
151 151 void PythonQt::cleanup()
152 152 {
153 153 if (_self) {
154 154 delete _self;
155 155 _self = NULL;
156 156 }
157 157 }
158 158
159 159 PythonQt* PythonQt::self() { return _self; }
160 160
161 161 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
162 162 {
163 163 _p = new PythonQtPrivate;
164 164 _p->_initFlags = flags;
165 165
166 166 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
167 167
168 168 if ((flags & PythonAlreadyInitialized) == 0) {
169 169 #ifdef PY3K
170 170 Py_SetProgramName(const_cast<wchar_t*>(L"PythonQt"));
171 171 #else
172 172 Py_SetProgramName(const_cast<char*>("PythonQt"));
173 173 #endif
174 174 if (flags & IgnoreSiteModule) {
175 175 // this prevents the automatic importing of Python site files
176 176 Py_NoSiteFlag = 1;
177 177 }
178 178 Py_Initialize();
179 179 }
180 180
181 181 // add our own python object types for qt object slots
182 182 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
183 183 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
184 184 }
185 185 Py_INCREF(&PythonQtSlotFunction_Type);
186 186
187 187 if (PyType_Ready(&PythonQtSignalFunction_Type) < 0) {
188 188 std::cerr << "could not initialize PythonQtSignalFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
189 189 }
190 190 Py_INCREF(&PythonQtSignalFunction_Type);
191 191
192 192 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
193 193 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
194 194 // add our own python object types for classes
195 195 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
196 196 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
197 197 }
198 198 Py_INCREF(&PythonQtClassWrapper_Type);
199 199
200 200 // add our own python object types for CPP instances
201 201 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
202 202 PythonQt::handleError();
203 203 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
204 204 }
205 205 Py_INCREF(&PythonQtInstanceWrapper_Type);
206 206
207 207 // add our own python object types for redirection of stdout
208 208 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
209 209 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
210 210 }
211 211 Py_INCREF(&PythonQtStdOutRedirectType);
212 212
213 213 // add our own python object types for redirection of stdin
214 214 if (PyType_Ready(&PythonQtStdInRedirectType) < 0) {
215 215 std::cerr << "could not initialize PythonQtStdInRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
216 216 }
217 217 Py_INCREF(&PythonQtStdInRedirectType);
218 218
219 219 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
220 220
221 221 }
222 222
223 223 PythonQt::~PythonQt() {
224 224 delete _p;
225 225 _p = NULL;
226 226 }
227 227
228 228 PythonQtPrivate::~PythonQtPrivate() {
229 229 delete _defaultImporter;
230 230 _defaultImporter = NULL;
231 231
232 232 {
233 233 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
234 234 while (i.hasNext()) {
235 235 delete i.next().value();
236 236 }
237 237 }
238 238 PythonQtConv::global_valueStorage.clear();
239 239 PythonQtConv::global_ptrStorage.clear();
240 240 PythonQtConv::global_variantStorage.clear();
241 241
242 242 PythonQtMethodInfo::cleanupCachedMethodInfos();
243 243 }
244 244
245 245 void PythonQt::setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData)
246 246 {
247 247 if (!callback)
248 248 {
249 249 std::cerr << "PythonQt::setRedirectStdInCallback - callback parameter is NULL !" << std::endl;
250 250 return;
251 251 }
252 252
253 253 PythonQtObjectPtr sys;
254 254 PythonQtObjectPtr in;
255 255 sys.setNewRef(PyImport_ImportModule("sys"));
256 256
257 257 // Backup original 'sys.stdin' if not yet done
258 258 if( !PyObject_HasAttrString(sys.object(), "pythonqt_original_stdin") )
259 259 PyObject_SetAttrString(sys.object(), "pythonqt_original_stdin", PyObject_GetAttrString(sys.object(), "stdin"));
260 260
261 261 in = PythonQtStdInRedirectType.tp_new(&PythonQtStdInRedirectType, NULL, NULL);
262 262 ((PythonQtStdInRedirect*)in.object())->_cb = callback;
263 263 ((PythonQtStdInRedirect*)in.object())->_callData = callbackData;
264 264 // replace the built in file objects with our own objects
265 265 PyModule_AddObject(sys.object(), "stdin", in);
266 266
267 267 // Backup custom 'stdin' into 'pythonqt_stdin'
268 268 Py_IncRef(in);
269 269 PyModule_AddObject(sys.object(), "pythonqt_stdin", in);
270 270 }
271 271
272 272 void PythonQt::setRedirectStdInCallbackEnabled(bool enabled)
273 273 {
274 274 PythonQtObjectPtr sys;
275 275 sys.setNewRef(PyImport_ImportModule("sys"));
276 276
277 277 if (enabled)
278 278 {
279 279 if( !PyObject_HasAttrString(sys.object(), "pythonqt_stdin") )
280 280 PyObject_SetAttrString(sys.object(), "stdin", PyObject_GetAttrString(sys.object(), "pythonqt_stdin"));
281 281 }
282 282 else
283 283 {
284 284 if( !PyObject_HasAttrString(sys.object(), "pythonqt_original_stdin") )
285 285 PyObject_SetAttrString(sys.object(), "stdin", PyObject_GetAttrString(sys.object(), "pythonqt_original_stdin"));
286 286 }
287 287 }
288 288
289 289 PythonQtImportFileInterface* PythonQt::importInterface()
290 290 {
291 291 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
292 292 }
293 293
294 294 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
295 295 {
296 296 if (_self->_p->_noLongerWrappedCB) {
297 297 (*_self->_p->_noLongerWrappedCB)(o);
298 298 };
299 299 }
300 300
301 301 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
302 302 {
303 303 _p->registerClass(metaobject, package, wrapperCreator, shell);
304 304 }
305 305
306 306 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
307 307 {
308 308 // we register all classes in the hierarchy
309 309 const QMetaObject* m = metaobject;
310 310 bool first = true;
311 311 while (m) {
312 312 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
313 313 if (!info->pythonQtClassWrapper()) {
314 314 info->setTypeSlots(typeSlots);
315 315 info->setupQObject(m);
316 316 createPythonQtClassWrapper(info, package, module);
317 317 if (m->superClass()) {
318 318 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
319 319 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
320 320 }
321 321 } else if (first && module) {
322 322 // There is a wrapper already, but if we got a module, we want to place the wrapper into that module as well,
323 323 // since it might have been placed into "private" earlier on.
324 324 // If the wrapper was already added to module before, it is just readded, which does no harm.
325 325 PyObject* classWrapper = info->pythonQtClassWrapper();
326 326 // AddObject steals a reference, so we need to INCREF
327 327 Py_INCREF(classWrapper);
328 328 PyModule_AddObject(module, info->className(), classWrapper);
329 329 }
330 330 if (first) {
331 331 first = false;
332 332 if (wrapperCreator) {
333 333 info->setDecoratorProvider(wrapperCreator);
334 334 }
335 335 if (shell) {
336 336 info->setShellSetInstanceWrapperCB(shell);
337 337 }
338 338 }
339 339 m = m->superClass();
340 340 }
341 341 }
342 342
343 343 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
344 344 {
345 345 PyObject* pack = module?module:packageByName(package);
346 346 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
347 347 PyModule_AddObject(pack, info->className(), pyobj);
348 348 if (!module && package && strncmp(package,"Qt",2)==0) {
349 349 // since PyModule_AddObject steals the reference, we need a incref once more...
350 350 Py_INCREF(pyobj);
351 351 // put all qt objects into Qt as well
352 352 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
353 353 }
354 354 info->setPythonQtClassWrapper(pyobj);
355 355 }
356 356
357 357 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
358 358 {
359 359 if (!obj) {
360 360 Py_INCREF(Py_None);
361 361 return Py_None;
362 362 }
363 363 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
364 364 if (wrap && wrap->_wrappedPtr) {
365 365 // uh oh, we want to wrap a QObject, but have a C++ wrapper at that
366 366 // address, so probably that C++ wrapper has been deleted earlier and
367 367 // now we see a QObject with the same address.
368 368 // Do not use the old wrapper anymore.
369 369 wrap = NULL;
370 370 }
371 371 if (!wrap) {
372 372 // smuggling it in...
373 373 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
374 374 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
375 375 registerClass(obj->metaObject());
376 376 classInfo = _knownClassInfos.value(obj->metaObject()->className());
377 377 }
378 378 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
379 379 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
380 380 } else {
381 381 Py_INCREF(wrap);
382 382 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
383 383 }
384 384 return (PyObject*)wrap;
385 385 }
386 386
387 387 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
388 388 {
389 389 if (!ptr) {
390 390 Py_INCREF(Py_None);
391 391 return Py_None;
392 392 }
393 393
394 394 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
395 395 PythonQtInstanceWrapper* possibleStillAliveWrapper = NULL;
396 396 if (wrap && wrap->_wrappedPtr) {
397 397 // we have a previous C++ wrapper... if the wrapper is for a C++ object,
398 398 // we are not sure if it may have been deleted earlier and we just see the same C++
399 399 // pointer once again. To make sure that we do not reuse a wrapper of the wrong type,
400 400 // we compare the classInfo() pointer and only reuse the wrapper if it has the same
401 401 // info. This is only needed for non-QObjects, since we know it when a QObject gets deleted.
402 402 possibleStillAliveWrapper = wrap;
403 403 wrap = NULL;
404 404 }
405 405 if (!wrap) {
406 406 PythonQtClassInfo* info = _knownClassInfos.value(name);
407 407 if (!info) {
408 408 // maybe it is a PyObject, which we can return directly
409 409 if (name == "PyObject") {
410 410 PyObject* p = (PyObject*)ptr;
411 411 Py_INCREF(p);
412 412 return p;
413 413 }
414 414
415 415 // we do not know the metaobject yet, but we might know it by its name:
416 416 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
417 417 // yes, we know it, so we can convert to QObject
418 418 QObject* qptr = (QObject*)ptr;
419 419 registerClass(qptr->metaObject());
420 420 info = _knownClassInfos.value(qptr->metaObject()->className());
421 421 }
422 422 }
423 423 if (info && info->isQObject()) {
424 424 QObject* qptr = (QObject*)ptr;
425 425 // if the object is a derived object, we want to switch the class info to the one of the derived class:
426 426 if (name!=(qptr->metaObject()->className())) {
427 427 info = _knownClassInfos.value(qptr->metaObject()->className());
428 428 if (!info) {
429 429 registerClass(qptr->metaObject());
430 430 info = _knownClassInfos.value(qptr->metaObject()->className());
431 431 }
432 432 }
433 433 wrap = createNewPythonQtInstanceWrapper(qptr, info);
434 434 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
435 435 return (PyObject*)wrap;
436 436 }
437 437
438 438 // not a known QObject, try to wrap via foreign wrapper factories
439 439 PyObject* foreignWrapper = NULL;
440 440 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
441 441 foreignWrapper = _foreignWrapperFactories.at(i)->wrap(name, ptr);
442 442 if (foreignWrapper) {
443 443 return foreignWrapper;
444 444 }
445 445 }
446 446
447 447 // not a known QObject, so try our wrapper factory:
448 448 QObject* wrapper = NULL;
449 449 for (int i=0; i<_cppWrapperFactories.size(); i++) {
450 450 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
451 451 if (wrapper) {
452 452 break;
453 453 }
454 454 }
455 455
456 456 if (info) {
457 457 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
458 458 ptr = info->castDownIfPossible(ptr, &info);
459 459
460 460 // if downcasting found out that the object is a QObject,
461 461 // handle it like one:
462 462 if (info && info->isQObject()) {
463 463 QObject* qptr = (QObject*)ptr;
464 464 // if the object is a derived object, we want to switch the class info to the one of the derived class:
465 465 if (name!=(qptr->metaObject()->className())) {
466 466 registerClass(qptr->metaObject());
467 467 info = _knownClassInfos.value(qptr->metaObject()->className());
468 468 }
469 469 wrap = createNewPythonQtInstanceWrapper(qptr, info);
470 470 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
471 471 return (PyObject*)wrap;
472 472 }
473 473 }
474 474
475 475 if (!info || info->pythonQtClassWrapper()==NULL) {
476 476 // still unknown, register as CPP class
477 477 registerCPPClass(name.constData());
478 478 info = _knownClassInfos.value(name);
479 479 }
480 480 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
481 481 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
482 482 info->setMetaObject(wrapper->metaObject());
483 483 }
484 484
485 485 if (possibleStillAliveWrapper && possibleStillAliveWrapper->classInfo() == info) {
486 486 wrap = possibleStillAliveWrapper;
487 487 Py_INCREF(wrap);
488 488 } else {
489 489 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
490 490 }
491 491 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
492 492 } else {
493 493 Py_INCREF(wrap);
494 494 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
495 495 }
496 496 return (PyObject*)wrap;
497 497 }
498 498
499 499 PyObject* PythonQtPrivate::dummyTuple() {
500 500 static PyObject* dummyTuple = NULL;
501 501 if (dummyTuple==NULL) {
502 502 dummyTuple = PyTuple_New(1);
503 503 #ifdef PY3K
504 504 PyTuple_SET_ITEM(dummyTuple, 0, PyUnicode_FromString("dummy"));
505 505 #else
506 506 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
507 507 #endif
508 508 }
509 509 return dummyTuple;
510 510 }
511 511
512 512
513 513 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
514 514 // call the associated class type to create a new instance...
515 515 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
516 516
517 517 result->setQObject(obj);
518 518 result->_wrappedPtr = wrappedPtr;
519 519 result->_ownedByPythonQt = false;
520 520 result->_useQMetaTypeDestroy = false;
521 521
522 522 if (wrappedPtr) {
523 523 _wrappedObjects.insert(wrappedPtr, result);
524 524 } else {
525 525 _wrappedObjects.insert(obj, result);
526 526 if (obj->parent()== NULL && _wrappedCB) {
527 527 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
528 528 (*_wrappedCB)(obj);
529 529 }
530 530 }
531 531 return result;
532 532 }
533 533
534 534 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
535 535 PythonQtClassWrapper* result;
536 536
537 537 #ifdef PY3K
538 538 PyObject* className = PyUnicode_FromString(info->className());
539 539 #else
540 540 PyObject* className = PyString_FromString(info->className());
541 541 #endif
542 542
543 543 PyObject* baseClasses = PyTuple_New(1);
544 544 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
545 545
546 546 PyObject* typeDict = PyDict_New();
547 547 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
548 548 PyDict_SetItemString(typeDict, "__module__", moduleName);
549 549
550 550 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
551 551
552 552 // set the class info so that PythonQtClassWrapper_new can read it
553 553 _currentClassInfoForClassWrapperCreation = info;
554 554 // create the new type object by calling the type
555 555 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
556 556
557 557 Py_DECREF(baseClasses);
558 558 Py_DECREF(typeDict);
559 559 Py_DECREF(args);
560 560 Py_DECREF(className);
561 561
562 562 return result;
563 563 }
564 564
565 565 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
566 566 {
567 567 PyObject* args = Py_BuildValue("(i)", enumValue);
568 568 PyObject* result = PyObject_Call(enumType, args, NULL);
569 569 Py_DECREF(args);
570 570 return result;
571 571 }
572 572
573 573 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
574 574 PyObject* result;
575 575
576 576 #ifdef PY3K
577 577 PyObject* className = PyUnicode_FromString(enumName);
578 578 #else
579 579 PyObject* className = PyString_FromString(enumName);
580 580 #endif
581 581
582 582 PyObject* baseClasses = PyTuple_New(1);
583 583 #ifdef PY3K
584 584 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyLong_Type);
585 585 #else
586 586 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
587 587 #endif
588 588
589 589 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
590 590 PyObject* typeDict = PyDict_New();
591 591 PyDict_SetItemString(typeDict, "__module__", module);
592 592
593 593 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
594 594
595 595 // create the new int derived type object by calling the core type
596 596 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
597 597
598 598 Py_DECREF(baseClasses);
599 599 Py_DECREF(typeDict);
600 600 Py_DECREF(args);
601 601 Py_DECREF(className);
602 602
603 603 return result;
604 604 }
605 605
606 606 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
607 607 {
608 608 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
609 609 if (!r) {
610 610 r = new PythonQtSignalReceiver(obj);
611 611 _p->_signalReceivers.insert(obj, r);
612 612 }
613 613 return r;
614 614 }
615 615
616 616 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
617 617 {
618 618 bool flag = false;
619 619 PythonQtObjectPtr callable = lookupCallable(module, objectname);
620 620 if (callable) {
621 621 PythonQtSignalReceiver* r = getSignalReceiver(obj);
622 622 flag = r->addSignalHandler(signal, callable);
623 623 if (!flag) {
624 624 // signal not found
625 625 }
626 626 } else {
627 627 // callable not found
628 628 }
629 629 return flag;
630 630 }
631 631
632 632 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
633 633 {
634 634 bool flag = false;
635 635 PythonQtSignalReceiver* r = getSignalReceiver(obj);
636 636 if (r) {
637 637 flag = r->addSignalHandler(signal, receiver);
638 638 }
639 639 return flag;
640 640 }
641 641
642 642 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
643 643 {
644 644 bool flag = false;
645 645 PythonQtObjectPtr callable = lookupCallable(module, objectname);
646 646 if (callable) {
647 647 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
648 648 if (r) {
649 649 flag = r->removeSignalHandler(signal, callable);
650 650 }
651 651 } else {
652 652 // callable not found
653 653 }
654 654 return flag;
655 655 }
656 656
657 657 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
658 658 {
659 659 bool flag = false;
660 660 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
661 661 if (r) {
662 662 flag = r->removeSignalHandler(signal, receiver);
663 663 }
664 664 return flag;
665 665 }
666 666
667 667 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
668 668 {
669 669 PythonQtObjectPtr p = lookupObject(module, name);
670 670 if (p) {
671 671 if (PyCallable_Check(p)) {
672 672 return p;
673 673 }
674 674 }
675 675 PyErr_Clear();
676 676 return NULL;
677 677 }
678 678
679 679 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
680 680 {
681 681 QStringList l = name.split('.');
682 682 PythonQtObjectPtr p = module;
683 683 PythonQtObjectPtr prev;
684 684 QByteArray b;
685 685 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
686 686 prev = p;
687 687 b = (*i).toLatin1();
688 688 if (PyDict_Check(p)) {
689 689 p = PyDict_GetItemString(p, b.data());
690 690 } else {
691 691 p.setNewRef(PyObject_GetAttrString(p, b.data()));
692 692 }
693 693 }
694 694 PyErr_Clear();
695 695 return p;
696 696 }
697 697
698 698 PythonQtObjectPtr PythonQt::getMainModule() {
699 699 //both borrowed
700 700 PythonQtObjectPtr dict = PyImport_GetModuleDict();
701 701 return PyDict_GetItemString(dict, "__main__");
702 702 }
703 703
704 704 PythonQtObjectPtr PythonQt::importModule(const QString& name)
705 705 {
706 706 PythonQtObjectPtr mod;
707 707 mod.setNewRef(PyImport_ImportModule(name.toLatin1().constData()));
708 708 return mod;
709 709 }
710 710
711 711
712 712 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
713 713 QVariant result;
714 714 clearError();
715 715 if (pycode) {
716 716 PyObject* dict = NULL;
717 717 PyObject* globals = NULL;
718 718 if (PyModule_Check(object)) {
719 719 dict = PyModule_GetDict(object);
720 720 globals = dict;
721 721 } else if (PyDict_Check(object)) {
722 722 dict = object;
723 723 globals = dict;
724 724 } else {
725 725 dict = PyObject_GetAttrString(object, "__dict__");
726 726 globals = PyObject_GetAttrString(PyImport_ImportModule(
727 727 #ifdef PY3K
728 728 PyUnicode_AsUTF8(
729 729 #else
730 730 PyString_AS_STRING(
731 731 #endif
732 732 PyObject_GetAttrString(object, "__module__"))),"__dict__");
733 733 }
734 734 PyObject* r = NULL;
735 735 if (dict) {
736 736 #ifdef PY3K
737 737 r = PyEval_EvalCode(pycode, globals, dict);
738 738 #else
739 739 r = PyEval_EvalCode((PyCodeObject*)pycode, globals , dict);
740 740 #endif
741 741 }
742 742 if (r) {
743 743 result = PythonQtConv::PyObjToQVariant(r);
744 744 Py_DECREF(r);
745 745 } else {
746 746 handleError();
747 747 }
748 748 } else {
749 749 handleError();
750 750 }
751 751 return result;
752 752 }
753 753
754 754 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
755 755 {
756 756 QVariant result;
757 757 PythonQtObjectPtr p;
758 758 PyObject* dict = NULL;
759 759 clearError();
760 760 if (PyModule_Check(object)) {
761 761 dict = PyModule_GetDict(object);
762 762 } else if (PyDict_Check(object)) {
763 763 dict = object;
764 764 }
765 765 if (dict) {
766 766 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
767 767 }
768 768 if (p) {
769 769 result = PythonQtConv::PyObjToQVariant(p);
770 770 } else {
771 771 handleError();
772 772 }
773 773 return result;
774 774 }
775 775
776 776 void PythonQt::evalFile(PyObject* module, const QString& filename)
777 777 {
778 778 PythonQtObjectPtr code = parseFile(filename);
779 779 clearError();
780 780 if (code) {
781 781 evalCode(module, code);
782 782 } else {
783 783 handleError();
784 784 }
785 785 }
786 786
787 787 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
788 788 {
789 789 PythonQtObjectPtr p;
790 790 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
791 791 clearError();
792 792 if (!p) {
793 793 handleError();
794 794 }
795 795 return p;
796 796 }
797 797
798 798 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
799 799 {
800 800 PythonQtObjectPtr code = parseFile(filename);
801 801 PythonQtObjectPtr module = _p->createModule(name, code);
802 802 return module;
803 803 }
804 804
805 805 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
806 806 {
807 807 PyErr_Clear();
808 808 QString scriptCode = script;
809 809 if (scriptCode.isEmpty()) {
810 810 // we always need at least a linefeed
811 811 scriptCode = "\n";
812 812 }
813 813 PythonQtObjectPtr pycode;
814 814 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
815 815 PythonQtObjectPtr module = _p->createModule(name, pycode);
816 816 return module;
817 817 }
818 818
819 819 PythonQtObjectPtr PythonQt::createUniqueModule()
820 820 {
821 821 static QString pyQtStr("PythonQt_module");
822 822 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
823 823 return createModuleFromScript(moduleName);
824 824 }
825 825
826 826 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
827 827 {
828 828 if (PyModule_Check(object)) {
829 829 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
830 830 } else if (PyDict_Check(object)) {
831 831 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
832 832 } else {
833 833 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
834 834 }
835 835 }
836 836
837 837 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
838 838 {
839 839 if (PyModule_Check(object)) {
840 840 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
841 841 } else if (PyDict_Check(object)) {
842 842 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
843 843 } else {
844 844 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
845 845 }
846 846 }
847 847
848 848 void PythonQt::removeVariable(PyObject* object, const QString& name)
849 849 {
850 850 if (PyDict_Check(object)) {
851 851 PyDict_DelItemString(object, name.toLatin1().data());
852 852 } else {
853 853 PyObject_DelAttrString(object, name.toLatin1().data());
854 854 }
855 855 }
856 856
857 857 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
858 858 {
859 859 QVariant result;
860 860 PythonQtObjectPtr obj = lookupObject(object, objectname);
861 861 if (obj) {
862 862 result = PythonQtConv::PyObjToQVariant(obj);
863 863 }
864 864 return result;
865 865 }
866 866
867 867 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
868 868 {
869 869 QStringList results;
870 870
871 871 PythonQtObjectPtr object;
872 872 if (objectname.isEmpty()) {
873 873 object = module;
874 874 } else {
875 875 object = lookupObject(module, objectname);
876 876 if (!object && type == CallOverloads) {
877 877 PyObject* dict = lookupObject(module, "__builtins__");
878 878 if (dict) {
879 879 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
880 880 }
881 881 }
882 882 }
883 883
884 884 if (object) {
885 885 results = introspectObject(object, type);
886 886 }
887 887
888 888 return results;
889 889 }
890 890
891 891 QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
892 892 {
893 893 QStringList results;
894 894
895 895 if (type == CallOverloads) {
896 896 if (PythonQtSlotFunction_Check(object)) {
897 897 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object;
898 898 PythonQtSlotInfo* info = o->m_ml;
899 899
900 900 while (info) {
901 901 results << info->fullSignature();
902 902 info = info->nextInfo();
903 903 }
904 904 } else if (PythonQtSignalFunction_Check(object)) {
905 905 PythonQtSignalFunctionObject* o = (PythonQtSignalFunctionObject*)object;
906 906 PythonQtSlotInfo* info = o->m_ml;
907 907
908 908 while (info) {
909 909 results << info->fullSignature();
910 910 info = info->nextInfo();
911 911 }
912 912 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
913 913 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
914 914 PythonQtSlotInfo* info = o->classInfo()->constructors();
915 915
916 916 while (info) {
917 917 results << info->fullSignature();
918 918 info = info->nextInfo();
919 919 }
920 920 } else {
921 921 QString signature = _p->getSignature(object);
922 922 if (!signature.isEmpty()) {
923 923 results << signature;
924 924 } else {
925 925 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
926 926 if (doc) {
927 927 #ifdef PY3K
928 928 results << PyUnicode_AsUTF8(doc);
929 929 #else
930 930 results << PyString_AsString(doc);
931 931 #endif
932 932 Py_DECREF(doc);
933 933 }
934 934 }
935 935 }
936 936 } else {
937 937 PyObject* keys = NULL;
938 938 bool isDict = false;
939 939 if (PyDict_Check(object)) {
940 940 keys = PyDict_Keys(object);
941 941 isDict = true;
942 942 } else {
943 943 keys = PyObject_Dir(object);
944 944 }
945 945 if (keys) {
946 946 int count = PyList_Size(keys);
947 947 PyObject* key;
948 948 PyObject* value;
949 949 QString keystr;
950 950 for (int i = 0;i<count;i++) {
951 951 key = PyList_GetItem(keys,i);
952 952 if (isDict) {
953 953 value = PyDict_GetItem(object, key);
954 954 Py_INCREF(value);
955 955 } else {
956 956 value = PyObject_GetAttr(object, key);
957 957 }
958 958 if (!value) continue;
959 959 #ifdef PY3K
960 960 keystr = PyUnicode_AsUTF8(key);
961 961 #else
962 962 keystr = PyString_AsString(key);
963 963 #endif
964 964 static const QString underscoreStr("__tmp");
965 965 if (!keystr.startsWith(underscoreStr)) {
966 966 switch (type) {
967 967 case Anything:
968 968 results << keystr;
969 969 break;
970 970 case Class:
971 971 #ifdef PY3K
972 972 if(PyType_Check(value)) {
973 973 #else
974 974 if (value->ob_type == &PyClass_Type || value->ob_type == &PyType_Type) {
975 975 #endif
976 976 results << keystr;
977 977 }
978 978 break;
979 979 case Variable:
980 980 if (
981 981 #ifndef PY3K
982 982 value->ob_type != &PyClass_Type &&
983 983 #endif
984 984 value->ob_type != &PyCFunction_Type &&
985 985 value->ob_type != &PyFunction_Type &&
986 986 value->ob_type != &PyMethod_Type &&
987 987 value->ob_type != &PyModule_Type &&
988 988 value->ob_type != &PyType_Type &&
989 989 value->ob_type != &PythonQtSlotFunction_Type
990 990 ) {
991 991 results << keystr;
992 992 }
993 993 break;
994 994 case Function:
995 995 if (value->ob_type == &PyCFunction_Type ||
996 996 value->ob_type == &PyFunction_Type ||
997 997 value->ob_type == &PyMethod_Type ||
998 998 value->ob_type == &PythonQtSlotFunction_Type
999 999 ) {
1000 1000 results << keystr;
1001 1001 }
1002 1002 break;
1003 1003 case Module:
1004 1004 if (value->ob_type == &PyModule_Type) {
1005 1005 results << keystr;
1006 1006 }
1007 1007 break;
1008 1008 default:
1009 1009 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
1010 1010 }
1011 1011 }
1012 1012 Py_DECREF(value);
1013 1013 }
1014 1014 Py_DECREF(keys);
1015 1015 }
1016 1016 if ((type == Anything) || (type == Variable)) {
1017 1017 if (object->ob_type == &PythonQtClassWrapper_Type) {
1018 1018 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
1019 1019 PythonQtClassInfo* info = o->classInfo();
1020 1020 results += info->propertyList();
1021 1021 }
1022 1022 }
1023 1023 }
1024 1024 return results;
1025 1025 }
1026 1026
1027 1027 PyObject* PythonQt::getObjectByType(const QString& typeName)
1028 1028 {
1029 1029 PythonQtObjectPtr sys;
1030 1030 sys.setNewRef(PyImport_ImportModule("sys"));
1031 1031 PythonQtObjectPtr modules = lookupObject(sys, "modules");
1032 1032 Q_ASSERT(PyDict_Check(modules));
1033 1033
1034 1034 QStringList tmp = typeName.split(".");
1035 1035 QString simpleTypeName = tmp.takeLast();
1036 1036 QString moduleName = tmp.join(".");
1037 1037
1038 1038 PyObject* object = NULL;
1039 1039 PyObject* moduleObject = PyDict_GetItemString(modules, moduleName.toLatin1().constData());
1040 1040 if (moduleObject) {
1041 1041 object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
1042 1042 }
1043 1043
1044 1044 if (!object) {
1045 1045 moduleObject = PyDict_GetItemString(modules, "__builtin__");
1046 1046 if (moduleObject) {
1047 1047 object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
1048 1048 }
1049 1049 }
1050 1050
1051 1051 return object;
1052 1052 }
1053 1053
1054 1054 QStringList PythonQt::introspectType(const QString& typeName, ObjectType type)
1055 1055 {
1056 1056 QStringList results;
1057 1057 PyObject* object = getObjectByType(typeName);
1058 1058 if (!object) {
1059 1059 // the last item may be a member, split it away and try again
1060 1060 QStringList tmp = typeName.split(".");
1061 1061 QString memberName = tmp.takeLast();
1062 1062 QString typeName;
1063 1063 if (tmp.isEmpty()) {
1064 1064 typeName = memberName;
1065 1065 memberName.clear();
1066 1066 } else {
1067 1067 typeName = tmp.takeLast();
1068 1068 }
1069 1069 PyObject* typeObject = getObjectByType(typeName);
1070 1070 if (typeObject) {
1071 1071 object = PyObject_GetAttrString(typeObject, memberName.toLatin1().constData());
1072 1072 }
1073 1073 }
1074 1074 if (object) {
1075 1075 results = introspectObject(object, type);
1076 1076 Py_DECREF(object);
1077 1077 }
1078 1078 return results;
1079 1079 }
1080 1080
1081 1081 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args, const QVariantMap& kwargs)
1082 1082 {
1083 1083 PythonQtObjectPtr callable = lookupCallable(object, name);
1084 1084 if (callable) {
1085 1085 return call(callable, args, kwargs);
1086 1086 } else {
1087 1087 return QVariant();
1088 1088 }
1089 1089 }
1090 1090
1091 1091 QVariant PythonQt::call(PyObject* callable, const QVariantList& args, const QVariantMap& kwargs)
1092 1092 {
1093 1093 QVariant r;
1094 1094 PythonQtObjectPtr result;
1095 1095 result.setNewRef(callAndReturnPyObject(callable, args, kwargs));
1096 1096 clearError();
1097 1097 if (result) {
1098 1098 r = PythonQtConv::PyObjToQVariant(result);
1099 1099 } else {
1100 1100 PythonQt::self()->handleError();
1101 1101 }
1102 1102 return r;
1103 1103 }
1104 1104
1105 1105 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args, const QVariantMap& kwargs)
1106 1106 {
1107 1107 PyObject* result = NULL;
1108 1108 if (callable) {
1109 1109 bool err = false;
1110 1110 PythonQtObjectPtr pargs;
1111 1111 int count = args.size();
1112 1112 if ((count > 0) || (kwargs.count() > 0)) { // create empty tuple if kwargs are given
1113 1113 pargs.setNewRef(PyTuple_New(count));
1114 1114
1115 1115 // transform QVariant arguments to Python
1116 1116 for (int i = 0; i < count; i++) {
1117 1117 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
1118 1118 if (arg) {
1119 1119 // steals reference, no unref
1120 1120 PyTuple_SetItem(pargs, i,arg);
1121 1121 } else {
1122 1122 err = true;
1123 1123 break;
1124 1124 }
1125 1125 }
1126 1126 }
1127 1127 if (!err) {
1128 1128 if (kwargs.isEmpty()) {
1129 1129 // do a direct call if we have no keyword arguments
1130 1130 PyErr_Clear();
1131 1131 result = PyObject_CallObject(callable, pargs);
1132 1132 } else {
1133 1133 // convert keyword arguments to Python
1134 1134 PythonQtObjectPtr pkwargs;
1135 1135 pkwargs.setNewRef(PyDict_New());
1136 1136 QMapIterator<QString, QVariant> it(kwargs);
1137 1137 while (it.hasNext()) {
1138 1138 it.next();
1139 1139 PyObject* arg = PythonQtConv::QVariantToPyObject(it.value());
1140 1140 if (arg) {
1141 1141 PyDict_SetItemString(pkwargs, it.key().toLatin1().constData(), arg);
1142 1142 } else {
1143 1143 err = true;
1144 1144 break;
1145 1145 }
1146 1146 }
1147 1147 if (!err) {
1148 1148 // call with arguments and keyword arguments
1149 1149 PyErr_Clear();
1150 1150 result = PyObject_Call(callable, pargs, pkwargs);
1151 1151 }
1152 1152 }
1153 1153 }
1154 1154 }
1155 1155 return result;
1156 1156 }
1157 1157
1158 1158 void PythonQt::addInstanceDecorators(QObject* o)
1159 1159 {
1160 1160 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
1161 1161 }
1162 1162
1163 1163 void PythonQt::addClassDecorators(QObject* o)
1164 1164 {
1165 1165 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
1166 1166 }
1167 1167
1168 1168 void PythonQt::addDecorators(QObject* o)
1169 1169 {
1170 1170 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
1171 1171 }
1172 1172
1173 1173 void PythonQt::registerQObjectClassNames(const QStringList& names)
1174 1174 {
1175 1175 _p->registerQObjectClassNames(names);
1176 1176 }
1177 1177
1178 1178 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
1179 1179 {
1180 1180 _p->_importInterface = importInterface;
1181 1181 PythonQtImport::init();
1182 1182 }
1183 1183
1184 1184 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
1185 1185 {
1186 1186 _p->_importIgnorePaths = paths;
1187 1187 }
1188 1188
1189 1189 const QStringList& PythonQt::getImporterIgnorePaths()
1190 1190 {
1191 1191 return _p->_importIgnorePaths;
1192 1192 }
1193 1193
1194 1194 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
1195 1195 {
1196 1196 _p->_cppWrapperFactories.append(factory);
1197 1197 }
1198 1198
1199 1199 void PythonQt::addWrapperFactory( PythonQtForeignWrapperFactory* factory )
1200 1200 {
1201 1201 _p->_foreignWrapperFactories.append(factory);
1202 1202 }
1203 1203
1204 1204 //---------------------------------------------------------------------------------------------------
1205 1205 PythonQtPrivate::PythonQtPrivate()
1206 1206 {
1207 1207 _importInterface = NULL;
1208 1208 _defaultImporter = new PythonQtQFileImporter;
1209 1209 _noLongerWrappedCB = NULL;
1210 1210 _wrappedCB = NULL;
1211 1211 _currentClassInfoForClassWrapperCreation = NULL;
1212 1212 _profilingCB = NULL;
1213 1213 _hadError = false;
1214 1214 _systemExitExceptionHandlerEnabled = false;
1215 1215 }
1216 1216
1217 1217 void PythonQtPrivate::setupSharedLibrarySuffixes()
1218 1218 {
1219 1219 _sharedLibrarySuffixes.clear();
1220 1220 PythonQtObjectPtr imp;
1221 1221 imp.setNewRef(PyImport_ImportModule("imp"));
1222 1222 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
1223 1223 QVariant result = imp.call("get_suffixes");
1224 1224 #ifdef __linux
1225 1225 #ifdef _DEBUG
1226 1226 // First look for shared libraries with the '_d' suffix in debug mode on Linux.
1227 1227 // This is a workaround, because python does not append the '_d' suffix on Linux
1228 1228 // and would always load the release library otherwise.
1229 1229 _sharedLibrarySuffixes << "_d.so";
1230 1230 #endif
1231 1231 #endif
1232 1232 Q_FOREACH (QVariant entry, result.toList()) {
1233 1233 QVariantList suffixEntry = entry.toList();
1234 1234 if (suffixEntry.count()==3) {
1235 1235 int code = suffixEntry.at(2).toInt();
1236 1236 if (code == cExtensionCode) {
1237 1237 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
1238 1238 }
1239 1239 }
1240 1240 }
1241 1241 }
1242 1242
1243 1243 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
1244 1244 {
1245 1245 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
1246 1246 _currentClassInfoForClassWrapperCreation = NULL;
1247 1247 return info;
1248 1248 }
1249 1249
1250 1250 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
1251 1251 {
1252 1252 o->setParent(this);
1253 1253 int numMethods = o->metaObject()->methodCount();
1254 1254 for (int i = 0; i < numMethods; i++) {
1255 1255 QMetaMethod m = o->metaObject()->method(i);
1256 1256 if ((m.methodType() == QMetaMethod::Method ||
1257 1257 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
1258 1258 // QMetaMethod::signature changed to QMetaMethod::methodSignature in QT5
1259 1259 #if( QT_VERSION >= QT_VERSION_CHECK(5,0,0) )
1260 1260 QByteArray signature = m.methodSignature();
1261 1261 #else
1262 1262 QByteArray signature = m.signature();
1263 1263 #endif
1264 1264 if (signature.startsWith("new_")) {
1265 1265 if ((decoTypes & ConstructorDecorator) == 0) continue;
1266 1266 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1267 1267 if (info->parameters().at(0).pointerCount == 1) {
1268 1268 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
1269 1269 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1270 1270 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1271 1271 classInfo->addConstructor(newSlot);
1272 1272 }
1273 1273 } else if (signature.startsWith("delete_")) {
1274 1274 if ((decoTypes & DestructorDecorator) == 0) continue;
1275 1275 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
1276 1276 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1277 1277 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1278 1278 classInfo->setDestructor(newSlot);
1279 1279 } else if (signature.startsWith("static_")) {
1280 1280 if ((decoTypes & StaticDecorator) == 0) continue;
1281 1281 QByteArray nameOfClass = signature.mid(7);
1282 1282 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
1283 1283 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1284 1284 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1285 1285 classInfo->addDecoratorSlot(newSlot);
1286 1286 } else {
1287 1287 if ((decoTypes & InstanceDecorator) == 0) continue;
1288 1288 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1289 1289 if (info->parameters().count()>1) {
1290 1290 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
1291 1291 if (p.pointerCount==1) {
1292 1292 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
1293 1293 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
1294 1294 classInfo->addDecoratorSlot(newSlot);
1295 1295 }
1296 1296 }
1297 1297 }
1298 1298 }
1299 1299 }
1300 1300 }
1301 1301
1302 1302 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
1303 1303 {
1304 1304 Q_FOREACH(QString name, names) {
1305 1305 _knownQObjectClassNames.insert(name.toLatin1(), true);
1306 1306 }
1307 1307 }
1308 1308
1309 1309 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
1310 1310 {
1311 1311 _signalReceivers.remove(obj);
1312 1312 }
1313 1313
1314 1314 namespace
1315 1315 {
1316 1316 //! adapted from python source file "pythonrun.c", function "handle_system_exit"
1317 1317 //! return the exitcode instead of calling "Py_Exit".
1318 1318 //! it gives the application an opportunity to properly terminate.
1319 1319 int custom_system_exit_exception_handler()
1320 1320 {
1321 1321 PyObject *exception, *value, *tb;
1322 1322 int exitcode = 0;
1323 1323
1324 1324 // if (Py_InspectFlag)
1325 1325 // /* Don't exit if -i flag was given. This flag is set to 0
1326 1326 // * when entering interactive mode for inspecting. */
1327 1327 // return exitcode;
1328 1328
1329 1329 PyErr_Fetch(&exception, &value, &tb);
1330 1330 #ifdef PY3K
1331 1331 std::cout << std::endl;
1332 1332 #else
1333 1333 if (Py_FlushLine())
1334 1334 PyErr_Clear();
1335 1335 #endif
1336 1336 fflush(stdout);
1337 1337 if (value == NULL || value == Py_None)
1338 1338 goto done;
1339 1339 if (PyExceptionInstance_Check(value)) {
1340 1340 /* The error code should be in the `code' attribute. */
1341 1341 PyObject *code = PyObject_GetAttrString(value, "code");
1342 1342 if (code) {
1343 1343 Py_DECREF(value);
1344 1344 value = code;
1345 1345 if (value == Py_None)
1346 1346 goto done;
1347 1347 }
1348 1348 /* If we failed to dig out the 'code' attribute,
1349 1349 just let the else clause below print the error. */
1350 1350 }
1351 1351 #ifdef PY3K
1352 1352 if (PyLong_Check(value))
1353 1353 exitcode = (int)PyLong_AsLong(value);
1354 1354 #else
1355 1355 if (PyInt_Check(value))
1356 1356 exitcode = (int)PyInt_AsLong(value);
1357 1357 #endif
1358 1358 else {
1359 1359 PyObject *sys_stderr = PySys_GetObject(const_cast<char*>("stderr"));
1360 1360 if (sys_stderr != NULL && sys_stderr != Py_None) {
1361 1361 PyFile_WriteObject(value, sys_stderr, Py_PRINT_RAW);
1362 1362 } else {
1363 1363 PyObject_Print(value, stderr, Py_PRINT_RAW);
1364 1364 fflush(stderr);
1365 1365 }
1366 1366 PySys_WriteStderr("\n");
1367 1367 exitcode = 1;
1368 1368 }
1369 1369 done:
1370 1370 /* Restore and clear the exception info, in order to properly decref
1371 1371 * the exception, value, and traceback. If we just exit instead,
1372 1372 * these leak, which confuses PYTHONDUMPREFS output, and may prevent
1373 1373 * some finalizers from running.
1374 1374 */
1375 1375 PyErr_Restore(exception, value, tb);
1376 1376 PyErr_Clear();
1377 1377 return exitcode;
1378 1378 //Py_Exit(exitcode);
1379 1379 }
1380 1380 }
1381 1381
1382 1382 bool PythonQt::handleError()
1383 1383 {
1384 1384 bool flag = false;
1385 1385 if (PyErr_Occurred()) {
1386 1386
1387 1387 if (_p->_systemExitExceptionHandlerEnabled &&
1388 1388 PyErr_ExceptionMatches(PyExc_SystemExit)) {
1389 1389 int exitcode = custom_system_exit_exception_handler();
1390 1390 Q_EMIT PythonQt::self()->systemExitExceptionRaised(exitcode);
1391 1391 }
1392 1392 else
1393 1393 {
1394 1394 // currently we just print the error and the stderr handler parses the errors
1395 1395 PyErr_Print();
1396 1396
1397 1397 /*
1398 1398 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1399 1399 PyObject *ptype;
1400 1400 PyObject *pvalue;
1401 1401 PyObject *ptraceback;
1402 1402 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1403 1403
1404 1404 Py_XDECREF(ptype);
1405 1405 Py_XDECREF(pvalue);
1406 1406 Py_XDECREF(ptraceback);
1407 1407 */
1408 1408 PyErr_Clear();
1409 1409 }
1410 1410 flag = true;
1411 1411 }
1412 1412 _p->_hadError = flag;
1413 1413 return flag;
1414 1414 }
1415 1415
1416 1416 bool PythonQt::hadError()const
1417 1417 {
1418 1418 return _p->_hadError;
1419 1419 }
1420 1420
1421 1421 void PythonQt::clearError()
1422 1422 {
1423 1423 _p->_hadError = false;
1424 1424 }
1425 1425
1426 1426 void PythonQt::setSystemExitExceptionHandlerEnabled(bool value)
1427 1427 {
1428 1428 _p->_systemExitExceptionHandlerEnabled = value;
1429 1429 }
1430 1430
1431 1431 bool PythonQt::systemExitExceptionHandlerEnabled() const
1432 1432 {
1433 1433 return _p->_systemExitExceptionHandlerEnabled;
1434 1434 }
1435 1435
1436 1436 void PythonQt::addSysPath(const QString& path)
1437 1437 {
1438 1438 PythonQtObjectPtr sys;
1439 1439 sys.setNewRef(PyImport_ImportModule("sys"));
1440 1440 PythonQtObjectPtr obj = lookupObject(sys, "path");
1441 1441 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1442 1442 }
1443 1443
1444 1444 void PythonQt::overwriteSysPath(const QStringList& paths)
1445 1445 {
1446 1446 PythonQtObjectPtr sys;
1447 1447 sys.setNewRef(PyImport_ImportModule("sys"));
1448 1448 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1449 1449 }
1450 1450
1451 1451 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1452 1452 {
1453 1453 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1454 1454 }
1455 1455
1456 1456 void PythonQt::stdOutRedirectCB(const QString& str)
1457 1457 {
1458 1458 if (!PythonQt::self()) {
1459 1459 std::cout << str.toLatin1().data() << std::endl;
1460 1460 return;
1461 1461 }
1462 1462 Q_EMIT PythonQt::self()->pythonStdOut(str);
1463 1463 }
1464 1464
1465 1465 void PythonQt::stdErrRedirectCB(const QString& str)
1466 1466 {
1467 1467 if (!PythonQt::self()) {
1468 1468 std::cerr << str.toLatin1().data() << std::endl;
1469 1469 return;
1470 1470 }
1471 1471 Q_EMIT PythonQt::self()->pythonStdErr(str);
1472 1472 }
1473 1473
1474 1474 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1475 1475 {
1476 1476 _p->_wrappedCB = cb;
1477 1477 }
1478 1478
1479 1479 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1480 1480 {
1481 1481 _p->_noLongerWrappedCB = cb;
1482 1482 }
1483 1483
1484 1484 void PythonQt::setProfilingCallback(ProfilingCB* cb)
1485 1485 {
1486 1486 _p->_profilingCB = cb;
1487 1487 }
1488 1488
1489 1489
1490 1490 static PyMethodDef PythonQtMethods[] = {
1491 1491 {NULL, NULL, 0, NULL}
1492 1492 };
1493 1493
1494 1494 #ifdef PY3K
1495 static PyModuleDef PythonQtModule = {
1495 static PyModuleDef PythonQtModuleDef = {
1496 1496 PyModuleDef_HEAD_INIT,
1497 1497 "",
1498 1498 NULL,
1499 1499 -1,
1500 1500 PythonQtMethods,
1501 1501 NULL,
1502 1502 NULL,
1503 1503 NULL,
1504 1504 NULL
1505 1505 };
1506 1506 #endif
1507 1507
1508 1508 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1509 1509 {
1510 1510 QByteArray name = "PythonQt";
1511 1511 if (!pythonQtModuleName.isEmpty()) {
1512 1512 name = pythonQtModuleName;
1513 1513 }
1514 1514 #ifdef PY3K
1515 PythonQtModule.m_name = name.constData();
1516 _p->_pythonQtModule = PyModule_Create(&PythonQtModule);
1515 PythonQtModuleDef.m_name = name.constData();
1516 _p->_pythonQtModule = PyModule_Create(&PythonQtModuleDef);
1517 1517 #else
1518 1518 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1519 1519 #endif
1520 1520 _p->_pythonQtModuleName = name;
1521 1521
1522 PythonQtObjectPtr sys;
1523 sys.setNewRef(PyImport_ImportModule("sys"));
1524
1522 1525 if (redirectStdOut) {
1523 PythonQtObjectPtr sys;
1524 1526 PythonQtObjectPtr out;
1525 1527 PythonQtObjectPtr err;
1526 sys.setNewRef(PyImport_ImportModule("sys"));
1527 1528 // create a redirection object for stdout and stderr
1528 1529 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1529 1530 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1530 1531 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1531 1532 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1532 1533 // replace the built in file objects with our own objects
1533 1534 PyModule_AddObject(sys, "stdout", out);
1534 1535 PyModule_AddObject(sys, "stderr", err);
1535 1536 }
1536 1537
1537 1538 // add PythonQt to the list of builtin module names
1538 PythonQtObjectPtr sys;
1539 sys.setNewRef(PyImport_ImportModule("sys"));
1540 1539 PyObject *old_module_names = PyObject_GetAttrString(sys.object(),"builtin_module_names");
1541 1540 Py_ssize_t old_size = PyTuple_Size(old_module_names);
1542 1541 PyObject *module_names = PyTuple_New(old_size+1);
1543 1542 for(Py_ssize_t i = 0; i < old_size; i++)
1544 1543 PyTuple_SetItem(module_names, i, PyTuple_GetItem(old_module_names, i));
1545 1544 #ifdef PY3K
1546 1545 PyTuple_SetItem(module_names, old_size, PyUnicode_FromString(name.constData()));
1547 1546 #else
1548 1547 PyTuple_SetItem(module_names, old_size, PyString_FromString(name.constData()));
1549 1548 #endif
1550 1549 PyModule_AddObject(sys.object(),"builtin_module_names",module_names);
1551 1550 Py_DecRef(old_module_names);
1551
1552 #ifdef PY3K
1553 PyDict_SetItem(PyObject_GetAttrString(sys.object(), "modules"), PyUnicode_FromString(name.constData()), _p->_pythonQtModule.object());
1554 #endif
1552 1555 }
1553 1556
1554 1557 QString PythonQt::getReturnTypeOfWrappedMethod(PyObject* module, const QString& name)
1555 1558 {
1556 1559 QStringList tmp = name.split(".");
1557 1560 QString methodName = tmp.takeLast();
1558 1561 QString variableName = tmp.join(".");
1559 1562 // TODO: the variableName may be a type name, this needs to be handled differently,
1560 1563 // because it is not necessarily known in the module context
1561 1564 PythonQtObjectPtr variableObject = lookupObject(module, variableName);
1562 1565 if (variableObject.isNull()) {
1563 1566 return "";
1564 1567 }
1565 1568
1566 1569 return getReturnTypeOfWrappedMethodHelper(variableObject, methodName, name);
1567 1570 }
1568 1571
1569 1572 QString PythonQt::getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName)
1570 1573 {
1571 1574 PythonQtObjectPtr typeObject = getObjectByType(typeName);
1572 1575 if (typeObject.isNull()) {
1573 1576 return "";
1574 1577 }
1575 1578 return getReturnTypeOfWrappedMethodHelper(typeObject, methodName, typeName + "." + methodName);
1576 1579 }
1577 1580
1578 1581 QString PythonQt::getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context)
1579 1582 {
1580 1583 PythonQtObjectPtr methodObject;
1581 1584 if (PyDict_Check(variableObject)) {
1582 1585 methodObject = PyDict_GetItemString(variableObject, methodName.toLatin1().constData());
1583 1586 } else {
1584 1587 methodObject.setNewRef(PyObject_GetAttrString(variableObject, methodName.toLatin1().constData()));
1585 1588 }
1586 1589 if (methodObject.isNull()) {
1587 1590 return "";
1588 1591 }
1589 1592
1590 1593 QString type;
1591 1594
1592 1595 #ifdef PY3K
1593 1596 if (PyType_Check(methodObject)) {
1594 1597 #else
1595 1598 if (methodObject->ob_type == &PyClass_Type || methodObject->ob_type == &PyType_Type) {
1596 1599 #endif
1597 1600 // the methodObject is not a method, but the name of a type/class. This means
1598 1601 // a constructor is called. Return the context.
1599 1602 type = context;
1600 1603 } else if (methodObject->ob_type == &PythonQtSlotFunction_Type) {
1601 1604 QString className;
1602 1605
1603 1606 if (PyObject_TypeCheck(variableObject, &PythonQtInstanceWrapper_Type)) {
1604 1607 // the type name of wrapped instance is the class name
1605 1608 className = variableObject->ob_type->tp_name;
1606 1609 } else {
1607 1610 PyObject* classNameObject = PyObject_GetAttrString(variableObject, "__name__");
1608 1611 if (classNameObject) {
1609 1612 #ifdef PY3K
1610 1613 Q_ASSERT(PyUnicode_Check(classNameObject));
1611 1614 className = PyUnicode_AsUTF8(classNameObject);
1612 1615 #else
1613 1616 Q_ASSERT(PyString_Check(classNameObject));
1614 1617 className = PyString_AsString(classNameObject);
1615 1618 #endif
1616 1619 Py_DECREF(classNameObject);
1617 1620 }
1618 1621 }
1619 1622
1620 1623 if (!className.isEmpty()) {
1621 1624 PythonQtClassInfo* info = _p->_knownClassInfos.value(className.toLatin1().constData());
1622 1625 if (info) {
1623 1626 PythonQtSlotInfo* slotInfo = info->member(methodName.toLatin1().constData())._slot;
1624 1627 if (slotInfo) {
1625 1628 if (slotInfo->metaMethod()) {
1626 1629 type = slotInfo->metaMethod()->typeName();
1627 1630 if (!type.isEmpty()) {
1628 1631 QChar c = type.at(type.length()-1);
1629 1632 while (c == '*' || c == '&') {
1630 1633 type.truncate(type.length()-1);
1631 1634 if (!type.isEmpty()) {
1632 1635 c = type.at(type.length()-1);
1633 1636 } else {
1634 1637 break;
1635 1638 }
1636 1639 }
1637 1640 // split away template arguments
1638 1641 type = type.split("<").first();
1639 1642 // split away const
1640 1643 type = type.split(" ").last().trimmed();
1641 1644
1642 1645 // if the type is a known class info, then create the full type name, i.e. include the
1643 1646 // module name. For example, the slot may return a QDate, then this looks up the
1644 1647 // name _PythonQt.QtCore.QDate.
1645 1648 PythonQtClassInfo* typeInfo = _p->_knownClassInfos.value(type.toLatin1().constData());
1646 1649 if (typeInfo && typeInfo->pythonQtClassWrapper()) {
1647 1650 PyObject* s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__module__");
1648 1651 #ifdef PY3K
1649 1652 Q_ASSERT(PyUnicode_Check(s));
1650 1653 type = QString(PyUnicode_AsUTF8(s));
1651 1654 #else
1652 1655 Q_ASSERT(PyString_Check(s));
1653 1656 type = QString(PyString_AsString(s)) + "." + type;
1654 1657 #endif
1655 1658 Py_DECREF(s);
1656 1659 s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__name__");
1657 1660 #ifdef PY3K
1658 1661 Q_ASSERT(PyUnicode_Check(s));
1659 1662 #else
1660 1663 Q_ASSERT(PyString_Check(s));
1661 1664 #endif
1662 1665 Py_DECREF(s);
1663 1666 }
1664 1667 }
1665 1668 }
1666 1669 }
1667 1670 }
1668 1671 }
1669 1672 }
1670 1673 return type;
1671 1674 }
1672 1675
1673 1676 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1674 1677 {
1675 1678 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1676 1679 }
1677 1680
1678 1681
1679 1682 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1680 1683 {
1681 1684 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1682 1685 if (!info) {
1683 1686 info = new PythonQtClassInfo();
1684 1687 info->setupCPPObject(typeName);
1685 1688 _knownClassInfos.insert(typeName, info);
1686 1689 }
1687 1690 return info;
1688 1691 }
1689 1692
1690 1693 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1691 1694 {
1692 1695 _p->addPolymorphicHandler(typeName, cb);
1693 1696 }
1694 1697
1695 1698 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1696 1699 {
1697 1700 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1698 1701 info->addPolymorphicHandler(cb);
1699 1702 }
1700 1703
1701 1704 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1702 1705 {
1703 1706 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1704 1707 }
1705 1708
1706 1709 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1707 1710 {
1708 1711 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1709 1712 if (info) {
1710 1713 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1711 1714 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1712 1715 return true;
1713 1716 } else {
1714 1717 return false;
1715 1718 }
1716 1719 }
1717 1720
1718 1721 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1719 1722 {
1720 1723 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1721 1724 if (!info->pythonQtClassWrapper()) {
1722 1725 info->setTypeSlots(typeSlots);
1723 1726 info->setupCPPObject(typeName);
1724 1727 createPythonQtClassWrapper(info, package, module);
1725 1728 }
1726 1729 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1727 1730 addParentClass(typeName, parentTypeName, 0);
1728 1731 }
1729 1732 if (wrapperCreator) {
1730 1733 info->setDecoratorProvider(wrapperCreator);
1731 1734 }
1732 1735 if (shell) {
1733 1736 info->setShellSetInstanceWrapperCB(shell);
1734 1737 }
1735 1738 }
1736 1739
1737 1740 PyObject* PythonQtPrivate::packageByName(const char* name)
1738 1741 {
1739 1742 if (name==NULL || name[0]==0) {
1740 1743 name = "private";
1741 1744 }
1742 1745 PyObject* v = _packages.value(name);
1743 1746 if (!v) {
1744 1747 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1745 1748 _packages.insert(name, v);
1746 1749 // AddObject steals the reference, so increment it!
1747 1750 Py_INCREF(v);
1748 1751 PyModule_AddObject(_pythonQtModule, name, v);
1749 1752 }
1750 1753 return v;
1751 1754 }
1752 1755
1753 1756 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1754 1757 {
1755 1758 QString error = "Return value '" + PythonQtConv::PyObjGetString(result) + "' can not be converted to expected C++ type '" + methodInfo->parameters().at(0).name + "' as return value of virtual method " + signature;
1756 1759 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1757 1760 PythonQt::self()->handleError();
1758 1761 }
1759 1762
1760 1763 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1761 1764 {
1762 1765 if (_p->_initFlags & ExternalHelp) {
1763 1766 Q_EMIT pythonHelpRequest(QByteArray(info->className()));
1764 1767 return Py_BuildValue("");
1765 1768 } else {
1766 1769 #ifdef PY3K
1767 1770 return PyUnicode_FromString(info->help().toLatin1().data());
1768 1771 #else
1769 1772 return PyString_FromString(info->help().toLatin1().data());
1770 1773 #endif
1771 1774 }
1772 1775 }
1773 1776
1774 1777 void PythonQt::clearNotFoundCachedMembers()
1775 1778 {
1776 1779 Q_FOREACH(PythonQtClassInfo* info, _p->_knownClassInfos) {
1777 1780 info->clearNotFoundCachedMembers();
1778 1781 }
1779 1782 }
1780 1783
1781 1784 void PythonQt::removeWrapperFactory( PythonQtCppWrapperFactory* factory )
1782 1785 {
1783 1786 _p->_cppWrapperFactories.removeAll(factory);
1784 1787 }
1785 1788
1786 1789 void PythonQt::removeWrapperFactory( PythonQtForeignWrapperFactory* factory )
1787 1790 {
1788 1791 _p->_foreignWrapperFactories.removeAll(factory);
1789 1792 }
1790 1793
1791 1794 void PythonQtPrivate::removeWrapperPointer(void* obj)
1792 1795 {
1793 1796 _wrappedObjects.remove(obj);
1794 1797 }
1795 1798
1796 1799 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1797 1800 {
1798 1801 _wrappedObjects.insert(obj, wrapper);
1799 1802 }
1800 1803
1801 1804 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1802 1805 {
1803 1806 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1804 1807 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1805 1808 // this is a wrapper whose QObject was already removed due to destruction
1806 1809 // so the obj pointer has to be a new QObject with the same address...
1807 1810 // we remove the old one and set the copy to NULL
1808 1811 wrap->_objPointerCopy = NULL;
1809 1812 removeWrapperPointer(obj);
1810 1813 wrap = NULL;
1811 1814 }
1812 1815 return wrap;
1813 1816 }
1814 1817
1815 1818 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1816 1819 {
1817 1820 PythonQtObjectPtr result;
1818 1821 PythonQt::self()->clearError();
1819 1822 if (pycode) {
1820 1823 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1821 1824 } else {
1822 1825 PythonQt::self()->handleError();
1823 1826 }
1824 1827 return result;
1825 1828 }
1826 1829
1827 1830 void* PythonQtPrivate::unwrapForeignWrapper( const QByteArray& classname, PyObject* obj )
1828 1831 {
1829 1832 void* foreignObject = NULL;
1830 1833 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
1831 1834 foreignObject = _foreignWrapperFactories.at(i)->unwrap(classname, obj);
1832 1835 if (foreignObject) {
1833 1836 return foreignObject;
1834 1837 }
1835 1838 }
1836 1839 return NULL;
1837 1840 }
1838 1841
1839 1842 bool PythonQtPrivate::isMethodDescriptor(PyObject* object) const
1840 1843 {
1841 1844 // This implementation is the same as in inspect.ismethoddescriptor(), inspect.py.
1842 1845 if (PyObject_HasAttrString(object, "__get__") &&
1843 1846 !PyObject_HasAttrString(object, "__set__") &&
1844 1847 !PyMethod_Check(object) &&
1845 1848 !PyFunction_Check(object)
1846 1849 #ifndef PY3K
1847 1850 && !PyClass_Check(object)
1848 1851 #endif
1849 1852 ) {
1850 1853 return true;
1851 1854 }
1852 1855 return false;
1853 1856 }
1854 1857
1855 1858 QString PythonQtPrivate::getSignature(PyObject* object)
1856 1859 {
1857 1860 QString signature;
1858 1861
1859 1862 if (object) {
1860 1863 PyMethodObject* method = NULL;
1861 1864 PyFunctionObject* func = NULL;
1862 1865
1863 1866 bool decrefMethod = false;
1864 1867
1865 1868 #ifdef PY3K
1866 1869 if (PyType_Check(object)) {
1867 1870 #else
1868 1871 if (object->ob_type == &PyClass_Type || object->ob_type == &PyType_Type) {
1869 1872 #endif
1870 1873 method = (PyMethodObject*)PyObject_GetAttrString(object, "__init__");
1871 1874 decrefMethod = true;
1872 1875 } else if (object->ob_type == &PyFunction_Type) {
1873 1876 func = (PyFunctionObject*)object;
1874 1877 } else if (object->ob_type == &PyMethod_Type) {
1875 1878 method = (PyMethodObject*)object;
1876 1879 }
1877 1880 if (method) {
1878 1881 if (PyFunction_Check(method->im_func)) {
1879 1882 func = (PyFunctionObject*)method->im_func;
1880 1883 } else if (isMethodDescriptor((PyObject*)method)) {
1881 1884 QString docstr;
1882 1885 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
1883 1886 if (doc) {
1884 1887 #ifdef PY3K
1885 1888 docstr = PyUnicode_AsUTF8(doc);
1886 1889 #else
1887 1890 docstr = PyString_AsString(doc);
1888 1891 #endif
1889 1892 Py_DECREF(doc);
1890 1893 }
1891 1894
1892 1895 PyObject* s = PyObject_GetAttrString(object, "__name__");
1893 1896 if (s) {
1894 1897 #ifdef PY3K
1895 1898 Q_ASSERT(PyUnicode_Check(s));
1896 1899 signature = PyUnicode_AsUTF8(s);
1897 1900 #else
1898 1901 Q_ASSERT(PyString_Check(s));
1899 1902 signature = PyString_AsString(s);
1900 1903 #endif
1901 1904 if (docstr.startsWith(signature + "(")) {
1902 1905 signature = docstr;
1903 1906 } else {
1904 1907 signature += "(...)";
1905 1908 if (!docstr.isEmpty()) {
1906 1909 signature += "\n\n" + docstr;
1907 1910 }
1908 1911 }
1909 1912 Py_DECREF(s);
1910 1913 }
1911 1914 }
1912 1915 }
1913 1916
1914 1917 if (func) {
1915 1918 QString funcName;
1916 1919 PyObject* s = PyObject_GetAttrString((PyObject*)func, "__name__");
1917 1920 if (s) {
1918 1921 #ifdef PY3K
1919 1922 Q_ASSERT(PyUnicode_Check(s));
1920 1923 funcName = PyUnicode_AsUTF8(s);
1921 1924 #else
1922 1925 Q_ASSERT(PyString_Check(s));
1923 1926 funcName = PyString_AsString(s);
1924 1927 #endif
1925 1928 Py_DECREF(s);
1926 1929 }
1927 1930 if (method && funcName == "__init__") {
1928 1931 PyObject* s = PyObject_GetAttrString(object, "__name__");
1929 1932 if (s) {
1930 1933 #ifdef PY3K
1931 1934 Q_ASSERT(PyUnicode_Check(s));
1932 1935 funcName = PyUnicode_AsUTF8(s);
1933 1936 #else
1934 1937 Q_ASSERT(PyString_Check(s));
1935 1938 funcName = PyString_AsString(s);
1936 1939 #endif
1937 1940 Py_DECREF(s);
1938 1941 }
1939 1942 }
1940 1943
1941 1944 QStringList arguments;
1942 1945 QStringList defaults;
1943 1946 QString varargs;
1944 1947 QString varkeywords;
1945 1948 // NOTE: This implementation is based on function getargs() in inspect.py.
1946 1949 // inspect.getargs() can handle anonymous (tuple) arguments, while this code does not.
1947 1950 // It can be implemented, but it may be rarely needed and not necessary.
1948 1951 PyCodeObject* code = (PyCodeObject*)func->func_code;
1949 1952 if (code->co_varnames) {
1950 1953 int nargs = code->co_argcount;
1951 1954 Q_ASSERT(PyTuple_Check(code->co_varnames));
1952 1955 for (int i=0; i<nargs; i++) {
1953 1956 PyObject* name = PyTuple_GetItem(code->co_varnames, i);
1954 1957 #ifdef PY3K
1955 1958 Q_ASSERT(PyUnicode_Check(name));
1956 1959 arguments << PyUnicode_AsUTF8(name);
1957 1960 #else
1958 1961 Q_ASSERT(PyString_Check(name));
1959 1962 arguments << PyString_AsString(name);
1960 1963 #endif
1961 1964 }
1962 1965 if (code->co_flags & CO_VARARGS) {
1963 1966 PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
1964 1967 #ifdef PY3K
1965 1968 Q_ASSERT(PyUnicode_Check(s));
1966 1969 varargs = PyUnicode_AsUTF8(s);
1967 1970 #else
1968 1971 Q_ASSERT(PyString_Check(s));
1969 1972 varargs = PyString_AsString(s);
1970 1973 #endif
1971 1974 nargs += 1;
1972 1975 }
1973 1976 if (code->co_flags & CO_VARKEYWORDS) {
1974 1977 PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
1975 1978 #ifdef PY3K
1976 1979 Q_ASSERT(PyUnicode_Check(s));
1977 1980 varkeywords = PyUnicode_AsUTF8(s);
1978 1981 #else
1979 1982 Q_ASSERT(PyString_Check(s));
1980 1983 varkeywords = PyString_AsString(s);
1981 1984 #endif
1982 1985 }
1983 1986 }
1984 1987
1985 1988 PyObject* defaultsTuple = func->func_defaults;
1986 1989 if (defaultsTuple) {
1987 1990 Q_ASSERT(PyTuple_Check(defaultsTuple));
1988 1991 for (Py_ssize_t i=0; i<PyTuple_Size(defaultsTuple); i++) {
1989 1992 PyObject* d = PyTuple_GetItem(defaultsTuple, i);
1990 1993 PyObject* s = PyObject_Repr(d);
1991 1994 #ifdef PY3K
1992 1995 Q_ASSERT(PyUnicode_Check(s));
1993 1996 defaults << PyUnicode_AsUTF8(s);
1994 1997 #else
1995 1998 Q_ASSERT(PyString_Check(s));
1996 1999 defaults << PyString_AsString(s);
1997 2000 #endif
1998 2001 Py_DECREF(s);
1999 2002 }
2000 2003 }
2001 2004
2002 2005 int firstdefault = arguments.size() - defaults.size();
2003 2006 for (int i=0; i<arguments.size(); i++) {
2004 2007 if (!signature.isEmpty()) { signature += ", "; }
2005 2008 if (!method || i>0 || arguments[i] != "self") {
2006 2009 signature += arguments[i];
2007 2010 if (i >= firstdefault) {
2008 2011 signature += "=" + defaults[i-firstdefault];
2009 2012 }
2010 2013 }
2011 2014 }
2012 2015 if (!varargs.isEmpty()) {
2013 2016 if (!signature.isEmpty()) { signature += ", "; }
2014 2017 signature += "*" + varargs;
2015 2018 }
2016 2019 if (!varkeywords.isEmpty()) {
2017 2020 if (!signature.isEmpty()) { signature += ", "; }
2018 2021 signature += "**" + varkeywords;
2019 2022 }
2020 2023 signature = funcName + "(" + signature + ")";
2021 2024 }
2022 2025
2023 2026 if (method && decrefMethod) {
2024 2027 Py_DECREF(method);
2025 2028 }
2026 2029 }
2027 2030
2028 2031 return signature;
2029 2032 }
2030 2033
2031 2034 void PythonQtPrivate::shellClassDeleted( void* shellClass )
2032 2035 {
2033 2036 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(shellClass);
2034 2037 if (wrap && wrap->_wrappedPtr) {
2035 2038 // this is a pure C++ wrapper and the shell has gone, so we need
2036 2039 // to set the _wrappedPtr to NULL on the wrapper
2037 2040 wrap->_wrappedPtr = NULL;
2038 2041 // and then we remove the wrapper, since the wrapped class is gone
2039 2042 _wrappedObjects.remove(shellClass);
2040 2043 }
2041 2044 // if the wrapper is a QObject, we do not handle this here,
2042 2045 // it will be handled by the QPointer<> to the QObject, which becomes NULL
2043 2046 // via the QObject destructor.
2044 2047 }
2045 2048
2046 2049 PyObject* PythonQtPrivate::wrapMemoryAsBuffer( const void* data, Py_ssize_t size )
2047 2050 {
2048 2051 // P3K port needed later on! -- not anymore :D
2049 2052 #ifdef PY3K
2050 2053 return PyMemoryView_FromMemory((char*)data, size, PyBUF_READ);
2051 2054 #else
2052 2055 return PyBuffer_FromMemory((char*)data, size);
2053 2056 #endif
2054 2057 }
2055 2058
2056 2059 PyObject* PythonQtPrivate::wrapMemoryAsBuffer( void* data, Py_ssize_t size )
2057 2060 {
2058 2061 // P3K port needed later on! -- not anymore :D
2059 2062 #ifdef PY3K
2060 2063 return PyMemoryView_FromMemory((char*)data, size, PyBUF_READ | PyBUF_WRITE);
2061 2064 #else
2062 2065 return PyBuffer_FromReadWriteMemory((char*)data, size);
2063 2066 #endif
2064 2067 }
@@ -1,504 +1,504
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 PythonQtClassWrapper.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 "PythonQtClassWrapper.h"
43 43 #include <QObject>
44 44
45 45 #include "PythonQt.h"
46 46 #include "PythonQtSlot.h"
47 47 #include "PythonQtSignal.h"
48 48 #include "PythonQtClassInfo.h"
49 49 #include "PythonQtConversion.h"
50 50 #include "PythonQtInstanceWrapper.h"
51 51
52 52 static PyObject* PythonQtInstanceWrapper_invert(PythonQtInstanceWrapper* wrapper)
53 53 {
54 54 PyObject* result = NULL;
55 55 static QByteArray memberName = "__invert__";
56 56 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
57 57 if (opSlot._type == PythonQtMemberInfo::Slot) {
58 58 result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr);
59 59 }
60 60 return result;
61 61 }
62 62
63 63 static int PythonQtInstanceWrapper_nonzero(PythonQtInstanceWrapper* wrapper)
64 64 {
65 65 int result = (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
66 66 if (result) {
67 67 static QByteArray memberName = "__nonzero__";
68 68 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
69 69 if (opSlot._type == PythonQtMemberInfo::Slot) {
70 70 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr);
71 71 if (resultObj == Py_False) {
72 72 result = 0;
73 73 }
74 74 Py_XDECREF(resultObj);
75 75 }
76 76 }
77 77 return result;
78 78 }
79 79
80 80
81 81 static PyObject* PythonQtInstanceWrapper_binaryfunc(PyObject* self, PyObject* other, const QByteArray& opName, const QByteArray& fallbackOpName = QByteArray())
82 82 {
83 83 // since we disabled type checking, we can receive any object as self, but we currently only support
84 84 // different objects on the right. Otherwise we would need to generate __radd__ etc. methods.
85 85 if (!PyObject_TypeCheck(self, &PythonQtInstanceWrapper_Type)) {
86 86 QString error = "Unsupported operation " + opName + "(" + self->ob_type->tp_name + ", " + other->ob_type->tp_name + ")";
87 87 PyErr_SetString(PyExc_ArithmeticError, error.toLatin1().data());
88 88 return NULL;
89 89 }
90 90 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)self;
91 91 PyObject* result = NULL;
92 92 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(opName);
93 93 if (opSlot._type == PythonQtMemberInfo::Slot) {
94 94 // TODO get rid of tuple
95 95 PyObject* args = PyTuple_New(1);
96 96 Py_INCREF(other);
97 97 PyTuple_SET_ITEM(args, 0, other);
98 98 result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr);
99 99 Py_DECREF(args);
100 100 if (!result && !fallbackOpName.isEmpty()) {
101 101 // try fallback if we did not get a result
102 102 result = PythonQtInstanceWrapper_binaryfunc(self, other, fallbackOpName);
103 103 }
104 104 }
105 105 return result;
106 106 }
107 107
108 108 #define BINARY_OP(NAME) \
109 109 static PyObject* PythonQtInstanceWrapper_ ## NAME(PyObject* self, PyObject* other) \
110 110 { \
111 111 static const QByteArray opName("__" #NAME "__"); \
112 112 return PythonQtInstanceWrapper_binaryfunc(self, other, opName); \
113 113 }
114 114
115 115 #define BINARY_OP_INPLACE(NAME) \
116 116 static PyObject* PythonQtInstanceWrapper_i ## NAME(PyObject* self, PyObject* other) \
117 117 { \
118 118 static const QByteArray opName("__i" #NAME "__"); \
119 119 static const QByteArray fallbackName("__" #NAME "__"); \
120 120 return PythonQtInstanceWrapper_binaryfunc(self, other, opName, fallbackName); \
121 121 }
122 122
123 123 BINARY_OP(add)
124 124 BINARY_OP(sub)
125 125 BINARY_OP(mul)
126 126 BINARY_OP(div)
127 127 BINARY_OP(and)
128 128 BINARY_OP(or)
129 129 BINARY_OP(xor)
130 130 BINARY_OP(mod)
131 131 BINARY_OP(lshift)
132 132 BINARY_OP(rshift)
133 133
134 134 BINARY_OP_INPLACE(add)
135 135 BINARY_OP_INPLACE(sub)
136 136 BINARY_OP_INPLACE(mul)
137 137 BINARY_OP_INPLACE(div)
138 138 BINARY_OP_INPLACE(and)
139 139 BINARY_OP_INPLACE(or)
140 140 BINARY_OP_INPLACE(xor)
141 141 BINARY_OP_INPLACE(mod)
142 142 BINARY_OP_INPLACE(lshift)
143 143 BINARY_OP_INPLACE(rshift)
144 144
145 145 static void initializeSlots(PythonQtClassWrapper* wrap)
146 146 {
147 147 int typeSlots = wrap->classInfo()->typeSlots();
148 148 if (typeSlots) {
149 149 if (typeSlots & PythonQt::Type_Add) {
150 150 wrap->_base.as_number.nb_add = (binaryfunc)PythonQtInstanceWrapper_add;
151 151 }
152 152 if (typeSlots & PythonQt::Type_Subtract) {
153 153 wrap->_base.as_number.nb_subtract = (binaryfunc)PythonQtInstanceWrapper_sub;
154 154 }
155 155 if (typeSlots & PythonQt::Type_Multiply) {
156 156 wrap->_base.as_number.nb_multiply = (binaryfunc)PythonQtInstanceWrapper_mul;
157 157 }
158 158 if (typeSlots & PythonQt::Type_Divide) {
159 159 #ifndef PY3K
160 160 wrap->_base.as_number.nb_divide = (binaryfunc)PythonQtInstanceWrapper_div;
161 161 #endif
162 162 wrap->_base.as_number.nb_true_divide = (binaryfunc)PythonQtInstanceWrapper_div;
163 163 }
164 164 if (typeSlots & PythonQt::Type_And) {
165 165 wrap->_base.as_number.nb_and = (binaryfunc)PythonQtInstanceWrapper_and;
166 166 }
167 167 if (typeSlots & PythonQt::Type_Or) {
168 168 wrap->_base.as_number.nb_or = (binaryfunc)PythonQtInstanceWrapper_or;
169 169 }
170 170 if (typeSlots & PythonQt::Type_Xor) {
171 171 wrap->_base.as_number.nb_xor = (binaryfunc)PythonQtInstanceWrapper_xor;
172 172 }
173 173 if (typeSlots & PythonQt::Type_Mod) {
174 174 wrap->_base.as_number.nb_remainder = (binaryfunc)PythonQtInstanceWrapper_mod;
175 175 }
176 176 if (typeSlots & PythonQt::Type_LShift) {
177 177 wrap->_base.as_number.nb_lshift = (binaryfunc)PythonQtInstanceWrapper_lshift;
178 178 }
179 179 if (typeSlots & PythonQt::Type_RShift) {
180 180 wrap->_base.as_number.nb_rshift = (binaryfunc)PythonQtInstanceWrapper_rshift;
181 181 }
182 182
183 183 if (typeSlots & PythonQt::Type_InplaceAdd) {
184 184 wrap->_base.as_number.nb_add = (binaryfunc)PythonQtInstanceWrapper_iadd;
185 185 }
186 186 if (typeSlots & PythonQt::Type_InplaceSubtract) {
187 187 wrap->_base.as_number.nb_subtract = (binaryfunc)PythonQtInstanceWrapper_isub;
188 188 }
189 189 if (typeSlots & PythonQt::Type_InplaceMultiply) {
190 190 wrap->_base.as_number.nb_multiply = (binaryfunc)PythonQtInstanceWrapper_imul;
191 191 }
192 192 if (typeSlots & PythonQt::Type_InplaceDivide) {
193 193 #ifndef PY3K
194 194 wrap->_base.as_number.nb_inplace_divide = (binaryfunc)PythonQtInstanceWrapper_idiv;
195 195 #endif
196 196 wrap->_base.as_number.nb_inplace_true_divide = (binaryfunc)PythonQtInstanceWrapper_idiv;
197 197 }
198 198 if (typeSlots & PythonQt::Type_InplaceAnd) {
199 199 wrap->_base.as_number.nb_inplace_and = (binaryfunc)PythonQtInstanceWrapper_iand;
200 200 }
201 201 if (typeSlots & PythonQt::Type_InplaceOr) {
202 202 wrap->_base.as_number.nb_inplace_or = (binaryfunc)PythonQtInstanceWrapper_ior;
203 203 }
204 204 if (typeSlots & PythonQt::Type_InplaceXor) {
205 205 wrap->_base.as_number.nb_inplace_xor = (binaryfunc)PythonQtInstanceWrapper_ixor;
206 206 }
207 207 if (typeSlots & PythonQt::Type_InplaceMod) {
208 208 wrap->_base.as_number.nb_inplace_remainder = (binaryfunc)PythonQtInstanceWrapper_imod;
209 209 }
210 210 if (typeSlots & PythonQt::Type_InplaceLShift) {
211 211 wrap->_base.as_number.nb_inplace_lshift = (binaryfunc)PythonQtInstanceWrapper_ilshift;
212 212 }
213 213 if (typeSlots & PythonQt::Type_InplaceRShift) {
214 214 wrap->_base.as_number.nb_inplace_rshift = (binaryfunc)PythonQtInstanceWrapper_irshift;
215 215 }
216 216 if (typeSlots & PythonQt::Type_Invert) {
217 217 wrap->_base.as_number.nb_invert = (unaryfunc)PythonQtInstanceWrapper_invert;
218 218 }
219 219 if (typeSlots & PythonQt::Type_NonZero) {
220 220 #ifdef PY3K
221 221 wrap->_base.as_number.nb_bool = (inquiry)PythonQtInstanceWrapper_nonzero;
222 222 #else
223 223 wrap->_base.as_number.nb_nonzero = (inquiry)PythonQtInstanceWrapper_nonzero;
224 224 #endif
225 225 }
226 226 }
227 227 }
228 228
229 229 static PyObject* PythonQtClassWrapper_alloc(PyTypeObject *self, Py_ssize_t nitems)
230 230 {
231 231 // call the default type alloc
232 232 PyObject* obj = PyType_Type.tp_alloc(self, nitems);
233 233
234 234 // take current class type, if we are called via newPythonQtClassWrapper()
235 235 PythonQtClassWrapper* wrap = (PythonQtClassWrapper*)obj;
236 236 wrap->_classInfo = PythonQt::priv()->currentClassInfoForClassWrapperCreation();
237 237 if (wrap->_classInfo) {
238 238 initializeSlots(wrap);
239 239 }
240 240
241 241 return obj;
242 242 }
243 243
244 244
245 245 static int PythonQtClassWrapper_init(PythonQtClassWrapper* self, PyObject* args, PyObject* kwds)
246 246 {
247 247 // call the default type init
248 248 if (PyType_Type.tp_init((PyObject *)self, args, kwds) < 0) {
249 249 return -1;
250 250 }
251 251
252 252 // if we have no CPP class information, try our base class
253 253 if (!self->classInfo()) {
254 254 PyTypeObject* superType = ((PyTypeObject *)self)->tp_base;
255 255
256 256 // recursively search for PythonQtClassWrapper superclass,
257 257 // this is needed for multiple levels of inheritance in python,
258 258 // e.g.
259 259 // class MyWidgetBase(QWidget):
260 260 // ...
261 261 // class MyWidget(MyWidgetBase):
262 262 // ...
263 263 while( superType && Py_TYPE(superType) != &PythonQtClassWrapper_Type )
264 264 superType = superType->tp_base;
265 265
266 266 if (!superType || (Py_TYPE(superType) != &PythonQtClassWrapper_Type)) {
267 267 PyErr_Format(PyExc_TypeError, "type %s is not derived from PythonQtClassWrapper", ((PyTypeObject*)self)->tp_name);
268 268 return -1;
269 269 }
270 270
271 271 // take the class info from the superType
272 272 self->_classInfo = ((PythonQtClassWrapper*)superType)->classInfo();
273 273 }
274 274
275 275 return 0;
276 276 }
277 277
278 278 static PyObject *PythonQtClassWrapper_classname(PythonQtClassWrapper* type)
279 279 {
280 280 #ifdef PY3K
281 281 return PyUnicode_FromString((QString("Class_") + type->classInfo()->className()).toLatin1().data());
282 282 #else
283 283 return PyString_FromString((QString("Class_") + type->classInfo()->className()).toLatin1().data());
284 284 #endif
285 285 }
286 286
287 287 static PyObject *PythonQtClassWrapper_help(PythonQtClassWrapper* type)
288 288 {
289 289 return PythonQt::self()->helpCalled(type->classInfo());
290 290 }
291 291
292 292 PyObject *PythonQtClassWrapper_delete(PythonQtClassWrapper *type, PyObject *args)
293 293 {
294 294 Q_UNUSED(type);
295 295
296 296 Py_ssize_t argc = PyTuple_Size(args);
297 297 if (argc>0) {
298 298 PyObject* self = PyTuple_GET_ITEM(args, 0);
299 299 if (PyObject_TypeCheck(self, &PythonQtInstanceWrapper_Type)) {
300 300 return PythonQtInstanceWrapper_delete((PythonQtInstanceWrapper*)self);
301 301 }
302 302 }
303 303 return NULL;
304 304 }
305 305
306 306 PyObject *PythonQtClassWrapper_inherits(PythonQtClassWrapper *type, PyObject *args)
307 307 {
308 308 Q_UNUSED(type);
309 309 PythonQtInstanceWrapper* wrapper = NULL;
310 310 char *name = NULL;
311 311 if (!PyArg_ParseTuple(args, "O!s:PythonQtClassWrapper.inherits",&PythonQtInstanceWrapper_Type, &wrapper, &name)) {
312 312 return NULL;
313 313 }
314 314 return PythonQtConv::GetPyBool(wrapper->classInfo()->inherits(name));
315 315 }
316 316
317 317
318 318 static PyMethodDef PythonQtClassWrapper_methods[] = {
319 319 {"className", (PyCFunction)PythonQtClassWrapper_classname, METH_NOARGS,
320 320 "Return the classname of the object"
321 321 },
322 322 {"inherits", (PyCFunction)PythonQtClassWrapper_inherits, METH_VARARGS,
323 323 "Returns if the class inherits or is of given type name"
324 324 },
325 325 {"help", (PyCFunction)PythonQtClassWrapper_help, METH_NOARGS,
326 326 "Shows the help of available methods for this class"
327 327 },
328 328 {"delete", (PyCFunction)PythonQtClassWrapper_delete, METH_VARARGS,
329 329 "Deletes the given C++ object"
330 330 },
331 331 {NULL, NULL, 0 , NULL} /* Sentinel */
332 332 };
333 333
334 334
335 335 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name)
336 336 {
337 337 const char *attributeName;
338 338 PythonQtClassWrapper *wrapper = (PythonQtClassWrapper *)obj;
339 339
340 340 #ifdef PY3K
341 341 if ((attributeName = PyUnicode_AsUTF8(name)) == NULL) {
342 342 #else
343 343 if ((attributeName = PyString_AsString(name)) == NULL) {
344 344 #endif
345 345 return NULL;
346 346 }
347 347 if (obj == (PyObject*)&PythonQtInstanceWrapper_Type) {
348 348 return NULL;
349 349 }
350 350
351 351 if (qstrcmp(attributeName, "__dict__")==0) {
352 352 PyObject* objectDict = ((PyTypeObject *)wrapper)->tp_dict;
353 353 if (!wrapper->classInfo()) {
354 354 Py_INCREF(objectDict);
355 355 return objectDict;
356 356 }
357 357 PyObject* dict = PyDict_New();
358 358
359 359 QStringList l = wrapper->classInfo()->memberList();
360 360 Q_FOREACH (QString name, l) {
361 361 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
362 362 if (o) {
363 363 PyDict_SetItemString(dict, name.toLatin1().data(), o);
364 364 Py_DECREF(o);
365 365 } else {
366 366 // it must have been a property or child, which we do not know as a class object...
367 367 PyErr_Clear();
368 368 }
369 369 }
370 370 if (wrapper->classInfo()->constructors()) {
371 371 #ifdef PY3K
372 372 PyObject* initName = PyUnicode_FromString("__init__");
373 373 #else
374 374 PyObject* initName = PyString_FromString("__init__");
375 375 #endif
376 376 PyObject* func = PyType_Type.tp_getattro(obj, initName);
377 377 Py_DECREF(initName);
378 378 PyDict_SetItemString(dict, "__init__", func);
379 379 Py_DECREF(func);
380 380 }
381 381 for (int i = 0; PythonQtClassWrapper_methods[i].ml_name != NULL; i++) {
382 382 PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[i], obj);
383 383 PyDict_SetItemString(dict, PythonQtClassWrapper_methods[i].ml_name, func);
384 384 Py_DECREF(func);
385 385 }
386 386
387 387 PyDict_Update(dict, objectDict);
388 388 return dict;
389 389 }
390 390
391 391 // look in Python to support derived Python classes
392 #ifdef PY3K
393 return PyObject_GenericGetAttr(obj, name);
394 #else
395 392 PyObject* superAttr = PyType_Type.tp_getattro(obj, name);
396 393 if (superAttr) {
397 394 return superAttr;
398 395 }
399 396 PyErr_Clear();
400 397
401 398 if (wrapper->classInfo()) {
402 399 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
403 400 if (member._type == PythonQtMemberInfo::EnumValue) {
404 401 PyObject* enumValue = member._enumValue;
405 402 Py_INCREF(enumValue);
406 403 return enumValue;
407 404 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
408 405 PyObject* enumWrapper = member._enumWrapper;
409 406 Py_INCREF(enumWrapper);
410 407 return enumWrapper;
411 408 } else if (member._type == PythonQtMemberInfo::Slot) {
412 409 // we return all slots, even the instance slots, since they are callable as unbound slots with self argument
413 410 return PythonQtSlotFunction_New(member._slot, obj, NULL);
414 411 } else if (member._type == PythonQtMemberInfo::Signal) {
415 412 // we return all signals, even the instance signals, since they are callable as unbound signals with self argument
416 413 return PythonQtSignalFunction_New(member._slot, obj, NULL);
417 414 }
418 415 }
419 416
420 417 // look for the internal methods (className(), help())
418 #ifdef PY3K
419 PyObject* internalMethod = PyObject_GenericGetAttr(obj, name);
420 #else
421 421 PyObject* internalMethod = Py_FindMethod( PythonQtClassWrapper_methods, obj, (char*)attributeName);
422 #endif
422 423 if (internalMethod) {
423 424 return internalMethod;
424 425 }
425 426
426 427 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
427 428 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
428 429 return NULL;
429 #endif
430 430 }
431 431
432 432 static int PythonQtClassWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
433 433 {
434 434 return PyType_Type.tp_setattro(obj,name,value);
435 435 }
436 436
437 437 /*
438 438 static PyObject * PythonQtClassWrapper_repr(PyObject * obj)
439 439 {
440 440 PythonQtClassWrapper* wrapper = (PythonQtClassWrapper*)obj;
441 441 if (wrapper->classInfo()->isCPPWrapper()) {
442 442 const QMetaObject* meta = wrapper->classInfo()->metaObject();
443 443 if (!meta) {
444 444 QObject* decorator = wrapper->classInfo()->decorator();
445 445 if (decorator) {
446 446 meta = decorator->metaObject();
447 447 }
448 448 }
449 449 if (meta) {
450 450 return PyString_FromFormat("%s Class (C++ wrapped by %s)", wrapper->classInfo()->className(), meta->className());
451 451 } else {
452 452 return PyString_FromFormat("%s Class (C++ unwrapped)", wrapper->classInfo()->className());
453 453 }
454 454 } else {
455 455 return PyString_FromFormat("%s Class", wrapper->classInfo()->className());
456 456 }
457 457 }
458 458
459 459 */
460 460
461 461 PyTypeObject PythonQtClassWrapper_Type = {
462 462 PyVarObject_HEAD_INIT(NULL, 0)
463 463 "PythonQt.PythonQtClassWrapper", /*tp_name*/
464 464 sizeof(PythonQtClassWrapper), /*tp_basicsize*/
465 465 0, /*tp_itemsize*/
466 466 0, /*tp_dealloc*/
467 467 0, /*tp_print*/
468 468 0, /*tp_getattr*/
469 469 0, /*tp_setattr*/
470 470 0, /*tp_compare*/
471 471 0, //PythonQtClassWrapper_repr, /*tp_repr*/
472 472 0, /*tp_as_number*/
473 473 0, /*tp_as_sequence*/
474 474 0, /*tp_as_mapping*/
475 475 0, /*tp_hash */
476 476 0, /*tp_call*/
477 477 0, /*tp_str*/
478 478 PythonQtClassWrapper_getattro, /*tp_getattro*/
479 479 PythonQtClassWrapper_setattro, /*tp_setattro*/
480 480 0, /*tp_as_buffer*/
481 481 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
482 482 0, /* tp_doc */
483 483 0, /* tp_traverse */
484 484 0, /* tp_clear */
485 485 0, /* tp_richcompare */
486 486 0, /* tp_weaklistoffset */
487 487 0, /* tp_iter */
488 488 0, /* tp_iternext */
489 0, /* tp_methods */
489 PythonQtClassWrapper_methods, /* tp_methods */
490 490 0, /* tp_members */
491 491 0, /* tp_getset */
492 492 0, /* tp_base */
493 493 0, /* tp_dict */
494 494 0, /* tp_descr_get */
495 495 0, /* tp_descr_set */
496 496 0, /* tp_dictoffset */
497 497 (initproc)PythonQtClassWrapper_init, /* tp_init */
498 498 PythonQtClassWrapper_alloc, /* tp_alloc */
499 499 0, /* tp_new */
500 500 0, /* tp_free */
501 501 };
502 502
503 503 //-------------------------------------------------------
504 504
@@ -1,1378 +1,1374
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 PythonQtConversion.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtConversion.h"
43 43 #include "PythonQtVariants.h"
44 44 #include <QDateTime>
45 45 #include <QTime>
46 46 #include <QDate>
47 47
48 #if PY_MAJOR_VERSION >= 3
49 #define PY3K
50 #endif
51
52 48 PythonQtValueStorage<qint64, 128> PythonQtConv::global_valueStorage;
53 49 PythonQtValueStorage<void*, 128> PythonQtConv::global_ptrStorage;
54 50 PythonQtValueStorageWithCleanup<QVariant, 128> PythonQtConv::global_variantStorage;
55 51
56 52 QHash<int, PythonQtConvertMetaTypeToPythonCB*> PythonQtConv::_metaTypeToPythonConverters;
57 53 QHash<int, PythonQtConvertPythonToMetaTypeCB*> PythonQtConv::_pythonToMetaTypeConverters;
58 54
59 55 PyObject* PythonQtConv::GetPyBool(bool val)
60 56 {
61 57 PyObject* r = val?Py_True:Py_False;
62 58 Py_INCREF(r);
63 59 return r;
64 60 }
65 61
66 62 PyObject* PythonQtConv::ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data) {
67 63 // is it an enum value?
68 64 if (info.enumWrapper) {
69 65 if (info.pointerCount==0) {
70 66 return PythonQtPrivate::createEnumValueInstance(info.enumWrapper, *((unsigned int*)data));
71 67 } else {
72 68 // we do not support pointers to enums (who needs them?)
73 69 Py_INCREF(Py_None);
74 70 return Py_None;
75 71 }
76 72 }
77 73
78 74 if (info.typeId == QMetaType::Void) {
79 75 Py_INCREF(Py_None);
80 76 return Py_None;
81 77 } else if ((info.pointerCount == 1) && (info.typeId == QMetaType::Char)) {
82 78 // a char ptr will probably be a null terminated string, so we support that:
83 79 char* charPtr = *((char**)data);
84 80 if (charPtr) {
85 81 #ifdef PY3K
86 82 return PyUnicode_FromString(charPtr);
87 83 #else
88 84 return PyString_FromString(charPtr);
89 85 #endif
90 86 } else {
91 87 Py_INCREF(Py_None);
92 88 return Py_None;
93 89 }
94 90 } else if ((info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) &&
95 91 info.name.startsWith("QList<")) {
96 92 // it is a QList template:
97 93 QByteArray innerType = info.name.mid(6,info.name.length()-7);
98 94 if (innerType.endsWith("*")) {
99 95 innerType.truncate(innerType.length()-1);
100 96 QList<void*>* listPtr = NULL;
101 97 if (info.pointerCount == 1) {
102 98 listPtr = *((QList<void*>**)data);
103 99 } else if (info.pointerCount == 0) {
104 100 listPtr = (QList<void*>*)data;
105 101 }
106 102 if (listPtr) {
107 103 return ConvertQListOfPointerTypeToPythonList(listPtr, innerType);
108 104 } else {
109 105 return NULL;
110 106 }
111 107 }
112 108 }
113 109
114 110 if (info.typeId >= QMetaType::User) {
115 111 // if a converter is registered, we use is:
116 112 PythonQtConvertMetaTypeToPythonCB* converter = _metaTypeToPythonConverters.value(info.typeId);
117 113 if (converter) {
118 114 return (*converter)(data, info.typeId);
119 115 }
120 116 }
121 117
122 118 // special handling did not match, so we convert the usual way (either pointer or value version):
123 119 if (info.pointerCount == 1) {
124 120 // convert the pointer to a Python Object (we can handle ANY C++ object, in the worst case we just know the type and the pointer)
125 121 return PythonQt::priv()->wrapPtr(*((void**)data), info.name);
126 122 } else if (info.pointerCount == 0) {
127 123 // handle values that are not yet handled and not pointers
128 124 return ConvertQtValueToPythonInternal(info.typeId, data);
129 125 } else {
130 126 return NULL;
131 127 }
132 128 }
133 129
134 130 PyObject* PythonQtConv::ConvertQtValueToPythonInternal(int type, const void* data) {
135 131 switch (type) {
136 132 case QMetaType::Void:
137 133 Py_INCREF(Py_None);
138 134 return Py_None;
139 135 case QMetaType::Char:
140 136 return PyLong_FromLong(*((char*)data));
141 137 case QMetaType::UChar:
142 138 return PyLong_FromLong(*((unsigned char*)data));
143 139 case QMetaType::Short:
144 140 return PyLong_FromLong(*((short*)data));
145 141 case QMetaType::UShort:
146 142 return PyLong_FromLong(*((unsigned short*)data));
147 143 case QMetaType::Long:
148 144 return PyLong_FromLong(*((long*)data));
149 145 case QMetaType::ULong:
150 146 // does not fit into simple int of python
151 147 return PyLong_FromUnsignedLong(*((unsigned long*)data));
152 148 case QMetaType::Bool:
153 149 return PythonQtConv::GetPyBool(*((bool*)data));
154 150 case QMetaType::Int:
155 151 return PyLong_FromLong(*((int*)data));
156 152 case QMetaType::UInt:
157 153 // does not fit into simple int of python
158 154 return PyLong_FromUnsignedLong(*((unsigned int*)data));
159 155 case QMetaType::QChar:
160 156 return PyLong_FromLong(*((short*)data));
161 157 case QMetaType::Float:
162 158 return PyFloat_FromDouble(*((float*)data));
163 159 case QMetaType::Double:
164 160 return PyFloat_FromDouble(*((double*)data));
165 161 case QMetaType::LongLong:
166 162 return PyLong_FromLongLong(*((qint64*)data));
167 163 case QMetaType::ULongLong:
168 164 return PyLong_FromUnsignedLongLong(*((quint64*)data));
169 165 // implicit conversion from QByteArray to str has been removed:
170 166 //case QMetaType::QByteArray: {
171 167 // QByteArray* v = (QByteArray*) data;
172 168 // return PyString_FromStringAndSize(*v, v->size());
173 169 // }
174 170 case QMetaType::QVariantMap:
175 171 return PythonQtConv::QVariantMapToPyObject(*((QVariantMap*)data));
176 172 case QMetaType::QVariantList:
177 173 return PythonQtConv::QVariantListToPyObject(*((QVariantList*)data));
178 174 case QMetaType::QString:
179 175 return PythonQtConv::QStringToPyObject(*((QString*)data));
180 176 case QMetaType::QStringList:
181 177 return PythonQtConv::QStringListToPyObject(*((QStringList*)data));
182 178
183 179 case PythonQtMethodInfo::Variant:
184 180 return PythonQtConv::QVariantToPyObject(*((QVariant*)data));
185 181 case QMetaType::QObjectStar:
186 182 #if( QT_VERSION < QT_VERSION_CHECK(5,0,0) )
187 183 case QMetaType::QWidgetStar:
188 184 #endif
189 185 return PythonQt::priv()->wrapQObject(*((QObject**)data));
190 186
191 187 default:
192 188 if (PythonQt::priv()->isPythonQtObjectPtrMetaId(type)) {
193 189 // special case, it is a PythonQtObjectPtr which contains a PyObject, take it directly:
194 190 PyObject* o = ((PythonQtObjectPtr*)data)->object();
195 191 Py_INCREF(o);
196 192 return o;
197 193 } else {
198 194 if (type > 0) {
199 195 // if the type is known, we can construct it via QMetaType::construct
200 196 #if( QT_VERSION >= QT_VERSION_CHECK(5,0,0) )
201 197 void* newCPPObject = QMetaType::create(type, data);
202 198 #else
203 199 void* newCPPObject = QMetaType::construct(type, data);
204 200 #endif
205 201 // XXX this could be optimized by using metatypeid directly
206 202 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)PythonQt::priv()->wrapPtr(newCPPObject, QMetaType::typeName(type));
207 203 wrap->_ownedByPythonQt = true;
208 204 wrap->_useQMetaTypeDestroy = true;
209 205 return (PyObject*)wrap;
210 206 }
211 207 std::cerr << "Unknown type that can not be converted to Python: " << type << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
212 208 }
213 209 }
214 210 Py_INCREF(Py_None);
215 211 return Py_None;
216 212 }
217 213
218 214 void* PythonQtConv::CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info) {
219 215 void* ptr = NULL;
220 216 if (info.pointerCount>1) {
221 217 return NULL;
222 218 } else if (info.pointerCount==1) {
223 219 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
224 220 } else if (info.enumWrapper) {
225 221 // create enum return value
226 222 PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, ptr);
227 223 } else {
228 224 switch (info.typeId) {
229 225 case QMetaType::Char:
230 226 case QMetaType::UChar:
231 227 case QMetaType::Short:
232 228 case QMetaType::UShort:
233 229 case QMetaType::Long:
234 230 case QMetaType::ULong:
235 231 case QMetaType::Bool:
236 232 case QMetaType::Int:
237 233 case QMetaType::UInt:
238 234 case QMetaType::QChar:
239 235 case QMetaType::Float:
240 236 case QMetaType::Double:
241 237 PythonQtValueStorage_ADD_VALUE(global_valueStorage, qint64, 0, ptr);
242 238 break;
243 239 case PythonQtMethodInfo::Variant:
244 240 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, 0, ptr);
245 241 // return the ptr to the variant
246 242 break;
247 243 default:
248 244 if (info.typeId == PythonQtMethodInfo::Unknown) {
249 245 // check if we have a QList of pointers, which we can circumvent with a QList<void*>
250 246 if (info.name.startsWith("QList<")) {
251 247 QByteArray innerType = info.name.mid(6,info.name.length()-7);
252 248 if (innerType.endsWith("*")) {
253 249 static int id = QMetaType::type("QList<void*>");
254 250 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr);
255 251 // return the constData pointer that will be filled with the result value later on
256 252 ptr = (void*)((QVariant*)ptr)->constData();
257 253 }
258 254 }
259 255 }
260 256
261 257 if (!ptr && info.typeId!=PythonQtMethodInfo::Unknown) {
262 258 // everything else is stored in a QVariant, if we know the meta type...
263 259 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
264 260 // return the constData pointer that will be filled with the result value later on
265 261 ptr = (void*)((QVariant*)ptr)->constData();
266 262 }
267 263 }
268 264 }
269 265 return ptr;
270 266 }
271 267
272 268 void* PythonQtConv::castWrapperTo(PythonQtInstanceWrapper* wrapper, const QByteArray& className, bool& ok)
273 269 {
274 270 void* object;
275 271 if (wrapper->classInfo()->isCPPWrapper()) {
276 272 object = wrapper->_wrappedPtr;
277 273 } else {
278 274 QObject* tmp = wrapper->_obj;
279 275 object = tmp;
280 276 }
281 277 if (object) {
282 278 // if we can be upcasted to the given name, we pass the casted pointer in:
283 279 object = wrapper->classInfo()->castTo(object, className);
284 280 ok = object!=NULL;
285 281 } else {
286 282 // if it is a NULL ptr, we need to check if it inherits, so that we might pass the NULL ptr
287 283 ok = wrapper->classInfo()->inherits(className);
288 284 }
289 285 return object;
290 286 }
291 287
292 288 void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject)
293 289 {
294 290 void* ptr = alreadyAllocatedCPPObject;
295 291
296 292 static int penId = QMetaType::type("QPen");
297 293 static int brushId = QMetaType::type("QBrush");
298 294 static int cursorId = QMetaType::type("QCursor");
299 295 static int colorId = QMetaType::type("QColor");
300 296 static PyObject* qtGlobalColorEnum = PythonQtClassInfo::findEnumWrapper("Qt::GlobalColor", NULL);
301 297 if (typeId == cursorId) {
302 298 static PyObject* qtCursorShapeEnum = PythonQtClassInfo::findEnumWrapper("Qt::CursorShape", NULL);
303 299 if ((PyObject*)obj->ob_type == qtCursorShapeEnum) {
304 300 Qt::CursorShape val = (Qt::CursorShape)PyLong_AsLong(obj);
305 301 if (!ptr) {
306 302 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QCursor(), ptr);
307 303 ptr = (void*)((QVariant*)ptr)->constData();
308 304 }
309 305 *((QCursor*)ptr) = QCursor(val);
310 306 return ptr;
311 307 }
312 308 } else if (typeId == penId) {
313 309 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
314 310 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
315 311 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
316 312 Qt::GlobalColor val = (Qt::GlobalColor)PyLong_AsLong(obj);
317 313 if (!ptr) {
318 314 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
319 315 ptr = (void*)((QVariant*)ptr)->constData();
320 316 }
321 317 *((QPen*)ptr) = QPen(QColor(val));
322 318 return ptr;
323 319 } else if ((PyObject*)obj->ob_type == qtColorClass) {
324 320 if (!ptr) {
325 321 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
326 322 ptr = (void*)((QVariant*)ptr)->constData();
327 323 }
328 324 *((QPen*)ptr) = QPen(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
329 325 return ptr;
330 326 }
331 327 } else if (typeId == brushId) {
332 328 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
333 329 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
334 330 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
335 331 Qt::GlobalColor val = (Qt::GlobalColor)PyLong_AsLong(obj);
336 332 if (!ptr) {
337 333 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
338 334 ptr = (void*)((QVariant*)ptr)->constData();
339 335 }
340 336 *((QBrush*)ptr) = QBrush(QColor(val));
341 337 return ptr;
342 338 } else if ((PyObject*)obj->ob_type == qtColorClass) {
343 339 if (!ptr) {
344 340 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
345 341 ptr = (void*)((QVariant*)ptr)->constData();
346 342 }
347 343 *((QBrush*)ptr) = QBrush(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
348 344 return ptr;
349 345 }
350 346 } else if (typeId == colorId) {
351 347 // colors can be created from Qt::GlobalColor (and from colors, but that's the default)
352 348 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
353 349 Qt::GlobalColor val = (Qt::GlobalColor)PyLong_AsLong(obj);
354 350 if (!ptr) {
355 351 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QColor(), ptr);
356 352 ptr = (void*)((QVariant*)ptr)->constData();
357 353 }
358 354 *((QColor*)ptr) = QColor(val);
359 355 return ptr;
360 356 }
361 357 }
362 358 return NULL;
363 359 }
364 360
365 361 void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* /*classInfo*/, void* alreadyAllocatedCPPObject)
366 362 {
367 363 bool ok = false;
368 364 void* ptr = NULL;
369 365
370 366 // autoconversion of QPen/QBrush/QCursor/QColor from different type
371 367 if (info.pointerCount==0 && !strict) {
372 368 ptr = handlePythonToQtAutoConversion(info.typeId, obj, alreadyAllocatedCPPObject);
373 369 if (ptr) {
374 370 return ptr;
375 371 }
376 372 }
377 373
378 374 if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) && info.typeId != PythonQtMethodInfo::Variant) {
379 375 // if we have a Qt wrapper object and if we do not need a QVariant, we do the following:
380 376 // (the Variant case is handled below in a switch)
381 377
382 378 // a C++ wrapper (can be passed as pointer or reference)
383 379 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)obj;
384 380 void* object = castWrapperTo(wrap, info.name, ok);
385 381 if (ok) {
386 382 if (info.pointerCount==1) {
387 383 // store the wrapped pointer in an extra pointer and let ptr point to the extra pointer
388 384 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, object, ptr);
389 385 } else if (info.pointerCount==0) {
390 386 // store the wrapped pointer directly, since we are a reference
391 387 ptr = object;
392 388 }
393 389 } else {
394 390 // not matching, maybe a PyObject*?
395 391 if (info.name == "PyObject" && info.pointerCount==1) {
396 392 // handle low level PyObject directly
397 393 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, obj, ptr);
398 394 }
399 395 }
400 396 } else if (info.pointerCount == 1) {
401 397 // a pointer
402 398 if (info.typeId == QMetaType::Char || info.typeId == QMetaType::UChar)
403 399 {
404 400 #ifdef PY3K
405 401 if (PyUnicode_Check(obj)) {
406 402 QByteArray bytes(PyUnicode_AsUTF8(obj));
407 403 void* ptr2 = NULL;
408 404 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(NULL,global_variantStorage, QVariant, QVariant(bytes), ptr2);
409 405 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr);
410 406 #else
411 407 if (obj->ob_type == &PyString_Type) {
412 408 // take direct reference to string data
413 409 const char* data = PyString_AS_STRING(obj);
414 410 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (void*)data, ptr);
415 411 #endif
416 412 } else {
417 413 // convert to string
418 414 QString str = PyObjGetString(obj, strict, ok);
419 415 if (ok) {
420 416 QByteArray bytes;
421 417 bytes = str.toUtf8();
422 418 if (ok) {
423 419 void* ptr2 = NULL;
424 420 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(NULL,global_variantStorage, QVariant, QVariant(bytes), ptr2);
425 421 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr);
426 422 }
427 423 }
428 424 }
429 425 } else if (info.typeId == QMetaType::QString) {
430 426 // TODO: this is a special case for bad Qt APIs which take a QString*, like QtGui.QFileDialog.getSaveFileName
431 427 // In general we would need to decide to either support * args for all basic types (ignoring the fact that the
432 428 // result value is not useable in Python), or if all these APIs need to be wrapped manually/differently, like PyQt/PySide do.
433 429 QString str = PyObjGetString(obj, strict, ok);
434 430 if (ok) {
435 431 void* ptr2 = NULL;
436 432 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(NULL,global_variantStorage, QVariant, QVariant(str), ptr2);
437 433 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (void*)((QVariant*)ptr2)->constData(), ptr);
438 434 }
439 435 } else if (info.name == "PyObject") {
440 436 // handle low level PyObject directly
441 437 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, obj, ptr);
442 438 } else if (obj == Py_None) {
443 439 // None is treated as a NULL ptr
444 440 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
445 441 } else {
446 442 void* foreignWrapper = PythonQt::priv()->unwrapForeignWrapper(info.name, obj);
447 443 if (foreignWrapper) {
448 444 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, foreignWrapper, ptr);
449 445 } else {
450 446 // if we are not strict, we try if we are passed a 0 integer
451 447 if (!strict) {
452 448 bool ok;
453 449 int value = PyObjGetInt(obj, true, ok);
454 450 if (ok && value==0) {
455 451 // TODOXXX is this wise? or should it be expected from the programmer to use None?
456 452 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
457 453 }
458 454 }
459 455 }
460 456 }
461 457 } else if (info.pointerCount == 0) {
462 458 // not a pointer
463 459 switch (info.typeId) {
464 460 case QMetaType::Char:
465 461 {
466 462 int val = PyObjGetInt(obj, strict, ok);
467 463 if (ok) {
468 464 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, char, val, ptr);
469 465 }
470 466 }
471 467 break;
472 468 case QMetaType::UChar:
473 469 {
474 470 int val = PyObjGetInt(obj, strict, ok);
475 471 if (ok) {
476 472 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned char, val, ptr);
477 473 }
478 474 }
479 475 break;
480 476 case QMetaType::Short:
481 477 {
482 478 int val = PyObjGetInt(obj, strict, ok);
483 479 if (ok) {
484 480 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
485 481 }
486 482 }
487 483 break;
488 484 case QMetaType::UShort:
489 485 {
490 486 int val = PyObjGetInt(obj, strict, ok);
491 487 if (ok) {
492 488 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned short, val, ptr);
493 489 }
494 490 }
495 491 break;
496 492 case QMetaType::Long:
497 493 {
498 494 long val = (long)PyObjGetLongLong(obj, strict, ok);
499 495 if (ok) {
500 496 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, long, val, ptr);
501 497 }
502 498 }
503 499 break;
504 500 case QMetaType::ULong:
505 501 {
506 502 unsigned long val = (unsigned long)PyObjGetLongLong(obj, strict, ok);
507 503 if (ok) {
508 504 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned long, val, ptr);
509 505 }
510 506 }
511 507 break;
512 508 case QMetaType::Bool:
513 509 {
514 510 bool val = PyObjGetBool(obj, strict, ok);
515 511 if (ok) {
516 512 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, bool, val, ptr);
517 513 }
518 514 }
519 515 break;
520 516 case QMetaType::Int:
521 517 {
522 518 int val = PyObjGetInt(obj, strict, ok);
523 519 if (ok) {
524 520 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, int, val, ptr);
525 521 }
526 522 }
527 523 break;
528 524 case QMetaType::UInt:
529 525 {
530 526 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
531 527 if (ok) {
532 528 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
533 529 }
534 530 }
535 531 break;
536 532 case QMetaType::QChar:
537 533 {
538 534 int val = PyObjGetInt(obj, strict, ok);
539 535 if (ok) {
540 536 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
541 537 }
542 538 }
543 539 break;
544 540 case QMetaType::Float:
545 541 {
546 542 float val = (float)PyObjGetDouble(obj, strict, ok);
547 543 if (ok) {
548 544 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, float, val, ptr);
549 545 }
550 546 }
551 547 break;
552 548 case QMetaType::Double:
553 549 {
554 550 double val = (double)PyObjGetDouble(obj, strict, ok);
555 551 if (ok) {
556 552 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, double, val, ptr);
557 553 }
558 554 }
559 555 break;
560 556 case QMetaType::LongLong:
561 557 {
562 558 qint64 val = PyObjGetLongLong(obj, strict, ok);
563 559 if (ok) {
564 560 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, qint64, val, ptr);
565 561 }
566 562 }
567 563 break;
568 564 case QMetaType::ULongLong:
569 565 {
570 566 quint64 val = PyObjGetULongLong(obj, strict, ok);
571 567 if (ok) {
572 568 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, quint64, val, ptr);
573 569 }
574 570 }
575 571 break;
576 572 case QMetaType::QByteArray:
577 573 {
578 574 QByteArray bytes = PyObjGetBytes(obj, strict, ok);
579 575 if (ok) {
580 576 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(bytes), ptr);
581 577 ptr = (void*)((QVariant*)ptr)->constData();
582 578 }
583 579 }
584 580 break;
585 581 case QMetaType::QString:
586 582 {
587 583 QString str = PyObjGetString(obj, strict, ok);
588 584 if (ok) {
589 585 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str), ptr);
590 586 ptr = (void*)((QVariant*)ptr)->constData();
591 587 }
592 588 }
593 589 break;
594 590 case QMetaType::QStringList:
595 591 {
596 592 QStringList l = PyObjToStringList(obj, strict, ok);
597 593 if (ok) {
598 594 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(l), ptr);
599 595 ptr = (void*)((QVariant*)ptr)->constData();
600 596 }
601 597 }
602 598 break;
603 599
604 600 case PythonQtMethodInfo::Variant:
605 601 {
606 602 QVariant v = PyObjToQVariant(obj);
607 603 // the only case where conversion can fail it None and we want to pass that to, e.g. setProperty(),
608 604 // so we do not check v.isValid() here
609 605 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
610 606 }
611 607 break;
612 608 default:
613 609 {
614 610 // check for enum case
615 611 if (info.enumWrapper) {
616 612 unsigned int val;
617 613 ok = false;
618 614 if ((PyObject*)obj->ob_type == info.enumWrapper) {
619 615 // we have a exact enum type match:
620 616 val = PyLong_AsLong(obj);
621 617 ok = true;
622 618 } else if (!strict) {
623 619 // we try to get any integer, when not being strict. If we are strict, integers are not wanted because
624 620 // we want an integer overload to be taken first!
625 621 val = (unsigned int)PyObjGetLongLong(obj, false, ok);
626 622 }
627 623 if (ok) {
628 624 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
629 625 return ptr;
630 626 } else {
631 627 return NULL;
632 628 }
633 629 }
634 630
635 631 if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
636 632 // check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant
637 633 if (info.name.startsWith("QList<")) {
638 634 QByteArray innerType = info.name.mid(6,info.name.length()-7);
639 635 if (innerType.endsWith("*")) {
640 636 innerType.truncate(innerType.length()-1);
641 637 static int id = QMetaType::type("QList<void*>");
642 638 if (!alreadyAllocatedCPPObject) {
643 639 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(id), ptr);
644 640 ptr = (void*)((QVariant*)ptr)->constData();
645 641 } else {
646 642 ptr = alreadyAllocatedCPPObject;
647 643 }
648 644 ok = ConvertPythonListToQListOfPointerType(obj, (QList<void*>*)ptr, innerType, strict);
649 645 if (ok) {
650 646 return ptr;
651 647 } else {
652 648 return NULL;
653 649 }
654 650 }
655 651 }
656 652 }
657 653
658 654 // We only do this for registered type > QMetaType::User for performance reasons.
659 655 if (info.typeId >= QMetaType::User) {
660 656 // Maybe we have a special converter that is registered for that type:
661 657 PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(info.typeId);
662 658 if (converter) {
663 659 if (!alreadyAllocatedCPPObject) {
664 660 // create a new empty variant of concrete type:
665 661 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
666 662 ptr = (void*)((QVariant*)ptr)->constData();
667 663 } else {
668 664 ptr = alreadyAllocatedCPPObject;
669 665 }
670 666 // now call the converter, passing the internal object of the variant
671 667 ok = (*converter)(obj, ptr, info.typeId, strict);
672 668 if (ok) {
673 669 return ptr;
674 670 } else {
675 671 return NULL;
676 672 }
677 673 }
678 674 }
679 675 // if no type id is available, conversion to a QVariant makes no sense/is not possible
680 676 if (info.typeId != PythonQtMethodInfo::Unknown) {
681 677 // for all other types, we use the same qvariant conversion and pass out the constData of the variant:
682 678 QVariant v = PyObjToQVariant(obj, info.typeId);
683 679 if (v.isValid()) {
684 680 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
685 681 ptr = (void*)((QVariant*)ptr)->constData();
686 682 }
687 683 }
688 684 }
689 685 }
690 686 }
691 687 return ptr;
692 688 }
693 689
694 690
695 691 QStringList PythonQtConv::PyObjToStringList(PyObject* val, bool strict, bool& ok) {
696 692 QStringList v;
697 693 ok = false;
698 694 // if we are strict, we do not want to convert a string to a stringlist
699 695 // (strings in python are detected to be sequences)
700 696 if (strict && (
701 697 #ifndef PY3K
702 698 val->ob_type == &PyString_Type ||
703 699 #endif
704 700 PyUnicode_Check(val))) {
705 701 ok = false;
706 702 return v;
707 703 }
708 704 if (PySequence_Check(val)) {
709 705 int count = PySequence_Size(val);
710 706 for (int i = 0;i<count;i++) {
711 707 PyObject* value = PySequence_GetItem(val,i);
712 708 v.append(PyObjGetString(value,false,ok));
713 709 }
714 710 ok = true;
715 711 }
716 712 return v;
717 713 }
718 714
719 715 QString PythonQtConv::PyObjGetRepresentation(PyObject* val)
720 716 {
721 717 QString r;
722 718 PyObject* str = PyObject_Repr(val);
723 719 if (str) {
724 720 #ifdef PY3K
725 721 Py_UCS4 *x = PyUnicode_AsUCS4Copy(str);
726 722 r = QString::fromUcs4(x, PyUnicode_GetLength(str));
727 723 PyMem_Free(x);
728 724 #else
729 725 r = QString(PyString_AS_STRING(str));
730 726 #endif
731 727 Py_DECREF(str);
732 728 }
733 729 return r;
734 730 }
735 731
736 732 QString PythonQtConv::PyObjGetString(PyObject* val, bool strict, bool& ok) {
737 733 QString r;
738 734 ok = true;
739 735 #ifndef PY3K
740 736 if (Py_TYPE(val) == &PyString_Type) {
741 737 r = QString(PyString_AS_STRING(val));
742 738 } else
743 739 #endif
744 740 if (PyUnicode_Check(val)) {
745 741 #ifdef PY3K
746 742 Py_UCS4 *x = PyUnicode_AsUCS4Copy(val);
747 743 r = QString::fromUcs4(x, PyUnicode_GetLength(val));
748 744 PyMem_Free(x);
749 745 #else
750 746 PyObject *ptmp = PyUnicode_AsUTF8String(val);
751 747 if(ptmp) {
752 748 r = QString::fromUtf8(PyString_AS_STRING(ptmp));
753 749 Py_DECREF(ptmp);
754 750 }
755 751 #endif
756 752 } else if (!strict) {
757 753 // EXTRA: could also use _Unicode, but why should we?
758 754 PyObject* str = PyObject_Str(val);
759 755 if (str) {
760 756 #ifdef PY3K
761 757 Py_UCS4 *x = PyUnicode_AsUCS4Copy(str);
762 758 r = QString::fromUcs4(x, PyUnicode_GetLength(str));
763 759 PyMem_Free(x);
764 760 #else
765 761 r = QString(PyString_AS_STRING(str));
766 762 #endif
767 763 Py_DECREF(str);
768 764 } else {
769 765 ok = false;
770 766 }
771 767 } else {
772 768 ok = false;
773 769 }
774 770 return r;
775 771 }
776 772
777 773 QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) {
778 774 // TODO: support buffer objects in general
779 775 QByteArray r;
780 776 ok = true;
781 777 #ifdef PY3K
782 778 if (PyBytes_Check(val)) {
783 779 r = QByteArray(PyBytes_AS_STRING(val), PyBytes_GET_SIZE(val));
784 780 #else
785 781 if (Py_TYPE(val) == &PyString_Type) {
786 782 long size = PyString_GET_SIZE(val);
787 783 r = QByteArray(PyString_AS_STRING(val), size);
788 784 #endif
789 785 } else {
790 786 ok = false;
791 787 }
792 788 return r;
793 789 }
794 790
795 791 bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) {
796 792 bool d = false;
797 793 ok = false;
798 794 if (val == Py_False) {
799 795 d = false;
800 796 ok = true;
801 797 } else if (val == Py_True) {
802 798 d = true;
803 799 ok = true;
804 800 } else if (!strict) {
805 801 int result = PyObject_IsTrue(val);
806 802 d = (result == 1);
807 803 // the result is -1 if an error occurred, handle this:
808 804 ok = (result != -1);
809 805 }
810 806 return d;
811 807 }
812 808
813 809 int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) {
814 810 int d = 0;
815 811 ok = true;
816 812 #ifndef PY3K
817 813 if (val->ob_type == &PyInt_Type) {
818 814 d = PyInt_AS_LONG(val);
819 815 } else
820 816 #endif
821 817 if (Py_TYPE(val) == &PyLong_Type) {
822 818 // handle error on overflow!
823 819 d = PyLong_AsLong(val);
824 820 } else if (!strict) {
825 821 #ifndef PY3K
826 822 if (PyObject_TypeCheck(val, &PyInt_Type)) {
827 823 // support for derived int classes, e.g. for our enums
828 824 d = PyInt_AS_LONG(val);
829 825 } else
830 826 #endif
831 827 if (PyObject_TypeCheck(val, &PyLong_Type)) {
832 828 d = PyLong_AsLong(val);
833 829 } else if (Py_TYPE(val) == &PyFloat_Type) {
834 830 d = floor(PyFloat_AS_DOUBLE(val));
835 831 } else if (val == Py_False) {
836 832 d = 0;
837 833 } else if (val == Py_True) {
838 834 d = 1;
839 835 } else {
840 836 PyErr_Clear();
841 837 // PyInt_AsLong will try conversion to an int if the object is not an int:
842 838 d = PyLong_AsLong(val);
843 839 if (PyErr_Occurred()) {
844 840 ok = false;
845 841 PyErr_Clear();
846 842 }
847 843 }
848 844 } else {
849 845 ok = false;
850 846 }
851 847 return d;
852 848 }
853 849
854 850 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
855 851 qint64 d = 0;
856 852 ok = true;
857 853 #ifndef PY3K
858 854 if (val->ob_type == &PyInt_Type) {
859 855 d = PyInt_AS_LONG(val);
860 856 } else
861 857 #endif
862 858 if (Py_TYPE(val) == &PyLong_Type) {
863 859 d = PyLong_AsLongLong(val);
864 860 } else if (!strict) {
865 861 #ifndef PY3K
866 862 if (PyObject_TypeCheck(val, &PyInt_Type)) {
867 863 // support for derived int classes, e.g. for our enums
868 864 d = PyInt_AS_LONG(val);
869 865 } else
870 866 #endif
871 867 if (PyObject_TypeCheck(val, &PyLong_Type)) {
872 868 d = PyLong_AsLong(val);
873 869 } else if (Py_TYPE(val) == &PyFloat_Type) {
874 870 d = floor(PyFloat_AS_DOUBLE(val));
875 871 } else if (val == Py_False) {
876 872 d = 0;
877 873 } else if (val == Py_True) {
878 874 d = 1;
879 875 } else {
880 876 PyErr_Clear();
881 877 // PyLong_AsLongLong will try conversion to an int if the object is not an int:
882 878 d = PyLong_AsLongLong(val);
883 879 if (PyErr_Occurred()) {
884 880 ok = false;
885 881 PyErr_Clear();
886 882 }
887 883 }
888 884 } else {
889 885 ok = false;
890 886 }
891 887 return d;
892 888 }
893 889
894 890 quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) {
895 891 quint64 d = 0;
896 892 ok = true;
897 893 #ifndef PY3K
898 894 if (Py_TYPE(val) == &PyInt_Type) {
899 895 d = PyInt_AS_LONG(val);
900 896 } else
901 897 #endif
902 898 if (Py_TYPE(val) == &PyLong_Type) {
903 899 d = PyLong_AsLongLong(val);
904 900 } else if (!strict) {
905 901 #ifndef PY3K
906 902 if (PyObject_TypeCheck(val, &PyInt_Type)) {
907 903 // support for derived int classes, e.g. for our enums
908 904 d = PyInt_AS_LONG(val);
909 905 } else
910 906 #endif
911 907 if (PyObject_TypeCheck(val, &PyLong_Type)) {
912 908 d = PyLong_AsLong(val);
913 909 } else if (Py_TYPE(val) == &PyFloat_Type) {
914 910 d = floor(PyFloat_AS_DOUBLE(val));
915 911 } else if (val == Py_False) {
916 912 d = 0;
917 913 } else if (val == Py_True) {
918 914 d = 1;
919 915 } else {
920 916 PyErr_Clear();
921 917 // PyLong_AsLongLong will try conversion to an int if the object is not an int:
922 918 d = PyLong_AsLongLong(val);
923 919 if (PyErr_Occurred()) {
924 920 PyErr_Clear();
925 921 ok = false;
926 922 }
927 923 }
928 924 } else {
929 925 ok = false;
930 926 }
931 927 return d;
932 928 }
933 929
934 930 double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) {
935 931 double d = 0;
936 932 ok = true;
937 933 if (val->ob_type == &PyFloat_Type) {
938 934 d = PyFloat_AS_DOUBLE(val);
939 935 } else if (!strict) {
940 936 #ifndef PY3K
941 937 if (PyObject_TypeCheck(val, &PyInt_Type)) {
942 938 d = PyInt_AS_LONG(val);
943 939 } else
944 940 #endif
945 941 if (PyLong_Check(val)) {
946 942 d = PyLong_AsLong(val);
947 943 } else if (val == Py_False) {
948 944 d = 0;
949 945 } else if (val == Py_True) {
950 946 d = 1;
951 947 } else {
952 948 PyErr_Clear();
953 949 // PyFloat_AsDouble will try conversion to a double if the object is not a float:
954 950 d = PyFloat_AsDouble(val);
955 951 if (PyErr_Occurred()) {
956 952 PyErr_Clear();
957 953 ok = false;
958 954 }
959 955 }
960 956 } else {
961 957 ok = false;
962 958 }
963 959 return d;
964 960 }
965 961
966 962 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
967 963 {
968 964 QVariant v;
969 965 bool ok = true;
970 966
971 967 if (type==-1) {
972 968 // no special type requested
973 969 #ifdef PY3K
974 970 if (PyBytes_Check(val)) {
975 971 type = QVariant::ByteArray;
976 972 } else if (PyUnicode_Check(val)) {
977 973 #else
978 974 if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) {
979 975 #endif
980 976 type = QVariant::String;
981 977 } else if (val == Py_False || val == Py_True) {
982 978 type = QVariant::Bool;
983 979 #ifndef PY3K
984 980 } else if (PyObject_TypeCheck(val, &PyInt_Type)) {
985 981 type = QVariant::Int;
986 982 #endif
987 983 } else if (PyLong_Check(val)) {
988 984 type = QVariant::LongLong;
989 985 } else if (PyFloat_Check(val)) {
990 986 type = QVariant::Double;
991 987 } else if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
992 988 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
993 989 // c++ wrapper, check if the class names of the c++ objects match
994 990 if (wrap->classInfo()->isCPPWrapper()) {
995 991 if (wrap->classInfo()->metaTypeId()>0) {
996 992 // construct a new variant from the C++ object if it has a meta type (this will COPY the object!)
997 993 v = QVariant(wrap->classInfo()->metaTypeId(), wrap->_wrappedPtr);
998 994 } else {
999 995 // TODOXXX we could as well check if there is a registered meta type for "classname*", so that we may pass
1000 996 // the pointer here...
1001 997 // is this worth anything? we loose the knowledge of the cpp object type
1002 998 v = qVariantFromValue(wrap->_wrappedPtr);
1003 999 }
1004 1000 } else {
1005 1001 // this gives us a QObject pointer
1006 1002 QObject* myObject = wrap->_obj;
1007 1003 v = qVariantFromValue(myObject);
1008 1004 }
1009 1005 return v;
1010 1006 } else if (PyDict_Check(val)) {
1011 1007 type = QVariant::Map;
1012 1008 } else if (PyList_Check(val) || PyTuple_Check(val) || PySequence_Check(val)) {
1013 1009 type = QVariant::List;
1014 1010 } else if (val == Py_None) {
1015 1011 // none is invalid
1016 1012 type = QVariant::Invalid;
1017 1013 } else {
1018 1014 // this used to be:
1019 1015 // type = QVariant::String;
1020 1016 // but now we want to transport the Python Objects directly:
1021 1017 PythonQtObjectPtr o(val);
1022 1018 v = qVariantFromValue(o);
1023 1019 return v;
1024 1020 }
1025 1021 }
1026 1022 // special type request:
1027 1023 switch (type) {
1028 1024 case QVariant::Invalid:
1029 1025 return v;
1030 1026 break;
1031 1027 case QVariant::Int:
1032 1028 {
1033 1029 int d = PyObjGetInt(val, false, ok);
1034 1030 if (ok) return QVariant(d);
1035 1031 }
1036 1032 break;
1037 1033 case QVariant::UInt:
1038 1034 {
1039 1035 int d = PyObjGetInt(val, false,ok);
1040 1036 if (ok) v = QVariant((unsigned int)d);
1041 1037 }
1042 1038 break;
1043 1039 case QVariant::Bool:
1044 1040 {
1045 1041 int d = PyObjGetBool(val,false,ok);
1046 1042 if (ok) v = QVariant((bool)(d!=0));
1047 1043 }
1048 1044 break;
1049 1045 case QVariant::Double:
1050 1046 {
1051 1047 double d = PyObjGetDouble(val,false,ok);
1052 1048 if (ok) v = QVariant(d);
1053 1049 break;
1054 1050 }
1055 1051 case QMetaType::Float:
1056 1052 {
1057 1053 float d = (float) PyObjGetDouble(val,false,ok);
1058 1054 if (ok) v = qVariantFromValue(d);
1059 1055 break;
1060 1056 }
1061 1057 case QMetaType::Long:
1062 1058 {
1063 1059 long d = (long) PyObjGetLongLong(val,false,ok);
1064 1060 if (ok) v = qVariantFromValue(d);
1065 1061 break;
1066 1062 }
1067 1063 case QMetaType::ULong:
1068 1064 {
1069 1065 unsigned long d = (unsigned long) PyObjGetLongLong(val,false,ok);
1070 1066 if (ok) v = qVariantFromValue(d);
1071 1067 break;
1072 1068 }
1073 1069 case QMetaType::LongLong:
1074 1070 {
1075 1071 qint64 d = PyObjGetLongLong(val, false, ok);
1076 1072 if (ok) v = qVariantFromValue(d);
1077 1073 }
1078 1074 break;
1079 1075 case QMetaType::ULongLong:
1080 1076 {
1081 1077 quint64 d = PyObjGetULongLong(val, false, ok);
1082 1078 if (ok) v = qVariantFromValue(d);
1083 1079 }
1084 1080 break;
1085 1081 case QMetaType::Short:
1086 1082 {
1087 1083 short d = (short) PyObjGetInt(val,false,ok);
1088 1084 if (ok) v = qVariantFromValue(d);
1089 1085 break;
1090 1086 }
1091 1087 case QMetaType::UShort:
1092 1088 {
1093 1089 unsigned short d = (unsigned short) PyObjGetInt(val,false,ok);
1094 1090 if (ok) v = qVariantFromValue(d);
1095 1091 break;
1096 1092 }
1097 1093 case QMetaType::Char:
1098 1094 {
1099 1095 char d = (char) PyObjGetInt(val,false,ok);
1100 1096 if (ok) v = qVariantFromValue(d);
1101 1097 break;
1102 1098 }
1103 1099 case QMetaType::UChar:
1104 1100 {
1105 1101 unsigned char d = (unsigned char) PyObjGetInt(val,false,ok);
1106 1102 if (ok) v = qVariantFromValue(d);
1107 1103 break;
1108 1104 }
1109 1105
1110 1106 case QVariant::ByteArray:
1111 1107 case QVariant::String:
1112 1108 {
1113 1109 bool ok;
1114 1110 v = QVariant(PyObjGetString(val, false, ok));
1115 1111 }
1116 1112 break;
1117 1113
1118 1114 // these are important for MeVisLab
1119 1115 case QVariant::Map:
1120 1116 {
1121 1117 if (PyMapping_Check(val)) {
1122 1118 QMap<QString,QVariant> map;
1123 1119 PyObject* items = PyMapping_Items(val);
1124 1120 if (items) {
1125 1121 int count = PyList_Size(items);
1126 1122 PyObject* value;
1127 1123 PyObject* key;
1128 1124 PyObject* tuple;
1129 1125 for (int i = 0;i<count;i++) {
1130 1126 tuple = PyList_GetItem(items,i);
1131 1127 key = PyTuple_GetItem(tuple, 0);
1132 1128 value = PyTuple_GetItem(tuple, 1);
1133 1129 map.insert(PyObjGetString(key), PyObjToQVariant(value,-1));
1134 1130 }
1135 1131 Py_DECREF(items);
1136 1132 v = map;
1137 1133 }
1138 1134 }
1139 1135 }
1140 1136 break;
1141 1137 case QVariant::List:
1142 1138 if (PySequence_Check(val)) {
1143 1139 QVariantList list;
1144 1140 int count = PySequence_Size(val);
1145 1141 PyObject* value;
1146 1142 for (int i = 0;i<count;i++) {
1147 1143 value = PySequence_GetItem(val,i);
1148 1144 list.append(PyObjToQVariant(value, -1));
1149 1145 }
1150 1146 v = list;
1151 1147 }
1152 1148 break;
1153 1149 case QVariant::StringList:
1154 1150 {
1155 1151 bool ok;
1156 1152 QStringList l = PyObjToStringList(val, false, ok);
1157 1153 if (ok) {
1158 1154 v = l;
1159 1155 }
1160 1156 }
1161 1157 break;
1162 1158
1163 1159 default:
1164 1160 if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
1165 1161 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
1166 1162 if (wrap->classInfo()->isCPPWrapper() && wrap->classInfo()->metaTypeId() == type) {
1167 1163 // construct a new variant from the C++ object if it has the same meta type
1168 1164 v = QVariant(type, wrap->_wrappedPtr);
1169 1165 } else {
1170 1166 v = QVariant();
1171 1167 }
1172 1168 } else {
1173 1169 v = QVariant();
1174 1170 }
1175 1171 }
1176 1172 return v;
1177 1173 }
1178 1174
1179 1175 PyObject* PythonQtConv::QStringToPyObject(const QString& str)
1180 1176 {
1181 1177 if (str.isNull()) {
1182 1178 #ifdef PY3K
1183 1179 return PyUnicode_New(0, 0);
1184 1180 #else
1185 1181 return PyString_FromString("");
1186 1182 #endif
1187 1183 } else {
1188 1184 return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, NULL, NULL);
1189 1185 }
1190 1186 }
1191 1187
1192 1188 PyObject* PythonQtConv::QStringListToPyObject(const QStringList& list)
1193 1189 {
1194 1190 PyObject* result = PyTuple_New(list.count());
1195 1191 int i = 0;
1196 1192 QString str;
1197 1193 Q_FOREACH (str, list) {
1198 1194 PyTuple_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(str));
1199 1195 i++;
1200 1196 }
1201 1197 // why is the error state bad after this?
1202 1198 PyErr_Clear();
1203 1199 return result;
1204 1200 }
1205 1201
1206 1202 PyObject* PythonQtConv::QStringListToPyList(const QStringList& list)
1207 1203 {
1208 1204 PyObject* result = PyList_New(list.count());
1209 1205 int i = 0;
1210 1206 for (QStringList::ConstIterator it = list.begin(); it!=list.end(); ++it) {
1211 1207 PyList_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(*it));
1212 1208 i++;
1213 1209 }
1214 1210 return result;
1215 1211 }
1216 1212
1217 1213 PyObject* PythonQtConv::QVariantToPyObject(const QVariant& v)
1218 1214 {
1219 1215 return ConvertQtValueToPythonInternal(v.userType(), (void*)v.constData());
1220 1216 }
1221 1217
1222 1218 PyObject* PythonQtConv::QVariantMapToPyObject(const QVariantMap& m) {
1223 1219 PyObject* result = PyDict_New();
1224 1220 QVariantMap::const_iterator t = m.constBegin();
1225 1221 PyObject* key;
1226 1222 PyObject* val;
1227 1223 for (;t!=m.end();t++) {
1228 1224 key = QStringToPyObject(t.key());
1229 1225 val = QVariantToPyObject(t.value());
1230 1226 PyDict_SetItem(result, key, val);
1231 1227 Py_DECREF(key);
1232 1228 Py_DECREF(val);
1233 1229 }
1234 1230 return result;
1235 1231 }
1236 1232
1237 1233 PyObject* PythonQtConv::QVariantListToPyObject(const QVariantList& l) {
1238 1234 PyObject* result = PyTuple_New(l.count());
1239 1235 int i = 0;
1240 1236 QVariant v;
1241 1237 Q_FOREACH (v, l) {
1242 1238 PyTuple_SET_ITEM(result, i, PythonQtConv::QVariantToPyObject(v));
1243 1239 i++;
1244 1240 }
1245 1241 // why is the error state bad after this?
1246 1242 PyErr_Clear();
1247 1243 return result;
1248 1244 }
1249 1245
1250 1246 PyObject* PythonQtConv::ConvertQListOfPointerTypeToPythonList(QList<void*>* list, const QByteArray& typeName)
1251 1247 {
1252 1248 PyObject* result = PyTuple_New(list->count());
1253 1249 int i = 0;
1254 1250 Q_FOREACH (void* value, *list) {
1255 1251 PyTuple_SET_ITEM(result, i, PythonQt::priv()->wrapPtr(value, typeName));
1256 1252 i++;
1257 1253 }
1258 1254 return result;
1259 1255 }
1260 1256
1261 1257 bool PythonQtConv::ConvertPythonListToQListOfPointerType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool /*strict*/)
1262 1258 {
1263 1259 bool result = false;
1264 1260 if (PySequence_Check(obj)) {
1265 1261 result = true;
1266 1262 int count = PySequence_Size(obj);
1267 1263 PyObject* value;
1268 1264 for (int i = 0;i<count;i++) {
1269 1265 value = PySequence_GetItem(obj,i);
1270 1266 if (PyObject_TypeCheck(value, &PythonQtInstanceWrapper_Type)) {
1271 1267 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)value;
1272 1268 bool ok;
1273 1269 void* object = castWrapperTo(wrap, type, ok);
1274 1270 if (ok) {
1275 1271 list->append(object);
1276 1272 } else {
1277 1273 result = false;
1278 1274 break;
1279 1275 }
1280 1276 }
1281 1277 }
1282 1278 }
1283 1279 return result;
1284 1280 }
1285 1281
1286 1282 int PythonQtConv::getInnerTemplateMetaType(const QByteArray& typeName)
1287 1283 {
1288 1284 int idx = typeName.indexOf("<");
1289 1285 if (idx>0) {
1290 1286 int idx2 = typeName.indexOf(">");
1291 1287 if (idx2>0) {
1292 1288 QByteArray innerType = typeName.mid(idx+1,idx2-idx-1);
1293 1289 return QMetaType::type(innerType.constData());
1294 1290 }
1295 1291 }
1296 1292 return QMetaType::Void;
1297 1293 }
1298 1294
1299 1295
1300 1296 QString PythonQtConv::CPPObjectToString(int type, const void* data) {
1301 1297 QString r;
1302 1298 switch (type) {
1303 1299 case QVariant::Size: {
1304 1300 const QSize* s = static_cast<const QSize*>(data);
1305 1301 r = QString::number(s->width()) + ", " + QString::number(s->height());
1306 1302 }
1307 1303 break;
1308 1304 case QVariant::SizeF: {
1309 1305 const QSizeF* s = static_cast<const QSizeF*>(data);
1310 1306 r = QString::number(s->width()) + ", " + QString::number(s->height());
1311 1307 }
1312 1308 break;
1313 1309 case QVariant::Point: {
1314 1310 const QPoint* s = static_cast<const QPoint*>(data);
1315 1311 r = QString::number(s->x()) + ", " + QString::number(s->y());
1316 1312 }
1317 1313 break;
1318 1314 case QVariant::PointF: {
1319 1315 const QPointF* s = static_cast<const QPointF*>(data);
1320 1316 r = QString::number(s->x()) + ", " + QString::number(s->y());
1321 1317 }
1322 1318 break;
1323 1319 case QVariant::Rect: {
1324 1320 const QRect* s = static_cast<const QRect*>(data);
1325 1321 r = QString::number(s->x()) + ", " + QString::number(s->y());
1326 1322 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1327 1323 }
1328 1324 break;
1329 1325 case QVariant::RectF: {
1330 1326 const QRectF* s = static_cast<const QRectF*>(data);
1331 1327 r = QString::number(s->x()) + ", " + QString::number(s->y());
1332 1328 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1333 1329 }
1334 1330 break;
1335 1331 case QVariant::Date: {
1336 1332 const QDate* s = static_cast<const QDate*>(data);
1337 1333 r = s->toString(Qt::ISODate);
1338 1334 }
1339 1335 break;
1340 1336 case QVariant::DateTime: {
1341 1337 const QDateTime* s = static_cast<const QDateTime*>(data);
1342 1338 r = s->toString(Qt::ISODate);
1343 1339 }
1344 1340 break;
1345 1341 case QVariant::Time: {
1346 1342 const QTime* s = static_cast<const QTime*>(data);
1347 1343 r = s->toString(Qt::ISODate);
1348 1344 }
1349 1345 break;
1350 1346 case QVariant::Pixmap:
1351 1347 {
1352 1348 const QPixmap* s = static_cast<const QPixmap*>(data);
1353 1349 r = QString("Pixmap ") + QString::number(s->width()) + ", " + QString::number(s->height());
1354 1350 }
1355 1351 break;
1356 1352 case QVariant::Image:
1357 1353 {
1358 1354 const QImage* s = static_cast<const QImage*>(data);
1359 1355 r = QString("Image ") + QString::number(s->width()) + ", " + QString::number(s->height());
1360 1356 }
1361 1357 break;
1362 1358 case QVariant::Url:
1363 1359 {
1364 1360 const QUrl* s = static_cast<const QUrl*>(data);
1365 1361 r = s->toString();
1366 1362 }
1367 1363 break;
1368 1364 //TODO: add more printing for other variant types
1369 1365 default:
1370 1366 // this creates a copy, but that should not be expensive for typical simple variants
1371 1367 // (but we do not want to do this for our won user types!
1372 1368 if (type>0 && type < (int)QVariant::UserType) {
1373 1369 QVariant v(type, data);
1374 1370 r = v.toString();
1375 1371 }
1376 1372 }
1377 1373 return r;
1378 1374 }
@@ -1,853 +1,849
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 PythonQtImporter.h
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 // This module was inspired by the zipimport.c module of the original
41 41 // Python distribution. Most of the functions are identical or slightly
42 42 // modified to do all the loading of Python files via an external file interface.
43 43 // In contrast to zipimport.c, this module also writes *.pyc files
44 44 // automatically if it has write access/is not inside of a zip file.
45 45 //----------------------------------------------------------------------------------
46 46
47 47 #include "PythonQtImporter.h"
48 48 #include "PythonQtImportFileInterface.h"
49 49 #include "PythonQt.h"
50 50 #include "PythonQtConversion.h"
51 51 #include <QFile>
52 52 #include <QFileInfo>
53 53
54 #if PY_MAJOR_VERSION >= 3
55 #define PY3K
56 #endif
57
58 54 #define IS_SOURCE 0x0
59 55 #define IS_BYTECODE 0x1
60 56 #define IS_PACKAGE 0x2
61 57
62 58 struct st_mlab_searchorder {
63 59 char suffix[14];
64 60 int type;
65 61 };
66 62
67 63 /* mlab_searchorder defines how we search for a module in the Zip
68 64 archive: we first search for a package __init__, then for
69 65 non-package .pyc, .pyo and .py entries. The .pyc and .pyo entries
70 66 are swapped by initmlabimport() if we run in optimized mode. Also,
71 67 '/' is replaced by SEP there. */
72 68 struct st_mlab_searchorder mlab_searchorder[] = {
73 69 {"/__init__.pyc", IS_PACKAGE | IS_BYTECODE},
74 70 {"/__init__.pyo", IS_PACKAGE | IS_BYTECODE},
75 71 {"/__init__.py", IS_PACKAGE | IS_SOURCE},
76 72 {".pyc", IS_BYTECODE},
77 73 {".pyo", IS_BYTECODE},
78 74 {".py", IS_SOURCE},
79 75 {"", 0}
80 76 };
81 77
82 78 extern PyTypeObject PythonQtImporter_Type;
83 79 PyObject *PythonQtImportError;
84 80
85 81 QString PythonQtImport::getSubName(const QString& str)
86 82 {
87 83 int idx = str.lastIndexOf('.');
88 84 if (idx!=-1) {
89 85 return str.mid(idx+1);
90 86 } else {
91 87 return str;
92 88 }
93 89 }
94 90
95 91 PythonQtImport::ModuleInfo PythonQtImport::getModuleInfo(PythonQtImporter* self, const QString& fullname)
96 92 {
97 93 ModuleInfo info;
98 94 QString subname;
99 95 struct st_mlab_searchorder *zso;
100 96
101 97 subname = getSubName(fullname);
102 98 QString path = *self->_path + "/" + subname;
103 99
104 100 QString test;
105 101 for (zso = mlab_searchorder; *zso->suffix; zso++) {
106 102 test = path + zso->suffix;
107 103 if (PythonQt::importInterface()->exists(test)) {
108 104 info.fullPath = test;
109 105 info.moduleName = subname;
110 106 info.type = (zso->type & IS_PACKAGE)?MI_PACKAGE:MI_MODULE;
111 107 return info;
112 108 }
113 109 }
114 110 // test if it is a shared library
115 111 Q_FOREACH(const QString& suffix, PythonQt::priv()->sharedLibrarySuffixes()) {
116 112 test = path+suffix;
117 113 if (PythonQt::importInterface()->exists(test)) {
118 114 info.fullPath = test;
119 115 info.moduleName = subname;
120 116 info.type = MI_SHAREDLIBRARY;
121 117 return info;
122 118 }
123 119 }
124 120 return info;
125 121 }
126 122
127 123
128 124 /* PythonQtImporter.__init__
129 125 Just store the path argument (or reject if it is in the ignorePaths list
130 126 */
131 127 int PythonQtImporter_init(PythonQtImporter *self, PyObject *args, PyObject * /*kwds*/)
132 128 {
133 129 self->_path = NULL;
134 130
135 131 const char* cpath;
136 132 if (!PyArg_ParseTuple(args, "s",
137 133 &cpath))
138 134 return -1;
139 135
140 136 QString path(cpath);
141 137 if (PythonQt::importInterface()->exists(path)) {
142 138 const QStringList& ignorePaths = PythonQt::self()->getImporterIgnorePaths();
143 139 Q_FOREACH(QString ignorePath, ignorePaths) {
144 140 if (path.startsWith(ignorePath)) {
145 141 PyErr_SetString(PythonQtImportError,
146 142 "path ignored");
147 143 return -1;
148 144 }
149 145 }
150 146
151 147 self->_path = new QString(path);
152 148 return 0;
153 149 } else {
154 150 PyErr_SetString(PythonQtImportError,
155 151 "path does not exist error");
156 152 return -1;
157 153 }
158 154 }
159 155
160 156 void
161 157 PythonQtImporter_dealloc(PythonQtImporter *self)
162 158 {
163 159 // free the stored path
164 160 if (self->_path) delete self->_path;
165 161 // free ourself
166 162 Py_TYPE(self)->tp_free((PyObject *)self);
167 163 }
168 164
169 165
170 166 /* Check whether we can satisfy the import of the module named by
171 167 'fullname'. Return self if we can, None if we can't. */
172 168 PyObject *
173 169 PythonQtImporter_find_module(PyObject *obj, PyObject *args)
174 170 {
175 171 PythonQtImporter *self = (PythonQtImporter *)obj;
176 172 PyObject *path = NULL;
177 173 char *fullname;
178 174
179 175 if (!PyArg_ParseTuple(args, "s|O:PythonQtImporter.find_module",
180 176 &fullname, &path))
181 177 return NULL;
182 178
183 179 //qDebug() << "looking for " << fullname << " at " << *self->_path;
184 180
185 181 PythonQtImport::ModuleInfo info = PythonQtImport::getModuleInfo(self, fullname);
186 182 if (info.type != PythonQtImport::MI_NOT_FOUND) {
187 183 Py_INCREF(self);
188 184 return (PyObject *)self;
189 185 } else {
190 186 Py_INCREF(Py_None);
191 187 return Py_None;
192 188 }
193 189 }
194 190
195 191 /* Load and return the module named by 'fullname'. */
196 192 PyObject *
197 193 PythonQtImporter_load_module(PyObject *obj, PyObject *args)
198 194 {
199 195 PythonQtImporter *self = (PythonQtImporter *)obj;
200 196 PyObject *code = NULL, *mod = NULL, *dict = NULL;
201 197 char *fullname;
202 198
203 199 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.load_module",
204 200 &fullname))
205 201 return NULL;
206 202
207 203 PythonQtImport::ModuleInfo info = PythonQtImport::getModuleInfo(self, fullname);
208 204 if (info.type == PythonQtImport::MI_NOT_FOUND) {
209 205 return NULL;
210 206 }
211 207
212 208 if (info.type == PythonQtImport::MI_PACKAGE || info.type == PythonQtImport::MI_MODULE) {
213 209 QString fullPath;
214 210 code = PythonQtImport::getModuleCode(self, fullname, fullPath);
215 211 if (code == NULL) {
216 212 return NULL;
217 213 }
218 214
219 215 mod = PyImport_AddModule(fullname);
220 216 if (mod == NULL) {
221 217 Py_DECREF(code);
222 218 return NULL;
223 219 }
224 220 dict = PyModule_GetDict(mod);
225 221
226 222 if (PyDict_SetItemString(dict, "__loader__", (PyObject *)self) != 0) {
227 223 Py_DECREF(code);
228 224 Py_DECREF(mod);
229 225 return NULL;
230 226 }
231 227
232 228 if (info.type == PythonQtImport::MI_PACKAGE) {
233 229 PyObject *pkgpath, *fullpath;
234 230 QString subname = info.moduleName;
235 231 int err;
236 232
237 233 #ifdef PY3K
238 234 fullpath = PyUnicode_FromFormat("%s%c%s",
239 235 #else
240 236 fullpath = PyString_FromFormat("%s%c%s",
241 237 #endif
242 238 self->_path->toLatin1().constData(),
243 239 SEP,
244 240 subname.toLatin1().constData());
245 241 if (fullpath == NULL) {
246 242 Py_DECREF(code);
247 243 Py_DECREF(mod);
248 244 return NULL;
249 245 }
250 246
251 247 pkgpath = Py_BuildValue("[O]", fullpath);
252 248 Py_DECREF(fullpath);
253 249 if (pkgpath == NULL) {
254 250 Py_DECREF(code);
255 251 Py_DECREF(mod);
256 252 return NULL;
257 253 }
258 254 err = PyDict_SetItemString(dict, "__path__", pkgpath);
259 255 Py_DECREF(pkgpath);
260 256 if (err != 0) {
261 257 Py_DECREF(code);
262 258 Py_DECREF(mod);
263 259 return NULL;
264 260 }
265 261 }
266 262
267 263 mod = PyImport_ExecCodeModuleEx(fullname, code, fullPath.toLatin1().data());
268 264
269 265 if (PythonQt::importInterface()) {
270 266 PythonQt::importInterface()->importedModule(fullname);
271 267 }
272 268
273 269 Py_DECREF(code);
274 270 if (Py_VerboseFlag) {
275 271 PySys_WriteStderr("import %s # loaded from %s\n",
276 272 fullname, fullPath.toLatin1().constData());
277 273 }
278 274 } else {
279 275 PythonQtObjectPtr imp;
280 276 imp.setNewRef(PyImport_ImportModule("imp"));
281 277
282 278 // Create a PyList with the current path as its single element,
283 279 // which is required for find_module (it won't accept a tuple...)
284 280 PythonQtObjectPtr pathList;
285 281 pathList.setNewRef(PythonQtConv::QStringListToPyList(QStringList() << *self->_path));
286 282
287 283 QVariantList args;
288 284 // Pass the module name without the package prefix
289 285 args.append(info.moduleName);
290 286 // And the path where we know that the shared library is
291 287 args.append(QVariant::fromValue(pathList));
292 288 QVariant result = imp.call("find_module", args);
293 289 if (result.isValid()) {
294 290 // This will return a tuple with (file, pathname, description=(suffix,mode,type))
295 291 QVariantList list = result.toList();
296 292 if (list.count()==3) {
297 293 // We prepend the full module name (including package prefix)
298 294 list.prepend(fullname);
299 295 #ifdef __linux
300 296 #ifdef _DEBUG
301 297 // imp_find_module() does not respect the debug suffix '_d' on Linux,
302 298 // so it does not return the correct file path and we correct it now
303 299 // find_module opened a file to the release library, but that file handle is
304 300 // ignored on Linux and Windows, maybe on MacOS also.
305 301 list[2] = info.fullPath;
306 302 #endif
307 303 #endif
308 304 // And call "load_module" with (fullname, file, pathname, description=(suffix,mode,type))
309 305 PythonQtObjectPtr module = imp.call("load_module", list);
310 306 mod = module.object();
311 307 if (mod) {
312 308 Py_INCREF(mod);
313 309 }
314 310
315 311 // Finally, we need to close the file again, which find_module opened for us
316 312 PythonQtObjectPtr file = list.at(1);
317 313 file.call("close");
318 314 }
319 315 }
320 316 }
321 317 return mod;
322 318 }
323 319
324 320
325 321 PyObject *
326 322 PythonQtImporter_get_data(PyObject* /*obj*/, PyObject* /*args*/)
327 323 {
328 324 // EXTRA, NOT YET IMPLEMENTED
329 325 return NULL;
330 326 }
331 327
332 328 PyObject *
333 329 PythonQtImporter_get_code(PyObject *obj, PyObject *args)
334 330 {
335 331 PythonQtImporter *self = (PythonQtImporter *)obj;
336 332 char *fullname;
337 333
338 334 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.get_code", &fullname))
339 335 return NULL;
340 336
341 337 QString notused;
342 338 return PythonQtImport::getModuleCode(self, fullname, notused);
343 339 }
344 340
345 341 PyObject *
346 342 PythonQtImporter_get_source(PyObject * /*obj*/, PyObject * /*args*/)
347 343 {
348 344 // EXTRA, NOT YET IMPLEMENTED
349 345 return NULL;
350 346 }
351 347
352 348 PyDoc_STRVAR(doc_find_module,
353 349 "find_module(fullname, path=None) -> self or None.\n\
354 350 \n\
355 351 Search for a module specified by 'fullname'. 'fullname' must be the\n\
356 352 fully qualified (dotted) module name. It returns the PythonQtImporter\n\
357 353 instance itself if the module was found, or None if it wasn't.\n\
358 354 The optional 'path' argument is ignored -- it's there for compatibility\n\
359 355 with the importer protocol.");
360 356
361 357 PyDoc_STRVAR(doc_load_module,
362 358 "load_module(fullname) -> module.\n\
363 359 \n\
364 360 Load the module specified by 'fullname'. 'fullname' must be the\n\
365 361 fully qualified (dotted) module name. It returns the imported\n\
366 362 module, or raises PythonQtImportError if it wasn't found.");
367 363
368 364 PyDoc_STRVAR(doc_get_data,
369 365 "get_data(pathname) -> string with file data.\n\
370 366 \n\
371 367 Return the data associated with 'pathname'. Raise IOError if\n\
372 368 the file wasn't found.");
373 369
374 370 PyDoc_STRVAR(doc_get_code,
375 371 "get_code(fullname) -> code object.\n\
376 372 \n\
377 373 Return the code object for the specified module. Raise PythonQtImportError\n\
378 374 is the module couldn't be found.");
379 375
380 376 PyDoc_STRVAR(doc_get_source,
381 377 "get_source(fullname) -> source string.\n\
382 378 \n\
383 379 Return the source code for the specified module. Raise PythonQtImportError\n\
384 380 is the module couldn't be found, return None if the archive does\n\
385 381 contain the module, but has no source for it.");
386 382
387 383 PyMethodDef PythonQtImporter_methods[] = {
388 384 {"find_module", PythonQtImporter_find_module, METH_VARARGS,
389 385 doc_find_module},
390 386 {"load_module", PythonQtImporter_load_module, METH_VARARGS,
391 387 doc_load_module},
392 388 {"get_data", PythonQtImporter_get_data, METH_VARARGS,
393 389 doc_get_data},
394 390 {"get_code", PythonQtImporter_get_code, METH_VARARGS,
395 391 doc_get_code},
396 392 {"get_source", PythonQtImporter_get_source, METH_VARARGS,
397 393 doc_get_source},
398 394 {NULL, NULL, 0 , NULL} /* sentinel */
399 395 };
400 396
401 397
402 398 PyDoc_STRVAR(PythonQtImporter_doc,
403 399 "PythonQtImporter(path) -> PythonQtImporter object\n\
404 400 \n\
405 401 Create a new PythonQtImporter instance. 'path' must be a valid path on disk/or inside of a zip file known to MeVisLab\n\
406 402 . Every path is accepted.");
407 403
408 404 #define DEFERRED_ADDRESS(ADDR) 0
409 405
410 406 PyTypeObject PythonQtImporter_Type = {
411 407 PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
412 408 "PythonQtImport.PythonQtImporter",
413 409 sizeof(PythonQtImporter),
414 410 0, /* tp_itemsize */
415 411 (destructor)PythonQtImporter_dealloc, /* tp_dealloc */
416 412 0, /* tp_print */
417 413 0, /* tp_getattr */
418 414 0, /* tp_setattr */
419 415 0, /* tp_compare */
420 416 0, /* tp_repr */
421 417 0, /* tp_as_number */
422 418 0, /* tp_as_sequence */
423 419 0, /* tp_as_mapping */
424 420 0, /* tp_hash */
425 421 0, /* tp_call */
426 422 0, /* tp_str */
427 423 PyObject_GenericGetAttr, /* tp_getattro */
428 424 0, /* tp_setattro */
429 425 0, /* tp_as_buffer */
430 426 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE , /* tp_flags */
431 427 PythonQtImporter_doc, /* tp_doc */
432 428 0, /* tp_traverse */
433 429 0, /* tp_clear */
434 430 0, /* tp_richcompare */
435 431 0, /* tp_weaklistoffset */
436 432 0, /* tp_iter */
437 433 0, /* tp_iternext */
438 434 PythonQtImporter_methods, /* tp_methods */
439 435 0, /* tp_members */
440 436 0, /* tp_getset */
441 437 0, /* tp_base */
442 438 0, /* tp_dict */
443 439 0, /* tp_descr_get */
444 440 0, /* tp_descr_set */
445 441 0, /* tp_dictoffset */
446 442 (initproc)PythonQtImporter_init, /* tp_init */
447 443 PyType_GenericAlloc, /* tp_alloc */
448 444 PyType_GenericNew, /* tp_new */
449 445 PyObject_Del, /* tp_free */
450 446 };
451 447
452 448
453 449 /* Given a buffer, return the long that is represented by the first
454 450 4 bytes, encoded as little endian. This partially reimplements
455 451 marshal.c:r_long() */
456 452 long
457 453 PythonQtImport::getLong(unsigned char *buf)
458 454 {
459 455 long x;
460 456 x = buf[0];
461 457 x |= (long)buf[1] << 8;
462 458 x |= (long)buf[2] << 16;
463 459 x |= (long)buf[3] << 24;
464 460 #if SIZEOF_LONG > 4
465 461 /* Sign extension for 64-bit machines */
466 462 x |= -(x & 0x80000000L);
467 463 #endif
468 464 return x;
469 465 }
470 466
471 467 FILE *
472 468 open_exclusive(const QString& filename)
473 469 {
474 470 #if defined(O_EXCL)&&defined(O_CREAT)&&defined(O_WRONLY)&&defined(O_TRUNC)
475 471 /* Use O_EXCL to avoid a race condition when another process tries to
476 472 write the same file. When that happens, our open() call fails,
477 473 which is just fine (since it's only a cache).
478 474 XXX If the file exists and is writable but the directory is not
479 475 writable, the file will never be written. Oh well.
480 476 */
481 477 QFile::remove(filename);
482 478
483 479 int fd;
484 480 int flags = O_EXCL|O_CREAT|O_WRONLY|O_TRUNC;
485 481 #ifdef O_BINARY
486 482 flags |= O_BINARY; /* necessary for Windows */
487 483 #endif
488 484 #ifdef WIN32
489 485 fd = _wopen(filename.ucs2(), flags, 0666);
490 486 #else
491 487 fd = open(filename.local8Bit(), flags, 0666);
492 488 #endif
493 489 if (fd < 0)
494 490 return NULL;
495 491 return fdopen(fd, "wb");
496 492 #else
497 493 /* Best we can do -- on Windows this can't happen anyway */
498 494 return fopen(filename.toLocal8Bit().constData(), "wb");
499 495 #endif
500 496 }
501 497
502 498
503 499 void PythonQtImport::writeCompiledModule(PyCodeObject *co, const QString& filename, long mtime)
504 500 {
505 501 FILE *fp;
506 502 // we do not want to write Qt resources to disk, do we?
507 503 if (filename.startsWith(":")) {
508 504 return;
509 505 }
510 506 fp = open_exclusive(filename);
511 507 if (fp == NULL) {
512 508 if (Py_VerboseFlag)
513 509 PySys_WriteStderr(
514 510 "# can't create %s\n", filename.toLatin1().constData());
515 511 return;
516 512 }
517 513 #if PY_VERSION_HEX < 0x02040000
518 514 PyMarshal_WriteLongToFile(PyImport_GetMagicNumber(), fp);
519 515 #else
520 516 PyMarshal_WriteLongToFile(PyImport_GetMagicNumber(), fp, Py_MARSHAL_VERSION);
521 517 #endif
522 518 /* First write a 0 for mtime */
523 519 #if PY_VERSION_HEX < 0x02040000
524 520 PyMarshal_WriteLongToFile(0L, fp);
525 521 #else
526 522 PyMarshal_WriteLongToFile(0L, fp, Py_MARSHAL_VERSION);
527 523 #endif
528 524 #if PY_VERSION_HEX < 0x02040000
529 525 PyMarshal_WriteObjectToFile((PyObject *)co, fp);
530 526 #else
531 527 PyMarshal_WriteObjectToFile((PyObject *)co, fp, Py_MARSHAL_VERSION);
532 528 #endif
533 529 if (ferror(fp)) {
534 530 if (Py_VerboseFlag)
535 531 PySys_WriteStderr("# can't write %s\n", filename.toLatin1().constData());
536 532 /* Don't keep partial file */
537 533 fclose(fp);
538 534 QFile::remove(filename);
539 535 return;
540 536 }
541 537 /* Now write the true mtime */
542 538 fseek(fp, 4L, 0);
543 539 #if PY_VERSION_HEX < 0x02040000
544 540 PyMarshal_WriteLongToFile(mtime, fp);
545 541 #else
546 542 PyMarshal_WriteLongToFile(mtime, fp, Py_MARSHAL_VERSION);
547 543 #endif
548 544 fflush(fp);
549 545 fclose(fp);
550 546 if (Py_VerboseFlag)
551 547 PySys_WriteStderr("# wrote %s\n", filename.toLatin1().constData());
552 548 //#ifdef macintosh
553 549 // PyMac_setfiletype(cpathname, 'Pyth', 'PYC ');
554 550 //#endif
555 551 }
556 552
557 553 /* Given the contents of a .py[co] file in a buffer, unmarshal the data
558 554 and return the code object. Return None if it the magic word doesn't
559 555 match (we do this instead of raising an exception as we fall back
560 556 to .py if available and we don't want to mask other errors).
561 557 Returns a new reference. */
562 558 PyObject *
563 559 PythonQtImport::unmarshalCode(const QString& path, const QByteArray& data, time_t mtime)
564 560 {
565 561 PyObject *code;
566 562 // ugly cast, but Python API is not const safe
567 563 char *buf = (char*) data.constData();
568 564 int size = data.size();
569 565
570 566 if (size <= 9) {
571 567 PySys_WriteStderr("# %s has bad pyc data\n",
572 568 path.toLatin1().constData());
573 569 Py_INCREF(Py_None);
574 570 return Py_None;
575 571 }
576 572
577 573 if (getLong((unsigned char *)buf) != PyImport_GetMagicNumber()) {
578 574 if (Py_VerboseFlag)
579 575 PySys_WriteStderr("# %s has bad magic\n",
580 576 path.toLatin1().constData());
581 577 Py_INCREF(Py_None);
582 578 return Py_None;
583 579 }
584 580
585 581 if (mtime != 0) {
586 582 time_t timeDiff = getLong((unsigned char *)buf + 4) - mtime;
587 583 if (timeDiff<0) { timeDiff = -timeDiff; }
588 584 if (timeDiff > 1) {
589 585 if (Py_VerboseFlag)
590 586 PySys_WriteStderr("# %s has bad mtime\n",
591 587 path.toLatin1().constData());
592 588 Py_INCREF(Py_None);
593 589 return Py_None;
594 590 }
595 591 }
596 592
597 593 code = PyMarshal_ReadObjectFromString(buf + 8, size - 8);
598 594 if (code == NULL)
599 595 return NULL;
600 596 if (!PyCode_Check(code)) {
601 597 Py_DECREF(code);
602 598 PyErr_Format(PyExc_TypeError,
603 599 "compiled module %.200s is not a code object",
604 600 path.toLatin1().constData());
605 601 return NULL;
606 602 }
607 603 return code;
608 604 }
609 605
610 606
611 607 /* Given a string buffer containing Python source code, compile it
612 608 return and return a code object as a new reference. */
613 609 PyObject *
614 610 PythonQtImport::compileSource(const QString& path, const QByteArray& data)
615 611 {
616 612 PyObject *code;
617 613 QByteArray data1 = data;
618 614 // in qt4, data is null terminated
619 615 // data1.resize(data.size()+1);
620 616 // data1.data()[data.size()-1] = 0;
621 617 code = Py_CompileString(data.data(), path.toLatin1().constData(),
622 618 Py_file_input);
623 619 return code;
624 620 }
625 621
626 622
627 623 /* Return the code object for the module named by 'fullname' from the
628 624 Zip archive as a new reference. */
629 625 PyObject *
630 626 PythonQtImport::getCodeFromData(const QString& path, int isbytecode,int /*ispackage*/, time_t mtime)
631 627 {
632 628 PyObject *code;
633 629
634 630 QByteArray qdata;
635 631 if (!isbytecode) {
636 632 // mlabDebugConst("MLABPython", "reading source " << path);
637 633 bool ok;
638 634 qdata = PythonQt::importInterface()->readSourceFile(path, ok);
639 635 if (!ok) {
640 636 // mlabErrorConst("PythonQtImporter","File could not be verified" << path);
641 637 return NULL;
642 638 }
643 639 if (qdata == " ") {
644 640 qdata.clear();
645 641 }
646 642 } else {
647 643 qdata = PythonQt::importInterface()->readFileAsBytes(path);
648 644 }
649 645
650 646 if (isbytecode) {
651 647 // mlabDebugConst("MLABPython", "reading bytecode " << path);
652 648 code = unmarshalCode(path, qdata, mtime);
653 649 }
654 650 else {
655 651 // mlabDebugConst("MLABPython", "compiling source " << path);
656 652 code = compileSource(path, qdata);
657 653 if (code) {
658 654 // save a pyc file if possible
659 655 QDateTime time;
660 656 time = PythonQt::importInterface()->lastModifiedDate(path);
661 657 writeCompiledModule((PyCodeObject*)code, path+"c", time.toTime_t());
662 658 }
663 659 }
664 660 return code;
665 661 }
666 662
667 663 time_t
668 664 PythonQtImport::getMTimeOfSource(const QString& path)
669 665 {
670 666 time_t mtime = 0;
671 667 QString path2 = path;
672 668 path2.truncate(path.length()-1);
673 669
674 670 if (PythonQt::importInterface()->exists(path2)) {
675 671 QDateTime t = PythonQt::importInterface()->lastModifiedDate(path2);
676 672 if (t.isValid()) {
677 673 mtime = t.toTime_t();
678 674 }
679 675 }
680 676
681 677 return mtime;
682 678 }
683 679
684 680 /* Get the code object associated with the module specified by
685 681 'fullname'. */
686 682 PyObject *
687 683 PythonQtImport::getModuleCode(PythonQtImporter *self, const char* fullname, QString& modpath)
688 684 {
689 685 QString subname;
690 686 struct st_mlab_searchorder *zso;
691 687
692 688 subname = getSubName(fullname);
693 689 QString path = *self->_path + "/" + subname;
694 690
695 691 QString test;
696 692 for (zso = mlab_searchorder; *zso->suffix; zso++) {
697 693 PyObject *code = NULL;
698 694 test = path + zso->suffix;
699 695
700 696 if (Py_VerboseFlag > 1)
701 697 PySys_WriteStderr("# trying %s\n",
702 698 test.toLatin1().constData());
703 699 if (PythonQt::importInterface()->exists(test)) {
704 700 time_t mtime = 0;
705 701 int ispackage = zso->type & IS_PACKAGE;
706 702 int isbytecode = zso->type & IS_BYTECODE;
707 703
708 704 // if ignoreUpdatedPythonSourceFiles() returns true, then mtime stays 0
709 705 // and unmarshalCode() in getCodeFromData() will always read an existing *.pyc file,
710 706 // even if a newer *.py file exists. This is a release optimization where
711 707 // typically only *.pyc files are delivered without *.py files and reading file
712 708 // modification time is slow.
713 709 if (isbytecode && !PythonQt::importInterface()->ignoreUpdatedPythonSourceFiles()) {
714 710 mtime = getMTimeOfSource(test);
715 711 }
716 712 code = getCodeFromData(test, isbytecode, ispackage, mtime);
717 713 if (code == Py_None) {
718 714 Py_DECREF(code);
719 715 continue;
720 716 }
721 717 if (code != NULL) {
722 718 modpath = test;
723 719 }
724 720 return code;
725 721 }
726 722 }
727 723 PyErr_Format(PythonQtImportError, "can't find module '%.200s'", fullname);
728 724
729 725 return NULL;
730 726 }
731 727
732 728 QString PythonQtImport::replaceExtension(const QString& str, const QString& ext)
733 729 {
734 730 QString r;
735 731 int i = str.lastIndexOf('.');
736 732 if (i!=-1) {
737 733 r = str.mid(0,i) + "." + ext;
738 734 } else {
739 735 r = str + "." + ext;
740 736 }
741 737 return r;
742 738 }
743 739
744 740 PyObject* PythonQtImport::getCodeFromPyc(const QString& file)
745 741 {
746 742 PyObject* code;
747 743 const static QString pycStr("pyc");
748 744 QString pyc = replaceExtension(file, pycStr);
749 745 if (PythonQt::importInterface()->exists(pyc)) {
750 746 time_t mtime = 0;
751 747 // if ignoreUpdatedPythonSourceFiles() returns true, then mtime stays 0
752 748 // and unmarshalCode() in getCodeFromData() will always read an existing *.pyc file,
753 749 // even if a newer *.py file exists. This is a release optimization where
754 750 // typically only *.pyc files are delivered without *.py files and reading file
755 751 // modification time is slow.
756 752 if (!PythonQt::importInterface()->ignoreUpdatedPythonSourceFiles()) {
757 753 mtime = getMTimeOfSource(pyc);
758 754 }
759 755 code = getCodeFromData(pyc, true, false, mtime);
760 756 if (code != Py_None && code != NULL) {
761 757 return code;
762 758 }
763 759 if (code) {
764 760 Py_DECREF(code);
765 761 }
766 762 }
767 763 code = getCodeFromData(file,false,false,0);
768 764 return code;
769 765 }
770 766
771 767 /* Module init */
772 768
773 769 PyDoc_STRVAR(mlabimport_doc,
774 770 "Imports python files into PythonQt, completely replaces internal python import");
775 771
776 772 #ifdef PY3K
777 773 static struct PyModuleDef PythonQtImport_def = {
778 774 PyModuleDef_HEAD_INIT,
779 775 "PythonQtImport", /* m_name */
780 776 mlabimport_doc, /* m_doc */
781 777 -1, /* m_size */
782 778 NULL, /* m_methods */
783 779 NULL, /* m_reload */
784 780 NULL, /* m_traverse */
785 781 NULL, /* m_clear */
786 782 NULL /* m_free */
787 783 };
788 784 #endif
789 785
790 786 void PythonQtImport::init()
791 787 {
792 788 static bool first = true;
793 789 if (!first) {
794 790 return;
795 791 }
796 792 first = false;
797 793
798 794 PyObject *mod;
799 795
800 796 if (PyType_Ready(&PythonQtImporter_Type) < 0)
801 797 return;
802 798
803 799 /* Correct directory separator */
804 800 mlab_searchorder[0].suffix[0] = SEP;
805 801 mlab_searchorder[1].suffix[0] = SEP;
806 802 mlab_searchorder[2].suffix[0] = SEP;
807 803 if (Py_OptimizeFlag) {
808 804 /* Reverse *.pyc and *.pyo */
809 805 struct st_mlab_searchorder tmp;
810 806 tmp = mlab_searchorder[0];
811 807 mlab_searchorder[0] = mlab_searchorder[1];
812 808 mlab_searchorder[1] = tmp;
813 809 tmp = mlab_searchorder[3];
814 810 mlab_searchorder[3] = mlab_searchorder[4];
815 811 mlab_searchorder[4] = tmp;
816 812 }
817 813
818 814 #ifdef PY3K
819 815 mod = PyModule_Create(&PythonQtImport_def);
820 816 #else
821 817 mod = Py_InitModule4("PythonQtImport", NULL, mlabimport_doc,
822 818 NULL, PYTHON_API_VERSION);
823 819 #endif
824 820
825 821 PythonQtImportError = PyErr_NewException(const_cast<char*>("PythonQtImport.PythonQtImportError"),
826 822 PyExc_ImportError, NULL);
827 823 if (PythonQtImportError == NULL)
828 824 return;
829 825
830 826 Py_INCREF(PythonQtImportError);
831 827 if (PyModule_AddObject(mod, "PythonQtImportError",
832 828 PythonQtImportError) < 0)
833 829 return;
834 830
835 831 Py_INCREF(&PythonQtImporter_Type);
836 832 if (PyModule_AddObject(mod, "PythonQtImporter",
837 833 (PyObject *)&PythonQtImporter_Type) < 0)
838 834 return;
839 835
840 836 // set our importer into the path_hooks to handle all path on sys.path
841 837 PyObject* classobj = PyDict_GetItemString(PyModule_GetDict(mod), "PythonQtImporter");
842 838 PyObject* path_hooks = PySys_GetObject(const_cast<char*>("path_hooks"));
843 839 PyList_Append(path_hooks, classobj);
844 840
845 841 #ifndef WIN32
846 842 // reload the encodings module, because it might fail to custom import requirements (e.g. encryption).
847 843 PyObject* modules = PyImport_GetModuleDict();
848 844 PyObject* encodingsModule = PyDict_GetItemString(modules, "encodings");
849 845 if (encodingsModule != NULL) {
850 846 PyImport_ReloadModule(encodingsModule);
851 847 }
852 848 #endif
853 849 }
@@ -1,848 +1,844
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 PythonQtInstanceWrapper.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 "PythonQtInstanceWrapper.h"
43 43 #include <QObject>
44 44 #include "PythonQt.h"
45 45 #include "PythonQtSlot.h"
46 46 #include "PythonQtSignal.h"
47 47 #include "PythonQtClassInfo.h"
48 48 #include "PythonQtConversion.h"
49 49 #include "PythonQtClassWrapper.h"
50 50
51 #if PY_MAJOR_VERSION >= 3
52 #define PY3K
53 #endif
54
55 51 PythonQtClassInfo* PythonQtInstanceWrapperStruct::classInfo()
56 52 {
57 53 // take the class info from our type object
58 54 return ((PythonQtClassWrapper*)Py_TYPE(this))->_classInfo;
59 55 }
60 56
61 57 static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, bool force = false) {
62 58
63 59 // is this a C++ wrapper?
64 60 if (self->_wrappedPtr) {
65 61 //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
66 62
67 63 PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr);
68 64 // we own our qobject, so we delete it now:
69 65 delete self->_obj;
70 66 self->_obj = NULL;
71 67 if (force || self->_ownedByPythonQt) {
72 68 int type = self->classInfo()->metaTypeId();
73 69 if (self->_useQMetaTypeDestroy && type>=0) {
74 70 // use QMetaType to destroy the object
75 71 QMetaType::destroy(type, self->_wrappedPtr);
76 72 } else {
77 73 PythonQtSlotInfo* slot = self->classInfo()->destructor();
78 74 if (slot) {
79 75 void* args[2];
80 76 args[0] = NULL;
81 77 args[1] = &self->_wrappedPtr;
82 78 slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, slot->slotIndex(), args);
83 79 self->_wrappedPtr = NULL;
84 80 } else {
85 81 if (type>=0) {
86 82 // use QMetaType to destroy the object
87 83 QMetaType::destroy(type, self->_wrappedPtr);
88 84 } else {
89 85 // TODO: warn about not being able to destroy the object?
90 86 }
91 87 }
92 88 }
93 89 }
94 90 } else {
95 91 //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
96 92 if (self->_objPointerCopy) {
97 93 PythonQt::priv()->removeWrapperPointer(self->_objPointerCopy);
98 94 }
99 95 if (self->_obj) {
100 96 if (force || self->_ownedByPythonQt) {
101 97 if (force || !self->_obj->parent()) {
102 98 delete self->_obj;
103 99 }
104 100 } else {
105 101 if (self->_obj->parent()==NULL) {
106 102 // tell someone who is interested that the qobject is no longer wrapped, if it has no parent
107 103 PythonQt::qObjectNoLongerWrappedCB(self->_obj);
108 104 }
109 105 }
110 106 }
111 107 }
112 108 self->_obj = NULL;
113 109 }
114 110
115 111 static void PythonQtInstanceWrapper_dealloc(PythonQtInstanceWrapper* self)
116 112 {
117 113 PythonQtInstanceWrapper_deleteObject(self);
118 114 self->_obj.~QPointer<QObject>();
119 115 Py_TYPE(self)->tp_free((PyObject*)self);
120 116 }
121 117
122 118 static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
123 119 {
124 120 //PythonQtClassWrapper *classType = (PythonQtClassWrapper*)type;
125 121 PythonQtInstanceWrapper *self;
126 122 static PyObject* emptyTuple = NULL;
127 123 if (emptyTuple==NULL) {
128 124 emptyTuple = PyTuple_New(0);
129 125 }
130 126
131 127 self = (PythonQtInstanceWrapper*)PyBaseObject_Type.tp_new(type, emptyTuple, NULL);
132 128
133 129 if (self != NULL) {
134 130 new (&self->_obj) QPointer<QObject>();
135 131 self->_wrappedPtr = NULL;
136 132 self->_ownedByPythonQt = false;
137 133 self->_useQMetaTypeDestroy = false;
138 134 self->_isShellInstance = false;
139 135 }
140 136 return (PyObject *)self;
141 137 }
142 138
143 139 int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds)
144 140 {
145 141 if (args == PythonQtPrivate::dummyTuple()) {
146 142 // we are called from the internal PythonQt API, so our data will be filled later on...
147 143 return 0;
148 144 }
149 145
150 146 // we are called from python, try to construct our object
151 147 if (self->classInfo()->constructors()) {
152 148 void* directCPPPointer = NULL;
153 149 PythonQtSlotFunction_CallImpl(self->classInfo(), NULL, self->classInfo()->constructors(), args, kwds, NULL, &directCPPPointer);
154 150 if (PyErr_Occurred()) {
155 151 return -1;
156 152 }
157 153 if (directCPPPointer) {
158 154 // change ownershipflag to be owned by PythonQt
159 155 self->_ownedByPythonQt = true;
160 156 self->_useQMetaTypeDestroy = false;
161 157 if (self->classInfo()->isCPPWrapper()) {
162 158 self->_wrappedPtr = directCPPPointer;
163 159 // TODO xxx: if there is a wrapper factory, we might want to generate a wrapper for our class?!
164 160 } else {
165 161 self->setQObject((QObject*)directCPPPointer);
166 162 }
167 163 // register with PythonQt
168 164 PythonQt::priv()->addWrapperPointer(directCPPPointer, self);
169 165
170 166 PythonQtShellSetInstanceWrapperCB* cb = self->classInfo()->shellSetInstanceWrapperCB();
171 167 if (cb) {
172 168 // if we are a derived python class, we set the wrapper
173 169 // to activate the shell class, otherwise we just ignore that it is a shell...
174 170 // we detect it be checking if the type does not have PythonQtInstanceWrapper_Type as direct base class,
175 171 // which is the case for all non-python derived types
176 172 if (((PyObject*)self)->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
177 173 // set the wrapper and remember that we have a shell instance!
178 174 (*cb)(directCPPPointer, self);
179 175 self->_isShellInstance = true;
180 176 }
181 177 }
182 178 }
183 179 } else {
184 180 QString error = QString("No constructors available for ") + self->classInfo()->className();
185 181 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
186 182 return -1;
187 183 }
188 184 return 0;
189 185 }
190 186
191 187 static PyObject *PythonQtInstanceWrapper_richcompare(PythonQtInstanceWrapper* wrapper, PyObject* other, int code)
192 188 {
193 189 bool validPtrs = false;
194 190 bool areSamePtrs = false;
195 191 if (PyObject_TypeCheck((PyObject*)wrapper, &PythonQtInstanceWrapper_Type)) {
196 192 if (PyObject_TypeCheck(other, &PythonQtInstanceWrapper_Type)) {
197 193 validPtrs = true;
198 194 PythonQtInstanceWrapper* w1 = wrapper;
199 195 PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)other;
200 196 // check pointers directly
201 197 if (w1->_wrappedPtr != NULL) {
202 198 if (w1->_wrappedPtr == w2->_wrappedPtr) {
203 199 areSamePtrs = true;
204 200 }
205 201 } else if (w1->_obj == w2->_obj) {
206 202 areSamePtrs = true;
207 203 }
208 204 } else if (other == Py_None) {
209 205 validPtrs = true;
210 206 if (wrapper->_obj || wrapper->_wrappedPtr) {
211 207 areSamePtrs = false;
212 208 } else {
213 209 areSamePtrs = true;
214 210 }
215 211 }
216 212 }
217 213
218 214 if ((wrapper->classInfo()->typeSlots() & PythonQt::Type_RichCompare) == 0) {
219 215 // shortcut if richcompare is not supported:
220 216 if (validPtrs && code == Py_EQ) {
221 217 return PythonQtConv::GetPyBool(areSamePtrs);
222 218 } else if (validPtrs && code == Py_NE) {
223 219 return PythonQtConv::GetPyBool(!areSamePtrs);
224 220 }
225 221 Py_INCREF(Py_NotImplemented);
226 222 return Py_NotImplemented;
227 223 }
228 224
229 225 QByteArray memberName;
230 226 switch (code) {
231 227 case Py_LT:
232 228 {
233 229 static QByteArray name = "__lt__";
234 230 memberName = name;
235 231 }
236 232 break;
237 233
238 234 case Py_LE:
239 235 {
240 236 static QByteArray name = "__le__";
241 237 memberName = name;
242 238 }
243 239 break;
244 240
245 241 case Py_EQ:
246 242 {
247 243 static QByteArray name = "__eq__";
248 244 memberName = name;
249 245 }
250 246 break;
251 247
252 248 case Py_NE:
253 249 {
254 250 static QByteArray name = "__ne__";
255 251 memberName = name;
256 252 }
257 253 break;
258 254
259 255 case Py_GT:
260 256 {
261 257 static QByteArray name = "__gt__";
262 258 memberName = name;
263 259 }
264 260 break;
265 261
266 262 case Py_GE:
267 263 {
268 264 static QByteArray name = "__ge__";
269 265 memberName = name;
270 266 }
271 267 break;
272 268 }
273 269
274 270 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
275 271 if (opSlot._type == PythonQtMemberInfo::Slot) {
276 272 // TODO get rid of tuple
277 273 PyObject* args = PyTuple_New(1);
278 274 Py_INCREF(other);
279 275 PyTuple_SET_ITEM(args, 0, other);
280 276 PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr);
281 277 Py_DECREF(args);
282 278 return result;
283 279 } else {
284 280 // not implemented, let python try something else!
285 281 Py_INCREF(Py_NotImplemented);
286 282 return Py_NotImplemented;
287 283 }
288 284 }
289 285
290 286
291 287 static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* obj)
292 288 {
293 289 #ifdef PY3K
294 290 return PyUnicode_FromString(Py_TYPE(obj)->tp_name);
295 291 #else
296 292 return PyString_FromString(Py_TYPE(obj)->tp_name);
297 293 #endif
298 294 }
299 295
300 296 PyObject *PythonQtInstanceWrapper_inherits(PythonQtInstanceWrapper* obj, PyObject *args)
301 297 {
302 298 char *name = NULL;
303 299 if (!PyArg_ParseTuple(args, "s:PythonQtInstanceWrapper.inherits",&name)) {
304 300 return NULL;
305 301 }
306 302 return PythonQtConv::GetPyBool(obj->classInfo()->inherits(name));
307 303 }
308 304
309 305 static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* obj)
310 306 {
311 307 return PythonQt::self()->helpCalled(obj->classInfo());
312 308 }
313 309
314 310 PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self)
315 311 {
316 312 PythonQtInstanceWrapper_deleteObject(self, true);
317 313 Py_INCREF(Py_None);
318 314 return Py_None;
319 315 }
320 316
321 317
322 318 static PyMethodDef PythonQtInstanceWrapper_methods[] = {
323 319 {"className", (PyCFunction)PythonQtInstanceWrapper_classname, METH_NOARGS,
324 320 "Return the classname of the object"
325 321 },
326 322 {"inherits", (PyCFunction)PythonQtInstanceWrapper_inherits, METH_VARARGS,
327 323 "Returns if the class inherits or is of given type name"
328 324 },
329 325 {"help", (PyCFunction)PythonQtInstanceWrapper_help, METH_NOARGS,
330 326 "Shows the help of available methods for this class"
331 327 },
332 328 {"delete", (PyCFunction)PythonQtInstanceWrapper_delete, METH_NOARGS,
333 329 "Deletes the C++ object (at your own risk, my friend!)"
334 330 },
335 331 {NULL, NULL, 0, NULL} /* Sentinel */
336 332 };
337 333
338 334
339 335 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
340 336 {
341 337 const char *attributeName;
342 338 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
343 339
344 340 #ifdef PY3K
345 341 if ((attributeName = PyUnicode_AsUTF8(name)) == NULL) {
346 342 #else
347 343 if ((attributeName = PyString_AsString(name)) == NULL) {
348 344 #endif
349 345 return NULL;
350 346 }
351 347
352 348 if (qstrcmp(attributeName, "__dict__")==0) {
353 349 PyObject* dict = PyBaseObject_Type.tp_getattro(obj, name);
354 350 dict = PyDict_Copy(dict);
355 351
356 352 if (wrapper->_obj) {
357 353 // only the properties are missing, the rest is already available from
358 354 // PythonQtClassWrapper...
359 355 QStringList l = wrapper->classInfo()->propertyList();
360 356 Q_FOREACH (QString name, l) {
361 357 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
362 358 if (o) {
363 359 PyDict_SetItemString(dict, name.toLatin1().data(), o);
364 360 Py_DECREF(o);
365 361 } else {
366 362 std::cerr << "PythonQtInstanceWrapper: something is wrong, could not get attribute " << name.toLatin1().data();
367 363 }
368 364 }
369 365
370 366 QList<QByteArray> dynamicProps = wrapper->_obj->dynamicPropertyNames();
371 367 Q_FOREACH (QByteArray name, dynamicProps) {
372 368 PyObject* o = PyObject_GetAttrString(obj, name.data());
373 369 if (o) {
374 370 PyDict_SetItemString(dict, name.data(), o);
375 371 Py_DECREF(o);
376 372 } else {
377 373 std::cerr << "PythonQtInstanceWrapper: dynamic property could not be read " << name.data();
378 374 }
379 375 }
380 376 }
381 377 // Note: we do not put children into the dict, is would look confusing?!
382 378 return dict;
383 379 }
384 380
385 381 // first look in super, to return derived methods from base object first
386 382 PyObject* superAttr = PyBaseObject_Type.tp_getattro(obj, name);
387 383 if (superAttr) {
388 384 return superAttr;
389 385 }
390 386 PyErr_Clear();
391 387
392 388 // mlabDebugConst("Python","get " << attributeName);
393 389
394 390 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
395 391 switch (member._type) {
396 392 case PythonQtMemberInfo::Property:
397 393 if (wrapper->_obj) {
398 394 if (member._property.userType() != QVariant::Invalid) {
399 395
400 396 PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB();
401 397 if (profilingCB) {
402 398 QString methodName = "getProperty(";
403 399 methodName += attributeName;
404 400 methodName += ")";
405 401 profilingCB(PythonQt::Enter, wrapper->_obj->metaObject()->className(), methodName.toLatin1());
406 402 }
407 403
408 404 PyObject* value = PythonQtConv::QVariantToPyObject(member._property.read(wrapper->_obj));
409 405
410 406 if (profilingCB) {
411 407 profilingCB(PythonQt::Leave, NULL, NULL);
412 408 }
413 409
414 410 return value;
415 411
416 412 } else {
417 413 Py_INCREF(Py_None);
418 414 return Py_None;
419 415 }
420 416 } else {
421 417 QString error = QString("Trying to read property '") + attributeName + "' from a destroyed " + wrapper->classInfo()->className() + " object";
422 418 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
423 419 return NULL;
424 420 }
425 421 break;
426 422 case PythonQtMemberInfo::Slot:
427 423 return PythonQtSlotFunction_New(member._slot, obj, NULL);
428 424 break;
429 425 case PythonQtMemberInfo::Signal:
430 426 return PythonQtSignalFunction_New(member._slot, obj, NULL);
431 427 break;
432 428 case PythonQtMemberInfo::EnumValue:
433 429 {
434 430 PyObject* enumValue = member._enumValue;
435 431 Py_INCREF(enumValue);
436 432 return enumValue;
437 433 }
438 434 break;
439 435 case PythonQtMemberInfo::EnumWrapper:
440 436 {
441 437 PyObject* enumWrapper = member._enumWrapper;
442 438 Py_INCREF(enumWrapper);
443 439 return enumWrapper;
444 440 }
445 441 break;
446 442 case PythonQtMemberInfo::NotFound:
447 443 {
448 444 static const QByteArray getterString("py_get_");
449 445 // check for a getter slot
450 446 PythonQtMemberInfo member = wrapper->classInfo()->member(getterString + attributeName);
451 447 if (member._type == PythonQtMemberInfo::Slot) {
452 448 return PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, member._slot, NULL, NULL, wrapper->_wrappedPtr);
453 449 }
454 450
455 451 // handle dynamic properties
456 452 if (wrapper->_obj) {
457 453 QVariant v = wrapper->_obj->property(attributeName);
458 454 if (v.isValid()) {
459 455 return PythonQtConv::QVariantToPyObject(v);
460 456 }
461 457 }
462 458 }
463 459 break;
464 460 default:
465 461 // is an invalid type, go on
466 462 break;
467 463 }
468 464
469 465 // look for the internal methods (className(), help())
470 466 #ifdef PY3K
471 467 PyObject* internalMethod = PyObject_GenericGetAttr(obj, name);
472 468 #else
473 469 PyObject* internalMethod = Py_FindMethod( PythonQtInstanceWrapper_methods, obj, (char*)attributeName);
474 470 #endif
475 471 if (internalMethod) {
476 472 return internalMethod;
477 473 }
478 474 PyErr_Clear();
479 475
480 476 if (wrapper->_obj) {
481 477 // look for a child
482 478 QObjectList children = wrapper->_obj->children();
483 479 for (int i = 0; i < children.count(); i++) {
484 480 QObject *child = children.at(i);
485 481 if (child->objectName() == attributeName) {
486 482 return PythonQt::priv()->wrapQObject(child);
487 483 }
488 484 }
489 485 }
490 486
491 487 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
492 488 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
493 489 return NULL;
494 490 }
495 491
496 492 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
497 493 {
498 494 QString error;
499 495 const char *attributeName;
500 496 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
501 497
502 498 #ifdef PY3K
503 499 if ((attributeName = PyUnicode_AsUTF8(name)) == NULL)
504 500 #else
505 501 if ((attributeName = PyString_AsString(name)) == NULL)
506 502 #endif
507 503 return -1;
508 504
509 505 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
510 506 if (member._type == PythonQtMemberInfo::Property) {
511 507
512 508 if (!wrapper->_obj) {
513 509 error = QString("Trying to set property '") + attributeName + "' on a destroyed " + wrapper->classInfo()->className() + " object";
514 510 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
515 511 return -1;
516 512 }
517 513
518 514 QMetaProperty prop = member._property;
519 515 if (prop.isWritable()) {
520 516 QVariant v;
521 517 if (prop.isEnumType()) {
522 518 // this will give us either a string or an int, everything else will probably be an error
523 519 v = PythonQtConv::PyObjToQVariant(value);
524 520 } else {
525 521 int t = prop.userType();
526 522 v = PythonQtConv::PyObjToQVariant(value, t);
527 523 }
528 524 bool success = false;
529 525 if (v.isValid()) {
530 526 PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB();
531 527 if (profilingCB) {
532 528 QString methodName = "setProperty(";
533 529 methodName += attributeName;
534 530 methodName += ")";
535 531 profilingCB(PythonQt::Enter, wrapper->_obj->metaObject()->className(), methodName.toLatin1());
536 532 }
537 533
538 534 success = prop.write(wrapper->_obj, v);
539 535
540 536 if (profilingCB) {
541 537 profilingCB(PythonQt::Leave, NULL, NULL);
542 538 }
543 539 }
544 540 if (success) {
545 541 return 0;
546 542 } else {
547 543 error = QString("Property '") + attributeName + "' of type '" +
548 544 prop.typeName() + "' does not accept an object of type "
549 545 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
550 546 }
551 547 } else {
552 548 error = QString("Property '") + attributeName + "' of " + obj->ob_type->tp_name + " object is not writable";
553 549 }
554 550 } else if (member._type == PythonQtMemberInfo::Slot) {
555 551 error = QString("Slot '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
556 552 } else if (member._type == PythonQtMemberInfo::Signal) {
557 553 error = QString("Signal '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
558 554 } else if (member._type == PythonQtMemberInfo::EnumValue) {
559 555 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
560 556 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
561 557 error = QString("Enum '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
562 558 } else if (member._type == PythonQtMemberInfo::NotFound) {
563 559 // check for a setter slot
564 560 static const QByteArray setterString("py_set_");
565 561 PythonQtMemberInfo setter = wrapper->classInfo()->member(setterString + attributeName);
566 562 if (setter._type == PythonQtMemberInfo::Slot) {
567 563 // call the setter and ignore the result value
568 564 void* result;
569 565 PyObject* args = PyTuple_New(1);
570 566 Py_INCREF(value);
571 567 PyTuple_SET_ITEM(args, 0, value);
572 568 PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, setter._slot, args, NULL, wrapper->_wrappedPtr, &result);
573 569 Py_DECREF(args);
574 570 return 0;
575 571 }
576 572
577 573 // handle dynamic properties
578 574 if (wrapper->_obj) {
579 575 QVariant prop = wrapper->_obj->property(attributeName);
580 576 if (prop.isValid()) {
581 577 QVariant v = PythonQtConv::PyObjToQVariant(value);
582 578 if (v.isValid()) {
583 579 wrapper->_obj->setProperty(attributeName, v);
584 580 return 0;
585 581 } else {
586 582 error = QString("Dynamic property '") + attributeName + "' does not accept an object of type "
587 583 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
588 584 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
589 585 return -1;
590 586 }
591 587 }
592 588 }
593 589
594 590 // if we are a derived python class, we allow setting attributes.
595 591 // if we are a direct CPP wrapper, we do NOT allow it, since
596 592 // it would be confusing to allow it because a wrapper will go away when it is not seen by python anymore
597 593 // and when it is recreated from a CPP pointer the attributes are gone...
598 594 if (obj->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
599 595 return PyBaseObject_Type.tp_setattro(obj,name,value);
600 596 } else {
601 597 error = QString("'") + attributeName + "' does not exist on " + obj->ob_type->tp_name + " and creating new attributes on C++ objects is not allowed";
602 598 }
603 599 }
604 600
605 601 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
606 602 return -1;
607 603 }
608 604
609 605 static QString getStringFromObject(PythonQtInstanceWrapper* wrapper) {
610 606 QString result;
611 607 if (wrapper->_wrappedPtr) {
612 608 // first try some manually string conversions for some variants
613 609 int metaid = wrapper->classInfo()->metaTypeId();
614 610 result = PythonQtConv::CPPObjectToString(metaid, wrapper->_wrappedPtr);
615 611 if (!result.isEmpty()) {
616 612 return result;
617 613 }
618 614 }
619 615 if (wrapper->_wrappedPtr || wrapper->_obj) {
620 616 // next, try to call py_toString
621 617 PythonQtMemberInfo info = wrapper->classInfo()->member("py_toString");
622 618 if (info._type == PythonQtMemberInfo::Slot) {
623 619 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, NULL, NULL, wrapper->_wrappedPtr);
624 620 if (resultObj) {
625 621 // TODO this is one conversion too much, would be nicer to call the slot directly...
626 622 result = PythonQtConv::PyObjGetString(resultObj);
627 623 Py_DECREF(resultObj);
628 624 }
629 625 }
630 626 }
631 627 return result;
632 628 }
633 629
634 630 static PyObject * PythonQtInstanceWrapper_str(PyObject * obj)
635 631 {
636 632 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
637 633
638 634 // QByteArray should be directly returned as a str
639 635 if (wrapper->classInfo()->metaTypeId()==QVariant::ByteArray) {
640 636 QByteArray* b = (QByteArray*) wrapper->_wrappedPtr;
641 637 if (b->data()) {
642 638 #ifdef PY3K
643 639 return PyUnicode_FromStringAndSize(b->data(), b->size());
644 640 #else
645 641 return PyString_FromStringAndSize(b->data(), b->size());
646 642 #endif
647 643 } else {
648 644 #ifdef PY3K
649 645 return PyUnicode_New(0, 0);
650 646 #else
651 647 return PyString_FromString("");
652 648 #endif
653 649 }
654 650 }
655 651
656 652 const char* typeName = obj->ob_type->tp_name;
657 653 QObject *qobj = wrapper->_obj;
658 654 QString str = getStringFromObject(wrapper);
659 655 if (!str.isEmpty()) {
660 656 #ifdef PY3K
661 657 return PyUnicode_FromFormat("%s", str.toLatin1().constData());
662 658 #else
663 659 return PyString_FromFormat("%s", str.toLatin1().constData());
664 660 #endif
665 661 }
666 662 if (wrapper->_wrappedPtr) {
667 663 if (wrapper->_obj) {
668 664 #ifdef PY3K
669 665 return PyUnicode_FromFormat("%s (C++ Object %p wrapped by %s %p)", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
670 666 #else
671 667 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p)", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
672 668 #endif
673 669 } else {
674 670 #ifdef PY3K
675 671 return PyUnicode_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
676 672 #else
677 673 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
678 674 #endif
679 675 }
680 676 } else {
681 677 #ifdef PY3K
682 678 return PyUnicode_FromFormat("%s (QObject %p)", typeName, qobj);
683 679 #else
684 680 return PyString_FromFormat("%s (QObject %p)", typeName, qobj);
685 681 #endif
686 682 }
687 683 }
688 684
689 685 static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj)
690 686 {
691 687 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
692 688 const char* typeName = obj->ob_type->tp_name;
693 689
694 690 QObject *qobj = wrapper->_obj;
695 691 QString str = getStringFromObject(wrapper);
696 692 if (!str.isEmpty()) {
697 693 if (str.startsWith(typeName)) {
698 694 #ifdef PY3K
699 695 return PyUnicode_FromFormat("%s", str.toLatin1().constData());
700 696 #else
701 697 return PyString_FromFormat("%s", str.toLatin1().constData());
702 698 #endif
703 699 } else {
704 700 #ifdef PY3K
705 701 return PyUnicode_FromFormat("%s (%s, at: %p)", typeName, str.toLatin1().constData(), wrapper->_wrappedPtr ? wrapper->_wrappedPtr : qobj);
706 702 #else
707 703 return PyString_FromFormat("%s (%s, at: %p)", typeName, str.toLatin1().constData(), wrapper->_wrappedPtr ? wrapper->_wrappedPtr : qobj);
708 704 #endif
709 705 }
710 706 }
711 707 if (wrapper->_wrappedPtr) {
712 708 if (wrapper->_obj) {
713 709 #ifdef PY3K
714 710 return PyUnicode_FromFormat("%s (C++ object at: %p wrapped by %s at: %p)", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
715 711 #else
716 712 return PyString_FromFormat("%s (C++ object at: %p wrapped by %s at: %p)", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
717 713 #endif
718 714 } else {
719 715 #ifdef PY3K
720 716 return PyUnicode_FromFormat("%s (C++ object at: %p)", typeName, wrapper->_wrappedPtr);
721 717 #else
722 718 return PyString_FromFormat("%s (C++ object at: %p)", typeName, wrapper->_wrappedPtr);
723 719 #endif
724 720 }
725 721 } else {
726 722 #ifdef PY3K
727 723 return PyUnicode_FromFormat("%s (%s at: %p)", typeName, wrapper->classInfo()->className(), qobj);
728 724 #else
729 725 return PyString_FromFormat("%s (%s at: %p)", typeName, wrapper->classInfo()->className(), qobj);
730 726 #endif
731 727 }
732 728 }
733 729
734 730 static int PythonQtInstanceWrapper_builtin_nonzero(PyObject *obj)
735 731 {
736 732 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
737 733 return (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
738 734 }
739 735
740 736
741 737 static long PythonQtInstanceWrapper_hash(PythonQtInstanceWrapper *obj)
742 738 {
743 739 if (obj->_wrappedPtr != NULL) {
744 740 return reinterpret_cast<long>(obj->_wrappedPtr);
745 741 } else {
746 742 QObject* qobj = obj->_obj; // get pointer from QPointer wrapper
747 743 return reinterpret_cast<long>(qobj);
748 744 }
749 745 }
750 746
751 747
752 748
753 749 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
754 750 static PyNumberMethods PythonQtInstanceWrapper_as_number = {
755 751 0, /* nb_add */
756 752 0, /* nb_subtract */
757 753 0, /* nb_multiply */
758 754 #ifndef PY3K
759 755 0, /* nb_divide */
760 756 #endif
761 757 0, /* nb_remainder */
762 758 0, /* nb_divmod */
763 759 0, /* nb_power */
764 760 0, /* nb_negative */
765 761 0, /* nb_positive */
766 762 0, /* nb_absolute */
767 763 PythonQtInstanceWrapper_builtin_nonzero, /* nb_nonzero / nb_bool in Py3K */
768 764 0, /* nb_invert */
769 765 0, /* nb_lshift */
770 766 0, /* nb_rshift */
771 767 0, /* nb_and */
772 768 0, /* nb_xor */
773 769 0, /* nb_or */
774 770 #ifndef PY3K
775 771 0, /* nb_coerce */
776 772 #endif
777 773 0, /* nb_int */
778 774 0, /* nb_long / nb_reserved in Py3K */
779 775 0, /* nb_float */
780 776 #ifndef PY3K
781 777 0, /* nb_oct */
782 778 0, /* nb_hex */
783 779 #endif
784 780 0, /* nb_inplace_add */
785 781 0, /* nb_inplace_subtract */
786 782 0, /* nb_inplace_multiply */
787 783 #ifndef PY3K
788 784 0, /* nb_inplace_divide */
789 785 #endif
790 786 0, /* nb_inplace_remainder */
791 787 0, /* nb_inplace_power */
792 788 0, /* nb_inplace_lshift */
793 789 0, /* nb_inplace_rshift */
794 790 0, /* nb_inplace_and */
795 791 0, /* nb_inplace_xor */
796 792 0, /* nb_inplace_or */
797 793 0, /* nb_floor_divide */
798 794 0, /* nb_true_divide */
799 795 0, /* nb_inplace_floor_divide */
800 796 0, /* nb_inplace_true_divide */
801 797 #ifdef PY3K
802 798 0, /* nb_index in Py3K */
803 799 #endif
804 800 };
805 801
806 802 PyTypeObject PythonQtInstanceWrapper_Type = {
807 803 PyVarObject_HEAD_INIT(&PythonQtClassWrapper_Type, 0)
808 804 "PythonQt.PythonQtInstanceWrapper", /*tp_name*/
809 805 sizeof(PythonQtInstanceWrapper), /*tp_basicsize*/
810 806 0, /*tp_itemsize*/
811 807 (destructor)PythonQtInstanceWrapper_dealloc, /*tp_dealloc*/
812 808 0, /*tp_print*/
813 809 0, /*tp_getattr*/
814 810 0, /*tp_setattr*/
815 811 0, /*tp_compare*/
816 812 PythonQtInstanceWrapper_repr, /*tp_repr*/
817 813 &PythonQtInstanceWrapper_as_number, /*tp_as_number*/
818 814 0, /*tp_as_sequence*/
819 815 0, /*tp_as_mapping*/
820 816 (hashfunc)PythonQtInstanceWrapper_hash, /*tp_hash */
821 817 0, /*tp_call*/
822 818 PythonQtInstanceWrapper_str, /*tp_str*/
823 819 PythonQtInstanceWrapper_getattro, /*tp_getattro*/
824 820 PythonQtInstanceWrapper_setattro, /*tp_setattro*/
825 821 0, /*tp_as_buffer*/
826 822 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE /*| Py_TPFLAGS_CHECKTYPES FIXME Py_TPFLAGS_CHECKTYPES removal */, /*tp_flags*/
827 823 "PythonQtInstanceWrapper object", /* tp_doc */
828 824 0, /* tp_traverse */
829 825 0, /* tp_clear */
830 826 (richcmpfunc)PythonQtInstanceWrapper_richcompare, /* tp_richcompare */
831 827 0, /* tp_weaklistoffset */
832 828 0, /* tp_iter */
833 829 0, /* tp_iternext */
834 0, /* tp_methods */
830 PythonQtInstanceWrapper_methods, /* tp_methods */
835 831 0, /* tp_members */
836 832 0, /* tp_getset */
837 833 0, /* tp_base */
838 834 0, /* tp_dict */
839 835 0, /* tp_descr_get */
840 836 0, /* tp_descr_set */
841 837 0, /* tp_dictoffset */
842 838 (initproc)PythonQtInstanceWrapper_init, /* tp_init */
843 839 0, /* tp_alloc */
844 840 PythonQtInstanceWrapper_new, /* tp_new */
845 841 };
846 842
847 843 //-------------------------------------------------------
848 844
@@ -1,735 +1,731
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 PythonQtSlot.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtSlot.h"
44 44 #include "PythonQtInstanceWrapper.h"
45 45 #include "PythonQtClassInfo.h"
46 46 #include "PythonQtMisc.h"
47 47 #include "PythonQtConversion.h"
48 48 #include <iostream>
49 49
50 50 #include <exception>
51 51 #include <stdexcept>
52 52
53 53 #include <QByteArray>
54 54
55 #if PY_MAJOR_VERSION >= 3
56 #define PY3K
57 #endif
58
59 55 #define PYTHONQT_MAX_ARGS 32
60 56
61 57
62 58 bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer)
63 59 {
64 60 static unsigned int recursiveEntry = 0;
65 61
66 62 if (directReturnValuePointer) {
67 63 *directReturnValuePointer = NULL;
68 64 }
69 65 // store the current storage position, so that we can get back to this state after a slot is called
70 66 // (do this locally, so that we have all positions on the stack
71 67 PythonQtValueStoragePosition globalValueStoragePos;
72 68 PythonQtValueStoragePosition globalPtrStoragePos;
73 69 PythonQtValueStoragePosition globalVariantStoragePos;
74 70 PythonQtConv::global_valueStorage.getPos(globalValueStoragePos);
75 71 PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos);
76 72 PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos);
77 73
78 74 recursiveEntry++;
79 75
80 76 // the arguments that are passed to qt_metacall
81 77 void* argList[PYTHONQT_MAX_ARGS];
82 78 PyObject* result = NULL;
83 79 int argc = info->parameterCount();
84 80 const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters();
85 81
86 82 const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);
87 83 // set return argument to NULL
88 84 argList[0] = NULL;
89 85
90 86 bool ok = true;
91 87 bool skipFirst = false;
92 88 if (info->isInstanceDecorator()) {
93 89 skipFirst = true;
94 90
95 91 // for decorators on CPP objects, we take the cpp ptr, for QObjects we take the QObject pointer
96 92 void* arg1 = firstArgument;
97 93 if (!arg1) {
98 94 arg1 = objectToCall;
99 95 }
100 96 if (arg1) {
101 97 // upcast to correct parent class
102 98 arg1 = ((char*)arg1)+info->upcastingOffset();
103 99 }
104 100
105 101 argList[1] = &arg1;
106 102 if (ok) {
107 103 for (int i = 2; i<argc && ok; i++) {
108 104 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
109 105 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, classInfo);
110 106 if (argList[i]==NULL) {
111 107 ok = false;
112 108 break;
113 109 }
114 110 }
115 111 }
116 112 } else {
117 113 for (int i = 1; i<argc && ok; i++) {
118 114 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
119 115 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, classInfo);
120 116 if (argList[i]==NULL) {
121 117 ok = false;
122 118 break;
123 119 }
124 120 }
125 121 }
126 122
127 123 if (ok) {
128 124 // parameters are ok, now create the qt return value which is assigned to by metacall
129 125 if (returnValueParam.typeId != QMetaType::Void) {
130 126 // create empty default value for the return value
131 127 if (!directReturnValuePointer) {
132 128 // create empty default value for the return value
133 129 argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);
134 130 if (argList[0]==NULL) {
135 131 // return value could not be created, maybe we have a registered class with a default constructor, so that we can construct the pythonqt wrapper object and
136 132 // pass its internal pointer
137 133 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(returnValueParam.name);
138 134 if (info && info->pythonQtClassWrapper()) {
139 135 PyObject* emptyTuple = PyTuple_New(0);
140 136 // 1) default construct an empty object as python object (owned by PythonQt), by calling the meta class with empty arguments
141 137 result = PyObject_Call((PyObject*)info->pythonQtClassWrapper(), emptyTuple, NULL);
142 138 if (result) {
143 139 argList[0] = ((PythonQtInstanceWrapper*)result)->_wrappedPtr;
144 140 }
145 141 Py_DECREF(emptyTuple);
146 142 }
147 143 }
148 144 } else {
149 145 // we can use our pointer directly!
150 146 argList[0] = directReturnValuePointer;
151 147 }
152 148 }
153 149
154 150
155 151 PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB();
156 152 if (profilingCB) {
157 153 const char* className = NULL;
158 154 if (info->decorator()) {
159 155 className = info->decorator()->metaObject()->className();
160 156 } else {
161 157 className = objectToCall->metaObject()->className();
162 158 }
163 159
164 160 #if( QT_VERSION >= QT_VERSION_CHECK(5,0,0) )
165 161 profilingCB(PythonQt::Enter, className, info->metaMethod()->methodSignature());
166 162 #else
167 163 profilingCB(PythonQt::Enter, className, info->metaMethod()->signature());
168 164 #endif
169 165 }
170 166
171 167 // invoke the slot via metacall
172 168 bool hadException = false;
173 169 QObject* obj = info->decorator()?info->decorator():objectToCall;
174 170 if (!obj) {
175 171 hadException = true;
176 172 PyErr_SetString(PyExc_RuntimeError, "Trying to call a slot on a deleted QObject!");
177 173 } else {
178 174 try {
179 175 obj->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
180 176 } catch (std::bad_alloc & e) {
181 177 hadException = true;
182 178 QByteArray what("std::bad_alloc: ");
183 179 what += e.what();
184 180 PyErr_SetString(PyExc_MemoryError, what.constData());
185 181 } catch (std::runtime_error & e) {
186 182 hadException = true;
187 183 QByteArray what("std::runtime_error: ");
188 184 what += e.what();
189 185 PyErr_SetString(PyExc_RuntimeError, what.constData());
190 186 } catch (std::logic_error & e) {
191 187 hadException = true;
192 188 QByteArray what("std::logic_error: ");
193 189 what += e.what();
194 190 PyErr_SetString(PyExc_RuntimeError, what.constData());
195 191 } catch (std::exception& e) {
196 192 hadException = true;
197 193 QByteArray what("std::exception: ");
198 194 what += e.what();
199 195 #ifdef PY3K
200 196 PyErr_SetString(PyExc_RuntimeError, what.constData());
201 197 #else
202 198 PyErr_SetString(PyExc_StandardError, what.constData());
203 199 #endif
204 200 }
205 201 }
206 202
207 203 if (profilingCB) {
208 204 profilingCB(PythonQt::Leave, NULL, NULL);
209 205 }
210 206
211 207 // handle the return value (which in most cases still needs to be converted to a Python object)
212 208 if (!hadException) {
213 209 if (argList[0] || returnValueParam.typeId == QMetaType::Void) {
214 210 if (directReturnValuePointer) {
215 211 result = NULL;
216 212 } else {
217 213 // the resulting object maybe present already, because we created it above at 1)...
218 214 if (!result) {
219 215 result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]);
220 216 }
221 217 }
222 218 } else {
223 219 QString e = QString("Called ") + info->fullSignature() + ", return type '" + returnValueParam.name + "' is ignored because it is unknown to PythonQt. Probably you should register it using qRegisterMetaType() or add a default constructor decorator to the class.";
224 220 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
225 221 result = NULL;
226 222 }
227 223 } else {
228 224 result = NULL;
229 225 }
230 226 }
231 227 recursiveEntry--;
232 228
233 229 // reset the parameter storage position to the stored pos to "pop" the parameter stack
234 230 PythonQtConv::global_valueStorage.setPos(globalValueStoragePos);
235 231 PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos);
236 232 PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos);
237 233
238 234 *pythonReturnValue = result;
239 235 // NOTE: it is important to only return here, otherwise the stack will not be popped!!!
240 236 return result || (directReturnValuePointer && *directReturnValuePointer);
241 237 }
242 238
243 239 //-----------------------------------------------------------------------------------
244 240
245 241 static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL;
246 242
247 243 PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw)
248 244 {
249 245 PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func;
250 246 return PythonQtMemberFunction_Call(f->m_ml, f->m_self, args, kw);
251 247 }
252 248
253 249 PyObject *PythonQtMemberFunction_Call(PythonQtSlotInfo* info, PyObject* m_self, PyObject *args, PyObject *kw)
254 250 {
255 251 if (PyObject_TypeCheck(m_self, &PythonQtInstanceWrapper_Type)) {
256 252 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) m_self;
257 253 if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
258 254 QString error = QString("Trying to call '") + info->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
259 255 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
260 256 return NULL;
261 257 } else {
262 258 return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr);
263 259 }
264 260 } else if (m_self->ob_type == &PythonQtClassWrapper_Type) {
265 261 PythonQtClassWrapper* type = (PythonQtClassWrapper*) m_self;
266 262 if (info->isClassDecorator()) {
267 263 return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw);
268 264 } else {
269 265 // otherwise, it is an unbound call and we have an instanceDecorator or normal slot...
270 266 Py_ssize_t argc = PyTuple_Size(args);
271 267 if (argc>0) {
272 268 PyObject* firstArg = PyTuple_GET_ITEM(args, 0);
273 269 if (PyObject_TypeCheck(firstArg, (PyTypeObject*)&PythonQtInstanceWrapper_Type)
274 270 && ((PythonQtInstanceWrapper*)firstArg)->classInfo()->inherits(type->classInfo())) {
275 271 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg;
276 272 if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
277 273 QString error = QString("Trying to call '") + info->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
278 274 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
279 275 return NULL;
280 276 }
281 277 // strip the first argument...
282 278 PyObject* newargs = PyTuple_GetSlice(args, 1, argc);
283 279 PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, newargs, kw, self->_wrappedPtr);
284 280 Py_DECREF(newargs);
285 281 return result;
286 282 } else {
287 283 // first arg is not of correct type!
288 284 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument, got " + firstArg->ob_type->tp_name;
289 285 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
290 286 return NULL;
291 287 }
292 288 } else {
293 289 // wrong number of args
294 290 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument.";
295 291 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
296 292 return NULL;
297 293 }
298 294 }
299 295 }
300 296 return NULL;
301 297 }
302 298
303 299 PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg, void** directReturnValuePointer)
304 300 {
305 301 int argc = args?PyTuple_Size(args):0;
306 302
307 303 #ifdef PYTHONQT_DEBUG
308 304 std::cout << "called " << info->metaMethod()->typeName() << " " << info->metaMethod()->signature() << std::endl;
309 305 #endif
310 306
311 307 PyObject* r = NULL;
312 308 bool ok = false;
313 309 if (directReturnValuePointer) {
314 310 *directReturnValuePointer = NULL;
315 311 }
316 312 if (info->nextInfo()) {
317 313 // overloaded slot call, try on all slots with strict conversion first
318 314 bool strict = true;
319 315 PythonQtSlotInfo* i = info;
320 316 while (i) {
321 317 bool skipFirst = i->isInstanceDecorator();
322 318 if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
323 319 PyErr_Clear();
324 320 ok = PythonQtCallSlot(classInfo, objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer);
325 321 if (PyErr_Occurred() || ok) break;
326 322 }
327 323 i = i->nextInfo();
328 324 if (!i) {
329 325 if (strict) {
330 326 // one more run without being strict
331 327 strict = false;
332 328 i = info;
333 329 }
334 330 }
335 331 }
336 332 if (!ok && !PyErr_Occurred()) {
337 333 QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n");
338 334 PythonQtSlotInfo* i = info;
339 335 while (i) {
340 336 e += QString(i->fullSignature()) + "\n";
341 337 i = i->nextInfo();
342 338 }
343 339 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
344 340 }
345 341 } else {
346 342 // simple (non-overloaded) slot call
347 343 bool skipFirst = info->isInstanceDecorator();
348 344 if (info->parameterCount()-1-(skipFirst?1:0) == argc) {
349 345 PyErr_Clear();
350 346 ok = PythonQtCallSlot(classInfo, objectToCall, args, false, info, firstArg, &r, directReturnValuePointer);
351 347 if (!ok && !PyErr_Occurred()) {
352 348 QString e = QString("Called ") + info->fullSignature() + " with wrong arguments: " + PythonQtConv::PyObjGetString(args);
353 349 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
354 350 }
355 351 } else {
356 352 QString e = QString("Called ") + info->fullSignature() + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args);
357 353 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
358 354 }
359 355 }
360 356
361 357 return r;
362 358 }
363 359
364 360 PyObject *
365 361 PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module)
366 362 {
367 363 PythonQtSlotFunctionObject *op;
368 364 op = pythonqtslot_free_list;
369 365 if (op != NULL) {
370 366 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self);
371 367 PyObject_INIT(op, &PythonQtSlotFunction_Type);
372 368 }
373 369 else {
374 370 op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type);
375 371 if (op == NULL)
376 372 return NULL;
377 373 }
378 374 op->m_ml = ml;
379 375 Py_XINCREF(self);
380 376 op->m_self = self;
381 377 Py_XINCREF(module);
382 378 op->m_module = module;
383 379 PyObject_GC_Track(op);
384 380 return (PyObject *)op;
385 381 }
386 382
387 383 PythonQtSlotInfo*
388 384 PythonQtSlotFunction_GetSlotInfo(PyObject *op)
389 385 {
390 386 if (!PythonQtSlotFunction_Check(op)) {
391 387 PyErr_Format(PyExc_SystemError, "%s:%d: bad argument to internal function", __FILE__, __LINE__);
392 388 return NULL;
393 389 }
394 390 return ((PythonQtSlotFunctionObject *)op) -> m_ml;
395 391 }
396 392
397 393 PyObject *
398 394 PythonQtSlotFunction_GetSelf(PyObject *op)
399 395 {
400 396 if (!PythonQtSlotFunction_Check(op)) {
401 397 PyErr_Format(PyExc_SystemError, "%s:%d: bad argument to internal function", __FILE__, __LINE__);
402 398 return NULL;
403 399 }
404 400 return ((PythonQtSlotFunctionObject *)op) -> m_self;
405 401 }
406 402
407 403 /* Methods (the standard built-in methods, that is) */
408 404
409 405 static void
410 406 meth_dealloc(PythonQtSlotFunctionObject *m)
411 407 {
412 408 PyObject_GC_UnTrack(m);
413 409 Py_XDECREF(m->m_self);
414 410 Py_XDECREF(m->m_module);
415 411 m->m_self = (PyObject *)pythonqtslot_free_list;
416 412 pythonqtslot_free_list = m;
417 413 }
418 414
419 415 static PyObject *
420 416 meth_get__doc__(PythonQtSlotFunctionObject * /*m*/, void * /*closure*/)
421 417 {
422 418 Py_INCREF(Py_None);
423 419 return Py_None;
424 420 }
425 421
426 422 static PyObject *
427 423 meth_get__name__(PythonQtSlotFunctionObject *m, void * /*closure*/)
428 424 {
429 425 #if( QT_VERSION >= QT_VERSION_CHECK(5,0,0) )
430 426 #ifdef PY3K
431 427 return PyUnicode_FromString(m->m_ml->metaMethod()->methodSignature());
432 428 #else
433 429 return PyString_FromString(m->m_ml->metaMethod()->methodSignature());
434 430 #endif
435 431 #else
436 432 #ifdef PY3K
437 433 return PyUnicode_FromString(m->m_ml->metaMethod()->signature());
438 434 #else
439 435 return PyString_FromString(m->m_ml->metaMethod()->signature());
440 436 #endif
441 437 #endif
442 438 }
443 439
444 440 static int
445 441 meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg)
446 442 {
447 443 int err;
448 444 if (m->m_self != NULL) {
449 445 err = visit(m->m_self, arg);
450 446 if (err)
451 447 return err;
452 448 }
453 449 if (m->m_module != NULL) {
454 450 err = visit(m->m_module, arg);
455 451 if (err)
456 452 return err;
457 453 }
458 454 return 0;
459 455 }
460 456
461 457 static PyObject *
462 458 meth_get__self__(PythonQtSlotFunctionObject *m, void * /*closure*/)
463 459 {
464 460 PyObject *self;
465 461 #ifndef PY3K
466 462 if (PyEval_GetRestricted()) {
467 463 PyErr_SetString(PyExc_RuntimeError,
468 464 "method.__self__ not accessible in restricted mode");
469 465 return NULL;
470 466 }
471 467 #endif
472 468 self = m->m_self;
473 469 if (self == NULL)
474 470 self = Py_None;
475 471 Py_INCREF(self);
476 472 return self;
477 473 }
478 474
479 475 static PyGetSetDef meth_getsets [] = {
480 476 {const_cast<char*>("__doc__"), (getter)meth_get__doc__, NULL, NULL},
481 477 {const_cast<char*>("__name__"), (getter)meth_get__name__, NULL, NULL},
482 478 {const_cast<char*>("__self__"), (getter)meth_get__self__, NULL, NULL},
483 479 {NULL, NULL, NULL,NULL},
484 480 };
485 481
486 482 #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6
487 483 #define PY_WRITE_RESTRICTED WRITE_RESTRICTED
488 484 #endif
489 485
490 486 #define OFF(x) offsetof(PythonQtSlotFunctionObject, x)
491 487
492 488 static PyMemberDef meth_members[] = {
493 489 {const_cast<char*>("__module__"), T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED},
494 490 {NULL}
495 491 };
496 492
497 493 static PyObject *PythonQtSlotFunction_parameterTypes(PythonQtSlotFunctionObject* type)
498 494 {
499 495 return PythonQtMemberFunction_parameterTypes(type->m_ml);
500 496 }
501 497
502 498 static PyObject *PythonQtSlotFunction_parameterNames(PythonQtSlotFunctionObject* type)
503 499 {
504 500 return PythonQtMemberFunction_parameterNames(type->m_ml);
505 501 }
506 502
507 503 static PyObject *PythonQtSlotFunction_typeName(PythonQtSlotFunctionObject* type)
508 504 {
509 505 return PythonQtMemberFunction_typeName(type->m_ml);
510 506 }
511 507
512 508 PyObject *PythonQtMemberFunction_parameterTypes(PythonQtSlotInfo* theInfo)
513 509 {
514 510 PythonQtSlotInfo* info = theInfo;
515 511 int count = 0;
516 512 while (info) {
517 513 info = info->nextInfo();
518 514 count++;
519 515 }
520 516 info = theInfo;
521 517 PyObject* result = PyTuple_New(count);
522 518 for (int j = 0;j<count;j++) {
523 519 QList<QByteArray> types = info->metaMethod()->parameterTypes();
524 520 PyObject* tuple = PyTuple_New(types.count());
525 521 for (int i = 0; i<types.count();i++) {
526 522 #ifdef PY3K
527 523 PyTuple_SET_ITEM(tuple, i, PyUnicode_FromString(types.at(i).constData()));
528 524 #else
529 525 PyTuple_SET_ITEM(tuple, i, PyString_FromString(types.at(i).constData()));
530 526 #endif
531 527 }
532 528 info = info->nextInfo();
533 529 PyTuple_SET_ITEM(result, j, tuple);
534 530 }
535 531 return result;
536 532 }
537 533
538 534 PyObject *PythonQtMemberFunction_parameterNames(PythonQtSlotInfo* theInfo)
539 535 {
540 536 PythonQtSlotInfo* info = theInfo;
541 537 int count = 0;
542 538 while (info) {
543 539 info = info->nextInfo();
544 540 count++;
545 541 }
546 542 info = theInfo;
547 543 PyObject* result = PyTuple_New(count);
548 544 for (int j = 0;j<count;j++) {
549 545 QList<QByteArray> names = info->metaMethod()->parameterNames();
550 546 PyObject* tuple = PyTuple_New(names.count());
551 547 for (int i = 0; i<names.count();i++) {
552 548 #ifdef PY3K
553 549 PyTuple_SET_ITEM(tuple, i, PyUnicode_FromString(names.at(i).constData()));
554 550 #else
555 551 PyTuple_SET_ITEM(tuple, i, PyString_FromString(names.at(i).constData()));
556 552 #endif
557 553 }
558 554 info = info->nextInfo();
559 555 PyTuple_SET_ITEM(result, j, tuple);
560 556 }
561 557 return result;
562 558 }
563 559
564 560 PyObject *PythonQtMemberFunction_typeName(PythonQtSlotInfo* theInfo)
565 561 {
566 562 PythonQtSlotInfo* info = theInfo;
567 563 int count = 0;
568 564 while (info) {
569 565 info = info->nextInfo();
570 566 count++;
571 567 }
572 568 info = theInfo;
573 569 PyObject* result = PyTuple_New(count);
574 570 for (int j = 0;j<count;j++) {
575 571 QByteArray name = info->metaMethod()->typeName();
576 572 #ifdef PY3K
577 573 PyTuple_SET_ITEM(result, j, PyUnicode_FromString(name.constData()));
578 574 #else
579 575 PyTuple_SET_ITEM(result, j, PyString_FromString(name.constData()));
580 576 #endif
581 577 info = info->nextInfo();
582 578 }
583 579 return result;
584 580 }
585 581
586 582 static PyMethodDef meth_methods[] = {
587 583 {"parameterTypes", (PyCFunction)PythonQtSlotFunction_parameterTypes, METH_NOARGS,
588 584 "Returns a tuple of tuples of the C++ parameter types for all overloads of the slot"
589 585 },
590 586 {"parameterNames", (PyCFunction)PythonQtSlotFunction_parameterNames, METH_NOARGS,
591 587 "Returns a tuple of tuples of the C++ parameter type names (if available), for all overloads of the slot"
592 588 },
593 589 {"typeName", (PyCFunction)PythonQtSlotFunction_typeName, METH_NOARGS,
594 590 "Returns a tuple of the C++ return value types of each slot overload"
595 591 },
596 592 {NULL, NULL, 0 , NULL} /* Sentinel */
597 593 };
598 594
599 595 static PyObject *
600 596 meth_repr(PythonQtSlotFunctionObject *f)
601 597 {
602 598 if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
603 599 PythonQtClassWrapper* self = (PythonQtClassWrapper*) f->m_self;
604 600 #ifdef PY3K
605 601 return PyUnicode_FromFormat("<unbound qt slot %s of %s type>",
606 602 #else
607 603 return PyString_FromFormat("<unbound qt slot %s of %s type>",
608 604 #endif
609 605 f->m_ml->slotName().data(),
610 606 self->classInfo()->className());
611 607 } else {
612 608 #ifdef PY3K
613 609 return PyUnicode_FromFormat("<qt slot %s of %s instance at %p",
614 610 #else
615 611 return PyString_FromFormat("<qt slot %s of %s instance at %p>",
616 612 #endif
617 613 f->m_ml->slotName().data(),
618 614 f->m_self->ob_type->tp_name,
619 615 f->m_self);
620 616 }
621 617 }
622 618
623 619 static int
624 620 meth_compare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b)
625 621 {
626 622 if (a->m_self != b->m_self)
627 623 return (a->m_self < b->m_self) ? -1 : 1;
628 624 if (a->m_ml == b->m_ml)
629 625 return 0;
630 626 #if( QT_VERSION >= QT_VERSION_CHECK(5,0,0) )
631 627 if (strcmp(a->m_ml->metaMethod()->methodSignature(), b->m_ml->metaMethod()->methodSignature()) < 0)
632 628 #else
633 629 if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0)
634 630 #endif
635 631 return -1;
636 632 else
637 633 return 1;
638 634 }
639 635
640 636 static long
641 637 meth_hash(PythonQtSlotFunctionObject *a)
642 638 {
643 639 long x,y;
644 640 if (a->m_self == NULL)
645 641 x = 0;
646 642 else {
647 643 x = PyObject_Hash(a->m_self);
648 644 if (x == -1)
649 645 return -1;
650 646 }
651 647 y = _Py_HashPointer((void*)(a->m_ml));
652 648 if (y == -1)
653 649 return -1;
654 650 x ^= y;
655 651 if (x == -1)
656 652 x = -2;
657 653 return x;
658 654 }
659 655
660 656 // for python 3.x
661 657 static PyObject*
662 658 meth_richcompare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b, int op)
663 659 {
664 660 int x = meth_compare(a, b);
665 661 bool r;
666 662 if (op == Py_LT)
667 663 r = x < 0;
668 664 else if (op == Py_LE)
669 665 r = x < 1;
670 666 else if (op == Py_EQ)
671 667 r = x == 0;
672 668 else if (op == Py_NE)
673 669 r = x != 0;
674 670 else if (op == Py_GE)
675 671 r = x > -1;
676 672 else if (op == Py_GT)
677 673 r = x > 0;
678 674 if (r)
679 675 Py_RETURN_TRUE;
680 676 else
681 677 Py_RETURN_FALSE;
682 678 }
683 679
684 680
685 681 PyTypeObject PythonQtSlotFunction_Type = {
686 682 PyVarObject_HEAD_INIT(&PyType_Type, 0)
687 683 "builtin_qt_slot",
688 684 sizeof(PythonQtSlotFunctionObject),
689 685 0,
690 686 (destructor)meth_dealloc, /* tp_dealloc */
691 687 0, /* tp_print */
692 688 0, /* tp_getattr */
693 689 0, /* tp_setattr */
694 690 #ifdef PY3K
695 691 0,
696 692 #else
697 693 (cmpfunc)meth_compare, /* tp_compare */
698 694 #endif
699 695 (reprfunc)meth_repr, /* tp_repr */
700 696 0, /* tp_as_number */
701 697 0, /* tp_as_sequence */
702 698 0, /* tp_as_mapping */
703 699 (hashfunc)meth_hash, /* tp_hash */
704 700 PythonQtSlotFunction_Call, /* tp_call */
705 701 0, /* tp_str */
706 702 PyObject_GenericGetAttr, /* tp_getattro */
707 703 0, /* tp_setattro */
708 704 0, /* tp_as_buffer */
709 705 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
710 706 0, /* tp_doc */
711 707 (traverseproc)meth_traverse, /* tp_traverse */
712 708 0, /* tp_clear */
713 709 (richcmpfunc)meth_richcompare, /* tp_richcompare */
714 710 0, /* tp_weaklistoffset */
715 711 0, /* tp_iter */
716 712 0, /* tp_iternext */
717 713 meth_methods, /* tp_methods */
718 714 meth_members, /* tp_members */
719 715 meth_getsets, /* tp_getset */
720 716 0, /* tp_base */
721 717 0, /* tp_dict */
722 718 };
723 719
724 720 /* Clear out the free list */
725 721
726 722 void
727 723 PythonQtSlotFunction_Fini(void)
728 724 {
729 725 while (pythonqtslot_free_list) {
730 726 PythonQtSlotFunctionObject *v = pythonqtslot_free_list;
731 727 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(v->m_self);
732 728 PyObject_GC_Del(v);
733 729 }
734 730 }
735 731
@@ -1,587 +1,595
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 PythonQtTests.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 "PythonQtTests.h"
43 43
44 44 void PythonQtTestSlotCalling::initTestCase()
45 45 {
46 46 _helper = new PythonQtTestSlotCallingHelper(this);
47 47 PythonQtObjectPtr main = PythonQt::self()->getMainModule();
48 48 main.evalScript("import PythonQt");
49 49 PythonQt::self()->addObject(main, "obj", _helper);
50 50 }
51 51
52 52 void PythonQtTestSlotCalling::init() {
53 53
54 54 }
55 55
56 56
57 57 void* polymorphic_ClassB_Handler(const void* ptr, const char** className) {
58 58 ClassB* o = (ClassB*)ptr;
59 59 if (o->type()==2) {
60 60 *className = "ClassB";
61 61 return (ClassB*)o;
62 62 }
63 63 if (o->type()==3) {
64 64 *className = "ClassC";
65 65 return (ClassC*)o;
66 66 }
67 67 if (o->type()==4) {
68 68 *className = "ClassD";
69 69 return (ClassD*)o;
70 70 }
71 71 return NULL;
72 72 }
73 73
74 74 void PythonQtTestSlotCalling::testInheritance() {
75 75 PythonQt::self()->registerCPPClass("ClassA",NULL,NULL, PythonQtCreateObject<ClassAWrapper>);
76 76 PythonQt::self()->registerCPPClass("ClassB",NULL,NULL, PythonQtCreateObject<ClassBWrapper>);
77 77 PythonQt::self()->registerCPPClass("ClassC",NULL,NULL, PythonQtCreateObject<ClassCWrapper>);
78 78 PythonQt::self()->addParentClass("ClassC", "ClassA", PythonQtUpcastingOffset<ClassC,ClassA>());
79 79 PythonQt::self()->addParentClass("ClassC", "ClassB", PythonQtUpcastingOffset<ClassC,ClassB>());
80 80 PythonQt::self()->registerClass(&ClassD::staticMetaObject, NULL, PythonQtCreateObject<ClassDWrapper>);
81 81 PythonQt::self()->addParentClass("ClassD", "ClassA", PythonQtUpcastingOffset<ClassD,ClassA>());
82 82 PythonQt::self()->addParentClass("ClassD", "ClassB", PythonQtUpcastingOffset<ClassD,ClassB>());
83 83
84 84 PythonQtObjectPtr classA = PythonQt::self()->getMainModule().getVariable("PythonQt.private.ClassA");
85 85 PythonQtObjectPtr classB = PythonQt::self()->getMainModule().getVariable("PythonQt.private.ClassB");
86 86 PythonQtObjectPtr classC = PythonQt::self()->getMainModule().getVariable("PythonQt.private.ClassC");
87 87 PythonQtObjectPtr classD = PythonQt::self()->getMainModule().getVariable("PythonQt.private.ClassD");
88 88 QVERIFY(classA);
89 89 QVERIFY(classB);
90 90 QVERIFY(classC);
91 91 QVERIFY(classD);
92 92
93 93 QVERIFY(_helper->runScript("a = PythonQt.private.ClassA();\nif obj.getClassAPtr(a).getX()==1: obj.setPassed();\n"));
94 94 QEXPECT_FAIL("", "ClassB can not be converted to ClassA", Continue);
95 95 QVERIFY(_helper->runScript("a = PythonQt.private.ClassB();\nif obj.getClassAPtr(a).getX()==1: obj.setPassed();\n"));
96 96 QVERIFY(_helper->runScript("a = PythonQt.private.ClassC();\nif obj.getClassAPtr(a).getX()==1: obj.setPassed();\n"));
97 97 QVERIFY(_helper->runScript("a = PythonQt.private.ClassD();\nif obj.getClassAPtr(a).getX()==1: obj.setPassed();\n"));
98 98
99 99 QEXPECT_FAIL("", "ClassA can not be converted to ClassB", Continue);
100 100 QVERIFY(_helper->runScript("a = PythonQt.private.ClassA();\nif obj.getClassBPtr(a).getY()==2: obj.setPassed();\n"));
101 101 QVERIFY(_helper->runScript("a = PythonQt.private.ClassB();\nif obj.getClassBPtr(a).getY()==2: obj.setPassed();\n"));
102 102 QVERIFY(_helper->runScript("a = PythonQt.private.ClassC();\nif obj.getClassBPtr(a).getY()==2: obj.setPassed();\n"));
103 103 QVERIFY(_helper->runScript("a = PythonQt.private.ClassD();\nif obj.getClassBPtr(a).getY()==2: obj.setPassed();\n"));
104 104
105 105 QEXPECT_FAIL("", "ClassA can not be converted to ClassC", Continue);
106 106 QVERIFY(_helper->runScript("a = PythonQt.private.ClassA();\nif obj.getClassCPtr(a).getX()==1: obj.setPassed();\n"));
107 107 QEXPECT_FAIL("", "ClassB can not be converted to ClassC", Continue);
108 108 QVERIFY(_helper->runScript("a = PythonQt.private.ClassB();\nif obj.getClassCPtr(a).getX()==1: obj.setPassed();\n"));
109 109 QVERIFY(_helper->runScript("a = PythonQt.private.ClassC();\nif obj.getClassCPtr(a).getX()==1: obj.setPassed();\n"));
110 110 QEXPECT_FAIL("", "ClassD can not be converted to ClassC", Continue);
111 111 QVERIFY(_helper->runScript("a = PythonQt.private.ClassD();\nif obj.getClassCPtr(a).getX()==1: obj.setPassed();\n"));
112 112
113 113 QVERIFY(_helper->runScript("if type(obj.createClassA())==PythonQt.private.ClassA: obj.setPassed();\n"));
114 114 QVERIFY(_helper->runScript("if type(obj.createClassB())==PythonQt.private.ClassB: obj.setPassed();\n"));
115 115 QVERIFY(_helper->runScript("if type(obj.createClassCAsA())==PythonQt.private.ClassA: obj.setPassed();\n"));
116 116 QVERIFY(_helper->runScript("if type(obj.createClassCAsB())==PythonQt.private.ClassB: obj.setPassed();\n"));
117 117 QVERIFY(_helper->runScript("if type(obj.createClassD())==PythonQt.private.ClassD: obj.setPassed();\n"));
118 118 QVERIFY(_helper->runScript("if type(obj.createClassDAsA())==PythonQt.private.ClassA: obj.setPassed();\n"));
119 119 QVERIFY(_helper->runScript("if type(obj.createClassDAsB())==PythonQt.private.ClassB: obj.setPassed();\n"));
120 120
121 121 PythonQt::self()->addPolymorphicHandler("ClassB", polymorphic_ClassB_Handler);
122 122
123 123 QVERIFY(_helper->runScript("if type(obj.getClassBPtr(obj.createClassB()))==PythonQt.private.ClassB: obj.setPassed();\n"));
124 124 QVERIFY(_helper->runScript("if type(obj.createClassCAsB())==PythonQt.private.ClassC: obj.setPassed();\n"));
125 125 QVERIFY(_helper->runScript("if type(obj.createClassDAsB())==PythonQt.private.ClassD: obj.setPassed();\n"));
126 126
127 127 }
128 128
129 129 void PythonQtTestSlotCalling::testAutoConversion() {
130 130 QVERIFY(_helper->runScript("if obj.setAutoConvertColor(PythonQt.QtCore.Qt.red)==PythonQt.Qt.QColor(PythonQt.QtCore.Qt.red): obj.setPassed();\n"));
131 131 QVERIFY(_helper->runScript("if obj.setAutoConvertBrush(PythonQt.QtCore.Qt.red)==PythonQt.Qt.QBrush(PythonQt.QtCore.Qt.red): obj.setPassed();\n"));
132 132 QVERIFY(_helper->runScript("if obj.setAutoConvertPen(PythonQt.QtCore.Qt.red)==PythonQt.Qt.QPen(PythonQt.QtCore.Qt.red): obj.setPassed();\n"));
133 133 QVERIFY(_helper->runScript("if obj.setAutoConvertBrush(PythonQt.Qt.QColor(PythonQt.QtCore.Qt.red))==PythonQt.Qt.QBrush(PythonQt.QtCore.Qt.red): obj.setPassed();\n"));
134 134 QVERIFY(_helper->runScript("if obj.setAutoConvertPen(PythonQt.Qt.QColor(PythonQt.QtCore.Qt.red))==PythonQt.Qt.QPen(PythonQt.QtCore.Qt.red): obj.setPassed();\n"));
135 135 QVERIFY(_helper->runScript("if obj.setAutoConvertCursor(PythonQt.Qt.QCursor(PythonQt.QtCore.Qt.UpArrowCursor)).shape()==PythonQt.Qt.QCursor(PythonQt.QtCore.Qt.UpArrowCursor).shape(): obj.setPassed();\n"));
136 136 QVERIFY(_helper->runScript("if obj.setAutoConvertCursor(PythonQt.QtCore.Qt.UpArrowCursor).shape()==PythonQt.Qt.QCursor(PythonQt.QtCore.Qt.UpArrowCursor).shape(): obj.setPassed();\n"));
137 137 }
138 138
139 139 void PythonQtTestSlotCalling::testNoArgSlotCall()
140 140 {
141 141 QVERIFY(_helper->runScript("obj.testNoArg(); obj.setPassed();\n"));
142 142 }
143 143
144 144 void PythonQtTestSlotCalling::testOverloadedCall()
145 145 {
146 146 QVERIFY(_helper->runScript("obj.overload(False); obj.setPassed();\n", 0));
147 147 QVERIFY(_helper->runScript("obj.overload(True); obj.setPassed();\n", 0));
148 148 QVERIFY(_helper->runScript("obj.overload(12.5); obj.setPassed();\n", 1));
149 149 QVERIFY(_helper->runScript("obj.overload(12); obj.setPassed();\n", 2));
150 150 QVERIFY(_helper->runScript("obj.overload('test'); obj.setPassed();\n", 3));
151 151 QVERIFY(_helper->runScript("obj.overload(u'test'); obj.setPassed();\n", 3));
152 152 QVERIFY(_helper->runScript("obj.overload(('test','test2')); obj.setPassed();\n", 4));
153 153 QVERIFY(_helper->runScript("obj.overload(obj); obj.setPassed();\n", 5));
154 154 QVERIFY(_helper->runScript("obj.overload(12,13); obj.setPassed();\n", 6));
155 155 }
156 156
157 157 void PythonQtTestSlotCalling::testPyObjectSlotCall()
158 158 {
159 159 QVERIFY(_helper->runScript("if obj.getPyObject(PythonQt)==PythonQt: obj.setPassed();\n"));
160 160 QVERIFY(_helper->runScript("if obj.getPyObject('Hello')=='Hello': obj.setPassed();\n"));
161 161 QVERIFY(_helper->runScript("if obj.getPyObjectFromVariant(PythonQt)==PythonQt: obj.setPassed();\n"));
162 162 QVERIFY(_helper->runScript("if obj.getPyObjectFromVariant2(PythonQt)==PythonQt: obj.setPassed();\n"));
163 163 // QVERIFY(_helper->runScript("if obj.getPyObjectFromPtr(PythonQt)==PythonQt: obj.setPassed();\n"));
164 164 }
165 165
166 166 void PythonQtTestSlotCalling::testCPPSlotCalls()
167 167 {
168 168 // test QColor compare operation
169 169 QVERIFY(_helper->runScript("if PythonQt.QtGui.QColor(1,2,3)==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();obj.testNoArg()\n"));
170 170 QVERIFY(_helper->runScript("if PythonQt.QtGui.QColor(1,2,3)!=PythonQt.QtGui.QColor(3,2,1): obj.setPassed();obj.testNoArg()\n"));
171 171
172 172 // test passing/returning QColors
173 173 QVERIFY(_helper->runScript("if obj.getQColor1(PythonQt.QtGui.QColor(1,2,3))==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();\n"));
174 174 QVERIFY(_helper->runScript("if obj.getQColor2(PythonQt.QtGui.QColor(1,2,3))==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();\n"));
175 175 QVERIFY(_helper->runScript("if obj.getQColor3(PythonQt.QtGui.QColor(1,2,3))==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();\n"));
176 176 QVERIFY(_helper->runScript("if obj.getQColor4(PythonQt.QtGui.QColor(1,2,3))==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();\n"));
177 177 QVERIFY(_helper->runScript("if obj.getQColor5()==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();\n"));
178 178 }
179 179
180 180 void PythonQtTestSlotCalling::testPODSlotCalls()
181 181 {
182 182 QVERIFY(_helper->runScript("if obj.getBool(False)==False: obj.setPassed();\n"));
183 183 QVERIFY(_helper->runScript("if obj.getBool(True)==True: obj.setPassed();\n"));
184 184 QVERIFY(_helper->runScript("if obj.getInt(-42)==-42: obj.setPassed();\n"));
185 185 QVERIFY(_helper->runScript("if obj.getUInt(42)==42: obj.setPassed();\n"));
186 186 QVERIFY(_helper->runScript("if obj.getShort(-43)==-43: obj.setPassed();\n"));
187 187 QVERIFY(_helper->runScript("if obj.getUShort(43)==43: obj.setPassed();\n"));
188 188 QVERIFY(_helper->runScript("if obj.getChar(-12)==-12: obj.setPassed();\n"));
189 189 QVERIFY(_helper->runScript("if obj.getUChar(12)==12: obj.setPassed();\n"));
190 190 QVERIFY(_helper->runScript("if obj.getLong(-256*256*256)==-256*256*256: obj.setPassed();\n"));
191 191 QVERIFY(_helper->runScript("if obj.getULong(256*256*256)==256*256*256: obj.setPassed();\n"));
192 192 QVERIFY(_helper->runScript("if obj.getLongLong(-42)==-42: obj.setPassed();\n"));
193 193 QVERIFY(_helper->runScript("if obj.getULongLong(42)==42: obj.setPassed();\n"));
194 194 QVERIFY(_helper->runScript("if obj.getQChar(4096)==4096: obj.setPassed();\n"));
195 195 QVERIFY(_helper->runScript("if obj.getDouble(47.12)==47.12: obj.setPassed();\n"));
196 196 QVERIFY(_helper->runScript("if abs(obj.getFloat(47.11)-47.11)<0.01: obj.setPassed();\n"));
197 197 QVERIFY(_helper->runScript("if obj.getQString('testStr')=='testStr': obj.setPassed();\n"));
198 198 QVERIFY(_helper->runScript("if obj.getQString('')=='': obj.setPassed();\n"));
199 199 QVERIFY(_helper->runScript("if obj.getQStringList(('test','test2'))==('test','test2'): obj.setPassed();\n"));
200 200 }
201 201
202 202 void PythonQtTestSlotCalling::testQVariantSlotCalls()
203 203 {
204 204 QVERIFY(_helper->runScript("if obj.getQVariant(-42)==-42: obj.setPassed();\n"));
205 205 QVERIFY(_helper->runScript("if obj.getQVariant('testStr')=='testStr': obj.setPassed();\n"));
206 206 QVERIFY(_helper->runScript("if obj.getQVariant(('test','test2'))==('test','test2'): obj.setPassed();\n"));
207 207 QVERIFY(_helper->runScript("if obj.getQVariant(('test',12, 47.11))==('test',12, 47.11): obj.setPassed();\n"));
208 208 QVERIFY(_helper->runScript("if obj.getQVariant({'test':'bla','test2':47.11})=={'test':'bla','test2':47.11}: obj.setPassed();\n"));
209 209 QEXPECT_FAIL("", "Testing to pass a map and compare with a different map", Continue);
210 210 QVERIFY(_helper->runScript("if obj.getQVariant({'test':'bla2','test2':47.11})=={'test':'bla','test2':47.11}: obj.setPassed();\n"));
211 211 QVERIFY(_helper->runScript("if obj.getQVariant(obj)==obj: obj.setPassed();\n"));
212 212 }
213 213
214 214 void PythonQtTestSlotCalling::testObjectSlotCalls()
215 215 {
216 216 QVERIFY(_helper->runScript("if obj.getQObject(obj)==obj: obj.setPassed();\n"));
217 217 QVERIFY(_helper->runScript("if obj.getTestObject(obj)==obj: obj.setPassed();\n"));
218 218 QVERIFY(_helper->runScript("if obj.getNewObject().className()=='PythonQtTestSlotCallingHelper': obj.setPassed();\n"));
219 219 QEXPECT_FAIL("", "Testing to pass a QObject when another object was expected", Continue);
220 220 QVERIFY(_helper->runScript("if obj.getQWidget(obj)==obj: obj.setPassed();\n"));
221 221 }
222 222
223 223 void PythonQtTestSlotCalling::testCppFactory()
224 224 {
225 225 PythonQtTestCppFactory* f = new PythonQtTestCppFactory;
226 226 PythonQt::self()->addInstanceDecorators(new PQCppObjectDecorator);
227 227 // do not register, since we want to know if that works as well
228 228 //qRegisterMetaType<PQCppObjectNoWrap>("PQCppObjectNoWrap");
229 229 PythonQt::self()->addDecorators(new PQCppObjectNoWrapDecorator);
230 230
231 231 PythonQt::self()->addWrapperFactory(f);
232 232 QVERIFY(_helper->runScript("if obj.createPQCppObject(12).getHeight()==12: obj.setPassed();\n"));
233 233 QVERIFY(_helper->runScript("if obj.createPQCppObject(12).getH()==12: obj.setPassed();\n"));
234 234 QVERIFY(_helper->runScript("pq1 = obj.createPQCppObject(12);\n"
235 235 "pq2 = obj.createPQCppObject(13);\n"
236 236 "pq3 = obj.getPQCppObject(pq1);\n"
237 237 "pq4 = obj.getPQCppObject(pq2);\n"
238 238 "if pq3.getHeight()==12 and pq4.getHeight()==13: obj.setPassed();\n"
239 239 ));
240 240
241 241 QVERIFY(_helper->runScript("if obj.createPQCppObjectNoWrap(12).getH()==12: obj.setPassed();\n"));
242 242
243 243 QVERIFY(_helper->runScript("if obj.getPQCppObjectNoWrapAsValue().getH()==47: obj.setPassed();\n"));
244 244
245 245 qRegisterMetaType<PQUnknownButRegisteredValueObject>("PQUnknownButRegisteredValueObject");
246 QVERIFY(_helper->runScript("a = obj.getUnknownButRegisteredValueObjectAsPtr();print a;\nif a!=None: obj.setPassed();\n"));
247 QVERIFY(_helper->runScript("a = obj.getUnknownButRegisteredValueObjectAsValue();print a;\nif a!=None: obj.setPassed();\n"));
248 QVERIFY(_helper->runScript("a = obj.getUnknownValueObjectAsPtr();print a;\nif a!=None: obj.setPassed();\n"));
246 QVERIFY(_helper->runScript("a = obj.getUnknownButRegisteredValueObjectAsPtr();print (a);\nif a!=None: obj.setPassed();\n"));
247 QVERIFY(_helper->runScript("a = obj.getUnknownButRegisteredValueObjectAsValue();print (a);\nif a!=None: obj.setPassed();\n"));
248 QVERIFY(_helper->runScript("a = obj.getUnknownValueObjectAsPtr();print (a);\nif a!=None: obj.setPassed();\n"));
249 249 QEXPECT_FAIL("", "Testing by value return without the object being registered as QMetaType or having registered a default constructor decorator", Continue);
250 QVERIFY(_helper->runScript("a = obj.getUnknownValueObjectAsValue();print a;\nif a!=None: obj.setPassed();\n"));
250 QVERIFY(_helper->runScript("a = obj.getUnknownValueObjectAsValue();print (a);\nif a!=None: obj.setPassed();\n"));
251 251
252 252 // expect to get strict call to double overload
253 253 QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObjectNoWrap\na = PQCppObjectNoWrap(22.2)\nif a.getH()==2: obj.setPassed();\n"));
254 254 // expect to get un-strict call to double overload
255 255 QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObjectNoWrap\na = PQCppObjectNoWrap(22)\nif a.getH()==2: obj.setPassed();\n"));
256 256 // expect to get strict call to copy constructor overload
257 QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObjectNoWrap\na = PQCppObjectNoWrap(PQCppObjectNoWrap())\nprint a.getH()\nif a.getH()==1: obj.setPassed();\n"));
257 QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObjectNoWrap\na = PQCppObjectNoWrap(PQCppObjectNoWrap())\nprint (a.getH())\nif a.getH()==1: obj.setPassed();\n"));
258 258
259 259 // test decorated enums
260 260 // already registered by signals test
261 261 //PythonQt::self()->registerCPPClass("PQCppObject2",NULL,NULL, PythonQtCreateObject<PQCppObject2Decorator>);
262 262
263 263 // local enum (decorated)
264 QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObject2\na = PQCppObject2()\nprint a.testEnumFlag1\nif a.testEnumFlag1(PQCppObject2.TestEnumValue2)==PQCppObject2.TestEnumValue2: obj.setPassed();\n"));
264 QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObject2\na = PQCppObject2()\nprint (a.testEnumFlag1)\nif a.testEnumFlag1(PQCppObject2.TestEnumValue2)==PQCppObject2.TestEnumValue2: obj.setPassed();\n"));
265 265 // enum with namespace (decorated)
266 266 QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObject2\na = PQCppObject2()\nif a.testEnumFlag2(PQCppObject2.TestEnumValue2)==PQCppObject2.TestEnumValue2: obj.setPassed();\n"));
267 267 // with int overload to check overloading
268 268 QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObject2\na = PQCppObject2()\nif a.testEnumFlag3(PQCppObject2.TestEnumValue2)==PQCppObject2.TestEnumValue2: obj.setPassed();\n"));
269 269
270 270 }
271 271
272 272 PQCppObject2Decorator::TestEnumFlag PQCppObject2Decorator::testEnumFlag1(PQCppObject2* obj, PQCppObject2Decorator::TestEnumFlag flag) {
273 273 return flag;
274 274 }
275 275
276 276 PQCppObject2::TestEnumFlag PQCppObject2Decorator::testEnumFlag2(PQCppObject2* obj, PQCppObject2::TestEnumFlag flag) {
277 277 return flag;
278 278 }
279 279
280 280 // with int overload
281 281 PQCppObject2Decorator::TestEnumFlag PQCppObject2Decorator::testEnumFlag3(PQCppObject2* obj, int flag) {
282 282 return (TestEnumFlag)-1;
283 283 }
284 284 PQCppObject2Decorator::TestEnumFlag PQCppObject2Decorator::testEnumFlag3(PQCppObject2* obj, PQCppObject2Decorator::TestEnumFlag flag) {
285 285 return flag;
286 286 }
287 287
288 288 void PythonQtTestSlotCalling::testMultiArgsSlotCall()
289 289 {
290 290 QVERIFY(_helper->runScript("if obj.getMultiArgs(12,47.11,'test')==(12,47.11,'test'): obj.setPassed();\n"));
291 291 }
292 292
293 293 bool PythonQtTestSlotCallingHelper::runScript(const char* script, int expectedOverload)
294 294 {
295 295 _called = false;
296 296 _passed = false;
297 297 _calledOverload = -1;
298 298 PyRun_SimpleString(script);
299 299 return _called && _passed && _calledOverload==expectedOverload;
300 300 }
301 301
302 302
303 303 void PythonQtTestSignalHandler::initTestCase()
304 304 {
305 305 _helper = new PythonQtTestSignalHandlerHelper(this);
306 306 PythonQtObjectPtr main = PythonQt::self()->getMainModule();
307 307 PythonQt::self()->addObject(main, "obj", _helper);
308 308 }
309 309
310 310 void PythonQtTestSignalHandler::testSignalHandler()
311 311 {
312 312 PythonQtObjectPtr main = PythonQt::self()->getMainModule();
313 313 PyRun_SimpleString("def testIntSignal(a):\n if a==12: obj.setPassed();\n");
314 314 QVERIFY(PythonQt::self()->addSignalHandler(_helper, SIGNAL(intSignal(int)), main, "testIntSignal"));
315 315 QVERIFY(_helper->emitIntSignal(12));
316 316
317 317 PyRun_SimpleString("def testFloatSignal(a):\n if a==12: obj.setPassed();\n");
318 318 QVERIFY(PythonQt::self()->addSignalHandler(_helper, SIGNAL(floatSignal(float)), main, "testFloatSignal"));
319 319 QVERIFY(_helper->emitFloatSignal(12));
320 320
321 321 // test decorated enums
322 322 PythonQt::self()->registerCPPClass("PQCppObject2",NULL,NULL, PythonQtCreateObject<PQCppObject2Decorator>);
323 323
324 324 PyRun_SimpleString("def testEnumSignal(a):\n if a==1: obj.setPassed();\n");
325 325 QVERIFY(PythonQt::self()->addSignalHandler(_helper, SIGNAL(enumSignal(PQCppObject2::TestEnumFlag)), main, "testEnumSignal"));
326 326 QVERIFY(_helper->emitEnumSignal(PQCppObject2::TestEnumValue2));
327 327
328 328 PyRun_SimpleString("def testVariantSignal(a):\n if a==obj.expectedVariant(): obj.setPassed();\n");
329 329 QVERIFY(PythonQt::self()->addSignalHandler(_helper, SIGNAL(variantSignal(QVariant)), main, "testVariantSignal"));
330 330 _helper->setExpectedVariant(QString("Test"));
331 331 QVERIFY(_helper->emitVariantSignal(QString("Test")));
332 332 _helper->setExpectedVariant(12);
333 333 QVERIFY(_helper->emitVariantSignal(12));
334 334 _helper->setExpectedVariant(QStringList() << "test1" << "test2");
335 335 QVERIFY(_helper->emitVariantSignal(QStringList() << "test1" << "test2"));
336 336 _helper->setExpectedVariant(qVariantFromValue((QObject*)_helper));
337 337 QVERIFY(_helper->emitVariantSignal(qVariantFromValue((QObject*)_helper)));
338 338
339 339 PyRun_SimpleString("def testComplexSignal(a,b,l,o):\n if a==12 and b==13 and l==('test1','test2') and o == obj: obj.setPassed();\n");
340 340 // intentionally not normalized signal:
341 341 QVERIFY(PythonQt::self()->addSignalHandler(_helper, SIGNAL(complexSignal( int, float , const QStringList , QObject*)), main, "testComplexSignal"));
342 342 QVERIFY(_helper->emitComplexSignal(12,13,QStringList() << "test1" << "test2", _helper));
343 343
344 344 // try removing the handler
345 345 QVERIFY(PythonQt::self()->removeSignalHandler(_helper, SIGNAL(complexSignal( int, float , const QStringList , QObject*)), main, "testComplexSignal"));
346 346 // and emit the signal, which should fail because the handler was removed
347 347 QVERIFY(!_helper->emitComplexSignal(12,13,QStringList() << "test1" << "test2", _helper));
348 348
349 349 QVERIFY(PythonQt::self()->removeSignalHandler(_helper, SIGNAL(intSignal(int)), main, "testIntSignal"));
350 350 QVERIFY(PythonQt::self()->removeSignalHandler(_helper, SIGNAL(floatSignal(float)), main, "testFloatSignal"));
351 351 QVERIFY(PythonQt::self()->removeSignalHandler(_helper, SIGNAL(variantSignal(QVariant)), main, "testVariantSignal"));
352 352 QVERIFY(PythonQt::self()->removeSignalHandler(_helper, SIGNAL(enumSignal(PQCppObject2::TestEnumFlag)), main, "testEnumSignal"));
353 353
354 354 }
355 355
356 356 void PythonQtTestSignalHandler::testRecursiveSignalHandler()
357 357 {
358 358 PythonQtObjectPtr main = PythonQt::self()->getMainModule();
359 359 PyRun_SimpleString("def testSignal1(a):\n obj.emitSignal2(a);\n");
360 360 PyRun_SimpleString("def testSignal2(a):\n obj.emitSignal3(float(a));\n");
361 361 PyRun_SimpleString("def testSignal3(a):\n if a==12: obj.setPassed();\n");
362 362 QVERIFY(PythonQt::self()->addSignalHandler(_helper, SIGNAL(signal1(int)), main, "testSignal1"));
363 363 QVERIFY(PythonQt::self()->addSignalHandler(_helper, SIGNAL(signal2(const QString&)), main, "testSignal2"));
364 364 QVERIFY(PythonQt::self()->addSignalHandler(_helper, SIGNAL(signal3(float)), main, "testSignal3"));
365 365 QVERIFY(_helper->emitSignal1(12));
366 366 }
367 367
368 368
369 369 void PythonQtTestApi::initTestCase()
370 370 {
371 371 _helper = new PythonQtTestApiHelper();
372 372 _main = PythonQt::self()->getMainModule();
373 373 _main.evalScript("import PythonQt");
374 374 _main.addObject("obj", _helper);
375 375 }
376 376
377 377 void PythonQtTestApi::testProperties()
378 378 {
379 379 PythonQtObjectPtr main = PythonQt::self()->getMainModule();
380 380 // check for name alias (for backward comp to Qt3)
381 381 main.evalScript("obj.name = 'hello'");
382 382 QVERIFY(QString("hello") == main.getVariable("obj.name").toString());
383 383
384 384 main.evalScript("obj.objectName = 'hello2'");
385 385 QVERIFY(QString("hello2") == main.getVariable("obj.objectName").toString());
386 386
387 387 }
388 388
389 389 void PythonQtTestApi::testDynamicProperties()
390 390 {
391 391 PythonQtObjectPtr main = PythonQt::self()->getMainModule();
392 392
393 393 // this fails and should fail, but how could that be tested?
394 394 // main.evalScript("obj.testProp = 1");
395 395
396 396 // create a new dynamic property
397 397 main.evalScript("obj.setProperty('testProp','testValue')");
398 398
399 399 // read the property
400 400 QVERIFY(QString("testValue") == main.getVariable("obj.testProp").toString());
401 401 // modify and read again
402 402 main.evalScript("obj.testProp = 12");
403 403 QVERIFY(12 == main.getVariable("obj.testProp").toInt());
404 404
405 405 // check if dynamic property is in dict
406 406 QVERIFY(12 == main.evalScript("obj.__dict__['testProp']", Py_eval_input).toInt());
407 407
408 408 // check if dynamic property is in introspection
409 409 QStringList l = PythonQt::self()->introspection(PythonQt::self()->getMainModule(), "obj", PythonQt::Anything);
410 410 QVERIFY(l.contains("testProp"));
411 411
412 412 // check with None, previous value expected
413 413 main.evalScript("obj.testProp = None");
414 414 QVERIFY(12 == main.getVariable("obj.testProp").toInt());
415 415
416 416 // remove the dynamic property
417 417 main.evalScript("obj.setProperty('testProp', None)");
418 418
419 419 // check if dynamic property is really gone
420 420 QStringList l2 = PythonQt::self()->introspection(PythonQt::self()->getMainModule(), "obj", PythonQt::Anything);
421 421 QVERIFY(!l2.contains("testProp"));
422 422
423 423 }
424 424
425 425
426 426 bool PythonQtTestApiHelper::call(const QString& function, const QVariantList& args, const QVariant& expectedResult) {
427 427 _passed = false;
428 428 QVariant r = PythonQt::self()->call(PythonQt::self()->getMainModule(), function, args);
429 429 return _passed && expectedResult==r;
430 430 }
431 431
432 432 void PythonQtTestApi::testCall()
433 433 {
434 434 PythonQtObjectPtr main = PythonQt::self()->getMainModule();
435 435
436 436 QVERIFY(qvariant_cast<QObject*>(PythonQt::self()->getVariable(main, "obj"))==_helper);
437 437
438 438 PyRun_SimpleString("def testCallNoArgs():\n obj.setPassed();\n");
439 439 QVERIFY(_helper->call("testCallNoArgs", QVariantList(), QVariant()));
440 440
441 441 PyRun_SimpleString("def testCall1(a):\n if a=='test': obj.setPassed();\n return 'test2';\n");
442 442 QVERIFY(_helper->call("testCall1", QVariantList() << QVariant("test"), QVariant(QString("test2"))));
443 443
444 444 PyRun_SimpleString("def testCall2(a, b):\n if a=='test' and b==obj: obj.setPassed();\n return obj;\n");
445 445 QVariant r = PythonQt::self()->call(PythonQt::self()->getMainModule(), "testCall2", QVariantList() << QVariant("test") << qVariantFromValue((QObject*)_helper));
446 446 QObject* p = qvariant_cast<QObject*>(r);
447 447 QVERIFY(p==_helper);
448 448 }
449 449
450 450 void PythonQtTestApi::testVariables()
451 451 {
452 452 PythonQt::self()->addObject(PythonQt::self()->getMainModule(), "someObject", _helper);
453 453 QVariant v = PythonQt::self()->getVariable(PythonQt::self()->getMainModule(), "someObject");
454 454 QObject* p = qvariant_cast<QObject*>(v);
455 455 QVERIFY(p==_helper);
456 456 // test for unset variable
457 457 QVariant v2 = PythonQt::self()->getVariable(PythonQt::self()->getMainModule(), "someObject2");
458 458 QVERIFY(v2==QVariant());
459 459
460 460 PythonQt::self()->addVariable(PythonQt::self()->getMainModule(), "someValue", QStringList() << "test1" << "test2");
461 461 QVariant v3 = PythonQt::self()->getVariable(PythonQt::self()->getMainModule(), "someValue");
462 462 QVERIFY(v3 == QVariant(QStringList() << "test1" << "test2"));
463 463
464 464 QStringList l = PythonQt::self()->introspection(PythonQt::self()->getMainModule(), QString::null, PythonQt::Variable);
465 465 QSet<QString> s;
466 466 // check that at least these three variables are set
467 467 s << "obj" << "someObject" << "someValue";
468 468 foreach (QString value, s) {
469 469 QVERIFY(l.indexOf(value)!=-1);
470 470 }
471 471
472 472 // insert a second time!
473 473 PythonQt::self()->addObject(PythonQt::self()->getMainModule(), "someObject", _helper);
474 474 // and remove
475 475 PythonQt::self()->removeVariable(PythonQt::self()->getMainModule(), "someObject");
476 476 // we expect to find no variable
477 477 QVariant v4 = PythonQt::self()->getVariable(PythonQt::self()->getMainModule(), "someObject");
478 478 QVERIFY(v4==QVariant());
479 479 }
480 480
481 481 void PythonQtTestApi::testImporter()
482 482 {
483 483 PythonQt::self()->setImporter(_helper);
484 484 PythonQt::self()->overwriteSysPath(QStringList() << "c:\\test");
485 485 PyRun_SimpleString("import bla\n");
486 486 }
487 487
488 488 void PythonQtTestApi::testQtNamespace()
489 489 {
490 490 QVERIFY(_main.getVariable("PythonQt.QtCore.Qt.red").toInt()==Qt::red);
491 491 QVERIFY(_main.getVariable("PythonQt.QtCore.Qt.FlatCap").toInt()==Qt::FlatCap);
492 492 #if( QT_VERSION < QT_VERSION_CHECK(5,0,0) )
493 493 QVERIFY(PythonQtObjectPtr(_main.getVariable("PythonQt.QtCore.Qt.escape")));
494 494 #endif
495 495 // check for an enum type wrapper
496 496 QVERIFY(PythonQtObjectPtr(_main.getVariable("PythonQt.QtCore.Qt.AlignmentFlag")));
497 497 // check for a flags type wrapper
498 498 QVERIFY(PythonQtObjectPtr(_main.getVariable("PythonQt.QtCore.Qt.Alignment")));
499 499 }
500 500
501 501 void PythonQtTestApi::testConnects()
502 502 {
503 503 // QVERIFY((qvariant_vast<QColor>(_main.evalScript("PythonQt.Qt.QColor(PythonQt.Qt.Qt.red)" ,Py_eval_input)) == QColor(Qt::red));
504 504 //TODO: add signal/slot connect both with QObject.connect and connect
505 505 }
506 506
507 507 void PythonQtTestApi::testQColorDecorators()
508 508 {
509 509 PythonQtObjectPtr colorClass = _main.getVariable("PythonQt.QtGui.QColor");
510 510 QVERIFY(colorClass);
511 511 // verify that the class is in the correct module
512 512 QVERIFY(colorClass.getVariable("__module__") == "PythonQt.QtGui");
513 513 // test on Qt module as well:
514 514 colorClass = _main.getVariable("PythonQt.Qt.QColor");
515 515 QVERIFY(colorClass);
516 516 // constructors
517 517 QVERIFY(qvariant_cast<QColor>(colorClass.call(QVariantList() << 1 << 2 << 3)) == QColor(1,2,3));
518 518 QVERIFY(qvariant_cast<QColor>(colorClass.call()) == QColor());
519 519 QEXPECT_FAIL("", "Testing non-existing constructor", Continue);
520 520 QVERIFY(colorClass.call(QVariantList() << 1 << 2) != QVariant());
521 521
522 522 // check that enum overload is taken over int
523 523 QVERIFY(qvariant_cast<QColor>(_main.evalScript("PythonQt.Qt.QColor(PythonQt.Qt.Qt.red)" ,Py_eval_input)) == QColor(Qt::red));
524 524 // check that int overload is taken over enum
525 525 QVERIFY(qvariant_cast<QColor>(_main.evalScript("PythonQt.Qt.QColor(0x112233)" ,Py_eval_input)) == QColor(0x112233));
526 526
527 527 // check for decorated Cmyk enum value
528 528 QVERIFY(colorClass.getVariable("Cmyk").toInt() == QColor::Cmyk);
529 529 PythonQtObjectPtr staticMethod = colorClass.getVariable("fromRgb");
530 530 QVERIFY(staticMethod);
531 531 // direct call of static method via class
532 532 QVERIFY(qvariant_cast<QColor>(colorClass.call("fromRgb", QVariantList() << 1 << 2 << 3)) == QColor(1,2,3));
533 533 // direct call of static method
534 534 QVERIFY(qvariant_cast<QColor>(staticMethod.call(QVariantList() << 1 << 2 << 3)) == QColor(1,2,3));
535 535 PythonQtObjectPtr publicMethod = colorClass.getVariable("red");
536 536 QVERIFY(publicMethod);
537 537 // call with passing self in:
538 538 QVERIFY(colorClass.call("red", QVariantList() << QColor(255,0,0)).toInt() == 255);
539 539 }
540 540
541 541 QByteArray PythonQtTestApiHelper::readFileAsBytes(const QString& filename)
542 542 {
543 543 QByteArray b;
544 544 return b;
545 545 }
546 546
547 547 QByteArray PythonQtTestApiHelper::readSourceFile(const QString& filename, bool& ok)
548 548 {
549 549 QByteArray b;
550 550 ok = true;
551 551 return b;
552 552 }
553 553
554 554 bool PythonQtTestApiHelper::exists(const QString& filename)
555 555 {
556 556 return true;
557 557 }
558 558
559 559 QDateTime PythonQtTestApiHelper::lastModifiedDate(const QString& filename) {
560 560 return QDateTime::currentDateTime();
561 561 }
562 562
563 563
564 564 void PythonQtTestApi::testRedirect()
565 565 {
566 566 connect(PythonQt::self(), SIGNAL(pythonStdOut(const QString&)), _helper, SLOT(stdOut(const QString&)));
567 567 connect(PythonQt::self(), SIGNAL(pythonStdErr(const QString&)), _helper, SLOT(stdErr(const QString&)));
568 PyRun_SimpleString("print 'test'\n");
568 PyRun_SimpleString("print ('test')\n");
569 569 }
570 570
571 571 void PythonQtTestApiHelper::stdOut(const QString& s)
572 572 {
573 qDebug() << s;
573 outBuf.append(s);
574 QStringList x = outBuf.split("\n");
575 outBuf = x.takeLast();
576 foreach(QString s, x)
577 qDebug() << s;
574 578 }
575 579
576 580 void PythonQtTestApiHelper::stdErr(const QString& s)
577 581 {
578 qDebug() << s;
582 errBuf.append(s);
583 QStringList x = errBuf.split("\n");
584 errBuf = x.takeLast();
585 foreach(QString s, x)
586 qDebug() << s;
579 587 }
580 588
581 589 QObject* PythonQtTestCppFactory::create(const QByteArray& name, void *ptr)
582 590 {
583 591 if (name == "PQCppObject") {
584 592 return new PQCppObjectWrapper(ptr);
585 593 }
586 594 return NULL;
587 595 }
@@ -1,515 +1,517
1 1 #ifndef _PYTHONQTTESTS_H
2 2 #define _PYTHONQTTESTS_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 PythonQtTests.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 "PythonQt.h"
46 46 #include <QtTest/QtTest>
47 47 #include <QVariant>
48 48 #include "PythonQtImportFileInterface.h"
49 49 #include "PythonQtCppWrapperFactory.h"
50 50
51 51 #include <QPen>
52 52 #include <QColor>
53 53 #include <QBrush>
54 54 #include <QCursor>
55 55
56 56 class PythonQtTestSlotCallingHelper;
57 57 class PythonQtTestApiHelper;
58 58 class QWidget;
59 59
60 60 //! test the PythonQt api
61 61 class PythonQtTestApi : public QObject
62 62 {
63 63 Q_OBJECT
64 64
65 65 private slots:
66 66 void initTestCase();
67 67 void testCall();
68 68 void testVariables();
69 69 void testRedirect();
70 70 void testImporter();
71 71 void testQColorDecorators();
72 72 void testQtNamespace();
73 73 void testConnects();
74 74
75 75 void testProperties();
76 76 void testDynamicProperties();
77 77
78 78 private:
79 79 PythonQtTestApiHelper* _helper;
80 80 PythonQtObjectPtr _main;
81 81
82 82 };
83 83
84 84 class ClassA {
85 85 public:
86 86 ClassA() { x = 1; }
87 87 int x;
88 88 };
89 89
90 90 class ClassB {
91 91 public:
92 92 ClassB() { y = 2; }
93 93 int y;
94 94
95 95 virtual int type() { return 2; }
96 96 };
97 97
98 98 class ClassC : public ClassA, public ClassB {
99 99 public:
100 100 ClassC() { z = 3; }
101 101 int z;
102 102
103 103 virtual int type() { return 3; }
104 104 };
105 105
106 106 class ClassD : public QObject, public ClassA, public ClassB {
107 107 Q_OBJECT
108 108 public:
109 109 ClassD() { d = 4; }
110 110 public slots:
111 111 int getD() { return d; }
112 112 private:
113 113 int d;
114 114
115 115 virtual int type() { return 4; }
116 116 };
117 117
118 118 class ClassAWrapper : public QObject {
119 119 Q_OBJECT
120 120 public slots:
121 121 ClassA* new_ClassA() { return new ClassA; }
122 122 int getX(ClassA* o) { return o->x; }
123 123 };
124 124
125 125 class ClassBWrapper : public QObject {
126 126 Q_OBJECT
127 127 public slots:
128 128 ClassB* new_ClassB() { return new ClassB; }
129 129 int getY(ClassB* o) { return o->y; }
130 130 };
131 131
132 132 class ClassCWrapper : public QObject {
133 133 Q_OBJECT
134 134 public slots:
135 135 ClassC* new_ClassC() { return new ClassC; }
136 136 int getZ(ClassC* o) { return o->z; }
137 137 };
138 138
139 139 class ClassDWrapper : public QObject {
140 140 Q_OBJECT
141 141 public slots:
142 142 ClassD* new_ClassD() { return new ClassD; }
143 143 };
144 144
145 145
146 146 //! test the PythonQt api (helper)
147 147 class PythonQtTestApiHelper : public QObject , public PythonQtImportFileInterface
148 148 {
149 149 Q_OBJECT
150 150 public:
151 151 PythonQtTestApiHelper() {
152 152 };
153 153
154 154 bool call(const QString& function, const QVariantList& args, const QVariant& expectedResult);
155 155
156 156 virtual QByteArray readFileAsBytes(const QString& filename);
157 157
158 158 virtual QByteArray readSourceFile(const QString& filename, bool& ok);
159 159
160 160 virtual bool exists(const QString& filename);
161 161
162 162 virtual QDateTime lastModifiedDate(const QString& filename);
163 163
164 164 public slots:
165 165
166 166 //! call to set that the test has passed (from Python!)
167 167 void setPassed() { _passed = true; }
168 168
169 169 void stdOut(const QString&);
170 170 void stdErr(const QString&);
171 171
172 172 private:
173 QString outBuf;
174 QString errBuf;
173 175 bool _passed;
174 176 };
175 177
176 178
177 179 // test implementation of the wrapper factory
178 180 class PythonQtTestCppFactory : public PythonQtCppWrapperFactory
179 181 {
180 182 public:
181 183 virtual QObject* create(const QByteArray& name, void *ptr);
182 184 };
183 185
184 186 //! an cpp object to be wrapped
185 187 class PQCppObject {
186 188
187 189 public:
188 190 PQCppObject(int h) { _height = h; }
189 191
190 192 int getHeight() { return _height; }
191 193 void setHeight(int h) { _height = h; }
192 194
193 195 private:
194 196 int _height;
195 197 };
196 198
197 199 //! an qobject that wraps the existing cpp object
198 200 class PQCppObjectWrapper : public QObject {
199 201 Q_OBJECT
200 202 public:
201 203 PQCppObjectWrapper(void* ptr) {
202 204 _ptr = (PQCppObject*)ptr;
203 205 }
204 206
205 207 public slots:
206 208 int getHeight() { return _ptr->getHeight(); }
207 209 void setHeight(int h) { _ptr->setHeight(h); }
208 210
209 211 private:
210 212 PQCppObject* _ptr;
211 213 };
212 214
213 215 class PQCppObjectDecorator : public QObject {
214 216 Q_OBJECT
215 217 public slots:
216 218 int getH(PQCppObject* obj) { return obj->getHeight(); }
217 219
218 220 };
219 221
220 222 //! an cpp object to be wrapped by decorators only
221 223 class PQCppObjectNoWrap {
222 224
223 225 public:
224 226 PQCppObjectNoWrap() { _height = 0; }
225 227 PQCppObjectNoWrap(int h) { _height = h; }
226 228
227 229 int getHeight() { return _height; }
228 230 void setHeight(int h) { _height = h; }
229 231
230 232 private:
231 233 int _height;
232 234 };
233 235
234 236 class PQCppObjectNoWrapDecorator : public QObject {
235 237 Q_OBJECT
236 238
237 239 public slots:
238 240 PQCppObjectNoWrap* new_PQCppObjectNoWrap() {
239 241 return new PQCppObjectNoWrap(0);
240 242 }
241 243 PQCppObjectNoWrap* new_PQCppObjectNoWrap(const PQCppObjectNoWrap& other) {
242 244 return new PQCppObjectNoWrap(1);
243 245 }
244 246 PQCppObjectNoWrap* new_PQCppObjectNoWrap(double value) {
245 247 return new PQCppObjectNoWrap(2);
246 248 }
247 249
248 250 int getH(PQCppObjectNoWrap* obj) { return obj->getHeight(); }
249 251
250 252 };
251 253
252 254
253 255 //! an cpp object that is to be wrapped by decorators only
254 256 class PQCppObject2 {
255 257
256 258 public:
257 259 enum TestEnumFlag {
258 260 TestEnumValue1 = 0,
259 261 TestEnumValue2 = 1
260 262 };
261 263
262 264 PQCppObject2() {}
263 265
264 266 };
265 267
266 268 class PQCppObject2Decorator : public QObject {
267 269 Q_OBJECT
268 270
269 271 public:
270 272 Q_ENUMS(TestEnumFlag)
271 273 Q_FLAGS(TestEnum)
272 274
273 275 enum TestEnumFlag {
274 276 TestEnumValue1 = 0,
275 277 TestEnumValue2 = 1
276 278 };
277 279
278 280 Q_DECLARE_FLAGS(TestEnum, TestEnumFlag)
279 281
280 282 public slots:
281 283 PQCppObject2* new_PQCppObject2() {
282 284 return new PQCppObject2();
283 285 }
284 286
285 287 TestEnumFlag testEnumFlag1(PQCppObject2* obj, TestEnumFlag flag);
286 288
287 289 PQCppObject2::TestEnumFlag testEnumFlag2(PQCppObject2* obj, PQCppObject2::TestEnumFlag flag);
288 290
289 291 // with int overload
290 292 TestEnumFlag testEnumFlag3(PQCppObject2* obj, int flag);
291 293 TestEnumFlag testEnumFlag3(PQCppObject2* obj, TestEnumFlag flag);
292 294
293 295 };
294 296
295 297 class PQUnknownValueObject
296 298 {
297 299 public:
298 300 PQUnknownValueObject() {};
299 301 };
300 302
301 303 class PQUnknownButRegisteredValueObject
302 304 {
303 305 public:
304 306 PQUnknownButRegisteredValueObject() {};
305 307 };
306 308
307 309 //! test the calling of slots
308 310 class PythonQtTestSlotCalling : public QObject
309 311 {
310 312 Q_OBJECT
311 313
312 314 private slots:
313 315 void initTestCase();
314 316 void init();
315 317
316 318 void testNoArgSlotCall();
317 319 void testPODSlotCalls();
318 320 void testCPPSlotCalls();
319 321 void testQVariantSlotCalls();
320 322 void testObjectSlotCalls();
321 323 void testMultiArgsSlotCall();
322 324 void testPyObjectSlotCall();
323 325 void testOverloadedCall();
324 326 void testCppFactory();
325 327 void testInheritance();
326 328 void testAutoConversion();
327 329
328 330 private:
329 331 PythonQtTestSlotCallingHelper* _helper;
330 332
331 333 };
332 334
333 335 //! helper class for slot calling test
334 336 class PythonQtTestSlotCallingHelper : public QObject
335 337 {
336 338 Q_OBJECT
337 339 public:
338 340 PythonQtTestSlotCallingHelper(PythonQtTestSlotCalling* test) {
339 341 _test = test;
340 342 };
341 343
342 344 bool runScript(const char* script, int expectedOverload = -1);
343 345
344 346 public slots:
345 347
346 348 //! call to set that the test has passed (from Python!)
347 349 void setPassed() { _passed = true; }
348 350
349 351 //! no arguments, no return value:
350 352 void testNoArg() { _called = true; }
351 353
352 354 //! overload test!
353 355 void overload(bool a) { _calledOverload = 0; _called = true; }
354 356 void overload(float a) { _calledOverload = 1; _called = true;}
355 357 void overload(int a) { _calledOverload = 2; _called = true;}
356 358 void overload(const QString& str) { _calledOverload = 3; _called = true;}
357 359 void overload(const QStringList& str) { _calledOverload = 4; _called = true;}
358 360 void overload(QObject* str) { _calledOverload = 5; _called = true;}
359 361 void overload(float a, int b) { _calledOverload = 6; _called = true;}
360 362
361 363 //! POD values:
362 364 int getInt(int a) { _called = true; return a; }
363 365 unsigned int getUInt(unsigned int a) { _called = true; return a; }
364 366 bool getBool(bool a) { _called = true; return a; }
365 367 char getChar(char a) { _called = true; return a; }
366 368 unsigned char getUChar(unsigned char a) { _called = true; return a; }
367 369 long getLong(long a) { _called = true; return a; }
368 370 unsigned long getULong(unsigned long a) { _called = true; return a; }
369 371 short getShort(short a) { _called = true; return a; }
370 372 unsigned short getUShort(unsigned short a) { _called = true; return a; }
371 373 QChar getQChar(QChar a) { _called = true; return a; }
372 374 qint64 getLongLong(qint64 a) { _called = true; return a; }
373 375 quint64 getULongLong(quint64 a) { _called = true; return a; }
374 376 double getDouble(double d) { _called = true; return d; }
375 377 float getFloat(float d) { _called = true; return d; }
376 378
377 379 //! important qt types:
378 380 QString getQString(const QString& s) { _called = true; return s; }
379 381 QStringList getQStringList(const QStringList& l) { _called = true; return l; }
380 382 QVariant getQVariant(const QVariant& var) { _called = true; return var; }
381 383
382 384 // QColor as representative for C++ value classes
383 385 QColor getQColor1(const QColor& var) { _called = true; return var; }
384 386 QColor getQColor2(QColor& var) { _called = true; return var; }
385 387 QColor getQColor3(QColor* col) { _called = true; return *col; }
386 388 QColor getQColor4(const QVariant& color) { _called = true; return color.value<QColor>(); }
387 389 QColor* getQColor5() { _called = true; static QColor c(1,2,3); return &c; }
388 390
389 391 PyObject* getPyObject(PyObject* obj) { _called = true; return obj; }
390 392 PyObject* getPyObjectFromVariant(const QVariant& val) { _called = true; return PythonQtObjectPtr(val); }
391 393 QVariant getPyObjectFromVariant2(const QVariant& val) { _called = true; return val; }
392 394 // this does not yet work but is not required to work:
393 395 //PyObject* getPyObjectFromPtr(const PythonQtObjectPtr& val) { _called = true; return val; };
394 396
395 397 //! testing pointer passing
396 398 PythonQtTestSlotCallingHelper* getTestObject(PythonQtTestSlotCallingHelper* obj) { _called = true; return obj; }
397 399 //! testing inheritance checking
398 400 QObject* getQObject(QObject* obj) { _called = true; return obj; }
399 401 QWidget* getQWidget(QWidget* obj) { _called = true; return obj; }
400 402 //! testing if an object that was not wrapped is wrapped earlier is wrapped correctly
401 403 QObject* getNewObject() { _called = true; return new PythonQtTestSlotCallingHelper(NULL); }
402 404
403 405 QVariantList getMultiArgs(int a, double b, const QString& str) { _called = true; return (QVariantList() << a << b << str); }
404 406
405 407 //! cpp wrapper factory test
406 408 PQCppObject* createPQCppObject(int h) { _called = true; return new PQCppObject(h); }
407 409
408 410 //! cpp wrapper factory test
409 411 PQCppObject* getPQCppObject(PQCppObject* p) { _called = true; return p; }
410 412
411 413 //! cpp wrapper factory test
412 414 PQCppObjectNoWrap* createPQCppObjectNoWrap(int h) { _called = true; return new PQCppObjectNoWrap(h); }
413 415
414 416 //! cpp wrapper factory test
415 417 PQCppObjectNoWrap* getPQCppObjectNoWrap(PQCppObjectNoWrap* p) { _called = true; return p; }
416 418
417 419 //! get a return by value PQCppObjectNoWrap
418 420 PQCppObjectNoWrap getPQCppObjectNoWrapAsValue() { _called = true; return PQCppObjectNoWrap(47); }
419 421
420 422 PQUnknownButRegisteredValueObject getUnknownButRegisteredValueObjectAsValue() { _called = true; return PQUnknownButRegisteredValueObject(); }
421 423 PQUnknownValueObject getUnknownValueObjectAsValue() { _called = true; return PQUnknownValueObject(); }
422 424
423 425 PQUnknownButRegisteredValueObject* getUnknownButRegisteredValueObjectAsPtr() { _called = true; return new PQUnknownButRegisteredValueObject(); }
424 426 PQUnknownValueObject* getUnknownValueObjectAsPtr() { _called = true; return new PQUnknownValueObject(); }
425 427
426 428 ClassA* getClassAPtr(ClassA* o) { _called = true; return o; }
427 429 ClassB* getClassBPtr(ClassB* o) { _called = true; return o; }
428 430 ClassC* getClassCPtr(ClassC* o) { _called = true; return o; }
429 431 ClassD* getClassDPtr(ClassD* o) { _called = true; return o; }
430 432
431 433 ClassA* createClassA() { _called = true; return new ClassA; }
432 434 ClassB* createClassB() { _called = true; return new ClassB; }
433 435 ClassC* createClassC() { _called = true; return new ClassC; }
434 436 ClassD* createClassD() { _called = true; return new ClassD; }
435 437 ClassA* createClassCAsA() { _called = true; return new ClassC; }
436 438 ClassB* createClassCAsB() { _called = true; return new ClassC; }
437 439 ClassA* createClassDAsA() { _called = true; return new ClassD; }
438 440 ClassB* createClassDAsB() { _called = true; return new ClassD; }
439 441
440 442 QColor setAutoConvertColor(const QColor& color) { _called = true; return color; };
441 443 QBrush setAutoConvertBrush(const QBrush& brush) { _called = true; return brush; };
442 444 QPen setAutoConvertPen(const QPen& pen) { _called = true; return pen; };
443 445 QCursor setAutoConvertCursor(const QCursor& cursor) { _called = true; return cursor; };
444 446
445 447 private:
446 448 bool _passed;
447 449 bool _called;
448 450 int _calledOverload;
449 451 PythonQtTestSlotCalling* _test;
450 452 };
451 453
452 454 class PythonQtTestSignalHandlerHelper;
453 455
454 456 //! test the connection of signals to python
455 457 class PythonQtTestSignalHandler : public QObject
456 458 {
457 459 Q_OBJECT
458 460
459 461 private slots:
460 462 void initTestCase();
461 463
462 464 void testSignalHandler();
463 465 void testRecursiveSignalHandler();
464 466
465 467 private:
466 468 PythonQtTestSignalHandlerHelper* _helper;
467 469
468 470 };
469 471
470 472 //! helper class for signal testing
471 473 class PythonQtTestSignalHandlerHelper : public QObject
472 474 {
473 475 Q_OBJECT
474 476
475 477 public:
476 478 PythonQtTestSignalHandlerHelper(PythonQtTestSignalHandler* test) {
477 479 _test = test;
478 480 };
479 481
480 482 public slots:
481 483 void setPassed() { _passed = true; }
482 484
483 485 bool emitIntSignal(int a) { _passed = false; emit intSignal(a); return _passed; };
484 486 bool emitFloatSignal(float a) { _passed = false; emit floatSignal(a); return _passed; };
485 487 bool emitEnumSignal(PQCppObject2::TestEnumFlag flag) { _passed = false; emit enumSignal(flag); return _passed; };
486 488
487 489 bool emitVariantSignal(const QVariant& v) { _passed = false; emit variantSignal(v); return _passed; };
488 490 QVariant expectedVariant() { return _v; }
489 491 void setExpectedVariant(const QVariant& v) { _v = v; }
490 492
491 493 bool emitComplexSignal(int a, float b, const QStringList& l, QObject* obj) { _passed = false; emit complexSignal(a,b,l,obj); return _passed; };
492 494
493 495 bool emitSignal1(int a) { _passed = false; emit signal1(a); return _passed; };
494 496 bool emitSignal2(const QString& s) { _passed = false; emit signal2(s); return _passed; };
495 497 bool emitSignal3(float a) { _passed = false; emit signal3(a); return _passed; };
496 498
497 499 signals:
498 500 void intSignal(int);
499 501 void floatSignal(float);
500 502 void variantSignal(const QVariant& v);
501 503 void complexSignal(int a, float b, const QStringList& l, QObject* obj);
502 504 void enumSignal(PQCppObject2::TestEnumFlag flag);
503 505
504 506 void signal1(int);
505 507 void signal2(const QString&);
506 508 void signal3(float);
507 509
508 510 private:
509 511 bool _passed;
510 512 QVariant _v;
511 513
512 514 PythonQtTestSignalHandler* _test;
513 515 };
514 516
515 517 #endif
General Comments 0
You need to be logged in to leave comments. Login now