##// END OF EJS Templates
added support for std::exception handling...
florianlink -
r159:aaeb49c23826
parent child
Show More
@@ -1,526 +1,556
1 /*
1 /*
2 *
2 *
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 *
4 *
5 * This library is free software; you can redistribute it and/or
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
8 * version 2.1 of the License, or (at your option) any later version.
9 *
9 *
10 * This library is distributed in the hope that it will be useful,
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
13 * Lesser General Public License for more details.
14 *
14 *
15 * Further, this software is distributed without any warranty that it is
15 * Further, this software is distributed without any warranty that it is
16 * free of the rightful claim of any third person regarding infringement
16 * free of the rightful claim of any third person regarding infringement
17 * or the like. Any license provided herein, whether implied or
17 * or the like. Any license provided herein, whether implied or
18 * otherwise, applies only to this software file. Patent licenses, if
18 * otherwise, applies only to this software file. Patent licenses, if
19 * any, provided herein do not apply to combinations of this program with
19 * any, provided herein do not apply to combinations of this program with
20 * other software, or any other product whatsoever.
20 * other software, or any other product whatsoever.
21 *
21 *
22 * You should have received a copy of the GNU Lesser General Public
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
25 *
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 * 28359 Bremen, Germany or:
27 * 28359 Bremen, Germany or:
28 *
28 *
29 * http://www.mevis.de
29 * http://www.mevis.de
30 *
30 *
31 */
31 */
32
32
33 //----------------------------------------------------------------------------------
33 //----------------------------------------------------------------------------------
34 /*!
34 /*!
35 // \file PythonQtSlot.cpp
35 // \file PythonQtSlot.cpp
36 // \author Florian Link
36 // \author Florian Link
37 // \author Last changed by $Author: florian $
37 // \author Last changed by $Author: florian $
38 // \date 2006-05
38 // \date 2006-05
39 */
39 */
40 //----------------------------------------------------------------------------------
40 //----------------------------------------------------------------------------------
41
41
42 #include "PythonQt.h"
42 #include "PythonQt.h"
43 #include "PythonQtSlot.h"
43 #include "PythonQtSlot.h"
44 #include "PythonQtInstanceWrapper.h"
44 #include "PythonQtInstanceWrapper.h"
45 #include "PythonQtClassInfo.h"
45 #include "PythonQtClassInfo.h"
46 #include "PythonQtMisc.h"
46 #include "PythonQtMisc.h"
47 #include "PythonQtConversion.h"
47 #include "PythonQtConversion.h"
48 #include <iostream>
48 #include <iostream>
49
49
50 #include <exception>
51 #include <stdexcept>
52
50 #define PYTHONQT_MAX_ARGS 32
53 #define PYTHONQT_MAX_ARGS 32
51
54
52
55
53 bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer)
56 bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer)
54 {
57 {
55 static unsigned int recursiveEntry = 0;
58 static unsigned int recursiveEntry = 0;
56
59
57 if (directReturnValuePointer) {
60 if (directReturnValuePointer) {
58 *directReturnValuePointer = NULL;
61 *directReturnValuePointer = NULL;
59 }
62 }
60 // store the current storage position, so that we can get back to this state after a slot is called
63 // store the current storage position, so that we can get back to this state after a slot is called
61 // (do this locally, so that we have all positions on the stack
64 // (do this locally, so that we have all positions on the stack
62 PythonQtValueStoragePosition globalValueStoragePos;
65 PythonQtValueStoragePosition globalValueStoragePos;
63 PythonQtValueStoragePosition globalPtrStoragePos;
66 PythonQtValueStoragePosition globalPtrStoragePos;
64 PythonQtValueStoragePosition globalVariantStoragePos;
67 PythonQtValueStoragePosition globalVariantStoragePos;
65 PythonQtConv::global_valueStorage.getPos(globalValueStoragePos);
68 PythonQtConv::global_valueStorage.getPos(globalValueStoragePos);
66 PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos);
69 PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos);
67 PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos);
70 PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos);
68
71
69 recursiveEntry++;
72 recursiveEntry++;
70
73
71 // the arguments that are passed to qt_metacall
74 // the arguments that are passed to qt_metacall
72 void* argList[PYTHONQT_MAX_ARGS];
75 void* argList[PYTHONQT_MAX_ARGS];
73 PyObject* result = NULL;
76 PyObject* result = NULL;
74 int argc = info->parameterCount();
77 int argc = info->parameterCount();
75 const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters();
78 const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters();
76
79
77 const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);
80 const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);
78 // set return argument to NULL
81 // set return argument to NULL
79 argList[0] = NULL;
82 argList[0] = NULL;
80
83
81 bool ok = true;
84 bool ok = true;
82 bool skipFirst = false;
85 bool skipFirst = false;
83 if (info->isInstanceDecorator()) {
86 if (info->isInstanceDecorator()) {
84 skipFirst = true;
87 skipFirst = true;
85
88
86 // for decorators on CPP objects, we take the cpp ptr, for QObjects we take the QObject pointer
89 // for decorators on CPP objects, we take the cpp ptr, for QObjects we take the QObject pointer
87 void* arg1 = firstArgument;
90 void* arg1 = firstArgument;
88 if (!arg1) {
91 if (!arg1) {
89 arg1 = objectToCall;
92 arg1 = objectToCall;
90 }
93 }
91 if (arg1) {
94 if (arg1) {
92 // upcast to correct parent class
95 // upcast to correct parent class
93 arg1 = ((char*)arg1)+info->upcastingOffset();
96 arg1 = ((char*)arg1)+info->upcastingOffset();
94 }
97 }
95
98
96 argList[1] = &arg1;
99 argList[1] = &arg1;
97 if (ok) {
100 if (ok) {
98 for (int i = 2; i<argc && ok; i++) {
101 for (int i = 2; i<argc && ok; i++) {
99 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
102 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
100 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, classInfo);
103 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, classInfo);
101 if (argList[i]==NULL) {
104 if (argList[i]==NULL) {
102 ok = false;
105 ok = false;
103 break;
106 break;
104 }
107 }
105 }
108 }
106 }
109 }
107 } else {
110 } else {
108 for (int i = 1; i<argc && ok; i++) {
111 for (int i = 1; i<argc && ok; i++) {
109 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
112 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
110 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, classInfo);
113 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, classInfo);
111 if (argList[i]==NULL) {
114 if (argList[i]==NULL) {
112 ok = false;
115 ok = false;
113 break;
116 break;
114 }
117 }
115 }
118 }
116 }
119 }
117
120
118 if (ok) {
121 if (ok) {
119 // parameters are ok, now create the qt return value which is assigned to by metacall
122 // parameters are ok, now create the qt return value which is assigned to by metacall
120 if (returnValueParam.typeId != QMetaType::Void) {
123 if (returnValueParam.typeId != QMetaType::Void) {
121 // create empty default value for the return value
124 // create empty default value for the return value
122 if (!directReturnValuePointer) {
125 if (!directReturnValuePointer) {
123 // create empty default value for the return value
126 // create empty default value for the return value
124 argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);
127 argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);
125 if (argList[0]==NULL) {
128 if (argList[0]==NULL) {
126 // 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
129 // 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
127 // pass its internal pointer
130 // pass its internal pointer
128 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(returnValueParam.name);
131 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(returnValueParam.name);
129 if (info && info->pythonQtClassWrapper()) {
132 if (info && info->pythonQtClassWrapper()) {
130 PyObject* emptyTuple = PyTuple_New(0);
133 PyObject* emptyTuple = PyTuple_New(0);
131 // 1) default construct an empty object as python object (owned by PythonQt), by calling the meta class with empty arguments
134 // 1) default construct an empty object as python object (owned by PythonQt), by calling the meta class with empty arguments
132 result = PyObject_Call((PyObject*)info->pythonQtClassWrapper(), emptyTuple, NULL);
135 result = PyObject_Call((PyObject*)info->pythonQtClassWrapper(), emptyTuple, NULL);
133 if (result) {
136 if (result) {
134 argList[0] = ((PythonQtInstanceWrapper*)result)->_wrappedPtr;
137 argList[0] = ((PythonQtInstanceWrapper*)result)->_wrappedPtr;
135 }
138 }
136 Py_DECREF(emptyTuple);
139 Py_DECREF(emptyTuple);
137 }
140 }
138 }
141 }
139 } else {
142 } else {
140 // we can use our pointer directly!
143 // we can use our pointer directly!
141 argList[0] = directReturnValuePointer;
144 argList[0] = directReturnValuePointer;
142 }
145 }
143 }
146 }
144
147
145
148
146 PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB();
149 PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB();
147 if (profilingCB) {
150 if (profilingCB) {
148 const char* className = NULL;
151 const char* className = NULL;
149 if (info->decorator()) {
152 if (info->decorator()) {
150 className = info->decorator()->metaObject()->className();
153 className = info->decorator()->metaObject()->className();
151 } else {
154 } else {
152 className = objectToCall->metaObject()->className();
155 className = objectToCall->metaObject()->className();
153 }
156 }
154
157
155 profilingCB(PythonQt::Enter, className, info->metaMethod()->signature());
158 profilingCB(PythonQt::Enter, className, info->metaMethod()->signature());
156 }
159 }
157
160
158 // invoke the slot via metacall
161 // invoke the slot via metacall
162 bool hadException = false;
163 try {
159 (info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
164 (info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
165 } catch (std::bad_alloc & e) {
166 hadException = true;
167 QByteArray what("std::bad_alloc: ");
168 what += e.what();
169 PyErr_SetString(PyExc_MemoryError, what.constData());
170 } catch (std::runtime_error & e) {
171 hadException = true;
172 QByteArray what("std::runtime_error: ");
173 what += e.what();
174 PyErr_SetString(PyExc_RuntimeError, what.constData());
175 } catch (std::logic_error & e) {
176 hadException = true;
177 QByteArray what("std::logic_error: ");
178 what += e.what();
179 PyErr_SetString(PyExc_RuntimeError, what.constData());
180 } catch (std::exception& e) {
181 hadException = true;
182 QByteArray what("std::exception: ");
183 what += e.what();
184 PyErr_SetString(PyExc_StandardError, what.constData());
185 }
160
186
161 if (profilingCB) {
187 if (profilingCB) {
162 profilingCB(PythonQt::Leave, NULL, NULL);
188 profilingCB(PythonQt::Leave, NULL, NULL);
163 }
189 }
164
190
165 // handle the return value (which in most cases still needs to be converted to a Python object)
191 // handle the return value (which in most cases still needs to be converted to a Python object)
192 if (!hadException) {
166 if (argList[0] || returnValueParam.typeId == QMetaType::Void) {
193 if (argList[0] || returnValueParam.typeId == QMetaType::Void) {
167 if (directReturnValuePointer) {
194 if (directReturnValuePointer) {
168 result = NULL;
195 result = NULL;
169 } else {
196 } else {
170 // the resulting object maybe present already, because we created it above at 1)...
197 // the resulting object maybe present already, because we created it above at 1)...
171 if (!result) {
198 if (!result) {
172 result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]);
199 result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]);
173 }
200 }
174 }
201 }
175 } else {
202 } else {
176 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.";
203 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.";
177 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
204 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
178 result = NULL;
205 result = NULL;
179 }
206 }
207 } else {
208 result = NULL;
209 }
180 }
210 }
181 recursiveEntry--;
211 recursiveEntry--;
182
212
183 // reset the parameter storage position to the stored pos to "pop" the parameter stack
213 // reset the parameter storage position to the stored pos to "pop" the parameter stack
184 PythonQtConv::global_valueStorage.setPos(globalValueStoragePos);
214 PythonQtConv::global_valueStorage.setPos(globalValueStoragePos);
185 PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos);
215 PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos);
186 PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos);
216 PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos);
187
217
188 *pythonReturnValue = result;
218 *pythonReturnValue = result;
189 // NOTE: it is important to only return here, otherwise the stack will not be popped!!!
219 // NOTE: it is important to only return here, otherwise the stack will not be popped!!!
190 return result || (directReturnValuePointer && *directReturnValuePointer);
220 return result || (directReturnValuePointer && *directReturnValuePointer);
191 }
221 }
192
222
193 //-----------------------------------------------------------------------------------
223 //-----------------------------------------------------------------------------------
194
224
195 static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL;
225 static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL;
196
226
197 PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw)
227 PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw)
198 {
228 {
199 PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func;
229 PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func;
200 PythonQtSlotInfo* info = f->m_ml;
230 PythonQtSlotInfo* info = f->m_ml;
201 if (PyObject_TypeCheck(f->m_self, &PythonQtInstanceWrapper_Type)) {
231 if (PyObject_TypeCheck(f->m_self, &PythonQtInstanceWrapper_Type)) {
202 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self;
232 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self;
203 if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
233 if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
204 QString error = QString("Trying to call '") + f->m_ml->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
234 QString error = QString("Trying to call '") + f->m_ml->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
205 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
235 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
206 return NULL;
236 return NULL;
207 } else {
237 } else {
208 return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr);
238 return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr);
209 }
239 }
210 } else if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
240 } else if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
211 PythonQtClassWrapper* type = (PythonQtClassWrapper*) f->m_self;
241 PythonQtClassWrapper* type = (PythonQtClassWrapper*) f->m_self;
212 if (info->isClassDecorator()) {
242 if (info->isClassDecorator()) {
213 return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw);
243 return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw);
214 } else {
244 } else {
215 // otherwise, it is an unbound call and we have an instanceDecorator or normal slot...
245 // otherwise, it is an unbound call and we have an instanceDecorator or normal slot...
216 Py_ssize_t argc = PyTuple_Size(args);
246 Py_ssize_t argc = PyTuple_Size(args);
217 if (argc>0) {
247 if (argc>0) {
218 PyObject* firstArg = PyTuple_GET_ITEM(args, 0);
248 PyObject* firstArg = PyTuple_GET_ITEM(args, 0);
219 if (PyObject_TypeCheck(firstArg, (PyTypeObject*)&PythonQtInstanceWrapper_Type)
249 if (PyObject_TypeCheck(firstArg, (PyTypeObject*)&PythonQtInstanceWrapper_Type)
220 && ((PythonQtInstanceWrapper*)firstArg)->classInfo()->inherits(type->classInfo())) {
250 && ((PythonQtInstanceWrapper*)firstArg)->classInfo()->inherits(type->classInfo())) {
221 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg;
251 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg;
222 if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
252 if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
223 QString error = QString("Trying to call '") + f->m_ml->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
253 QString error = QString("Trying to call '") + f->m_ml->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
224 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
254 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
225 return NULL;
255 return NULL;
226 }
256 }
227 // strip the first argument...
257 // strip the first argument...
228 PyObject* newargs = PyTuple_GetSlice(args, 1, argc);
258 PyObject* newargs = PyTuple_GetSlice(args, 1, argc);
229 PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, newargs, kw, self->_wrappedPtr);
259 PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, newargs, kw, self->_wrappedPtr);
230 Py_DECREF(newargs);
260 Py_DECREF(newargs);
231 return result;
261 return result;
232 } else {
262 } else {
233 // first arg is not of correct type!
263 // first arg is not of correct type!
234 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument, got " + firstArg->ob_type->tp_name;
264 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument, got " + firstArg->ob_type->tp_name;
235 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
265 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
236 return NULL;
266 return NULL;
237 }
267 }
238 } else {
268 } else {
239 // wrong number of args
269 // wrong number of args
240 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument.";
270 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument.";
241 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
271 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
242 return NULL;
272 return NULL;
243 }
273 }
244 }
274 }
245 }
275 }
246 return NULL;
276 return NULL;
247 }
277 }
248
278
249 PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg, void** directReturnValuePointer)
279 PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg, void** directReturnValuePointer)
250 {
280 {
251 int argc = args?PyTuple_Size(args):0;
281 int argc = args?PyTuple_Size(args):0;
252
282
253 #ifdef PYTHONQT_DEBUG
283 #ifdef PYTHONQT_DEBUG
254 std::cout << "called " << info->metaMethod()->typeName() << " " << info->metaMethod()->signature() << std::endl;
284 std::cout << "called " << info->metaMethod()->typeName() << " " << info->metaMethod()->signature() << std::endl;
255 #endif
285 #endif
256
286
257 PyObject* r = NULL;
287 PyObject* r = NULL;
258 bool ok = false;
288 bool ok = false;
259 if (directReturnValuePointer) {
289 if (directReturnValuePointer) {
260 *directReturnValuePointer = NULL;
290 *directReturnValuePointer = NULL;
261 }
291 }
262 if (info->nextInfo()) {
292 if (info->nextInfo()) {
263 // overloaded slot call, try on all slots with strict conversion first
293 // overloaded slot call, try on all slots with strict conversion first
264 bool strict = true;
294 bool strict = true;
265 PythonQtSlotInfo* i = info;
295 PythonQtSlotInfo* i = info;
266 while (i) {
296 while (i) {
267 bool skipFirst = i->isInstanceDecorator();
297 bool skipFirst = i->isInstanceDecorator();
268 if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
298 if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
269 PyErr_Clear();
299 PyErr_Clear();
270 ok = PythonQtCallSlot(classInfo, objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer);
300 ok = PythonQtCallSlot(classInfo, objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer);
271 if (PyErr_Occurred() || ok) break;
301 if (PyErr_Occurred() || ok) break;
272 }
302 }
273 i = i->nextInfo();
303 i = i->nextInfo();
274 if (!i) {
304 if (!i) {
275 if (strict) {
305 if (strict) {
276 // one more run without being strict
306 // one more run without being strict
277 strict = false;
307 strict = false;
278 i = info;
308 i = info;
279 }
309 }
280 }
310 }
281 }
311 }
282 if (!ok && !PyErr_Occurred()) {
312 if (!ok && !PyErr_Occurred()) {
283 QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n");
313 QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n");
284 PythonQtSlotInfo* i = info;
314 PythonQtSlotInfo* i = info;
285 while (i) {
315 while (i) {
286 e += QString(i->fullSignature()) + "\n";
316 e += QString(i->fullSignature()) + "\n";
287 i = i->nextInfo();
317 i = i->nextInfo();
288 }
318 }
289 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
319 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
290 }
320 }
291 } else {
321 } else {
292 // simple (non-overloaded) slot call
322 // simple (non-overloaded) slot call
293 bool skipFirst = info->isInstanceDecorator();
323 bool skipFirst = info->isInstanceDecorator();
294 if (info->parameterCount()-1-(skipFirst?1:0) == argc) {
324 if (info->parameterCount()-1-(skipFirst?1:0) == argc) {
295 PyErr_Clear();
325 PyErr_Clear();
296 ok = PythonQtCallSlot(classInfo, objectToCall, args, false, info, firstArg, &r, directReturnValuePointer);
326 ok = PythonQtCallSlot(classInfo, objectToCall, args, false, info, firstArg, &r, directReturnValuePointer);
297 if (!ok && !PyErr_Occurred()) {
327 if (!ok && !PyErr_Occurred()) {
298 QString e = QString("Called ") + info->fullSignature() + " with wrong arguments: " + PythonQtConv::PyObjGetString(args);
328 QString e = QString("Called ") + info->fullSignature() + " with wrong arguments: " + PythonQtConv::PyObjGetString(args);
299 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
329 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
300 }
330 }
301 } else {
331 } else {
302 QString e = QString("Called ") + info->fullSignature() + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args);
332 QString e = QString("Called ") + info->fullSignature() + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args);
303 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
333 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
304 }
334 }
305 }
335 }
306
336
307 return r;
337 return r;
308 }
338 }
309
339
310 PyObject *
340 PyObject *
311 PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module)
341 PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module)
312 {
342 {
313 PythonQtSlotFunctionObject *op;
343 PythonQtSlotFunctionObject *op;
314 op = pythonqtslot_free_list;
344 op = pythonqtslot_free_list;
315 if (op != NULL) {
345 if (op != NULL) {
316 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self);
346 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self);
317 PyObject_INIT(op, &PythonQtSlotFunction_Type);
347 PyObject_INIT(op, &PythonQtSlotFunction_Type);
318 }
348 }
319 else {
349 else {
320 op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type);
350 op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type);
321 if (op == NULL)
351 if (op == NULL)
322 return NULL;
352 return NULL;
323 }
353 }
324 op->m_ml = ml;
354 op->m_ml = ml;
325 Py_XINCREF(self);
355 Py_XINCREF(self);
326 op->m_self = self;
356 op->m_self = self;
327 Py_XINCREF(module);
357 Py_XINCREF(module);
328 op->m_module = module;
358 op->m_module = module;
329 PyObject_GC_Track(op);
359 PyObject_GC_Track(op);
330 return (PyObject *)op;
360 return (PyObject *)op;
331 }
361 }
332
362
333 PythonQtSlotInfo*
363 PythonQtSlotInfo*
334 PythonQtSlotFunction_GetSlotInfo(PyObject *op)
364 PythonQtSlotFunction_GetSlotInfo(PyObject *op)
335 {
365 {
336 if (!PythonQtSlotFunction_Check(op)) {
366 if (!PythonQtSlotFunction_Check(op)) {
337 PyErr_BadInternalCall();
367 PyErr_BadInternalCall();
338 return NULL;
368 return NULL;
339 }
369 }
340 return ((PythonQtSlotFunctionObject *)op) -> m_ml;
370 return ((PythonQtSlotFunctionObject *)op) -> m_ml;
341 }
371 }
342
372
343 PyObject *
373 PyObject *
344 PythonQtSlotFunction_GetSelf(PyObject *op)
374 PythonQtSlotFunction_GetSelf(PyObject *op)
345 {
375 {
346 if (!PythonQtSlotFunction_Check(op)) {
376 if (!PythonQtSlotFunction_Check(op)) {
347 PyErr_BadInternalCall();
377 PyErr_BadInternalCall();
348 return NULL;
378 return NULL;
349 }
379 }
350 return ((PythonQtSlotFunctionObject *)op) -> m_self;
380 return ((PythonQtSlotFunctionObject *)op) -> m_self;
351 }
381 }
352
382
353 /* Methods (the standard built-in methods, that is) */
383 /* Methods (the standard built-in methods, that is) */
354
384
355 static void
385 static void
356 meth_dealloc(PythonQtSlotFunctionObject *m)
386 meth_dealloc(PythonQtSlotFunctionObject *m)
357 {
387 {
358 PyObject_GC_UnTrack(m);
388 PyObject_GC_UnTrack(m);
359 Py_XDECREF(m->m_self);
389 Py_XDECREF(m->m_self);
360 Py_XDECREF(m->m_module);
390 Py_XDECREF(m->m_module);
361 m->m_self = (PyObject *)pythonqtslot_free_list;
391 m->m_self = (PyObject *)pythonqtslot_free_list;
362 pythonqtslot_free_list = m;
392 pythonqtslot_free_list = m;
363 }
393 }
364
394
365 static PyObject *
395 static PyObject *
366 meth_get__doc__(PythonQtSlotFunctionObject * /*m*/, void * /*closure*/)
396 meth_get__doc__(PythonQtSlotFunctionObject * /*m*/, void * /*closure*/)
367 {
397 {
368 Py_INCREF(Py_None);
398 Py_INCREF(Py_None);
369 return Py_None;
399 return Py_None;
370 }
400 }
371
401
372 static PyObject *
402 static PyObject *
373 meth_get__name__(PythonQtSlotFunctionObject *m, void * /*closure*/)
403 meth_get__name__(PythonQtSlotFunctionObject *m, void * /*closure*/)
374 {
404 {
375 return PyString_FromString(m->m_ml->metaMethod()->signature());
405 return PyString_FromString(m->m_ml->metaMethod()->signature());
376 }
406 }
377
407
378 static int
408 static int
379 meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg)
409 meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg)
380 {
410 {
381 int err;
411 int err;
382 if (m->m_self != NULL) {
412 if (m->m_self != NULL) {
383 err = visit(m->m_self, arg);
413 err = visit(m->m_self, arg);
384 if (err)
414 if (err)
385 return err;
415 return err;
386 }
416 }
387 if (m->m_module != NULL) {
417 if (m->m_module != NULL) {
388 err = visit(m->m_module, arg);
418 err = visit(m->m_module, arg);
389 if (err)
419 if (err)
390 return err;
420 return err;
391 }
421 }
392 return 0;
422 return 0;
393 }
423 }
394
424
395 static PyObject *
425 static PyObject *
396 meth_get__self__(PythonQtSlotFunctionObject *m, void * /*closure*/)
426 meth_get__self__(PythonQtSlotFunctionObject *m, void * /*closure*/)
397 {
427 {
398 PyObject *self;
428 PyObject *self;
399 if (PyEval_GetRestricted()) {
429 if (PyEval_GetRestricted()) {
400 PyErr_SetString(PyExc_RuntimeError,
430 PyErr_SetString(PyExc_RuntimeError,
401 "method.__self__ not accessible in restricted mode");
431 "method.__self__ not accessible in restricted mode");
402 return NULL;
432 return NULL;
403 }
433 }
404 self = m->m_self;
434 self = m->m_self;
405 if (self == NULL)
435 if (self == NULL)
406 self = Py_None;
436 self = Py_None;
407 Py_INCREF(self);
437 Py_INCREF(self);
408 return self;
438 return self;
409 }
439 }
410
440
411 static PyGetSetDef meth_getsets [] = {
441 static PyGetSetDef meth_getsets [] = {
412 {"__doc__", (getter)meth_get__doc__, NULL, NULL},
442 {"__doc__", (getter)meth_get__doc__, NULL, NULL},
413 {"__name__", (getter)meth_get__name__, NULL, NULL},
443 {"__name__", (getter)meth_get__name__, NULL, NULL},
414 {"__self__", (getter)meth_get__self__, NULL, NULL},
444 {"__self__", (getter)meth_get__self__, NULL, NULL},
415 {NULL, NULL, NULL,NULL},
445 {NULL, NULL, NULL,NULL},
416 };
446 };
417
447
418 #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6
448 #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6
419 #define PY_WRITE_RESTRICTED WRITE_RESTRICTED
449 #define PY_WRITE_RESTRICTED WRITE_RESTRICTED
420 #endif
450 #endif
421
451
422 #define OFF(x) offsetof(PythonQtSlotFunctionObject, x)
452 #define OFF(x) offsetof(PythonQtSlotFunctionObject, x)
423
453
424 static PyMemberDef meth_members[] = {
454 static PyMemberDef meth_members[] = {
425 {"__module__", T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED},
455 {"__module__", T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED},
426 {NULL}
456 {NULL}
427 };
457 };
428
458
429 static PyObject *
459 static PyObject *
430 meth_repr(PythonQtSlotFunctionObject *f)
460 meth_repr(PythonQtSlotFunctionObject *f)
431 {
461 {
432 if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
462 if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
433 PythonQtClassWrapper* self = (PythonQtClassWrapper*) f->m_self;
463 PythonQtClassWrapper* self = (PythonQtClassWrapper*) f->m_self;
434 return PyString_FromFormat("<unbound qt slot %s of %s type>",
464 return PyString_FromFormat("<unbound qt slot %s of %s type>",
435 f->m_ml->slotName().data(),
465 f->m_ml->slotName().data(),
436 self->classInfo()->className());
466 self->classInfo()->className());
437 } else {
467 } else {
438 return PyString_FromFormat("<qt slot %s of %s instance at %p>",
468 return PyString_FromFormat("<qt slot %s of %s instance at %p>",
439 f->m_ml->slotName().data(),
469 f->m_ml->slotName().data(),
440 f->m_self->ob_type->tp_name,
470 f->m_self->ob_type->tp_name,
441 f->m_self);
471 f->m_self);
442 }
472 }
443 }
473 }
444
474
445 static int
475 static int
446 meth_compare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b)
476 meth_compare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b)
447 {
477 {
448 if (a->m_self != b->m_self)
478 if (a->m_self != b->m_self)
449 return (a->m_self < b->m_self) ? -1 : 1;
479 return (a->m_self < b->m_self) ? -1 : 1;
450 if (a->m_ml == b->m_ml)
480 if (a->m_ml == b->m_ml)
451 return 0;
481 return 0;
452 if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0)
482 if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0)
453 return -1;
483 return -1;
454 else
484 else
455 return 1;
485 return 1;
456 }
486 }
457
487
458 static long
488 static long
459 meth_hash(PythonQtSlotFunctionObject *a)
489 meth_hash(PythonQtSlotFunctionObject *a)
460 {
490 {
461 long x,y;
491 long x,y;
462 if (a->m_self == NULL)
492 if (a->m_self == NULL)
463 x = 0;
493 x = 0;
464 else {
494 else {
465 x = PyObject_Hash(a->m_self);
495 x = PyObject_Hash(a->m_self);
466 if (x == -1)
496 if (x == -1)
467 return -1;
497 return -1;
468 }
498 }
469 y = _Py_HashPointer((void*)(a->m_ml));
499 y = _Py_HashPointer((void*)(a->m_ml));
470 if (y == -1)
500 if (y == -1)
471 return -1;
501 return -1;
472 x ^= y;
502 x ^= y;
473 if (x == -1)
503 if (x == -1)
474 x = -2;
504 x = -2;
475 return x;
505 return x;
476 }
506 }
477
507
478
508
479 PyTypeObject PythonQtSlotFunction_Type = {
509 PyTypeObject PythonQtSlotFunction_Type = {
480 PyObject_HEAD_INIT(&PyType_Type)
510 PyObject_HEAD_INIT(&PyType_Type)
481 0,
511 0,
482 "builtin_qt_slot",
512 "builtin_qt_slot",
483 sizeof(PythonQtSlotFunctionObject),
513 sizeof(PythonQtSlotFunctionObject),
484 0,
514 0,
485 (destructor)meth_dealloc, /* tp_dealloc */
515 (destructor)meth_dealloc, /* tp_dealloc */
486 0, /* tp_print */
516 0, /* tp_print */
487 0, /* tp_getattr */
517 0, /* tp_getattr */
488 0, /* tp_setattr */
518 0, /* tp_setattr */
489 (cmpfunc)meth_compare, /* tp_compare */
519 (cmpfunc)meth_compare, /* tp_compare */
490 (reprfunc)meth_repr, /* tp_repr */
520 (reprfunc)meth_repr, /* tp_repr */
491 0, /* tp_as_number */
521 0, /* tp_as_number */
492 0, /* tp_as_sequence */
522 0, /* tp_as_sequence */
493 0, /* tp_as_mapping */
523 0, /* tp_as_mapping */
494 (hashfunc)meth_hash, /* tp_hash */
524 (hashfunc)meth_hash, /* tp_hash */
495 PythonQtSlotFunction_Call, /* tp_call */
525 PythonQtSlotFunction_Call, /* tp_call */
496 0, /* tp_str */
526 0, /* tp_str */
497 PyObject_GenericGetAttr, /* tp_getattro */
527 PyObject_GenericGetAttr, /* tp_getattro */
498 0, /* tp_setattro */
528 0, /* tp_setattro */
499 0, /* tp_as_buffer */
529 0, /* tp_as_buffer */
500 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
530 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
501 0, /* tp_doc */
531 0, /* tp_doc */
502 (traverseproc)meth_traverse, /* tp_traverse */
532 (traverseproc)meth_traverse, /* tp_traverse */
503 0, /* tp_clear */
533 0, /* tp_clear */
504 0, /* tp_richcompare */
534 0, /* tp_richcompare */
505 0, /* tp_weaklistoffset */
535 0, /* tp_weaklistoffset */
506 0, /* tp_iter */
536 0, /* tp_iter */
507 0, /* tp_iternext */
537 0, /* tp_iternext */
508 0, /* tp_methods */
538 0, /* tp_methods */
509 meth_members, /* tp_members */
539 meth_members, /* tp_members */
510 meth_getsets, /* tp_getset */
540 meth_getsets, /* tp_getset */
511 0, /* tp_base */
541 0, /* tp_base */
512 0, /* tp_dict */
542 0, /* tp_dict */
513 };
543 };
514
544
515 /* Clear out the free list */
545 /* Clear out the free list */
516
546
517 void
547 void
518 PythonQtSlotFunction_Fini(void)
548 PythonQtSlotFunction_Fini(void)
519 {
549 {
520 while (pythonqtslot_free_list) {
550 while (pythonqtslot_free_list) {
521 PythonQtSlotFunctionObject *v = pythonqtslot_free_list;
551 PythonQtSlotFunctionObject *v = pythonqtslot_free_list;
522 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(v->m_self);
552 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(v->m_self);
523 PyObject_GC_Del(v);
553 PyObject_GC_Del(v);
524 }
554 }
525 }
555 }
526
556
General Comments 0
You need to be logged in to leave comments. Login now