diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dfed026..fd06c186 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,35 +5,109 @@ # If you are not a CMake expert, you should better use the provided qmake profiles. #----------------------------------------------------------------------------- -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 2.8.12) #----------------------------------------------------------------------------- project(PythonQt) #----------------------------------------------------------------------------- -include(CTestUseLaunchers OPTIONAL) +#---------------------------------------------------------------------------- +# Qt version + +# Sanity checks +if(DEFINED Qt5_DIR AND DEFINED QT_QMAKE_EXECUTABLE) + message(FATAL_ERROR + "${PROJECT_NAME} shoult NOT be configured setting both Qt5_DIR and QT_QMAKE_EXECUTABLE options. +To build with Qt4, specify QT_QMAKE_EXECUTABLE. To build with Qt5, specify Qt5_DIR.") +endif() + +# Set PythonQt_QT_VERSION +if(DEFINED Qt5_DIR) + message(STATUS "${PROJECT_NAME}: Setting PythonQt_QT_VERSION to 5 because Qt5_DIR is defined.") + set(PythonQt_QT_VERSION 5) +elseif(DEFINED QT_QMAKE_EXECUTABLE) + message(STATUS "${PROJECT_NAME}: Setting PythonQt_QT_VERSION to 4 because QT_QMAKE_EXECUTABLE is defined.") + set(PythonQt_QT_VERSION 4) +else() + set(PythonQt_QT_VERSION 4 CACHE STRING "Pick a version of Qt to use: 4 or 5") + # Set the possible values of Qt version for cmake-gui + set_property(CACHE PythonQt_QT_VERSION PROPERTY STRINGS "4" "5") +endif() + +# Requirements +set(minimum_required_qt5_version "5.3.0") +set(minimum_required_qt4_version "4.6.2") +set(minimum_required_qt_version ${minimum_required_qt${PythonQt_QT_VERSION}_version}) + +# Qt components +set(qt5libs Core Widgets Network OpenGL Sql Svg UiTools WebKitWidgets Xml XmlPatterns) +set(qt4libs core gui network opengl sql svg uitools webkit xml xmlpatterns) +set(qtlibs ${qt${PythonQt_QT_VERSION}libs}) #----------------------------------------------------------------------------- # Python libraries find_package(PythonLibs REQUIRED) include_directories("${PYTHON_INCLUDE_DIR}") -add_definitions(-DPYTHONQT_USE_RELEASE_PYTHON_FALLBACK) +add_definitions( + -DPYTHONQT_USE_RELEASE_PYTHON_FALLBACK + -DPYTHONQT_SUPPORT_NAME_PROPERTY + ) #----------------------------------------------------------------------------- # Build options +if(NOT DEFINED PythonQt_INSTALL_RUNTIME_DIR) + set(PythonQt_INSTALL_RUNTIME_DIR bin) +endif() + +if(NOT DEFINED PythonQt_INSTALL_LIBRARY_DIR) + set(PythonQt_INSTALL_LIBRARY_DIR lib${LIB_SUFFIX}) +endif() + +if(NOT DEFINED PythonQt_INSTALL_ARCHIVE_DIR) + set(PythonQt_INSTALL_ARCHIVE_DIR lib${LIB_SUFFIX}) +endif() + +if(NOT DEFINED PythonQt_INSTALL_INCLUDE_DIR) + set(PythonQt_INSTALL_INCLUDE_DIR include/PythonQt) +endif() + +# Since the Qt bindings sources used for both Qt4 and Qt5 are +# grouped using Qt4 naming convention, qt_wrapped_libs variables are the +# same for the two Qt versions. +set(qt4_wrapped_libs ${qt4libs}) +set(qt5_wrapped_libs ${qt4libs}) +set(qt_wrapped_libs ${qt${PythonQt_QT_VERSION}_wrapped_libs}) + +set(qt5_wrapped_lib_depends_gui Multimedia) + +set(qtlib_to_wraplib_Widgets gui) +set(qtlib_to_wraplib_WebKitWidgets webkit) + +# Define PythonQt_Wrap_Qt* options option(PythonQt_Wrap_QtAll "Make all Qt components available in python" OFF) +foreach(qtlib ${qt_wrapped_libs}) + OPTION(PythonQt_Wrap_Qt${qtlib} "Make all of Qt${qtlib} available in python" OFF) +endforeach() -set(qtlibs core gui network opengl sql svg uitools webkit xml xmlpatterns) +# Set qtlib_to_wraplib_* variables foreach(qtlib ${qtlibs}) - OPTION(PythonQt_Wrap_Qt${qtlib} "Make all of Qt${qtlib} available in python" OFF) + string(TOLOWER ${qtlib} qtlib_lowercase) + if(DEFINED qtlib_to_wraplib_${qtlib}) + set(qtlib_lowercase ${qtlib_to_wraplib_${qtlib}}) + endif() + set(qtlib_to_wraplib_${qtlib} ${qtlib_lowercase}) endforeach() # Force option if it applies if(PythonQt_Wrap_QtAll) - list(REMOVE_ITEM qtlibs xmlpatterns) # xmlpatterns wrapper does *NOT* build at all :( - foreach(qtlib ${qtlibs}) + set(_qt_wrapped_libs ${qt_wrapped_libs}) + + # XXX xmlpatterns wrapper does *NOT* build at all :( + list(REMOVE_ITEM _qt_wrapped_libs xmlpatterns) + + foreach(qtlib ${_qt_wrapped_libs}) if(NOT ${PythonQt_Wrap_Qt${qtlib}}) set(PythonQt_Wrap_Qt${qtlib} ON CACHE BOOL "Make all of Qt${qtlib} available in python" FORCE) message(STATUS "Enabling [PythonQt_Wrap_Qt${qtlib}] because of [PythonQt_Wrap_QtAll] evaluates to True") @@ -51,38 +125,94 @@ endif() #----------------------------------------------------------------------------- # Setup Qt -set(minimum_required_qt_version "4.6.2") +if(PythonQt_QT_VERSION VERSION_GREATER "4") -find_package(Qt4) + # Required components + set(qt_required_components Core Widgets) + foreach(qtlib ${qtlibs}) + set(qt_wrapped_lib ${qtlib_to_wraplib_${qtlib}}) + if(${PythonQt_Wrap_Qt${qt_wrapped_lib}}) + list(APPEND qt_required_components ${qtlib} ${qt${PythonQt_QT_VERSION}_wrapped_lib_depends_${qt_wrapped_lib}}) + endif() + endforeach() + if(BUILD_TESTING) + list(APPEND qt_required_components Test) + endif() + list(REMOVE_DUPLICATES qt_required_components) + + message(STATUS "${PROJECT_NAME}: Required Qt components [${qt_required_components}]") + find_package(Qt5 ${minimum_required_qt_version} COMPONENTS ${qt_required_components} REQUIRED) + + set(QT_LIBRARIES ) + foreach(qtlib ${qt_required_components}) + include_directories(${Qt5${qtlib}_INCLUDE_DIRS}) + add_definitions(${Qt5${qtlib}_DEFINITIONS}) + list(APPEND QT_LIBRARIES ${Qt5${qtlib}_LIBRARIES}) + endforeach() -if(QT4_FOUND) + include_directories(${Qt5Core_PRIVATE_INCLUDE_DIRS}) - set(found_qt_version ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}.${QT_VERSION_PATCH}) + set(QT_VERSION_MAJOR ${Qt5Core_VERSION_MAJOR}) + set(QT_VERSION_MINOR ${Qt5Core_VERSION_MINOR}) - if(${found_qt_version} VERSION_LESS ${minimum_required_qt_version}) + macro(pythonqt_wrap_cpp) + qt5_wrap_cpp(${ARGV}) + endmacro() + +else() + + find_package(Qt4) + + if(QT4_FOUND) + + set(found_qt_version ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}.${QT_VERSION_PATCH}) + + if(${found_qt_version} VERSION_LESS ${minimum_required_qt_version}) message(FATAL_ERROR "error: PythonQt requires Qt >= ${minimum_required_qt_version} -- you cannot use Qt ${found_qt_version}.") - endif() - - # Enable required qt module - foreach(qtlib network opengl sql svg uitools webkit xml xmlpatterns) - string(TOUPPER ${qtlib} qtlib_uppercase) - if (NOT ${QT_QT${qtlib_uppercase}_FOUND}) - message(FATAL_ERROR "QT_QT${${qtlib_uppercase} *not* FOUND - Try to disable PythonQt_Wrap_Qt${qtlib}") endif() - set(QT_USE_QT${qtlib_uppercase} ${PythonQt_Wrap_Qt${qtlib}}) - endforeach() - - include(${QT_USE_FILE}) -else() - message(FATAL_ERROR "error: Qt4 was not found on your system. You probably need to set the QT_QMAKE_EXECUTABLE variable") + + # Enable required qt module + foreach(qtlib ${qt_wrapped_libs}) + string(TOUPPER ${qtlib} qtlib_uppercase) + if (NOT ${QT_QT${qtlib_uppercase}_FOUND}) + message(FATAL_ERROR "QT_QT${qtlib_uppercase} *not* FOUND - Try to disable PythonQt_Wrap_Qt${qtlib}") + endif() + set(QT_USE_QT${qtlib_uppercase} ${PythonQt_Wrap_Qt${qtlib}}) + endforeach() + + # Enable QtTest in Qt4 is the option BUILD_TESTING was activated + set(QT_USE_QTTEST ${BUILD_TESTING}) + + include(${QT_USE_FILE}) + else() + message(FATAL_ERROR "error: Qt4 was not found on your system. You probably need to set the QT_QMAKE_EXECUTABLE variable") + endif() + + macro(pythonqt_wrap_cpp) + qt4_wrap_cpp(${ARGV}) + endmacro() + endif() +if(UNIX) + find_package(OpenGL) + if(OPENGL_FOUND) + list(APPEND QT_LIBRARIES ${OPENGL_LIBRARIES}) + endif() +endif() #----------------------------------------------------------------------------- -# The variable "generated_cpp_suffix" allows to conditionnally compile the generated wrappers +# The variable "generated_cpp_suffix" allows to conditionnally compile the generated wrappers # associated with the Qt version being used. + +set(generated_cpp_suffix_46 _47) +set(generated_cpp_suffix_52 _50) +set(generated_cpp_suffix_51 _50) + set(generated_cpp_suffix "_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}") -if("${generated_cpp_suffix}" STREQUAL "_46") - set(generated_cpp_suffix "_47") # Also use 4.7 wrappers for 4.6.x version +if(DEFINED generated_cpp_suffix_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}) + set(generated_cpp_suffix "${generated_cpp_suffix_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}}") +elseif(${QT_VERSION_MAJOR}.${QT_VERSION_MINOR} VERSION_GREATER "5.4") + set(generated_cpp_suffix "_54") endif() #----------------------------------------------------------------------------- @@ -106,8 +236,10 @@ set(sources src/PythonQtStdDecorators.cpp src/PythonQtStdIn.cpp src/PythonQtStdOut.cpp + src/PythonQtProperty.cpp + src/PythonQtSlotDecorator.cpp src/gui/PythonQtScriptingConsole.cpp - + generated_cpp${generated_cpp_suffix}/PythonQt_QtBindings.cpp generated_cpp${generated_cpp_suffix}/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin0.cpp @@ -141,8 +273,11 @@ set(headers src/PythonQtStdIn.h src/PythonQtStdOut.h src/PythonQtSystem.h + src/PythonQtUtils.h src/PythonQtVariants.h src/PythonQtPythonInclude.h + src/PythonQtProperty.h + src/PythonQtSlotDecorator.cpp generated_cpp${generated_cpp_suffix}/PythonQt_QtBindings.h ) @@ -161,46 +296,36 @@ set(moc_sources #----------------------------------------------------------------------------- # Add extra sources -foreach(qtlib core gui network opengl sql svg uitools webkit xml xmlpatterns) - +foreach(qtlib ${qt_wrapped_libs}) + if (${PythonQt_Wrap_Qt${qtlib}}) - + ADD_DEFINITIONS(-DPYTHONQT_WRAP_Qt${qtlib}) - + set(file_prefix generated_cpp${generated_cpp_suffix}/com_trolltech_qt_${qtlib}/com_trolltech_qt_${qtlib}) - - foreach(index RANGE 0 11) - + + foreach(index RANGE 0 12) + # Source files if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file_prefix}${index}.cpp) list(APPEND sources ${file_prefix}${index}.cpp) endif() - + # Headers that should run through moc if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file_prefix}${index}.h) list(APPEND moc_sources ${file_prefix}${index}.h) endif() - + endforeach() - + list(APPEND sources ${file_prefix}_init.cpp) endif() endforeach() -#----------------------------------------------------------------------------- -# UI files -set(ui_sources ) - -#----------------------------------------------------------------------------- -# Resources -set(qrc_sources ) - #----------------------------------------------------------------------------- # Do wrapping -qt4_wrap_cpp(gen_moc_sources ${moc_sources}) -qt4_wrap_ui(gen_ui_sources ${ui_sources}) -qt4_add_resources(gen_qrc_sources ${qrc_sources}) +pythonqt_wrap_cpp(gen_moc_sources ${moc_sources}) #----------------------------------------------------------------------------- # Build the library @@ -208,12 +333,10 @@ qt4_add_resources(gen_qrc_sources ${qrc_sources}) include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/src ) - + add_library(PythonQt SHARED ${sources} ${gen_moc_sources} - ${gen_ui_sources} - ${gen_qrc_sources} ) set_target_properties(PythonQt PROPERTIES DEFINE_SYMBOL PYTHONQT_EXPORTS) @@ -225,6 +348,10 @@ set_target_properties(PythonQt PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib" ) +target_compile_options(PythonQt PRIVATE + $<$:/bigobj> + ) + target_link_libraries(PythonQt ${PYTHON_LIBRARY} ${QT_LIBRARIES} @@ -234,7 +361,53 @@ target_link_libraries(PythonQt # Install library (on windows, put the dll in 'bin' and the archive in 'lib') install(TARGETS PythonQt - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib) -install(FILES ${headers} DESTINATION include/PythonQt) + RUNTIME DESTINATION ${PythonQt_INSTALL_RUNTIME_DIR} + LIBRARY DESTINATION ${PythonQt_INSTALL_LIBRARY_DIR} + ARCHIVE DESTINATION ${PythonQt_INSTALL_ARCHIVE_DIR}) +install(FILES ${headers} DESTINATION ${PythonQt_INSTALL_INCLUDE_DIR}) + +#----------------------------------------------------------------------------- +# Testing + +option(BUILD_TESTING "Build the testing tree." OFF) +include(CTest) + +if(BUILD_TESTING) + create_test_sourcelist(test_sources PythonQtCppTests.cpp + tests/PythonQtTestMain.cpp + ) + + set_property(SOURCE tests/PythonQtTestMain.cpp PROPERTY COMPILE_DEFINITIONS "main=tests_PythonQtTestMain") + + list(APPEND test_sources + tests/PythonQtTests.cpp + tests/PythonQtTests.h + ) + + pythonqt_wrap_cpp(test_sources + tests/PythonQtTests.h + ) + + if(PythonQt_Wrap_Qtcore) + include_directories(generated_cpp${generated_cpp_suffix}) + + list(APPEND test_sources + tests/PythonQtTestCleanup.cpp + tests/PythonQtTestCleanup.h + ) + pythonqt_wrap_cpp(test_sources + tests/PythonQtTestCleanup.h + ) + + set_property(SOURCE tests/PythonQtTestMain.cpp APPEND PROPERTY COMPILE_DEFINITIONS "PythonQt_Wrap_Qtcore") + endif() + + add_executable(PythonQtCppTests ${test_sources}) + target_link_libraries(PythonQtCppTests PythonQt) + + add_test( + NAME tests_PythonQtTestMain + COMMAND ${Slicer_LAUNCH_COMMAND} $ tests/PythonQtTestMain + ) +endif() + diff --git a/README.md b/README.md new file mode 100644 index 00000000..1750ded5 --- /dev/null +++ b/README.md @@ -0,0 +1,175 @@ +PythonQt +======== + +Overview +-------- + +PythonQt is a dynamic [Python](http://www.python.org) binding for [Qt](http://qt.nokia.com). +It offers an easy way to embed the Python scripting language into +your Qt applications. It makes heavy use of the QMetaObject system and thus requires Qt4.x. + +This project is a fork of the [official PythonQt](http://pythonqt.sourceforge.net/) repository +hosted on sourceforge. + +It serves as *staging area* to contain patches that will then be contributed back to the +official repository. + +Prerequisites +------------- + +* CMake 2.8.12 +* Qt 4.6.2 or above + +Build instructions +------------------ + +By default, the `patched-7` version will be checked out. + +``` +git clone git://github.com/commontk/PythonQt.git +mkdir PythonQt-build +cd PythonQt-build +cmake -DQT_QMAKE_EXECUTABLE:FILEPATH=/path/to/qmake ../PythonQt +make +``` + +Additional configure options are: + +* `CMAKE_BUILD_TYPE`: Debug, Release, RelWithDebInfo or MinSizeRel +* `PythonQt_DEBUG`: Enable/Disable PythonQt debug output +* `PythonQt_Wrap_QtAll`: Make all Qt components available in python +* `PythonQt_Wrap_Qt`: Build PythonQt wrapper associated with ``. Possible `` are `gui`, `network`, `opengl`, `sql`, `uitools`, `webkit`, `xml`, `xmlpatterns`. + +Available branches +------------------ + +This repository contains 9 branches: + +### patched-9 +* Based on patched-8 +* List of features: + * Add MSVC 2017 support + * Add Qt 5.8 and Qt 5.9 support + +### patched-8 +* Based on [r455](http://sourceforge.net/p/pythonqt/code/455/) with: + * revert of [r444](http://sourceforge.net/p/pythonqt/code/444/) + * all changes from ``patched-7`` cherry-picked. + +### patched-7 +* Based on [r443](http://sourceforge.net/p/pythonqt/code/443/) with: + * partial revert of [r431](http://sourceforge.net/p/pythonqt/code/431/) to re-enable CMake support + * all changes from ``patched-6`` cherry-picked. + +### patched-6 +* Based on patched-5 + [r403](http://sourceforge.net/p/pythonqt/code/403/) +* List of bug fixes: + * Fix for memory leaks and cleanup crash +* Includes the following PythonQt updates: +``` +$ git shortlog 2d445d5..e93e36b --no-merges +florianlink (8): + fixed error handling for evalFile made name->objectName alias optional (off by default, add PYTHONQT_SUPPORT_NAME_PROPERTY to DEFINES if you need it) added py_delete() slot support for built-in delete() method + added support for QTimer::singleShot() + fixed a missign QMetaObject::disconnect which leads to connection leaking added removeSignalHandlers() + fixed test + initial version that handles qualified virtual calls better + improved handling of qualified virtual calls + improved handling of qualified virtual calls + removed generating wrappers for virtual functions that are already declared in a base class +``` + +### patched-5 +* Based on patched-4 + [r403](http://sourceforge.net/p/pythonqt/code/403/) excluding commit [r397](http://sourceforge.net/p/pythonqt/code/397/) +* List of bug fixes: + * Fix for memory leaks and cleanup crash +* List of features: + * CMake: + * Fix install rules + * Fix "_invalid_parameter_noinfo_noreturn" link error + * PythonQt: + * Add Qt5 support + * Add PY3K support + +### patched-4 +* Based on patched-3 + [r245](http://sourceforge.net/p/pythonqt/code/245/) +* List of features: + * Add BUILD_TESTING option disabled by default to keep behavior consistent with previous version. + * Do not exclude enums from wrapping if they are QFlags. + * Ensure enums added using only Q_FLAGS without corresponding Q_ENUMS are wrapped. + +### patched-3 +* Backported: + * Most of the [change specific to](https://github.com/commontk/PythonQt/compare/e2dce4b...patched-2) `patched-2` branch have been backported upstream: [r241](http://sourceforge.net/p/pythonqt/code/241/), [r242](http://sourceforge.net/p/pythonqt/code/242/), [r243](http://sourceforge.net/p/pythonqt/code/243/) + +### patched-2 + +* Based on [r228](http://sourceforge.net/p/pythonqt/code/228/) +* List of features: + * At configuration time, detect the Qt version used and seamlessly compile the appropriate wrappers (Qt 4.8, 4.7 or 4.6). + * Add method allowing to know if a python error occurred: [5935f29](https://github.com/commontk/PythonQt/commit/5935f29978deed892a13ddef02cb14c205c6124d) + * Also add associated method "resetErrorFlag": [a386dc60](https://github.com/commontk/PythonQt/commit/a386dc60f71c15e67c611bc31b26cee756ed833a) + * Fix compilation issue on VS2010 when PythonQt Debug build against python Release: [7e1e07f](https://github.com/commontk/PythonQt/commit/7e1e07f34b2420e420e2858e5ea9a49fe1e0d235) + * Add option Add PythonQt_Wrap_QtAll: [97df3b0](https://github.com/commontk/PythonQt/commit/97df3b0845b3f5c987d3141a9e651436882f5913) and [9104fa9](https://github.com/commontk/PythonQt/commit/9104fa924859f4a865016f2138c06ec856f449d4) + * Ensure all 4.8 generated wrappers are considered: [654f324](https://github.com/commontk/PythonQt/commit/654f3249d1cf3f3ff674b2ff6cca7a2ef3517f60) + * Update "PythonQtPythonInclude.h" to avoid build error on recent MacOSX: [7b8ee130](https://github.com/commontk/PythonQt/commit/7b8ee13058bc0b366983ce8228612e75f8dd9ca8) and [47738f9c](https://github.com/commontk/PythonQt/commit/47738f9c8c5d3ffa77c8f2e1844f899e5b548f0c) + * Update "PythonQtPythonInclude.h" to fix windows build issue when PythonQt Debug build against python Release[6366f00](https://github.com/commontk/PythonQt/commit/6366f002a93aa238c55f58de949d09c552cda5a9) + * Optionally include CTestUseLaunchers: [211440](https://github.com/commontk/PythonQt/commit/2114405a47836b3fb16a3f66fec6a02184f32e71) + * Add SystemExit exception handler. If enabled, the signal "systemExitExceptionRaised" will be emitted. It gives application the opportunity to cleanup and terminate nicely: [3c84463d](https://github.com/commontk/PythonQt/commit/3c84463d3fc4a99c94207c1116ba33d7a412a95f) + * Add "isatty" function to StdOutRedirect. Needed by some logging frame: [7132dba9](https://github.com/commontk/PythonQt/commit/7132dba93064c2a02591b42305fecdd5d59702d3) +* Backported: + * Most of the [change specific to](https://github.com/commontk/PythonQt/compare/svn-mirror...patched) `patched` branch have been backported upstream: [r200](http://sourceforge.net/p/pythonqt/code/200/), [r201](http://sourceforge.net/p/pythonqt/code/201/), [r202](http://sourceforge.net/p/pythonqt/code/202/), [r203](http://sourceforge.net/p/pythonqt/code/203/), [r204](http://sourceforge.net/p/pythonqt/code/204/) + * CMake option `PYTHONQT_USE_VTK` has been removed ([r205](http://sourceforge.net/p/pythonqt/code/205/)), the foreign wrapper mechanism should be used: [r206](http://sourceforge.net/p/pythonqt/code/206/) + +### patched + +* Based on [r193](http://sourceforge.net/p/pythonqt/code/193/) +* List of features: + * CMake'ified PythonQt project + * CMake'ified PythonQt/generator project + * Add `dPython.h` file, it provides the ability to link against release python with a debug build of your project. + * Option `PYTHONQT_USE_VTK` CMake option allowing to teach PythonQt how to deal with `vtkObject` + * Stdin can optionally be redirected to a custom callback + * [More details](https://github.com/commontk/PythonQt/compare/svn-mirror...patched) + +### svn-mirror + +* SVN history imported using `git-svn` + +Contributing +------------ + +Once you've made your great commits: + +1. [Fork][fk] PythonQt +2. Create a topic branch - `git checkout -b my_branch` +3. Push to your branch - `git push origin my_branch` +4. Create an [Issue][is] with a link to your branch +5. That's it! + + +Meta +---- + +* Code: `git clone git://github.com/commontk/PythonQt.git` +* Home: +* Bugs: + +License +------- + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +[fk]: http://help.github.com/forking/ +[is]: http://github.com/jcfr/qJobManager/issues + diff --git a/generated_cpp_50/PythonQt_QtBindings.cpp b/generated_cpp_50/PythonQt_QtBindings.cpp new file mode 100644 index 00000000..7ae1630a --- /dev/null +++ b/generated_cpp_50/PythonQt_QtBindings.cpp @@ -0,0 +1,58 @@ + +#include "PythonQt_QtBindings.h" + +#include "PythonQt.h" + +void PythonQt_init_QtGui(PyObject*); +void PythonQt_init_QtSvg(PyObject*); +void PythonQt_init_QtSql(PyObject*); +void PythonQt_init_QtNetwork(PyObject*); +void PythonQt_init_QtCore(PyObject*); +void PythonQt_init_QtWebKit(PyObject*); +void PythonQt_init_QtOpenGL(PyObject*); +void PythonQt_init_QtXml(PyObject*); +void PythonQt_init_QtXmlPatterns(PyObject*); +void PythonQt_init_QtUiTools(PyObject*); + +PYTHONQT_EXPORT void PythonQt_init_QtBindings() + { + #ifdef PYTHONQT_WRAP_Qtcore + PythonQt_init_QtCore(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtgui + PythonQt_init_QtGui(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtnetwork + PythonQt_init_QtNetwork(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtopengl + PythonQt_init_QtOpenGL(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtsql + PythonQt_init_QtSql(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtsvg + PythonQt_init_QtSvg(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtuitools + PythonQt_init_QtUiTools(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtwebkit + PythonQt_init_QtWebKit(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtxml + PythonQt_init_QtXml(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtxmlpatterns + PythonQt_init_QtXmlPatterns(0); + #endif + }; diff --git a/generated_cpp_50/PythonQt_QtBindings.h b/generated_cpp_50/PythonQt_QtBindings.h new file mode 100644 index 00000000..03e96aed --- /dev/null +++ b/generated_cpp_50/PythonQt_QtBindings.h @@ -0,0 +1,10 @@ +#ifndef _PYTHONQT_QTBINDINGS_H +#define _PYTHONQT_QTBINDINGS_H + +#include "PythonQtSystem.h" + +/// Initialize Qt bindings enabled at configuration time +PYTHONQT_EXPORT void PythonQt_init_QtBindings(); + +#endif + diff --git a/generated_cpp_53/PythonQt_QtBindings.cpp b/generated_cpp_53/PythonQt_QtBindings.cpp new file mode 100644 index 00000000..7ae1630a --- /dev/null +++ b/generated_cpp_53/PythonQt_QtBindings.cpp @@ -0,0 +1,58 @@ + +#include "PythonQt_QtBindings.h" + +#include "PythonQt.h" + +void PythonQt_init_QtGui(PyObject*); +void PythonQt_init_QtSvg(PyObject*); +void PythonQt_init_QtSql(PyObject*); +void PythonQt_init_QtNetwork(PyObject*); +void PythonQt_init_QtCore(PyObject*); +void PythonQt_init_QtWebKit(PyObject*); +void PythonQt_init_QtOpenGL(PyObject*); +void PythonQt_init_QtXml(PyObject*); +void PythonQt_init_QtXmlPatterns(PyObject*); +void PythonQt_init_QtUiTools(PyObject*); + +PYTHONQT_EXPORT void PythonQt_init_QtBindings() + { + #ifdef PYTHONQT_WRAP_Qtcore + PythonQt_init_QtCore(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtgui + PythonQt_init_QtGui(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtnetwork + PythonQt_init_QtNetwork(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtopengl + PythonQt_init_QtOpenGL(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtsql + PythonQt_init_QtSql(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtsvg + PythonQt_init_QtSvg(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtuitools + PythonQt_init_QtUiTools(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtwebkit + PythonQt_init_QtWebKit(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtxml + PythonQt_init_QtXml(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtxmlpatterns + PythonQt_init_QtXmlPatterns(0); + #endif + }; diff --git a/generated_cpp_53/PythonQt_QtBindings.h b/generated_cpp_53/PythonQt_QtBindings.h new file mode 100644 index 00000000..03e96aed --- /dev/null +++ b/generated_cpp_53/PythonQt_QtBindings.h @@ -0,0 +1,10 @@ +#ifndef _PYTHONQT_QTBINDINGS_H +#define _PYTHONQT_QTBINDINGS_H + +#include "PythonQtSystem.h" + +/// Initialize Qt bindings enabled at configuration time +PYTHONQT_EXPORT void PythonQt_init_QtBindings(); + +#endif + diff --git a/generated_cpp_54/PythonQt_QtBindings.cpp b/generated_cpp_54/PythonQt_QtBindings.cpp new file mode 100644 index 00000000..7ae1630a --- /dev/null +++ b/generated_cpp_54/PythonQt_QtBindings.cpp @@ -0,0 +1,58 @@ + +#include "PythonQt_QtBindings.h" + +#include "PythonQt.h" + +void PythonQt_init_QtGui(PyObject*); +void PythonQt_init_QtSvg(PyObject*); +void PythonQt_init_QtSql(PyObject*); +void PythonQt_init_QtNetwork(PyObject*); +void PythonQt_init_QtCore(PyObject*); +void PythonQt_init_QtWebKit(PyObject*); +void PythonQt_init_QtOpenGL(PyObject*); +void PythonQt_init_QtXml(PyObject*); +void PythonQt_init_QtXmlPatterns(PyObject*); +void PythonQt_init_QtUiTools(PyObject*); + +PYTHONQT_EXPORT void PythonQt_init_QtBindings() + { + #ifdef PYTHONQT_WRAP_Qtcore + PythonQt_init_QtCore(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtgui + PythonQt_init_QtGui(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtnetwork + PythonQt_init_QtNetwork(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtopengl + PythonQt_init_QtOpenGL(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtsql + PythonQt_init_QtSql(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtsvg + PythonQt_init_QtSvg(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtuitools + PythonQt_init_QtUiTools(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtwebkit + PythonQt_init_QtWebKit(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtxml + PythonQt_init_QtXml(0); + #endif + + #ifdef PYTHONQT_WRAP_Qtxmlpatterns + PythonQt_init_QtXmlPatterns(0); + #endif + }; diff --git a/generated_cpp_54/PythonQt_QtBindings.h b/generated_cpp_54/PythonQt_QtBindings.h new file mode 100644 index 00000000..03e96aed --- /dev/null +++ b/generated_cpp_54/PythonQt_QtBindings.h @@ -0,0 +1,10 @@ +#ifndef _PYTHONQT_QTBINDINGS_H +#define _PYTHONQT_QTBINDINGS_H + +#include "PythonQtSystem.h" + +/// Initialize Qt bindings enabled at configuration time +PYTHONQT_EXPORT void PythonQt_init_QtBindings(); + +#endif + diff --git a/generated_cpp_54/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin0.h b/generated_cpp_54/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin0.h index 01968e1e..d85e7e9d 100644 --- a/generated_cpp_54/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin0.h +++ b/generated_cpp_54/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin0.h @@ -1264,7 +1264,11 @@ enum WindowModality{ enum WindowState{ WindowNoState = Qt::WindowNoState, WindowMinimized = Qt::WindowMinimized, WindowMaximized = Qt::WindowMaximized, WindowFullScreen = Qt::WindowFullScreen, WindowActive = Qt::WindowActive}; enum WindowType{ - Widget = Qt::Widget, Window = Qt::Window, Dialog = Qt::Dialog, Sheet = Qt::Sheet, Drawer = Qt::Drawer, Popup = Qt::Popup, Tool = Qt::Tool, ToolTip = Qt::ToolTip, SplashScreen = Qt::SplashScreen, Desktop = Qt::Desktop, SubWindow = Qt::SubWindow, ForeignWindow = Qt::ForeignWindow, CoverWindow = Qt::CoverWindow, WindowType_Mask = Qt::WindowType_Mask, MSWindowsFixedSizeDialogHint = Qt::MSWindowsFixedSizeDialogHint, MSWindowsOwnDC = Qt::MSWindowsOwnDC, BypassWindowManagerHint = Qt::BypassWindowManagerHint, X11BypassWindowManagerHint = Qt::X11BypassWindowManagerHint, FramelessWindowHint = Qt::FramelessWindowHint, WindowTitleHint = Qt::WindowTitleHint, WindowSystemMenuHint = Qt::WindowSystemMenuHint, WindowMinimizeButtonHint = Qt::WindowMinimizeButtonHint, WindowMaximizeButtonHint = Qt::WindowMaximizeButtonHint, WindowMinMaxButtonsHint = Qt::WindowMinMaxButtonsHint, WindowContextHelpButtonHint = Qt::WindowContextHelpButtonHint, WindowShadeButtonHint = Qt::WindowShadeButtonHint, WindowStaysOnTopHint = Qt::WindowStaysOnTopHint, WindowTransparentForInput = Qt::WindowTransparentForInput, WindowOverridesSystemGestures = Qt::WindowOverridesSystemGestures, WindowDoesNotAcceptFocus = Qt::WindowDoesNotAcceptFocus, CustomizeWindowHint = Qt::CustomizeWindowHint, WindowStaysOnBottomHint = Qt::WindowStaysOnBottomHint, WindowCloseButtonHint = Qt::WindowCloseButtonHint, MacWindowToolBarButtonHint = Qt::MacWindowToolBarButtonHint, BypassGraphicsProxyWidget = Qt::BypassGraphicsProxyWidget, WindowOkButtonHint = Qt::WindowOkButtonHint, WindowCancelButtonHint = Qt::WindowCancelButtonHint, NoDropShadowWindowHint = Qt::NoDropShadowWindowHint, WindowFullscreenButtonHint = Qt::WindowFullscreenButtonHint}; + Widget = Qt::Widget, Window = Qt::Window, Dialog = Qt::Dialog, Sheet = Qt::Sheet, Drawer = Qt::Drawer, Popup = Qt::Popup, Tool = Qt::Tool, ToolTip = Qt::ToolTip, SplashScreen = Qt::SplashScreen, Desktop = Qt::Desktop, SubWindow = Qt::SubWindow, ForeignWindow = Qt::ForeignWindow, CoverWindow = Qt::CoverWindow, WindowType_Mask = Qt::WindowType_Mask, MSWindowsFixedSizeDialogHint = Qt::MSWindowsFixedSizeDialogHint, MSWindowsOwnDC = Qt::MSWindowsOwnDC, BypassWindowManagerHint = Qt::BypassWindowManagerHint, X11BypassWindowManagerHint = Qt::X11BypassWindowManagerHint, FramelessWindowHint = Qt::FramelessWindowHint, WindowTitleHint = Qt::WindowTitleHint, WindowSystemMenuHint = Qt::WindowSystemMenuHint, WindowMinimizeButtonHint = Qt::WindowMinimizeButtonHint, WindowMaximizeButtonHint = Qt::WindowMaximizeButtonHint, WindowMinMaxButtonsHint = Qt::WindowMinMaxButtonsHint, WindowContextHelpButtonHint = Qt::WindowContextHelpButtonHint, WindowShadeButtonHint = Qt::WindowShadeButtonHint, WindowStaysOnTopHint = Qt::WindowStaysOnTopHint, WindowTransparentForInput = Qt::WindowTransparentForInput, WindowOverridesSystemGestures = Qt::WindowOverridesSystemGestures, WindowDoesNotAcceptFocus = Qt::WindowDoesNotAcceptFocus, CustomizeWindowHint = Qt::CustomizeWindowHint, WindowStaysOnBottomHint = Qt::WindowStaysOnBottomHint, WindowCloseButtonHint = Qt::WindowCloseButtonHint, MacWindowToolBarButtonHint = Qt::MacWindowToolBarButtonHint, BypassGraphicsProxyWidget = Qt::BypassGraphicsProxyWidget, NoDropShadowWindowHint = Qt::NoDropShadowWindowHint, WindowFullscreenButtonHint = Qt::WindowFullscreenButtonHint +#if QT_VERSION < 0x50800 + , WindowOkButtonHint = Qt::WindowOkButtonHint, WindowCancelButtonHint = Qt::WindowCancelButtonHint +#endif +}; Q_DECLARE_FLAGS(Alignment, AlignmentFlag) Q_DECLARE_FLAGS(DockWidgetAreas, DockWidgetArea) Q_DECLARE_FLAGS(DropActions, DropAction) diff --git a/generated_cpp_56/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin0.h b/generated_cpp_56/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin0.h index 66750cf3..015ed67f 100644 --- a/generated_cpp_56/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin0.h +++ b/generated_cpp_56/com_trolltech_qt_core_builtin/com_trolltech_qt_core_builtin0.h @@ -1272,7 +1272,7 @@ enum WindowModality{ enum WindowState{ WindowNoState = Qt::WindowNoState, WindowMinimized = Qt::WindowMinimized, WindowMaximized = Qt::WindowMaximized, WindowFullScreen = Qt::WindowFullScreen, WindowActive = Qt::WindowActive}; enum WindowType{ - Widget = Qt::Widget, Window = Qt::Window, Dialog = Qt::Dialog, Sheet = Qt::Sheet, Drawer = Qt::Drawer, Popup = Qt::Popup, Tool = Qt::Tool, ToolTip = Qt::ToolTip, SplashScreen = Qt::SplashScreen, Desktop = Qt::Desktop, SubWindow = Qt::SubWindow, ForeignWindow = Qt::ForeignWindow, CoverWindow = Qt::CoverWindow, WindowType_Mask = Qt::WindowType_Mask, MSWindowsFixedSizeDialogHint = Qt::MSWindowsFixedSizeDialogHint, MSWindowsOwnDC = Qt::MSWindowsOwnDC, BypassWindowManagerHint = Qt::BypassWindowManagerHint, X11BypassWindowManagerHint = Qt::X11BypassWindowManagerHint, FramelessWindowHint = Qt::FramelessWindowHint, WindowTitleHint = Qt::WindowTitleHint, WindowSystemMenuHint = Qt::WindowSystemMenuHint, WindowMinimizeButtonHint = Qt::WindowMinimizeButtonHint, WindowMaximizeButtonHint = Qt::WindowMaximizeButtonHint, WindowMinMaxButtonsHint = Qt::WindowMinMaxButtonsHint, WindowContextHelpButtonHint = Qt::WindowContextHelpButtonHint, WindowShadeButtonHint = Qt::WindowShadeButtonHint, WindowStaysOnTopHint = Qt::WindowStaysOnTopHint, WindowTransparentForInput = Qt::WindowTransparentForInput, WindowOverridesSystemGestures = Qt::WindowOverridesSystemGestures, WindowDoesNotAcceptFocus = Qt::WindowDoesNotAcceptFocus, MaximizeUsingFullscreenGeometryHint = Qt::MaximizeUsingFullscreenGeometryHint, CustomizeWindowHint = Qt::CustomizeWindowHint, WindowStaysOnBottomHint = Qt::WindowStaysOnBottomHint, WindowCloseButtonHint = Qt::WindowCloseButtonHint, MacWindowToolBarButtonHint = Qt::MacWindowToolBarButtonHint, BypassGraphicsProxyWidget = Qt::BypassGraphicsProxyWidget, NoDropShadowWindowHint = Qt::NoDropShadowWindowHint, WindowFullscreenButtonHint = Qt::WindowFullscreenButtonHint}; + Widget = Qt::Widget, Window = Qt::Window, Dialog = Qt::Dialog, Sheet = Qt::Sheet, Drawer = Qt::Drawer, Popup = Qt::Popup, Tool = Qt::Tool, ToolTip = Qt::ToolTip, SplashScreen = Qt::SplashScreen, Desktop = Qt::Desktop, SubWindow = Qt::SubWindow, ForeignWindow = Qt::ForeignWindow, CoverWindow = Qt::CoverWindow, WindowType_Mask = Qt::WindowType_Mask, MSWindowsFixedSizeDialogHint = Qt::MSWindowsFixedSizeDialogHint, MSWindowsOwnDC = Qt::MSWindowsOwnDC, BypassWindowManagerHint = Qt::BypassWindowManagerHint, X11BypassWindowManagerHint = Qt::X11BypassWindowManagerHint, FramelessWindowHint = Qt::FramelessWindowHint, WindowTitleHint = Qt::WindowTitleHint, WindowSystemMenuHint = Qt::WindowSystemMenuHint, WindowMinimizeButtonHint = Qt::WindowMinimizeButtonHint, WindowMaximizeButtonHint = Qt::WindowMaximizeButtonHint, WindowMinMaxButtonsHint = Qt::WindowMinMaxButtonsHint, WindowContextHelpButtonHint = Qt::WindowContextHelpButtonHint, WindowShadeButtonHint = Qt::WindowShadeButtonHint, WindowStaysOnTopHint = Qt::WindowStaysOnTopHint, WindowTransparentForInput = Qt::WindowTransparentForInput, WindowOverridesSystemGestures = Qt::WindowOverridesSystemGestures, WindowDoesNotAcceptFocus = Qt::WindowDoesNotAcceptFocus, MaximizeUsingFullscreenGeometryHint = Qt::MaximizeUsingFullscreenGeometryHint, CustomizeWindowHint = Qt::CustomizeWindowHint, WindowStaysOnBottomHint = Qt::WindowStaysOnBottomHint, WindowCloseButtonHint = Qt::WindowCloseButtonHint, MacWindowToolBarButtonHint = Qt::MacWindowToolBarButtonHint, BypassGraphicsProxyWidget = Qt::BypassGraphicsProxyWidget, NoDropShadowWindowHint = Qt::NoDropShadowWindowHint, WindowFullscreenButtonHint = Qt::WindowFullscreenButtonHint, WindowOkButtonHint = Qt::WindowOkButtonHint, WindowCancelButtonHint = Qt::WindowCancelButtonHint}; Q_DECLARE_FLAGS(Alignment, AlignmentFlag) Q_DECLARE_FLAGS(DockWidgetAreas, DockWidgetArea) Q_DECLARE_FLAGS(DropActions, DropAction) diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index fa09e0d3..7b0020d7 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -274,6 +274,10 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) void PythonQt::cleanup() { if (_self) { + // Remove signal handlers in advance, since destroying them calls back into + // PythonQt::priv()->removeSignalEmitter() + _self->removeSignalHandlers(); + delete _self; _self = NULL; } @@ -695,6 +699,7 @@ PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtCla PyObject* className = PyString_FromString(pythonClassName.constData()); PyObject* baseClasses = PyTuple_New(1); + Py_INCREF(&PythonQtInstanceWrapper_Type); PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type); PyObject* typeDict = PyDict_New(); @@ -708,6 +713,7 @@ PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtCla // create the new type object by calling the type result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL); + Py_DECREF(moduleName); Py_DECREF(baseClasses); Py_DECREF(typeDict); Py_DECREF(args); @@ -730,6 +736,7 @@ PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, Py PyObject* className = PyString_FromString(enumName); PyObject* baseClasses = PyTuple_New(1); + Py_INCREF(&PyInt_Type); PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type); PyObject* module = PyObject_GetAttrString(parentObject, "__module__"); @@ -741,6 +748,7 @@ PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, Py // create the new int derived type object by calling the core type result = PyObject_Call((PyObject *)&PyType_Type, args, NULL); + Py_DECREF(module); Py_DECREF(baseClasses); Py_DECREF(typeDict); Py_DECREF(args); @@ -1329,6 +1337,10 @@ PythonQtPrivate::PythonQtPrivate() _hadError = false; _systemExitExceptionHandlerEnabled = false; _debugAPI = new PythonQtDebugAPI(this); + + PythonQtConv::global_valueStorage.init(); + PythonQtConv::global_ptrStorage.init(); + PythonQtConv::global_variantStorage.init(); } void PythonQtPrivate::setupSharedLibrarySuffixes() @@ -1366,6 +1378,10 @@ PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation() void PythonQtPrivate::addDecorators(QObject* o, int decoTypes) { + if (!o) + { + return; + } o->setParent(this); int numMethods = o->metaObject()->methodCount(); for (int i = 0; i < numMethods; i++) { @@ -1647,6 +1663,7 @@ void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQ #endif _p->_pythonQtModuleName = name; + Py_INCREF(&PythonQtBoolResult_Type); PyModule_AddObject(_p->pythonQtModule().object(), "BoolResult", (PyObject*)&PythonQtBoolResult_Type); PythonQtObjectPtr sys; sys.setNewRef(PyImport_ImportModule("sys")); @@ -1670,7 +1687,9 @@ void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQ Py_ssize_t old_size = PyTuple_Size(old_module_names); PyObject *module_names = PyTuple_New(old_size + 1); for (Py_ssize_t i = 0; i < old_size; i++) { - PyTuple_SetItem(module_names, i, PyTuple_GetItem(old_module_names, i)); + PyObject *item = PyTuple_GetItem(old_module_names, i); + Py_INCREF(item); + PyTuple_SetItem(module_names, i, item); } PyTuple_SetItem(module_names, old_size, PyString_FromString(name.constData())); PyModule_AddObject(sys.object(), "builtin_module_names", module_names); diff --git a/src/PythonQt.h b/src/PythonQt.h index 5a385936..9171011f 100644 --- a/src/PythonQt.h +++ b/src/PythonQt.h @@ -526,7 +526,7 @@ class PYTHONQT_EXPORT PythonQt : public QObject { //@{ //! get access to internal data (should not be used on the public API, but is used by some C functions) - static PythonQtPrivate* priv() { return _self->_p; } + static PythonQtPrivate* priv() { return _self ? _self->_p : NULL; } //! clear all NotFound entries on all class infos, to ensure that //! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded diff --git a/src/PythonQtClassInfo.cpp b/src/PythonQtClassInfo.cpp index a75d7644..d26453c8 100644 --- a/src/PythonQtClassInfo.cpp +++ b/src/PythonQtClassInfo.cpp @@ -273,9 +273,12 @@ bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* int enumCount = meta->enumeratorCount(); for (int i=0;ienumerator(i); - // we do not want flags, they will cause our values to appear two times - if (e.isFlag()) continue; - + if (_cachedMembers.contains(memberName)) { + #ifdef PYTHONQT_DEBUG + std::cout << "cached enum " << memberName << " on " << meta->className() << std::endl; + #endif + continue; + } for (int j=0; j < e.keyCount(); j++) { if (qstrcmp(e.key(j), memberName)==0) { PyObject* enumType = findEnumWrapper(e.name()); @@ -536,9 +539,6 @@ QStringList PythonQtClassInfo::memberList() for (int i = 0; ienumeratorCount(); i++) { QMetaEnum e = meta->enumerator(i); l << e.name(); - // we do not want flags, they will cause our values to appear two times - if (e.isFlag()) continue; - for (int j=0; j < e.keyCount(); j++) { l << QString(e.key(j)); } diff --git a/src/PythonQtInstanceWrapper.cpp b/src/PythonQtInstanceWrapper.cpp index 3fa19b21..8fd3d8b6 100644 --- a/src/PythonQtInstanceWrapper.cpp +++ b/src/PythonQtInstanceWrapper.cpp @@ -119,7 +119,9 @@ static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, static void PythonQtInstanceWrapper_dealloc(PythonQtInstanceWrapper* self) { - PythonQtInstanceWrapper_deleteObject(self); + if (PythonQt::self()) { + PythonQtInstanceWrapper_deleteObject(self); + } self->_obj.~QPointer(); Py_TYPE(self)->tp_free((PyObject*)self); } diff --git a/src/PythonQtMisc.h b/src/PythonQtMisc.h index 2c75c456..65b58878 100644 --- a/src/PythonQtMisc.h +++ b/src/PythonQtMisc.h @@ -76,12 +76,25 @@ template class PythonQtValueStorage PythonQtValueStorage() { _chunkIdx = 0; _chunkOffset = 0; + _currentChunk = NULL; + }; + + //! initialize memory + void init() { + assert(_currentChunk == NULL); + assert(_chunks.isEmpty()); + _chunkIdx = 0; + _chunkOffset = 0; _currentChunk = new T[chunkEntries]; _chunks.append(_currentChunk); - }; + } //! clear all memory void clear() { + _chunkIdx = 0; + _chunkOffset = 0; + _currentChunk = NULL; + T* chunk; Q_FOREACH(chunk, _chunks) { delete[]chunk; diff --git a/src/PythonQtObjectPtr.cpp b/src/PythonQtObjectPtr.cpp index 95fb4e0f..2d79a5bb 100644 --- a/src/PythonQtObjectPtr.cpp +++ b/src/PythonQtObjectPtr.cpp @@ -49,7 +49,7 @@ PythonQtObjectPtr::PythonQtObjectPtr(PyObject* o) PythonQtObjectPtr::~PythonQtObjectPtr() { - if (_object) Py_DECREF(_object); + if (_object && Py_IsInitialized()) Py_DECREF(_object); } void PythonQtObjectPtr::setNewRef(PyObject* o) diff --git a/src/PythonQtPythonInclude.h b/src/PythonQtPythonInclude.h index 20d5ab8e..be8d0e00 100644 --- a/src/PythonQtPythonInclude.h +++ b/src/PythonQtPythonInclude.h @@ -60,7 +60,7 @@ // release Python DLL if it is available by undefining _DEBUG while // including Python.h #if defined(PYTHONQT_USE_RELEASE_PYTHON_FALLBACK) && defined(_DEBUG) -#undef _DEBUG +# define PYTHONQT_UNDEF_DEBUG // Include these low level headers before undefing _DEBUG. Otherwise when doing // a debug build against a release build of python the compiler will end up // including these low level headers without DEBUG enabled, causing it to try @@ -80,14 +80,17 @@ # include # include # include -#if defined(_MSC_VER) && _MSC_VER >= 1400 -#define _CRT_NOFORCE_MANIFEST 1 -#define _STL_NOFORCE_MANIFEST 1 +# undef _DEBUG +# if defined(_MSC_VER) && _MSC_VER >= 1400 +# define _CRT_NOFORCE_MANIFEST 1 +# define _STL_NOFORCE_MANIFEST 1 +# endif #endif + #include -#define _DEBUG -#else -#include + +#ifdef PYTHONQT_UNDEF_DEBUG +# define _DEBUG #endif // get Qt keywords back diff --git a/src/PythonQtSignalReceiver.cpp b/src/PythonQtSignalReceiver.cpp index fda77da9..54341657 100644 --- a/src/PythonQtSignalReceiver.cpp +++ b/src/PythonQtSignalReceiver.cpp @@ -177,7 +177,9 @@ PythonQtSignalReceiver::PythonQtSignalReceiver(QObject* obj):PythonQtSignalRecei PythonQtSignalReceiver::~PythonQtSignalReceiver() { - PythonQt::priv()->removeSignalEmitter(_obj); + if (PythonQt::priv()) { + PythonQt::priv()->removeSignalEmitter(_obj); + } } diff --git a/src/PythonQtSlot.cpp b/src/PythonQtSlot.cpp index 612a6670..ca594a55 100644 --- a/src/PythonQtSlot.cpp +++ b/src/PythonQtSlot.cpp @@ -86,7 +86,6 @@ bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj argList[0] = NULL; bool ok = true; - bool skipFirst = false; PythonQtPassThisOwnershipType passThisOwnership = IgnoreOwnership; int instanceDecoOffset = 0; @@ -94,7 +93,6 @@ bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj // would go away if it is moved into the if scope void* arg1 = NULL; if (info->isInstanceDecorator()) { - skipFirst = true; instanceDecoOffset = 1; // for decorators on CPP objects, we take the cpp ptr, for QObjects we take the QObject pointer diff --git a/src/PythonQtStdIn.cpp b/src/PythonQtStdIn.cpp index 7bf2c961..1311ad83 100644 --- a/src/PythonQtStdIn.cpp +++ b/src/PythonQtStdIn.cpp @@ -53,6 +53,7 @@ static PyObject *PythonQtStdInRedirect_new(PyTypeObject *type, PyObject * /*args static PyObject *PythonQtStdInRedirect_readline(PyObject * self, PyObject * args) { + Q_UNUSED(args); PythonQtStdInRedirect* s = (PythonQtStdInRedirect*)self; QString string; if (s->_cb) { diff --git a/tests/PythonQtTestCleanup.cpp b/tests/PythonQtTestCleanup.cpp new file mode 100644 index 00000000..b60c7023 --- /dev/null +++ b/tests/PythonQtTestCleanup.cpp @@ -0,0 +1,80 @@ +#include "PythonQtTestCleanup.h" +#include "PythonQt.h" +#include "PythonQt_QtBindings.h" + +void PythonQtTestCleanup::initTestCase() +{ +} + +void PythonQtTestCleanup::cleanupTestCase() +{ +} + +void PythonQtTestCleanup::init() +{ + // Initialize before each test + + PythonQt::init(PythonQt::IgnoreSiteModule); + PythonQt_init_QtBindings(); + + _helper = new PythonQtTestCleanupHelper(); + PythonQtObjectPtr main = PythonQt::self()->getMainModule(); + PythonQt::self()->addObject(main, "obj", _helper); +} + +void PythonQtTestCleanup::cleanup() +{ + // Finalize and cleanup after each test + + if (Py_IsInitialized()) { + Py_Finalize(); + } + + PythonQt::cleanup(); + + delete _helper; + _helper = NULL; +} + +void PythonQtTestCleanup::testQtEnum() +{ + QVERIFY(_helper->runScript( + "import PythonQt.QtCore\n" \ + "x = PythonQt.QtCore.QFile.ReadOnly\n" \ + "obj.setPassed()" + )); +} + +void PythonQtTestCleanup::testCallQtMethodInDel() +{ + QVERIFY(_helper->runScript( + "import PythonQt.QtCore\n" \ + "class TimerWrapper(object):\n" \ + " def __init__(self):\n" \ + " self.timer = PythonQt.QtCore.QTimer()\n" \ + " def __del__(self):\n" \ + " self.timer.setSingleShot(True)\n" \ + "x = TimerWrapper()\n" \ + "obj.setPassed()\n" + )); +} + +void PythonQtTestCleanup::testSignalReceiverCleanup() +{ + PythonQtObjectPtr main = PythonQt::self()->getMainModule(); + + // Test that PythonQtSignalReceiver is cleaned up properly, + // i.e. PythonQt::cleanup() doesn't segfault + main.evalScript( + "import PythonQt.QtCore\n" \ + "timer = PythonQt.QtCore.QTimer(obj)\n" \ + "timer.connect('destroyed()', obj.onDestroyed)\n" \ + ); +} + +bool PythonQtTestCleanupHelper::runScript(const char* script) +{ + _passed = false; + PyRun_SimpleString(script); + return _passed; +} diff --git a/tests/PythonQtTestCleanup.h b/tests/PythonQtTestCleanup.h new file mode 100644 index 00000000..b2a15886 --- /dev/null +++ b/tests/PythonQtTestCleanup.h @@ -0,0 +1,47 @@ +#ifndef _PYTHONQTTESTCLEANUP_H +#define _PYTHONQTTESTCLEANUP_H + +#include "PythonQt.h" +#include + +class PythonQtTestCleanupHelper; + +//! Test PythonQt cleanup and Python interpreter finalization +class PythonQtTestCleanup : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + + void testQtEnum(); + void testCallQtMethodInDel(); + void testSignalReceiverCleanup(); + +private: + PythonQtTestCleanupHelper* _helper; +}; + +//! Test helper class +class PythonQtTestCleanupHelper : public QObject +{ + Q_OBJECT +public: + PythonQtTestCleanupHelper() : + _passed(false) { + }; + + bool runScript(const char* script); + +public Q_SLOTS: + void setPassed() { _passed = true; } + void onDestroyed(QObject *) { } + +private: + bool _passed; +}; + +#endif diff --git a/tests/PythonQtTestMain.cpp b/tests/PythonQtTestMain.cpp index 44f5bea6..8b498ab4 100644 --- a/tests/PythonQtTestMain.cpp +++ b/tests/PythonQtTestMain.cpp @@ -41,10 +41,11 @@ #include "PythonQt.h" #include "PythonQtTests.h" +#include "PythonQtTestCleanup.h" #include -int main( int argc, char **argv ) +int main(int argc, char *argv[]) { QApplication qapp(argc, argv); @@ -60,11 +61,21 @@ int main( int argc, char **argv ) PythonQt::cleanup(); + if (Py_IsInitialized()) { + Py_Finalize(); + } + +#ifdef PythonQt_Wrap_Qtcore + PythonQtTestCleanup cleanup; + failCount += QTest::qExec(&cleanup, argc, argv); + if (failCount>0) { std::cerr << "Tests failed: " << failCount << std::endl; } else { std::cout << "All tests passed successfully." << std::endl; } +#endif + return failCount; } diff --git a/tests/PythonQtTests.cpp b/tests/PythonQtTests.cpp index 30d6932d..801198dd 100644 --- a/tests/PythonQtTests.cpp +++ b/tests/PythonQtTests.cpp @@ -298,24 +298,67 @@ void PythonQtTestSlotCalling::testCppFactory() // with int overload to check overloading QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObject2\na = PQCppObject2()\nif a.testEnumFlag3(PQCppObject2.TestEnumValue2)==PQCppObject2.TestEnumValue2: obj.setPassed();\n")); + PythonQt::self()->registerCPPClass("PQCppObjectQFlagOnly",NULL,NULL, PythonQtCreateObject); + + + // local enum (decorated) + QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObjectQFlagOnly\na = PQCppObjectQFlagOnly()\nprint a.testEnumFlag1\nif a.testEnumFlag1(PQCppObjectQFlagOnly.TestEnumValue2)==PQCppObjectQFlagOnly.TestEnumValue2: obj.setPassed();\n")); + + // enum with namespace (decorated) + QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObjectQFlagOnly\na = PQCppObjectQFlagOnly()\nif a.testEnumFlag2(PQCppObjectQFlagOnly.TestEnumValue2)==PQCppObjectQFlagOnly.TestEnumValue2: obj.setPassed();\n")); + // with int overload to check overloading + QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObjectQFlagOnly\na = PQCppObjectQFlagOnly()\nif a.testEnumFlag3(PQCppObjectQFlagOnly.TestEnumValue2)==PQCppObjectQFlagOnly.TestEnumValue2: obj.setPassed();\n")); + } +// PQCppObject2Decorator + PQCppObject2Decorator::TestEnumFlag PQCppObject2Decorator::testEnumFlag1(PQCppObject2* obj, PQCppObject2Decorator::TestEnumFlag flag) { + Q_UNUSED(obj); return flag; } PQCppObject2::TestEnumFlag PQCppObject2Decorator::testEnumFlag2(PQCppObject2* obj, PQCppObject2::TestEnumFlag flag) { + Q_UNUSED(obj); return flag; } // with int overload PQCppObject2Decorator::TestEnumFlag PQCppObject2Decorator::testEnumFlag3(PQCppObject2* obj, int flag) { + Q_UNUSED(obj); + Q_UNUSED(flag); return (TestEnumFlag)-1; } PQCppObject2Decorator::TestEnumFlag PQCppObject2Decorator::testEnumFlag3(PQCppObject2* obj, PQCppObject2Decorator::TestEnumFlag flag) { + Q_UNUSED(obj); + return flag; +} + +// PQCppObjectQFlagOnlyDecorator + +PQCppObjectQFlagOnlyDecorator::TestEnumFlag PQCppObjectQFlagOnlyDecorator::testEnumFlag1(PQCppObjectQFlagOnly* obj, PQCppObjectQFlagOnlyDecorator::TestEnumFlag flag) { + Q_UNUSED(obj); + return flag; +} + +PQCppObjectQFlagOnly::TestEnumFlag PQCppObjectQFlagOnlyDecorator::testEnumFlag2(PQCppObjectQFlagOnly* obj, PQCppObjectQFlagOnly::TestEnumFlag flag) { + Q_UNUSED(obj); return flag; } +// with int overload +PQCppObjectQFlagOnlyDecorator::TestEnumFlag PQCppObjectQFlagOnlyDecorator::testEnumFlag3(PQCppObjectQFlagOnly* obj, int flag) { + Q_UNUSED(obj); + Q_UNUSED(flag); + return (TestEnumFlag)-1; +} +PQCppObjectQFlagOnlyDecorator::TestEnumFlag PQCppObjectQFlagOnlyDecorator::testEnumFlag3(PQCppObjectQFlagOnly* obj, PQCppObjectQFlagOnlyDecorator::TestEnumFlag flag) { + Q_UNUSED(obj); + return flag; +} + +// PythonQtTestSlotCalling + void PythonQtTestSlotCalling::testMultiArgsSlotCall() { QVERIFY(_helper->runScript("if obj.getMultiArgs(12,47.11,'test')==(12,47.11,'test'): obj.setPassed();\n")); @@ -585,12 +628,14 @@ void PythonQtTestApi::testQColorDecorators() QByteArray PythonQtTestApiHelper::readFileAsBytes(const QString& filename) { + Q_UNUSED(filename); QByteArray b; return b; } QByteArray PythonQtTestApiHelper::readSourceFile(const QString& filename, bool& ok) { + Q_UNUSED(filename); QByteArray b; ok = true; return b; @@ -598,10 +643,12 @@ QByteArray PythonQtTestApiHelper::readSourceFile(const QString& filename, bool& bool PythonQtTestApiHelper::exists(const QString& filename) { + Q_UNUSED(filename); return true; } QDateTime PythonQtTestApiHelper::lastModifiedDate(const QString& filename) { + Q_UNUSED(filename); return QDateTime::currentDateTime(); } @@ -625,6 +672,7 @@ void PythonQtTestApiHelper::stdErr(const QString& s) QObject* PythonQtTestCppFactory::create(const QByteArray& name, void *ptr) { + Q_UNUSED(name); if (name == "PQCppObject") { return new PQCppObjectWrapper(ptr); } diff --git a/tests/PythonQtTests.h b/tests/PythonQtTests.h index ece44596..c273432a 100644 --- a/tests/PythonQtTests.h +++ b/tests/PythonQtTests.h @@ -240,9 +240,11 @@ public Q_SLOTS: return new PQCppObjectNoWrap(0); } PQCppObjectNoWrap* new_PQCppObjectNoWrap(const PQCppObjectNoWrap& other) { + Q_UNUSED(other); return new PQCppObjectNoWrap(1); } PQCppObjectNoWrap* new_PQCppObjectNoWrap(double value) { + Q_UNUSED(value); return new PQCppObjectNoWrap(2); } @@ -293,6 +295,36 @@ class PQCppObject2Decorator : public QObject { }; +typedef PQCppObject2 PQCppObjectQFlagOnly; + +class PQCppObjectQFlagOnlyDecorator : public QObject { + Q_OBJECT + +public: + Q_FLAGS(TestEnumFlag) + + enum TestEnumFlag { + TestEnumValue1 = 0, + TestEnumValue2 = 1 + }; + + Q_DECLARE_FLAGS(TestEnum, TestEnumFlag) + + public slots: + PQCppObjectQFlagOnly* new_PQCppObjectQFlagOnly() { + return new PQCppObjectQFlagOnly(); + } + + TestEnumFlag testEnumFlag1(PQCppObjectQFlagOnly* obj, TestEnumFlag flag); + + PQCppObjectQFlagOnly::TestEnumFlag testEnumFlag2(PQCppObjectQFlagOnly* obj, PQCppObjectQFlagOnly::TestEnumFlag flag); + + // with int overload + TestEnumFlag testEnumFlag3(PQCppObjectQFlagOnly* obj, int flag); + TestEnumFlag testEnumFlag3(PQCppObjectQFlagOnly* obj, TestEnumFlag flag); + +}; + class PQUnknownValueObject { public: @@ -399,13 +431,13 @@ public Q_SLOTS: void testNoArg() { _called = true; } //! overload test! - void overload(bool a) { _calledOverload = 0; _called = true; } - void overload(float a) { _calledOverload = 1; _called = true;} - void overload(int a) { _calledOverload = 2; _called = true;} - void overload(const QString& str) { _calledOverload = 3; _called = true;} - void overload(const QStringList& str) { _calledOverload = 4; _called = true;} - void overload(QObject* str) { _calledOverload = 5; _called = true;} - void overload(float a, int b) { _calledOverload = 6; _called = true;} + void overload(bool a) { Q_UNUSED(a); _calledOverload = 0; _called = true; } + void overload(float a) { Q_UNUSED(a); _calledOverload = 1; _called = true;} + void overload(int a) { Q_UNUSED(a); _calledOverload = 2; _called = true;} + void overload(const QString& str) { Q_UNUSED(str); _calledOverload = 3; _called = true;} + void overload(const QStringList& str) { Q_UNUSED(str); _calledOverload = 4; _called = true;} + void overload(QObject* str) { Q_UNUSED(str); _calledOverload = 5; _called = true;} + void overload(float a, int b) { Q_UNUSED(a); Q_UNUSED(b);_calledOverload = 6; _called = true;} //! POD values: int getInt(int a) { _called = true; return a; }