@@ -140,6 +140,22 void PythonQt::init(int flags) | |||
|
140 | 140 | PythonQtRegisterToolClassesTemplateConverter(QTextFormat); |
|
141 | 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 | 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 | 1149 | PyObject* PythonQtPrivate::packageByName(const char* name) |
|
1163 | 1150 | { |
|
1164 | 1151 | if (name==NULL || name[0]==0) { |
@@ -1167,11 +1154,6 PyObject* PythonQtPrivate::packageByName(const char* name) | |||
|
1167 | 1154 | PyObject* v = _packages.value(name); |
|
1168 | 1155 | if (!v) { |
|
1169 | 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 | 1157 | _packages.insert(name, v); |
|
1176 | 1158 | // AddObject steals the reference, so increment it! |
|
1177 | 1159 | Py_INCREF(v); |
@@ -1180,6 +1162,12 PyObject* PythonQtPrivate::packageByName(const char* name) | |||
|
1180 | 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 | 1172 | PyObject* PythonQt::helpCalled(PythonQtClassInfo* info) |
|
1185 | 1173 | { |
@@ -470,6 +470,9 public: | |||
|
470 | 470 | //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation |
|
471 | 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 | 476 | private: |
|
474 | 477 | |
|
475 | 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 | 310 | if (!found) { |
|
311 | // maybe it is an enum wrapper? | |
|
311 | 312 | PyObject* p = findEnumWrapper(memberName); |
|
312 | 313 | if (p) { |
|
313 | 314 | info._type = PythonQtMemberInfo::EnumWrapper; |
@@ -317,6 +318,20 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName) | |||
|
317 | 318 | } |
|
318 | 319 | } |
|
319 | 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 | 335 | // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup) |
|
321 | 336 | info._type = PythonQtMemberInfo::NotFound; |
|
322 | 337 | _cachedMembers.insert(memberName, info); |
@@ -144,7 +144,7 | |||
|
144 | 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 | 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 | 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 | 148 | - PythonQt does not offer to add new signals to Python/C++ objects |
|
149 | 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 | 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 | 58 | ParameterInfo type; |
|
59 | 59 | fillParameterInfo(type, QByteArray(meta.typeName()), classInfo); |
|
60 | 60 | _parameters.append(type); |
|
61 | QByteArray name; | |
|
62 | 61 | QList<QByteArray> names = meta.parameterTypes(); |
|
63 | foreach (name, names) { | |
|
62 | foreach (const QByteArray& name, names) { | |
|
64 | 63 | fillParameterInfo(type, name, classInfo); |
|
65 | 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 | 79 | const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo) |
|
70 | 80 | { |
|
71 | 81 | QByteArray sig(signal.signature()); |
@@ -79,12 +89,25 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMet | |||
|
79 | 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); | |
|
85 | int idx = metaObject->indexOfMethod(sig); | |
|
86 | QMetaMethod meta = metaObject->method(idx); | |
|
87 | return PythonQtMethodInfo::getCachedMethodInfo(meta, NULL); | |
|
94 | QByteArray typeName = args[0]; | |
|
95 | QList<QByteArray> arguments; | |
|
96 | QByteArray fullSig = typeName; | |
|
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 | 113 | void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo) |
@@ -74,6 +74,7 public: | |||
|
74 | 74 | PythonQtMethodInfo() {}; |
|
75 | 75 | ~PythonQtMethodInfo() {}; |
|
76 | 76 | PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo); |
|
77 | PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args); | |
|
77 | 78 | PythonQtMethodInfo(const PythonQtMethodInfo& other) { |
|
78 | 79 | _parameters = other._parameters; |
|
79 | 80 | } |
@@ -82,8 +83,8 public: | |||
|
82 | 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 | 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 |
static const PythonQtMethodInfo* getCachedMethodInfoFrom |
|
|
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 | |
|
87 | static const PythonQtMethodInfo* getCachedMethodInfoFromArgumentList(int numArgs, const char** args); | |
|
87 | 88 | |
|
88 | 89 | //! cleanup the cache |
|
89 | 90 | static void cleanupCachedMethodInfos(); |
@@ -48,7 +48,7 | |||
|
48 | 48 | #include "funcobject.h" |
|
49 | 49 | |
|
50 | 50 | void PythonQtSignalTarget::call(void **arguments) const { |
|
51 |
PyObject* result = call(_callable, methodInfo(), arguments |
|
|
51 | PyObject* result = call(_callable, methodInfo(), arguments); | |
|
52 | 52 | if (result) { |
|
53 | 53 | Py_DECREF(result); |
|
54 | 54 | } |
@@ -86,9 +86,6 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInf | |||
|
86 | 86 | const PythonQtMethodInfo* m = methodInfos; |
|
87 | 87 | // parameterCount includes return value: |
|
88 | 88 | int count = m->parameterCount(); |
|
89 | if (skipFirstArgumentOfMethodInfo) { | |
|
90 | count--; | |
|
91 | } | |
|
92 | 89 | if (numPythonArgs!=-1) { |
|
93 | 90 | if (count>numPythonArgs+1) { |
|
94 | 91 | // take less arguments |
@@ -103,12 +100,8 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInf | |||
|
103 | 100 | bool err = false; |
|
104 | 101 | // transform Qt values to Python |
|
105 | 102 | const QList<PythonQtMethodInfo::ParameterInfo>& params = m->parameters(); |
|
106 | int skipFirstOffset = 0; | |
|
107 | if (skipFirstArgumentOfMethodInfo) { | |
|
108 | skipFirstOffset = 1; | |
|
109 | } | |
|
110 | 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 | 105 | PyObject* arg = PythonQtConv::ConvertQtValueToPython(param, arguments[i]); |
|
113 | 106 | if (arg) { |
|
114 | 107 | // steals reference, no unref |
@@ -71,6 +71,28 public slots: | |||
|
71 | 71 | void setParent(QObject* o, QObject* parent); |
|
72 | 72 | |
|
73 | 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 | 97 | //TODO: add findChild/findChildren/children/... |
|
76 | 98 | }; |
General Comments 0
You need to be logged in to leave comments.
Login now