@@ -245,6 +245,14 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* p | |||
|
245 | 245 | PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className()); |
|
246 | 246 | info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo)); |
|
247 | 247 | } |
|
248 | } else if (first && module) { | |
|
249 | // There is a wrapper already, but if we got a module, we want to place the wrapper into that module as well, | |
|
250 | // since it might have been placed into "private" earlier on. | |
|
251 | // If the wrapper was already added to module before, it is just readded, which does no harm. | |
|
252 | PyObject* classWrapper = info->pythonQtClassWrapper(); | |
|
253 | // AddObject steals a reference, so we need to INCREF | |
|
254 | Py_INCREF(classWrapper); | |
|
255 | PyModule_AddObject(module, info->className(), classWrapper); | |
|
248 | 256 | } |
|
249 | 257 | if (first) { |
|
250 | 258 | first = false; |
@@ -913,6 +921,7 PythonQtPrivate::PythonQtPrivate() | |||
|
913 | 921 | _noLongerWrappedCB = NULL; |
|
914 | 922 | _wrappedCB = NULL; |
|
915 | 923 | _currentClassInfoForClassWrapperCreation = NULL; |
|
924 | _profilingCB = NULL; | |
|
916 | 925 | } |
|
917 | 926 | |
|
918 | 927 | void PythonQtPrivate::setupSharedLibrarySuffixes() |
@@ -922,6 +931,14 void PythonQtPrivate::setupSharedLibrarySuffixes() | |||
|
922 | 931 | imp.setNewRef(PyImport_ImportModule("imp")); |
|
923 | 932 | int cExtensionCode = imp.getVariable("C_EXTENSION").toInt(); |
|
924 | 933 | QVariant result = imp.call("get_suffixes"); |
|
934 | #ifdef __linux | |
|
935 | #ifdef _DEBUG | |
|
936 | // First look for shared libraries with the '_d' suffix in debug mode on Linux. | |
|
937 | // This is a workaround, because python does not append the '_d' suffix on Linux | |
|
938 | // and would always load the release library otherwise. | |
|
939 | _sharedLibrarySuffixes << "_d.so"; | |
|
940 | #endif | |
|
941 | #endif | |
|
925 | 942 | foreach (QVariant entry, result.toList()) { |
|
926 | 943 | QVariantList suffixEntry = entry.toList(); |
|
927 | 944 | if (suffixEntry.count()==3) { |
@@ -1066,6 +1083,10 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedC | |||
|
1066 | 1083 | _p->_noLongerWrappedCB = cb; |
|
1067 | 1084 | } |
|
1068 | 1085 | |
|
1086 | void PythonQt::setProfilingCallback(ProfilingCB* cb) | |
|
1087 | { | |
|
1088 | _p->_profilingCB = cb; | |
|
1089 | } | |
|
1069 | 1090 | |
|
1070 | 1091 | |
|
1071 | 1092 | static PyMethodDef PythonQtMethods[] = { |
@@ -1194,6 +1215,13 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info) | |||
|
1194 | 1215 | } |
|
1195 | 1216 | } |
|
1196 | 1217 | |
|
1218 | void PythonQt::clearNotFoundCachedMembers() | |
|
1219 | { | |
|
1220 | foreach(PythonQtClassInfo* info, _p->_knownClassInfos) { | |
|
1221 | info->clearNotFoundCachedMembers(); | |
|
1222 | } | |
|
1223 | } | |
|
1224 | ||
|
1197 | 1225 | void PythonQtPrivate::removeWrapperPointer(void* obj) |
|
1198 | 1226 | { |
|
1199 | 1227 | _wrappedObjects.remove(obj); |
@@ -143,6 +143,16 public: | |||
|
143 | 143 | |
|
144 | 144 | }; |
|
145 | 145 | |
|
146 | //! enum for profiling callback | |
|
147 | enum ProfilingCallbackState { | |
|
148 | Enter = 1, | |
|
149 | Leave = 2 | |
|
150 | }; | |
|
151 | ||
|
152 | //! callback for profiling. className and methodName are only passed when state == Enter, otherwise | |
|
153 | //! they are NULL. | |
|
154 | typedef void ProfilingCB(ProfilingCallbackState state, const char* className, const char* methodName); | |
|
155 | ||
|
146 | 156 | //--------------------------------------------------------------------------- |
|
147 | 157 | //! \name Singleton Initialization |
|
148 | 158 | //@{ |
@@ -427,6 +437,10 public: | |||
|
427 | 437 | //! The error is currently just output to the python stderr, future version might implement better trace printing |
|
428 | 438 | bool handleError(); |
|
429 | 439 | |
|
440 | //! clear all NotFound entries on all class infos, to ensure that | |
|
441 | //! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded | |
|
442 | void clearNotFoundCachedMembers(); | |
|
443 | ||
|
430 | 444 | //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt |
|
431 | 445 | void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb); |
|
432 | 446 | //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt |
@@ -442,6 +456,9 public: | |||
|
442 | 456 | //! @return new reference |
|
443 | 457 | PythonQtObjectPtr lookupObject(PyObject* module, const QString& name); |
|
444 | 458 | |
|
459 | //! sets a callback that is called before and after function calls for profiling | |
|
460 | void setProfilingCallback(ProfilingCB* cb); | |
|
461 | ||
|
445 | 462 | //@} |
|
446 | 463 | |
|
447 | 464 | signals: |
@@ -575,6 +592,9 public: | |||
|
575 | 592 | //! get access to the PythonQt module |
|
576 | 593 | PythonQtObjectPtr pythonQtModule() const { return _pythonQtModule; } |
|
577 | 594 | |
|
595 | //! returns the profiling callback, which may be NULL | |
|
596 | PythonQt::ProfilingCB* profilingCB() const { return _profilingCB; } | |
|
597 | ||
|
578 | 598 | private: |
|
579 | 599 | //! Setup the shared library suffixes by getting them from the "imp" module. |
|
580 | 600 | void setupSharedLibrarySuffixes(); |
@@ -625,6 +645,8 private: | |||
|
625 | 645 | |
|
626 | 646 | PythonQtClassInfo* _currentClassInfoForClassWrapperCreation; |
|
627 | 647 | |
|
648 | PythonQt::ProfilingCB* _profilingCB; | |
|
649 | ||
|
628 | 650 | int _initFlags; |
|
629 | 651 | int _PythonQtObjectPtr_metaId; |
|
630 | 652 |
@@ -847,3 +847,22 PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) { | |||
|
847 | 847 | return NULL; |
|
848 | 848 | } |
|
849 | 849 | |
|
850 | void PythonQtClassInfo::setDecoratorProvider( PythonQtQObjectCreatorFunctionCB* cb ) | |
|
851 | { | |
|
852 | _decoratorProviderCB = cb; | |
|
853 | _decoratorProvider = NULL; | |
|
854 | _enumsCreated = false; | |
|
855 | } | |
|
856 | ||
|
857 | void PythonQtClassInfo::clearNotFoundCachedMembers() | |
|
858 | { | |
|
859 | // remove all not found entries, since a new decorator means new slots, | |
|
860 | // which might have been cached as "NotFound" already. | |
|
861 | QMutableHashIterator<QByteArray, PythonQtMemberInfo> it(_cachedMembers); | |
|
862 | while (it.hasNext()) { | |
|
863 | it.next(); | |
|
864 | if (it.value()._type == PythonQtMemberInfo::NotFound) { | |
|
865 | it.remove(); | |
|
866 | } | |
|
867 | } | |
|
868 | } |
@@ -166,7 +166,7 public: | |||
|
166 | 166 | int metaTypeId() { return _metaTypeId; } |
|
167 | 167 | |
|
168 | 168 | //! set an additional decorator provider that offers additional decorator slots for this class |
|
169 |
void setDecoratorProvider(PythonQtQObjectCreatorFunctionCB* cb) |
|
|
169 | void setDecoratorProvider(PythonQtQObjectCreatorFunctionCB* cb); | |
|
170 | 170 | |
|
171 | 171 | //! get the decorator qobject instance |
|
172 | 172 | QObject* decorator(); |
@@ -202,6 +202,9 public: | |||
|
202 | 202 | //! returns if the localScope has an enum of that type name or if the enum contains a :: scope, if that class contails the enum |
|
203 | 203 | static PyObject* findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum = NULL); |
|
204 | 204 | |
|
205 | //! clear all members that where cached as "NotFound" | |
|
206 | void clearNotFoundCachedMembers(); | |
|
207 | ||
|
205 | 208 | private: |
|
206 | 209 | void createEnumWrappers(); |
|
207 | 210 | void createEnumWrappers(const QMetaObject* meta); |
@@ -266,6 +266,31 static PyObject *PythonQtClassWrapper_help(PythonQtClassWrapper* type) | |||
|
266 | 266 | return PythonQt::self()->helpCalled(type->classInfo()); |
|
267 | 267 | } |
|
268 | 268 | |
|
269 | PyObject *PythonQtClassWrapper_delete(PythonQtClassWrapper *type, PyObject *args) | |
|
270 | { | |
|
271 | Q_UNUSED(type); | |
|
272 | ||
|
273 | Py_ssize_t argc = PyTuple_Size(args); | |
|
274 | if (argc>0) { | |
|
275 | PyObject* self = PyTuple_GET_ITEM(args, 0); | |
|
276 | if (PyObject_TypeCheck(self, &PythonQtInstanceWrapper_Type)) { | |
|
277 | return PythonQtInstanceWrapper_delete((PythonQtInstanceWrapper*)self); | |
|
278 | } | |
|
279 | } | |
|
280 | return NULL; | |
|
281 | } | |
|
282 | ||
|
283 | PyObject *PythonQtClassWrapper_inherits(PythonQtClassWrapper *type, PyObject *args) | |
|
284 | { | |
|
285 | Q_UNUSED(type); | |
|
286 | PythonQtInstanceWrapper* wrapper = NULL; | |
|
287 | char *name = NULL; | |
|
288 | if (!PyArg_ParseTuple(args, "O!s:PythonQtClassWrapper.inherits",&PythonQtInstanceWrapper_Type, &wrapper, &name)) { | |
|
289 | return NULL; | |
|
290 | } | |
|
291 | return PythonQtConv::GetPyBool(wrapper->classInfo()->inherits(name)); | |
|
292 | } | |
|
293 | ||
|
269 | 294 | PyObject *PythonQtClassWrapper__init__(PythonQtClassWrapper *type, PyObject *args) |
|
270 | 295 | { |
|
271 | 296 | Py_ssize_t argc = PyTuple_Size(args); |
@@ -295,16 +320,23 PyObject *PythonQtClassWrapper__init__(PythonQtClassWrapper *type, PyObject *arg | |||
|
295 | 320 | return NULL; |
|
296 | 321 | } |
|
297 | 322 | |
|
323 | ||
|
298 | 324 | static PyMethodDef PythonQtClassWrapper_methods[] = { |
|
299 | 325 | {"__init__", (PyCFunction)PythonQtClassWrapper__init__, METH_VARARGS, |
|
300 | "Return the classname of the object" | |
|
326 | "Init function" | |
|
301 | 327 | }, |
|
302 | 328 | {"className", (PyCFunction)PythonQtClassWrapper_classname, METH_NOARGS, |
|
303 | 329 | "Return the classname of the object" |
|
304 | 330 | }, |
|
331 | {"inherits", (PyCFunction)PythonQtClassWrapper_inherits, METH_VARARGS, | |
|
332 | "Returns if the class inherits or is of given type name" | |
|
333 | }, | |
|
305 | 334 | {"help", (PyCFunction)PythonQtClassWrapper_help, METH_NOARGS, |
|
306 | 335 | "Shows the help of available methods for this class" |
|
307 | 336 | }, |
|
337 | {"delete", (PyCFunction)PythonQtClassWrapper_delete, METH_VARARGS, | |
|
338 | "Deletes the given C++ object" | |
|
339 | }, | |
|
308 | 340 | {NULL, NULL, 0 , NULL} /* Sentinel */ |
|
309 | 341 | }; |
|
310 | 342 | |
@@ -344,7 +376,7 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) | |||
|
344 | 376 | PyDict_SetItemString(dict, "__init__", func); |
|
345 | 377 | Py_DECREF(func); |
|
346 | 378 | } |
|
347 | for (int i = 1;i<3;i++) { | |
|
379 | for (int i = 1; PythonQtClassWrapper_methods[i].ml_name != NULL; i++) { | |
|
348 | 380 | PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[i], obj); |
|
349 | 381 | PyDict_SetItemString(dict, PythonQtClassWrapper_methods[i].ml_name, func); |
|
350 | 382 | Py_DECREF(func); |
@@ -47,7 +47,7 | |||
|
47 | 47 | |
|
48 | 48 | PythonQtValueStorage<qint64, 128> PythonQtConv::global_valueStorage; |
|
49 | 49 | PythonQtValueStorage<void*, 128> PythonQtConv::global_ptrStorage; |
|
50 |
PythonQtValueStorage<QVariant, |
|
|
50 | PythonQtValueStorageWithCleanup<QVariant, 128> PythonQtConv::global_variantStorage; | |
|
51 | 51 | |
|
52 | 52 | QHash<int, PythonQtConvertMetaTypeToPythonCB*> PythonQtConv::_metaTypeToPythonConverters; |
|
53 | 53 | QHash<int, PythonQtConvertPythonToMetaTypeCB*> PythonQtConv::_pythonToMetaTypeConverters; |
@@ -144,7 +144,7 public: | |||
|
144 | 144 | |
|
145 | 145 | static PythonQtValueStorage<qint64, 128> global_valueStorage; |
|
146 | 146 | static PythonQtValueStorage<void*, 128> global_ptrStorage; |
|
147 |
static PythonQtValueStorage<QVariant, |
|
|
147 | static PythonQtValueStorageWithCleanup<QVariant, 128> global_variantStorage; | |
|
148 | 148 | |
|
149 | 149 | protected: |
|
150 | 150 | static QHash<int, PythonQtConvertMetaTypeToPythonCB*> _metaTypeToPythonConverters; |
|
1 | NO CONTENT: modified file |
@@ -67,6 +67,9 public: | |||
|
67 | 67 | //! get the last modified data of a file |
|
68 | 68 | virtual QDateTime lastModifiedDate(const QString& filename) = 0; |
|
69 | 69 | |
|
70 | //! indicates that *.py files which are newer than their corresponding *.pyc files | |
|
71 | //! are ignored | |
|
72 | virtual bool ignoreUpdatedPythonSourceFiles() { return false; } | |
|
70 | 73 | }; |
|
71 | 74 | |
|
72 | 75 | #endif |
@@ -114,6 +114,7 PythonQtImport::ModuleInfo PythonQtImport::getModuleInfo(PythonQtImporter* self, | |||
|
114 | 114 | info.fullPath = test; |
|
115 | 115 | info.moduleName = subname; |
|
116 | 116 | info.type = MI_SHAREDLIBRARY; |
|
117 | return info; | |
|
117 | 118 | } |
|
118 | 119 | } |
|
119 | 120 | return info; |
@@ -276,12 +277,21 PythonQtImporter_load_module(PyObject *obj, PyObject *args) | |||
|
276 | 277 | args.append(QVariant::fromValue(pathList)); |
|
277 | 278 | QVariant result = imp.call("find_module", args); |
|
278 | 279 | if (result.isValid()) { |
|
279 | // This will return a tuple with (file, pathname, description) | |
|
280 | // This will return a tuple with (file, pathname, description=(suffix,mode,type)) | |
|
280 | 281 | QVariantList list = result.toList(); |
|
281 | 282 | if (list.count()==3) { |
|
282 | 283 | // We prepend the full module name (including package prefix) |
|
283 | 284 | list.prepend(fullname); |
|
284 | // And call "load_module" with (fullname, file, pathname, description) | |
|
285 | #ifdef __linux | |
|
286 | #ifdef _DEBUG | |
|
287 | // imp_find_module() does not respect the debug suffix '_d' on Linux, | |
|
288 | // so it does not return the correct file path and we correct it now | |
|
289 | // find_module opened a file to the release library, but that file handle is | |
|
290 | // ignored on Linux and Windows, maybe on MacOS also. | |
|
291 | list[2] = info.fullPath; | |
|
292 | #endif | |
|
293 | #endif | |
|
294 | // And call "load_module" with (fullname, file, pathname, description=(suffix,mode,type)) | |
|
285 | 295 | PythonQtObjectPtr module = imp.call("load_module", list); |
|
286 | 296 | mod = module.object(); |
|
287 | 297 | if (mod) { |
@@ -559,13 +569,17 PythonQtImport::unmarshalCode(const QString& path, const QByteArray& data, time_ | |||
|
559 | 569 | return Py_None; |
|
560 | 570 | } |
|
561 | 571 | |
|
562 | if (mtime != 0 && !(getLong((unsigned char *)buf + 4) == mtime)) { | |
|
572 | if (mtime != 0) { | |
|
573 | time_t timeDiff = getLong((unsigned char *)buf + 4) - mtime; | |
|
574 | if (timeDiff<0) { timeDiff = -timeDiff; } | |
|
575 | if (timeDiff > 1) { | |
|
563 | 576 | if (Py_VerboseFlag) |
|
564 | 577 | PySys_WriteStderr("# %s has bad mtime\n", |
|
565 | 578 |
|
|
566 | 579 | Py_INCREF(Py_None); |
|
567 | 580 | return Py_None; |
|
568 | 581 | } |
|
582 | } | |
|
569 | 583 | |
|
570 | 584 | code = PyMarshal_ReadObjectFromString(buf + 8, size - 8); |
|
571 | 585 | if (code == NULL) |
@@ -645,7 +659,10 PythonQtImport::getMTimeOfSource(const QString& path) | |||
|
645 | 659 | path2.truncate(path.length()-1); |
|
646 | 660 | |
|
647 | 661 | if (PythonQt::importInterface()->exists(path2)) { |
|
648 |
|
|
|
662 | QDateTime t = PythonQt::importInterface()->lastModifiedDate(path2); | |
|
663 | if (t.isValid()) { | |
|
664 | mtime = t.toTime_t(); | |
|
665 | } | |
|
649 | 666 | } |
|
650 | 667 | |
|
651 | 668 | return mtime; |
@@ -675,7 +692,12 PythonQtImport::getModuleCode(PythonQtImporter *self, const char* fullname, QStr | |||
|
675 | 692 | int ispackage = zso->type & IS_PACKAGE; |
|
676 | 693 | int isbytecode = zso->type & IS_BYTECODE; |
|
677 | 694 | |
|
678 | if (isbytecode) { | |
|
695 | // if ignoreUpdatedPythonSourceFiles() returns true, then mtime stays 0 | |
|
696 | // and unmarshalCode() in getCodeFromData() will always read an existing *.pyc file, | |
|
697 | // even if a newer *.py file exists. This is a release optimization where | |
|
698 | // typically only *.pyc files are delivered without *.py files and reading file | |
|
699 | // modification time is slow. | |
|
700 | if (isbytecode && !PythonQt::importInterface()->ignoreUpdatedPythonSourceFiles()) { | |
|
679 | 701 | mtime = getMTimeOfSource(test); |
|
680 | 702 | } |
|
681 | 703 | code = getCodeFromData(test, isbytecode, ispackage, mtime); |
@@ -713,7 +735,14 PyObject* PythonQtImport::getCodeFromPyc(const QString& file) | |||
|
713 | 735 | QString pyc = replaceExtension(file, pycStr); |
|
714 | 736 | if (PythonQt::importInterface()->exists(pyc)) { |
|
715 | 737 | time_t mtime = 0; |
|
738 | // if ignoreUpdatedPythonSourceFiles() returns true, then mtime stays 0 | |
|
739 | // and unmarshalCode() in getCodeFromData() will always read an existing *.pyc file, | |
|
740 | // even if a newer *.py file exists. This is a release optimization where | |
|
741 | // typically only *.pyc files are delivered without *.py files and reading file | |
|
742 | // modification time is slow. | |
|
743 | if (!PythonQt::importInterface()->ignoreUpdatedPythonSourceFiles()) { | |
|
716 | 744 | mtime = getMTimeOfSource(pyc); |
|
745 | } | |
|
717 | 746 | code = getCodeFromData(pyc, true, false, mtime); |
|
718 | 747 | if (code != Py_None && code != NULL) { |
|
719 | 748 | return code; |
@@ -288,12 +288,21 static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* obj) | |||
|
288 | 288 | return PyString_FromString(obj->ob_type->tp_name); |
|
289 | 289 | } |
|
290 | 290 | |
|
291 | PyObject *PythonQtInstanceWrapper_inherits(PythonQtInstanceWrapper* obj, PyObject *args) | |
|
292 | { | |
|
293 | char *name = NULL; | |
|
294 | if (!PyArg_ParseTuple(args, "s:PythonQtInstanceWrapper.inherits",&name)) { | |
|
295 | return NULL; | |
|
296 | } | |
|
297 | return PythonQtConv::GetPyBool(obj->classInfo()->inherits(name)); | |
|
298 | } | |
|
299 | ||
|
291 | 300 | static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* obj) |
|
292 | 301 | { |
|
293 | 302 | return PythonQt::self()->helpCalled(obj->classInfo()); |
|
294 | 303 | } |
|
295 | 304 | |
|
296 |
|
|
|
305 | PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self) | |
|
297 | 306 | { |
|
298 | 307 | PythonQtInstanceWrapper_deleteObject(self, true); |
|
299 | 308 | Py_INCREF(Py_None); |
@@ -305,6 +314,9 static PyMethodDef PythonQtInstanceWrapper_methods[] = { | |||
|
305 | 314 | {"className", (PyCFunction)PythonQtInstanceWrapper_classname, METH_NOARGS, |
|
306 | 315 | "Return the classname of the object" |
|
307 | 316 | }, |
|
317 | {"inherits", (PyCFunction)PythonQtInstanceWrapper_inherits, METH_VARARGS, | |
|
318 | "Returns if the class inherits or is of given type name" | |
|
319 | }, | |
|
308 | 320 | {"help", (PyCFunction)PythonQtInstanceWrapper_help, METH_NOARGS, |
|
309 | 321 | "Shows the help of available methods for this class" |
|
310 | 322 | }, |
@@ -371,7 +383,23 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) | |||
|
371 | 383 | case PythonQtMemberInfo::Property: |
|
372 | 384 | if (wrapper->_obj) { |
|
373 | 385 | if (member._property.userType() != QVariant::Invalid) { |
|
374 | return PythonQtConv::QVariantToPyObject(member._property.read(wrapper->_obj)); | |
|
386 | ||
|
387 | PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB(); | |
|
388 | if (profilingCB) { | |
|
389 | QString methodName = "getProperty("; | |
|
390 | methodName += attributeName; | |
|
391 | methodName += ")"; | |
|
392 | profilingCB(PythonQt::Enter, wrapper->_obj->metaObject()->className(), methodName.toLatin1()); | |
|
393 | } | |
|
394 | ||
|
395 | PyObject* value = PythonQtConv::QVariantToPyObject(member._property.read(wrapper->_obj)); | |
|
396 | ||
|
397 | if (profilingCB) { | |
|
398 | profilingCB(PythonQt::Leave, NULL, NULL); | |
|
399 | } | |
|
400 | ||
|
401 | return value; | |
|
402 | ||
|
375 | 403 | } else { |
|
376 | 404 | Py_INCREF(Py_None); |
|
377 | 405 | return Py_None; |
@@ -475,7 +503,19 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObjec | |||
|
475 | 503 | } |
|
476 | 504 | bool success = false; |
|
477 | 505 | if (v.isValid()) { |
|
506 | PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB(); | |
|
507 | if (profilingCB) { | |
|
508 | QString methodName = "setProperty("; | |
|
509 | methodName += attributeName; | |
|
510 | methodName += ")"; | |
|
511 | profilingCB(PythonQt::Enter, wrapper->_obj->metaObject()->className(), methodName.toLatin1()); | |
|
512 | } | |
|
513 | ||
|
478 | 514 | success = prop.write(wrapper->_obj, v); |
|
515 | ||
|
516 | if (profilingCB) { | |
|
517 | profilingCB(PythonQt::Leave, NULL, NULL); | |
|
518 | } | |
|
479 | 519 | } |
|
480 | 520 | if (success) { |
|
481 | 521 | return 0; |
@@ -605,17 +645,17 static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj) | |||
|
605 | 645 | if (str.startsWith(typeName)) { |
|
606 | 646 | return PyString_FromFormat("%s", str.toLatin1().constData()); |
|
607 | 647 | } else { |
|
608 | return PyString_FromFormat("%s(%s, %p)", typeName, str.toLatin1().constData(), wrapper->_wrappedPtr); | |
|
648 | return PyString_FromFormat("%s (%s, at: %p)", typeName, str.toLatin1().constData(), wrapper->_wrappedPtr ? wrapper->_wrappedPtr : qobj); | |
|
609 | 649 | } |
|
610 | 650 | } |
|
611 | 651 | if (wrapper->_wrappedPtr) { |
|
612 | 652 | if (wrapper->_obj) { |
|
613 |
return PyString_FromFormat("%s (C++ |
|
|
653 | return PyString_FromFormat("%s (C++ object at: %p wrapped by %s at: %p)", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj); | |
|
614 | 654 | } else { |
|
615 |
return PyString_FromFormat("%s (C++ |
|
|
655 | return PyString_FromFormat("%s (C++ object at: %p)", typeName, wrapper->_wrappedPtr); | |
|
616 | 656 | } |
|
617 | 657 | } else { |
|
618 | return PyString_FromFormat("%s (%s %p)", typeName, wrapper->classInfo()->className(), qobj); | |
|
658 | return PyString_FromFormat("%s (%s at: %p)", typeName, wrapper->classInfo()->className(), qobj); | |
|
619 | 659 | } |
|
620 | 660 | } |
|
621 | 661 |
@@ -95,4 +95,6 typedef struct PythonQtInstanceWrapperStruct { | |||
|
95 | 95 | |
|
96 | 96 | int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds); |
|
97 | 97 | |
|
98 | PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self); | |
|
99 | ||
|
98 | 100 | #endif |
@@ -192,7 +192,6 int PythonQtMethodInfo::nameToType(const char* name) | |||
|
192 | 192 | _parameterTypeDict.insert("qreal", QMetaType::Double); |
|
193 | 193 | _parameterTypeDict.insert("QChar", QMetaType::QChar); |
|
194 | 194 | _parameterTypeDict.insert("QByteArray", QMetaType::QByteArray); |
|
195 | _parameterTypeDict.insert("Q3CString", QMetaType::QByteArray); | |
|
196 | 195 | _parameterTypeDict.insert("QString", QMetaType::QString); |
|
197 | 196 | _parameterTypeDict.insert("", QMetaType::Void); |
|
198 | 197 | _parameterTypeDict.insert("void", QMetaType::Void); |
@@ -203,7 +202,6 int PythonQtMethodInfo::nameToType(const char* name) | |||
|
203 | 202 | _parameterTypeDict.insert("qulonglong", QMetaType::ULongLong); |
|
204 | 203 | _parameterTypeDict.insert("qint64", QMetaType::LongLong); |
|
205 | 204 | _parameterTypeDict.insert("quint64", QMetaType::ULongLong); |
|
206 | _parameterTypeDict.insert("QIconSet", QMetaType::QIcon); | |
|
207 | 205 | _parameterTypeDict.insert("QVariantMap", QMetaType::QVariantMap); |
|
208 | 206 | _parameterTypeDict.insert("QVariantList", QMetaType::QVariantList); |
|
209 | 207 | _parameterTypeDict.insert("QMap<QString,QVariant>", QMetaType::QVariantMap); |
@@ -216,15 +214,14 int PythonQtMethodInfo::nameToType(const char* name) | |||
|
216 | 214 | _parameterTypeDict.insert("QUrl", QMetaType::QUrl); |
|
217 | 215 | _parameterTypeDict.insert("QLocale", QMetaType::QLocale); |
|
218 | 216 | _parameterTypeDict.insert("QRect", QMetaType::QRect); |
|
219 |
_parameterTypeDict.insert("QRect |
|
|
217 | _parameterTypeDict.insert("QRectF", QMetaType::QRectF); | |
|
220 | 218 | _parameterTypeDict.insert("QSize", QMetaType::QSize); |
|
221 |
_parameterTypeDict.insert("QSize |
|
|
219 | _parameterTypeDict.insert("QSizeF", QMetaType::QSizeF); | |
|
222 | 220 | _parameterTypeDict.insert("QLine", QMetaType::QLine); |
|
223 |
_parameterTypeDict.insert("QLine |
|
|
221 | _parameterTypeDict.insert("QLineF", QMetaType::QLineF); | |
|
224 | 222 | _parameterTypeDict.insert("QPoint", QMetaType::QPoint); |
|
225 |
_parameterTypeDict.insert("QPoint |
|
|
223 | _parameterTypeDict.insert("QPointF", QMetaType::QPointF); | |
|
226 | 224 | _parameterTypeDict.insert("QRegExp", QMetaType::QRegExp); |
|
227 | // _parameterTypeDict.insert("QColorGroup", QMetaType::QColorGroup); | |
|
228 | 225 | _parameterTypeDict.insert("QFont", QMetaType::QFont); |
|
229 | 226 | _parameterTypeDict.insert("QPixmap", QMetaType::QPixmap); |
|
230 | 227 | _parameterTypeDict.insert("QBrush", QMetaType::QBrush); |
@@ -232,7 +229,7 int PythonQtMethodInfo::nameToType(const char* name) | |||
|
232 | 229 | _parameterTypeDict.insert("QCursor", QMetaType::QCursor); |
|
233 | 230 | _parameterTypeDict.insert("QPalette", QMetaType::QPalette); |
|
234 | 231 | _parameterTypeDict.insert("QIcon", QMetaType::QIcon); |
|
235 |
_parameterTypeDict.insert("QImage", QMetaType::Q |
|
|
232 | _parameterTypeDict.insert("QImage", QMetaType::QImage); | |
|
236 | 233 | _parameterTypeDict.insert("QRegion", QMetaType::QRegion); |
|
237 | 234 | _parameterTypeDict.insert("QBitmap", QMetaType::QBitmap); |
|
238 | 235 | _parameterTypeDict.insert("QSizePolicy", QMetaType::QSizePolicy); |
@@ -89,13 +89,6 public: | |||
|
89 | 89 | _chunks.clear(); |
|
90 | 90 | } |
|
91 | 91 | |
|
92 | //! reset the storage to 0 (without freeing memory, thus caching old entries for reuse) | |
|
93 | void reset() { | |
|
94 | _chunkIdx = 0; | |
|
95 | _chunkOffset = 0; | |
|
96 | _currentChunk = _chunks.at(0); | |
|
97 | } | |
|
98 | ||
|
99 | 92 | //! get the current position to be restored with setPos |
|
100 | 93 | void getPos(PythonQtValueStoragePosition & pos) { |
|
101 | 94 | pos.chunkIdx = _chunkIdx; |
@@ -129,7 +122,7 public: | |||
|
129 | 122 | return newEntry; |
|
130 | 123 | }; |
|
131 | 124 | |
|
132 | private: | |
|
125 | protected: | |
|
133 | 126 | QList<T*> _chunks; |
|
134 | 127 | |
|
135 | 128 | int _chunkIdx; |
@@ -138,5 +131,45 private: | |||
|
138 | 131 | |
|
139 | 132 | }; |
|
140 | 133 | |
|
134 | //! a helper class that stores basic C++ value types in chunks and clears the unused values on setPos() usage. | |
|
135 | template <typename T, int chunkEntries> class PythonQtValueStorageWithCleanup : public PythonQtValueStorage<T, chunkEntries> | |
|
136 | { | |
|
137 | public: | |
|
138 | void setPos(const PythonQtValueStoragePosition& pos) { | |
|
139 | if (_chunkIdx > pos.chunkIdx) { | |
|
140 | T* firstChunk = _chunks.at(pos.chunkIdx); | |
|
141 | // clear region in first chunk | |
|
142 | for (int i = pos.chunkOffset; i < chunkEntries; i++) { | |
|
143 | firstChunk[i] = T(); | |
|
144 | } | |
|
145 | for (int chunk = pos.chunkIdx + 1; chunk < _chunkIdx; chunk++) { | |
|
146 | // clear the full chunks between the first and last chunk | |
|
147 | T* fullChunk = _chunks.at(chunk); | |
|
148 | for (int i = 0; i < chunkEntries; i++) { | |
|
149 | fullChunk[i] = T(); | |
|
150 | } | |
|
151 | } | |
|
152 | // clear region in last chunk | |
|
153 | T* lastChunk = _chunks.at(_chunkIdx); | |
|
154 | for (int i = 0; i < _chunkOffset; i++) { | |
|
155 | lastChunk[i] = T(); | |
|
156 | } | |
|
157 | } else if (_chunkIdx == pos.chunkIdx) { | |
|
158 | // clear the region in the last chunk only | |
|
159 | T* lastChunk = _chunks.at(_chunkIdx); | |
|
160 | for (int i = pos.chunkOffset; i<_chunkOffset; i++) { | |
|
161 | lastChunk[i] = T(); | |
|
162 | } | |
|
163 | } | |
|
164 | ||
|
165 | PythonQtValueStorage<T, chunkEntries>::setPos(pos); | |
|
166 | } | |
|
167 | ||
|
168 | private: | |
|
169 | using PythonQtValueStorage<T, chunkEntries>::_chunks; | |
|
170 | using PythonQtValueStorage<T, chunkEntries>::_chunkIdx; | |
|
171 | using PythonQtValueStorage<T, chunkEntries>::_chunkOffset; | |
|
172 | using PythonQtValueStorage<T, chunkEntries>::_currentChunk; | |
|
173 | }; | |
|
141 | 174 | |
|
142 | 175 | #endif |
@@ -67,7 +67,7 public: | |||
|
67 | 67 | if (o) Py_INCREF(_object); |
|
68 | 68 | } |
|
69 | 69 | |
|
70 | ~PythonQtObjectPtr() { if (_object) Py_DECREF(_object); } | |
|
70 | ~PythonQtObjectPtr() { if (_object) { Py_DECREF(_object); } } | |
|
71 | 71 | |
|
72 | 72 |
//! If the given variant holds a PythonQtObjectPtr, extract the value from it and hold onto the reference. This results in an increment of the reference count. |
|
73 | 73 | bool fromVariant(const QVariant& variant); |
@@ -116,7 +116,7 public: | |||
|
116 | 116 | //! sets the object and passes the ownership (stealing the reference, in Python slang) |
|
117 | 117 | void setNewRef(PyObject* o) { |
|
118 | 118 | if (o != _object) { |
|
119 | if (_object) Py_DECREF(_object); | |
|
119 | if (_object) { Py_DECREF(_object); } | |
|
120 | 120 | _object = o; |
|
121 | 121 | } |
|
122 | 122 | } |
@@ -157,9 +157,9 protected: | |||
|
157 | 157 | |
|
158 | 158 | void setObject(PyObject* o) { |
|
159 | 159 | if (o != _object) { |
|
160 | if (_object) Py_DECREF(_object); | |
|
160 | if (_object) { Py_DECREF(_object); } | |
|
161 | 161 | _object = o; |
|
162 | if (_object) Py_INCREF(_object); | |
|
162 | if (_object) { Py_INCREF(_object); } | |
|
163 | 163 | } |
|
164 | 164 | } |
|
165 | 165 |
@@ -56,6 +56,8 void PythonQtSignalTarget::call(void **arguments) const { | |||
|
56 | 56 | |
|
57 | 57 | PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInfo* methodInfos, void **arguments, bool skipFirstArgumentOfMethodInfo) |
|
58 | 58 | { |
|
59 | Q_UNUSED(skipFirstArgumentOfMethodInfo) | |
|
60 | ||
|
59 | 61 | // Note: we check if the callable is a PyFunctionObject and has a fixed number of arguments |
|
60 | 62 | // if that is the case, we only pass these arguments to python and skip the additional arguments from the signal |
|
61 | 63 |
@@ -50,7 +50,7 class PythonQtMethodInfo; | |||
|
50 | 50 | class PythonQtClassInfo; |
|
51 | 51 | |
|
52 | 52 | //! stores information about a signal target |
|
53 |
/*! copy construction and assignment works fine with the C++ standard behavio |
|
|
53 | /*! copy construction and assignment works fine with the C++ standard behavior and are thus not implemented | |
|
54 | 54 | */ |
|
55 | 55 | class PYTHONQT_EXPORT PythonQtSignalTarget { |
|
56 | 56 | public: |
@@ -142,9 +142,26 bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj | |||
|
142 | 142 | } |
|
143 | 143 | } |
|
144 | 144 | |
|
145 | ||
|
146 | PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB(); | |
|
147 | if (profilingCB) { | |
|
148 | const char* className = NULL; | |
|
149 | if (info->decorator()) { | |
|
150 | className = info->decorator()->metaObject()->className(); | |
|
151 | } else { | |
|
152 | className = objectToCall->metaObject()->className(); | |
|
153 | } | |
|
154 | ||
|
155 | profilingCB(PythonQt::Enter, className, info->metaMethod()->signature()); | |
|
156 | } | |
|
157 | ||
|
145 | 158 | // invoke the slot via metacall |
|
146 | 159 | (info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList); |
|
147 | 160 | |
|
161 | if (profilingCB) { | |
|
162 | profilingCB(PythonQt::Leave, NULL, NULL); | |
|
163 | } | |
|
164 | ||
|
148 | 165 | // handle the return value (which in most cases still needs to be converted to a Python object) |
|
149 | 166 | if (argList[0] || returnValueParam.typeId == QMetaType::Void) { |
|
150 | 167 | if (directReturnValuePointer) { |
@@ -126,15 +126,6 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal | |||
|
126 | 126 | return r; |
|
127 | 127 | } |
|
128 | 128 | |
|
129 | #undef emit | |
|
130 | void PythonQtStdDecorators::emit(QObject* sender, const QByteArray& signal, PyObject* arg1 ,PyObject* arg2 , | |
|
131 | PyObject* arg3 ,PyObject* arg4 ,PyObject* arg5 ,PyObject* arg6 ,PyObject* arg7 ) | |
|
132 | { | |
|
133 | // TODO xxx | |
|
134 | // use normal PythonQtSlot calling code, add "allowSignal" to member lookup?! | |
|
135 | } | |
|
136 | #define emit | |
|
137 | ||
|
138 | 129 | QObject* PythonQtStdDecorators::parent(QObject* o) { |
|
139 | 130 | return o->parent(); |
|
140 | 131 | } |
@@ -62,11 +62,6 public slots: | |||
|
62 | 62 | bool disconnect(QObject* sender, const QByteArray& signal, PyObject* callable); |
|
63 | 63 | bool disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot); |
|
64 | 64 | |
|
65 | #undef emit | |
|
66 | void emit(QObject* sender, const QByteArray& signal, PyObject* arg1 = NULL,PyObject* arg2 = NULL, | |
|
67 | PyObject* arg3 = NULL,PyObject* arg4 = NULL,PyObject* arg5 = NULL,PyObject* arg6 = NULL,PyObject* arg7 = NULL); | |
|
68 | #define emit | |
|
69 | ||
|
70 | 65 | QObject* parent(QObject* o); |
|
71 | 66 | void setParent(QObject* o, QObject* parent); |
|
72 | 67 | |
@@ -80,13 +75,13 public slots: | |||
|
80 | 75 | |
|
81 | 76 | double static_Qt_qAbs(double a) { return qAbs(a); } |
|
82 | 77 | double static_Qt_qBound(double a,double b,double c) { return qBound(a,b,c); } |
|
83 | void static_Qt_qDebug(const QByteArray& msg) { qDebug(msg.constData()); } | |
|
78 | void static_Qt_qDebug(const QByteArray& msg) { qDebug("%s", msg.constData()); } | |
|
84 | 79 | // TODO: multi arg qDebug... |
|
85 | void static_Qt_qWarning(const QByteArray& msg) { qWarning(msg.constData()); } | |
|
80 | void static_Qt_qWarning(const QByteArray& msg) { qWarning("%s", msg.constData()); } | |
|
86 | 81 | // TODO: multi arg qWarning... |
|
87 | void static_Qt_qCritical(const QByteArray& msg) { qCritical(msg.constData()); } | |
|
82 | void static_Qt_qCritical(const QByteArray& msg) { qCritical("%s", msg.constData()); } | |
|
88 | 83 | // TODO: multi arg qCritical... |
|
89 | void static_Qt_qFatal(const QByteArray& msg) { qFatal(msg.constData()); } | |
|
84 | void static_Qt_qFatal(const QByteArray& msg) { qFatal("%s", msg.constData()); } | |
|
90 | 85 | // TODO: multi arg qFatal... |
|
91 | 86 | bool static_Qt_qFuzzyCompare(double a, double b) { return qFuzzyCompare(a, b); } |
|
92 | 87 | double static_Qt_qMax(double a, double b) { return qMax(a, b); } |
General Comments 0
You need to be logged in to leave comments.
Login now