##// END OF EJS Templates
fixed isSame to use python comparison...
florianlink -
r160:7b78560a4b52
parent child
Show More
@@ -1,228 +1,233
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 PythonQtSignalReceiver.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 "PythonQtSignalReceiver.h"
43 43 #include "PythonQtClassInfo.h"
44 44 #include "PythonQtMethodInfo.h"
45 45 #include "PythonQtConversion.h"
46 46 #include <QMetaObject>
47 47 #include <QMetaMethod>
48 48 #include "funcobject.h"
49 49
50 50 void PythonQtSignalTarget::call(void **arguments) const {
51 51 PyObject* result = call(_callable, methodInfo(), arguments);
52 52 if (result) {
53 53 Py_DECREF(result);
54 54 }
55 55 }
56 56
57 57 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInfo* methodInfos, void **arguments, bool skipFirstArgumentOfMethodInfo)
58 58 {
59 59 Q_UNUSED(skipFirstArgumentOfMethodInfo)
60 60
61 61 // Note: we check if the callable is a PyFunctionObject and has a fixed number of arguments
62 62 // if that is the case, we only pass these arguments to python and skip the additional arguments from the signal
63 63
64 64 int numPythonArgs = -1;
65 65 if (PyFunction_Check(callable)) {
66 66 PyObject* o = callable;
67 67 PyFunctionObject* func = (PyFunctionObject*)o;
68 68 PyCodeObject* code = (PyCodeObject*)func->func_code;
69 69 if (!(code->co_flags & 0x04)) {
70 70 numPythonArgs = code->co_argcount;
71 71 } else {
72 72 // variable numbers of arguments allowed
73 73 }
74 74 } else if (PyMethod_Check(callable)) {
75 75 PyObject* o = callable;
76 76 PyMethodObject* method = (PyMethodObject*)o;
77 77 if (PyFunction_Check(method->im_func)) {
78 78 PyFunctionObject* func = (PyFunctionObject*)method->im_func;
79 79 PyCodeObject* code = (PyCodeObject*)func->func_code;
80 80 if (!(code->co_flags & 0x04)) {
81 81 numPythonArgs = code->co_argcount - 1; // we subtract one because the first is "self"
82 82 } else {
83 83 // variable numbers of arguments allowed
84 84 }
85 85 }
86 86 }
87 87
88 88 const PythonQtMethodInfo* m = methodInfos;
89 89 // parameterCount includes return value:
90 90 int count = m->parameterCount();
91 91 if (numPythonArgs!=-1) {
92 92 if (count>numPythonArgs+1) {
93 93 // take less arguments
94 94 count = numPythonArgs+1;
95 95 }
96 96 }
97 97
98 98 PyObject* pargs = NULL;
99 99 if (count>1) {
100 100 pargs = PyTuple_New(count-1);
101 101 }
102 102 bool err = false;
103 103 // transform Qt values to Python
104 104 const QList<PythonQtMethodInfo::ParameterInfo>& params = m->parameters();
105 105 for (int i = 1; i < count; i++) {
106 106 const PythonQtMethodInfo::ParameterInfo& param = params.at(i);
107 107 PyObject* arg = PythonQtConv::ConvertQtValueToPython(param, arguments[i]);
108 108 if (arg) {
109 109 // steals reference, no unref
110 110 PyTuple_SetItem(pargs, i-1,arg);
111 111 } else {
112 112 err = true;
113 113 break;
114 114 }
115 115 }
116 116
117 117 PyObject* result = NULL;
118 118 if (!err) {
119 119 PyErr_Clear();
120 120 result = PyObject_CallObject(callable, pargs);
121 121 if (result) {
122 122 // ok
123 123 } else {
124 124 PythonQt::self()->handleError();
125 125 }
126 126 }
127 127 if (pargs) {
128 128 // free the arguments again
129 129 Py_DECREF(pargs);
130 130 }
131 131
132 132 return result;
133 133 }
134 134
135 bool PythonQtSignalTarget::isSame( int signalId, PyObject* callable ) const
136 {
137 return PyObject_Compare(callable, _callable) == 0 && signalId==_signalId;
138 }
139
135 140 //------------------------------------------------------------------------------
136 141
137 142 PythonQtSignalReceiver::PythonQtSignalReceiver(QObject* obj):PythonQtSignalReceiverBase(obj)
138 143 {
139 144 _obj = obj;
140 145
141 146 // fetch the class info for object, since we will need to for correct enum resolution in
142 147 // signals
143 148 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
144 149 if (!_objClassInfo || !_objClassInfo->isQObject()) {
145 150 PythonQt::self()->registerClass(obj->metaObject());
146 151 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
147 152 }
148 153 // force decorator/enum creation
149 154 _objClassInfo->decorator();
150 155
151 156 _slotCount = staticMetaObject.methodOffset();
152 157 }
153 158
154 159 PythonQtSignalReceiver::~PythonQtSignalReceiver()
155 160 {
156 161 PythonQt::priv()->removeSignalEmitter(_obj);
157 162 }
158 163
159 164
160 165 bool PythonQtSignalReceiver::addSignalHandler(const char* signal, PyObject* callable)
161 166 {
162 167 bool flag = false;
163 168 int sigId = getSignalIndex(signal);
164 169 if (sigId>=0) {
165 170 // create PythonQtMethodInfo from signal
166 171 QMetaMethod meta = _obj->metaObject()->method(sigId);
167 172 const PythonQtMethodInfo* signalInfo = PythonQtMethodInfo::getCachedMethodInfo(meta, _objClassInfo);
168 173 PythonQtSignalTarget t(sigId, signalInfo, _slotCount, callable);
169 174 _targets.append(t);
170 175 // now connect to ourselves with the new slot id
171 176 QMetaObject::connect(_obj, sigId, this, _slotCount, Qt::AutoConnection, 0);
172 177
173 178 _slotCount++;
174 179 flag = true;
175 180 }
176 181 return flag;
177 182 }
178 183
179 184 bool PythonQtSignalReceiver::removeSignalHandler(const char* signal, PyObject* callable)
180 185 {
181 186 bool found = false;
182 187 int sigId = getSignalIndex(signal);
183 188 if (sigId>=0) {
184 189 QMutableListIterator<PythonQtSignalTarget> i(_targets);
185 190 while (i.hasNext()) {
186 191 if (i.next().isSame(sigId, callable)) {
187 192 i.remove();
188 193 found = true;
189 194 break;
190 195 }
191 196 }
192 197 }
193 198 return found;
194 199 }
195 200
196 201 void PythonQtSignalReceiver::removeSignalHandlers()
197 202 {
198 203 _targets.clear();
199 204 }
200 205
201 206 int PythonQtSignalReceiver::getSignalIndex(const char* signal)
202 207 {
203 208 int sigId = _obj->metaObject()->indexOfSignal(signal+1);
204 209 if (sigId<0) {
205 210 QByteArray tmpSig = QMetaObject::normalizedSignature(signal+1);
206 211 sigId = _obj->metaObject()->indexOfSignal(tmpSig);
207 212 }
208 213 return sigId;
209 214 }
210 215
211 216 int PythonQtSignalReceiver::qt_metacall(QMetaObject::Call c, int id, void **arguments)
212 217 {
213 218 // mlabDebugConst("PythonQt", "PythonQtSignalReceiver invoke " << _obj->className() << " " << _obj->name() << " " << id);
214 219 if (c != QMetaObject::InvokeMetaMethod) {
215 220 QObject::qt_metacall(c, id, arguments);
216 221 }
217 222
218 223 bool found = false;
219 224 foreach(const PythonQtSignalTarget& t, _targets) {
220 225 if (t.slotId() == id) {
221 226 found = true;
222 227 t.call(arguments);
223 228 break;
224 229 }
225 230 }
226 231 return 0;
227 232 }
228 233
@@ -1,141 +1,141
1 1 #ifndef _PYTHONQTSIGNALRECEIVER_H
2 2 #define _PYTHONQTSIGNALRECEIVER_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 PythonQtSignalReceiver.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include <Python.h>
46 46 #include "PythonQtSystem.h"
47 47 #include "PythonQtObjectPtr.h"
48 48
49 49 class PythonQtMethodInfo;
50 50 class PythonQtClassInfo;
51 51
52 52 //! stores information about a signal target
53 53 /*! copy construction and assignment works fine with the C++ standard behavior and are thus not implemented
54 54 */
55 55 class PYTHONQT_EXPORT PythonQtSignalTarget {
56 56 public:
57 57 PythonQtSignalTarget() {
58 58 _signalId = -1;
59 59 _methodInfo = NULL;
60 60 _slotId = -1;
61 61 }
62 62
63 63 PythonQtSignalTarget(int signalId,const PythonQtMethodInfo* methodInfo, int slotId, PyObject* callable)
64 64 {
65 65 _signalId = signalId;
66 66 _slotId = slotId;
67 67 _methodInfo = methodInfo;
68 68 _callable = callable;
69 69 };
70 70
71 71 ~PythonQtSignalTarget() {
72 72 };
73 73
74 74 //! get the id of the original signal
75 75 int signalId() const { return _signalId; }
76 76
77 77 //! get the id that was assigned to this simulated slot
78 78 int slotId() const { return _slotId; }
79 79
80 80 //! get the signals parameter info
81 81 const PythonQtMethodInfo* methodInfo() const { return _methodInfo; }
82 82
83 83 //! call the python callable with the given arguments (as defined in methodInfo)
84 84 void call(void **arguments) const;
85 85
86 86 //! check if it is the same signal target
87 bool isSame(int signalId, PyObject* callable) const { return callable==_callable && signalId==_signalId; }
87 bool isSame(int signalId, PyObject* callable) const;
88 88
89 89 //! call the given callable with arguments described by PythonQtMethodInfo, returns a new reference as result value (or NULL)
90 90 static PyObject* call(PyObject* callable, const PythonQtMethodInfo* methodInfo, void **arguments, bool skipFirstArgumentOfMethodInfo = false);
91 91
92 92 private:
93 93 int _signalId;
94 94 int _slotId;
95 95 const PythonQtMethodInfo* _methodInfo;
96 96 PythonQtObjectPtr _callable;
97 97 };
98 98
99 99 //! base class for signal receivers
100 100 /*!
101 101 */
102 102 class PythonQtSignalReceiverBase : public QObject {
103 103 Q_OBJECT
104 104 public:
105 105 PythonQtSignalReceiverBase(QObject* obj):QObject(obj) {};
106 106 };
107 107
108 108 //! receives all signals for one QObject
109 109 /*! we derive from our base but do not declare the QObject macro because we want to reimplement qt_metacall only.
110 110 */
111 111 class PythonQtSignalReceiver : public PythonQtSignalReceiverBase {
112 112
113 113 public:
114 114 PythonQtSignalReceiver(QObject* obj);
115 115 ~PythonQtSignalReceiver();
116 116
117 117 //! add a signal handler
118 118 bool addSignalHandler(const char* signal, PyObject* callable);
119 119
120 120 //! remove a signal handler
121 121 bool removeSignalHandler(const char* signal, PyObject* callable);
122 122
123 123 //! remove all signal handlers
124 124 void removeSignalHandlers();
125 125
126 126 //! we implement this method to simulate a number of slots that match the ids in _targets
127 127 virtual int qt_metacall(QMetaObject::Call c, int id, void **arguments);
128 128
129 129 private:
130 130 //! get the index of the signal
131 131 int getSignalIndex(const char* signal);
132 132
133 133 QObject* _obj;
134 134 PythonQtClassInfo* _objClassInfo;
135 135 int _slotCount;
136 136 // linear list may get slow on multiple targets, but I think typically we have many objects and just a few signals
137 137 QList<PythonQtSignalTarget> _targets;
138 138 };
139 139
140 140
141 141 #endif
General Comments 0
You need to be logged in to leave comments. Login now