##// END OF EJS Templates
improved so that dict contains properties and that dir() shows all available things, including the derived base attributes...
florianlink -
r34:5daedfb035c8
parent child
Show More
@@ -1,718 +1,727
1 /*
1 /*
2 *
2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2006 MeVis Research GmbH 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 Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Research GmbH, 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 PythonQt.cpp
35 // \file PythonQt.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 "PythonQtClassInfo.h"
42 #include "PythonQtClassInfo.h"
43 #include "PythonQtMethodInfo.h"
43 #include "PythonQtMethodInfo.h"
44 #include "PythonQt.h"
44 #include "PythonQt.h"
45 #include <QMetaMethod>
45 #include <QMetaMethod>
46
46
47 QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;
47 QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;
48
48
49 PythonQtClassInfo::PythonQtClassInfo() {
49 PythonQtClassInfo::PythonQtClassInfo() {
50 _meta = NULL;
50 _meta = NULL;
51 _constructors = NULL;
51 _constructors = NULL;
52 _destructor = NULL;
52 _destructor = NULL;
53 _decoratorProvider = NULL;
53 _decoratorProvider = NULL;
54 _decoratorProviderCB = NULL;
54 _decoratorProviderCB = NULL;
55 _pythonQtClassWrapper = NULL;
55 _pythonQtClassWrapper = NULL;
56 _shellSetInstanceWrapperCB = NULL;
56 _shellSetInstanceWrapperCB = NULL;
57 _metaTypeId = -1;
57 _metaTypeId = -1;
58 _isQObject = false;
58 _isQObject = false;
59 }
59 }
60
60
61 PythonQtClassInfo::~PythonQtClassInfo()
61 PythonQtClassInfo::~PythonQtClassInfo()
62 {
62 {
63 clearCachedMembers();
63 clearCachedMembers();
64
64
65 if (_constructors) {
65 if (_constructors) {
66 _constructors->deleteOverloadsAndThis();
66 _constructors->deleteOverloadsAndThis();
67 }
67 }
68 if (_destructor) {
68 if (_destructor) {
69 _destructor->deleteOverloadsAndThis();
69 _destructor->deleteOverloadsAndThis();
70 }
70 }
71 foreach(PythonQtSlotInfo* info, _decoratorSlots) {
71 foreach(PythonQtSlotInfo* info, _decoratorSlots) {
72 info->deleteOverloadsAndThis();
72 info->deleteOverloadsAndThis();
73 }
73 }
74 }
74 }
75
75
76 void PythonQtClassInfo::setupQObject(const QMetaObject* meta)
76 void PythonQtClassInfo::setupQObject(const QMetaObject* meta)
77 {
77 {
78 // _wrappedClassName is already set earlier in the class setup
78 // _wrappedClassName is already set earlier in the class setup
79 _isQObject = true;
79 _isQObject = true;
80 _meta = meta;
80 _meta = meta;
81 }
81 }
82
82
83 void PythonQtClassInfo::setupCPPObject(const QByteArray& classname)
83 void PythonQtClassInfo::setupCPPObject(const QByteArray& classname)
84 {
84 {
85 _isQObject = false;
85 _isQObject = false;
86 _wrappedClassName = classname;
86 _wrappedClassName = classname;
87 _metaTypeId = QMetaType::type(classname);
87 _metaTypeId = QMetaType::type(classname);
88 }
88 }
89
89
90 void PythonQtClassInfo::clearCachedMembers()
90 void PythonQtClassInfo::clearCachedMembers()
91 {
91 {
92 QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers);
92 QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers);
93 while (i.hasNext()) {
93 while (i.hasNext()) {
94 PythonQtMemberInfo member = i.next().value();
94 PythonQtMemberInfo member = i.next().value();
95 if (member._type== PythonQtMemberInfo::Slot) {
95 if (member._type== PythonQtMemberInfo::Slot) {
96 PythonQtSlotInfo* info = member._slot;
96 PythonQtSlotInfo* info = member._slot;
97 while (info) {
97 while (info) {
98 PythonQtSlotInfo* next = info->nextInfo();
98 PythonQtSlotInfo* next = info->nextInfo();
99 delete info;
99 delete info;
100 info = next;
100 info = next;
101 }
101 }
102 }
102 }
103 }
103 }
104 }
104 }
105
105
106 int PythonQtClassInfo::findCharOffset(const char* sigStart, char someChar)
106 int PythonQtClassInfo::findCharOffset(const char* sigStart, char someChar)
107 {
107 {
108 const char* sigEnd = sigStart;
108 const char* sigEnd = sigStart;
109 char c;
109 char c;
110 do {
110 do {
111 c = *sigEnd++;
111 c = *sigEnd++;
112 } while (c!=someChar && c!=0);
112 } while (c!=someChar && c!=0);
113 return sigEnd-sigStart-1;
113 return sigEnd-sigStart-1;
114 }
114 }
115
115
116 bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName)
116 bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName)
117 {
117 {
118 bool found = false;
118 bool found = false;
119 bool nameMapped = false;
119 bool nameMapped = false;
120 const char* attributeName = memberName;
120 const char* attributeName = memberName;
121 // look for properties
121 // look for properties
122 int i = _meta->indexOfProperty(attributeName);
122 int i = _meta->indexOfProperty(attributeName);
123 if (i==-1) {
123 if (i==-1) {
124 // try to map name to objectName
124 // try to map name to objectName
125 if (qstrcmp(attributeName, "name")==0) {
125 if (qstrcmp(attributeName, "name")==0) {
126 attributeName = "objectName";
126 attributeName = "objectName";
127 nameMapped = true;
127 nameMapped = true;
128 i = _meta->indexOfProperty(attributeName);
128 i = _meta->indexOfProperty(attributeName);
129 }
129 }
130 }
130 }
131 if (i!=-1) {
131 if (i!=-1) {
132 PythonQtMemberInfo newInfo(_meta->property(i));
132 PythonQtMemberInfo newInfo(_meta->property(i));
133 _cachedMembers.insert(attributeName, newInfo);
133 _cachedMembers.insert(attributeName, newInfo);
134 if (nameMapped) {
134 if (nameMapped) {
135 _cachedMembers.insert(memberName, newInfo);
135 _cachedMembers.insert(memberName, newInfo);
136 }
136 }
137 #ifdef PYTHONQT_DEBUG
137 #ifdef PYTHONQT_DEBUG
138 std::cout << "caching property " << memberName << " on " << _meta->className() << std::endl;
138 std::cout << "caching property " << memberName << " on " << _meta->className() << std::endl;
139 #endif
139 #endif
140 found = true;
140 found = true;
141 }
141 }
142 return found;
142 return found;
143 }
143 }
144
144
145 PythonQtSlotInfo* PythonQtClassInfo::recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
145 PythonQtSlotInfo* PythonQtClassInfo::recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
146 {
146 {
147 inputInfo = findDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset);
147 inputInfo = findDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset);
148 foreach(const ParentClassInfo& info, _parentClasses) {
148 foreach(const ParentClassInfo& info, _parentClasses) {
149 inputInfo = info._parent->recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset+info._upcastingOffset);
149 inputInfo = info._parent->recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset+info._upcastingOffset);
150 }
150 }
151 return inputInfo;
151 return inputInfo;
152 }
152 }
153
153
154 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset) {
154 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset) {
155 QObject* decoratorProvider = decorator();
155 QObject* decoratorProvider = decorator();
156 int memberNameLen = strlen(memberName);
156 int memberNameLen = strlen(memberName);
157 if (decoratorProvider) {
157 if (decoratorProvider) {
158 //qDebug()<< "looking " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
158 //qDebug()<< "looking " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
159 const QMetaObject* meta = decoratorProvider->metaObject();
159 const QMetaObject* meta = decoratorProvider->metaObject();
160 int numMethods = meta->methodCount();
160 int numMethods = meta->methodCount();
161 int startFrom = QObject::staticMetaObject.methodCount();
161 int startFrom = QObject::staticMetaObject.methodCount();
162 for (int i = startFrom; i < numMethods; i++) {
162 for (int i = startFrom; i < numMethods; i++) {
163 QMetaMethod m = meta->method(i);
163 QMetaMethod m = meta->method(i);
164 if ((m.methodType() == QMetaMethod::Method ||
164 if ((m.methodType() == QMetaMethod::Method ||
165 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
165 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
166
166
167 const char* sigStart = m.signature();
167 const char* sigStart = m.signature();
168 bool isClassDeco = false;
168 bool isClassDeco = false;
169 if (qstrncmp(sigStart, "static_", 7)==0) {
169 if (qstrncmp(sigStart, "static_", 7)==0) {
170 // skip the static_classname_ part of the string
170 // skip the static_classname_ part of the string
171 sigStart += 7 + 1 + strlen(className());
171 sigStart += 7 + 1 + strlen(className());
172 isClassDeco = true;
172 isClassDeco = true;
173 } else if (qstrncmp(sigStart, "new_", 4)==0) {
173 } else if (qstrncmp(sigStart, "new_", 4)==0) {
174 isClassDeco = true;
174 isClassDeco = true;
175 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
175 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
176 isClassDeco = true;
176 isClassDeco = true;
177 }
177 }
178 // find the first '('
178 // find the first '('
179 int offset = findCharOffset(sigStart, '(');
179 int offset = findCharOffset(sigStart, '(');
180
180
181 // XXX no checking is currently done if the slots have correct first argument or not...
181 // XXX no checking is currently done if the slots have correct first argument or not...
182
182
183 // check if same length and same name
183 // check if same length and same name
184 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
184 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
185 found = true;
185 found = true;
186 PythonQtSlotInfo* info = new PythonQtSlotInfo(m, i, decoratorProvider, isClassDeco?PythonQtSlotInfo::ClassDecorator:PythonQtSlotInfo::InstanceDecorator);
186 PythonQtSlotInfo* info = new PythonQtSlotInfo(m, i, decoratorProvider, isClassDeco?PythonQtSlotInfo::ClassDecorator:PythonQtSlotInfo::InstanceDecorator);
187 info->setUpcastingOffset(upcastingOffset);
187 info->setUpcastingOffset(upcastingOffset);
188 //qDebug()<< "adding " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
188 //qDebug()<< "adding " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
189 if (tail) {
189 if (tail) {
190 tail->setNextInfo(info);
190 tail->setNextInfo(info);
191 } else {
191 } else {
192 PythonQtMemberInfo newInfo(info);
192 PythonQtMemberInfo newInfo(info);
193 memberCache.insert(memberName, newInfo);
193 memberCache.insert(memberName, newInfo);
194 }
194 }
195 tail = info;
195 tail = info;
196 }
196 }
197 }
197 }
198 }
198 }
199 }
199 }
200
200
201 tail = findDecoratorSlots(memberName, memberNameLen, tail, found, memberCache, upcastingOffset);
201 tail = findDecoratorSlots(memberName, memberNameLen, tail, found, memberCache, upcastingOffset);
202
202
203 return tail;
203 return tail;
204 }
204 }
205
205
206 bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName)
206 bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName)
207 {
207 {
208 bool found = false;
208 bool found = false;
209 int memberNameLen = strlen(memberName);
209 int memberNameLen = strlen(memberName);
210 PythonQtSlotInfo* tail = NULL;
210 PythonQtSlotInfo* tail = NULL;
211 if (_meta) {
211 if (_meta) {
212 int numMethods = _meta->methodCount();
212 int numMethods = _meta->methodCount();
213 for (int i = 0; i < numMethods; i++) {
213 for (int i = 0; i < numMethods; i++) {
214 QMetaMethod m = _meta->method(i);
214 QMetaMethod m = _meta->method(i);
215 if ((m.methodType() == QMetaMethod::Method ||
215 if ((m.methodType() == QMetaMethod::Method ||
216 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
216 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
217
217
218 const char* sigStart = m.signature();
218 const char* sigStart = m.signature();
219 // find the first '('
219 // find the first '('
220 int offset = findCharOffset(sigStart, '(');
220 int offset = findCharOffset(sigStart, '(');
221
221
222 // check if same length and same name
222 // check if same length and same name
223 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
223 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
224 found = true;
224 found = true;
225 PythonQtSlotInfo* info = new PythonQtSlotInfo(m, i);
225 PythonQtSlotInfo* info = new PythonQtSlotInfo(m, i);
226 if (tail) {
226 if (tail) {
227 tail->setNextInfo(info);
227 tail->setNextInfo(info);
228 } else {
228 } else {
229 PythonQtMemberInfo newInfo(info);
229 PythonQtMemberInfo newInfo(info);
230 _cachedMembers.insert(memberName, newInfo);
230 _cachedMembers.insert(memberName, newInfo);
231 }
231 }
232 tail = info;
232 tail = info;
233 }
233 }
234 }
234 }
235 }
235 }
236 }
236 }
237
237
238 // look for dynamic decorators in this class and in derived classes
238 // look for dynamic decorators in this class and in derived classes
239 tail = recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, tail, found, _cachedMembers, 0);
239 tail = recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, tail, found, _cachedMembers, 0);
240
240
241 return found;
241 return found;
242 }
242 }
243
243
244 bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* memberName)
244 bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* memberName)
245 {
245 {
246 bool found = false;
246 bool found = false;
247 // look for enum values
247 // look for enum values
248 int enumCount = meta->enumeratorCount();
248 int enumCount = meta->enumeratorCount();
249 for (int i=0;i<enumCount; i++) {
249 for (int i=0;i<enumCount; i++) {
250 QMetaEnum e = meta->enumerator(i);
250 QMetaEnum e = meta->enumerator(i);
251 for (int j=0; j < e.keyCount(); j++) {
251 for (int j=0; j < e.keyCount(); j++) {
252 if (qstrcmp(e.key(j), memberName)==0) {
252 if (qstrcmp(e.key(j), memberName)==0) {
253 PythonQtMemberInfo newInfo(e.value(j));
253 PythonQtMemberInfo newInfo(e.value(j));
254 _cachedMembers.insert(memberName, newInfo);
254 _cachedMembers.insert(memberName, newInfo);
255 #ifdef PYTHONQT_DEBUG
255 #ifdef PYTHONQT_DEBUG
256 std::cout << "caching enum " << memberName << " on " << meta->className() << std::endl;
256 std::cout << "caching enum " << memberName << " on " << meta->className() << std::endl;
257 #endif
257 #endif
258 found = true;
258 found = true;
259 break;
259 break;
260 }
260 }
261 }
261 }
262 }
262 }
263 return found;
263 return found;
264 }
264 }
265
265
266 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
266 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
267 {
267 {
268 PythonQtMemberInfo info = _cachedMembers.value(memberName);
268 PythonQtMemberInfo info = _cachedMembers.value(memberName);
269 if (info._type != PythonQtMemberInfo::Invalid) {
269 if (info._type != PythonQtMemberInfo::Invalid) {
270 return info;
270 return info;
271 } else {
271 } else {
272 bool found = false;
272 bool found = false;
273
273
274 found = lookForPropertyAndCache(memberName);
274 found = lookForPropertyAndCache(memberName);
275 if (!found) {
275 if (!found) {
276 found = lookForMethodAndCache(memberName);
276 found = lookForMethodAndCache(memberName);
277 }
277 }
278 if (!found) {
278 if (!found) {
279 if (_meta) {
279 if (_meta) {
280 // check enums in our meta object directly
280 // check enums in our meta object directly
281 found = lookForEnumAndCache(_meta, memberName);
281 found = lookForEnumAndCache(_meta, memberName);
282 }
282 }
283 if (!found) {
283 if (!found) {
284 // check enums in the class hierachy of CPP classes
284 // check enums in the class hierachy of CPP classes
285 // look for dynamic decorators in this class and in derived classes
285 // look for dynamic decorators in this class and in derived classes
286 QList<QObject*> decoObjects;
286 QList<QObject*> decoObjects;
287 recursiveCollectDecoratorObjects(decoObjects);
287 recursiveCollectDecoratorObjects(decoObjects);
288 foreach(QObject* deco, decoObjects) {
288 foreach(QObject* deco, decoObjects) {
289 // call on ourself for caching, but with different metaObject():
289 // call on ourself for caching, but with different metaObject():
290 found = lookForEnumAndCache(deco->metaObject(), memberName);
290 found = lookForEnumAndCache(deco->metaObject(), memberName);
291 if (found) {
291 if (found) {
292 break;
292 break;
293 }
293 }
294 }
294 }
295 }
295 }
296 }
296 }
297 if (!found) {
297 if (!found) {
298 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
298 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
299 info._type = PythonQtMemberInfo::NotFound;
299 info._type = PythonQtMemberInfo::NotFound;
300 _cachedMembers.insert(memberName, info);
300 _cachedMembers.insert(memberName, info);
301 }
301 }
302 }
302 }
303
303
304 return _cachedMembers.value(memberName);
304 return _cachedMembers.value(memberName);
305 }
305 }
306
306
307 void PythonQtClassInfo::recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects) {
307 void PythonQtClassInfo::recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects) {
308 QObject* deco = decorator();
308 QObject* deco = decorator();
309 if (deco) {
309 if (deco) {
310 decoratorObjects.append(deco);
310 decoratorObjects.append(deco);
311 }
311 }
312 foreach(const ParentClassInfo& info, _parentClasses) {
312 foreach(const ParentClassInfo& info, _parentClasses) {
313 info._parent->recursiveCollectDecoratorObjects(decoratorObjects);
313 info._parent->recursiveCollectDecoratorObjects(decoratorObjects);
314 }
314 }
315 }
315 }
316
316
317 void PythonQtClassInfo::recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects) {
317 void PythonQtClassInfo::recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects) {
318 classInfoObjects.append(this);
318 classInfoObjects.append(this);
319 foreach(const ParentClassInfo& info, _parentClasses) {
319 foreach(const ParentClassInfo& info, _parentClasses) {
320 info._parent->recursiveCollectClassInfos(classInfoObjects);
320 info._parent->recursiveCollectClassInfos(classInfoObjects);
321 }
321 }
322 }
322 }
323
323
324 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
324 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
325 {
325 {
326 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
326 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
327 while (it.hasNext()) {
327 while (it.hasNext()) {
328
328
329 PythonQtSlotInfo* infoOrig = it.next();
329 PythonQtSlotInfo* infoOrig = it.next();
330
330
331 const char* sigStart = infoOrig->metaMethod()->signature();
331 const char* sigStart = infoOrig->metaMethod()->signature();
332 if (qstrncmp("static_", sigStart, 7)==0) {
332 if (qstrncmp("static_", sigStart, 7)==0) {
333 sigStart += 7;
333 sigStart += 7;
334 sigStart += findCharOffset(sigStart, '_')+1;
334 sigStart += findCharOffset(sigStart, '_')+1;
335 }
335 }
336 int offset = findCharOffset(sigStart, '(');
336 int offset = findCharOffset(sigStart, '(');
337 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
337 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
338 //make a copy, otherwise we will have trouble on overloads!
338 //make a copy, otherwise we will have trouble on overloads!
339 PythonQtSlotInfo* info = new PythonQtSlotInfo(*infoOrig);
339 PythonQtSlotInfo* info = new PythonQtSlotInfo(*infoOrig);
340 info->setUpcastingOffset(upcastingOffset);
340 info->setUpcastingOffset(upcastingOffset);
341 found = true;
341 found = true;
342 if (tail) {
342 if (tail) {
343 tail->setNextInfo(info);
343 tail->setNextInfo(info);
344 } else {
344 } else {
345 PythonQtMemberInfo newInfo(info);
345 PythonQtMemberInfo newInfo(info);
346 memberCache.insert(memberName, newInfo);
346 memberCache.insert(memberName, newInfo);
347 }
347 }
348 tail = info;
348 tail = info;
349 }
349 }
350 }
350 }
351 return tail;
351 return tail;
352 }
352 }
353
353
354 void PythonQtClassInfo::listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly) {
354 void PythonQtClassInfo::listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly) {
355 QObject* decoratorProvider = decorator();
355 QObject* decoratorProvider = decorator();
356 if (decoratorProvider) {
356 if (decoratorProvider) {
357 const QMetaObject* meta = decoratorProvider->metaObject();
357 const QMetaObject* meta = decoratorProvider->metaObject();
358 int numMethods = meta->methodCount();
358 int numMethods = meta->methodCount();
359 int startFrom = QObject::staticMetaObject.methodCount();
359 int startFrom = QObject::staticMetaObject.methodCount();
360 for (int i = startFrom; i < numMethods; i++) {
360 for (int i = startFrom; i < numMethods; i++) {
361 QMetaMethod m = meta->method(i);
361 QMetaMethod m = meta->method(i);
362 if ((m.methodType() == QMetaMethod::Method ||
362 if ((m.methodType() == QMetaMethod::Method ||
363 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
363 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
364
364
365 const char* sigStart = m.signature();
365 const char* sigStart = m.signature();
366 bool isClassDeco = false;
366 bool isClassDeco = false;
367 if (qstrncmp(sigStart, "static_", 7)==0) {
367 if (qstrncmp(sigStart, "static_", 7)==0) {
368 // skip the static_classname_ part of the string
368 // skip the static_classname_ part of the string
369 sigStart += 7 + 1 + strlen(className());
369 sigStart += 7 + 1 + strlen(className());
370 isClassDeco = true;
370 isClassDeco = true;
371 } else if (qstrncmp(sigStart, "new_", 4)==0) {
371 } else if (qstrncmp(sigStart, "new_", 4)==0) {
372 continue;
372 continue;
373 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
373 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
374 continue;
374 continue;
375 }
375 }
376 // find the first '('
376 // find the first '('
377 int offset = findCharOffset(sigStart, '(');
377 int offset = findCharOffset(sigStart, '(');
378
378
379 // XXX no checking is currently done if the slots have correct first argument or not...
379 // XXX no checking is currently done if the slots have correct first argument or not...
380 if (!metaOnly || isClassDeco) {
380 if (!metaOnly || isClassDeco) {
381 list << QString::fromLatin1(sigStart, offset);
381 list << QString::fromLatin1(sigStart, offset);
382 }
382 }
383 }
383 }
384 }
384 }
385 }
385 }
386
386
387 // look for global decorator slots
387 // look for global decorator slots
388 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
388 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
389 while (it.hasNext()) {
389 while (it.hasNext()) {
390 PythonQtSlotInfo* slot = it.next();
390 PythonQtSlotInfo* slot = it.next();
391 if (metaOnly) {
391 if (metaOnly) {
392 if (slot->isClassDecorator()) {
392 if (slot->isClassDecorator()) {
393 QByteArray first = slot->slotName();
393 QByteArray first = slot->slotName();
394 if (first.startsWith("static_")) {
394 if (first.startsWith("static_")) {
395 int idx = first.indexOf('_');
395 int idx = first.indexOf('_');
396 idx = first.indexOf('_', idx+1);
396 idx = first.indexOf('_', idx+1);
397 first = first.mid(idx+1);
397 first = first.mid(idx+1);
398 }
398 }
399 list << first;
399 list << first;
400 }
400 }
401 } else {
401 } else {
402 list << slot->slotName();
402 list << slot->slotName();
403 }
403 }
404 }
404 }
405 }
405 }
406
407 QStringList PythonQtClassInfo::memberList(bool metaOnly)
408 {
409 decorator();
410
406
407 QStringList PythonQtClassInfo::propertyList()
408 {
411 QStringList l;
409 QStringList l;
412 QString h;
410 if (_isQObject && _meta) {
413 if (_isQObject && _meta && !metaOnly) {
414 int i;
411 int i;
415 int numProperties = _meta->propertyCount();
412 int numProperties = _meta->propertyCount();
416 for (i = 0; i < numProperties; i++) {
413 for (i = 0; i < numProperties; i++) {
417 QMetaProperty p = _meta->property(i);
414 QMetaProperty p = _meta->property(i);
418 l << QString(p.name());
415 l << QString(p.name());
419 }
416 }
420 }
417 }
418 return l;
419 }
420
421 QStringList PythonQtClassInfo::memberList(bool metaOnly)
422 {
423 decorator();
424
425 QStringList l;
426 QString h;
427 if (_isQObject && _meta && !metaOnly) {
428 l = propertyList();
429 }
421
430
422 // normal slots of QObject (or wrapper QObject)
431 // normal slots of QObject (or wrapper QObject)
423 if (!metaOnly && _meta) {
432 if (!metaOnly && _meta) {
424 int numMethods = _meta->methodCount();
433 int numMethods = _meta->methodCount();
425 bool skipQObj = !_isQObject;
434 bool skipQObj = !_isQObject;
426 for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) {
435 for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) {
427 QMetaMethod m = _meta->method(i);
436 QMetaMethod m = _meta->method(i);
428 if ((m.methodType() == QMetaMethod::Method ||
437 if ((m.methodType() == QMetaMethod::Method ||
429 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
438 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
430 QByteArray signa(m.signature());
439 QByteArray signa(m.signature());
431 if (signa.startsWith("new_")) continue;
440 if (signa.startsWith("new_")) continue;
432 if (signa.startsWith("delete_")) continue;
441 if (signa.startsWith("delete_")) continue;
433 if (signa.startsWith("static_")) continue;
442 if (signa.startsWith("static_")) continue;
434 PythonQtSlotInfo slot(m, i);
443 PythonQtSlotInfo slot(m, i);
435 l << slot.slotName();
444 l << slot.slotName();
436 }
445 }
437 }
446 }
438 }
447 }
439
448
440 {
449 {
441 // look for dynamic decorators in this class and in derived classes
450 // look for dynamic decorators in this class and in derived classes
442 QList<PythonQtClassInfo*> infos;
451 QList<PythonQtClassInfo*> infos;
443 recursiveCollectClassInfos(infos);
452 recursiveCollectClassInfos(infos);
444 foreach(PythonQtClassInfo* info, infos) {
453 foreach(PythonQtClassInfo* info, infos) {
445 info->listDecoratorSlotsFromDecoratorProvider(l, metaOnly);
454 info->listDecoratorSlotsFromDecoratorProvider(l, metaOnly);
446 }
455 }
447 }
456 }
448
457
449 // List enumerator keys...
458 // List enumerator keys...
450 QList<const QMetaObject*> enumMetaObjects;
459 QList<const QMetaObject*> enumMetaObjects;
451 if (_meta) {
460 if (_meta) {
452 enumMetaObjects << _meta;
461 enumMetaObjects << _meta;
453 }
462 }
454 // check enums in the class hierachy of CPP classes
463 // check enums in the class hierachy of CPP classes
455 QList<QObject*> decoObjects;
464 QList<QObject*> decoObjects;
456 recursiveCollectDecoratorObjects(decoObjects);
465 recursiveCollectDecoratorObjects(decoObjects);
457 foreach(QObject* deco, decoObjects) {
466 foreach(QObject* deco, decoObjects) {
458 enumMetaObjects << deco->metaObject();
467 enumMetaObjects << deco->metaObject();
459 }
468 }
460
469
461 foreach(const QMetaObject* meta, enumMetaObjects) {
470 foreach(const QMetaObject* meta, enumMetaObjects) {
462 for (int i = 0; i<meta->enumeratorCount(); i++) {
471 for (int i = 0; i<meta->enumeratorCount(); i++) {
463 QMetaEnum e = meta->enumerator(i);
472 QMetaEnum e = meta->enumerator(i);
464 for (int j=0; j < e.keyCount(); j++) {
473 for (int j=0; j < e.keyCount(); j++) {
465 l << QString(e.key(j));
474 l << QString(e.key(j));
466 }
475 }
467 }
476 }
468 }
477 }
469
478
470 return QSet<QString>::fromList(l).toList();
479 return QSet<QString>::fromList(l).toList();
471 }
480 }
472
481
473 const char* PythonQtClassInfo::className()
482 const char* PythonQtClassInfo::className()
474 {
483 {
475 return _wrappedClassName.constData();
484 return _wrappedClassName.constData();
476 }
485 }
477
486
478 void* PythonQtClassInfo::castTo(void* ptr, const char* classname)
487 void* PythonQtClassInfo::castTo(void* ptr, const char* classname)
479 {
488 {
480 if (ptr==NULL) {
489 if (ptr==NULL) {
481 return NULL;
490 return NULL;
482 }
491 }
483 if (_wrappedClassName == classname) {
492 if (_wrappedClassName == classname) {
484 return ptr;
493 return ptr;
485 }
494 }
486 foreach(const ParentClassInfo& info, _parentClasses) {
495 foreach(const ParentClassInfo& info, _parentClasses) {
487 void* result = info._parent->castTo((char*)ptr + info._upcastingOffset, classname);
496 void* result = info._parent->castTo((char*)ptr + info._upcastingOffset, classname);
488 if (result) {
497 if (result) {
489 return result;
498 return result;
490 }
499 }
491 }
500 }
492 return NULL;
501 return NULL;
493 }
502 }
494
503
495 bool PythonQtClassInfo::inherits(const char* name)
504 bool PythonQtClassInfo::inherits(const char* name)
496 {
505 {
497 if (_wrappedClassName == name) {
506 if (_wrappedClassName == name) {
498 return true;
507 return true;
499 }
508 }
500 foreach(const ParentClassInfo& info, _parentClasses) {
509 foreach(const ParentClassInfo& info, _parentClasses) {
501 if (info._parent->inherits(name)) {
510 if (info._parent->inherits(name)) {
502 return true;
511 return true;
503 }
512 }
504 }
513 }
505 return false;
514 return false;
506 }
515 }
507
516
508 bool PythonQtClassInfo::inherits(PythonQtClassInfo* classInfo)
517 bool PythonQtClassInfo::inherits(PythonQtClassInfo* classInfo)
509 {
518 {
510 if (classInfo == this) {
519 if (classInfo == this) {
511 return true;
520 return true;
512 }
521 }
513 foreach(const ParentClassInfo& info, _parentClasses) {
522 foreach(const ParentClassInfo& info, _parentClasses) {
514 if (info._parent->inherits(classInfo)) {
523 if (info._parent->inherits(classInfo)) {
515 return true;
524 return true;
516 }
525 }
517 }
526 }
518 return false;
527 return false;
519 }
528 }
520
529
521 QString PythonQtClassInfo::help()
530 QString PythonQtClassInfo::help()
522 {
531 {
523 decorator();
532 decorator();
524 QString h;
533 QString h;
525 h += QString("--- ") + QString(className()) + QString(" ---\n");
534 h += QString("--- ") + QString(className()) + QString(" ---\n");
526
535
527 if (_isQObject) {
536 if (_isQObject) {
528 h += "Properties:\n";
537 h += "Properties:\n";
529
538
530 int i;
539 int i;
531 int numProperties = _meta->propertyCount();
540 int numProperties = _meta->propertyCount();
532 for (i = 0; i < numProperties; i++) {
541 for (i = 0; i < numProperties; i++) {
533 QMetaProperty p = _meta->property(i);
542 QMetaProperty p = _meta->property(i);
534 h += QString(p.name()) + " (" + QString(p.typeName()) + " )\n";
543 h += QString(p.name()) + " (" + QString(p.typeName()) + " )\n";
535 }
544 }
536 }
545 }
537
546
538 if (constructors()) {
547 if (constructors()) {
539 h += "Constructors:\n";
548 h += "Constructors:\n";
540 PythonQtSlotInfo* constr = constructors();
549 PythonQtSlotInfo* constr = constructors();
541 while (constr) {
550 while (constr) {
542 h += constr->fullSignature() + "\n";
551 h += constr->fullSignature() + "\n";
543 constr = constr->nextInfo();
552 constr = constr->nextInfo();
544 }
553 }
545 }
554 }
546
555
547 h += "Slots:\n";
556 h += "Slots:\n";
548 h += "QString help()\n";
557 h += "QString help()\n";
549 h += "QString className()\n";
558 h += "QString className()\n";
550
559
551 if (_meta) {
560 if (_meta) {
552 int numMethods = _meta->methodCount();
561 int numMethods = _meta->methodCount();
553 for (int i = 0; i < numMethods; i++) {
562 for (int i = 0; i < numMethods; i++) {
554 QMetaMethod m = _meta->method(i);
563 QMetaMethod m = _meta->method(i);
555 if ((m.methodType() == QMetaMethod::Method ||
564 if ((m.methodType() == QMetaMethod::Method ||
556 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
565 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
557 QByteArray signa(m.signature());
566 QByteArray signa(m.signature());
558 if (signa.startsWith("new_")) continue;
567 if (signa.startsWith("new_")) continue;
559 if (signa.startsWith("delete_")) continue;
568 if (signa.startsWith("delete_")) continue;
560 if (signa.startsWith("static_")) continue;
569 if (signa.startsWith("static_")) continue;
561 PythonQtSlotInfo slot(m, i);
570 PythonQtSlotInfo slot(m, i);
562 h += slot.fullSignature()+ "\n";
571 h += slot.fullSignature()+ "\n";
563 }
572 }
564 }
573 }
565 }
574 }
566
575
567 // TODO xxx : decorators and enums from decorator() are missing...
576 // TODO xxx : decorators and enums from decorator() are missing...
568 // maybe we can reuse memberlist()?
577 // maybe we can reuse memberlist()?
569
578
570 if (_meta && _meta->enumeratorCount()) {
579 if (_meta && _meta->enumeratorCount()) {
571 h += "Enums:\n";
580 h += "Enums:\n";
572 for (int i = 0; i<_meta->enumeratorCount(); i++) {
581 for (int i = 0; i<_meta->enumeratorCount(); i++) {
573 QMetaEnum e = _meta->enumerator(i);
582 QMetaEnum e = _meta->enumerator(i);
574 h += QString(e.name()) + " {";
583 h += QString(e.name()) + " {";
575 for (int j=0; j < e.keyCount(); j++) {
584 for (int j=0; j < e.keyCount(); j++) {
576 if (j) { h+= ", "; }
585 if (j) { h+= ", "; }
577 h += e.key(j);
586 h += e.key(j);
578 }
587 }
579 h += " }\n";
588 h += " }\n";
580 }
589 }
581 }
590 }
582
591
583 if (_isQObject && _meta) {
592 if (_isQObject && _meta) {
584 int numMethods = _meta->methodCount();
593 int numMethods = _meta->methodCount();
585 if (numMethods>0) {
594 if (numMethods>0) {
586 h += "Signals:\n";
595 h += "Signals:\n";
587 for (int i = 0; i < numMethods; i++) {
596 for (int i = 0; i < numMethods; i++) {
588 QMetaMethod m = _meta->method(i);
597 QMetaMethod m = _meta->method(i);
589 if (m.methodType() == QMetaMethod::Signal) {
598 if (m.methodType() == QMetaMethod::Signal) {
590 h += QString(m.signature()) + "\n";
599 h += QString(m.signature()) + "\n";
591 }
600 }
592 }
601 }
593 }
602 }
594 }
603 }
595 return h;
604 return h;
596 }
605 }
597
606
598 PythonQtSlotInfo* PythonQtClassInfo::constructors()
607 PythonQtSlotInfo* PythonQtClassInfo::constructors()
599 {
608 {
600 if (!_constructors) {
609 if (!_constructors) {
601 // force creation of lazy decorator, which will register the decorators
610 // force creation of lazy decorator, which will register the decorators
602 decorator();
611 decorator();
603 }
612 }
604 return _constructors;
613 return _constructors;
605 }
614 }
606
615
607 PythonQtSlotInfo* PythonQtClassInfo::destructor()
616 PythonQtSlotInfo* PythonQtClassInfo::destructor()
608 {
617 {
609 if (!_destructor) {
618 if (!_destructor) {
610 // force creation of lazy decorator, which will register the decorators
619 // force creation of lazy decorator, which will register the decorators
611 decorator();
620 decorator();
612 }
621 }
613 return _destructor;
622 return _destructor;
614 }
623 }
615
624
616 void PythonQtClassInfo::addConstructor(PythonQtSlotInfo* info)
625 void PythonQtClassInfo::addConstructor(PythonQtSlotInfo* info)
617 {
626 {
618 PythonQtSlotInfo* prev = constructors();
627 PythonQtSlotInfo* prev = constructors();
619 if (prev) {
628 if (prev) {
620 info->setNextInfo(prev->nextInfo());
629 info->setNextInfo(prev->nextInfo());
621 prev->setNextInfo(info);
630 prev->setNextInfo(info);
622 } else {
631 } else {
623 _constructors = info;
632 _constructors = info;
624 }
633 }
625 }
634 }
626
635
627 void PythonQtClassInfo::addDecoratorSlot(PythonQtSlotInfo* info)
636 void PythonQtClassInfo::addDecoratorSlot(PythonQtSlotInfo* info)
628 {
637 {
629 _decoratorSlots.append(info);
638 _decoratorSlots.append(info);
630 }
639 }
631
640
632 void PythonQtClassInfo::setDestructor(PythonQtSlotInfo* info)
641 void PythonQtClassInfo::setDestructor(PythonQtSlotInfo* info)
633 {
642 {
634 if (_destructor) {
643 if (_destructor) {
635 _destructor->deleteOverloadsAndThis();
644 _destructor->deleteOverloadsAndThis();
636 }
645 }
637 _destructor = info;
646 _destructor = info;
638 }
647 }
639
648
640 void PythonQtClassInfo::setMetaObject(const QMetaObject* meta)
649 void PythonQtClassInfo::setMetaObject(const QMetaObject* meta)
641 {
650 {
642 _meta = meta;
651 _meta = meta;
643 clearCachedMembers();
652 clearCachedMembers();
644 }
653 }
645
654
646 QObject* PythonQtClassInfo::decorator()
655 QObject* PythonQtClassInfo::decorator()
647 {
656 {
648 if (!_decoratorProvider && _decoratorProviderCB) {
657 if (!_decoratorProvider && _decoratorProviderCB) {
649 _decoratorProvider = (*_decoratorProviderCB)();
658 _decoratorProvider = (*_decoratorProviderCB)();
650 if (_decoratorProvider) {
659 if (_decoratorProvider) {
651 _decoratorProvider->setParent(PythonQt::priv());
660 _decoratorProvider->setParent(PythonQt::priv());
652 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
661 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
653 }
662 }
654 }
663 }
655 return _decoratorProvider;
664 return _decoratorProvider;
656 }
665 }
657
666
658 bool PythonQtClassInfo::hasOwnerMethodButNoOwner(void* object)
667 bool PythonQtClassInfo::hasOwnerMethodButNoOwner(void* object)
659 {
668 {
660 PythonQtMemberInfo info = member("hasOwner");
669 PythonQtMemberInfo info = member("hasOwner");
661 if (info._type == PythonQtMemberInfo::Slot) {
670 if (info._type == PythonQtMemberInfo::Slot) {
662 void* obj = object;
671 void* obj = object;
663 bool result = false;
672 bool result = false;
664 void* args[2];
673 void* args[2];
665 args[0] = &result;
674 args[0] = &result;
666 args[1] = &obj;
675 args[1] = &obj;
667 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
676 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
668 return !result;
677 return !result;
669 } else {
678 } else {
670 return false;
679 return false;
671 }
680 }
672 }
681 }
673
682
674 void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, char** resultClassName)
683 void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, char** resultClassName)
675 {
684 {
676 if (!_polymorphicHandlers.isEmpty()) {
685 if (!_polymorphicHandlers.isEmpty()) {
677 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
686 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
678 void* resultPtr = (*cb)(ptr, resultClassName);
687 void* resultPtr = (*cb)(ptr, resultClassName);
679 if (resultPtr) {
688 if (resultPtr) {
680 return resultPtr;
689 return resultPtr;
681 }
690 }
682 }
691 }
683 }
692 }
684 foreach(const ParentClassInfo& info, _parentClasses) {
693 foreach(const ParentClassInfo& info, _parentClasses) {
685 if (!info._parent->isQObject()) {
694 if (!info._parent->isQObject()) {
686 void* resultPtr = info._parent->recursiveCastDownIfPossible((char*)ptr + info._upcastingOffset, resultClassName);
695 void* resultPtr = info._parent->recursiveCastDownIfPossible((char*)ptr + info._upcastingOffset, resultClassName);
687 if (resultPtr) {
696 if (resultPtr) {
688 return resultPtr;
697 return resultPtr;
689 }
698 }
690 }
699 }
691 }
700 }
692 return NULL;
701 return NULL;
693 }
702 }
694
703
695 void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo)
704 void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo)
696 {
705 {
697 char* className;
706 char* className;
698 // this would do downcasting recursively...
707 // this would do downcasting recursively...
699 // void* resultPtr = recursiveCastDownIfPossible(ptr, &className);
708 // void* resultPtr = recursiveCastDownIfPossible(ptr, &className);
700
709
701 // we only do downcasting on the base object, not on the whole inheritance tree...
710 // we only do downcasting on the base object, not on the whole inheritance tree...
702 void* resultPtr = NULL;
711 void* resultPtr = NULL;
703 if (!_polymorphicHandlers.isEmpty()) {
712 if (!_polymorphicHandlers.isEmpty()) {
704 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
713 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
705 resultPtr = (*cb)(ptr, &className);
714 resultPtr = (*cb)(ptr, &className);
706 if (resultPtr) {
715 if (resultPtr) {
707 break;
716 break;
708 }
717 }
709 }
718 }
710 }
719 }
711 if (resultPtr) {
720 if (resultPtr) {
712 *resultClassInfo = PythonQt::priv()->getClassInfo(className);
721 *resultClassInfo = PythonQt::priv()->getClassInfo(className);
713 } else {
722 } else {
714 *resultClassInfo = this;
723 *resultClassInfo = this;
715 resultPtr = ptr;
724 resultPtr = ptr;
716 }
725 }
717 return resultPtr;
726 return resultPtr;
718 }
727 }
@@ -1,240 +1,243
1 #ifndef _PYTHONQTCLASSINFO_H
1 #ifndef _PYTHONQTCLASSINFO_H
2 #define _PYTHONQTCLASSINFO_H
2 #define _PYTHONQTCLASSINFO_H
3
3
4 /*
4 /*
5 *
5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
7 *
7 *
8 * This library is free software; you can redistribute it and/or
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
11 * version 2.1 of the License, or (at your option) any later version.
12 *
12 *
13 * This library is distributed in the hope that it will be useful,
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
16 * Lesser General Public License for more details.
17 *
17 *
18 * Further, this software is distributed without any warranty that it is
18 * Further, this software is distributed without any warranty that it is
19 * free of the rightful claim of any third person regarding infringement
19 * free of the rightful claim of any third person regarding infringement
20 * or the like. Any license provided herein, whether implied or
20 * or the like. Any license provided herein, whether implied or
21 * otherwise, applies only to this software file. Patent licenses, if
21 * otherwise, applies only to this software file. Patent licenses, if
22 * any, provided herein do not apply to combinations of this program with
22 * any, provided herein do not apply to combinations of this program with
23 * other software, or any other product whatsoever.
23 * other software, or any other product whatsoever.
24 *
24 *
25 * You should have received a copy of the GNU Lesser General Public
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
30 * 28359 Bremen, Germany or:
30 * 28359 Bremen, Germany or:
31 *
31 *
32 * http://www.mevis.de
32 * http://www.mevis.de
33 *
33 *
34 */
34 */
35
35
36 #include <QMetaObject>
36 #include <QMetaObject>
37 #include <QMetaMethod>
37 #include <QMetaMethod>
38 #include <QHash>
38 #include <QHash>
39 #include <QByteArray>
39 #include <QByteArray>
40 #include <QList>
40 #include <QList>
41 #include "PythonQt.h"
41 #include "PythonQt.h"
42
42
43 class PythonQtSlotInfo;
43 class PythonQtSlotInfo;
44
44
45 struct PythonQtMemberInfo {
45 struct PythonQtMemberInfo {
46 enum Type {
46 enum Type {
47 Invalid, Slot, EnumValue, Property, NotFound
47 Invalid, Slot, EnumValue, Property, NotFound
48 };
48 };
49
49
50 PythonQtMemberInfo():_slot(NULL),_enumValue(0),_type(Invalid) { }
50 PythonQtMemberInfo():_slot(NULL),_enumValue(0),_type(Invalid) { }
51
51
52 PythonQtMemberInfo(PythonQtSlotInfo* info) {
52 PythonQtMemberInfo(PythonQtSlotInfo* info) {
53 _type = Slot;
53 _type = Slot;
54 _slot = info;
54 _slot = info;
55 _enumValue = 0;
55 _enumValue = 0;
56 }
56 }
57
57
58 PythonQtMemberInfo(unsigned int enumValue) {
58 PythonQtMemberInfo(unsigned int enumValue) {
59 _type = EnumValue;
59 _type = EnumValue;
60 _slot = NULL;
60 _slot = NULL;
61 _enumValue = enumValue;
61 _enumValue = enumValue;
62 }
62 }
63
63
64 PythonQtMemberInfo(const QMetaProperty& prop) {
64 PythonQtMemberInfo(const QMetaProperty& prop) {
65 _type = Property;
65 _type = Property;
66 _slot = NULL;
66 _slot = NULL;
67 _enumValue = 0;
67 _enumValue = 0;
68 _property = prop;
68 _property = prop;
69 }
69 }
70
70
71 Type _type;
71 Type _type;
72
72
73 // TODO: this could be a union...
73 // TODO: this could be a union...
74 PythonQtSlotInfo* _slot;
74 PythonQtSlotInfo* _slot;
75 unsigned int _enumValue;
75 unsigned int _enumValue;
76 QMetaProperty _property;
76 QMetaProperty _property;
77 };
77 };
78
78
79 //! a class that stores all required information about a Qt object (and an optional associated C++ class name)
79 //! a class that stores all required information about a Qt object (and an optional associated C++ class name)
80 /*! for fast lookup of slots when calling the object from Python
80 /*! for fast lookup of slots when calling the object from Python
81 */
81 */
82 class PythonQtClassInfo {
82 class PythonQtClassInfo {
83
83
84 public:
84 public:
85 PythonQtClassInfo();
85 PythonQtClassInfo();
86 ~PythonQtClassInfo();
86 ~PythonQtClassInfo();
87
87
88 //! store information about parent classes
88 //! store information about parent classes
89 struct ParentClassInfo {
89 struct ParentClassInfo {
90 ParentClassInfo(PythonQtClassInfo* parent, int upcastingOffset=0):_parent(parent),_upcastingOffset(upcastingOffset)
90 ParentClassInfo(PythonQtClassInfo* parent, int upcastingOffset=0):_parent(parent),_upcastingOffset(upcastingOffset)
91 {};
91 {};
92
92
93 PythonQtClassInfo* _parent;
93 PythonQtClassInfo* _parent;
94 int _upcastingOffset;
94 int _upcastingOffset;
95 };
95 };
96
96
97
97
98 //! setup as a QObject, taking the meta object as meta information about the QObject
98 //! setup as a QObject, taking the meta object as meta information about the QObject
99 void setupQObject(const QMetaObject* meta);
99 void setupQObject(const QMetaObject* meta);
100
100
101 //! setup as a CPP (non-QObject), taking the classname
101 //! setup as a CPP (non-QObject), taking the classname
102 void setupCPPObject(const QByteArray& classname);
102 void setupCPPObject(const QByteArray& classname);
103
103
104 //! get the Python method definition for a given slot name (without return type and signature)
104 //! get the Python method definition for a given slot name (without return type and signature)
105 PythonQtMemberInfo member(const char* member);
105 PythonQtMemberInfo member(const char* member);
106
106
107 //! get access to the constructor slot (which may be overloaded if there are multiple constructors)
107 //! get access to the constructor slot (which may be overloaded if there are multiple constructors)
108 PythonQtSlotInfo* constructors();
108 PythonQtSlotInfo* constructors();
109
109
110 //! get access to the destructor slot
110 //! get access to the destructor slot
111 PythonQtSlotInfo* destructor();
111 PythonQtSlotInfo* destructor();
112
112
113 //! add a constructor, ownership is passed to classinfo
113 //! add a constructor, ownership is passed to classinfo
114 void addConstructor(PythonQtSlotInfo* info);
114 void addConstructor(PythonQtSlotInfo* info);
115
115
116 //! set a destructor, ownership is passed to classinfo
116 //! set a destructor, ownership is passed to classinfo
117 void setDestructor(PythonQtSlotInfo* info);
117 void setDestructor(PythonQtSlotInfo* info);
118
118
119 //! add a decorator slot, ownership is passed to classinfo
119 //! add a decorator slot, ownership is passed to classinfo
120 void addDecoratorSlot(PythonQtSlotInfo* info);
120 void addDecoratorSlot(PythonQtSlotInfo* info);
121
121
122 //! get the classname (either of the QObject or of the wrapped CPP object)
122 //! get the classname (either of the QObject or of the wrapped CPP object)
123 const char* className();
123 const char* className();
124
124
125 //! returns if the QObject
125 //! returns if the QObject
126 bool isQObject() { return _isQObject; }
126 bool isQObject() { return _isQObject; }
127
127
128 //! returns if the class is a CPP wrapper
128 //! returns if the class is a CPP wrapper
129 bool isCPPWrapper() { return !_isQObject; }
129 bool isCPPWrapper() { return !_isQObject; }
130
130
131 //! get the meta object
131 //! get the meta object
132 const QMetaObject* metaObject() { return _meta; }
132 const QMetaObject* metaObject() { return _meta; }
133
133
134 //! set the meta object, this will reset the caching
134 //! set the meta object, this will reset the caching
135 void setMetaObject(const QMetaObject* meta);
135 void setMetaObject(const QMetaObject* meta);
136
136
137 //! returns if this class inherits from the given classname
137 //! returns if this class inherits from the given classname
138 bool inherits(const char* classname);
138 bool inherits(const char* classname);
139
139
140 //! returns if this class inherits from the given classinfo
140 //! returns if this class inherits from the given classinfo
141 bool inherits(PythonQtClassInfo* info);
141 bool inherits(PythonQtClassInfo* info);
142
142
143 //! casts the given \c ptr to an object of type \c classname, returns the new pointer
143 //! casts the given \c ptr to an object of type \c classname, returns the new pointer
144 //! which might be different to \c ptr due to C++ multiple inheritance
144 //! which might be different to \c ptr due to C++ multiple inheritance
145 //! (if the cast is not possible or if ptr is NULL, NULL is returned)
145 //! (if the cast is not possible or if ptr is NULL, NULL is returned)
146 void* castTo(void* ptr, const char* classname);
146 void* castTo(void* ptr, const char* classname);
147
147
148 //! get help string for the metaobject
148 //! get help string for the metaobject
149 QString help();
149 QString help();
150
150
151 //! get list of all properties (on QObjects only, otherwise the list is empty)
152 QStringList propertyList();
153
151 //! get list of all members
154 //! get list of all members
152 QStringList memberList(bool metaOnly = false);
155 QStringList memberList(bool metaOnly = false);
153
156
154 //! get the meta type id of this class (only valid for isCPPWrapper() == true)
157 //! get the meta type id of this class (only valid for isCPPWrapper() == true)
155 int metaTypeId() { return _metaTypeId; }
158 int metaTypeId() { return _metaTypeId; }
156
159
157 //! set an additional decorator provider that offers additional decorator slots for this class
160 //! set an additional decorator provider that offers additional decorator slots for this class
158 void setDecoratorProvider(PythonQtQObjectCreatorFunctionCB* cb) { _decoratorProviderCB = cb; _decoratorProvider = NULL; }
161 void setDecoratorProvider(PythonQtQObjectCreatorFunctionCB* cb) { _decoratorProviderCB = cb; _decoratorProvider = NULL; }
159
162
160 //! get the decorator qobject instance
163 //! get the decorator qobject instance
161 QObject* decorator();
164 QObject* decorator();
162
165
163 //! add the parent class info of a CPP object
166 //! add the parent class info of a CPP object
164 void addParentClass(const ParentClassInfo& info) { _parentClasses.append(info); }
167 void addParentClass(const ParentClassInfo& info) { _parentClasses.append(info); }
165
168
166 //! check if the special method "hasOwner" is implemented and if it returns false, which means that the object may be destroyed
169 //! check if the special method "hasOwner" is implemented and if it returns false, which means that the object may be destroyed
167 bool hasOwnerMethodButNoOwner(void* object);
170 bool hasOwnerMethodButNoOwner(void* object);
168
171
169 //! set the associated PythonQtClassWrapper (which handles instance creation of this type)
172 //! set the associated PythonQtClassWrapper (which handles instance creation of this type)
170 void setPythonQtClassWrapper(PyObject* obj) { _pythonQtClassWrapper = obj; }
173 void setPythonQtClassWrapper(PyObject* obj) { _pythonQtClassWrapper = obj; }
171
174
172 //! get the associated PythonQtClassWrapper (which handles instance creation of this type)
175 //! get the associated PythonQtClassWrapper (which handles instance creation of this type)
173 PyObject* pythonQtClassWrapper() { return _pythonQtClassWrapper; }
176 PyObject* pythonQtClassWrapper() { return _pythonQtClassWrapper; }
174
177
175 //! set the shell set instance wrapper cb
178 //! set the shell set instance wrapper cb
176 void setShellSetInstanceWrapperCB(PythonQtShellSetInstanceWrapperCB* cb) {
179 void setShellSetInstanceWrapperCB(PythonQtShellSetInstanceWrapperCB* cb) {
177 _shellSetInstanceWrapperCB = cb;
180 _shellSetInstanceWrapperCB = cb;
178 }
181 }
179
182
180 //! get the shell set instance wrapper cb
183 //! get the shell set instance wrapper cb
181 PythonQtShellSetInstanceWrapperCB* shellSetInstanceWrapperCB() {
184 PythonQtShellSetInstanceWrapperCB* shellSetInstanceWrapperCB() {
182 return _shellSetInstanceWrapperCB;
185 return _shellSetInstanceWrapperCB;
183 }
186 }
184
187
185 //! add a handler for polymorphic downcasting
188 //! add a handler for polymorphic downcasting
186 void addPolymorphicHandler(PythonQtPolymorphicHandlerCB* cb) { _polymorphicHandlers.append(cb); }
189 void addPolymorphicHandler(PythonQtPolymorphicHandlerCB* cb) { _polymorphicHandlers.append(cb); }
187
190
188 //! cast the pointer down in the class hierarchy if a polymorphic handler allows to do that
191 //! cast the pointer down in the class hierarchy if a polymorphic handler allows to do that
189 void* castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo);
192 void* castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo);
190
193
191 private:
194 private:
192 //! clear all cached members
195 //! clear all cached members
193 void clearCachedMembers();
196 void clearCachedMembers();
194
197
195 void* recursiveCastDownIfPossible(void* ptr, char** resultClassName);
198 void* recursiveCastDownIfPossible(void* ptr, char** resultClassName);
196
199
197 PythonQtSlotInfo* findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
200 PythonQtSlotInfo* findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
198 void listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly);
201 void listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly);
199 PythonQtSlotInfo* recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
202 PythonQtSlotInfo* recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
200
203
201 void recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects);
204 void recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects);
202 void recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects);
205 void recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects);
203
206
204 bool lookForPropertyAndCache(const char* memberName);
207 bool lookForPropertyAndCache(const char* memberName);
205 bool lookForMethodAndCache(const char* memberName);
208 bool lookForMethodAndCache(const char* memberName);
206 bool lookForEnumAndCache(const QMetaObject* m, const char* memberName);
209 bool lookForEnumAndCache(const QMetaObject* m, const char* memberName);
207
210
208 PythonQtSlotInfo* findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
211 PythonQtSlotInfo* findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
209 int findCharOffset(const char* sigStart, char someChar);
212 int findCharOffset(const char* sigStart, char someChar);
210
213
211 QHash<QByteArray, PythonQtMemberInfo> _cachedMembers;
214 QHash<QByteArray, PythonQtMemberInfo> _cachedMembers;
212
215
213 PythonQtSlotInfo* _constructors;
216 PythonQtSlotInfo* _constructors;
214 PythonQtSlotInfo* _destructor;
217 PythonQtSlotInfo* _destructor;
215 QList<PythonQtSlotInfo*> _decoratorSlots;
218 QList<PythonQtSlotInfo*> _decoratorSlots;
216
219
217 const QMetaObject* _meta;
220 const QMetaObject* _meta;
218
221
219 QByteArray _wrappedClassName;
222 QByteArray _wrappedClassName;
220 QList<ParentClassInfo> _parentClasses;
223 QList<ParentClassInfo> _parentClasses;
221
224
222 QList<PythonQtPolymorphicHandlerCB*> _polymorphicHandlers;
225 QList<PythonQtPolymorphicHandlerCB*> _polymorphicHandlers;
223
226
224 QObject* _decoratorProvider;
227 QObject* _decoratorProvider;
225 PythonQtQObjectCreatorFunctionCB* _decoratorProviderCB;
228 PythonQtQObjectCreatorFunctionCB* _decoratorProviderCB;
226
229
227 PyObject* _pythonQtClassWrapper;
230 PyObject* _pythonQtClassWrapper;
228
231
229 PythonQtShellSetInstanceWrapperCB* _shellSetInstanceWrapperCB;
232 PythonQtShellSetInstanceWrapperCB* _shellSetInstanceWrapperCB;
230
233
231 int _metaTypeId;
234 int _metaTypeId;
232
235
233 bool _isQObject;
236 bool _isQObject;
234
237
235 };
238 };
236
239
237 //---------------------------------------------------------------
240 //---------------------------------------------------------------
238
241
239
242
240 #endif
243 #endif
@@ -1,567 +1,571
1 /*
1 /*
2 *
2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2006 MeVis Research GmbH 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 Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Research GmbH, 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 PythonQtInstanceWrapper.cpp
35 // \file PythonQtInstanceWrapper.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 "PythonQtInstanceWrapper.h"
42 #include "PythonQtInstanceWrapper.h"
43 #include <QObject>
43 #include <QObject>
44 #include "PythonQt.h"
44 #include "PythonQt.h"
45 #include "PythonQtSlot.h"
45 #include "PythonQtSlot.h"
46 #include "PythonQtClassInfo.h"
46 #include "PythonQtClassInfo.h"
47 #include "PythonQtConversion.h"
47 #include "PythonQtConversion.h"
48 #include "PythonQtClassWrapper.h"
48 #include "PythonQtClassWrapper.h"
49
49
50 PythonQtClassInfo* PythonQtInstanceWrapperStruct::classInfo()
50 PythonQtClassInfo* PythonQtInstanceWrapperStruct::classInfo()
51 {
51 {
52 // take the class info from our type object
52 // take the class info from our type object
53 return ((PythonQtClassWrapper*)ob_type)->_classInfo;
53 return ((PythonQtClassWrapper*)ob_type)->_classInfo;
54 }
54 }
55
55
56 static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, bool force = false) {
56 static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, bool force = false) {
57
57
58 // is this a C++ wrapper?
58 // is this a C++ wrapper?
59 if (self->_wrappedPtr) {
59 if (self->_wrappedPtr) {
60 //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
60 //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
61
61
62 PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr);
62 PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr);
63 // we own our qobject, so we delete it now:
63 // we own our qobject, so we delete it now:
64 delete self->_obj;
64 delete self->_obj;
65 self->_obj = NULL;
65 self->_obj = NULL;
66 if (force || self->classInfo()->hasOwnerMethodButNoOwner(self->_wrappedPtr) || self->_ownedByPythonQt) {
66 if (force || self->classInfo()->hasOwnerMethodButNoOwner(self->_wrappedPtr) || self->_ownedByPythonQt) {
67 int type = self->classInfo()->metaTypeId();
67 int type = self->classInfo()->metaTypeId();
68 if (self->_useQMetaTypeDestroy && type>=0) {
68 if (self->_useQMetaTypeDestroy && type>=0) {
69 // use QMetaType to destroy the object
69 // use QMetaType to destroy the object
70 QMetaType::destroy(type, self->_wrappedPtr);
70 QMetaType::destroy(type, self->_wrappedPtr);
71 } else {
71 } else {
72 PythonQtSlotInfo* slot = self->classInfo()->destructor();
72 PythonQtSlotInfo* slot = self->classInfo()->destructor();
73 if (slot) {
73 if (slot) {
74 void* args[2];
74 void* args[2];
75 args[0] = NULL;
75 args[0] = NULL;
76 args[1] = &self->_wrappedPtr;
76 args[1] = &self->_wrappedPtr;
77 slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, slot->slotIndex(), args);
77 slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, slot->slotIndex(), args);
78 self->_wrappedPtr = NULL;
78 self->_wrappedPtr = NULL;
79 } else {
79 } else {
80 if (type>=0) {
80 if (type>=0) {
81 // use QMetaType to destroy the object
81 // use QMetaType to destroy the object
82 QMetaType::destroy(type, self->_wrappedPtr);
82 QMetaType::destroy(type, self->_wrappedPtr);
83 } else {
83 } else {
84 // TODO: warn about not being able to destroy the object?
84 // TODO: warn about not being able to destroy the object?
85 }
85 }
86 }
86 }
87 }
87 }
88 }
88 }
89 } else {
89 } else {
90 //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
90 //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
91 if (self->_objPointerCopy) {
91 if (self->_objPointerCopy) {
92 PythonQt::priv()->removeWrapperPointer(self->_objPointerCopy);
92 PythonQt::priv()->removeWrapperPointer(self->_objPointerCopy);
93 }
93 }
94 if (self->_obj) {
94 if (self->_obj) {
95 if (force || self->_ownedByPythonQt) {
95 if (force || self->_ownedByPythonQt) {
96 if (force || !self->_obj->parent()) {
96 if (force || !self->_obj->parent()) {
97 delete self->_obj;
97 delete self->_obj;
98 }
98 }
99 } else {
99 } else {
100 if (self->_obj->parent()==NULL) {
100 if (self->_obj->parent()==NULL) {
101 // tell someone who is interested that the qobject is no longer wrapped, if it has no parent
101 // tell someone who is interested that the qobject is no longer wrapped, if it has no parent
102 PythonQt::qObjectNoLongerWrappedCB(self->_obj);
102 PythonQt::qObjectNoLongerWrappedCB(self->_obj);
103 }
103 }
104 }
104 }
105 }
105 }
106 }
106 }
107 self->_obj = NULL;
107 self->_obj = NULL;
108 }
108 }
109
109
110 static void PythonQtInstanceWrapper_dealloc(PythonQtInstanceWrapper* self)
110 static void PythonQtInstanceWrapper_dealloc(PythonQtInstanceWrapper* self)
111 {
111 {
112 PythonQtInstanceWrapper_deleteObject(self);
112 PythonQtInstanceWrapper_deleteObject(self);
113 self->_obj.~QPointer<QObject>();
113 self->_obj.~QPointer<QObject>();
114 self->ob_type->tp_free((PyObject*)self);
114 self->ob_type->tp_free((PyObject*)self);
115 }
115 }
116
116
117 static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * args, PyObject * /*kwds*/)
117 static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * args, PyObject * /*kwds*/)
118 {
118 {
119 //PythonQtClassWrapper *classType = (PythonQtClassWrapper*)type;
119 //PythonQtClassWrapper *classType = (PythonQtClassWrapper*)type;
120 PythonQtInstanceWrapper *self;
120 PythonQtInstanceWrapper *self;
121 static PyObject* emptyTuple = NULL;
121 static PyObject* emptyTuple = NULL;
122 if (emptyTuple==NULL) {
122 if (emptyTuple==NULL) {
123 emptyTuple = PyTuple_New(0);
123 emptyTuple = PyTuple_New(0);
124 }
124 }
125
125
126 self = (PythonQtInstanceWrapper*)PyBaseObject_Type.tp_new(type, emptyTuple, NULL);
126 self = (PythonQtInstanceWrapper*)PyBaseObject_Type.tp_new(type, emptyTuple, NULL);
127
127
128 if (self != NULL) {
128 if (self != NULL) {
129 new (&self->_obj) QPointer<QObject>();
129 new (&self->_obj) QPointer<QObject>();
130 self->_wrappedPtr = NULL;
130 self->_wrappedPtr = NULL;
131 self->_ownedByPythonQt = false;
131 self->_ownedByPythonQt = false;
132 self->_useQMetaTypeDestroy = false;
132 self->_useQMetaTypeDestroy = false;
133 self->_isShellInstance = false;
133 self->_isShellInstance = false;
134 }
134 }
135 return (PyObject *)self;
135 return (PyObject *)self;
136 }
136 }
137
137
138 int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds)
138 int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds)
139 {
139 {
140 if (args == PythonQtPrivate::dummyTuple()) {
140 if (args == PythonQtPrivate::dummyTuple()) {
141 // we are called from the internal PythonQt API, so our data will be filled later on...
141 // we are called from the internal PythonQt API, so our data will be filled later on...
142 return 0;
142 return 0;
143 }
143 }
144
144
145 // we are called from python, try to construct our object
145 // we are called from python, try to construct our object
146 if (self->classInfo()->constructors()) {
146 if (self->classInfo()->constructors()) {
147 void* directCPPPointer = NULL;
147 void* directCPPPointer = NULL;
148 PythonQtSlotFunction_CallImpl(NULL, self->classInfo()->constructors(), args, kwds, NULL, &directCPPPointer);
148 PythonQtSlotFunction_CallImpl(NULL, self->classInfo()->constructors(), args, kwds, NULL, &directCPPPointer);
149 if (PyErr_Occurred()) {
149 if (PyErr_Occurred()) {
150 return -1;
150 return -1;
151 }
151 }
152 if (directCPPPointer) {
152 if (directCPPPointer) {
153 // change ownershipflag to be owned by PythonQt
153 // change ownershipflag to be owned by PythonQt
154 self->_ownedByPythonQt = true;
154 self->_ownedByPythonQt = true;
155 self->_useQMetaTypeDestroy = false;
155 self->_useQMetaTypeDestroy = false;
156 if (self->classInfo()->isCPPWrapper()) {
156 if (self->classInfo()->isCPPWrapper()) {
157 self->_wrappedPtr = directCPPPointer;
157 self->_wrappedPtr = directCPPPointer;
158 // TODO xxx: if there is a wrapper factory, we might want to generate a wrapper for our class?!
158 // TODO xxx: if there is a wrapper factory, we might want to generate a wrapper for our class?!
159 } else {
159 } else {
160 self->setQObject((QObject*)directCPPPointer);
160 self->setQObject((QObject*)directCPPPointer);
161 }
161 }
162 // register with PythonQt
162 // register with PythonQt
163 PythonQt::priv()->addWrapperPointer(directCPPPointer, self);
163 PythonQt::priv()->addWrapperPointer(directCPPPointer, self);
164
164
165 PythonQtShellSetInstanceWrapperCB* cb = self->classInfo()->shellSetInstanceWrapperCB();
165 PythonQtShellSetInstanceWrapperCB* cb = self->classInfo()->shellSetInstanceWrapperCB();
166 if (cb) {
166 if (cb) {
167 // if we are a derived python class, we set the wrapper
167 // if we are a derived python class, we set the wrapper
168 // to activate the shell class, otherwise we just ignore that it is a shell...
168 // to activate the shell class, otherwise we just ignore that it is a shell...
169 // we detect it be checking if the type does not have PythonQtInstanceWrapper_Type as direct base class,
169 // we detect it be checking if the type does not have PythonQtInstanceWrapper_Type as direct base class,
170 // which is the case for all non-python derived types
170 // which is the case for all non-python derived types
171 if (((PyObject*)self)->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
171 if (((PyObject*)self)->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
172 // set the wrapper and remember that we have a shell instance!
172 // set the wrapper and remember that we have a shell instance!
173 (*cb)(directCPPPointer, self);
173 (*cb)(directCPPPointer, self);
174 self->_isShellInstance = true;
174 self->_isShellInstance = true;
175 }
175 }
176 }
176 }
177 }
177 }
178 } else {
178 } else {
179 QString error = QString("No constructors available for ") + self->classInfo()->className();
179 QString error = QString("No constructors available for ") + self->classInfo()->className();
180 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
180 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
181 return -1;
181 return -1;
182 }
182 }
183 return 0;
183 return 0;
184 }
184 }
185
185
186 static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* obj)
186 static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* obj)
187 {
187 {
188 return PyString_FromString(obj->ob_type->tp_name);
188 return PyString_FromString(obj->ob_type->tp_name);
189 }
189 }
190
190
191 static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* obj)
191 static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* obj)
192 {
192 {
193 return PythonQt::self()->helpCalled(obj->classInfo());
193 return PythonQt::self()->helpCalled(obj->classInfo());
194 }
194 }
195
195
196 static PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self)
196 static PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self)
197 {
197 {
198 PythonQtInstanceWrapper_deleteObject(self, true);
198 PythonQtInstanceWrapper_deleteObject(self, true);
199 Py_INCREF(Py_None);
199 Py_INCREF(Py_None);
200 return Py_None;
200 return Py_None;
201 }
201 }
202
202
203
203
204 static PyMethodDef PythonQtInstanceWrapper_methods[] = {
204 static PyMethodDef PythonQtInstanceWrapper_methods[] = {
205 {"className", (PyCFunction)PythonQtInstanceWrapper_classname, METH_NOARGS,
205 {"className", (PyCFunction)PythonQtInstanceWrapper_classname, METH_NOARGS,
206 "Return the classname of the object"
206 "Return the classname of the object"
207 },
207 },
208 {"help", (PyCFunction)PythonQtInstanceWrapper_help, METH_NOARGS,
208 {"help", (PyCFunction)PythonQtInstanceWrapper_help, METH_NOARGS,
209 "Shows the help of available methods for this class"
209 "Shows the help of available methods for this class"
210 },
210 },
211 {"delete", (PyCFunction)PythonQtInstanceWrapper_delete, METH_NOARGS,
211 {"delete", (PyCFunction)PythonQtInstanceWrapper_delete, METH_NOARGS,
212 "Deletes the C++ object (at your own risk, my friend!)"
212 "Deletes the C++ object (at your own risk, my friend!)"
213 },
213 },
214 {NULL, NULL, 0, NULL} /* Sentinel */
214 {NULL, NULL, 0, NULL} /* Sentinel */
215 };
215 };
216
216
217
217
218 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
218 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
219 {
219 {
220 const char *attributeName;
220 const char *attributeName;
221 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
221 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
222
222
223 if ((attributeName = PyString_AsString(name)) == NULL) {
223 if ((attributeName = PyString_AsString(name)) == NULL) {
224 return NULL;
224 return NULL;
225 }
225 }
226
226
227 if (qstrcmp(attributeName, "__dict__")==0) {
227 if (qstrcmp(attributeName, "__dict__")==0) {
228 QStringList l = wrapper->classInfo()->memberList(false);
228 PyObject* dict = PyBaseObject_Type.tp_getattro(obj, name);
229 PyObject* dict = PyDict_New();
229 dict = PyDict_Copy(dict);
230
231 // only the properties are missing, the rest is already available from
232 // PythonQtClassWrapper...
233 QStringList l = wrapper->classInfo()->propertyList();
230 foreach (QString name, l) {
234 foreach (QString name, l) {
231 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
235 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
232 PyDict_SetItemString(dict, name.toLatin1().data(), o);
236 if (o) {
233 Py_DECREF(o);
237 PyDict_SetItemString(dict, name.toLatin1().data(), o);
238 Py_DECREF(o);
239 } else {
240 std::cerr << "PythonQtInstanceWrapper: something is wrong, could not get attribute " << name.toLatin1().data();
241 }
234 }
242 }
235 // TODO xxx:
236 // this does include python member methods, but not attributes, from where can we get
237 // the correct dict with the attributes of the derive
238
239 // Note: we do not put children into the dict, is would look confusing?!
243 // Note: we do not put children into the dict, is would look confusing?!
240 return dict;
244 return dict;
241 }
245 }
242
246
243 // first look in super, to return derived methods from base object first
247 // first look in super, to return derived methods from base object first
244 PyObject* superAttr = PyBaseObject_Type.tp_getattro(obj, name);
248 PyObject* superAttr = PyBaseObject_Type.tp_getattro(obj, name);
245 if (superAttr) {
249 if (superAttr) {
246 return superAttr;
250 return superAttr;
247 }
251 }
248 PyErr_Clear();
252 PyErr_Clear();
249
253
250 if (!wrapper->_obj && !wrapper->_wrappedPtr) {
254 if (!wrapper->_obj && !wrapper->_wrappedPtr) {
251 QString error = QString("Trying to read attribute '") + attributeName + "' from a destroyed " + wrapper->classInfo()->className() + " object";
255 QString error = QString("Trying to read attribute '") + attributeName + "' from a destroyed " + wrapper->classInfo()->className() + " object";
252 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
256 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
253 return NULL;
257 return NULL;
254 }
258 }
255
259
256 // mlabDebugConst("Python","get " << attributeName);
260 // mlabDebugConst("Python","get " << attributeName);
257
261
258 // TODO: dynamic properties are missing
262 // TODO: dynamic properties are missing
259
263
260 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
264 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
261 switch (member._type) {
265 switch (member._type) {
262 case PythonQtMemberInfo::Property:
266 case PythonQtMemberInfo::Property:
263 if (wrapper->_obj) {
267 if (wrapper->_obj) {
264 if (member._property.userType() != QVariant::Invalid) {
268 if (member._property.userType() != QVariant::Invalid) {
265 return PythonQtConv::QVariantToPyObject(member._property.read(wrapper->_obj));
269 return PythonQtConv::QVariantToPyObject(member._property.read(wrapper->_obj));
266 } else {
270 } else {
267 Py_INCREF(Py_None);
271 Py_INCREF(Py_None);
268 return Py_None;
272 return Py_None;
269 }
273 }
270 }
274 }
271 break;
275 break;
272 case PythonQtMemberInfo::Slot:
276 case PythonQtMemberInfo::Slot:
273 return PythonQtSlotFunction_New(member._slot, obj, NULL);
277 return PythonQtSlotFunction_New(member._slot, obj, NULL);
274 break;
278 break;
275 case PythonQtMemberInfo::EnumValue:
279 case PythonQtMemberInfo::EnumValue:
276 return PyInt_FromLong(member._enumValue);
280 return PyInt_FromLong(member._enumValue);
277 break;
281 break;
278 default:
282 default:
279 // is an invalid type, go on
283 // is an invalid type, go on
280 break;
284 break;
281 }
285 }
282
286
283 // look for the interal methods (className(), help())
287 // look for the interal methods (className(), help())
284 PyObject* internalMethod = Py_FindMethod( PythonQtInstanceWrapper_methods, obj, (char*)attributeName);
288 PyObject* internalMethod = Py_FindMethod( PythonQtInstanceWrapper_methods, obj, (char*)attributeName);
285 if (internalMethod) {
289 if (internalMethod) {
286 return internalMethod;
290 return internalMethod;
287 }
291 }
288 PyErr_Clear();
292 PyErr_Clear();
289
293
290 if (wrapper->_obj) {
294 if (wrapper->_obj) {
291 // look for a child
295 // look for a child
292 QObjectList children = wrapper->_obj->children();
296 QObjectList children = wrapper->_obj->children();
293 for (int i = 0; i < children.count(); i++) {
297 for (int i = 0; i < children.count(); i++) {
294 QObject *child = children.at(i);
298 QObject *child = children.at(i);
295 if (child->objectName() == attributeName) {
299 if (child->objectName() == attributeName) {
296 return PythonQt::self()->priv()->wrapQObject(child);
300 return PythonQt::self()->priv()->wrapQObject(child);
297 }
301 }
298 }
302 }
299 }
303 }
300
304
301 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
305 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
302 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
306 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
303 return NULL;
307 return NULL;
304 }
308 }
305
309
306 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
310 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
307 {
311 {
308 QString error;
312 QString error;
309 char *attributeName;
313 char *attributeName;
310 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
314 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
311
315
312 if ((attributeName = PyString_AsString(name)) == NULL)
316 if ((attributeName = PyString_AsString(name)) == NULL)
313 return -1;
317 return -1;
314
318
315 if (!wrapper->_obj) {
319 if (!wrapper->_obj) {
316 error = QString("Trying to set attribute '") + attributeName + "' on a destroyed " + wrapper->classInfo()->className() + " object";
320 error = QString("Trying to set attribute '") + attributeName + "' on a destroyed " + wrapper->classInfo()->className() + " object";
317 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
321 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
318 return -1;
322 return -1;
319 }
323 }
320
324
321 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
325 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
322 if (member._type == PythonQtMemberInfo::Property) {
326 if (member._type == PythonQtMemberInfo::Property) {
323 QMetaProperty prop = member._property;
327 QMetaProperty prop = member._property;
324 if (prop.isWritable()) {
328 if (prop.isWritable()) {
325 QVariant v;
329 QVariant v;
326 if (prop.isEnumType()) {
330 if (prop.isEnumType()) {
327 // this will give us either a string or an int, everything else will probably be an error
331 // this will give us either a string or an int, everything else will probably be an error
328 v = PythonQtConv::PyObjToQVariant(value);
332 v = PythonQtConv::PyObjToQVariant(value);
329 } else {
333 } else {
330 int t = prop.userType();
334 int t = prop.userType();
331 v = PythonQtConv::PyObjToQVariant(value, t);
335 v = PythonQtConv::PyObjToQVariant(value, t);
332 }
336 }
333 bool success = false;
337 bool success = false;
334 if (v.isValid()) {
338 if (v.isValid()) {
335 success = prop.write(wrapper->_obj, v);
339 success = prop.write(wrapper->_obj, v);
336 }
340 }
337 if (success) {
341 if (success) {
338 return 0;
342 return 0;
339 } else {
343 } else {
340 error = QString("Property '") + attributeName + "' of type '" +
344 error = QString("Property '") + attributeName + "' of type '" +
341 prop.typeName() + "' does not accept an object of type "
345 prop.typeName() + "' does not accept an object of type "
342 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
346 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
343 }
347 }
344 } else {
348 } else {
345 error = QString("Property '") + attributeName + "' of " + obj->ob_type->tp_name + " object is not writable";
349 error = QString("Property '") + attributeName + "' of " + obj->ob_type->tp_name + " object is not writable";
346 }
350 }
347 } else if (member._type == PythonQtMemberInfo::Slot) {
351 } else if (member._type == PythonQtMemberInfo::Slot) {
348 error = QString("Slot '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
352 error = QString("Slot '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
349 } else if (member._type == PythonQtMemberInfo::EnumValue) {
353 } else if (member._type == PythonQtMemberInfo::EnumValue) {
350 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
354 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
351 } else if (member._type == PythonQtMemberInfo::NotFound) {
355 } else if (member._type == PythonQtMemberInfo::NotFound) {
352 // if we are a derived python class, we allow setting attributes.
356 // if we are a derived python class, we allow setting attributes.
353 // if we are a direct CPP wrapper, we do NOT allow it, since
357 // if we are a direct CPP wrapper, we do NOT allow it, since
354 // it would be confusing to allow it because a wrapper will go away when it is not seen by python anymore
358 // it would be confusing to allow it because a wrapper will go away when it is not seen by python anymore
355 // and when it is recreated from a CPP pointer the attributes are gone...
359 // and when it is recreated from a CPP pointer the attributes are gone...
356 if (obj->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
360 if (obj->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
357 return PyBaseObject_Type.tp_setattro(obj,name,value);
361 return PyBaseObject_Type.tp_setattro(obj,name,value);
358 } else {
362 } else {
359 error = QString("'") + attributeName + "' does not exist on " + obj->ob_type->tp_name + " and creating new attributes on C++ objects is not allowed";
363 error = QString("'") + attributeName + "' does not exist on " + obj->ob_type->tp_name + " and creating new attributes on C++ objects is not allowed";
360 }
364 }
361 }
365 }
362
366
363 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
367 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
364 return -1;
368 return -1;
365 }
369 }
366
370
367 static PyObject * PythonQtInstanceWrapper_str(PyObject * obj)
371 static PyObject * PythonQtInstanceWrapper_str(PyObject * obj)
368 {
372 {
369 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
373 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
370 const char* typeName = obj->ob_type->tp_name;
374 const char* typeName = obj->ob_type->tp_name;
371 QObject *qobj = wrapper->_obj;
375 QObject *qobj = wrapper->_obj;
372 if (wrapper->_wrappedPtr) {
376 if (wrapper->_wrappedPtr) {
373 QString str = PythonQtConv::CPPObjectToString(wrapper->classInfo()->metaTypeId(), wrapper->_wrappedPtr);
377 QString str = PythonQtConv::CPPObjectToString(wrapper->classInfo()->metaTypeId(), wrapper->_wrappedPtr);
374 if (!str.isEmpty()) {
378 if (!str.isEmpty()) {
375 return PyString_FromFormat("%s", str.toLatin1().constData());
379 return PyString_FromFormat("%s", str.toLatin1().constData());
376 } else
380 } else
377 if (wrapper->_obj) {
381 if (wrapper->_obj) {
378 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
382 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
379 } else {
383 } else {
380 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
384 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
381 }
385 }
382 } else {
386 } else {
383 return PyString_FromFormat("%s (QObject %p)", typeName, qobj);
387 return PyString_FromFormat("%s (QObject %p)", typeName, qobj);
384 }
388 }
385 }
389 }
386
390
387 static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj)
391 static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj)
388 {
392 {
389 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
393 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
390 const char* typeName = obj->ob_type->tp_name;
394 const char* typeName = obj->ob_type->tp_name;
391
395
392 QObject *qobj = wrapper->_obj;
396 QObject *qobj = wrapper->_obj;
393 if (wrapper->_wrappedPtr) {
397 if (wrapper->_wrappedPtr) {
394 QString str = PythonQtConv::CPPObjectToString(wrapper->classInfo()->metaTypeId(), wrapper->_wrappedPtr);
398 QString str = PythonQtConv::CPPObjectToString(wrapper->classInfo()->metaTypeId(), wrapper->_wrappedPtr);
395 if (!str.isEmpty()) {
399 if (!str.isEmpty()) {
396 return PyString_FromFormat("%s(%s, %p)", typeName, str.toLatin1().constData(), wrapper->_wrappedPtr);
400 return PyString_FromFormat("%s(%s, %p)", typeName, str.toLatin1().constData(), wrapper->_wrappedPtr);
397 } else
401 } else
398 if (wrapper->_obj) {
402 if (wrapper->_obj) {
399 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
403 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
400 } else {
404 } else {
401 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
405 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
402 }
406 }
403 } else {
407 } else {
404 return PyString_FromFormat("%s (QObject %p)", typeName, wrapper->classInfo()->className(), qobj);
408 return PyString_FromFormat("%s (QObject %p)", typeName, wrapper->classInfo()->className(), qobj);
405 }
409 }
406 }
410 }
407
411
408 static int PythonQtInstanceWrapper_compare(PyObject * obj1, PyObject * obj2)
412 static int PythonQtInstanceWrapper_compare(PyObject * obj1, PyObject * obj2)
409 {
413 {
410 if (PyObject_TypeCheck(obj1, &PythonQtInstanceWrapper_Type) &&
414 if (PyObject_TypeCheck(obj1, &PythonQtInstanceWrapper_Type) &&
411 PyObject_TypeCheck(obj2, &PythonQtInstanceWrapper_Type)) {
415 PyObject_TypeCheck(obj2, &PythonQtInstanceWrapper_Type)) {
412
416
413 PythonQtInstanceWrapper* w1 = (PythonQtInstanceWrapper*)obj1;
417 PythonQtInstanceWrapper* w1 = (PythonQtInstanceWrapper*)obj1;
414 PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)obj2;
418 PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)obj2;
415 // check pointers directly first:
419 // check pointers directly first:
416 if (w1->_wrappedPtr != NULL) {
420 if (w1->_wrappedPtr != NULL) {
417 if (w1->_wrappedPtr == w2->_wrappedPtr) {
421 if (w1->_wrappedPtr == w2->_wrappedPtr) {
418 return 0;
422 return 0;
419 }
423 }
420 } else if (w1->_obj == w2->_obj) {
424 } else if (w1->_obj == w2->_obj) {
421 return 0;
425 return 0;
422 }
426 }
423 const char* class1 = w1->classInfo()->className();
427 const char* class1 = w1->classInfo()->className();
424 const char* class2 = w2->classInfo()->className();
428 const char* class2 = w2->classInfo()->className();
425 if (strcmp(class1, class2) == 0) {
429 if (strcmp(class1, class2) == 0) {
426 // same class names, so we can try the operator_equal
430 // same class names, so we can try the operator_equal
427 PythonQtMemberInfo info = w1->classInfo()->member("operator_equal");
431 PythonQtMemberInfo info = w1->classInfo()->member("operator_equal");
428 if (info._type == PythonQtMemberInfo::Slot) {
432 if (info._type == PythonQtMemberInfo::Slot) {
429 bool result = false;
433 bool result = false;
430 void* obj1 = w1->_wrappedPtr;
434 void* obj1 = w1->_wrappedPtr;
431 if (!obj1) {
435 if (!obj1) {
432 obj1 = w1->_obj;
436 obj1 = w1->_obj;
433 }
437 }
434 if (!obj1) { return -1; }
438 if (!obj1) { return -1; }
435 void* obj2 = w2->_wrappedPtr;
439 void* obj2 = w2->_wrappedPtr;
436 if (!obj2) {
440 if (!obj2) {
437 obj2 = w2->_obj;
441 obj2 = w2->_obj;
438 }
442 }
439 if (!obj2) { return -1; }
443 if (!obj2) { return -1; }
440 if (info._slot->isInstanceDecorator()) {
444 if (info._slot->isInstanceDecorator()) {
441 // call on decorator QObject
445 // call on decorator QObject
442 void* args[3];
446 void* args[3];
443 args[0] = &result;
447 args[0] = &result;
444 args[1] = &obj1; // this is a pointer, so it needs a pointer to a pointer
448 args[1] = &obj1; // this is a pointer, so it needs a pointer to a pointer
445 args[2] = obj2; // this is a reference, so it needs the direct pointer
449 args[2] = obj2; // this is a reference, so it needs the direct pointer
446 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
450 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
447 return result?0:-1;
451 return result?0:-1;
448 } else {
452 } else {
449 // call directly on QObject
453 // call directly on QObject
450 if (w1->_obj && w2->_obj) {
454 if (w1->_obj && w2->_obj) {
451 void* args[2];
455 void* args[2];
452 args[0] = &result;
456 args[0] = &result;
453 args[2] = obj2; // this is a reference, so it needs the direct pointer
457 args[2] = obj2; // this is a reference, so it needs the direct pointer
454 w1->_obj->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
458 w1->_obj->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
455 }
459 }
456 }
460 }
457 }
461 }
458 }
462 }
459 }
463 }
460 return -1;
464 return -1;
461 }
465 }
462
466
463 static int PythonQtInstanceWrapper_nonzero(PyObject *obj)
467 static int PythonQtInstanceWrapper_nonzero(PyObject *obj)
464 {
468 {
465 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
469 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
466 return (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
470 return (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
467 }
471 }
468
472
469
473
470 static long PythonQtInstanceWrapper_hash(PythonQtInstanceWrapper *obj)
474 static long PythonQtInstanceWrapper_hash(PythonQtInstanceWrapper *obj)
471 {
475 {
472 if (obj->_wrappedPtr != NULL) {
476 if (obj->_wrappedPtr != NULL) {
473 return reinterpret_cast<long>(obj->_wrappedPtr);
477 return reinterpret_cast<long>(obj->_wrappedPtr);
474 } else {
478 } else {
475 QObject* qobj = obj->_obj; // get pointer from QPointer wrapper
479 QObject* qobj = obj->_obj; // get pointer from QPointer wrapper
476 return reinterpret_cast<long>(qobj);
480 return reinterpret_cast<long>(qobj);
477 }
481 }
478 }
482 }
479
483
480
484
481
485
482 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
486 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
483 static PyNumberMethods PythonQtInstanceWrapper_as_number = {
487 static PyNumberMethods PythonQtInstanceWrapper_as_number = {
484 0, /* nb_add */
488 0, /* nb_add */
485 0, /* nb_subtract */
489 0, /* nb_subtract */
486 0, /* nb_multiply */
490 0, /* nb_multiply */
487 0, /* nb_divide */
491 0, /* nb_divide */
488 0, /* nb_remainder */
492 0, /* nb_remainder */
489 0, /* nb_divmod */
493 0, /* nb_divmod */
490 0, /* nb_power */
494 0, /* nb_power */
491 0, /* nb_negative */
495 0, /* nb_negative */
492 0, /* nb_positive */
496 0, /* nb_positive */
493 0, /* nb_absolute */
497 0, /* nb_absolute */
494 PythonQtInstanceWrapper_nonzero, /* nb_nonzero */
498 PythonQtInstanceWrapper_nonzero, /* nb_nonzero */
495 0, /* nb_invert */
499 0, /* nb_invert */
496 0, /* nb_lshift */
500 0, /* nb_lshift */
497 0, /* nb_rshift */
501 0, /* nb_rshift */
498 0, /* nb_and */
502 0, /* nb_and */
499 0, /* nb_xor */
503 0, /* nb_xor */
500 0, /* nb_or */
504 0, /* nb_or */
501 0, /* nb_coerce */
505 0, /* nb_coerce */
502 0, /* nb_int */
506 0, /* nb_int */
503 0, /* nb_long */
507 0, /* nb_long */
504 0, /* nb_float */
508 0, /* nb_float */
505 0, /* nb_oct */
509 0, /* nb_oct */
506 0, /* nb_hex */
510 0, /* nb_hex */
507 0, /* nb_inplace_add */
511 0, /* nb_inplace_add */
508 0, /* nb_inplace_subtract */
512 0, /* nb_inplace_subtract */
509 0, /* nb_inplace_multiply */
513 0, /* nb_inplace_multiply */
510 0, /* nb_inplace_divide */
514 0, /* nb_inplace_divide */
511 0, /* nb_inplace_remainder */
515 0, /* nb_inplace_remainder */
512 0, /* nb_inplace_power */
516 0, /* nb_inplace_power */
513 0, /* nb_inplace_lshift */
517 0, /* nb_inplace_lshift */
514 0, /* nb_inplace_rshift */
518 0, /* nb_inplace_rshift */
515 0, /* nb_inplace_and */
519 0, /* nb_inplace_and */
516 0, /* nb_inplace_xor */
520 0, /* nb_inplace_xor */
517 0, /* nb_inplace_or */
521 0, /* nb_inplace_or */
518 0, /* nb_floor_divide */
522 0, /* nb_floor_divide */
519 0, /* nb_true_divide */
523 0, /* nb_true_divide */
520 0, /* nb_inplace_floor_divide */
524 0, /* nb_inplace_floor_divide */
521 0, /* nb_inplace_true_divide */
525 0, /* nb_inplace_true_divide */
522 };
526 };
523
527
524 PyTypeObject PythonQtInstanceWrapper_Type = {
528 PyTypeObject PythonQtInstanceWrapper_Type = {
525 PyObject_HEAD_INIT(&PythonQtClassWrapper_Type)
529 PyObject_HEAD_INIT(&PythonQtClassWrapper_Type)
526 0, /*ob_size*/
530 0, /*ob_size*/
527 "PythonQt.PythonQtInstanceWrapper", /*tp_name*/
531 "PythonQt.PythonQtInstanceWrapper", /*tp_name*/
528 sizeof(PythonQtInstanceWrapper), /*tp_basicsize*/
532 sizeof(PythonQtInstanceWrapper), /*tp_basicsize*/
529 0, /*tp_itemsize*/
533 0, /*tp_itemsize*/
530 (destructor)PythonQtInstanceWrapper_dealloc, /*tp_dealloc*/
534 (destructor)PythonQtInstanceWrapper_dealloc, /*tp_dealloc*/
531 0, /*tp_print*/
535 0, /*tp_print*/
532 0, /*tp_getattr*/
536 0, /*tp_getattr*/
533 0, /*tp_setattr*/
537 0, /*tp_setattr*/
534 PythonQtInstanceWrapper_compare, /*tp_compare*/
538 PythonQtInstanceWrapper_compare, /*tp_compare*/
535 PythonQtInstanceWrapper_repr, /*tp_repr*/
539 PythonQtInstanceWrapper_repr, /*tp_repr*/
536 &PythonQtInstanceWrapper_as_number, /*tp_as_number*/
540 &PythonQtInstanceWrapper_as_number, /*tp_as_number*/
537 0, /*tp_as_sequence*/
541 0, /*tp_as_sequence*/
538 0, /*tp_as_mapping*/
542 0, /*tp_as_mapping*/
539 (hashfunc)PythonQtInstanceWrapper_hash, /*tp_hash */
543 (hashfunc)PythonQtInstanceWrapper_hash, /*tp_hash */
540 0, /*tp_call*/
544 0, /*tp_call*/
541 PythonQtInstanceWrapper_str, /*tp_str*/
545 PythonQtInstanceWrapper_str, /*tp_str*/
542 PythonQtInstanceWrapper_getattro, /*tp_getattro*/
546 PythonQtInstanceWrapper_getattro, /*tp_getattro*/
543 PythonQtInstanceWrapper_setattro, /*tp_setattro*/
547 PythonQtInstanceWrapper_setattro, /*tp_setattro*/
544 0, /*tp_as_buffer*/
548 0, /*tp_as_buffer*/
545 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
549 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
546 "PythonQtInstanceWrapper object", /* tp_doc */
550 "PythonQtInstanceWrapper object", /* tp_doc */
547 0, /* tp_traverse */
551 0, /* tp_traverse */
548 0, /* tp_clear */
552 0, /* tp_clear */
549 0, /* tp_richcompare */
553 0, /* tp_richcompare */
550 0, /* tp_weaklistoffset */
554 0, /* tp_weaklistoffset */
551 0, /* tp_iter */
555 0, /* tp_iter */
552 0, /* tp_iternext */
556 0, /* tp_iternext */
553 0, /* tp_methods */
557 0, /* tp_methods */
554 0, /* tp_members */
558 0, /* tp_members */
555 0, /* tp_getset */
559 0, /* tp_getset */
556 0, /* tp_base */
560 0, /* tp_base */
557 0, /* tp_dict */
561 0, /* tp_dict */
558 0, /* tp_descr_get */
562 0, /* tp_descr_get */
559 0, /* tp_descr_set */
563 0, /* tp_descr_set */
560 0, /* tp_dictoffset */
564 0, /* tp_dictoffset */
561 (initproc)PythonQtInstanceWrapper_init, /* tp_init */
565 (initproc)PythonQtInstanceWrapper_init, /* tp_init */
562 0, /* tp_alloc */
566 0, /* tp_alloc */
563 PythonQtInstanceWrapper_new, /* tp_new */
567 PythonQtInstanceWrapper_new, /* tp_new */
564 };
568 };
565
569
566 //-------------------------------------------------------
570 //-------------------------------------------------------
567
571
General Comments 0
You need to be logged in to leave comments. Login now