diff --git a/README.md b/README.md index d91cc315..1d058e36 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # PythonQt + [![License](https://img.shields.io/github/license/mevislab/pythonqt.svg?color=blue)](LICENSE) PythonQt is a dynamic [Python](https://www.python.org) binding for [Qt](https://www.qt.io). @@ -6,12 +7,15 @@ It offers an easy way to embed the Python scripting language into your Qt applications. # Documentation + API documentation is available at: https://mevislab.github.io/pythonqt # Licensing + PythonQt is distributed under the `LGPL 2.1` license. ## Licensing of Generator + The build system of PythonQt makes use of a patched version of the LGPL'ed QtScript generator, located in the `generator` directory. @@ -26,3 +30,18 @@ The generated wrappers are pre-generated and checked-in, so you only need to build and run the generator when you want to build additional wrappers or you want to upgrade/downgrade to another Qt version, but this requires updating the typesystems as well. + +# Building + +## Building on Windows with MinGW + +To build PythonQt, you need to set the environment variable `PYTHON_PATH` to +point to the root dir of the python installation. Then you should set the +`PYTHON_VERSION` variable to the Python version number. + +When using the prebuild Python installer, this will be: + +```cmd +set PYTHON_PATH=c:\Python310 +set PYTHON_VERSION=3.10 +``` diff --git a/build/python.prf b/build/python.prf index aae26277..87443b9a 100644 --- a/build/python.prf +++ b/build/python.prf @@ -1,12 +1,12 @@ # profile to include and link Python -# Change this variable to your python version (2.6, 2.7, 3.3, ...) +# Change this variable to your python version (3.7, 3.8, ...) isEmpty( PYTHON_VERSION ) { PYTHON_VERSION=$$(PYTHON_VERSION) } isEmpty( PYTHON_VERSION ) { - PYTHON_VERSION=2.7 + PYTHON_VERSION=3.10 } isEmpty( PYTHON_DIR ) { @@ -36,7 +36,7 @@ equals(PYTHON_VERSION_MAJOR, 2) { } contains(PKGCONFIG, "python.*"){ -# If `pkg-config` is configured, use `qmake PKGCONFIG+=python3.8-embed CONFIG+=...` +# If `pkg-config` is configured, use `qmake PKGCONFIG+=python3.10-embed CONFIG+=...` # or `PKGCONFIG+=python2.7m`-like form for older versions, # see `pkg-config --list-all | grep python` for details. # This can help with GNU/Linux (including macOS with Homebrew), MSYS2/MinGW environment, @@ -54,16 +54,12 @@ contains(PKGCONFIG, "python.*"){ # for windows install a Python development kit or build Python yourself from the sources # Make sure that you set the environment variable PYTHON_PATH to point to your # python installation (or the python sources/header files when building from source). - # Make sure that you set the environment variable PYTHON_LIB to point to - # the directory where the python libs are located. # # When using the prebuild Python installer, this will be: - # set PYTHON_PATH = c:\Python26 - # set PYTHON_LIB = c:\Python26\libs + # set PYTHON_PATH = c:\Python310 # # When using the python sources, this will be something like: - # set PYTHON_PATH = c:\yourDir\Python-2.6.1\ - # set PYTHON_LIB = c:\yourDir\Python-2.6.1\PCbuild8\Win32 + # set PYTHON_PATH = c:\yourDir\Python-3.10.12\ # check if debug or release CONFIG(debug, debug|release) { diff --git a/doxygen/Doxyfile b/doxygen/Doxyfile index 7c6f6092..8013ca1e 100644 --- a/doxygen/Doxyfile +++ b/doxygen/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.8.15 +# Doxyfile 1.9.5 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -12,6 +12,16 @@ # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options @@ -60,12 +70,13 @@ PROJECT_LOGO = OUTPUT_DIRECTORY = . -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes -# performance problems for the file system. +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO @@ -81,26 +92,18 @@ ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English -# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all generated output in the proper direction. -# Possible values are: None, LTR, RTL and Context. -# The default value is: None. - -OUTPUT_TEXT_DIRECTION = None - # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. @@ -187,6 +190,16 @@ SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus @@ -207,6 +220,14 @@ QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. @@ -230,25 +251,19 @@ TAB_SIZE = 4 # the documentation. An alias has the form: # name=value # For example adding -# "sideeffect=@par Side Effects:\n" +# "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines (in the resulting output). You can put ^^ in the value part of an -# alias to insert a newline as if a physical newline was in the original file. -# When you need a literal { or } or , in the value part of an alias you have to -# escape them by means of a backslash (\), this can lead to conflicts with the -# commands \{ and \} for these it is advised to use the version @{ and @} or use -# a double escape (\\{ and \\}) +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) ALIASES = -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all @@ -289,19 +304,22 @@ OPTIMIZE_OUTPUT_SLICE = NO # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, -# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the -# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat -# .inc files as Fortran files (default is PHP), and .f files as C (default is -# Fortran), use: inc=Fortran f=C. +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. EXTENSION_MAPPING = @@ -319,7 +337,7 @@ MARKDOWN_SUPPORT = YES # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. -# Minimum value: 0, maximum value: 99, default value: 0. +# Minimum value: 0, maximum value: 99, default value: 5. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 0 @@ -435,6 +453,19 @@ TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -455,6 +486,12 @@ EXTRACT_ALL = YES EXTRACT_PRIVATE = NO +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. @@ -492,6 +529,13 @@ EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation @@ -509,8 +553,8 @@ HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO, these declarations will be -# included in the documentation. +# declarations. If set to NO, these declarations will be included in the +# documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO @@ -529,12 +573,20 @@ HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES, upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. -# The default value is: system dependent. +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. CASE_SENSE_NAMES = YES @@ -552,6 +604,12 @@ HIDE_SCOPE_NAMES = NO HIDE_COMPOUND_REFERENCE= NO +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +# SHOW_HEADERFILE = YES + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -709,7 +767,8 @@ FILE_VERSION_FILTER = # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE @@ -755,24 +814,28 @@ WARNINGS = YES WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. If -# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC # The default value is: NO. WARN_NO_PARAMDOC = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when -# a warning is encountered. +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. # The default value is: NO. WARN_AS_ERROR = NO @@ -783,13 +846,27 @@ WARN_AS_ERROR = NO # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +# WARN_LINE_FORMAT = "at line $line of file $file" + # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard -# error (stderr). +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). WARN_LOGFILE = doxygen.log @@ -808,8 +885,9 @@ INPUT = ../src # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: https://www.gnu.org/software/libiconv/) for the list of -# possible encodings. +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING # The default value is: UTF-8. INPUT_ENCODING = UTF-8 @@ -822,11 +900,15 @@ INPUT_ENCODING = UTF-8 # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, -# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. +# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, +# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C +# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.h @@ -865,7 +947,7 @@ EXCLUDE_PATTERNS = # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test +# ANamespace::AClass, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* @@ -913,6 +995,11 @@ IMAGE_PATH = . # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. @@ -954,6 +1041,15 @@ FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +# FORTRAN_COMMENT_AFTER = 72 + #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- @@ -1040,6 +1136,46 @@ USE_HTAGS = NO VERBATIM_HEADERS = YES +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which doxygen's built-in parser lacks the necessary type information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS +# tag is set to YES then doxygen will add the directory of each input to the +# include path. +# The default value is: YES. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_ADD_INC_PATHS = YES + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- @@ -1051,13 +1187,6 @@ VERBATIM_HEADERS = YES ALPHABETICAL_INDEX = YES -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored @@ -1157,7 +1286,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see +# this color. Hue is specified as an angle on a color-wheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. @@ -1167,7 +1296,7 @@ HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A +# in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1196,9 +1325,9 @@ HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that -# are dynamically created via Javascript. If disabled, the navigation index will +# are dynamically created via JavaScript. If disabled, the navigation index will # consists of multiple levels of tabs that are statically embedded in every HTML -# page. Disable this option to support browsers that do not have Javascript, +# page. Disable this option to support browsers that do not have JavaScript, # like the Qt help browser. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1228,10 +1357,11 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: https://developer.apple.com/xcode/), introduced with OSX -# 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy # genXcode/_index.html for more information. @@ -1273,8 +1403,12 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML @@ -1304,7 +1438,7 @@ CHM_FILE = HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated -# (YES) or that it should be included in the master .chm file (NO). +# (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1349,7 +1483,8 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1357,8 +1492,8 @@ QHP_NAMESPACE = # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- -# folders). +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1366,30 +1501,30 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = @@ -1432,16 +1567,28 @@ DISABLE_INDEX = NO # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +# FULL_SIDEBAR = NO + # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # @@ -1466,6 +1613,17 @@ TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML @@ -1475,19 +1633,14 @@ EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANSPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. -FORMULA_TRANSPARENT = YES +FORMULA_MACROFILE = # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# https://www.mathjax.org) which uses client side Javascript for the rendering +# https://www.mathjax.org) which uses client side JavaScript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path @@ -1498,10 +1651,17 @@ FORMULA_TRANSPARENT = YES USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1514,22 +1674,29 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from https://www.mathjax.org before deployment. -# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1557,7 +1724,7 @@ MATHJAX_CODEFILE = SEARCHENGINE = NO # When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a web server instead of a web client using Javascript. There +# implemented using a web server instead of a web client using JavaScript. There # are two flavors of web server based searching depending on the EXTERNAL_SEARCH # setting. When disabled, doxygen will generate a PHP script for searching and # an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing @@ -1576,7 +1743,8 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: https://xapian.org/). +# Xapian (see: +# https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1589,8 +1757,9 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: https://xapian.org/). See the section "External Indexing and -# Searching" for details. +# Xapian (see: +# https://xapian.org/). See the section "External Indexing and Searching" for +# details. # This tag requires that the tag SEARCHENGINE is set to YES. SEARCHENGINE_URL = @@ -1685,7 +1854,7 @@ COMPACT_LATEX = NO # The default value is: a4. # This tag requires that the tag GENERATE_LATEX is set to YES. -PAPER_TYPE = a4wide +PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names # that should be included in the LaTeX output. The package can be specified just @@ -1699,29 +1868,31 @@ PAPER_TYPE = a4wide EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the -# generated LaTeX document. The header should contain everything until the first -# chapter. If it is left blank doxygen will generate a standard header. See -# section "Doxygen usage" for information on how to let doxygen write the -# default header to a separate file. +# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for +# the generated LaTeX document. The header should contain everything until the +# first chapter. If it is left blank doxygen will generate a standard header. It +# is highly recommended to start with a default header using +# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty +# and then modify the file new_header.tex. See also section "Doxygen usage" for +# information on how to generate the default header that doxygen normally uses. # -# Note: Only use a user-defined header if you know what you are doing! The -# following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber, -# $projectbrief, $projectlogo. Doxygen will replace $title with the empty -# string, for the replacement values of the other commands the user is referred -# to HTML_HEADER. +# Note: Only use a user-defined header if you know what you are doing! +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. The following +# commands have a special meaning inside the header (and footer): For a +# description of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HEADER = -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the -# generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. See +# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for +# the generated LaTeX document. The footer should contain everything after the +# last chapter. If it is left blank doxygen will generate a standard footer. See # LATEX_HEADER for more information on how to generate a default footer and what -# special commands can be used inside the footer. -# -# Note: Only use a user-defined footer if you know what you are doing! +# special commands can be used inside the footer. See also section "Doxygen +# usage" for information on how to generate the default footer that doxygen +# normally uses. Note: Only use a user-defined footer if you know what you are +# doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_FOOTER = @@ -1754,9 +1925,11 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = NO -# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES, to get a -# higher quality PDF documentation. +# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as +# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX +# files. Set this option to YES, to get a higher quality PDF documentation. +# +# See also section LATEX_CMD_NAME for selecting the engine. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1764,8 +1937,7 @@ USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode # command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. This option is also used -# when generating formulas in HTML. +# if errors occur, instead of asking the user for help. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1778,16 +1950,6 @@ LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO -# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source -# code with syntax highlighting in the LaTeX output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_SOURCE_CODE = NO - # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See # https://en.wikipedia.org/wiki/BibTeX and \cite for more info. @@ -1868,16 +2030,6 @@ RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = -# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code -# with syntax highlighting in the RTF output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_RTF is set to YES. - -RTF_SOURCE_CODE = NO - #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- @@ -1974,15 +2126,6 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook -# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the -# program listings (including syntax highlighting and cross-referencing -# information) to the DOCBOOK output. Note that enabling this will significantly -# increase the size of the DOCBOOK output. -# The default value is: NO. -# This tag requires that the tag GENERATE_DOCBOOK is set to YES. - -DOCBOOK_PROGRAMLISTING = NO - #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- @@ -2069,7 +2212,8 @@ SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the -# preprocessor. +# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of +# RECURSIVE has no effect here. # This tag requires that the tag SEARCH_INCLUDES is set to YES. INCLUDE_PATH = @@ -2157,34 +2301,10 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of 'which perl'). -# The default file (with absolute path) is: /usr/bin/perl. - -PERL_PATH = /usr/bin/perl - #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram -# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to -# NO turns the diagrams off. Note that this option also works with HAVE_DOT -# disabled, but it is recommended to install and use dot, since it yields more -# powerful graphs. -# The default value is: YES. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see: -# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. @@ -2217,35 +2337,20 @@ HAVE_DOT = NO DOT_NUM_THREADS = 0 -# When you want a differently looking font in the dot files that doxygen -# generates you can specify the font name using DOT_FONTNAME. You need to make -# sure dot is able to find the font, which can be done by putting it in a -# standard location or by setting the DOTFONTPATH environment variable or by -# setting DOT_FONTPATH to the directory containing the font. -# The default value is: Helvetica. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_FONTNAME = - -# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of -# dot graphs. -# Minimum value: 4, maximum value: 24, default value: 10. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the default font as specified with -# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set -# the path where dot can find it using this tag. +# You can set the path where dot can find font specified with fontname in +# DOT_COMMON_ATTR and others dot attributes. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for -# each documented class showing the direct and indirect inheritance relations. -# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a +# graph for each documented class showing the direct and indirect inheritance +# relations. In case HAVE_DOT is set as well dot will be used to draw the graph, +# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set +# to TEXT the direct and indirect inheritance relations will be shown as texts / +# links. +# Possible values are: NO, YES, TEXT and GRAPH. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. CLASS_GRAPH = YES @@ -2259,7 +2364,8 @@ CLASS_GRAPH = YES COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for -# groups, showing the direct groups dependencies. +# groups, showing the direct groups dependencies. See also the chapter Grouping +# in the manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2282,10 +2388,32 @@ UML_LOOK = NO # but if the number exceeds 15, the total amount of fields shown is limited to # 10. # Minimum value: 0, maximum value: 100, default value: 10. -# This tag requires that the tag HAVE_DOT is set to YES. +# This tag requires that the tag UML_LOOK is set to YES. UML_LIMIT_NUM_FIELDS = 10 +# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and +# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS +# tag is set to YES, doxygen will add type and arguments for attributes and +# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen +# will not generate fields with class member information in the UML graphs. The +# class diagrams will look similar to the default class diagrams but using UML +# notation for the relationships. +# Possible values are: NO, YES and NONE. +# The default value is: NO. +# This tag requires that the tag UML_LOOK is set to YES. + +DOT_UML_DETAILS = NO + +# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters +# to display on a single line. If the actual line length exceeds this threshold +# significantly it will wrapped across multiple lines. Some heuristics are apply +# to avoid ugly line breaks. +# Minimum value: 0, maximum value: 1000, default value: 17. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_WRAP_THRESHOLD = 17 + # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and # collaboration graphs will show the relations between templates and their # instances. @@ -2405,10 +2533,10 @@ MSCFILE_DIRS = DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the -# path where java can find the plantuml.jar file. If left blank, it is assumed -# PlantUML is not used or called during a preprocessing step. Doxygen will -# generate a warning when it encounters a \startuml command in this case and -# will not generate output for the diagram. +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. PLANTUML_JAR_PATH = @@ -2446,18 +2574,6 @@ DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not seem -# to support this out of the box. -# -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). -# The default value is: NO. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_TRANSPARENT = NO - # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support @@ -2470,14 +2586,18 @@ DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated # graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate # files that are used to generate the various graphs. +# +# Note: This setting is not only used for dot files but also for msc temporary +# files. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. DOT_CLEANUP = YES diff --git a/generator/abstractmetabuilder.cpp b/generator/abstractmetabuilder.cpp index faf16aee..4a886c42 100644 --- a/generator/abstractmetabuilder.cpp +++ b/generator/abstractmetabuilder.cpp @@ -391,6 +391,28 @@ void AbstractMetaBuilder::sortLists() } } +AbstractMetaClass* AbstractMetaBuilder::getGlobalNamespace(const TypeEntry* typeEntry) +{ + QString package = typeEntry->javaPackage(); + QString globalName = TypeDatabase::globalNamespaceClassName(typeEntry); + + AbstractMetaClass* global = m_meta_classes.findClass(package + "." + globalName); + if (!global) { + ComplexTypeEntry* gte = new NamespaceTypeEntry(globalName); + gte->setTargetLangPackage(typeEntry->javaPackage()); + gte->setCodeGeneration(typeEntry->codeGeneration()); + global = createMetaClass(); + global->setIsGlobalNamespace(true); + global->setTypeEntry(gte); + *global += AbstractMetaAttributes::Final; + *global += AbstractMetaAttributes::Public; + *global += AbstractMetaAttributes::Fake; + + m_meta_classes << global; + } + return global; +} + bool AbstractMetaBuilder::build() { Q_ASSERT(!m_file_name.isEmpty()); @@ -460,36 +482,21 @@ bool AbstractMetaBuilder::build() AbstractMetaEnum *meta_enum = traverseEnum(item, 0, QSet()); if (meta_enum) { - QString package = meta_enum->typeEntry()->javaPackage(); - QString globalName = TypeDatabase::globalNamespaceClassName(meta_enum->typeEntry()); - - AbstractMetaClass *global = m_meta_classes.findClass(package + "." + globalName); - if (!global) { - ComplexTypeEntry *gte = new ObjectTypeEntry(globalName); - gte->setTargetLangPackage(meta_enum->typeEntry()->javaPackage()); - gte->setCodeGeneration(meta_enum->typeEntry()->codeGeneration()); - global = createMetaClass(); - global->setTypeEntry(gte); - *global += AbstractMetaAttributes::Final; - *global += AbstractMetaAttributes::Public; - *global += AbstractMetaAttributes::Fake; - - m_meta_classes << global; - } + AbstractMetaClass* global = getGlobalNamespace(meta_enum->typeEntry()); global->addEnum(meta_enum); - meta_enum->setEnclosingClass(global); - meta_enum->typeEntry()->setQualifier(globalName); // Global enums should be public despite not having public // identifiers so we'll fix the original attributes here. meta_enum->setOriginalAttributes(meta_enum->attributes()); - } - + // global enums have their own include + if (meta_enum->typeEntry()->include().isValid()) { + global->typeEntry()->addExtraInclude(meta_enum->typeEntry()->include()); + } + } } - // Go through all typedefs to see if we have defined any // specific typedefs to be used as classes. TypeAliasList typeAliases = m_dom->typeAliases(); @@ -1166,6 +1173,48 @@ void AbstractMetaBuilder::traverseFunctions(ScopeModelItem scope_item, AbstractM } } } + removeEquivalentFunctions(meta_class); +} + +void AbstractMetaBuilder::removeEquivalentFunctions(AbstractMetaClass* parent) +{ + AbstractMetaFunctionList functions = parent->functions(); + for (AbstractMetaFunction* fun : functions) + { + AbstractMetaArgumentList args = fun->arguments(); + bool candidateToRemove = false; + for (AbstractMetaArgument* arg : args) { + const TypeEntry* argType = arg->type()->typeEntry(); + if (argType && argType->equivalentType()) { + candidateToRemove = true; + break; + } + } + if (!candidateToRemove) { + continue; + } + // check if there are other functions with the same name and equivalent parameters + AbstractMetaFunctionList overloadedFunctions = parent->queryFunctionsByName(fun->name()); + for (AbstractMetaFunction* overload : overloadedFunctions) { + if (overload != fun) { + AbstractMetaArgumentList overloadArgs = overload->arguments(); + if (overloadArgs.size() == args.size()) { + bool equivalentArgs = true; + for (int i = 0; i < args.size() && equivalentArgs; i++) { + const TypeEntry* argType = args[i]->type()->typeEntry(); + const TypeEntry* overloadArgType = overloadArgs[i]->type()->typeEntry(); + // This could have some more equivalency checks, but currently this seems to be sufficient + equivalentArgs = (argType && overloadArgType && + (argType == overloadArgType || argType->equivalentType() == overloadArgType)); + } + if (equivalentArgs) { + parent->removeFunction(fun); + break; + } + } + } + } + } } bool AbstractMetaBuilder::setupInheritance(AbstractMetaClass *meta_class) diff --git a/generator/abstractmetabuilder.h b/generator/abstractmetabuilder.h index 5fa72da6..abaf900c 100644 --- a/generator/abstractmetabuilder.h +++ b/generator/abstractmetabuilder.h @@ -96,6 +96,10 @@ class AbstractMetaBuilder void traverseStreamOperator(FunctionModelItem function_item); void traverseCompareOperator(FunctionModelItem item); void traverseBinaryArithmeticOperator(FunctionModelItem item); + + //! remove functions/methods that are overloads with equivalent parameter types + //! when called from Python + void removeEquivalentFunctions(AbstractMetaClass* parent); AbstractMetaFunction *traverseFunction(FunctionModelItem function); AbstractMetaField *traverseField(VariableModelItem field, const AbstractMetaClass *cls); @@ -145,6 +149,8 @@ class AbstractMetaBuilder private: void sortLists(); + AbstractMetaClass* getGlobalNamespace(const TypeEntry* typeEntry); + QString m_file_name; AbstractMetaClassList m_meta_classes; diff --git a/generator/abstractmetalang.cpp b/generator/abstractmetalang.cpp index 67fc4d2a..b8c0cd33 100644 --- a/generator/abstractmetalang.cpp +++ b/generator/abstractmetalang.cpp @@ -1103,6 +1103,11 @@ void AbstractMetaClass::addFunction(AbstractMetaFunction *function) m_has_nonpublic |= !function->isPublic(); } +void AbstractMetaClass::removeFunction(AbstractMetaFunction* function) +{ + m_functions.removeOne(function); +} + bool AbstractMetaClass::hasSignal(const AbstractMetaFunction *other) const { if (!other->isSignal()) diff --git a/generator/abstractmetalang.h b/generator/abstractmetalang.h index f161c5c7..560b8169 100644 --- a/generator/abstractmetalang.h +++ b/generator/abstractmetalang.h @@ -676,6 +676,7 @@ class AbstractMetaClass : public AbstractMetaAttributes m_has_clone_operator(false), m_is_type_alias(false), m_has_actual_declaration(false), + m_is_global_namespace(false), m_qDebug_stream_function(0) { } @@ -688,6 +689,7 @@ class AbstractMetaClass : public AbstractMetaAttributes AbstractMetaFunctionList functions() const { return m_functions; } void setFunctions(const AbstractMetaFunctionList &functions); void addFunction(AbstractMetaFunction *function); + void removeFunction(AbstractMetaFunction* function); bool hasFunction(const AbstractMetaFunction *f) const; bool hasFunction(const QString &str) const; bool hasSignal(const AbstractMetaFunction *f) const; @@ -800,6 +802,9 @@ class AbstractMetaClass : public AbstractMetaAttributes void setHasActualDeclaration(bool on) { m_has_actual_declaration = on; } bool hasActualDeclaration() const { return m_has_actual_declaration; } + void setIsGlobalNamespace(bool on) { m_is_global_namespace = on; } + bool isGlobalNamespace() const { return m_is_global_namespace; } + QString getDefaultNonZeroFunction() const; void addPropertySpec(QPropertySpec *spec) { m_property_specs << spec; } @@ -861,7 +866,8 @@ class AbstractMetaClass : public AbstractMetaAttributes uint m_has_clone_operator :1; uint m_is_type_alias : 1; uint m_has_actual_declaration : 1; - uint m_reserved : 17; + uint m_is_global_namespace : 1; + uint m_reserved : 16; QString m_destructor_exception; const AbstractMetaClass *m_enclosing_class{}; diff --git a/generator/generator.pri b/generator/generator.pri index 490e265c..d6bde5a4 100644 --- a/generator/generator.pri +++ b/generator/generator.pri @@ -35,7 +35,6 @@ win32-clang-msvc:QMAKE_CXXFLAGS += -Wno-language-extension-token -Wno-microsoft- # Input HEADERS += \ $$GENERATORPATH/generator.h \ - $$GENERATORPATH/main.h \ $$GENERATORPATH/reporthandler.h \ $$GENERATORPATH/typeparser.h \ $$GENERATORPATH/typesystem.h \ diff --git a/generator/main.cpp b/generator/main.cpp index e438bcd9..7cb3b79d 100644 --- a/generator/main.cpp +++ b/generator/main.cpp @@ -40,14 +40,15 @@ ****************************************************************************/ #include +#include -#include "main.h" #include "asttoxml.h" #include "reporthandler.h" #include "typesystem.h" #include "generatorset.h" #include "fileout.h" #include "control.h" +#include "pp.h" #include #include @@ -57,39 +58,163 @@ void displayHelp(GeneratorSet *generatorSet); -static unsigned int getQtVersion(const QString& commandLineIncludes) +namespace { - QRegularExpression re("#define\\s+QTCORE_VERSION\\s+0x([0-9a-f]+)", QRegularExpression::CaseInsensitiveOption); - for (const QString& includeDir : Preprocess::getIncludeDirectories(commandLineIncludes)) { - QFileInfo fi(QDir(includeDir), "qtcoreversion.h"); - if (fi.exists()) { - QString filePath = fi.absoluteFilePath(); - QFile f(filePath); - if (f.open(QIODevice::ReadOnly)) { - QTextStream ts(&f); - QString content = ts.readAll(); - f.close(); - auto match = re.match(content); - if (match.isValid()) { - unsigned int result; - bool ok; - result = match.captured(1).toUInt(&ok, 16); - if (!ok) { - printf("Could not parse Qt version in file [%s] (looked for #define QTCORE_VERSION)\n", - qPrintable(filePath)); + + QStringList getIncludeDirectories(const QString &commandLineIncludes) + { + QStringList includes; + includes << QString("."); + + QChar pathSplitter = QDir::listSeparator(); + + // Environment PYTHONQT_INCLUDE + QString includePath = getenv("PYTHONQT_INCLUDE"); + if (!includePath.isEmpty()) + includes += includePath.split(pathSplitter, Qt::SkipEmptyParts); + + // Includes from the command line + if (!commandLineIncludes.isEmpty()) + includes += commandLineIncludes.split(pathSplitter, Qt::SkipEmptyParts); + for (auto it = includes.begin(); it != includes.end();) + { + if (!QDir(*it).exists()) + { + qWarning("Include path %s does not exist, ignoring it.", it->toUtf8().constData()); + it = includes.erase(it); + } + else + { + ++it; + } + } + + // Include Qt + QString qtdir = getenv("QTDIR"); + if (qtdir.isEmpty() || !QDir(qtdir).exists(qtdir)) + { + QString reason = "The QTDIR environment variable " + qtdir.isEmpty() ? + "is not set. " : "points to a non-existing directory. "; +#if defined(Q_OS_MAC) + qWarning((reason + "Assuming standard binary install using frameworks.").toUtf8().constData()); + QString frameworkDir = "/Library/Frameworks"; + includes << (frameworkDir + "/QtXml.framework/Headers"); + includes << (frameworkDir + "/QtNetwork.framework/Headers"); + includes << (frameworkDir + "/QtCore.framework/Headers"); + includes << (frameworkDir + "/QtGui.framework/Headers"); + includes << (frameworkDir + "/QtOpenGL.framework/Headers"); + includes << frameworkDir; +#else + qWarning((reason + "This may cause problems with finding the necessary include files.").toUtf8().constData()); +#endif + } + else + { + std::cout << "-------------------------------------------------------------" << std::endl; + std::cout << "Using QT at: " << qtdir.toLocal8Bit().constData() << std::endl; + std::cout << "-------------------------------------------------------------" << std::endl; + qtdir += "/include"; + includes << (qtdir + "/QtXml"); + includes << (qtdir + "/QtNetwork"); + includes << (qtdir + "/QtCore"); + includes << (qtdir + "/QtGui"); + includes << (qtdir + "/QtOpenGL"); + includes << qtdir; + } + return includes; + } + + bool + preprocess(const QString &sourceFile, const QString &targetFile, const QString &commandLineIncludes = QString()) + { + rpp::pp_environment env; + rpp::pp preprocess(env); + + rpp::pp_null_output_iterator null_out; + + const char *ppconfig = ":/trolltech/generator/parser/rpp/pp-qt-configuration"; + + QFile file(ppconfig); + if (!file.open(QFile::ReadOnly)) + { + fprintf(stderr, "Preprocessor configuration file not found '%s'\n", ppconfig); + return false; + } + + QByteArray ba = file.readAll(); + file.close(); + preprocess.operator()(ba.constData(), ba.constData() + ba.size(), null_out); + + foreach(QString + include, getIncludeDirectories(commandLineIncludes)) { + preprocess.push_include_path(QDir::toNativeSeparators(include).toStdString()); + } + + QString currentDir = QDir::current().absolutePath(); + QFileInfo sourceInfo(sourceFile); + QDir::setCurrent(sourceInfo.absolutePath()); + + std::string result; + result.reserve(20 * 1024); // 20K + + result += "# 1 \"builtins\"\n"; + result += "# 1 \""; + result += sourceFile.toStdString(); + result += "\"\n"; + + preprocess.file(sourceInfo.fileName().toStdString(), + rpp::pp_output_iterator(result)); + + QDir::setCurrent(currentDir); + + QFile f(targetFile); + if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) + { + fprintf(stderr, "Failed to write preprocessed file: %s\n", qPrintable(targetFile)); + } + f.write(result.c_str(), result.length()); + + return true; + } + + unsigned int getQtVersion(const QString &commandLineIncludes) + { + QRegularExpression re("#define\\s+QTCORE_VERSION\\s+0x([0-9a-f]+)", QRegularExpression::CaseInsensitiveOption); + for (const QString &includeDir: getIncludeDirectories(commandLineIncludes)) + { + QFileInfo fi(QDir(includeDir), "qtcoreversion.h"); + if (fi.exists()) + { + QString filePath = fi.absoluteFilePath(); + QFile f(filePath); + if (f.open(QIODevice::ReadOnly)) + { + QTextStream ts(&f); + QString content = ts.readAll(); + f.close(); + auto match = re.match(content); + if (match.isValid()) + { + unsigned int result; + bool ok; + result = match.captured(1).toUInt(&ok, 16); + if (!ok) + { + printf("Could not parse Qt version in file [%s] (looked for #define QTCORE_VERSION)\n", + qPrintable(filePath)); + } + return result; + } } - return result; } } + printf("Error: Could not find Qt version (looked for qtcoreversion.h in %s)\n", + qPrintable(commandLineIncludes)); + return 0; } - } - printf("Error: Could not find Qt version (looked for qtcoreversion.h in %s)\n", - qPrintable(commandLineIncludes)); - return 0; -} +}; -#include int main(int argc, char *argv[]) { ReportHandler::setContext("Arguments"); @@ -102,7 +227,6 @@ int main(int argc, char *argv[]) QString fileName; QString typesystemFileName; QString pp_file = ".preprocessed.tmp"; - QStringList rebuild_classes; QMap args; unsigned int qtVersion{}; @@ -203,13 +327,17 @@ int main(int argc, char *argv[]) printf("Parsing typesystem file [%s]\n", qPrintable(typesystemFileName)); fflush(stdout); ReportHandler::setContext("Typesystem"); - if (!TypeDatabase::instance()->parseFile(typesystemFileName, qtVersion)) + if (TypeDatabase::instance()->parseFile(typesystemFileName, qtVersion)) { + TypeDatabase::instance()->finalSetup(); + } + else { qFatal("Cannot parse file: '%s'", qPrintable(typesystemFileName)); + } printf("PreProcessing - Generate [%s] using [%s] and include-paths [%s]\n", qPrintable(pp_file), qPrintable(fileName), qPrintable(args.value("include-paths"))); ReportHandler::setContext("Preprocess"); - if (!Preprocess::preprocess(fileName, pp_file, args.value("include-paths"))) { + if (!preprocess(fileName, pp_file, args.value("include-paths"))) { fprintf(stderr, "Preprocessor failed on file: '%s'\n", qPrintable(fileName)); return 1; } @@ -238,11 +366,7 @@ int main(int argc, char *argv[]) void displayHelp(GeneratorSet* generatorSet) { -#if defined(Q_OS_WIN32) - char path_splitter = ';'; -#else - char path_splitter = ':'; -#endif + const auto path_splitter = QDir::listSeparator().toLatin1(); printf("Usage:\n generator [options] header-file typesystem-file\n\n"); printf("Available options:\n\n"); printf("General:\n"); diff --git a/generator/main.h b/generator/main.h deleted file mode 100644 index 388e9250..00000000 --- a/generator/main.h +++ /dev/null @@ -1,153 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Script Generator project on Qt Labs. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef MAIN_H -#define MAIN_H - -#include "pp.h" - -#include -#include - -struct Preprocess -{ - - static QStringList getIncludeDirectories(const QString& commandLineIncludes) - { - QStringList includes; - includes << QString("."); - -#if defined(Q_OS_WIN32) - const char *path_splitter = ";"; -#else - const char *path_splitter = ":"; -#endif - - // Environment INCLUDE - QString includePath = getenv("INCLUDE"); - if (!includePath.isEmpty()) - includes += includePath.split(path_splitter); - - // Includes from the command line - if (!commandLineIncludes.isEmpty()) - includes += commandLineIncludes.split(path_splitter); - - // Include Qt - QString qtdir = getenv ("QTDIR"); - if (qtdir.isEmpty()) { -#if defined(Q_OS_MAC) - qWarning("QTDIR environment variable not set. Assuming standard binary install using frameworks."); - QString frameworkDir = "/Library/Frameworks"; - includes << (frameworkDir + "/QtXml.framework/Headers"); - includes << (frameworkDir + "/QtNetwork.framework/Headers"); - includes << (frameworkDir + "/QtCore.framework/Headers"); - includes << (frameworkDir + "/QtGui.framework/Headers"); - includes << (frameworkDir + "/QtOpenGL.framework/Headers"); - includes << frameworkDir; -#else - qWarning("QTDIR environment variable not set. This may cause problems with finding the necessary include files."); -#endif - } else { - std::cout << "-------------------------------------------------------------" << std::endl; - std::cout << "Using QT at: " << qtdir.toLocal8Bit().constData() << std::endl; - std::cout << "-------------------------------------------------------------" << std::endl; - qtdir += "/include"; - includes << (qtdir + "/QtXml"); - includes << (qtdir + "/QtNetwork"); - includes << (qtdir + "/QtCore"); - includes << (qtdir + "/QtGui"); - includes << (qtdir + "/QtOpenGL"); - includes << qtdir; - } - return includes; - } - - static bool preprocess(const QString &sourceFile, const QString &targetFile, const QString &commandLineIncludes = QString()) - { - rpp::pp_environment env; - rpp::pp preprocess(env); - - rpp::pp_null_output_iterator null_out; - - const char *ppconfig = ":/trolltech/generator/parser/rpp/pp-qt-configuration"; - - QFile file(ppconfig); - if (!file.open(QFile::ReadOnly)) { - fprintf(stderr, "Preprocessor configuration file not found '%s'\n", ppconfig); - return false; - } - - QByteArray ba = file.readAll(); - file.close(); - preprocess.operator() (ba.constData(), ba.constData() + ba.size(), null_out); - - foreach (QString include, getIncludeDirectories(commandLineIncludes)) { - preprocess.push_include_path(QDir::toNativeSeparators(include).toStdString()); - } - - QString currentDir = QDir::current().absolutePath(); - QFileInfo sourceInfo(sourceFile); - QDir::setCurrent(sourceInfo.absolutePath()); - - std::string result; - result.reserve (20 * 1024); // 20K - - result += "# 1 \"builtins\"\n"; - result += "# 1 \""; - result += sourceFile.toStdString(); - result += "\"\n"; - - preprocess.file (sourceInfo.fileName().toStdString(), - rpp::pp_output_iterator (result)); - - QDir::setCurrent(currentDir); - - QFile f(targetFile); - if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { - fprintf(stderr, "Failed to write preprocessed file: %s\n", qPrintable(targetFile)); - } - f.write(result.c_str(), result.length()); - - return true; - } -}; - -#endif // MAIN_H diff --git a/generator/qtscript_masterinclude.h b/generator/qtscript_masterinclude.h index cc679058..8c0da0b8 100644 --- a/generator/qtscript_masterinclude.h +++ b/generator/qtscript_masterinclude.h @@ -127,9 +127,11 @@ #include #endif +#if QT_VERSION < 0x060000 #ifndef QT_NO_XMLPATTERNS # include #endif +#endif #ifndef QT_NO_WEBKIT # include @@ -1232,4 +1234,8 @@ #define GL_LOGIC_OP GL_INDEX_LOGIC_OP #define GL_TEXTURE_COMPONENTS GL_TEXTURE_INTERNAL_FORMAT #include +#if QT_VERSION >= 0x060000 +#include +#endif + #endif // QT_NO_OPENGL diff --git a/generator/setupgenerator.cpp b/generator/setupgenerator.cpp index f7eb31d0..e22c6325 100644 --- a/generator/setupgenerator.cpp +++ b/generator/setupgenerator.cpp @@ -52,10 +52,6 @@ void SetupGenerator::addClass(const QString& package, const AbstractMetaClass *c packHash[package].append(cls); } -void maybeDeclareMetaType(QTextStream &stream, const QString &typeName, - QSet ®isteredTypeNames); -bool hasDefaultConstructor(const AbstractMetaClass *meta_class); - static QStringList getOperatorCodes(const AbstractMetaClass* cls) { QSet operatorCodes; AbstractMetaFunctionList returned; @@ -247,34 +243,11 @@ void SetupGenerator::generate() continue; std::stable_sort(list.begin(), list.end(), AbstractMetaClass::less_than); - QString packKey = pack.key(); - QString packName = pack.key(); - QStringList components = packName.split("_"); - if ((components.size() > 2) && (components.at(0) == "com") - && (components.at(1) == "trolltech")) { - // kill com.trolltech in key - components.removeAt(0); - components.removeAt(0); - } - - QString shortPackName; - foreach (QString comp, components) { - comp[0] = comp[0].toUpper(); - shortPackName += comp; - } - // add missing camel case (workaround..) - if (shortPackName == "QtWebkit") { - shortPackName = "QtWebKit"; - } else if (shortPackName == "QtXmlpatterns") { - shortPackName = "QtXmlPatterns"; - } else if (shortPackName == "QtWebenginewidgets") { - shortPackName = "QtWebEngineWidgets"; - } else if (shortPackName == "QtOpengl") { - shortPackName = "QtOpenGL"; - } else if (shortPackName == "QtUitools") { - shortPackName = "QtUiTools"; - } - + QString packKey = ShellGenerator::toFileNameBase(pack.key()); + QString packName = packKey; + QString qtPackageName = "Qt" + pack.key().split('.').back().split('_').front(); + bool isBuiltin = packKey.endsWith("_builtin"); + QString initName = qtPackageName + (isBuiltin ? "Builtin" : ""); { QString fileName(packName + "/" + packKey + "_init.cpp"); @@ -291,7 +264,7 @@ void SetupGenerator::generate() s << endl; QStringList polymorphicHandlers; - if (!packName.endsWith("_builtin")) { + if (!isBuiltin) { polymorphicHandlers = writePolymorphicHandler(s, list.at(0)->package(), classes_with_polymorphic_id, list); s << endl; } @@ -328,11 +301,7 @@ void SetupGenerator::generate() s << endl; // declare individual class creation functions - s << "void PythonQt_init_" << shortPackName << "(PyObject* module) {" << endl; - - if (shortPackName.endsWith("Builtin")) { - shortPackName = shortPackName.mid(0, shortPackName.length()-strlen("builtin")); - } + s << "void PythonQt_init_" << initName << "(PyObject* module) {" << endl; foreach (const AbstractMetaClass *cls, list) { if (cls->qualifiedCppName().contains("Ssl")) { @@ -367,10 +336,12 @@ void SetupGenerator::generate() operatorCodes = "0"; } if (cls->isQObject()) { - s << "PythonQt::priv()->registerClass(&" << cls->qualifiedCppName() << "::staticMetaObject, \"" << shortPackName <<"\", PythonQtCreateObjectname() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl; + s << "PythonQt::priv()->registerClass(&" << cls->qualifiedCppName() << "::staticMetaObject, \"" << qtPackageName <<"\", PythonQtCreateObjectname() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl; + } else if (cls->isGlobalNamespace()) { + s << "PythonQt::priv()->registerGlobalNamespace(\"" << cls->qualifiedCppName() << "\", \"" << qtPackageName << "\", PythonQtCreateObjectname() << ">, PythonQtWrapper_" << cls->name() << "::staticMetaObject, module); " << endl; } else { QString baseName = cls->baseClass()?cls->baseClass()->qualifiedCppName():""; - s << "PythonQt::priv()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << shortPackName <<"\", PythonQtCreateObjectname() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl; + s << "PythonQt::priv()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << qtPackageName <<"\", PythonQtCreateObjectname() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl; } for (AbstractMetaClass* interface : cls->interfaces()) { // the interface might be our own class... (e.g. QPaintDevice) diff --git a/generator/shellgenerator.cpp b/generator/shellgenerator.cpp index fa7a0672..0b4fa0c4 100644 --- a/generator/shellgenerator.cpp +++ b/generator/shellgenerator.cpp @@ -50,8 +50,6 @@ bool ShellGenerator::shouldGenerate(const AbstractMetaClass *meta_class) const { uint cg = meta_class->typeEntry()->codeGeneration(); - // ignore the "Global" namespace, which contains the QtMsgType enum - if (meta_class->name().startsWith("Global")) return false; return ((cg & TypeEntry::GenerateCode) != 0); } diff --git a/generator/shellgenerator.h b/generator/shellgenerator.h index 1699b780..26b4c1ea 100644 --- a/generator/shellgenerator.h +++ b/generator/shellgenerator.h @@ -53,7 +53,7 @@ class ShellGenerator : public Generator public: virtual QString subDirectoryForClass(const AbstractMetaClass *cls) const { - return "generated_cpp/" + cls->package().replace(".", "_") + "/"; + return "generated_cpp/" + toFileNameBase(cls->package()) + "/"; } void writeTypeInfo(QTextStream &s, const AbstractMetaType *type, Option option = NoOption, TypeSystem::Ownership ownership = TypeSystem::InvalidOwnership); @@ -95,7 +95,9 @@ class ShellGenerator : public Generator static bool isBuiltIn(const QString& name); static bool isSpecialStreamingOperator(const AbstractMetaFunction *fun); - + + static QString toFileNameBase(QString packageName) { return packageName.replace('.', '_').toLower(); } + static void writeInclude(QTextStream &stream, const Include &inc); // this scope is used in writeFunctionArguments diff --git a/generator/shellheadergenerator.cpp b/generator/shellheadergenerator.cpp index b0a5c70a..20431a83 100644 --- a/generator/shellheadergenerator.cpp +++ b/generator/shellheadergenerator.cpp @@ -102,9 +102,10 @@ void ShellHeaderGenerator::write(QTextStream& s, const AbstractMetaClass* meta_c { setCurrentScope(meta_class); QString builtIn = ShellGenerator::isBuiltIn(meta_class->name()) ? "_builtin" : ""; - QString pro_file_name = meta_class->package().replace(".", "_") + builtIn + "/" + meta_class->package().replace(".", "_") + builtIn + ".pri"; + QString fileBaseName = toFileNameBase(meta_class->package() + builtIn); + QString pro_file_name = fileBaseName + "/" + fileBaseName + ".pri"; priGenerator->addHeader(pro_file_name, fileNameForClass(meta_class)); - setupGenerator->addClass(meta_class->package().replace(".", "_") + builtIn, meta_class); + setupGenerator->addClass(meta_class->package() + builtIn, meta_class); QString include_block = "PYTHONQTWRAPPER_" + meta_class->name().toUpper() + "_H"; @@ -311,7 +312,8 @@ void ShellHeaderGenerator::write(QTextStream& s, const AbstractMetaClass* meta_c bool isEnumClass = enum1->typeEntry()->isEnumClass(); s << "enum " << (isEnumClass ? "class " : "") << enum1->name() << "{" << endl; bool first = true; - QString scope = enum1->wasProtected() ? promoterClassName(meta_class) : meta_class->qualifiedCppName(); + QString scope = meta_class->isGlobalNamespace() ? QString() : + (enum1->wasProtected() ? promoterClassName(meta_class) : meta_class->qualifiedCppName()); if (isEnumClass) { scope += "::" + enum1->name(); } diff --git a/generator/shellimplgenerator.cpp b/generator/shellimplgenerator.cpp index b4ee83f3..2145af03 100644 --- a/generator/shellimplgenerator.cpp +++ b/generator/shellimplgenerator.cpp @@ -73,7 +73,8 @@ void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_cla setCurrentScope(meta_class); QString builtIn = ShellGenerator::isBuiltIn(meta_class->name())?"_builtin":""; - QString pro_file_name = meta_class->package().replace(".", "_") + builtIn + "/" + meta_class->package().replace(".", "_") + builtIn + ".pri"; + QString fileBaseName = toFileNameBase(meta_class->package() + builtIn); + QString pro_file_name = fileBaseName + "/" + fileBaseName + ".pri"; priGenerator->addSource(pro_file_name, fileNameForClass(meta_class)); s << "#include \"PythonQtWrapper_" << meta_class->name() << ".h\"" << endl << endl; diff --git a/generator/typesystem.cpp b/generator/typesystem.cpp index ae8111c4..c9a2607f 100644 --- a/generator/typesystem.cpp +++ b/generator/typesystem.cpp @@ -1509,14 +1509,27 @@ TypeDatabase *TypeDatabase::instance() TypeDatabase::TypeDatabase() : m_suppressWarnings(true) { - addType(new StringTypeEntry("QString")); + StringTypeEntry* mainStringType = new StringTypeEntry("QString"); + addType(mainStringType); StringTypeEntry *e = new StringTypeEntry("QLatin1String"); e->setPreferredConversion(false); + e->setEquivalentType(mainStringType); addType(e); e = new StringTypeEntry("QStringRef"); e->setPreferredConversion(false); + e->setEquivalentType(mainStringType); + addType(e); + + e = new StringTypeEntry("QStringView"); + e->setPreferredConversion(false); + e->setEquivalentType(mainStringType); + addType(e); + + e = new StringTypeEntry("QAnyStringView"); + e->setPreferredConversion(false); + e->setEquivalentType(mainStringType); addType(e); e = new StringTypeEntry("QXmlStreamStringRef"); @@ -1560,6 +1573,19 @@ TypeDatabase::TypeDatabase() : m_suppressWarnings(true) addRemoveFunctionToTemplates(this); } +void TypeDatabase::finalSetup() +{ + TypeEntry* byteArrayType = findType("QByteArray"); + if (byteArrayType) { + // Support QByteArrayView as alternative parameter type. + // Using StringTypeEntry for it, because no wrappers are generated for those types + StringTypeEntry* e = new StringTypeEntry("QByteArrayView"); + e->setPreferredConversion(false); + e->setEquivalentType(byteArrayType); + addType(e); + } +} + bool TypeDatabase::parseFile(const QString &filename, unsigned int qtVersion, bool generate) { QFile file(filename); @@ -1809,8 +1835,9 @@ FlagsTypeEntry *TypeDatabase::findFlagsType(const QString &name) const return fte ? fte : (FlagsTypeEntry *) m_flags_entries.value(name); } -QString TypeDatabase::globalNamespaceClassName(const TypeEntry * /*entry*/) { - return QLatin1String("Global"); +QString TypeDatabase::globalNamespaceClassName(const TypeEntry * entry) +{ + return "Qt" + entry->javaPackage().split('.').back(); } diff --git a/generator/typesystem.h b/generator/typesystem.h index a68850d8..a6d8b4cb 100644 --- a/generator/typesystem.h +++ b/generator/typesystem.h @@ -549,6 +549,8 @@ class TypeEntry virtual bool isNativeIdBased() const { return false; } + virtual TypeEntry* equivalentType() const { return nullptr; } + private: QString m_name; Type m_type; @@ -1013,8 +1015,14 @@ class ValueTypeEntry : public ComplexTypeEntry virtual bool isNativeIdBased() const { return true; } + virtual TypeEntry* equivalentType() const { return _equivalentType; } + void setEquivalentType(TypeEntry* typeEntry) { _equivalentType = typeEntry; } + protected: ValueTypeEntry(const QString &name, Type t) : ComplexTypeEntry(name, t) { } + +private: + TypeEntry* _equivalentType{}; }; @@ -1226,6 +1234,7 @@ class TypeDatabase QString filename() const { return "typesystem.txt"; } bool parseFile(const QString &filename, unsigned int qtVersion, bool generate = true); + void finalSetup(); private: bool m_suppressWarnings; diff --git a/generator/typesystem_core.xml b/generator/typesystem_core.xml index 32d68413..6fe37a3d 100644 --- a/generator/typesystem_core.xml +++ b/generator/typesystem_core.xml @@ -1,5 +1,5 @@ - + @@ -19,21 +19,38 @@ + + + + + + + + + + + + + + + + + @@ -203,6 +220,8 @@ + + @@ -220,6 +239,7 @@ + @@ -241,6 +261,7 @@ + @@ -416,6 +437,8 @@ + + @@ -444,43 +467,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/generator/typesystem_gui.xml b/generator/typesystem_gui.xml index 80364fc9..dd772ca8 100644 --- a/generator/typesystem_gui.xml +++ b/generator/typesystem_gui.xml @@ -1,5 +1,5 @@ - + @@ -22,11 +22,13 @@ + + @@ -84,6 +86,7 @@ + @@ -104,6 +107,7 @@ + @@ -156,13 +160,15 @@ + + - + @@ -390,6 +396,8 @@ + + @@ -451,6 +459,7 @@ + @@ -525,8 +534,8 @@ - - + + @@ -614,6 +623,7 @@ + @@ -640,6 +650,7 @@ + @@ -730,6 +741,7 @@ + @@ -771,6 +783,7 @@ + @@ -889,6 +902,7 @@ + @@ -1117,6 +1131,7 @@ PyObject* constScanLine(QImage* image, int line) { + @@ -1323,6 +1338,7 @@ PyObject* constScanLine(QImage* image, int line) { + @@ -2525,6 +2541,7 @@ PyObject* constScanLine(QImage* image, int line) { + @@ -2932,6 +2949,7 @@ PyObject* constScanLine(QImage* image, int line) { + @@ -3074,6 +3092,7 @@ PyObject* constScanLine(QImage* image, int line) { + @@ -3092,6 +3111,8 @@ PyObject* constScanLine(QImage* image, int line) { + + @@ -3112,6 +3133,9 @@ PyObject* constScanLine(QImage* image, int line) { + @@ -3171,6 +3195,15 @@ PyObject* constScanLine(QImage* image, int line) { + + + + + + + + + diff --git a/generator/typesystem_multimedia.xml b/generator/typesystem_multimedia.xml index d4f1a984..6c719988 100644 --- a/generator/typesystem_multimedia.xml +++ b/generator/typesystem_multimedia.xml @@ -1,5 +1,5 @@ - + @@ -7,6 +7,8 @@ + + @@ -126,11 +128,14 @@ + + + @@ -193,14 +198,14 @@ - + - + @@ -209,7 +214,7 @@ - + diff --git a/generator/typesystem_network.xml b/generator/typesystem_network.xml index 2b0a4b95..239c574d 100644 --- a/generator/typesystem_network.xml +++ b/generator/typesystem_network.xml @@ -1,14 +1,10 @@ - + - - - - @@ -81,6 +77,7 @@ + @@ -88,6 +85,7 @@ + @@ -110,8 +108,6 @@ - - @@ -172,8 +168,6 @@ - - @@ -191,6 +185,8 @@ + + @@ -230,6 +226,23 @@ + + + + + + + + + + + + + + + + + diff --git a/generator/typesystem_opengl.xml b/generator/typesystem_opengl.xml index c0c6d851..b8de602c 100644 --- a/generator/typesystem_opengl.xml +++ b/generator/typesystem_opengl.xml @@ -1,7 +1,6 @@ - - - + + diff --git a/generator/typesystem_qml.xml b/generator/typesystem_qml.xml index ebc664fd..60db1e5e 100644 --- a/generator/typesystem_qml.xml +++ b/generator/typesystem_qml.xml @@ -1,20 +1,46 @@ - + + + + + + + + + - + + + + + + + + + + + + + + + + + + + diff --git a/generator/typesystem_quick.xml b/generator/typesystem_quick.xml index bd255e68..ac889ecc 100644 --- a/generator/typesystem_quick.xml +++ b/generator/typesystem_quick.xml @@ -1,5 +1,5 @@ - + @@ -29,9 +29,16 @@ - + + - + + + + + + + diff --git a/generator/typesystem_sql.xml b/generator/typesystem_sql.xml index f3377411..334860d8 100644 --- a/generator/typesystem_sql.xml +++ b/generator/typesystem_sql.xml @@ -1,5 +1,5 @@ - + diff --git a/generator/typesystem_svg.xml b/generator/typesystem_svg.xml index 06d9f565..c4e5a6a7 100644 --- a/generator/typesystem_svg.xml +++ b/generator/typesystem_svg.xml @@ -1,5 +1,5 @@ - + diff --git a/generator/typesystem_uitools.xml b/generator/typesystem_uitools.xml index 1b2c2edb..9b5b3b9d 100644 --- a/generator/typesystem_uitools.xml +++ b/generator/typesystem_uitools.xml @@ -1,4 +1,4 @@ - + diff --git a/generator/typesystem_webenginewidgets.xml b/generator/typesystem_webenginewidgets.xml index 53fa87d5..e89b61c9 100644 --- a/generator/typesystem_webenginewidgets.xml +++ b/generator/typesystem_webenginewidgets.xml @@ -1,18 +1,22 @@ - + + + + + - + @@ -22,6 +26,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/generator/typesystem_webkit.xml b/generator/typesystem_webkit.xml index b1a4eb7f..84ba47e4 100644 --- a/generator/typesystem_webkit.xml +++ b/generator/typesystem_webkit.xml @@ -1,5 +1,5 @@ - + diff --git a/generator/typesystem_xml.xml b/generator/typesystem_xml.xml index 5fbba69e..27d8f24f 100644 --- a/generator/typesystem_xml.xml +++ b/generator/typesystem_xml.xml @@ -1,5 +1,6 @@ - + + @@ -36,6 +37,7 @@ + @@ -180,6 +182,7 @@ + diff --git a/generator/typesystem_xmlpatterns.xml b/generator/typesystem_xmlpatterns.xml index 958ddfac..c61126d9 100644 --- a/generator/typesystem_xmlpatterns.xml +++ b/generator/typesystem_xmlpatterns.xml @@ -1,6 +1,5 @@ - - + @@ -112,6 +111,8 @@ + + diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index 8ff82ab6..3302854b 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -122,16 +122,14 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) } else { qRegisterMetaType("size_t"); } -#if QT_VERSION < 0x060000 - int stringRefId = qRegisterMetaType("QStringRef"); - PythonQtConv::registerMetaTypeToPythonConverter(stringRefId, PythonQtConv::convertFromStringRef); -#endif + PythonQtConv::registerStringViewTypes(); int objectPtrListId = qRegisterMetaType >("QList"); PythonQtConv::registerMetaTypeToPythonConverter(objectPtrListId, PythonQtConv::convertFromQListOfPythonQtObjectPtr); PythonQtConv::registerPythonToMetaTypeConverter(objectPtrListId, PythonQtConv::convertToQListOfPythonQtObjectPtr); PythonQtRegisterToolClassesTemplateConverter(int); + PythonQtRegisterToolClassesTemplateConverter(bool); PythonQtRegisterToolClassesTemplateConverter(float); PythonQtRegisterToolClassesTemplateConverter(double); PythonQtRegisterToolClassesTemplateConverter(qint32); @@ -262,6 +260,9 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) PythonQtRegisterToolClassesTemplateConverterForKnownClass(QPen); PythonQtRegisterToolClassesTemplateConverterForKnownClass(QTextLength); PythonQtRegisterToolClassesTemplateConverterForKnownClass(QTextFormat); +#if QT_VERSION < 0x060000 + PythonQtRegisterToolClassesTemplateConverterForKnownClass(QMatrix); +#endif PyObject* pack = PythonQt::priv()->packageByName("QtCore"); PyObject* pack2 = PythonQt::priv()->packageByName("Qt"); @@ -2112,6 +2113,73 @@ void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentT } } +namespace { + + void addObjectToPackage(PyObject* obj, const char* name, const char* packageName, PyObject* package) + { + if (PyModule_AddObject(package, name, obj) < 0) { + Py_DECREF(obj); + std::cerr << "failed to add " << name << " to " << packageName << "\n"; + } + } + +}; + +void PythonQtPrivate::registerGlobalNamespace(const char* typeName, const char* packageName, PythonQtQObjectCreatorFunctionCB* wrapperCreator, const QMetaObject& metaObject, PyObject* module) +{ + registerCPPClass(typeName, "", packageName, wrapperCreator, nullptr, module, 0); + + PyObject* package = module ? module : PythonQt::priv()->packageByName(packageName); + PythonQtClassInfo* classInfo = PythonQt::priv()->getClassInfo(typeName); + PyObject* globalNamespace = classInfo->pythonQtClassWrapper(); + + // Collect the names of global methods + QSet methodNames; + for (int i = metaObject.methodOffset(); i < metaObject.methodCount(); i++) { + methodNames.insert(metaObject.method(i).name()); + } + QByteArray staticPrefix = "static_" + QByteArray(typeName) + "_"; // every static method starts with this string + for (auto name: methodNames) { + if (name.startsWith(staticPrefix)) { // non-static methods wouldn't work (and should not exists) + name = name.mid(staticPrefix.length()); + PyObject* obj = PyObject_GetAttrString(globalNamespace, name.constData()); + if (obj) { + addObjectToPackage(obj, name, packageName, package); + } + else { + std::cerr << "method not found " << name.constData() << " in " << typeName << std::endl; + } + } + } + + // Global enums + for (int i = metaObject.enumeratorOffset(); i < metaObject.enumeratorCount(); i++) { + QMetaEnum metaEnum = metaObject.enumerator(i); + PyObject* obj = PyObject_GetAttrString(globalNamespace, metaEnum.name()); + if (obj) { + addObjectToPackage(obj, metaEnum.name(), packageName, package); + } + else { + std::cerr << "enum type not found " << metaEnum.name() << " in " << typeName << std::endl; + } +#if QT_VERSION > 0x050800 + bool isScoped = metaEnum.isScoped(); +#else + bool isScoped = false; +#endif + if (!isScoped) { + for (int j = 0; j < metaEnum.keyCount(); j++) { + QByteArray key = PythonQtClassInfo::escapeReservedNames(metaEnum.key(j)); + int value = metaEnum.value(j); + PyObject* obj = PyInt_FromLong(value); + addObjectToPackage(obj, key, packageName, package); + } + } + } + + PythonQtClassInfo::addGlobalNamespaceWrapper(classInfo); +} + PyObject* PythonQtPrivate::packageByName(const char* name) { if (name==nullptr || name[0]==0) { diff --git a/src/PythonQt.h b/src/PythonQt.h index 767f9928..d7de9233 100644 --- a/src/PythonQt.h +++ b/src/PythonQt.h @@ -754,6 +754,9 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject { */ void registerCPPClass(const char* typeName, const char* parentTypeName = nullptr, const char* package = nullptr, PythonQtQObjectCreatorFunctionCB* wrapperCreator = nullptr, PythonQtShellSetInstanceWrapperCB* shell = nullptr, PyObject* module = nullptr, int typeSlots = 0); + //! Same as above, but all enums of the created wrapper will also be added to the given package and to the "Qt" package + void registerGlobalNamespace(const char* typeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, const QMetaObject& metaObject, PyObject* module = nullptr); + //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes //! and it will register the classes when it first sees a pointer to such a derived class void registerQObjectClassNames(const QStringList& names); diff --git a/src/PythonQtClassInfo.cpp b/src/PythonQtClassInfo.cpp index b2013b8a..c132b211 100644 --- a/src/PythonQtClassInfo.cpp +++ b/src/PythonQtClassInfo.cpp @@ -49,6 +49,14 @@ QHash PythonQtMethodInfo::_parameterTypeDict; +// List of registered global namespace wrappers that might contain a top-level enum definition +QList PythonQtClassInfo::_globalNamespaceWrappers; + +// List of words that are reserved in Python, but not in C++, so they need escaping +QSet PythonQtClassInfo::_reservedNames{ + "None", "True", "False" +}; + PythonQtClassInfo::PythonQtClassInfo() { _meta = nullptr; _constructors = nullptr; @@ -282,7 +290,7 @@ bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* continue; } for (int j=0; j < e.keyCount(); j++) { - if (qstrcmp(e.key(j), memberName)==0) { + if (escapeReservedNames(e.key(j)) == memberName) { PyObject* enumType = findEnumWrapper(e.name()); if (enumType) { PythonQtObjectPtr enumValuePtr; @@ -554,7 +562,7 @@ QStringList PythonQtClassInfo::memberList() } } -#if QT_VERSION >= 0x060000 +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) QSet set(l.begin(), l.end()); return set.values(); #else @@ -846,11 +854,20 @@ PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtCla return nullptr; } } + PyObject* enumWrapper = nullptr; if (localScope) { - return localScope->findEnumWrapper(name); - } else { - return nullptr; + enumWrapper = localScope->findEnumWrapper(name); + } + if (!enumWrapper) { + // it might be a top-level enum - search in all currently registered global namespace wrappers + for (PythonQtClassInfo* globalWrapper : _globalNamespaceWrappers) { + enumWrapper = globalWrapper->findEnumWrapper(name); + if (enumWrapper) { + break; + } + } } + return enumWrapper; } void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta) @@ -859,6 +876,13 @@ void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta) QMetaEnum e = meta->enumerator(i); PythonQtObjectPtr p; p.setNewRef(PythonQtPrivate::createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper)); + // add enum values to the enum type itself, in case enum value names are so generic + // that they are not unique + for (int j = 0; j < e.keyCount(); j++) { + PythonQtObjectPtr enumValuePtr; + enumValuePtr.setNewRef(PythonQtPrivate::createEnumValueInstance(p.object(), e.value(j))); + p.addVariable(escapeReservedNames(e.key(j)), enumValuePtr.toLocalVariant()); + } _enumWrappers.append(p); } } @@ -1004,6 +1028,21 @@ PythonQtVoidPtrCB* PythonQtClassInfo::referenceCountingUnrefCB() return _unrefCallback; } +QByteArray PythonQtClassInfo::escapeReservedNames(const QByteArray& name) +{ + if (_reservedNames.contains(name)) { + return name + "_"; + } + else { + return name; + } +} + +void PythonQtClassInfo::addGlobalNamespaceWrapper(PythonQtClassInfo* namespaceWrapper) +{ + _globalNamespaceWrappers.insert(0, namespaceWrapper); +} + void PythonQtClassInfo::updateRefCountingCBs() { if (!_refCallback) { diff --git a/src/PythonQtClassInfo.h b/src/PythonQtClassInfo.h index 5e3faf54..fa439f5d 100644 --- a/src/PythonQtClassInfo.h +++ b/src/PythonQtClassInfo.h @@ -237,6 +237,13 @@ class PYTHONQT_EXPORT PythonQtClassInfo { //! _typeSlots with Type_RichCompare. The result is cached internally. bool supportsRichCompare(); + //! Sometimes enum values use a reserved name in Python. In this case + //! replace it with something that is not reserved + static QByteArray escapeReservedNames(const QByteArray& name); + + //! Add a wrapper that contains global enums + static void addGlobalNamespaceWrapper(PythonQtClassInfo* namespaceWrapper); + private: void updateRefCountingCBs(); @@ -300,6 +307,9 @@ class PYTHONQT_EXPORT PythonQtClassInfo { bool _searchPolymorphicHandlerOnParent; bool _searchRefCountCB; + static QList _globalNamespaceWrappers; + + static QSet _reservedNames; }; //--------------------------------------------------------------- diff --git a/src/PythonQtClassWrapper.cpp b/src/PythonQtClassWrapper.cpp index ad8f5064..d4ab7d4c 100644 --- a/src/PythonQtClassWrapper.cpp +++ b/src/PythonQtClassWrapper.cpp @@ -465,7 +465,7 @@ static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) auto members = wrapper->classInfo()->memberList(); auto properties = wrapper->classInfo()->propertyList(); -#if QT_VERSION >= 0x060000 +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) QSet completeSet(members.begin(), members.end()); completeSet.unite(QSet(properties.begin(), properties.end())); #else diff --git a/src/PythonQtConversion.cpp b/src/PythonQtConversion.cpp index f47506fd..285cece4 100644 --- a/src/PythonQtConversion.cpp +++ b/src/PythonQtConversion.cpp @@ -48,6 +48,22 @@ #include #include +#if QT_VERSION < 0x060000 +#include + +Q_DECLARE_METATYPE(QStringRef) + +int PythonQtConv::stringRefTypeId = 0; +#else +#include +#include +#include + +int PythonQtConv::stringViewTypeId = 0; +int PythonQtConv::anyStringViewTypeId = 0; +int PythonQtConv::byteArrayViewTypeId = 0; +#endif + QHash PythonQtConv::_metaTypeToPythonConverters; QHash PythonQtConv::_pythonToMetaTypeConverters; @@ -385,6 +401,9 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) && info.typeId != PythonQtMethodInfo::Variant && +#if QT_VERSION >= 0x060000 + info.typeId != byteArrayViewTypeId && // this case is handled later on +#endif !PythonQt::priv()->isPythonQtAnyObjectPtrMetaId(info.typeId)) { // if we have a Qt wrapper object and if we do not need a QVariant, we do the following: // (the Variant case is handled below in a switch) @@ -583,13 +602,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i break; case QMetaType::QByteArray: { - QByteArray bytes = PyObjGetBytes(obj, strict, ok); - if (!ok && !strict) { - // since Qt uses QByteArray in many places for identifier strings, - // we need to allow implicit conversion from unicode as well. - // We allow that for both Python 2.x and 3.x to be compatible. - bytes = PyObjGetString(obj, true, ok).toUtf8(); - } + QByteArray bytes = PyObjGetBytesAllowString(obj, strict, ok); if (ok) { PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, QVariant(bytes), ptr); ptr = (void*)((QVariant*)ptr)->constData(); @@ -633,19 +646,85 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i // we have a exact enum type match: val = PyInt_AS_LONG(obj); ok = true; - } else if (!strict) { + } + else if (!strict) { // we try to get any integer, when not being strict. If we are strict, integers are not wanted because // we want an integer overload to be taken first! val = (unsigned int)PyObjGetLongLong(obj, false, ok); } if (ok) { - PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, unsigned int, val, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, unsigned int, val, ptr); return ptr; - } else { + } + else { return nullptr; } } + // Handle QStringView et al, which need a reference to a persistent QString +#if QT_VERSION < 0x060000 + if (info.typeId == stringRefTypeId) { + QString str = PyObjGetString(obj, strict, ok); + if (ok) { + void* ptr2 = nullptr; + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(nullptr, frame, QVariant(str), ptr2); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, + QVariant::fromValue(QStringRef((const QString*)((QVariant*)ptr2)->constData())), ptr); + ptr = (void*)((QVariant*)ptr)->constData(); + return ptr; + } + else { + return nullptr; + } + } +#else + if (info.typeId == stringViewTypeId) { + // Handle QStringView, which needs a reference to a persistent QString + QString str = PyObjGetString(obj, strict, ok); + if (ok) { + void* ptr2 = nullptr; + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(nullptr, frame, QVariant(str), ptr2); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, + QVariant::fromValue(QStringView(*((const QString*)((QVariant*)ptr2)->constData()))), ptr); + ptr = (void*)((QVariant*)ptr)->constData(); + return ptr; + } + else { + return nullptr; + } + } + else if (info.typeId == anyStringViewTypeId) { + // Handle QAnyStringView, which needs a reference to a persistent QString + QString str = PyObjGetString(obj, strict, ok); + if (ok) { + void* ptr2 = nullptr; + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(nullptr, frame, QVariant(str), ptr2); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, + QVariant::fromValue(QAnyStringView(*((const QString*)((QVariant*)ptr2)->constData()))), ptr); + ptr = (void*)((QVariant*)ptr)->constData(); + return ptr; + } + else { + return nullptr; + } + } + else if (info.typeId == byteArrayViewTypeId) { + // Handle QByteArrayView, which needs a reference to a persistent QByteArray + QByteArray ba = PyObjGetBytesAllowString(obj, strict, ok); + if (ok) { + void* ptr2 = nullptr; + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(nullptr, frame, QVariant(ba), ptr2); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, + QVariant::fromValue(QByteArrayView(*((const QByteArray*)((QVariant*)ptr2)->constData()))), ptr); + ptr = (void*)((QVariant*)ptr)->constData(); + return ptr; + } + else { + return nullptr; + } + } +#endif + if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) { // check for QList case, where we will use a QList QVariant if (info.isQList && (info.innerNamePointerCount == 1)) { @@ -783,6 +862,15 @@ QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) // TODO: support buffer objects in general QByteArray r; ok = true; + if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) { + // check if we already have a QByteArray wrapper here + PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)val; + bool baOk; + QByteArray* baPtr = (QByteArray*)castWrapperTo(wrapper, "QByteArray", baOk); + if (baOk && baPtr) { + return *baPtr; + } + } if (PyBytes_Check(val)) { r = QByteArray(PyBytes_AS_STRING(val), PyBytes_GET_SIZE(val)); } else { @@ -791,6 +879,18 @@ QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) return r; } +QByteArray PythonQtConv::PyObjGetBytesAllowString(PyObject* val, bool strict, bool& ok) +{ + QByteArray bytes = PyObjGetBytes(val, strict, ok); + if (!ok && !strict) { + // since Qt uses QByteArray in many places for identifier strings, + // we need to allow implicit conversion from unicode as well. + // We allow that for both Python 2.x and 3.x to be compatible. + bytes = PyObjGetString(val, true, ok).toUtf8(); + } + return bytes; +} + bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) { bool d = false; ok = false; @@ -1497,7 +1597,23 @@ PyObject* PythonQtConv::createCopyFromMetaType( int type, const void* data ) #if QT_VERSION < 0x060000 PyObject* PythonQtConv::convertFromStringRef(const void* inObject, int /*metaTypeId*/) { - return PythonQtConv::QStringToPyObject(((QStringRef*)inObject)->toString()); + return QStringToPyObject(((QStringRef*)inObject)->toString()); +} +#else +PyObject* PythonQtConv::convertFromStringView(const void* inObject, int /*metaTypeId*/) +{ + return QStringToPyObject(((QStringView*)inObject)->toString()); +} + +PyObject* PythonQtConv::convertFromAnyStringView(const void* inObject, int /*metaTypeId*/) +{ + return QStringToPyObject(((QAnyStringView*)inObject)->toString()); +} + +PyObject* PythonQtConv::convertFromByteArrayView(const void* inObject, int) +{ + QByteArray ba = ((QByteArrayView*)inObject)->toByteArray(); + return createCopyFromMetaType(QMetaType::QByteArray, &ba); } #endif @@ -1551,6 +1667,21 @@ bool PythonQtConv::isStringType(PyTypeObject* type) #endif } +void PythonQtConv::registerStringViewTypes() +{ +#if QT_VERSION < 0x060000 + stringRefTypeId = qRegisterMetaType("QStringRef"); + PythonQtConv::registerMetaTypeToPythonConverter(stringRefTypeId, PythonQtConv::convertFromStringRef); +#else + stringViewTypeId = qRegisterMetaType("QStringView"); + PythonQtConv::registerMetaTypeToPythonConverter(stringViewTypeId, PythonQtConv::convertFromStringView); + anyStringViewTypeId = qRegisterMetaType("QAnyStringView"); + PythonQtConv::registerMetaTypeToPythonConverter(anyStringViewTypeId, PythonQtConv::convertFromAnyStringView); + byteArrayViewTypeId = qRegisterMetaType("QByteArrayView"); + PythonQtConv::registerMetaTypeToPythonConverter(byteArrayViewTypeId, PythonQtConv::convertFromByteArrayView); +#endif +} + PyObject* PythonQtConv::convertFromQListOfPythonQtObjectPtr(const void* inObject, int /*metaTypeId*/) { QList& list = *((QList*)inObject); diff --git a/src/PythonQtConversion.h b/src/PythonQtConversion.h index 7876b652..d0f0eeb1 100644 --- a/src/PythonQtConversion.h +++ b/src/PythonQtConversion.h @@ -132,6 +132,8 @@ class PYTHONQT_EXPORT PythonQtConv { static QString PyObjGetString(PyObject* val, bool strict, bool &ok); //! get bytes from py object static QByteArray PyObjGetBytes(PyObject* val, bool strict, bool &ok); + //! get bytes from py object, also allows Python string + static QByteArray PyObjGetBytesAllowString(PyObject* val, bool strict, bool& ok); //! get int from py object static int PyObjGetInt(PyObject* val, bool strict, bool &ok); //! get int64 from py object @@ -187,6 +189,10 @@ class PYTHONQT_EXPORT PythonQtConv { static PyObject* convertFromQListOfPythonQtObjectPtr(const void* /* QList* */ inObject, int /*metaTypeId*/); #if QT_VERSION < 0x060000 static PyObject* convertFromStringRef(const void* inObject, int /*metaTypeId*/); +#else + static PyObject* convertFromStringView(const void* inObject, int /*metaTypeId*/); + static PyObject* convertFromAnyStringView(const void* inObject, int /*metaTypeId*/); + static PyObject* convertFromByteArrayView(const void* inObject, int /*metaTypeId*/); #endif //! Returns the name of the equivalent CPP type (for signals and slots) @@ -195,6 +201,9 @@ class PYTHONQT_EXPORT PythonQtConv { //! Returns if the given object is a string (or unicode string) static bool isStringType(PyTypeObject* type); + //! Register QStringView like types, that need to be handled specially + static void registerStringViewTypes(); + protected: static QHash _metaTypeToPythonConverters; static QHash _pythonToMetaTypeConverters; @@ -215,6 +224,13 @@ class PYTHONQT_EXPORT PythonQtConv { template static PyObject* mapToPython (const Map& m); +#if QT_VERSION < 0x060000 + static int stringRefTypeId; +#else + static int stringViewTypeId; + static int anyStringViewTypeId; + static int byteArrayViewTypeId; +#endif }; template @@ -273,7 +289,7 @@ PyObject* PythonQtConvertListOfKnownClassToPythonList(const void* /*QList* */ ListType* list = (ListType*)inList; static PythonQtClassInfo* innerType = PythonQt::priv()->getClassInfo(PythonQtMethodInfo::getInnerListTypeName(QByteArray(QMetaType::typeName(metaTypeId)))); if (innerType == nullptr) { - std::cerr << "PythonQtConvertListOfKnownClassToPythonList: unknown inner type " << innerType->className().constData() << std::endl; + std::cerr << "PythonQtConvertListOfKnownClassToPythonList: unknown inner type for " << QMetaType::typeName(metaTypeId) << std::endl; } PyObject* result = PyTuple_New(list->size()); int i = 0; @@ -293,7 +309,7 @@ bool PythonQtConvertPythonListToListOfKnownClass(PyObject* obj, void* /*QList ListType* list = (ListType*)outList; static PythonQtClassInfo* innerType = PythonQt::priv()->getClassInfo(PythonQtMethodInfo::getInnerListTypeName(QByteArray(QMetaType::typeName(metaTypeId)))); if (innerType == nullptr) { - std::cerr << "PythonQtConvertListOfKnownClassToPythonList: unknown inner type " << innerType->className().constData() << std::endl; + std::cerr << "PythonQtConvertListOfKnownClassToPythonList: unknown inner type for " << QMetaType::typeName(metaTypeId) << std::endl; } bool result = false; if (PySequence_Check(obj)) { diff --git a/src/PythonQtDoc.h b/src/PythonQtDoc.h index ac7d3d56..7adfe8d4 100644 --- a/src/PythonQtDoc.h +++ b/src/PythonQtDoc.h @@ -95,8 +95,8 @@ Qt framework. - Support for Qt namespace (with all enumerators) - All PythonQt wrapped objects support the dir() statement, so that you can see easily which attributes a QObject, CPP object or QVariant has - No preprocessing/wrapping tool needs to be started, PythonQt can script any QObject without prior knowledge about it (except for the MetaObject information from the \b moc) - - Multiple inheritance for C++ objects (e.g. a QWidget is derived from QObject and QPaintDevice, PythonQt will automatically cast a QWidget to a QPaintDevice when needed) - - Polymorphic downcasting (if e.g. PythonQt sees a QEvent, it can downcast it depending on the type(), so the Python e.g. sees a QPaintEvent instead of a plain QEvent) + - Multiple inheritance for C++ objects (e.g. if a QWidget is derived from QObject and QPaintDevice, PythonQt will automatically cast a QWidget to a QPaintDevice when needed) + - Polymorphic downcasting (if e.g. PythonQt sees a QEvent, it can downcast it depending on the type(), so the Python code e.g. sees a QPaintEvent instead of a plain QEvent) - Deriving C++ objects from Python and overwriting virtual method with a Python implementation (requires usage of wrapper generator or manual work!) - Extensible handler for Python/C++ conversion of complex types, e.g. mapping of QVector to/from a Python array - Setting of dynamic QObject properties via setProperty(), dynamic properties can be accessed for reading and writing like normal Python attributes (but creating a new property needs to be done with setProperty(), to distinguish from normal Python attributes) @@ -112,12 +112,13 @@ Qt framework. - QtCore - QtGui - QtNetwork - - QtOpenGL + - QtOpenGL (before Qt6) - QtSql - QtSvg - - QtWebKit + - QtWebEngineWidgets + - QtWebKit (when available) - QtXml - - QtXmlPatterns + - QtXmlPatterns (before Qt6) - QtMultimedia - QtQml - QtQuick @@ -129,18 +130,19 @@ Qt framework. \section Supported Supported Versions PythonQt supports: - - Python 2 (>= Python 2.6) - - Python 3 (>= Python 3.3) - - Qt 4.x (Qt 4.7 and Qt 4.8 recommended) - - Qt 5.x (Tested with Qt 5.0, 5.3, 5.4 and 5.6) + - Python 2 (>= Python 2.7) + - Python 3 (>= Python 3.6) + - Qt 4.x (Qt 4.7 and Qt 4.8 recommended) (not in the master branch, see below) + - Qt 5.x (Tested with Qt 5.0, 5.3, 5.4, 5.6, 5.11, 5.12 and 5.15) + - Qt 6.x (Tested with Qt 6.5 and 6.6) - support may not be complete, support for optional modules may be added as needed The last working Qt4 version is available at svn branches/Qt4LastWorkingVersion or you can download the PythonQt 3.0 release. - The current svn trunk no longer supports Qt4, since we started to make use of some Qt5-only features. + The current git master branch no longer supports Qt4, since we started to make use of some Qt5-only features. \section Comparison Comparison with PySide - PythonQt is not as pythonic as PySide in many details (e.g. buffer protocol, pickling, translation support, ...) and it is mainly thought for embedding and intercommunication between Qt/Cpp and Python - - PythonQt offers properties as Python attributes, while PySide offers them as setter/getter methods (e.g. QWidget.width is a property in PythonQt and a method in PySide) + - PythonQt offers properties as Python attributes, while PySide offers them as setter/getter methods (e.g. QWidget.width is a property in PythonQt and a method in PySide, though in PySide6 in can also be made a property) - PythonQt currently does not support instanceof checks for Qt classes, except for the exact match and derived Python classes - QObject.emit to emit Qt signals from Python is not yet implemented but PythonQt allows to just emit a signal by calling it like a normal slot - Ownership handling of objects is not as complete as in PySide and PySide, especially in situations where the ownership is not clearly passed to C++ on the C++ API. @@ -169,7 +171,7 @@ Qt framework. The PythonQt wrappers generated by the generator located in the "generated_cpp" directory are free to be used without any licensing restrictions. - The generated wrappers are pre-generated and checked-in for 5.0, 5.3, 5.4 and 5.6, so you only need to build and run the + The generated wrappers are pre-generated and checked-in for 5.0, 5.3, 5.4, 5.6 and 5.11, so you only need to build and run the generator when you want to build additional wrappers or you want to upgrade/downgrade to another Qt version. You may use the generator to generate C++ bindings for your own C++ classes (e.g., to make them inheritable in Python), but this is currently not documented and involves creating your own typesystem files. @@ -196,13 +198,13 @@ Qt framework. char/uchar,int/uint,short,ushort,QCharinteger longinteger ulong,longlong,ulonglonglong - QStringunicode string - QByteArrayQByteArray wrapper \ref qbytearray-bytes "(1)" + QString \ref qstring "(1)"unicode string + QByteArray \ref qbytearray "(2)"QByteArray wrapper \ref qbytearray-bytes "(3)" char*str QStringListtuple of unicode strings QVariantListtuple of objects QVariantMapdict of objects - QVariantdepends on type \ref qvariant "(2)" + QVariantdepends on type \ref qvariant "(4)" QSize, QRect and all other standard Qt QVariantsvariant wrapper that supports complete API of the respective Qt classes OwnRegisteredMetaTypeC++ wrapper, optionally with additional information/wrapping provided by registerCPPClass() QListconverts to a list of CPP wrappers @@ -210,9 +212,11 @@ Qt framework. EnumTypeEnum wrapper derived from python integer QObject (and derived classes)QObject wrapper C++ objectCPP wrapper, either wrapped via PythonQtCppWrapperFactory or just decorated with decorators - PyObjectPyObject \ref pyobject "(3)" + PyObjectPyObject \ref pyobject "(5)" + -# \anchor qstring QStringRef (Qt5), QStringView and QAnyStringView (Qt6) are handled like QString. + -# \anchor qbytearray QByteArrayView (Qt6) is handled like QByteArray. -# \anchor qbytearray-bytes The Python 'bytes' type will automatically be converted to QByteArray where required. For converting a QByteArray to 'bytes' use the .data() method. -# \anchor qvariant QVariants are mapped recursively as given above, e.g. a dictionary can contain lists of dictionaries of doubles. @@ -241,7 +245,7 @@ Qt framework. properties of the objects as if they where normal python properties. In addition to this, the wrapped objects support - - className() - returns a string that reprents the classname of the QObject + - className() - returns a string that represents the classname of the QObject - help() - shows all properties, slots, enums, decorator slots and constructors of the object, in a printable form - delete() - deletes the object (use with care, especially if you passed the ownership to C++) - connect(signal, function) - connect the signal of the given object to a python function @@ -265,6 +269,27 @@ Qt framework. \endcode + And this example shows how you can define your own signals and slots: + + \code + class MySender(QtCore.QObject): + + emitProgress = QtCore.Signal(float) # this is actually a double argument in C++ + + class MyReceiver(QtCore.QObject): + + @QtCore.Slot(float) + def progress(self, value): + print(f"progress: {value}") + + sender = MySender() + receiver = MyReceiver() + # connecting with the effective signature: + sender.connect("emitProgress(double)", receiver, "progress(double)") + sender.emitProgress(2.0) + + \endcode + \section CPP CPP Wrapping You can create dedicated wrapper QObjects for any C++ class. This is done by deriving from PythonQtCppWrapperFactory @@ -304,6 +329,8 @@ QtCore.QDate.currentDate() # enum value QtCore.QFont.UltraCondensed +# or, alternatively +QtCore.QFont.Stretch.UltraCondensed \endcode @@ -450,11 +477,11 @@ yourCpp = None \page Building Building - PythonQt requires at least Qt 4.6.1 (for earlier Qt versions, you will need to run the pythonqt_generator, Qt 4.3 is the absolute minimum) and Python 2.6.x/2.7.x or Python 3.3 (or higher). + PythonQt requires at least Qt 5.0 and Python 2.7.x or Python 3.6 (or higher). To compile PythonQt, you will need a python developer installation which includes Python's header files and the python2x.[lib | dll | so | dynlib]. The recommended way to build PythonQt is to use the QMake-based *.pro file. - The build scripts a currently set to use Python 2.6. + The build scripts are currently set to use Python 3.10 by default. You may need to tweak the \b build/python.prf file to set the correct Python includes and libs on your system. \subsection Windows @@ -465,21 +492,20 @@ the python2x.[lib | dll | so | dynlib]. Python yourself, using your compiler. To build PythonQt, you need to set the environment variable \b PYTHON_PATH to point to the root - dir of the python installation and \b PYTHON_LIB to point to - the directory where the python lib file is located. + dir of the python installation and \b PYTHON_VERSION should state the used Python version. When using the prebuild Python installer, this will be: \code - > set PYTHON_PATH = c:\Python26 - > set PYTHON_LIB = c:\Python26\libs + > set PYTHON_PATH = c:\Python310 + > set PYTHON_VERSION = 3.10 \endcode When using the python sources, this will be something like: \code - > set PYTHON_PATH = c:\yourDir\Python-2.6.1\ - > set PYTHON_LIB = c:\yourDir\Python-2.6.1\PCbuild8\Win32 + > set PYTHON_PATH = c:\yourDir\Python-3.10.12\ + > set PYTHON_VERSION = 3.10 \endcode To build all, do the following (after setting the above variables): @@ -519,7 +545,7 @@ the python2x.[lib | dll | so | dynlib]. You should add PythonQt/lib to your LD_LIBRARY_PATH so that the runtime linker can find the *.so files. - \subsection MacOsX + \subsection MacOS On Mac, Python is installed as a Framework, so you should not need to install it. To build PythonQt, just do a: diff --git a/src/PythonQtStdDecorators.h b/src/PythonQtStdDecorators.h index f3f6948b..3b1179d1 100644 --- a/src/PythonQtStdDecorators.h +++ b/src/PythonQtStdDecorators.h @@ -58,7 +58,7 @@ #include #include #include -#if QT_VERSION >= 0x060000 +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) #include #endif @@ -109,7 +109,7 @@ public Q_SLOTS: int static_Qt_qrand() { -#if QT_VERSION < 0x060000 +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) return qrand(); #else return QRandomGenerator::global()->generate(); @@ -118,7 +118,7 @@ public Q_SLOTS: void static_Qt_qsrand(uint a) { -#if QT_VERSION < 0x060000 +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) qsrand(a); #else QRandomGenerator::global()->seed(a); diff --git a/src/PythonQtVariants.h b/src/PythonQtVariants.h index 833f35c8..d2ba9eff 100644 --- a/src/PythonQtVariants.h +++ b/src/PythonQtVariants.h @@ -72,6 +72,9 @@ #include #include #include +#if QT_VERSION < 0x060000 +#include +#endif #endif