@@ -140,6 +140,22 void PythonQt::init(int flags) | |||||
140 | PythonQtRegisterToolClassesTemplateConverter(QTextFormat); |
|
140 | PythonQtRegisterToolClassesTemplateConverter(QTextFormat); | |
141 | PythonQtRegisterToolClassesTemplateConverter(QMatrix); |
|
141 | PythonQtRegisterToolClassesTemplateConverter(QMatrix); | |
142 |
|
142 | |||
|
143 | ||||
|
144 | PyObject* pack = PythonQt::priv()->packageByName("QtCore"); | |||
|
145 | PyObject* pack2 = PythonQt::priv()->packageByName("Qt"); | |||
|
146 | PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper(); | |||
|
147 | const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal" | |||
|
148 | ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"}; | |||
|
149 | for (unsigned int i = 0;i<16; i++) { | |||
|
150 | PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]); | |||
|
151 | if (obj) { | |||
|
152 | PyModule_AddObject(pack, names[i], obj); | |||
|
153 | Py_INCREF(obj); | |||
|
154 | PyModule_AddObject(pack2, names[i], obj); | |||
|
155 | } else { | |||
|
156 | std::cerr << "method not found " << names[i]; | |||
|
157 | } | |||
|
158 | } | |||
143 | } |
|
159 | } | |
144 |
|
160 | |||
145 | void PythonQt::cleanup() |
|
161 | void PythonQt::cleanup() | |
@@ -1130,35 +1146,6 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentT | |||||
1130 | } |
|
1146 | } | |
1131 | } |
|
1147 | } | |
1132 |
|
1148 | |||
1133 | static PyObject *PythonQt_SIGNAL(PyObject * /*type*/, PyObject *args) |
|
|||
1134 | { |
|
|||
1135 | const char* value; |
|
|||
1136 | if (!PyArg_ParseTuple(args, "s", &value)) { |
|
|||
1137 | return NULL; |
|
|||
1138 | } |
|
|||
1139 | // we do not prepend 0,1 or 2, why should we? |
|
|||
1140 | return PyString_FromString(QByteArray("2") + value); |
|
|||
1141 | } |
|
|||
1142 |
|
||||
1143 | static PyObject *PythonQt_SLOT(PyObject * /*type*/, PyObject *args) |
|
|||
1144 | { |
|
|||
1145 | const char* value; |
|
|||
1146 | if (!PyArg_ParseTuple(args, "s", &value)) { |
|
|||
1147 | return NULL; |
|
|||
1148 | } |
|
|||
1149 | // we do not prepend 0,1 or 2, why should we? |
|
|||
1150 | return PyString_FromString(QByteArray("1") + value); |
|
|||
1151 | } |
|
|||
1152 |
|
||||
1153 | static PyMethodDef PythonQt_Qt_methods[] = { |
|
|||
1154 | {"SIGNAL", (PyCFunction)PythonQt_SIGNAL, METH_VARARGS, |
|
|||
1155 | "Returns a signal string" |
|
|||
1156 | }, |
|
|||
1157 | {"SLOT", (PyCFunction)PythonQt_SLOT, METH_VARARGS, |
|
|||
1158 | "Returns a slot string" |
|
|||
1159 | } |
|
|||
1160 | }; |
|
|||
1161 |
|
||||
1162 | PyObject* PythonQtPrivate::packageByName(const char* name) |
|
1149 | PyObject* PythonQtPrivate::packageByName(const char* name) | |
1163 | { |
|
1150 | { | |
1164 | if (name==NULL || name[0]==0) { |
|
1151 | if (name==NULL || name[0]==0) { | |
@@ -1167,11 +1154,6 PyObject* PythonQtPrivate::packageByName(const char* name) | |||||
1167 | PyObject* v = _packages.value(name); |
|
1154 | PyObject* v = _packages.value(name); | |
1168 | if (!v) { |
|
1155 | if (!v) { | |
1169 | v = PyImport_AddModule((QByteArray("PythonQt.") + name).constData()); |
|
1156 | v = PyImport_AddModule((QByteArray("PythonQt.") + name).constData()); | |
1170 | if (strcmp(name,"Qt")==0 || strcmp(name,"QtCore")==0) { |
|
|||
1171 | // add SIGNAL and SLOT functions |
|
|||
1172 | PyModule_AddObject(v, "SIGNAL", PyCFunction_New(PythonQt_Qt_methods, v)); |
|
|||
1173 | PyModule_AddObject(v, "SLOT", PyCFunction_New(PythonQt_Qt_methods+1, v)); |
|
|||
1174 | } |
|
|||
1175 | _packages.insert(name, v); |
|
1157 | _packages.insert(name, v); | |
1176 | // AddObject steals the reference, so increment it! |
|
1158 | // AddObject steals the reference, so increment it! | |
1177 | Py_INCREF(v); |
|
1159 | Py_INCREF(v); | |
@@ -1180,6 +1162,12 PyObject* PythonQtPrivate::packageByName(const char* name) | |||||
1180 | return v; |
|
1162 | return v; | |
1181 | } |
|
1163 | } | |
1182 |
|
1164 | |||
|
1165 | void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result) | |||
|
1166 | { | |||
|
1167 | QString error = "Return value '" + PythonQtConv::PyObjGetString(result) + "' can not be converted to expected C++ type '" + methodInfo->parameters().at(0).name + "' as return value of virtual method " + signature; | |||
|
1168 | PyErr_SetString(PyExc_AttributeError, error.toLatin1().data()); | |||
|
1169 | PythonQt::self()->handleError(); | |||
|
1170 | } | |||
1183 |
|
1171 | |||
1184 | PyObject* PythonQt::helpCalled(PythonQtClassInfo* info) |
|
1172 | PyObject* PythonQt::helpCalled(PythonQtClassInfo* info) | |
1185 | { |
|
1173 | { |
@@ -470,6 +470,9 public: | |||||
470 | //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation |
|
470 | //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation | |
471 | static PyObject* dummyTuple(); |
|
471 | static PyObject* dummyTuple(); | |
472 |
|
472 | |||
|
473 | //! called by virtual overloads when a python return value can not be converted to the required Qt type | |||
|
474 | void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result); | |||
|
475 | ||||
473 | private: |
|
476 | private: | |
474 |
|
477 | |||
475 | //! create a new pythonqt class wrapper and place it in the pythonqt module |
|
478 | //! create a new pythonqt class wrapper and place it in the pythonqt module |
@@ -308,6 +308,7 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName) | |||||
308 | } |
|
308 | } | |
309 | } |
|
309 | } | |
310 | if (!found) { |
|
310 | if (!found) { | |
|
311 | // maybe it is an enum wrapper? | |||
311 | PyObject* p = findEnumWrapper(memberName); |
|
312 | PyObject* p = findEnumWrapper(memberName); | |
312 | if (p) { |
|
313 | if (p) { | |
313 | info._type = PythonQtMemberInfo::EnumWrapper; |
|
314 | info._type = PythonQtMemberInfo::EnumWrapper; | |
@@ -317,6 +318,20 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName) | |||||
317 | } |
|
318 | } | |
318 | } |
|
319 | } | |
319 | if (!found) { |
|
320 | if (!found) { | |
|
321 | // since python keywords can not be looked up, we check if the name contains a single trailing _ | |||
|
322 | // and remove that and look again, so that we e.g. find exec on an exec_ lookup | |||
|
323 | QByteArray mbrName(memberName); | |||
|
324 | if ((mbrName.length()>2) && | |||
|
325 | (mbrName.at(mbrName.length()-1) == '_') && | |||
|
326 | (mbrName.at(mbrName.length()-2) != '_')) { | |||
|
327 | mbrName = mbrName.mid(0,mbrName.length()-1); | |||
|
328 | found = lookForMethodAndCache(mbrName.constData()); | |||
|
329 | if (found) { | |||
|
330 | return _cachedMembers.value(mbrName); | |||
|
331 | } | |||
|
332 | } | |||
|
333 | } | |||
|
334 | if (!found) { | |||
320 | // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup) |
|
335 | // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup) | |
321 | info._type = PythonQtMemberInfo::NotFound; |
|
336 | info._type = PythonQtMemberInfo::NotFound; | |
322 | _cachedMembers.insert(memberName, info); |
|
337 | _cachedMembers.insert(memberName, info); |
@@ -144,7 +144,7 | |||||
144 | - PythonQt allows to communicate in both directions, e.g. calling a Python object from C++ AND calling a C++ method from Python, while PyQt only handles the Python->C++ direction |
|
144 | - PythonQt allows to communicate in both directions, e.g. calling a Python object from C++ AND calling a C++ method from Python, while PyQt only handles the Python->C++ direction | |
145 | - PythonQt offers properties as Python attributes, while PyQt offers them as setter/getter methods (e.g. QWidget.width is a property in PythonQt and a method in PyQt) |
|
145 | - PythonQt offers properties as Python attributes, while PyQt offers them as setter/getter methods (e.g. QWidget.width is a property in PythonQt and a method in PyQt) | |
146 | - PythonQt does not support instanceof checks for Qt classes, except for the exact match and derived Python classes |
|
146 | - PythonQt does not support instanceof checks for Qt classes, except for the exact match and derived Python classes | |
147 | - QObject.emit to emit Qt signals from Python is not yet implemented |
|
147 | - QObject.emit to emit Qt signals from Python is not yet implemented but PythonQt allows to just emit a signal by calling it | |
148 | - PythonQt does not offer to add new signals to Python/C++ objects |
|
148 | - PythonQt does not offer to add new signals to Python/C++ objects | |
149 | - Ownership of objects is a bit different in PythonQt, currently Python classes derived from a C++ class need to be manually references in PythonQt to not get deleted too early (this will be fixed) |
|
149 | - Ownership of objects is a bit different in PythonQt, currently Python classes derived from a C++ class need to be manually references in PythonQt to not get deleted too early (this will be fixed) | |
150 | - Probably there are lots of details that differ, I do not know PyQt that well to list them all. |
|
150 | - Probably there are lots of details that differ, I do not know PyQt that well to list them all. |
@@ -58,14 +58,24 PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInf | |||||
58 | ParameterInfo type; |
|
58 | ParameterInfo type; | |
59 | fillParameterInfo(type, QByteArray(meta.typeName()), classInfo); |
|
59 | fillParameterInfo(type, QByteArray(meta.typeName()), classInfo); | |
60 | _parameters.append(type); |
|
60 | _parameters.append(type); | |
61 | QByteArray name; |
|
|||
62 | QList<QByteArray> names = meta.parameterTypes(); |
|
61 | QList<QByteArray> names = meta.parameterTypes(); | |
63 | foreach (name, names) { |
|
62 | foreach (const QByteArray& name, names) { | |
64 | fillParameterInfo(type, name, classInfo); |
|
63 | fillParameterInfo(type, name, classInfo); | |
65 | _parameters.append(type); |
|
64 | _parameters.append(type); | |
66 | } |
|
65 | } | |
67 | } |
|
66 | } | |
68 |
|
67 | |||
|
68 | PythonQtMethodInfo::PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args) | |||
|
69 | { | |||
|
70 | ParameterInfo type; | |||
|
71 | fillParameterInfo(type, typeName, NULL); | |||
|
72 | _parameters.append(type); | |||
|
73 | foreach (const QByteArray& name, args) { | |||
|
74 | fillParameterInfo(type, name, NULL); | |||
|
75 | _parameters.append(type); | |||
|
76 | } | |||
|
77 | } | |||
|
78 | ||||
69 | const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo) |
|
79 | const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo) | |
70 | { |
|
80 | { | |
71 | QByteArray sig(signal.signature()); |
|
81 | QByteArray sig(signal.signature()); | |
@@ -79,12 +89,25 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMet | |||||
79 | return result; |
|
89 | return result; | |
80 | } |
|
90 | } | |
81 |
|
91 | |||
82 |
const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFrom |
|
92 | const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(int numArgs, const char** args) | |
83 | { |
|
93 | { | |
84 | QByteArray sig = QMetaObject::normalizedSignature(signature); |
|
94 | QByteArray typeName = args[0]; | |
85 | int idx = metaObject->indexOfMethod(sig); |
|
95 | QList<QByteArray> arguments; | |
86 | QMetaMethod meta = metaObject->method(idx); |
|
96 | QByteArray fullSig = typeName; | |
87 | return PythonQtMethodInfo::getCachedMethodInfo(meta, NULL); |
|
97 | fullSig += "("; | |
|
98 | for (int i =1;i<numArgs; i++) { | |||
|
99 | if (i>1) { | |||
|
100 | fullSig += ","; | |||
|
101 | } | |||
|
102 | arguments << QByteArray(args[i]); | |||
|
103 | } | |||
|
104 | fullSig += ")"; | |||
|
105 | PythonQtMethodInfo* result = _cachedSignatures.value(fullSig); | |||
|
106 | if (!result) { | |||
|
107 | result = new PythonQtMethodInfo(typeName, arguments); | |||
|
108 | _cachedSignatures.insert(fullSig, result); | |||
|
109 | } | |||
|
110 | return result; | |||
88 | } |
|
111 | } | |
89 |
|
112 | |||
90 | void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo) |
|
113 | void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo) |
@@ -74,6 +74,7 public: | |||||
74 | PythonQtMethodInfo() {}; |
|
74 | PythonQtMethodInfo() {}; | |
75 | ~PythonQtMethodInfo() {}; |
|
75 | ~PythonQtMethodInfo() {}; | |
76 | PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo); |
|
76 | PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo); | |
|
77 | PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args); | |||
77 | PythonQtMethodInfo(const PythonQtMethodInfo& other) { |
|
78 | PythonQtMethodInfo(const PythonQtMethodInfo& other) { | |
78 | _parameters = other._parameters; |
|
79 | _parameters = other._parameters; | |
79 | } |
|
80 | } | |
@@ -82,8 +83,8 public: | |||||
82 | //! multiple requests for the same method, classInfo is passed to allow local enum resolution (if NULL is passed, no local enums are recognized) |
|
83 | //! multiple requests for the same method, classInfo is passed to allow local enum resolution (if NULL is passed, no local enums are recognized) | |
83 | static const PythonQtMethodInfo* getCachedMethodInfo(const QMetaMethod& method, PythonQtClassInfo* classInfo); |
|
84 | static const PythonQtMethodInfo* getCachedMethodInfo(const QMetaMethod& method, PythonQtClassInfo* classInfo); | |
84 |
|
85 | |||
85 | //! get the cached method info by finding the meta method on the meta object via its signature, enums are only supported with leading namespace:: |
|
86 | //! get the cached method info using the passed in list of return value and arguments, return value needs to be passed as first arg | |
86 |
static const PythonQtMethodInfo* getCachedMethodInfoFrom |
|
87 | static const PythonQtMethodInfo* getCachedMethodInfoFromArgumentList(int numArgs, const char** args); | |
87 |
|
88 | |||
88 | //! cleanup the cache |
|
89 | //! cleanup the cache | |
89 | static void cleanupCachedMethodInfos(); |
|
90 | static void cleanupCachedMethodInfos(); |
@@ -48,7 +48,7 | |||||
48 | #include "funcobject.h" |
|
48 | #include "funcobject.h" | |
49 |
|
49 | |||
50 | void PythonQtSignalTarget::call(void **arguments) const { |
|
50 | void PythonQtSignalTarget::call(void **arguments) const { | |
51 |
PyObject* result = call(_callable, methodInfo(), arguments |
|
51 | PyObject* result = call(_callable, methodInfo(), arguments); | |
52 | if (result) { |
|
52 | if (result) { | |
53 | Py_DECREF(result); |
|
53 | Py_DECREF(result); | |
54 | } |
|
54 | } | |
@@ -86,9 +86,6 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInf | |||||
86 | const PythonQtMethodInfo* m = methodInfos; |
|
86 | const PythonQtMethodInfo* m = methodInfos; | |
87 | // parameterCount includes return value: |
|
87 | // parameterCount includes return value: | |
88 | int count = m->parameterCount(); |
|
88 | int count = m->parameterCount(); | |
89 | if (skipFirstArgumentOfMethodInfo) { |
|
|||
90 | count--; |
|
|||
91 | } |
|
|||
92 | if (numPythonArgs!=-1) { |
|
89 | if (numPythonArgs!=-1) { | |
93 | if (count>numPythonArgs+1) { |
|
90 | if (count>numPythonArgs+1) { | |
94 | // take less arguments |
|
91 | // take less arguments | |
@@ -103,12 +100,8 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInf | |||||
103 | bool err = false; |
|
100 | bool err = false; | |
104 | // transform Qt values to Python |
|
101 | // transform Qt values to Python | |
105 | const QList<PythonQtMethodInfo::ParameterInfo>& params = m->parameters(); |
|
102 | const QList<PythonQtMethodInfo::ParameterInfo>& params = m->parameters(); | |
106 | int skipFirstOffset = 0; |
|
|||
107 | if (skipFirstArgumentOfMethodInfo) { |
|
|||
108 | skipFirstOffset = 1; |
|
|||
109 | } |
|
|||
110 | for (int i = 1; i < count; i++) { |
|
103 | for (int i = 1; i < count; i++) { | |
111 |
const PythonQtMethodInfo::ParameterInfo& param = params.at(i |
|
104 | const PythonQtMethodInfo::ParameterInfo& param = params.at(i); | |
112 | PyObject* arg = PythonQtConv::ConvertQtValueToPython(param, arguments[i]); |
|
105 | PyObject* arg = PythonQtConv::ConvertQtValueToPython(param, arguments[i]); | |
113 | if (arg) { |
|
106 | if (arg) { | |
114 | // steals reference, no unref |
|
107 | // steals reference, no unref |
@@ -71,6 +71,28 public slots: | |||||
71 | void setParent(QObject* o, QObject* parent); |
|
71 | void setParent(QObject* o, QObject* parent); | |
72 |
|
72 | |||
73 | QVariantList children(QObject* o); |
|
73 | QVariantList children(QObject* o); | |
|
74 | ||||
|
75 | double static_Qt_qAbs(double a) { return qAbs(a); } | |||
|
76 | double static_Qt_qBound(double a,double b,double c) { return qBound(a,b,c); } | |||
|
77 | void static_Qt_qDebug(const QByteArray& msg) { qDebug(msg.constData()); } | |||
|
78 | // TODO: multi arg qDebug... | |||
|
79 | void static_Qt_qWarning(const QByteArray& msg) { qWarning(msg.constData()); } | |||
|
80 | // TODO: multi arg qWarning... | |||
|
81 | void static_Qt_qCritical(const QByteArray& msg) { qCritical(msg.constData()); } | |||
|
82 | // TODO: multi arg qCritical... | |||
|
83 | void static_Qt_qFatal(const QByteArray& msg) { qFatal(msg.constData()); } | |||
|
84 | // TODO: multi arg qFatal... | |||
|
85 | bool static_Qt_qFuzzyCompare(double a, double b) { return qFuzzyCompare(a, b); } | |||
|
86 | double static_Qt_qMax(double a, double b) { return qMax(a, b); } | |||
|
87 | double static_Qt_qMin(double a, double b) { return qMin(a, b); } | |||
|
88 | int static_Qt_qRound(double a) { return qRound(a); } | |||
|
89 | qint64 static_Qt_qRound64(double a) { return qRound64(a); } | |||
|
90 | const char* static_Qt_qVersion() { return qVersion(); } | |||
|
91 | int static_Qt_qrand() { return qrand(); } | |||
|
92 | void static_Qt_qsrand(uint a) { qsrand(a); } | |||
|
93 | ||||
|
94 | QByteArray static_Qt_SIGNAL(const QByteArray& s) { return QByteArray("2") + s; } | |||
|
95 | QByteArray static_Qt_SLOT(const QByteArray& s) { return QByteArray("1") + s; } | |||
74 |
|
96 | |||
75 | //TODO: add findChild/findChildren/children/... |
|
97 | //TODO: add findChild/findChildren/children/... | |
76 | }; |
|
98 | }; |
General Comments 0
You need to be logged in to leave comments.
Login now