@@ -80,7 +80,7 void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) | |||
|
80 | 80 | |
|
81 | 81 | PythonQt_init_QtCoreBuiltin(NULL); |
|
82 | 82 | PythonQt_init_QtGuiBuiltin(NULL); |
|
83 | ||
|
83 | ||
|
84 | 84 | PythonQtRegisterToolClassesTemplateConverter(QByteArray); |
|
85 | 85 | PythonQtRegisterToolClassesTemplateConverter(QDate); |
|
86 | 86 | PythonQtRegisterToolClassesTemplateConverter(QTime); |
@@ -157,7 +157,7 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName) | |||
|
157 | 157 | } |
|
158 | 158 | Py_Initialize(); |
|
159 | 159 | } |
|
160 | ||
|
160 | ||
|
161 | 161 | // add our own python object types for qt object slots |
|
162 | 162 | if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) { |
|
163 | 163 | std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl; |
@@ -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[] = { |
@@ -1080,7 +1101,7 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQ | |||
|
1080 | 1101 | } |
|
1081 | 1102 | _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods); |
|
1082 | 1103 | _p->_pythonQtModuleName = name; |
|
1083 | ||
|
1104 | ||
|
1084 | 1105 | if (redirectStdOut) { |
|
1085 | 1106 | PythonQtObjectPtr sys; |
|
1086 | 1107 | PythonQtObjectPtr out; |
@@ -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); |
@@ -75,7 +75,7 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtI | |||
|
75 | 75 | |
|
76 | 76 | //! returns the offset that needs to be added to upcast an object of type T1 to T2 |
|
77 | 77 | template<class T1, class T2> int PythonQtUpcastingOffset() { |
|
78 |
return (((char*)(static_cast<T2*>(reinterpret_cast<T1*>(0x100)))) - ((char*)reinterpret_cast<T1*>(0x100))); |
|
|
78 | return (((char*)(static_cast<T2*>(reinterpret_cast<T1*>(0x100)))) - ((char*)reinterpret_cast<T1*>(0x100))); | |
|
79 | 79 | } |
|
80 | 80 | |
|
81 | 81 | //! callback to create a QObject lazily |
@@ -143,10 +143,20 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 | //@{ |
|
149 | ||
|
159 | ||
|
150 | 160 | //! initialize the python qt binding (flags are a or combination of PythonQt::InitFlags), if \c pythonQtModuleName is given |
|
151 | 161 | //! it defines the name of the python module that PythonQt will add, otherwise "PythonQt" is used. |
|
152 | 162 | //! This can be used to e.g. pass in PySide or PyQt4 to make it more compatible. |
@@ -159,7 +169,7 public: | |||
|
159 | 169 | static PythonQt* self() { return _self; } |
|
160 | 170 | |
|
161 | 171 | //@} |
|
162 | ||
|
172 | ||
|
163 | 173 | //! defines the object types for introspection |
|
164 | 174 | enum ObjectType { |
|
165 | 175 | Class, |
@@ -186,13 +196,13 public: | |||
|
186 | 196 | //! to a module later on. |
|
187 | 197 | //! The user needs to make sure that the \c name is unique in the python module dictionary. |
|
188 | 198 | PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename); |
|
189 | ||
|
199 | ||
|
190 | 200 | //! creates the new module \c name and evaluates the given script in the context of that module. |
|
191 | 201 | //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code |
|
192 | 202 | //! to a module later on. |
|
193 | 203 | //! The user needs to make sure that the \c name is unique in the python module dictionary. |
|
194 | 204 | PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString()); |
|
195 | ||
|
205 | ||
|
196 | 206 | //! create a uniquely named module, you can use evalFile or evalScript to populate the module with |
|
197 | 207 | //! script code |
|
198 | 208 | PythonQtObjectPtr createUniqueModule(); |
@@ -213,20 +223,20 public: | |||
|
213 | 223 | void setModuleImportPath(PyObject* module, const QStringList& paths); |
|
214 | 224 | |
|
215 | 225 | //@} |
|
216 | ||
|
226 | ||
|
217 | 227 | //--------------------------------------------------------------------------- |
|
218 | 228 | //! \name Registering Classes |
|
219 | 229 | //@{ |
|
220 | ||
|
230 | ||
|
221 | 231 | //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well) |
|
222 | 232 | /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject, |
|
223 | 233 | you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */ |
|
224 | 234 | void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL); |
|
225 | ||
|
235 | ||
|
226 | 236 | //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants |
|
227 | 237 | //! (ownership of wrapper is passed to PythonQt) |
|
228 | 238 | /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type! |
|
229 | ||
|
239 | ||
|
230 | 240 | This will add a wrapper object that is used to make calls to the given classname \c typeName. |
|
231 | 241 | All slots that take a pointer to typeName as the first argument will be callable from Python on |
|
232 | 242 | a variant object that contains such a type. |
@@ -251,7 +261,7 public: | |||
|
251 | 261 | //--------------------------------------------------------------------------- |
|
252 | 262 | //! \name Script Parsing and Evaluation |
|
253 | 263 | //@{ |
|
254 | ||
|
264 | ||
|
255 | 265 | //! parses the given file and returns the python code object, this can then be used to call evalCode() |
|
256 | 266 | PythonQtObjectPtr parseFile(const QString& filename); |
|
257 | 267 | |
@@ -287,7 +297,7 public: | |||
|
287 | 297 | |
|
288 | 298 | //--------------------------------------------------------------------------- |
|
289 | 299 | //! \name Variable access |
|
290 |
//@{ |
|
|
300 | //@{ | |
|
291 | 301 | |
|
292 | 302 | //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable) |
|
293 | 303 | void addObject(PyObject* object, const QString& name, QObject* qObject); |
@@ -312,7 +322,7 public: | |||
|
312 | 322 | |
|
313 | 323 | //--------------------------------------------------------------------------- |
|
314 | 324 | //! \name Calling Python Objects |
|
315 |
//@{ |
|
|
325 | //@{ | |
|
316 | 326 | |
|
317 | 327 | //! call the given python \c callable in the scope of object, returns the result converted to a QVariant |
|
318 | 328 | QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList()); |
@@ -385,10 +395,10 public: | |||
|
385 | 395 | //--------------------------------------------------------------------------- |
|
386 | 396 | //! \name Custom Importer |
|
387 | 397 | //@{ |
|
388 | ||
|
398 | ||
|
389 | 399 | //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files) |
|
390 | 400 | //! (this method should be called directly after initialization of init() and before calling overwriteSysPath(). |
|
391 |
//! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks". |
|
|
401 | //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks". | |
|
392 | 402 | //! This is not reversible, so even setting setImporter(NULL) afterwards will |
|
393 | 403 | //! keep the custom PythonQt importer with a QFile default import interface. |
|
394 | 404 | //! Subsequent python import calls will make use of the passed importInterface |
@@ -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 |
@@ -437,11 +451,14 public: | |||
|
437 | 451 | |
|
438 | 452 | //! called by internal help methods |
|
439 | 453 | PyObject* helpCalled(PythonQtClassInfo* info); |
|
440 | ||
|
454 | ||
|
441 | 455 | //! returns the found object or NULL |
|
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: |
@@ -507,7 +524,7 public: | |||
|
507 | 524 | |
|
508 | 525 | //! add a handler for polymorphic downcasting |
|
509 | 526 | void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb); |
|
510 | ||
|
527 | ||
|
511 | 528 | //! lookup existing classinfo and return new if not yet present |
|
512 | 529 | PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName); |
|
513 | 530 | |
@@ -528,13 +545,13 public: | |||
|
528 | 545 | //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants |
|
529 | 546 | //! (ownership of wrapper is passed to PythonQt) |
|
530 | 547 | /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type! |
|
531 | ||
|
548 | ||
|
532 | 549 | This will add a wrapper object that is used to make calls to the given classname \c typeName. |
|
533 | 550 | All slots that take a pointer to typeName as the first argument will be callable from Python on |
|
534 | 551 | a variant object that contains such a type. |
|
535 | 552 | */ |
|
536 | 553 | void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0); |
|
537 | ||
|
554 | ||
|
538 | 555 | //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes |
|
539 | 556 | //! and it will register the classes when it first sees a pointer to such a derived class |
|
540 | 557 | void registerQObjectClassNames(const QStringList& names); |
@@ -571,10 +588,13 public: | |||
|
571 | 588 | |
|
572 | 589 | //! called by virtual overloads when a python return value can not be converted to the required Qt type |
|
573 | 590 | void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result); |
|
574 | ||
|
591 | ||
|
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(); |
@@ -605,13 +625,13 private: | |||
|
605 | 625 | |
|
606 | 626 | //! the name of the PythonQt python module |
|
607 | 627 | QByteArray _pythonQtModuleName; |
|
608 | ||
|
628 | ||
|
609 | 629 | //! the importer interface (if set) |
|
610 | 630 | PythonQtImportFileInterface* _importInterface; |
|
611 | 631 | |
|
612 | 632 | //! the default importer |
|
613 | 633 | PythonQtQFileImporter* _defaultImporter; |
|
614 | ||
|
634 | ||
|
615 | 635 | PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB; |
|
616 | 636 | PythonQtQObjectWrappedCB* _wrappedCB; |
|
617 | 637 | |
@@ -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(); |
@@ -201,7 +201,10 public: | |||
|
201 | 201 | |
|
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); |
@@ -225,7 +228,7 private: | |||
|
225 | 228 | |
|
226 | 229 | PythonQtSlotInfo* findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset); |
|
227 | 230 | int findCharOffset(const char* sigStart, char someChar); |
|
228 | ||
|
231 | ||
|
229 | 232 |
|
|
230 | 233 | |
|
231 | 234 | PythonQtSlotInfo* _constructors; |
@@ -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 | |
@@ -313,7 +345,7 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) | |||
|
313 | 345 | { |
|
314 | 346 | const char *attributeName; |
|
315 | 347 | PythonQtClassWrapper *wrapper = (PythonQtClassWrapper *)obj; |
|
316 | ||
|
348 | ||
|
317 | 349 | if ((attributeName = PyString_AsString(name)) == NULL) { |
|
318 | 350 | return NULL; |
|
319 | 351 | } |
@@ -328,7 +360,7 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) | |||
|
328 | 360 | return dict; |
|
329 | 361 | } |
|
330 | 362 | dict = PyDict_Copy(dict); |
|
331 | ||
|
363 | ||
|
332 | 364 | QStringList l = wrapper->classInfo()->memberList(false); |
|
333 | 365 | foreach (QString name, l) { |
|
334 | 366 | PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data()); |
@@ -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); |
@@ -396,7 +428,7 static PyObject * PythonQtClassWrapper_repr(PyObject * obj) | |||
|
396 | 428 | { |
|
397 | 429 | PythonQtClassWrapper* wrapper = (PythonQtClassWrapper*)obj; |
|
398 | 430 | if (wrapper->classInfo()->isCPPWrapper()) { |
|
399 |
const QMetaObject* meta = wrapper->classInfo()->metaObject(); |
|
|
431 | const QMetaObject* meta = wrapper->classInfo()->metaObject(); | |
|
400 | 432 | if (!meta) { |
|
401 | 433 | QObject* decorator = wrapper->classInfo()->decorator(); |
|
402 | 434 | if (decorator) { |
@@ -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; |
@@ -46,7 +46,7 | |||
|
46 | 46 | #include <QString> |
|
47 | 47 | #include <QByteArray> |
|
48 | 48 | |
|
49 |
//! Defines an abstract interface to file access for the Python import statement. |
|
|
49 | //! Defines an abstract interface to file access for the Python import statement. | |
|
50 | 50 | //! see PythonQt::setImporter() |
|
51 | 51 | class PythonQtImportFileInterface { |
|
52 | 52 | |
@@ -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 | #endif No newline at end of file | |
|
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; |
@@ -263,7 +264,7 PythonQtImporter_load_module(PyObject *obj, PyObject *args) | |||
|
263 | 264 | } else { |
|
264 | 265 | PythonQtObjectPtr imp; |
|
265 | 266 | imp.setNewRef(PyImport_ImportModule("imp")); |
|
266 | ||
|
267 | ||
|
267 | 268 | // Create a PyList with the current path as its single element, |
|
268 | 269 | // which is required for find_module (it won't accept a tuple...) |
|
269 | 270 | PythonQtObjectPtr pathList; |
@@ -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,12 +569,16 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)) { | |
|
563 | if (Py_VerboseFlag) | |
|
564 | PySys_WriteStderr("# %s has bad mtime\n", | |
|
565 | path.toLatin1().constData()); | |
|
566 | Py_INCREF(Py_None); | |
|
567 | return Py_None; | |
|
572 | if (mtime != 0) { | |
|
573 | time_t timeDiff = getLong((unsigned char *)buf + 4) - mtime; | |
|
574 | if (timeDiff<0) { timeDiff = -timeDiff; } | |
|
575 | if (timeDiff > 1) { | |
|
576 | if (Py_VerboseFlag) | |
|
577 | PySys_WriteStderr("# %s has bad mtime\n", | |
|
578 | path.toLatin1().constData()); | |
|
579 | Py_INCREF(Py_None); | |
|
580 | return Py_None; | |
|
581 | } | |
|
568 | 582 | } |
|
569 | 583 | |
|
570 | 584 | code = PyMarshal_ReadObjectFromString(buf + 8, size - 8); |
@@ -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; |
|
716 | mtime = getMTimeOfSource(pyc); | |
|
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()) { | |
|
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 |
@@ -90,9 +90,11 typedef struct PythonQtInstanceWrapperStruct { | |||
|
90 | 90 | |
|
91 | 91 | //! stores if the object is a shell instance |
|
92 | 92 | bool _isShellInstance; |
|
93 | ||
|
93 | ||
|
94 | 94 | } PythonQtInstanceWrapper; |
|
95 | 95 | |
|
96 | 96 | int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds); |
|
97 | 97 | |
|
98 | #endif No newline at end of file | |
|
98 | PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self); | |
|
99 | ||
|
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 |
@@ -57,21 +57,21 public: | |||
|
57 | 57 | setObject(p.object()); |
|
58 | 58 | } |
|
59 | 59 | |
|
60 |
//! 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. |
|
|
60 | //! 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. | |
|
61 | 61 | PythonQtObjectPtr(const QVariant& variant):_object(NULL) { |
|
62 |
fromVariant(variant); |
|
|
62 | fromVariant(variant); | |
|
63 | 63 | } |
|
64 | ||
|
64 | ||
|
65 | 65 | PythonQtObjectPtr(PyObject* o) { |
|
66 | 66 | _object = o; |
|
67 | 67 | if (o) Py_INCREF(_object); |
|
68 | 68 | } |
|
69 | 69 | |
|
70 | ~PythonQtObjectPtr() { if (_object) Py_DECREF(_object); } | |
|
71 | ||
|
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. |
|
|
70 | ~PythonQtObjectPtr() { if (_object) { Py_DECREF(_object); } } | |
|
71 | ||
|
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); |
|
74 | ||
|
74 | ||
|
75 | 75 | PythonQtObjectPtr &operator=(const PythonQtObjectPtr &p) { |
|
76 | 76 | setObject(p.object()); |
|
77 | 77 | return *this; |
@@ -82,13 +82,13 public: | |||
|
82 | 82 | return *this; |
|
83 | 83 | } |
|
84 | 84 | |
|
85 | ||
|
85 | ||
|
86 | 86 | PythonQtObjectPtr &operator=(const QVariant& variant) { |
|
87 | 87 | fromVariant(variant); |
|
88 | 88 | return *this; |
|
89 | 89 | } |
|
90 | 90 | |
|
91 | ||
|
91 | ||
|
92 | 92 | bool operator==( const PythonQtObjectPtr &p ) const { |
|
93 | 93 | return object() == p.object(); |
|
94 | 94 | } |
@@ -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 | |
@@ -171,4 +171,4 private: | |||
|
171 | 171 | // register it to the meta type system |
|
172 | 172 | Q_DECLARE_METATYPE(PythonQtObjectPtr) |
|
173 | 173 | |
|
174 | #endif No newline at end of file | |
|
174 | #endif |
@@ -56,9 +56,11 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 | ||
|
62 | 64 | int numPythonArgs = -1; |
|
63 | 65 | if (PyFunction_Check(callable)) { |
|
64 | 66 | PyObject* o = callable; |
@@ -135,7 +137,7 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInf | |||
|
135 | 137 | PythonQtSignalReceiver::PythonQtSignalReceiver(QObject* obj):PythonQtSignalReceiverBase(obj) |
|
136 | 138 | { |
|
137 | 139 | _obj = obj; |
|
138 | ||
|
140 | ||
|
139 | 141 | // fetch the class info for object, since we will need to for correct enum resolution in |
|
140 | 142 | // signals |
|
141 | 143 | _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject()); |
@@ -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: |
@@ -53,7 +53,7 | |||
|
53 | 53 | bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer) |
|
54 | 54 | { |
|
55 | 55 | static unsigned int recursiveEntry = 0; |
|
56 | ||
|
56 | ||
|
57 | 57 | if (directReturnValuePointer) { |
|
58 | 58 | *directReturnValuePointer = NULL; |
|
59 | 59 | } |
@@ -65,19 +65,19 bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj | |||
|
65 | 65 | PythonQtConv::global_valueStorage.getPos(globalValueStoragePos); |
|
66 | 66 | PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos); |
|
67 | 67 | PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos); |
|
68 | ||
|
68 | ||
|
69 | 69 | recursiveEntry++; |
|
70 | ||
|
70 | ||
|
71 | 71 | // the arguments that are passed to qt_metacall |
|
72 | 72 | void* argList[PYTHONQT_MAX_ARGS]; |
|
73 | 73 | PyObject* result = NULL; |
|
74 | 74 | int argc = info->parameterCount(); |
|
75 | 75 | const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters(); |
|
76 | ||
|
76 | ||
|
77 | 77 | const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0); |
|
78 | 78 | // set return argument to NULL |
|
79 | 79 | argList[0] = NULL; |
|
80 | ||
|
80 | ||
|
81 | 81 | bool ok = true; |
|
82 | 82 | bool skipFirst = false; |
|
83 | 83 | if (info->isInstanceDecorator()) { |
@@ -114,7 +114,7 bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj | |||
|
114 | 114 | } |
|
115 | 115 | } |
|
116 | 116 | } |
|
117 | ||
|
117 | ||
|
118 | 118 | if (ok) { |
|
119 | 119 | // parameters are ok, now create the qt return value which is assigned to by metacall |
|
120 | 120 | if (returnValueParam.typeId != QMetaType::Void) { |
@@ -133,8 +133,8 bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj | |||
|
133 | 133 | if (result) { |
|
134 | 134 | argList[0] = ((PythonQtInstanceWrapper*)result)->_wrappedPtr; |
|
135 | 135 | } |
|
136 |
Py_DECREF(emptyTuple); |
|
|
137 |
} |
|
|
136 | Py_DECREF(emptyTuple); | |
|
137 | } | |
|
138 | 138 | } |
|
139 | 139 | } else { |
|
140 | 140 | // we can use our pointer directly! |
@@ -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) { |
@@ -162,12 +179,12 bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj | |||
|
162 | 179 | } |
|
163 | 180 | } |
|
164 | 181 | recursiveEntry--; |
|
165 | ||
|
182 | ||
|
166 | 183 | // reset the parameter storage position to the stored pos to "pop" the parameter stack |
|
167 | 184 | PythonQtConv::global_valueStorage.setPos(globalValueStoragePos); |
|
168 | 185 | PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos); |
|
169 | 186 | PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos); |
|
170 | ||
|
187 | ||
|
171 | 188 | *pythonReturnValue = result; |
|
172 | 189 | // NOTE: it is important to only return here, otherwise the stack will not be popped!!! |
|
173 | 190 | return result || (directReturnValuePointer && *directReturnValuePointer); |
@@ -286,7 +303,7 PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* o | |||
|
286 | 303 | PyErr_SetString(PyExc_ValueError, e.toLatin1().data()); |
|
287 | 304 | } |
|
288 | 305 | } |
|
289 | ||
|
306 | ||
|
290 | 307 | return r; |
|
291 | 308 | } |
|
292 | 309 |
@@ -53,7 +53,7 bool PythonQtStdDecorators::connect(QObject* sender, const QByteArray& signal, P | |||
|
53 | 53 | } else { |
|
54 | 54 | signalTmp = "2" + signal; |
|
55 | 55 | } |
|
56 | ||
|
56 | ||
|
57 | 57 | if (sender) { |
|
58 | 58 | return PythonQt::self()->addSignalHandler(sender, signalTmp, callable); |
|
59 | 59 | } else { |
@@ -112,7 +112,7 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal | |||
|
112 | 112 | } else { |
|
113 | 113 | signalTmp = "2" + signal; |
|
114 | 114 | } |
|
115 | ||
|
115 | ||
|
116 | 116 | QByteArray slotTmp; |
|
117 | 117 | first = slot.at(0); |
|
118 | 118 | if (first>='0' && first<='9') { |
@@ -120,21 +120,12 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal | |||
|
120 | 120 | } else { |
|
121 | 121 | slotTmp = "1" + slot; |
|
122 | 122 | } |
|
123 | ||
|
123 | ||
|
124 | 124 | r = QObject::disconnect(sender, signalTmp, receiver, slotTmp); |
|
125 | 125 | } |
|
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 | } |
@@ -244,7 +235,7 QObject* PythonQtStdDecorators::findChild(QObject* parent, const char* typeName, | |||
|
244 | 235 | if (!name.isNull() && obj->objectName() != name) |
|
245 | 236 | continue; |
|
246 | 237 | |
|
247 |
if ((typeName && obj->inherits(typeName)) || |
|
|
238 | if ((typeName && obj->inherits(typeName)) || | |
|
248 | 239 | (meta && meta->cast(obj))) |
|
249 | 240 | return obj; |
|
250 | 241 | } |
@@ -274,7 +265,7 int PythonQtStdDecorators::findChildren(QObject* parent, const char* typeName, c | |||
|
274 | 265 | if (!name.isNull() && obj->objectName() != name) |
|
275 | 266 | continue; |
|
276 | 267 | |
|
277 |
if ((typeName && obj->inherits(typeName)) || |
|
|
268 | if ((typeName && obj->inherits(typeName)) || | |
|
278 | 269 | (meta && meta->cast(obj))) { |
|
279 | 270 | list += obj; |
|
280 | 271 | } |
@@ -301,7 +292,7 int PythonQtStdDecorators::findChildren(QObject* parent, const char* typeName, c | |||
|
301 | 292 | if (regExp.indexIn(obj->objectName()) == -1) |
|
302 | 293 | continue; |
|
303 | 294 | |
|
304 |
if ((typeName && obj->inherits(typeName)) || |
|
|
295 | if ((typeName && obj->inherits(typeName)) || | |
|
305 | 296 | (meta && meta->cast(obj))) { |
|
306 | 297 | list += obj; |
|
307 | 298 | } |
@@ -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 | |
@@ -74,19 +69,19 public slots: | |||
|
74 | 69 | QObject* findChild(QObject* parent, PyObject* type, const QString& name = QString()); |
|
75 | 70 | QList<QObject*> findChildren(QObject* parent, PyObject* type, const QString& name= QString()); |
|
76 | 71 | QList<QObject*> findChildren(QObject* parent, PyObject* type, const QRegExp& regExp); |
|
77 | ||
|
72 | ||
|
78 | 73 | bool setProperty(QObject* o, const char* name, const QVariant& value); |
|
79 | 74 | QVariant property(QObject* o, const char* name); |
|
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); } |
@@ -98,7 +93,7 public slots: | |||
|
98 | 93 | void static_Qt_qsrand(uint a) { qsrand(a); } |
|
99 | 94 | |
|
100 | 95 | QString tr(QObject* obj, const QByteArray& text, const QByteArray& ambig = QByteArray(), int n = -1); |
|
101 | ||
|
96 | ||
|
102 | 97 | QByteArray static_Qt_SIGNAL(const QByteArray& s) { return QByteArray("2") + s; } |
|
103 | 98 | QByteArray static_Qt_SLOT(const QByteArray& s) { return QByteArray("1") + s; } |
|
104 | 99 |
General Comments 0
You need to be logged in to leave comments.
Login now